1a2f3d83cSJiri Slaby (SUSE) // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2a2f3d83cSJiri Slaby (SUSE) /*
3a2f3d83cSJiri Slaby (SUSE)  * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
4a2f3d83cSJiri Slaby (SUSE)  *
5a2f3d83cSJiri Slaby (SUSE)  * Main part
6a2f3d83cSJiri Slaby (SUSE)  *
7a2f3d83cSJiri Slaby (SUSE)  * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
8a2f3d83cSJiri Slaby (SUSE)  *
9a2f3d83cSJiri Slaby (SUSE)  * If distributed as part of the Linux kernel, this code is licensed under the
10a2f3d83cSJiri Slaby (SUSE)  * terms of the GPL v2.
11a2f3d83cSJiri Slaby (SUSE)  *
12a2f3d83cSJiri Slaby (SUSE)  * Otherwise, the following license terms apply:
13a2f3d83cSJiri Slaby (SUSE)  *
14a2f3d83cSJiri Slaby (SUSE)  * * Redistribution and use in source and binary forms, with or without
15a2f3d83cSJiri Slaby (SUSE)  * * modification, are permitted provided that the following conditions
16a2f3d83cSJiri Slaby (SUSE)  * * are met:
17a2f3d83cSJiri Slaby (SUSE)  * * 1) Redistributions of source code must retain the above copyright
18a2f3d83cSJiri Slaby (SUSE)  * *    notice, this list of conditions and the following disclaimer.
19a2f3d83cSJiri Slaby (SUSE)  * * 2) Redistributions in binary form must reproduce the above copyright
20a2f3d83cSJiri Slaby (SUSE)  * *    notice, this list of conditions and the following disclaimer in the
21a2f3d83cSJiri Slaby (SUSE)  * *    documentation and/or other materials provided with the distribution.
22a2f3d83cSJiri Slaby (SUSE)  * * 3) The name of the author may not be used to endorse or promote products
23a2f3d83cSJiri Slaby (SUSE)  * *    derived from this software without specific psisusbr written permission.
24a2f3d83cSJiri Slaby (SUSE)  * *
25a2f3d83cSJiri Slaby (SUSE)  * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
26a2f3d83cSJiri Slaby (SUSE)  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27a2f3d83cSJiri Slaby (SUSE)  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28a2f3d83cSJiri Slaby (SUSE)  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29a2f3d83cSJiri Slaby (SUSE)  * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30a2f3d83cSJiri Slaby (SUSE)  * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31a2f3d83cSJiri Slaby (SUSE)  * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32a2f3d83cSJiri Slaby (SUSE)  * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33a2f3d83cSJiri Slaby (SUSE)  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34a2f3d83cSJiri Slaby (SUSE)  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35a2f3d83cSJiri Slaby (SUSE)  *
36a2f3d83cSJiri Slaby (SUSE)  * Author:	Thomas Winischhofer <thomas@winischhofer.net>
37a2f3d83cSJiri Slaby (SUSE)  *
38a2f3d83cSJiri Slaby (SUSE)  */
39a2f3d83cSJiri Slaby (SUSE) 
40a2f3d83cSJiri Slaby (SUSE) #include <linux/mutex.h>
41a2f3d83cSJiri Slaby (SUSE) #include <linux/module.h>
42a2f3d83cSJiri Slaby (SUSE) #include <linux/kernel.h>
43a2f3d83cSJiri Slaby (SUSE) #include <linux/signal.h>
44a2f3d83cSJiri Slaby (SUSE) #include <linux/errno.h>
45a2f3d83cSJiri Slaby (SUSE) #include <linux/poll.h>
46a2f3d83cSJiri Slaby (SUSE) #include <linux/init.h>
47a2f3d83cSJiri Slaby (SUSE) #include <linux/slab.h>
48a2f3d83cSJiri Slaby (SUSE) #include <linux/spinlock.h>
49a2f3d83cSJiri Slaby (SUSE) #include <linux/kref.h>
50a2f3d83cSJiri Slaby (SUSE) #include <linux/usb.h>
51a2f3d83cSJiri Slaby (SUSE) #include <linux/vmalloc.h>
52a2f3d83cSJiri Slaby (SUSE) 
53a2f3d83cSJiri Slaby (SUSE) #include "sisusb.h"
54a2f3d83cSJiri Slaby (SUSE) 
55a2f3d83cSJiri Slaby (SUSE) #define SISUSB_DONTSYNC
56a2f3d83cSJiri Slaby (SUSE) 
57a2f3d83cSJiri Slaby (SUSE) /* Forward declarations / clean-up routines */
58a2f3d83cSJiri Slaby (SUSE) 
59a2f3d83cSJiri Slaby (SUSE) static struct usb_driver sisusb_driver;
60a2f3d83cSJiri Slaby (SUSE) 
sisusb_free_buffers(struct sisusb_usb_data * sisusb)61a2f3d83cSJiri Slaby (SUSE) static void sisusb_free_buffers(struct sisusb_usb_data *sisusb)
62a2f3d83cSJiri Slaby (SUSE) {
63a2f3d83cSJiri Slaby (SUSE) 	int i;
64a2f3d83cSJiri Slaby (SUSE) 
65a2f3d83cSJiri Slaby (SUSE) 	for (i = 0; i < NUMOBUFS; i++) {
66a2f3d83cSJiri Slaby (SUSE) 		kfree(sisusb->obuf[i]);
67a2f3d83cSJiri Slaby (SUSE) 		sisusb->obuf[i] = NULL;
68a2f3d83cSJiri Slaby (SUSE) 	}
69a2f3d83cSJiri Slaby (SUSE) 	kfree(sisusb->ibuf);
70a2f3d83cSJiri Slaby (SUSE) 	sisusb->ibuf = NULL;
71a2f3d83cSJiri Slaby (SUSE) }
72a2f3d83cSJiri Slaby (SUSE) 
sisusb_free_urbs(struct sisusb_usb_data * sisusb)73a2f3d83cSJiri Slaby (SUSE) static void sisusb_free_urbs(struct sisusb_usb_data *sisusb)
74a2f3d83cSJiri Slaby (SUSE) {
75a2f3d83cSJiri Slaby (SUSE) 	int i;
76a2f3d83cSJiri Slaby (SUSE) 
77a2f3d83cSJiri Slaby (SUSE) 	for (i = 0; i < NUMOBUFS; i++) {
78a2f3d83cSJiri Slaby (SUSE) 		usb_free_urb(sisusb->sisurbout[i]);
79a2f3d83cSJiri Slaby (SUSE) 		sisusb->sisurbout[i] = NULL;
80a2f3d83cSJiri Slaby (SUSE) 	}
81a2f3d83cSJiri Slaby (SUSE) 	usb_free_urb(sisusb->sisurbin);
82a2f3d83cSJiri Slaby (SUSE) 	sisusb->sisurbin = NULL;
83a2f3d83cSJiri Slaby (SUSE) }
84a2f3d83cSJiri Slaby (SUSE) 
85a2f3d83cSJiri Slaby (SUSE) /* Level 0: USB transport layer */
86a2f3d83cSJiri Slaby (SUSE) 
87a2f3d83cSJiri Slaby (SUSE) /* 1. out-bulks */
88a2f3d83cSJiri Slaby (SUSE) 
89a2f3d83cSJiri Slaby (SUSE) /* out-urb management */
90a2f3d83cSJiri Slaby (SUSE) 
91a2f3d83cSJiri Slaby (SUSE) /* Return 1 if all free, 0 otherwise */
sisusb_all_free(struct sisusb_usb_data * sisusb)92a2f3d83cSJiri Slaby (SUSE) static int sisusb_all_free(struct sisusb_usb_data *sisusb)
93a2f3d83cSJiri Slaby (SUSE) {
94a2f3d83cSJiri Slaby (SUSE) 	int i;
95a2f3d83cSJiri Slaby (SUSE) 
96a2f3d83cSJiri Slaby (SUSE) 	for (i = 0; i < sisusb->numobufs; i++) {
97a2f3d83cSJiri Slaby (SUSE) 
98a2f3d83cSJiri Slaby (SUSE) 		if (sisusb->urbstatus[i] & SU_URB_BUSY)
99a2f3d83cSJiri Slaby (SUSE) 			return 0;
100a2f3d83cSJiri Slaby (SUSE) 
101a2f3d83cSJiri Slaby (SUSE) 	}
102a2f3d83cSJiri Slaby (SUSE) 
103a2f3d83cSJiri Slaby (SUSE) 	return 1;
104a2f3d83cSJiri Slaby (SUSE) }
105a2f3d83cSJiri Slaby (SUSE) 
106a2f3d83cSJiri Slaby (SUSE) /* Kill all busy URBs */
sisusb_kill_all_busy(struct sisusb_usb_data * sisusb)107a2f3d83cSJiri Slaby (SUSE) static void sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
108a2f3d83cSJiri Slaby (SUSE) {
109a2f3d83cSJiri Slaby (SUSE) 	int i;
110a2f3d83cSJiri Slaby (SUSE) 
111a2f3d83cSJiri Slaby (SUSE) 	if (sisusb_all_free(sisusb))
112a2f3d83cSJiri Slaby (SUSE) 		return;
113a2f3d83cSJiri Slaby (SUSE) 
114a2f3d83cSJiri Slaby (SUSE) 	for (i = 0; i < sisusb->numobufs; i++) {
115a2f3d83cSJiri Slaby (SUSE) 
116a2f3d83cSJiri Slaby (SUSE) 		if (sisusb->urbstatus[i] & SU_URB_BUSY)
117a2f3d83cSJiri Slaby (SUSE) 			usb_kill_urb(sisusb->sisurbout[i]);
118a2f3d83cSJiri Slaby (SUSE) 
119a2f3d83cSJiri Slaby (SUSE) 	}
120a2f3d83cSJiri Slaby (SUSE) }
121a2f3d83cSJiri Slaby (SUSE) 
122a2f3d83cSJiri Slaby (SUSE) /* Return 1 if ok, 0 if error (not all complete within timeout) */
sisusb_wait_all_out_complete(struct sisusb_usb_data * sisusb)123a2f3d83cSJiri Slaby (SUSE) static int sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
124a2f3d83cSJiri Slaby (SUSE) {
125a2f3d83cSJiri Slaby (SUSE) 	int timeout = 5 * HZ, i = 1;
126a2f3d83cSJiri Slaby (SUSE) 
127a2f3d83cSJiri Slaby (SUSE) 	wait_event_timeout(sisusb->wait_q, (i = sisusb_all_free(sisusb)),
128a2f3d83cSJiri Slaby (SUSE) 			timeout);
129a2f3d83cSJiri Slaby (SUSE) 
130a2f3d83cSJiri Slaby (SUSE) 	return i;
131a2f3d83cSJiri Slaby (SUSE) }
132a2f3d83cSJiri Slaby (SUSE) 
sisusb_outurb_available(struct sisusb_usb_data * sisusb)133a2f3d83cSJiri Slaby (SUSE) static int sisusb_outurb_available(struct sisusb_usb_data *sisusb)
134a2f3d83cSJiri Slaby (SUSE) {
135a2f3d83cSJiri Slaby (SUSE) 	int i;
136a2f3d83cSJiri Slaby (SUSE) 
137a2f3d83cSJiri Slaby (SUSE) 	for (i = 0; i < sisusb->numobufs; i++) {
138a2f3d83cSJiri Slaby (SUSE) 
139a2f3d83cSJiri Slaby (SUSE) 		if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
140a2f3d83cSJiri Slaby (SUSE) 			return i;
141a2f3d83cSJiri Slaby (SUSE) 
142a2f3d83cSJiri Slaby (SUSE) 	}
143a2f3d83cSJiri Slaby (SUSE) 
144a2f3d83cSJiri Slaby (SUSE) 	return -1;
145a2f3d83cSJiri Slaby (SUSE) }
146a2f3d83cSJiri Slaby (SUSE) 
sisusb_get_free_outbuf(struct sisusb_usb_data * sisusb)147a2f3d83cSJiri Slaby (SUSE) static int sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
148a2f3d83cSJiri Slaby (SUSE) {
149a2f3d83cSJiri Slaby (SUSE) 	int i, timeout = 5 * HZ;
150a2f3d83cSJiri Slaby (SUSE) 
151a2f3d83cSJiri Slaby (SUSE) 	wait_event_timeout(sisusb->wait_q,
152a2f3d83cSJiri Slaby (SUSE) 			((i = sisusb_outurb_available(sisusb)) >= 0), timeout);
153a2f3d83cSJiri Slaby (SUSE) 
154a2f3d83cSJiri Slaby (SUSE) 	return i;
155a2f3d83cSJiri Slaby (SUSE) }
156a2f3d83cSJiri Slaby (SUSE) 
sisusb_alloc_outbuf(struct sisusb_usb_data * sisusb)157a2f3d83cSJiri Slaby (SUSE) static int sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
158a2f3d83cSJiri Slaby (SUSE) {
159a2f3d83cSJiri Slaby (SUSE) 	int i;
160a2f3d83cSJiri Slaby (SUSE) 
161a2f3d83cSJiri Slaby (SUSE) 	i = sisusb_outurb_available(sisusb);
162a2f3d83cSJiri Slaby (SUSE) 
163a2f3d83cSJiri Slaby (SUSE) 	if (i >= 0)
164a2f3d83cSJiri Slaby (SUSE) 		sisusb->urbstatus[i] |= SU_URB_ALLOC;
165a2f3d83cSJiri Slaby (SUSE) 
166a2f3d83cSJiri Slaby (SUSE) 	return i;
167a2f3d83cSJiri Slaby (SUSE) }
168a2f3d83cSJiri Slaby (SUSE) 
sisusb_free_outbuf(struct sisusb_usb_data * sisusb,int index)169a2f3d83cSJiri Slaby (SUSE) static void sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
170a2f3d83cSJiri Slaby (SUSE) {
171a2f3d83cSJiri Slaby (SUSE) 	if ((index >= 0) && (index < sisusb->numobufs))
172a2f3d83cSJiri Slaby (SUSE) 		sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
173a2f3d83cSJiri Slaby (SUSE) }
174a2f3d83cSJiri Slaby (SUSE) 
175a2f3d83cSJiri Slaby (SUSE) /* completion callback */
176a2f3d83cSJiri Slaby (SUSE) 
sisusb_bulk_completeout(struct urb * urb)177a2f3d83cSJiri Slaby (SUSE) static void sisusb_bulk_completeout(struct urb *urb)
178a2f3d83cSJiri Slaby (SUSE) {
179a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_urb_context *context = urb->context;
180a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_usb_data *sisusb;
181a2f3d83cSJiri Slaby (SUSE) 
182a2f3d83cSJiri Slaby (SUSE) 	if (!context)
183a2f3d83cSJiri Slaby (SUSE) 		return;
184a2f3d83cSJiri Slaby (SUSE) 
185a2f3d83cSJiri Slaby (SUSE) 	sisusb = context->sisusb;
186a2f3d83cSJiri Slaby (SUSE) 
187a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
188a2f3d83cSJiri Slaby (SUSE) 		return;
189a2f3d83cSJiri Slaby (SUSE) 
190a2f3d83cSJiri Slaby (SUSE) #ifndef SISUSB_DONTSYNC
191a2f3d83cSJiri Slaby (SUSE) 	if (context->actual_length)
192a2f3d83cSJiri Slaby (SUSE) 		*(context->actual_length) += urb->actual_length;
193a2f3d83cSJiri Slaby (SUSE) #endif
194a2f3d83cSJiri Slaby (SUSE) 
195a2f3d83cSJiri Slaby (SUSE) 	sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
196a2f3d83cSJiri Slaby (SUSE) 	wake_up(&sisusb->wait_q);
197a2f3d83cSJiri Slaby (SUSE) }
198a2f3d83cSJiri Slaby (SUSE) 
sisusb_bulkout_msg(struct sisusb_usb_data * sisusb,int index,unsigned int pipe,void * data,int len,int * actual_length,int timeout,unsigned int tflags)199a2f3d83cSJiri Slaby (SUSE) static int sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index,
200a2f3d83cSJiri Slaby (SUSE) 		unsigned int pipe, void *data, int len, int *actual_length,
201a2f3d83cSJiri Slaby (SUSE) 		int timeout, unsigned int tflags)
202a2f3d83cSJiri Slaby (SUSE) {
203a2f3d83cSJiri Slaby (SUSE) 	struct urb *urb = sisusb->sisurbout[index];
204a2f3d83cSJiri Slaby (SUSE) 	int retval, byteswritten = 0;
205a2f3d83cSJiri Slaby (SUSE) 
206a2f3d83cSJiri Slaby (SUSE) 	/* Set up URB */
207a2f3d83cSJiri Slaby (SUSE) 	urb->transfer_flags = 0;
208a2f3d83cSJiri Slaby (SUSE) 
209a2f3d83cSJiri Slaby (SUSE) 	usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
210a2f3d83cSJiri Slaby (SUSE) 			sisusb_bulk_completeout,
211a2f3d83cSJiri Slaby (SUSE) 			&sisusb->urbout_context[index]);
212a2f3d83cSJiri Slaby (SUSE) 
213a2f3d83cSJiri Slaby (SUSE) 	urb->transfer_flags |= tflags;
214a2f3d83cSJiri Slaby (SUSE) 	urb->actual_length = 0;
215a2f3d83cSJiri Slaby (SUSE) 
216a2f3d83cSJiri Slaby (SUSE) 	/* Set up context */
217a2f3d83cSJiri Slaby (SUSE) 	sisusb->urbout_context[index].actual_length = (timeout) ?
218a2f3d83cSJiri Slaby (SUSE) 			NULL : actual_length;
219a2f3d83cSJiri Slaby (SUSE) 
220a2f3d83cSJiri Slaby (SUSE) 	/* Declare this urb/buffer in use */
221a2f3d83cSJiri Slaby (SUSE) 	sisusb->urbstatus[index] |= SU_URB_BUSY;
222a2f3d83cSJiri Slaby (SUSE) 
223a2f3d83cSJiri Slaby (SUSE) 	/* Submit URB */
224a2f3d83cSJiri Slaby (SUSE) 	retval = usb_submit_urb(urb, GFP_KERNEL);
225a2f3d83cSJiri Slaby (SUSE) 
226a2f3d83cSJiri Slaby (SUSE) 	/* If OK, and if timeout > 0, wait for completion */
227a2f3d83cSJiri Slaby (SUSE) 	if ((retval == 0) && timeout) {
228a2f3d83cSJiri Slaby (SUSE) 		wait_event_timeout(sisusb->wait_q,
229a2f3d83cSJiri Slaby (SUSE) 				(!(sisusb->urbstatus[index] & SU_URB_BUSY)),
230a2f3d83cSJiri Slaby (SUSE) 				timeout);
231a2f3d83cSJiri Slaby (SUSE) 		if (sisusb->urbstatus[index] & SU_URB_BUSY) {
232a2f3d83cSJiri Slaby (SUSE) 			/* URB timed out... kill it and report error */
233a2f3d83cSJiri Slaby (SUSE) 			usb_kill_urb(urb);
234a2f3d83cSJiri Slaby (SUSE) 			retval = -ETIMEDOUT;
235a2f3d83cSJiri Slaby (SUSE) 		} else {
236a2f3d83cSJiri Slaby (SUSE) 			/* Otherwise, report urb status */
237a2f3d83cSJiri Slaby (SUSE) 			retval = urb->status;
238a2f3d83cSJiri Slaby (SUSE) 			byteswritten = urb->actual_length;
239a2f3d83cSJiri Slaby (SUSE) 		}
240a2f3d83cSJiri Slaby (SUSE) 	}
241a2f3d83cSJiri Slaby (SUSE) 
242a2f3d83cSJiri Slaby (SUSE) 	if (actual_length)
243a2f3d83cSJiri Slaby (SUSE) 		*actual_length = byteswritten;
244a2f3d83cSJiri Slaby (SUSE) 
245a2f3d83cSJiri Slaby (SUSE) 	return retval;
246a2f3d83cSJiri Slaby (SUSE) }
247a2f3d83cSJiri Slaby (SUSE) 
248a2f3d83cSJiri Slaby (SUSE) /* 2. in-bulks */
249a2f3d83cSJiri Slaby (SUSE) 
250a2f3d83cSJiri Slaby (SUSE) /* completion callback */
251a2f3d83cSJiri Slaby (SUSE) 
sisusb_bulk_completein(struct urb * urb)252a2f3d83cSJiri Slaby (SUSE) static void sisusb_bulk_completein(struct urb *urb)
253a2f3d83cSJiri Slaby (SUSE) {
254a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_usb_data *sisusb = urb->context;
255a2f3d83cSJiri Slaby (SUSE) 
256a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
257a2f3d83cSJiri Slaby (SUSE) 		return;
258a2f3d83cSJiri Slaby (SUSE) 
259a2f3d83cSJiri Slaby (SUSE) 	sisusb->completein = 1;
260a2f3d83cSJiri Slaby (SUSE) 	wake_up(&sisusb->wait_q);
261a2f3d83cSJiri Slaby (SUSE) }
262a2f3d83cSJiri Slaby (SUSE) 
sisusb_bulkin_msg(struct sisusb_usb_data * sisusb,unsigned int pipe,void * data,int len,int * actual_length,int timeout,unsigned int tflags)263a2f3d83cSJiri Slaby (SUSE) static int sisusb_bulkin_msg(struct sisusb_usb_data *sisusb,
264a2f3d83cSJiri Slaby (SUSE) 		unsigned int pipe, void *data, int len,
265a2f3d83cSJiri Slaby (SUSE) 		int *actual_length, int timeout, unsigned int tflags)
266a2f3d83cSJiri Slaby (SUSE) {
267a2f3d83cSJiri Slaby (SUSE) 	struct urb *urb = sisusb->sisurbin;
268a2f3d83cSJiri Slaby (SUSE) 	int retval, readbytes = 0;
269a2f3d83cSJiri Slaby (SUSE) 
270a2f3d83cSJiri Slaby (SUSE) 	urb->transfer_flags = 0;
271a2f3d83cSJiri Slaby (SUSE) 
272a2f3d83cSJiri Slaby (SUSE) 	usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
273a2f3d83cSJiri Slaby (SUSE) 			sisusb_bulk_completein, sisusb);
274a2f3d83cSJiri Slaby (SUSE) 
275a2f3d83cSJiri Slaby (SUSE) 	urb->transfer_flags |= tflags;
276a2f3d83cSJiri Slaby (SUSE) 	urb->actual_length = 0;
277a2f3d83cSJiri Slaby (SUSE) 
278a2f3d83cSJiri Slaby (SUSE) 	sisusb->completein = 0;
279a2f3d83cSJiri Slaby (SUSE) 	retval = usb_submit_urb(urb, GFP_KERNEL);
280a2f3d83cSJiri Slaby (SUSE) 	if (retval == 0) {
281a2f3d83cSJiri Slaby (SUSE) 		wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
282a2f3d83cSJiri Slaby (SUSE) 		if (!sisusb->completein) {
283a2f3d83cSJiri Slaby (SUSE) 			/* URB timed out... kill it and report error */
284a2f3d83cSJiri Slaby (SUSE) 			usb_kill_urb(urb);
285a2f3d83cSJiri Slaby (SUSE) 			retval = -ETIMEDOUT;
286a2f3d83cSJiri Slaby (SUSE) 		} else {
287a2f3d83cSJiri Slaby (SUSE) 			/* URB completed within timeout */
288a2f3d83cSJiri Slaby (SUSE) 			retval = urb->status;
289a2f3d83cSJiri Slaby (SUSE) 			readbytes = urb->actual_length;
290a2f3d83cSJiri Slaby (SUSE) 		}
291a2f3d83cSJiri Slaby (SUSE) 	}
292a2f3d83cSJiri Slaby (SUSE) 
293a2f3d83cSJiri Slaby (SUSE) 	if (actual_length)
294a2f3d83cSJiri Slaby (SUSE) 		*actual_length = readbytes;
295a2f3d83cSJiri Slaby (SUSE) 
296a2f3d83cSJiri Slaby (SUSE) 	return retval;
297a2f3d83cSJiri Slaby (SUSE) }
298a2f3d83cSJiri Slaby (SUSE) 
299a2f3d83cSJiri Slaby (SUSE) 
300a2f3d83cSJiri Slaby (SUSE) /* Level 1:  */
301a2f3d83cSJiri Slaby (SUSE) 
302a2f3d83cSJiri Slaby (SUSE) /* Send a bulk message of variable size
303a2f3d83cSJiri Slaby (SUSE)  *
304a2f3d83cSJiri Slaby (SUSE)  * To copy the data from userspace, give pointer to "userbuffer",
305a2f3d83cSJiri Slaby (SUSE)  * to copy from (non-DMA) kernel memory, give "kernbuffer". If
306a2f3d83cSJiri Slaby (SUSE)  * both of these are NULL, it is assumed, that the transfer
307a2f3d83cSJiri Slaby (SUSE)  * buffer "sisusb->obuf[index]" is set up with the data to send.
308a2f3d83cSJiri Slaby (SUSE)  * Index is ignored if either kernbuffer or userbuffer is set.
309a2f3d83cSJiri Slaby (SUSE)  * If async is nonzero, URBs will be sent without waiting for
310a2f3d83cSJiri Slaby (SUSE)  * completion of the previous URB.
311a2f3d83cSJiri Slaby (SUSE)  *
312a2f3d83cSJiri Slaby (SUSE)  * (return 0 on success)
313a2f3d83cSJiri Slaby (SUSE)  */
314a2f3d83cSJiri Slaby (SUSE) 
sisusb_send_bulk_msg(struct sisusb_usb_data * sisusb,int ep,int len,char * kernbuffer,const char __user * userbuffer,int index,ssize_t * bytes_written,unsigned int tflags,int async)315a2f3d83cSJiri Slaby (SUSE) static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
316a2f3d83cSJiri Slaby (SUSE) 		char *kernbuffer, const char __user *userbuffer, int index,
317a2f3d83cSJiri Slaby (SUSE) 		ssize_t *bytes_written, unsigned int tflags, int async)
318a2f3d83cSJiri Slaby (SUSE) {
319a2f3d83cSJiri Slaby (SUSE) 	int result = 0, retry, count = len;
320a2f3d83cSJiri Slaby (SUSE) 	int passsize, thispass, transferred_len = 0;
321a2f3d83cSJiri Slaby (SUSE) 	int fromuser = (userbuffer != NULL) ? 1 : 0;
322a2f3d83cSJiri Slaby (SUSE) 	int fromkern = (kernbuffer != NULL) ? 1 : 0;
323a2f3d83cSJiri Slaby (SUSE) 	unsigned int pipe;
324a2f3d83cSJiri Slaby (SUSE) 	char *buffer;
325a2f3d83cSJiri Slaby (SUSE) 
326a2f3d83cSJiri Slaby (SUSE) 	(*bytes_written) = 0;
327a2f3d83cSJiri Slaby (SUSE) 
328a2f3d83cSJiri Slaby (SUSE) 	/* Sanity check */
329a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
330a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
331a2f3d83cSJiri Slaby (SUSE) 
332a2f3d83cSJiri Slaby (SUSE) 	/* If we copy data from kernel or userspace, force the
333a2f3d83cSJiri Slaby (SUSE) 	 * allocation of a buffer/urb. If we have the data in
334a2f3d83cSJiri Slaby (SUSE) 	 * the transfer buffer[index] already, reuse the buffer/URB
335a2f3d83cSJiri Slaby (SUSE) 	 * if the length is > buffer size. (So, transmitting
336a2f3d83cSJiri Slaby (SUSE) 	 * large data amounts directly from the transfer buffer
337a2f3d83cSJiri Slaby (SUSE) 	 * treats the buffer as a ring buffer. However, we need
338a2f3d83cSJiri Slaby (SUSE) 	 * to sync in this case.)
339a2f3d83cSJiri Slaby (SUSE) 	 */
340a2f3d83cSJiri Slaby (SUSE) 	if (fromuser || fromkern)
341a2f3d83cSJiri Slaby (SUSE) 		index = -1;
342a2f3d83cSJiri Slaby (SUSE) 	else if (len > sisusb->obufsize)
343a2f3d83cSJiri Slaby (SUSE) 		async = 0;
344a2f3d83cSJiri Slaby (SUSE) 
345a2f3d83cSJiri Slaby (SUSE) 	pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
346a2f3d83cSJiri Slaby (SUSE) 
347a2f3d83cSJiri Slaby (SUSE) 	do {
348a2f3d83cSJiri Slaby (SUSE) 		passsize = thispass = (sisusb->obufsize < count) ?
349a2f3d83cSJiri Slaby (SUSE) 				sisusb->obufsize : count;
350a2f3d83cSJiri Slaby (SUSE) 
351a2f3d83cSJiri Slaby (SUSE) 		if (index < 0)
352a2f3d83cSJiri Slaby (SUSE) 			index = sisusb_get_free_outbuf(sisusb);
353a2f3d83cSJiri Slaby (SUSE) 
354a2f3d83cSJiri Slaby (SUSE) 		if (index < 0)
355a2f3d83cSJiri Slaby (SUSE) 			return -EIO;
356a2f3d83cSJiri Slaby (SUSE) 
357a2f3d83cSJiri Slaby (SUSE) 		buffer = sisusb->obuf[index];
358a2f3d83cSJiri Slaby (SUSE) 
359a2f3d83cSJiri Slaby (SUSE) 		if (fromuser) {
360a2f3d83cSJiri Slaby (SUSE) 
361a2f3d83cSJiri Slaby (SUSE) 			if (copy_from_user(buffer, userbuffer, passsize))
362a2f3d83cSJiri Slaby (SUSE) 				return -EFAULT;
363a2f3d83cSJiri Slaby (SUSE) 
364a2f3d83cSJiri Slaby (SUSE) 			userbuffer += passsize;
365a2f3d83cSJiri Slaby (SUSE) 
366a2f3d83cSJiri Slaby (SUSE) 		} else if (fromkern) {
367a2f3d83cSJiri Slaby (SUSE) 
368a2f3d83cSJiri Slaby (SUSE) 			memcpy(buffer, kernbuffer, passsize);
369a2f3d83cSJiri Slaby (SUSE) 			kernbuffer += passsize;
370a2f3d83cSJiri Slaby (SUSE) 
371a2f3d83cSJiri Slaby (SUSE) 		}
372a2f3d83cSJiri Slaby (SUSE) 
373a2f3d83cSJiri Slaby (SUSE) 		retry = 5;
374a2f3d83cSJiri Slaby (SUSE) 		while (thispass) {
375a2f3d83cSJiri Slaby (SUSE) 
376a2f3d83cSJiri Slaby (SUSE) 			if (!sisusb->sisusb_dev)
377a2f3d83cSJiri Slaby (SUSE) 				return -ENODEV;
378a2f3d83cSJiri Slaby (SUSE) 
379a2f3d83cSJiri Slaby (SUSE) 			result = sisusb_bulkout_msg(sisusb, index, pipe,
380a2f3d83cSJiri Slaby (SUSE) 					buffer, thispass, &transferred_len,
381a2f3d83cSJiri Slaby (SUSE) 					async ? 0 : 5 * HZ, tflags);
382a2f3d83cSJiri Slaby (SUSE) 
383a2f3d83cSJiri Slaby (SUSE) 			if (result == -ETIMEDOUT) {
384a2f3d83cSJiri Slaby (SUSE) 
385a2f3d83cSJiri Slaby (SUSE) 				/* Will not happen if async */
386a2f3d83cSJiri Slaby (SUSE) 				if (!retry--)
387a2f3d83cSJiri Slaby (SUSE) 					return -ETIME;
388a2f3d83cSJiri Slaby (SUSE) 
389a2f3d83cSJiri Slaby (SUSE) 				continue;
390a2f3d83cSJiri Slaby (SUSE) 			}
391a2f3d83cSJiri Slaby (SUSE) 
392a2f3d83cSJiri Slaby (SUSE) 			if ((result == 0) && !async && transferred_len) {
393a2f3d83cSJiri Slaby (SUSE) 
394a2f3d83cSJiri Slaby (SUSE) 				thispass -= transferred_len;
395a2f3d83cSJiri Slaby (SUSE) 				buffer += transferred_len;
396a2f3d83cSJiri Slaby (SUSE) 
397a2f3d83cSJiri Slaby (SUSE) 			} else
398a2f3d83cSJiri Slaby (SUSE) 				break;
399a2f3d83cSJiri Slaby (SUSE) 		}
400a2f3d83cSJiri Slaby (SUSE) 
401a2f3d83cSJiri Slaby (SUSE) 		if (result)
402a2f3d83cSJiri Slaby (SUSE) 			return result;
403a2f3d83cSJiri Slaby (SUSE) 
404a2f3d83cSJiri Slaby (SUSE) 		(*bytes_written) += passsize;
405a2f3d83cSJiri Slaby (SUSE) 		count            -= passsize;
406a2f3d83cSJiri Slaby (SUSE) 
407a2f3d83cSJiri Slaby (SUSE) 		/* Force new allocation in next iteration */
408a2f3d83cSJiri Slaby (SUSE) 		if (fromuser || fromkern)
409a2f3d83cSJiri Slaby (SUSE) 			index = -1;
410a2f3d83cSJiri Slaby (SUSE) 
411a2f3d83cSJiri Slaby (SUSE) 	} while (count > 0);
412a2f3d83cSJiri Slaby (SUSE) 
413a2f3d83cSJiri Slaby (SUSE) 	if (async) {
414a2f3d83cSJiri Slaby (SUSE) #ifdef SISUSB_DONTSYNC
415a2f3d83cSJiri Slaby (SUSE) 		(*bytes_written) = len;
416a2f3d83cSJiri Slaby (SUSE) 		/* Some URBs/buffers might be busy */
417a2f3d83cSJiri Slaby (SUSE) #else
418a2f3d83cSJiri Slaby (SUSE) 		sisusb_wait_all_out_complete(sisusb);
419a2f3d83cSJiri Slaby (SUSE) 		(*bytes_written) = transferred_len;
420a2f3d83cSJiri Slaby (SUSE) 		/* All URBs and all buffers are available */
421a2f3d83cSJiri Slaby (SUSE) #endif
422a2f3d83cSJiri Slaby (SUSE) 	}
423a2f3d83cSJiri Slaby (SUSE) 
424a2f3d83cSJiri Slaby (SUSE) 	return ((*bytes_written) == len) ? 0 : -EIO;
425a2f3d83cSJiri Slaby (SUSE) }
426a2f3d83cSJiri Slaby (SUSE) 
427a2f3d83cSJiri Slaby (SUSE) /* Receive a bulk message of variable size
428a2f3d83cSJiri Slaby (SUSE)  *
429a2f3d83cSJiri Slaby (SUSE)  * To copy the data to userspace, give pointer to "userbuffer",
430a2f3d83cSJiri Slaby (SUSE)  * to copy to kernel memory, give "kernbuffer". One of them
431a2f3d83cSJiri Slaby (SUSE)  * MUST be set. (There is no technique for letting the caller
432a2f3d83cSJiri Slaby (SUSE)  * read directly from the ibuf.)
433a2f3d83cSJiri Slaby (SUSE)  *
434a2f3d83cSJiri Slaby (SUSE)  */
435a2f3d83cSJiri Slaby (SUSE) 
sisusb_recv_bulk_msg(struct sisusb_usb_data * sisusb,int ep,int len,void * kernbuffer,char __user * userbuffer,ssize_t * bytes_read,unsigned int tflags)436a2f3d83cSJiri Slaby (SUSE) static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
437a2f3d83cSJiri Slaby (SUSE) 		void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
438a2f3d83cSJiri Slaby (SUSE) 		unsigned int tflags)
439a2f3d83cSJiri Slaby (SUSE) {
440a2f3d83cSJiri Slaby (SUSE) 	int result = 0, retry, count = len;
441a2f3d83cSJiri Slaby (SUSE) 	int bufsize, thispass, transferred_len;
442a2f3d83cSJiri Slaby (SUSE) 	unsigned int pipe;
443a2f3d83cSJiri Slaby (SUSE) 	char *buffer;
444a2f3d83cSJiri Slaby (SUSE) 
445a2f3d83cSJiri Slaby (SUSE) 	(*bytes_read) = 0;
446a2f3d83cSJiri Slaby (SUSE) 
447a2f3d83cSJiri Slaby (SUSE) 	/* Sanity check */
448a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
449a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
450a2f3d83cSJiri Slaby (SUSE) 
451a2f3d83cSJiri Slaby (SUSE) 	pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
452a2f3d83cSJiri Slaby (SUSE) 	buffer = sisusb->ibuf;
453a2f3d83cSJiri Slaby (SUSE) 	bufsize = sisusb->ibufsize;
454a2f3d83cSJiri Slaby (SUSE) 
455a2f3d83cSJiri Slaby (SUSE) 	retry = 5;
456a2f3d83cSJiri Slaby (SUSE) 
457a2f3d83cSJiri Slaby (SUSE) #ifdef SISUSB_DONTSYNC
458a2f3d83cSJiri Slaby (SUSE) 	if (!(sisusb_wait_all_out_complete(sisusb)))
459a2f3d83cSJiri Slaby (SUSE) 		return -EIO;
460a2f3d83cSJiri Slaby (SUSE) #endif
461a2f3d83cSJiri Slaby (SUSE) 
462a2f3d83cSJiri Slaby (SUSE) 	while (count > 0) {
463a2f3d83cSJiri Slaby (SUSE) 
464a2f3d83cSJiri Slaby (SUSE) 		if (!sisusb->sisusb_dev)
465a2f3d83cSJiri Slaby (SUSE) 			return -ENODEV;
466a2f3d83cSJiri Slaby (SUSE) 
467a2f3d83cSJiri Slaby (SUSE) 		thispass = (bufsize < count) ? bufsize : count;
468a2f3d83cSJiri Slaby (SUSE) 
469a2f3d83cSJiri Slaby (SUSE) 		result = sisusb_bulkin_msg(sisusb, pipe, buffer, thispass,
470a2f3d83cSJiri Slaby (SUSE) 				&transferred_len, 5 * HZ, tflags);
471a2f3d83cSJiri Slaby (SUSE) 
472a2f3d83cSJiri Slaby (SUSE) 		if (transferred_len)
473a2f3d83cSJiri Slaby (SUSE) 			thispass = transferred_len;
474a2f3d83cSJiri Slaby (SUSE) 
475a2f3d83cSJiri Slaby (SUSE) 		else if (result == -ETIMEDOUT) {
476a2f3d83cSJiri Slaby (SUSE) 
477a2f3d83cSJiri Slaby (SUSE) 			if (!retry--)
478a2f3d83cSJiri Slaby (SUSE) 				return -ETIME;
479a2f3d83cSJiri Slaby (SUSE) 
480a2f3d83cSJiri Slaby (SUSE) 			continue;
481a2f3d83cSJiri Slaby (SUSE) 
482a2f3d83cSJiri Slaby (SUSE) 		} else
483a2f3d83cSJiri Slaby (SUSE) 			return -EIO;
484a2f3d83cSJiri Slaby (SUSE) 
485a2f3d83cSJiri Slaby (SUSE) 
486a2f3d83cSJiri Slaby (SUSE) 		if (thispass) {
487a2f3d83cSJiri Slaby (SUSE) 
488a2f3d83cSJiri Slaby (SUSE) 			(*bytes_read) += thispass;
489a2f3d83cSJiri Slaby (SUSE) 			count         -= thispass;
490a2f3d83cSJiri Slaby (SUSE) 
491a2f3d83cSJiri Slaby (SUSE) 			if (userbuffer) {
492a2f3d83cSJiri Slaby (SUSE) 
493a2f3d83cSJiri Slaby (SUSE) 				if (copy_to_user(userbuffer, buffer, thispass))
494a2f3d83cSJiri Slaby (SUSE) 					return -EFAULT;
495a2f3d83cSJiri Slaby (SUSE) 
496a2f3d83cSJiri Slaby (SUSE) 				userbuffer += thispass;
497a2f3d83cSJiri Slaby (SUSE) 
498a2f3d83cSJiri Slaby (SUSE) 			} else {
499a2f3d83cSJiri Slaby (SUSE) 
500a2f3d83cSJiri Slaby (SUSE) 				memcpy(kernbuffer, buffer, thispass);
501a2f3d83cSJiri Slaby (SUSE) 				kernbuffer += thispass;
502a2f3d83cSJiri Slaby (SUSE) 
503a2f3d83cSJiri Slaby (SUSE) 			}
504a2f3d83cSJiri Slaby (SUSE) 
505a2f3d83cSJiri Slaby (SUSE) 		}
506a2f3d83cSJiri Slaby (SUSE) 
507a2f3d83cSJiri Slaby (SUSE) 	}
508a2f3d83cSJiri Slaby (SUSE) 
509a2f3d83cSJiri Slaby (SUSE) 	return ((*bytes_read) == len) ? 0 : -EIO;
510a2f3d83cSJiri Slaby (SUSE) }
511a2f3d83cSJiri Slaby (SUSE) 
sisusb_send_packet(struct sisusb_usb_data * sisusb,int len,struct sisusb_packet * packet)512a2f3d83cSJiri Slaby (SUSE) static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
513a2f3d83cSJiri Slaby (SUSE) 		struct sisusb_packet *packet)
514a2f3d83cSJiri Slaby (SUSE) {
515a2f3d83cSJiri Slaby (SUSE) 	int ret;
516a2f3d83cSJiri Slaby (SUSE) 	ssize_t bytes_transferred = 0;
517a2f3d83cSJiri Slaby (SUSE) 	__le32 tmp;
518a2f3d83cSJiri Slaby (SUSE) 
519a2f3d83cSJiri Slaby (SUSE) 	if (len == 6)
520a2f3d83cSJiri Slaby (SUSE) 		packet->data = 0;
521a2f3d83cSJiri Slaby (SUSE) 
522a2f3d83cSJiri Slaby (SUSE) #ifdef SISUSB_DONTSYNC
523a2f3d83cSJiri Slaby (SUSE) 	if (!(sisusb_wait_all_out_complete(sisusb)))
524a2f3d83cSJiri Slaby (SUSE) 		return 1;
525a2f3d83cSJiri Slaby (SUSE) #endif
526a2f3d83cSJiri Slaby (SUSE) 
527a2f3d83cSJiri Slaby (SUSE) 	/* Eventually correct endianness */
528a2f3d83cSJiri Slaby (SUSE) 	SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
529a2f3d83cSJiri Slaby (SUSE) 
530a2f3d83cSJiri Slaby (SUSE) 	/* 1. send the packet */
531a2f3d83cSJiri Slaby (SUSE) 	ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
532a2f3d83cSJiri Slaby (SUSE) 			(char *)packet, NULL, 0, &bytes_transferred, 0, 0);
533a2f3d83cSJiri Slaby (SUSE) 
534a2f3d83cSJiri Slaby (SUSE) 	if ((ret == 0) && (len == 6)) {
535a2f3d83cSJiri Slaby (SUSE) 
536a2f3d83cSJiri Slaby (SUSE) 		/* 2. if packet len == 6, it means we read, so wait for 32bit
537a2f3d83cSJiri Slaby (SUSE) 		 *    return value and write it to packet->data
538a2f3d83cSJiri Slaby (SUSE) 		 */
539a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
540a2f3d83cSJiri Slaby (SUSE) 				(char *)&tmp, NULL, &bytes_transferred, 0);
541a2f3d83cSJiri Slaby (SUSE) 
542a2f3d83cSJiri Slaby (SUSE) 		packet->data = le32_to_cpu(tmp);
543a2f3d83cSJiri Slaby (SUSE) 	}
544a2f3d83cSJiri Slaby (SUSE) 
545a2f3d83cSJiri Slaby (SUSE) 	return ret;
546a2f3d83cSJiri Slaby (SUSE) }
547a2f3d83cSJiri Slaby (SUSE) 
sisusb_send_bridge_packet(struct sisusb_usb_data * sisusb,int len,struct sisusb_packet * packet,unsigned int tflags)548a2f3d83cSJiri Slaby (SUSE) static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
549a2f3d83cSJiri Slaby (SUSE) 		struct sisusb_packet *packet, unsigned int tflags)
550a2f3d83cSJiri Slaby (SUSE) {
551a2f3d83cSJiri Slaby (SUSE) 	int ret;
552a2f3d83cSJiri Slaby (SUSE) 	ssize_t bytes_transferred = 0;
553a2f3d83cSJiri Slaby (SUSE) 	__le32 tmp;
554a2f3d83cSJiri Slaby (SUSE) 
555a2f3d83cSJiri Slaby (SUSE) 	if (len == 6)
556a2f3d83cSJiri Slaby (SUSE) 		packet->data = 0;
557a2f3d83cSJiri Slaby (SUSE) 
558a2f3d83cSJiri Slaby (SUSE) #ifdef SISUSB_DONTSYNC
559a2f3d83cSJiri Slaby (SUSE) 	if (!(sisusb_wait_all_out_complete(sisusb)))
560a2f3d83cSJiri Slaby (SUSE) 		return 1;
561a2f3d83cSJiri Slaby (SUSE) #endif
562a2f3d83cSJiri Slaby (SUSE) 
563a2f3d83cSJiri Slaby (SUSE) 	/* Eventually correct endianness */
564a2f3d83cSJiri Slaby (SUSE) 	SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
565a2f3d83cSJiri Slaby (SUSE) 
566a2f3d83cSJiri Slaby (SUSE) 	/* 1. send the packet */
567a2f3d83cSJiri Slaby (SUSE) 	ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
568a2f3d83cSJiri Slaby (SUSE) 			(char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
569a2f3d83cSJiri Slaby (SUSE) 
570a2f3d83cSJiri Slaby (SUSE) 	if ((ret == 0) && (len == 6)) {
571a2f3d83cSJiri Slaby (SUSE) 
572a2f3d83cSJiri Slaby (SUSE) 		/* 2. if packet len == 6, it means we read, so wait for 32bit
573a2f3d83cSJiri Slaby (SUSE) 		 *    return value and write it to packet->data
574a2f3d83cSJiri Slaby (SUSE) 		 */
575a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
576a2f3d83cSJiri Slaby (SUSE) 				(char *)&tmp, NULL, &bytes_transferred, 0);
577a2f3d83cSJiri Slaby (SUSE) 
578a2f3d83cSJiri Slaby (SUSE) 		packet->data = le32_to_cpu(tmp);
579a2f3d83cSJiri Slaby (SUSE) 	}
580a2f3d83cSJiri Slaby (SUSE) 
581a2f3d83cSJiri Slaby (SUSE) 	return ret;
582a2f3d83cSJiri Slaby (SUSE) }
583a2f3d83cSJiri Slaby (SUSE) 
584a2f3d83cSJiri Slaby (SUSE) /* access video memory and mmio (return 0 on success) */
585a2f3d83cSJiri Slaby (SUSE) 
586a2f3d83cSJiri Slaby (SUSE) /* Low level */
587a2f3d83cSJiri Slaby (SUSE) 
588a2f3d83cSJiri Slaby (SUSE) /* The following routines assume being used to transfer byte, word,
589a2f3d83cSJiri Slaby (SUSE)  * long etc.
590a2f3d83cSJiri Slaby (SUSE)  * This means that
591a2f3d83cSJiri Slaby (SUSE)  *   - the write routines expect "data" in machine endianness format.
592a2f3d83cSJiri Slaby (SUSE)  *     The data will be converted to leXX in sisusb_xxx_packet.
593a2f3d83cSJiri Slaby (SUSE)  *   - the read routines can expect read data in machine-endianess.
594a2f3d83cSJiri Slaby (SUSE)  */
595a2f3d83cSJiri Slaby (SUSE) 
sisusb_write_memio_byte(struct sisusb_usb_data * sisusb,int type,u32 addr,u8 data)596a2f3d83cSJiri Slaby (SUSE) static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
597a2f3d83cSJiri Slaby (SUSE) 		u32 addr, u8 data)
598a2f3d83cSJiri Slaby (SUSE) {
599a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
600a2f3d83cSJiri Slaby (SUSE) 
601a2f3d83cSJiri Slaby (SUSE) 	packet.header  = (1 << (addr & 3)) | (type << 6);
602a2f3d83cSJiri Slaby (SUSE) 	packet.address = addr & ~3;
603a2f3d83cSJiri Slaby (SUSE) 	packet.data    = data << ((addr & 3) << 3);
604a2f3d83cSJiri Slaby (SUSE) 	return sisusb_send_packet(sisusb, 10, &packet);
605a2f3d83cSJiri Slaby (SUSE) }
606a2f3d83cSJiri Slaby (SUSE) 
sisusb_write_memio_word(struct sisusb_usb_data * sisusb,int type,u32 addr,u16 data)607a2f3d83cSJiri Slaby (SUSE) static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
608a2f3d83cSJiri Slaby (SUSE) 		u32 addr, u16 data)
609a2f3d83cSJiri Slaby (SUSE) {
610a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
611a2f3d83cSJiri Slaby (SUSE) 	int ret = 0;
612a2f3d83cSJiri Slaby (SUSE) 
613a2f3d83cSJiri Slaby (SUSE) 	packet.address = addr & ~3;
614a2f3d83cSJiri Slaby (SUSE) 
615a2f3d83cSJiri Slaby (SUSE) 	switch (addr & 3) {
616a2f3d83cSJiri Slaby (SUSE) 	case 0:
617a2f3d83cSJiri Slaby (SUSE) 		packet.header = (type << 6) | 0x0003;
618a2f3d83cSJiri Slaby (SUSE) 		packet.data   = (u32)data;
619a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
620a2f3d83cSJiri Slaby (SUSE) 		break;
621a2f3d83cSJiri Slaby (SUSE) 	case 1:
622a2f3d83cSJiri Slaby (SUSE) 		packet.header = (type << 6) | 0x0006;
623a2f3d83cSJiri Slaby (SUSE) 		packet.data   = (u32)data << 8;
624a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
625a2f3d83cSJiri Slaby (SUSE) 		break;
626a2f3d83cSJiri Slaby (SUSE) 	case 2:
627a2f3d83cSJiri Slaby (SUSE) 		packet.header = (type << 6) | 0x000c;
628a2f3d83cSJiri Slaby (SUSE) 		packet.data   = (u32)data << 16;
629a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
630a2f3d83cSJiri Slaby (SUSE) 		break;
631a2f3d83cSJiri Slaby (SUSE) 	case 3:
632a2f3d83cSJiri Slaby (SUSE) 		packet.header = (type << 6) | 0x0008;
633a2f3d83cSJiri Slaby (SUSE) 		packet.data   = (u32)data << 24;
634a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
635a2f3d83cSJiri Slaby (SUSE) 		packet.header = (type << 6) | 0x0001;
636a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
637a2f3d83cSJiri Slaby (SUSE) 		packet.data   = (u32)data >> 8;
638a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 10, &packet);
639a2f3d83cSJiri Slaby (SUSE) 	}
640a2f3d83cSJiri Slaby (SUSE) 
641a2f3d83cSJiri Slaby (SUSE) 	return ret;
642a2f3d83cSJiri Slaby (SUSE) }
643a2f3d83cSJiri Slaby (SUSE) 
sisusb_write_memio_24bit(struct sisusb_usb_data * sisusb,int type,u32 addr,u32 data)644a2f3d83cSJiri Slaby (SUSE) static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
645a2f3d83cSJiri Slaby (SUSE) 		u32 addr, u32 data)
646a2f3d83cSJiri Slaby (SUSE) {
647a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
648a2f3d83cSJiri Slaby (SUSE) 	int ret = 0;
649a2f3d83cSJiri Slaby (SUSE) 
650a2f3d83cSJiri Slaby (SUSE) 	packet.address = addr & ~3;
651a2f3d83cSJiri Slaby (SUSE) 
652a2f3d83cSJiri Slaby (SUSE) 	switch (addr & 3) {
653a2f3d83cSJiri Slaby (SUSE) 	case 0:
654a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0007;
655a2f3d83cSJiri Slaby (SUSE) 		packet.data    = data & 0x00ffffff;
656a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
657a2f3d83cSJiri Slaby (SUSE) 		break;
658a2f3d83cSJiri Slaby (SUSE) 	case 1:
659a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x000e;
660a2f3d83cSJiri Slaby (SUSE) 		packet.data    = data << 8;
661a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
662a2f3d83cSJiri Slaby (SUSE) 		break;
663a2f3d83cSJiri Slaby (SUSE) 	case 2:
664a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x000c;
665a2f3d83cSJiri Slaby (SUSE) 		packet.data    = data << 16;
666a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
667a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0001;
668a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
669a2f3d83cSJiri Slaby (SUSE) 		packet.data    = (data >> 16) & 0x00ff;
670a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 10, &packet);
671a2f3d83cSJiri Slaby (SUSE) 		break;
672a2f3d83cSJiri Slaby (SUSE) 	case 3:
673a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0008;
674a2f3d83cSJiri Slaby (SUSE) 		packet.data    = data << 24;
675a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
676a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0003;
677a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
678a2f3d83cSJiri Slaby (SUSE) 		packet.data    = (data >> 8) & 0xffff;
679a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 10, &packet);
680a2f3d83cSJiri Slaby (SUSE) 	}
681a2f3d83cSJiri Slaby (SUSE) 
682a2f3d83cSJiri Slaby (SUSE) 	return ret;
683a2f3d83cSJiri Slaby (SUSE) }
684a2f3d83cSJiri Slaby (SUSE) 
sisusb_write_memio_long(struct sisusb_usb_data * sisusb,int type,u32 addr,u32 data)685a2f3d83cSJiri Slaby (SUSE) static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
686a2f3d83cSJiri Slaby (SUSE) 		u32 addr, u32 data)
687a2f3d83cSJiri Slaby (SUSE) {
688a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
689a2f3d83cSJiri Slaby (SUSE) 	int ret = 0;
690a2f3d83cSJiri Slaby (SUSE) 
691a2f3d83cSJiri Slaby (SUSE) 	packet.address = addr & ~3;
692a2f3d83cSJiri Slaby (SUSE) 
693a2f3d83cSJiri Slaby (SUSE) 	switch (addr & 3) {
694a2f3d83cSJiri Slaby (SUSE) 	case 0:
695a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x000f;
696a2f3d83cSJiri Slaby (SUSE) 		packet.data    = data;
697a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
698a2f3d83cSJiri Slaby (SUSE) 		break;
699a2f3d83cSJiri Slaby (SUSE) 	case 1:
700a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x000e;
701a2f3d83cSJiri Slaby (SUSE) 		packet.data    = data << 8;
702a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
703a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0001;
704a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
705a2f3d83cSJiri Slaby (SUSE) 		packet.data    = data >> 24;
706a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 10, &packet);
707a2f3d83cSJiri Slaby (SUSE) 		break;
708a2f3d83cSJiri Slaby (SUSE) 	case 2:
709a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x000c;
710a2f3d83cSJiri Slaby (SUSE) 		packet.data    = data << 16;
711a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
712a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0003;
713a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
714a2f3d83cSJiri Slaby (SUSE) 		packet.data    = data >> 16;
715a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 10, &packet);
716a2f3d83cSJiri Slaby (SUSE) 		break;
717a2f3d83cSJiri Slaby (SUSE) 	case 3:
718a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0008;
719a2f3d83cSJiri Slaby (SUSE) 		packet.data    = data << 24;
720a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 10, &packet);
721a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0007;
722a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
723a2f3d83cSJiri Slaby (SUSE) 		packet.data    = data >> 8;
724a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 10, &packet);
725a2f3d83cSJiri Slaby (SUSE) 	}
726a2f3d83cSJiri Slaby (SUSE) 
727a2f3d83cSJiri Slaby (SUSE) 	return ret;
728a2f3d83cSJiri Slaby (SUSE) }
729a2f3d83cSJiri Slaby (SUSE) 
730a2f3d83cSJiri Slaby (SUSE) /* The xxx_bulk routines copy a buffer of variable size. They treat the
731a2f3d83cSJiri Slaby (SUSE)  * buffer as chars, therefore lsb/msb has to be corrected if using the
732a2f3d83cSJiri Slaby (SUSE)  * byte/word/long/etc routines for speed-up
733a2f3d83cSJiri Slaby (SUSE)  *
734a2f3d83cSJiri Slaby (SUSE)  * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
735a2f3d83cSJiri Slaby (SUSE)  * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
736a2f3d83cSJiri Slaby (SUSE)  * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
737a2f3d83cSJiri Slaby (SUSE)  * that the data already is in the transfer buffer "sisusb->obuf[index]".
738a2f3d83cSJiri Slaby (SUSE)  */
739a2f3d83cSJiri Slaby (SUSE) 
sisusb_write_mem_bulk(struct sisusb_usb_data * sisusb,u32 addr,char * kernbuffer,int length,const char __user * userbuffer,int index,ssize_t * bytes_written)740a2f3d83cSJiri Slaby (SUSE) static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
741a2f3d83cSJiri Slaby (SUSE) 		char *kernbuffer, int length, const char __user *userbuffer,
742a2f3d83cSJiri Slaby (SUSE) 		int index, ssize_t *bytes_written)
743a2f3d83cSJiri Slaby (SUSE) {
744a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
745a2f3d83cSJiri Slaby (SUSE) 	int  ret = 0;
746a2f3d83cSJiri Slaby (SUSE) 	static int msgcount;
747a2f3d83cSJiri Slaby (SUSE) 	u8   swap8, fromkern = kernbuffer ? 1 : 0;
748a2f3d83cSJiri Slaby (SUSE) 	u16  swap16;
749a2f3d83cSJiri Slaby (SUSE) 	u32  swap32, flag = (length >> 28) & 1;
750a2f3d83cSJiri Slaby (SUSE) 	u8 buf[4];
751a2f3d83cSJiri Slaby (SUSE) 
752a2f3d83cSJiri Slaby (SUSE) 	/* if neither kernbuffer not userbuffer are given, assume
753a2f3d83cSJiri Slaby (SUSE) 	 * data in obuf
754a2f3d83cSJiri Slaby (SUSE) 	 */
755a2f3d83cSJiri Slaby (SUSE) 	if (!fromkern && !userbuffer)
756a2f3d83cSJiri Slaby (SUSE) 		kernbuffer = sisusb->obuf[index];
757a2f3d83cSJiri Slaby (SUSE) 
758a2f3d83cSJiri Slaby (SUSE) 	(*bytes_written = 0);
759a2f3d83cSJiri Slaby (SUSE) 
760a2f3d83cSJiri Slaby (SUSE) 	length &= 0x00ffffff;
761a2f3d83cSJiri Slaby (SUSE) 
762a2f3d83cSJiri Slaby (SUSE) 	while (length) {
763a2f3d83cSJiri Slaby (SUSE) 		switch (length) {
764a2f3d83cSJiri Slaby (SUSE) 		case 1:
765a2f3d83cSJiri Slaby (SUSE) 			if (userbuffer) {
766a2f3d83cSJiri Slaby (SUSE) 				if (get_user(swap8, (u8 __user *)userbuffer))
767a2f3d83cSJiri Slaby (SUSE) 					return -EFAULT;
768a2f3d83cSJiri Slaby (SUSE) 			} else
769a2f3d83cSJiri Slaby (SUSE) 				swap8 = kernbuffer[0];
770a2f3d83cSJiri Slaby (SUSE) 
771a2f3d83cSJiri Slaby (SUSE) 			ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM,
772a2f3d83cSJiri Slaby (SUSE) 					addr, swap8);
773a2f3d83cSJiri Slaby (SUSE) 
774a2f3d83cSJiri Slaby (SUSE) 			if (!ret)
775a2f3d83cSJiri Slaby (SUSE) 				(*bytes_written)++;
776a2f3d83cSJiri Slaby (SUSE) 
777a2f3d83cSJiri Slaby (SUSE) 			return ret;
778a2f3d83cSJiri Slaby (SUSE) 
779a2f3d83cSJiri Slaby (SUSE) 		case 2:
780a2f3d83cSJiri Slaby (SUSE) 			if (userbuffer) {
781a2f3d83cSJiri Slaby (SUSE) 				if (get_user(swap16, (u16 __user *)userbuffer))
782a2f3d83cSJiri Slaby (SUSE) 					return -EFAULT;
783a2f3d83cSJiri Slaby (SUSE) 			} else
784a2f3d83cSJiri Slaby (SUSE) 				swap16 = *((u16 *)kernbuffer);
785a2f3d83cSJiri Slaby (SUSE) 
786a2f3d83cSJiri Slaby (SUSE) 			ret = sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
787a2f3d83cSJiri Slaby (SUSE) 					addr, swap16);
788a2f3d83cSJiri Slaby (SUSE) 
789a2f3d83cSJiri Slaby (SUSE) 			if (!ret)
790a2f3d83cSJiri Slaby (SUSE) 				(*bytes_written) += 2;
791a2f3d83cSJiri Slaby (SUSE) 
792a2f3d83cSJiri Slaby (SUSE) 			return ret;
793a2f3d83cSJiri Slaby (SUSE) 
794a2f3d83cSJiri Slaby (SUSE) 		case 3:
795a2f3d83cSJiri Slaby (SUSE) 			if (userbuffer) {
796a2f3d83cSJiri Slaby (SUSE) 				if (copy_from_user(&buf, userbuffer, 3))
797a2f3d83cSJiri Slaby (SUSE) 					return -EFAULT;
798a2f3d83cSJiri Slaby (SUSE) #ifdef __BIG_ENDIAN
799a2f3d83cSJiri Slaby (SUSE) 				swap32 = (buf[0] << 16) |
800a2f3d83cSJiri Slaby (SUSE) 					 (buf[1] <<  8) |
801a2f3d83cSJiri Slaby (SUSE) 					 buf[2];
802a2f3d83cSJiri Slaby (SUSE) #else
803a2f3d83cSJiri Slaby (SUSE) 				swap32 = (buf[2] << 16) |
804a2f3d83cSJiri Slaby (SUSE) 					 (buf[1] <<  8) |
805a2f3d83cSJiri Slaby (SUSE) 					 buf[0];
806a2f3d83cSJiri Slaby (SUSE) #endif
807a2f3d83cSJiri Slaby (SUSE) 			} else
808a2f3d83cSJiri Slaby (SUSE) #ifdef __BIG_ENDIAN
809a2f3d83cSJiri Slaby (SUSE) 				swap32 = (kernbuffer[0] << 16) |
810a2f3d83cSJiri Slaby (SUSE) 					 (kernbuffer[1] <<  8) |
811a2f3d83cSJiri Slaby (SUSE) 					 kernbuffer[2];
812a2f3d83cSJiri Slaby (SUSE) #else
813a2f3d83cSJiri Slaby (SUSE) 				swap32 = (kernbuffer[2] << 16) |
814a2f3d83cSJiri Slaby (SUSE) 					 (kernbuffer[1] <<  8) |
815a2f3d83cSJiri Slaby (SUSE) 					 kernbuffer[0];
816a2f3d83cSJiri Slaby (SUSE) #endif
817a2f3d83cSJiri Slaby (SUSE) 
818a2f3d83cSJiri Slaby (SUSE) 			ret = sisusb_write_memio_24bit(sisusb, SISUSB_TYPE_MEM,
819a2f3d83cSJiri Slaby (SUSE) 					addr, swap32);
820a2f3d83cSJiri Slaby (SUSE) 
821a2f3d83cSJiri Slaby (SUSE) 			if (!ret)
822a2f3d83cSJiri Slaby (SUSE) 				(*bytes_written) += 3;
823a2f3d83cSJiri Slaby (SUSE) 
824a2f3d83cSJiri Slaby (SUSE) 			return ret;
825a2f3d83cSJiri Slaby (SUSE) 
826a2f3d83cSJiri Slaby (SUSE) 		case 4:
827a2f3d83cSJiri Slaby (SUSE) 			if (userbuffer) {
828a2f3d83cSJiri Slaby (SUSE) 				if (get_user(swap32, (u32 __user *)userbuffer))
829a2f3d83cSJiri Slaby (SUSE) 					return -EFAULT;
830a2f3d83cSJiri Slaby (SUSE) 			} else
831a2f3d83cSJiri Slaby (SUSE) 				swap32 = *((u32 *)kernbuffer);
832a2f3d83cSJiri Slaby (SUSE) 
833a2f3d83cSJiri Slaby (SUSE) 			ret = sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM,
834a2f3d83cSJiri Slaby (SUSE) 					addr, swap32);
835a2f3d83cSJiri Slaby (SUSE) 			if (!ret)
836a2f3d83cSJiri Slaby (SUSE) 				(*bytes_written) += 4;
837a2f3d83cSJiri Slaby (SUSE) 
838a2f3d83cSJiri Slaby (SUSE) 			return ret;
839a2f3d83cSJiri Slaby (SUSE) 
840a2f3d83cSJiri Slaby (SUSE) 		default:
841a2f3d83cSJiri Slaby (SUSE) 			if ((length & ~3) > 0x10000) {
842a2f3d83cSJiri Slaby (SUSE) 
843a2f3d83cSJiri Slaby (SUSE) 				packet.header  = 0x001f;
844a2f3d83cSJiri Slaby (SUSE) 				packet.address = 0x000001d4;
845a2f3d83cSJiri Slaby (SUSE) 				packet.data    = addr;
846a2f3d83cSJiri Slaby (SUSE) 				ret = sisusb_send_bridge_packet(sisusb, 10,
847a2f3d83cSJiri Slaby (SUSE) 						&packet, 0);
848a2f3d83cSJiri Slaby (SUSE) 				packet.header  = 0x001f;
849a2f3d83cSJiri Slaby (SUSE) 				packet.address = 0x000001d0;
850a2f3d83cSJiri Slaby (SUSE) 				packet.data    = (length & ~3);
851a2f3d83cSJiri Slaby (SUSE) 				ret |= sisusb_send_bridge_packet(sisusb, 10,
852a2f3d83cSJiri Slaby (SUSE) 						&packet, 0);
853a2f3d83cSJiri Slaby (SUSE) 				packet.header  = 0x001f;
854a2f3d83cSJiri Slaby (SUSE) 				packet.address = 0x000001c0;
855a2f3d83cSJiri Slaby (SUSE) 				packet.data    = flag | 0x16;
856a2f3d83cSJiri Slaby (SUSE) 				ret |= sisusb_send_bridge_packet(sisusb, 10,
857a2f3d83cSJiri Slaby (SUSE) 						&packet, 0);
858a2f3d83cSJiri Slaby (SUSE) 				if (userbuffer) {
859a2f3d83cSJiri Slaby (SUSE) 					ret |= sisusb_send_bulk_msg(sisusb,
860a2f3d83cSJiri Slaby (SUSE) 							SISUSB_EP_GFX_LBULK_OUT,
861a2f3d83cSJiri Slaby (SUSE) 							(length & ~3),
862a2f3d83cSJiri Slaby (SUSE) 							NULL, userbuffer, 0,
863a2f3d83cSJiri Slaby (SUSE) 							bytes_written, 0, 1);
864a2f3d83cSJiri Slaby (SUSE) 					userbuffer += (*bytes_written);
865a2f3d83cSJiri Slaby (SUSE) 				} else if (fromkern) {
866a2f3d83cSJiri Slaby (SUSE) 					ret |= sisusb_send_bulk_msg(sisusb,
867a2f3d83cSJiri Slaby (SUSE) 							SISUSB_EP_GFX_LBULK_OUT,
868a2f3d83cSJiri Slaby (SUSE) 							(length & ~3),
869a2f3d83cSJiri Slaby (SUSE) 							kernbuffer, NULL, 0,
870a2f3d83cSJiri Slaby (SUSE) 							bytes_written, 0, 1);
871a2f3d83cSJiri Slaby (SUSE) 					kernbuffer += (*bytes_written);
872a2f3d83cSJiri Slaby (SUSE) 				} else {
873a2f3d83cSJiri Slaby (SUSE) 					ret |= sisusb_send_bulk_msg(sisusb,
874a2f3d83cSJiri Slaby (SUSE) 							SISUSB_EP_GFX_LBULK_OUT,
875a2f3d83cSJiri Slaby (SUSE) 							(length & ~3),
876a2f3d83cSJiri Slaby (SUSE) 							NULL, NULL, index,
877a2f3d83cSJiri Slaby (SUSE) 							bytes_written, 0, 1);
878a2f3d83cSJiri Slaby (SUSE) 					kernbuffer += ((*bytes_written) &
879a2f3d83cSJiri Slaby (SUSE) 							(sisusb->obufsize-1));
880a2f3d83cSJiri Slaby (SUSE) 				}
881a2f3d83cSJiri Slaby (SUSE) 
882a2f3d83cSJiri Slaby (SUSE) 			} else {
883a2f3d83cSJiri Slaby (SUSE) 
884a2f3d83cSJiri Slaby (SUSE) 				packet.header  = 0x001f;
885a2f3d83cSJiri Slaby (SUSE) 				packet.address = 0x00000194;
886a2f3d83cSJiri Slaby (SUSE) 				packet.data    = addr;
887a2f3d83cSJiri Slaby (SUSE) 				ret = sisusb_send_bridge_packet(sisusb, 10,
888a2f3d83cSJiri Slaby (SUSE) 						&packet, 0);
889a2f3d83cSJiri Slaby (SUSE) 				packet.header  = 0x001f;
890a2f3d83cSJiri Slaby (SUSE) 				packet.address = 0x00000190;
891a2f3d83cSJiri Slaby (SUSE) 				packet.data    = (length & ~3);
892a2f3d83cSJiri Slaby (SUSE) 				ret |= sisusb_send_bridge_packet(sisusb, 10,
893a2f3d83cSJiri Slaby (SUSE) 						&packet, 0);
894a2f3d83cSJiri Slaby (SUSE) 				if (sisusb->flagb0 != 0x16) {
895a2f3d83cSJiri Slaby (SUSE) 					packet.header  = 0x001f;
896a2f3d83cSJiri Slaby (SUSE) 					packet.address = 0x00000180;
897a2f3d83cSJiri Slaby (SUSE) 					packet.data    = flag | 0x16;
898a2f3d83cSJiri Slaby (SUSE) 					ret |= sisusb_send_bridge_packet(sisusb,
899a2f3d83cSJiri Slaby (SUSE) 							10, &packet, 0);
900a2f3d83cSJiri Slaby (SUSE) 					sisusb->flagb0 = 0x16;
901a2f3d83cSJiri Slaby (SUSE) 				}
902a2f3d83cSJiri Slaby (SUSE) 				if (userbuffer) {
903a2f3d83cSJiri Slaby (SUSE) 					ret |= sisusb_send_bulk_msg(sisusb,
904a2f3d83cSJiri Slaby (SUSE) 							SISUSB_EP_GFX_BULK_OUT,
905a2f3d83cSJiri Slaby (SUSE) 							(length & ~3),
906a2f3d83cSJiri Slaby (SUSE) 							NULL, userbuffer, 0,
907a2f3d83cSJiri Slaby (SUSE) 							bytes_written, 0, 1);
908a2f3d83cSJiri Slaby (SUSE) 					userbuffer += (*bytes_written);
909a2f3d83cSJiri Slaby (SUSE) 				} else if (fromkern) {
910a2f3d83cSJiri Slaby (SUSE) 					ret |= sisusb_send_bulk_msg(sisusb,
911a2f3d83cSJiri Slaby (SUSE) 							SISUSB_EP_GFX_BULK_OUT,
912a2f3d83cSJiri Slaby (SUSE) 							(length & ~3),
913a2f3d83cSJiri Slaby (SUSE) 							kernbuffer, NULL, 0,
914a2f3d83cSJiri Slaby (SUSE) 							bytes_written, 0, 1);
915a2f3d83cSJiri Slaby (SUSE) 					kernbuffer += (*bytes_written);
916a2f3d83cSJiri Slaby (SUSE) 				} else {
917a2f3d83cSJiri Slaby (SUSE) 					ret |= sisusb_send_bulk_msg(sisusb,
918a2f3d83cSJiri Slaby (SUSE) 							SISUSB_EP_GFX_BULK_OUT,
919a2f3d83cSJiri Slaby (SUSE) 							(length & ~3),
920a2f3d83cSJiri Slaby (SUSE) 							NULL, NULL, index,
921a2f3d83cSJiri Slaby (SUSE) 							bytes_written, 0, 1);
922a2f3d83cSJiri Slaby (SUSE) 					kernbuffer += ((*bytes_written) &
923a2f3d83cSJiri Slaby (SUSE) 							(sisusb->obufsize-1));
924a2f3d83cSJiri Slaby (SUSE) 				}
925a2f3d83cSJiri Slaby (SUSE) 			}
926a2f3d83cSJiri Slaby (SUSE) 			if (ret) {
927a2f3d83cSJiri Slaby (SUSE) 				msgcount++;
928a2f3d83cSJiri Slaby (SUSE) 				if (msgcount < 500)
929a2f3d83cSJiri Slaby (SUSE) 					dev_err(&sisusb->sisusb_dev->dev,
930a2f3d83cSJiri Slaby (SUSE) 							"Wrote %zd of %d bytes, error %d\n",
931a2f3d83cSJiri Slaby (SUSE) 							*bytes_written, length,
932a2f3d83cSJiri Slaby (SUSE) 							ret);
933a2f3d83cSJiri Slaby (SUSE) 				else if (msgcount == 500)
934a2f3d83cSJiri Slaby (SUSE) 					dev_err(&sisusb->sisusb_dev->dev,
935a2f3d83cSJiri Slaby (SUSE) 							"Too many errors, logging stopped\n");
936a2f3d83cSJiri Slaby (SUSE) 			}
937a2f3d83cSJiri Slaby (SUSE) 			addr += (*bytes_written);
938a2f3d83cSJiri Slaby (SUSE) 			length -= (*bytes_written);
939a2f3d83cSJiri Slaby (SUSE) 		}
940a2f3d83cSJiri Slaby (SUSE) 
941a2f3d83cSJiri Slaby (SUSE) 		if (ret)
942a2f3d83cSJiri Slaby (SUSE) 			break;
943a2f3d83cSJiri Slaby (SUSE) 
944a2f3d83cSJiri Slaby (SUSE) 	}
945a2f3d83cSJiri Slaby (SUSE) 
946a2f3d83cSJiri Slaby (SUSE) 	return ret ? -EIO : 0;
947a2f3d83cSJiri Slaby (SUSE) }
948a2f3d83cSJiri Slaby (SUSE) 
949a2f3d83cSJiri Slaby (SUSE) /* Remember: Read data in packet is in machine-endianess! So for
950a2f3d83cSJiri Slaby (SUSE)  * byte, word, 24bit, long no endian correction is necessary.
951a2f3d83cSJiri Slaby (SUSE)  */
952a2f3d83cSJiri Slaby (SUSE) 
sisusb_read_memio_byte(struct sisusb_usb_data * sisusb,int type,u32 addr,u8 * data)953a2f3d83cSJiri Slaby (SUSE) static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
954a2f3d83cSJiri Slaby (SUSE) 		u32 addr, u8 *data)
955a2f3d83cSJiri Slaby (SUSE) {
956a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
957a2f3d83cSJiri Slaby (SUSE) 	int ret;
958a2f3d83cSJiri Slaby (SUSE) 
959a2f3d83cSJiri Slaby (SUSE) 	CLEARPACKET(&packet);
960a2f3d83cSJiri Slaby (SUSE) 	packet.header  = (1 << (addr & 3)) | (type << 6);
961a2f3d83cSJiri Slaby (SUSE) 	packet.address = addr & ~3;
962a2f3d83cSJiri Slaby (SUSE) 	ret = sisusb_send_packet(sisusb, 6, &packet);
963a2f3d83cSJiri Slaby (SUSE) 	*data = (u8)(packet.data >> ((addr & 3) << 3));
964a2f3d83cSJiri Slaby (SUSE) 	return ret;
965a2f3d83cSJiri Slaby (SUSE) }
966a2f3d83cSJiri Slaby (SUSE) 
sisusb_read_memio_word(struct sisusb_usb_data * sisusb,int type,u32 addr,u16 * data)967a2f3d83cSJiri Slaby (SUSE) static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
968a2f3d83cSJiri Slaby (SUSE) 		u32 addr, u16 *data)
969a2f3d83cSJiri Slaby (SUSE) {
970a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
971a2f3d83cSJiri Slaby (SUSE) 	int ret = 0;
972a2f3d83cSJiri Slaby (SUSE) 
973a2f3d83cSJiri Slaby (SUSE) 	CLEARPACKET(&packet);
974a2f3d83cSJiri Slaby (SUSE) 
975a2f3d83cSJiri Slaby (SUSE) 	packet.address = addr & ~3;
976a2f3d83cSJiri Slaby (SUSE) 
977a2f3d83cSJiri Slaby (SUSE) 	switch (addr & 3) {
978a2f3d83cSJiri Slaby (SUSE) 	case 0:
979a2f3d83cSJiri Slaby (SUSE) 		packet.header = (type << 6) | 0x0003;
980a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
981a2f3d83cSJiri Slaby (SUSE) 		*data = (u16)(packet.data);
982a2f3d83cSJiri Slaby (SUSE) 		break;
983a2f3d83cSJiri Slaby (SUSE) 	case 1:
984a2f3d83cSJiri Slaby (SUSE) 		packet.header = (type << 6) | 0x0006;
985a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
986a2f3d83cSJiri Slaby (SUSE) 		*data = (u16)(packet.data >> 8);
987a2f3d83cSJiri Slaby (SUSE) 		break;
988a2f3d83cSJiri Slaby (SUSE) 	case 2:
989a2f3d83cSJiri Slaby (SUSE) 		packet.header = (type << 6) | 0x000c;
990a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
991a2f3d83cSJiri Slaby (SUSE) 		*data = (u16)(packet.data >> 16);
992a2f3d83cSJiri Slaby (SUSE) 		break;
993a2f3d83cSJiri Slaby (SUSE) 	case 3:
994a2f3d83cSJiri Slaby (SUSE) 		packet.header = (type << 6) | 0x0008;
995a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
996a2f3d83cSJiri Slaby (SUSE) 		*data = (u16)(packet.data >> 24);
997a2f3d83cSJiri Slaby (SUSE) 		packet.header = (type << 6) | 0x0001;
998a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
999a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 6, &packet);
1000a2f3d83cSJiri Slaby (SUSE) 		*data |= (u16)(packet.data << 8);
1001a2f3d83cSJiri Slaby (SUSE) 	}
1002a2f3d83cSJiri Slaby (SUSE) 
1003a2f3d83cSJiri Slaby (SUSE) 	return ret;
1004a2f3d83cSJiri Slaby (SUSE) }
1005a2f3d83cSJiri Slaby (SUSE) 
sisusb_read_memio_24bit(struct sisusb_usb_data * sisusb,int type,u32 addr,u32 * data)1006a2f3d83cSJiri Slaby (SUSE) static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1007a2f3d83cSJiri Slaby (SUSE) 		u32 addr, u32 *data)
1008a2f3d83cSJiri Slaby (SUSE) {
1009a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
1010a2f3d83cSJiri Slaby (SUSE) 	int ret = 0;
1011a2f3d83cSJiri Slaby (SUSE) 
1012a2f3d83cSJiri Slaby (SUSE) 	packet.address = addr & ~3;
1013a2f3d83cSJiri Slaby (SUSE) 
1014a2f3d83cSJiri Slaby (SUSE) 	switch (addr & 3) {
1015a2f3d83cSJiri Slaby (SUSE) 	case 0:
1016a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0007;
1017a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
1018a2f3d83cSJiri Slaby (SUSE) 		*data = packet.data & 0x00ffffff;
1019a2f3d83cSJiri Slaby (SUSE) 		break;
1020a2f3d83cSJiri Slaby (SUSE) 	case 1:
1021a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x000e;
1022a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
1023a2f3d83cSJiri Slaby (SUSE) 		*data = packet.data >> 8;
1024a2f3d83cSJiri Slaby (SUSE) 		break;
1025a2f3d83cSJiri Slaby (SUSE) 	case 2:
1026a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x000c;
1027a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
1028a2f3d83cSJiri Slaby (SUSE) 		*data = packet.data >> 16;
1029a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0001;
1030a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
1031a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 6, &packet);
1032a2f3d83cSJiri Slaby (SUSE) 		*data |= ((packet.data & 0xff) << 16);
1033a2f3d83cSJiri Slaby (SUSE) 		break;
1034a2f3d83cSJiri Slaby (SUSE) 	case 3:
1035a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0008;
1036a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
1037a2f3d83cSJiri Slaby (SUSE) 		*data = packet.data >> 24;
1038a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0003;
1039a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
1040a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 6, &packet);
1041a2f3d83cSJiri Slaby (SUSE) 		*data |= ((packet.data & 0xffff) << 8);
1042a2f3d83cSJiri Slaby (SUSE) 	}
1043a2f3d83cSJiri Slaby (SUSE) 
1044a2f3d83cSJiri Slaby (SUSE) 	return ret;
1045a2f3d83cSJiri Slaby (SUSE) }
1046a2f3d83cSJiri Slaby (SUSE) 
sisusb_read_memio_long(struct sisusb_usb_data * sisusb,int type,u32 addr,u32 * data)1047a2f3d83cSJiri Slaby (SUSE) static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1048a2f3d83cSJiri Slaby (SUSE) 		u32 addr, u32 *data)
1049a2f3d83cSJiri Slaby (SUSE) {
1050a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
1051a2f3d83cSJiri Slaby (SUSE) 	int ret = 0;
1052a2f3d83cSJiri Slaby (SUSE) 
1053a2f3d83cSJiri Slaby (SUSE) 	packet.address = addr & ~3;
1054a2f3d83cSJiri Slaby (SUSE) 
1055a2f3d83cSJiri Slaby (SUSE) 	switch (addr & 3) {
1056a2f3d83cSJiri Slaby (SUSE) 	case 0:
1057a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x000f;
1058a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
1059a2f3d83cSJiri Slaby (SUSE) 		*data = packet.data;
1060a2f3d83cSJiri Slaby (SUSE) 		break;
1061a2f3d83cSJiri Slaby (SUSE) 	case 1:
1062a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x000e;
1063a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
1064a2f3d83cSJiri Slaby (SUSE) 		*data = packet.data >> 8;
1065a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0001;
1066a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
1067a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 6, &packet);
1068a2f3d83cSJiri Slaby (SUSE) 		*data |= (packet.data << 24);
1069a2f3d83cSJiri Slaby (SUSE) 		break;
1070a2f3d83cSJiri Slaby (SUSE) 	case 2:
1071a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x000c;
1072a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
1073a2f3d83cSJiri Slaby (SUSE) 		*data = packet.data >> 16;
1074a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0003;
1075a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
1076a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 6, &packet);
1077a2f3d83cSJiri Slaby (SUSE) 		*data |= (packet.data << 16);
1078a2f3d83cSJiri Slaby (SUSE) 		break;
1079a2f3d83cSJiri Slaby (SUSE) 	case 3:
1080a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0008;
1081a2f3d83cSJiri Slaby (SUSE) 		ret = sisusb_send_packet(sisusb, 6, &packet);
1082a2f3d83cSJiri Slaby (SUSE) 		*data = packet.data >> 24;
1083a2f3d83cSJiri Slaby (SUSE) 		packet.header  = (type << 6) | 0x0007;
1084a2f3d83cSJiri Slaby (SUSE) 		packet.address = (addr & ~3) + 4;
1085a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_packet(sisusb, 6, &packet);
1086a2f3d83cSJiri Slaby (SUSE) 		*data |= (packet.data << 8);
1087a2f3d83cSJiri Slaby (SUSE) 	}
1088a2f3d83cSJiri Slaby (SUSE) 
1089a2f3d83cSJiri Slaby (SUSE) 	return ret;
1090a2f3d83cSJiri Slaby (SUSE) }
1091a2f3d83cSJiri Slaby (SUSE) 
sisusb_read_mem_bulk(struct sisusb_usb_data * sisusb,u32 addr,char * kernbuffer,int length,char __user * userbuffer,ssize_t * bytes_read)1092a2f3d83cSJiri Slaby (SUSE) static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1093a2f3d83cSJiri Slaby (SUSE) 		char *kernbuffer, int length, char __user *userbuffer,
1094a2f3d83cSJiri Slaby (SUSE) 		ssize_t *bytes_read)
1095a2f3d83cSJiri Slaby (SUSE) {
1096a2f3d83cSJiri Slaby (SUSE) 	int ret = 0;
1097a2f3d83cSJiri Slaby (SUSE) 	char buf[4];
1098a2f3d83cSJiri Slaby (SUSE) 	u16 swap16;
1099a2f3d83cSJiri Slaby (SUSE) 	u32 swap32;
1100a2f3d83cSJiri Slaby (SUSE) 
1101a2f3d83cSJiri Slaby (SUSE) 	(*bytes_read = 0);
1102a2f3d83cSJiri Slaby (SUSE) 
1103a2f3d83cSJiri Slaby (SUSE) 	length &= 0x00ffffff;
1104a2f3d83cSJiri Slaby (SUSE) 
1105a2f3d83cSJiri Slaby (SUSE) 	while (length) {
1106a2f3d83cSJiri Slaby (SUSE) 		switch (length) {
1107a2f3d83cSJiri Slaby (SUSE) 		case 1:
1108a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1109a2f3d83cSJiri Slaby (SUSE) 					addr, &buf[0]);
1110a2f3d83cSJiri Slaby (SUSE) 			if (!ret) {
1111a2f3d83cSJiri Slaby (SUSE) 				(*bytes_read)++;
1112a2f3d83cSJiri Slaby (SUSE) 				if (userbuffer) {
1113a2f3d83cSJiri Slaby (SUSE) 					if (put_user(buf[0], (u8 __user *)userbuffer))
1114a2f3d83cSJiri Slaby (SUSE) 						return -EFAULT;
1115a2f3d83cSJiri Slaby (SUSE) 				} else
1116a2f3d83cSJiri Slaby (SUSE) 					kernbuffer[0] = buf[0];
1117a2f3d83cSJiri Slaby (SUSE) 			}
1118a2f3d83cSJiri Slaby (SUSE) 			return ret;
1119a2f3d83cSJiri Slaby (SUSE) 
1120a2f3d83cSJiri Slaby (SUSE) 		case 2:
1121a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1122a2f3d83cSJiri Slaby (SUSE) 					addr, &swap16);
1123a2f3d83cSJiri Slaby (SUSE) 			if (!ret) {
1124a2f3d83cSJiri Slaby (SUSE) 				(*bytes_read) += 2;
1125a2f3d83cSJiri Slaby (SUSE) 				if (userbuffer) {
1126a2f3d83cSJiri Slaby (SUSE) 					if (put_user(swap16, (u16 __user *)userbuffer))
1127a2f3d83cSJiri Slaby (SUSE) 						return -EFAULT;
1128a2f3d83cSJiri Slaby (SUSE) 				} else {
1129a2f3d83cSJiri Slaby (SUSE) 					*((u16 *)kernbuffer) = swap16;
1130a2f3d83cSJiri Slaby (SUSE) 				}
1131a2f3d83cSJiri Slaby (SUSE) 			}
1132a2f3d83cSJiri Slaby (SUSE) 			return ret;
1133a2f3d83cSJiri Slaby (SUSE) 
1134a2f3d83cSJiri Slaby (SUSE) 		case 3:
1135a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1136a2f3d83cSJiri Slaby (SUSE) 					addr, &swap32);
1137a2f3d83cSJiri Slaby (SUSE) 			if (!ret) {
1138a2f3d83cSJiri Slaby (SUSE) 				(*bytes_read) += 3;
1139a2f3d83cSJiri Slaby (SUSE) #ifdef __BIG_ENDIAN
1140a2f3d83cSJiri Slaby (SUSE) 				buf[0] = (swap32 >> 16) & 0xff;
1141a2f3d83cSJiri Slaby (SUSE) 				buf[1] = (swap32 >> 8) & 0xff;
1142a2f3d83cSJiri Slaby (SUSE) 				buf[2] = swap32 & 0xff;
1143a2f3d83cSJiri Slaby (SUSE) #else
1144a2f3d83cSJiri Slaby (SUSE) 				buf[2] = (swap32 >> 16) & 0xff;
1145a2f3d83cSJiri Slaby (SUSE) 				buf[1] = (swap32 >> 8) & 0xff;
1146a2f3d83cSJiri Slaby (SUSE) 				buf[0] = swap32 & 0xff;
1147a2f3d83cSJiri Slaby (SUSE) #endif
1148a2f3d83cSJiri Slaby (SUSE) 				if (userbuffer) {
1149a2f3d83cSJiri Slaby (SUSE) 					if (copy_to_user(userbuffer,
1150a2f3d83cSJiri Slaby (SUSE) 							&buf[0], 3))
1151a2f3d83cSJiri Slaby (SUSE) 						return -EFAULT;
1152a2f3d83cSJiri Slaby (SUSE) 				} else {
1153a2f3d83cSJiri Slaby (SUSE) 					kernbuffer[0] = buf[0];
1154a2f3d83cSJiri Slaby (SUSE) 					kernbuffer[1] = buf[1];
1155a2f3d83cSJiri Slaby (SUSE) 					kernbuffer[2] = buf[2];
1156a2f3d83cSJiri Slaby (SUSE) 				}
1157a2f3d83cSJiri Slaby (SUSE) 			}
1158a2f3d83cSJiri Slaby (SUSE) 			return ret;
1159a2f3d83cSJiri Slaby (SUSE) 
1160a2f3d83cSJiri Slaby (SUSE) 		default:
1161a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1162a2f3d83cSJiri Slaby (SUSE) 					addr, &swap32);
1163a2f3d83cSJiri Slaby (SUSE) 			if (!ret) {
1164a2f3d83cSJiri Slaby (SUSE) 				(*bytes_read) += 4;
1165a2f3d83cSJiri Slaby (SUSE) 				if (userbuffer) {
1166a2f3d83cSJiri Slaby (SUSE) 					if (put_user(swap32, (u32 __user *)userbuffer))
1167a2f3d83cSJiri Slaby (SUSE) 						return -EFAULT;
1168a2f3d83cSJiri Slaby (SUSE) 
1169a2f3d83cSJiri Slaby (SUSE) 					userbuffer += 4;
1170a2f3d83cSJiri Slaby (SUSE) 				} else {
1171a2f3d83cSJiri Slaby (SUSE) 					*((u32 *)kernbuffer) = swap32;
1172a2f3d83cSJiri Slaby (SUSE) 					kernbuffer += 4;
1173a2f3d83cSJiri Slaby (SUSE) 				}
1174a2f3d83cSJiri Slaby (SUSE) 				addr += 4;
1175a2f3d83cSJiri Slaby (SUSE) 				length -= 4;
1176a2f3d83cSJiri Slaby (SUSE) 			}
1177a2f3d83cSJiri Slaby (SUSE) 		}
1178a2f3d83cSJiri Slaby (SUSE) 		if (ret)
1179a2f3d83cSJiri Slaby (SUSE) 			break;
1180a2f3d83cSJiri Slaby (SUSE) 	}
1181a2f3d83cSJiri Slaby (SUSE) 
1182a2f3d83cSJiri Slaby (SUSE) 	return ret;
1183a2f3d83cSJiri Slaby (SUSE) }
1184a2f3d83cSJiri Slaby (SUSE) 
1185a2f3d83cSJiri Slaby (SUSE) /* High level: Gfx (indexed) register access */
1186a2f3d83cSJiri Slaby (SUSE) 
sisusb_setidxreg(struct sisusb_usb_data * sisusb,u32 port,u8 index,u8 data)1187a2f3d83cSJiri Slaby (SUSE) static int sisusb_setidxreg(struct sisusb_usb_data *sisusb, u32 port,
1188a2f3d83cSJiri Slaby (SUSE) 		u8 index, u8 data)
1189a2f3d83cSJiri Slaby (SUSE) {
1190a2f3d83cSJiri Slaby (SUSE) 	int ret;
1191a2f3d83cSJiri Slaby (SUSE) 
1192a2f3d83cSJiri Slaby (SUSE) 	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1193a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1194a2f3d83cSJiri Slaby (SUSE) 	return ret;
1195a2f3d83cSJiri Slaby (SUSE) }
1196a2f3d83cSJiri Slaby (SUSE) 
sisusb_getidxreg(struct sisusb_usb_data * sisusb,u32 port,u8 index,u8 * data)1197a2f3d83cSJiri Slaby (SUSE) static int sisusb_getidxreg(struct sisusb_usb_data *sisusb, u32 port,
1198a2f3d83cSJiri Slaby (SUSE) 		u8 index, u8 *data)
1199a2f3d83cSJiri Slaby (SUSE) {
1200a2f3d83cSJiri Slaby (SUSE) 	int ret;
1201a2f3d83cSJiri Slaby (SUSE) 
1202a2f3d83cSJiri Slaby (SUSE) 	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1203a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1204a2f3d83cSJiri Slaby (SUSE) 	return ret;
1205a2f3d83cSJiri Slaby (SUSE) }
1206a2f3d83cSJiri Slaby (SUSE) 
sisusb_setidxregandor(struct sisusb_usb_data * sisusb,u32 port,u8 idx,u8 myand,u8 myor)1207a2f3d83cSJiri Slaby (SUSE) static int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, u32 port, u8 idx,
1208a2f3d83cSJiri Slaby (SUSE) 		u8 myand, u8 myor)
1209a2f3d83cSJiri Slaby (SUSE) {
1210a2f3d83cSJiri Slaby (SUSE) 	int ret;
1211a2f3d83cSJiri Slaby (SUSE) 	u8 tmp;
1212a2f3d83cSJiri Slaby (SUSE) 
1213a2f3d83cSJiri Slaby (SUSE) 	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1214a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1215a2f3d83cSJiri Slaby (SUSE) 	tmp &= myand;
1216a2f3d83cSJiri Slaby (SUSE) 	tmp |= myor;
1217a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1218a2f3d83cSJiri Slaby (SUSE) 	return ret;
1219a2f3d83cSJiri Slaby (SUSE) }
1220a2f3d83cSJiri Slaby (SUSE) 
sisusb_setidxregmask(struct sisusb_usb_data * sisusb,u32 port,u8 idx,u8 data,u8 mask)1221a2f3d83cSJiri Slaby (SUSE) static int sisusb_setidxregmask(struct sisusb_usb_data *sisusb,
1222a2f3d83cSJiri Slaby (SUSE) 		u32 port, u8 idx, u8 data, u8 mask)
1223a2f3d83cSJiri Slaby (SUSE) {
1224a2f3d83cSJiri Slaby (SUSE) 	int ret;
1225a2f3d83cSJiri Slaby (SUSE) 	u8 tmp;
1226a2f3d83cSJiri Slaby (SUSE) 
1227a2f3d83cSJiri Slaby (SUSE) 	ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1228a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1229a2f3d83cSJiri Slaby (SUSE) 	tmp &= ~(mask);
1230a2f3d83cSJiri Slaby (SUSE) 	tmp |= (data & mask);
1231a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1232a2f3d83cSJiri Slaby (SUSE) 	return ret;
1233a2f3d83cSJiri Slaby (SUSE) }
1234a2f3d83cSJiri Slaby (SUSE) 
sisusb_setidxregor(struct sisusb_usb_data * sisusb,u32 port,u8 index,u8 myor)1235a2f3d83cSJiri Slaby (SUSE) static int sisusb_setidxregor(struct sisusb_usb_data *sisusb, u32 port,
1236a2f3d83cSJiri Slaby (SUSE) 		u8 index, u8 myor)
1237a2f3d83cSJiri Slaby (SUSE) {
1238a2f3d83cSJiri Slaby (SUSE) 	return sisusb_setidxregandor(sisusb, port, index, 0xff, myor);
1239a2f3d83cSJiri Slaby (SUSE) }
1240a2f3d83cSJiri Slaby (SUSE) 
sisusb_setidxregand(struct sisusb_usb_data * sisusb,u32 port,u8 idx,u8 myand)1241a2f3d83cSJiri Slaby (SUSE) static int sisusb_setidxregand(struct sisusb_usb_data *sisusb, u32 port,
1242a2f3d83cSJiri Slaby (SUSE) 		u8 idx, u8 myand)
1243a2f3d83cSJiri Slaby (SUSE) {
1244a2f3d83cSJiri Slaby (SUSE) 	return sisusb_setidxregandor(sisusb, port, idx, myand, 0x00);
1245a2f3d83cSJiri Slaby (SUSE) }
1246a2f3d83cSJiri Slaby (SUSE) 
1247a2f3d83cSJiri Slaby (SUSE) /* Write/read video ram */
1248a2f3d83cSJiri Slaby (SUSE) 
1249a2f3d83cSJiri Slaby (SUSE) #ifdef SISUSBENDIANTEST
sisusb_testreadwrite(struct sisusb_usb_data * sisusb)1250a2f3d83cSJiri Slaby (SUSE) static void sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
1251a2f3d83cSJiri Slaby (SUSE) {
1252a2f3d83cSJiri Slaby (SUSE) 	static u8 srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
1253a2f3d83cSJiri Slaby (SUSE) 	char destbuffer[10];
1254a2f3d83cSJiri Slaby (SUSE) 	int i, j;
1255a2f3d83cSJiri Slaby (SUSE) 
1256a2f3d83cSJiri Slaby (SUSE) 	sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7);
1257a2f3d83cSJiri Slaby (SUSE) 
1258a2f3d83cSJiri Slaby (SUSE) 	for (i = 1; i <= 7; i++) {
1259a2f3d83cSJiri Slaby (SUSE) 		dev_dbg(&sisusb->sisusb_dev->dev,
1260a2f3d83cSJiri Slaby (SUSE) 				"sisusb: rwtest %d bytes\n", i);
1261a2f3d83cSJiri Slaby (SUSE) 		sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i);
1262a2f3d83cSJiri Slaby (SUSE) 		for (j = 0; j < i; j++) {
1263a2f3d83cSJiri Slaby (SUSE) 			dev_dbg(&sisusb->sisusb_dev->dev,
1264a2f3d83cSJiri Slaby (SUSE) 					"rwtest read[%d] = %x\n",
1265a2f3d83cSJiri Slaby (SUSE) 					j, destbuffer[j]);
1266a2f3d83cSJiri Slaby (SUSE) 		}
1267a2f3d83cSJiri Slaby (SUSE) 	}
1268a2f3d83cSJiri Slaby (SUSE) }
1269a2f3d83cSJiri Slaby (SUSE) #endif
1270a2f3d83cSJiri Slaby (SUSE) 
1271a2f3d83cSJiri Slaby (SUSE) /* access pci config registers (reg numbers 0, 4, 8, etc) */
1272a2f3d83cSJiri Slaby (SUSE) 
sisusb_write_pci_config(struct sisusb_usb_data * sisusb,int regnum,u32 data)1273a2f3d83cSJiri Slaby (SUSE) static int sisusb_write_pci_config(struct sisusb_usb_data *sisusb,
1274a2f3d83cSJiri Slaby (SUSE) 		int regnum, u32 data)
1275a2f3d83cSJiri Slaby (SUSE) {
1276a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
1277a2f3d83cSJiri Slaby (SUSE) 
1278a2f3d83cSJiri Slaby (SUSE) 	packet.header = 0x008f;
1279a2f3d83cSJiri Slaby (SUSE) 	packet.address = regnum | 0x10000;
1280a2f3d83cSJiri Slaby (SUSE) 	packet.data = data;
1281a2f3d83cSJiri Slaby (SUSE) 	return sisusb_send_packet(sisusb, 10, &packet);
1282a2f3d83cSJiri Slaby (SUSE) }
1283a2f3d83cSJiri Slaby (SUSE) 
sisusb_read_pci_config(struct sisusb_usb_data * sisusb,int regnum,u32 * data)1284a2f3d83cSJiri Slaby (SUSE) static int sisusb_read_pci_config(struct sisusb_usb_data *sisusb,
1285a2f3d83cSJiri Slaby (SUSE) 		int regnum, u32 *data)
1286a2f3d83cSJiri Slaby (SUSE) {
1287a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
1288a2f3d83cSJiri Slaby (SUSE) 	int ret;
1289a2f3d83cSJiri Slaby (SUSE) 
1290a2f3d83cSJiri Slaby (SUSE) 	packet.header = 0x008f;
1291a2f3d83cSJiri Slaby (SUSE) 	packet.address = (u32)regnum | 0x10000;
1292a2f3d83cSJiri Slaby (SUSE) 	ret = sisusb_send_packet(sisusb, 6, &packet);
1293a2f3d83cSJiri Slaby (SUSE) 	*data = packet.data;
1294a2f3d83cSJiri Slaby (SUSE) 	return ret;
1295a2f3d83cSJiri Slaby (SUSE) }
1296a2f3d83cSJiri Slaby (SUSE) 
1297a2f3d83cSJiri Slaby (SUSE) /* Clear video RAM */
1298a2f3d83cSJiri Slaby (SUSE) 
sisusb_clear_vram(struct sisusb_usb_data * sisusb,u32 address,int length)1299a2f3d83cSJiri Slaby (SUSE) static int sisusb_clear_vram(struct sisusb_usb_data *sisusb,
1300a2f3d83cSJiri Slaby (SUSE) 		u32 address, int length)
1301a2f3d83cSJiri Slaby (SUSE) {
1302a2f3d83cSJiri Slaby (SUSE) 	int ret, i;
1303a2f3d83cSJiri Slaby (SUSE) 	ssize_t j;
1304a2f3d83cSJiri Slaby (SUSE) 
1305a2f3d83cSJiri Slaby (SUSE) 	if (address < sisusb->vrambase)
1306a2f3d83cSJiri Slaby (SUSE) 		return 1;
1307a2f3d83cSJiri Slaby (SUSE) 
1308a2f3d83cSJiri Slaby (SUSE) 	if (address >= sisusb->vrambase + sisusb->vramsize)
1309a2f3d83cSJiri Slaby (SUSE) 		return 1;
1310a2f3d83cSJiri Slaby (SUSE) 
1311a2f3d83cSJiri Slaby (SUSE) 	if (address + length > sisusb->vrambase + sisusb->vramsize)
1312a2f3d83cSJiri Slaby (SUSE) 		length = sisusb->vrambase + sisusb->vramsize - address;
1313a2f3d83cSJiri Slaby (SUSE) 
1314a2f3d83cSJiri Slaby (SUSE) 	if (length <= 0)
1315a2f3d83cSJiri Slaby (SUSE) 		return 0;
1316a2f3d83cSJiri Slaby (SUSE) 
1317a2f3d83cSJiri Slaby (SUSE) 	/* allocate free buffer/urb and clear the buffer */
1318a2f3d83cSJiri Slaby (SUSE) 	i = sisusb_alloc_outbuf(sisusb);
1319a2f3d83cSJiri Slaby (SUSE) 	if (i < 0)
1320a2f3d83cSJiri Slaby (SUSE) 		return -EBUSY;
1321a2f3d83cSJiri Slaby (SUSE) 
1322a2f3d83cSJiri Slaby (SUSE) 	memset(sisusb->obuf[i], 0, sisusb->obufsize);
1323a2f3d83cSJiri Slaby (SUSE) 
1324a2f3d83cSJiri Slaby (SUSE) 	/* We can write a length > buffer size here. The buffer
1325a2f3d83cSJiri Slaby (SUSE) 	 * data will simply be re-used (like a ring-buffer).
1326a2f3d83cSJiri Slaby (SUSE) 	 */
1327a2f3d83cSJiri Slaby (SUSE) 	ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1328a2f3d83cSJiri Slaby (SUSE) 
1329a2f3d83cSJiri Slaby (SUSE) 	/* Free the buffer/urb */
1330a2f3d83cSJiri Slaby (SUSE) 	sisusb_free_outbuf(sisusb, i);
1331a2f3d83cSJiri Slaby (SUSE) 
1332a2f3d83cSJiri Slaby (SUSE) 	return ret;
1333a2f3d83cSJiri Slaby (SUSE) }
1334a2f3d83cSJiri Slaby (SUSE) 
1335a2f3d83cSJiri Slaby (SUSE) /* Initialize the graphics core (return 0 on success)
1336a2f3d83cSJiri Slaby (SUSE)  * This resets the graphics hardware and puts it into
1337a2f3d83cSJiri Slaby (SUSE)  * a defined mode (640x480@60Hz)
1338a2f3d83cSJiri Slaby (SUSE)  */
1339a2f3d83cSJiri Slaby (SUSE) 
1340a2f3d83cSJiri Slaby (SUSE) #define GETREG(r, d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1341a2f3d83cSJiri Slaby (SUSE) #define SETREG(r, d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1342a2f3d83cSJiri Slaby (SUSE) #define SETIREG(r, i, d) sisusb_setidxreg(sisusb, r, i, d)
1343a2f3d83cSJiri Slaby (SUSE) #define GETIREG(r, i, d) sisusb_getidxreg(sisusb, r, i, d)
1344a2f3d83cSJiri Slaby (SUSE) #define SETIREGOR(r, i, o) sisusb_setidxregor(sisusb, r, i, o)
1345a2f3d83cSJiri Slaby (SUSE) #define SETIREGAND(r, i, a) sisusb_setidxregand(sisusb, r, i, a)
1346a2f3d83cSJiri Slaby (SUSE) #define SETIREGANDOR(r, i, a, o) sisusb_setidxregandor(sisusb, r, i, a, o)
1347a2f3d83cSJiri Slaby (SUSE) #define READL(a, d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1348a2f3d83cSJiri Slaby (SUSE) #define WRITEL(a, d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1349a2f3d83cSJiri Slaby (SUSE) #define READB(a, d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1350a2f3d83cSJiri Slaby (SUSE) #define WRITEB(a, d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1351a2f3d83cSJiri Slaby (SUSE) 
sisusb_triggersr16(struct sisusb_usb_data * sisusb,u8 ramtype)1352a2f3d83cSJiri Slaby (SUSE) static int sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1353a2f3d83cSJiri Slaby (SUSE) {
1354a2f3d83cSJiri Slaby (SUSE) 	int ret;
1355a2f3d83cSJiri Slaby (SUSE) 	u8 tmp8;
1356a2f3d83cSJiri Slaby (SUSE) 
1357a2f3d83cSJiri Slaby (SUSE) 	ret = GETIREG(SISSR, 0x16, &tmp8);
1358a2f3d83cSJiri Slaby (SUSE) 	if (ramtype <= 1) {
1359a2f3d83cSJiri Slaby (SUSE) 		tmp8 &= 0x3f;
1360a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x16, tmp8);
1361a2f3d83cSJiri Slaby (SUSE) 		tmp8 |= 0x80;
1362a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x16, tmp8);
1363a2f3d83cSJiri Slaby (SUSE) 	} else {
1364a2f3d83cSJiri Slaby (SUSE) 		tmp8 |= 0xc0;
1365a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x16, tmp8);
1366a2f3d83cSJiri Slaby (SUSE) 		tmp8 &= 0x0f;
1367a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x16, tmp8);
1368a2f3d83cSJiri Slaby (SUSE) 		tmp8 |= 0x80;
1369a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x16, tmp8);
1370a2f3d83cSJiri Slaby (SUSE) 		tmp8 &= 0x0f;
1371a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x16, tmp8);
1372a2f3d83cSJiri Slaby (SUSE) 		tmp8 |= 0xd0;
1373a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x16, tmp8);
1374a2f3d83cSJiri Slaby (SUSE) 		tmp8 &= 0x0f;
1375a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x16, tmp8);
1376a2f3d83cSJiri Slaby (SUSE) 		tmp8 |= 0xa0;
1377a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x16, tmp8);
1378a2f3d83cSJiri Slaby (SUSE) 	}
1379a2f3d83cSJiri Slaby (SUSE) 	return ret;
1380a2f3d83cSJiri Slaby (SUSE) }
1381a2f3d83cSJiri Slaby (SUSE) 
sisusb_getbuswidth(struct sisusb_usb_data * sisusb,int * bw,int * chab)1382a2f3d83cSJiri Slaby (SUSE) static int sisusb_getbuswidth(struct sisusb_usb_data *sisusb,
1383a2f3d83cSJiri Slaby (SUSE) 		int *bw, int *chab)
1384a2f3d83cSJiri Slaby (SUSE) {
1385a2f3d83cSJiri Slaby (SUSE) 	int ret;
1386a2f3d83cSJiri Slaby (SUSE) 	u8  ramtype, done = 0;
1387a2f3d83cSJiri Slaby (SUSE) 	u32 t0, t1, t2, t3;
1388a2f3d83cSJiri Slaby (SUSE) 	u32 ramptr = SISUSB_PCI_MEMBASE;
1389a2f3d83cSJiri Slaby (SUSE) 
1390a2f3d83cSJiri Slaby (SUSE) 	ret = GETIREG(SISSR, 0x3a, &ramtype);
1391a2f3d83cSJiri Slaby (SUSE) 	ramtype &= 3;
1392a2f3d83cSJiri Slaby (SUSE) 
1393a2f3d83cSJiri Slaby (SUSE) 	ret |= SETIREG(SISSR, 0x13, 0x00);
1394a2f3d83cSJiri Slaby (SUSE) 
1395a2f3d83cSJiri Slaby (SUSE) 	if (ramtype <= 1) {
1396a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x14, 0x12);
1397a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGAND(SISSR, 0x15, 0xef);
1398a2f3d83cSJiri Slaby (SUSE) 	} else {
1399a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x14, 0x02);
1400a2f3d83cSJiri Slaby (SUSE) 	}
1401a2f3d83cSJiri Slaby (SUSE) 
1402a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_triggersr16(sisusb, ramtype);
1403a2f3d83cSJiri Slaby (SUSE) 	ret |= WRITEL(ramptr +  0, 0x01234567);
1404a2f3d83cSJiri Slaby (SUSE) 	ret |= WRITEL(ramptr +  4, 0x456789ab);
1405a2f3d83cSJiri Slaby (SUSE) 	ret |= WRITEL(ramptr +  8, 0x89abcdef);
1406a2f3d83cSJiri Slaby (SUSE) 	ret |= WRITEL(ramptr + 12, 0xcdef0123);
1407a2f3d83cSJiri Slaby (SUSE) 	ret |= WRITEL(ramptr + 16, 0x55555555);
1408a2f3d83cSJiri Slaby (SUSE) 	ret |= WRITEL(ramptr + 20, 0x55555555);
1409a2f3d83cSJiri Slaby (SUSE) 	ret |= WRITEL(ramptr + 24, 0xffffffff);
1410a2f3d83cSJiri Slaby (SUSE) 	ret |= WRITEL(ramptr + 28, 0xffffffff);
1411a2f3d83cSJiri Slaby (SUSE) 	ret |= READL(ramptr +  0, &t0);
1412a2f3d83cSJiri Slaby (SUSE) 	ret |= READL(ramptr +  4, &t1);
1413a2f3d83cSJiri Slaby (SUSE) 	ret |= READL(ramptr +  8, &t2);
1414a2f3d83cSJiri Slaby (SUSE) 	ret |= READL(ramptr + 12, &t3);
1415a2f3d83cSJiri Slaby (SUSE) 
1416a2f3d83cSJiri Slaby (SUSE) 	if (ramtype <= 1) {
1417a2f3d83cSJiri Slaby (SUSE) 
1418a2f3d83cSJiri Slaby (SUSE) 		*chab = 0; *bw = 64;
1419a2f3d83cSJiri Slaby (SUSE) 
1420a2f3d83cSJiri Slaby (SUSE) 		if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1421a2f3d83cSJiri Slaby (SUSE) 			if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1422a2f3d83cSJiri Slaby (SUSE) 				*chab = 0; *bw = 64;
1423a2f3d83cSJiri Slaby (SUSE) 				ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1424a2f3d83cSJiri Slaby (SUSE) 			}
1425a2f3d83cSJiri Slaby (SUSE) 		}
1426a2f3d83cSJiri Slaby (SUSE) 		if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1427a2f3d83cSJiri Slaby (SUSE) 			*chab = 1; *bw = 64;
1428a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREGANDOR(SISSR, 0x14, 0xfc, 0x01);
1429a2f3d83cSJiri Slaby (SUSE) 
1430a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_triggersr16(sisusb, ramtype);
1431a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr +  0, 0x89abcdef);
1432a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr +  4, 0xcdef0123);
1433a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr +  8, 0x55555555);
1434a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr + 12, 0x55555555);
1435a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1436a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1437a2f3d83cSJiri Slaby (SUSE) 			ret |= READL(ramptr +  4, &t1);
1438a2f3d83cSJiri Slaby (SUSE) 
1439a2f3d83cSJiri Slaby (SUSE) 			if (t1 != 0xcdef0123) {
1440a2f3d83cSJiri Slaby (SUSE) 				*bw = 32;
1441a2f3d83cSJiri Slaby (SUSE) 				ret |= SETIREGOR(SISSR, 0x15, 0x10);
1442a2f3d83cSJiri Slaby (SUSE) 			}
1443a2f3d83cSJiri Slaby (SUSE) 		}
1444a2f3d83cSJiri Slaby (SUSE) 
1445a2f3d83cSJiri Slaby (SUSE) 	} else {
1446a2f3d83cSJiri Slaby (SUSE) 
1447a2f3d83cSJiri Slaby (SUSE) 		*chab = 0; *bw = 64;	/* default: cha, bw = 64 */
1448a2f3d83cSJiri Slaby (SUSE) 
1449a2f3d83cSJiri Slaby (SUSE) 		done = 0;
1450a2f3d83cSJiri Slaby (SUSE) 
1451a2f3d83cSJiri Slaby (SUSE) 		if (t1 == 0x456789ab) {
1452a2f3d83cSJiri Slaby (SUSE) 			if (t0 == 0x01234567) {
1453a2f3d83cSJiri Slaby (SUSE) 				*chab = 0; *bw = 64;
1454a2f3d83cSJiri Slaby (SUSE) 				done = 1;
1455a2f3d83cSJiri Slaby (SUSE) 			}
1456a2f3d83cSJiri Slaby (SUSE) 		} else {
1457a2f3d83cSJiri Slaby (SUSE) 			if (t0 == 0x01234567) {
1458a2f3d83cSJiri Slaby (SUSE) 				*chab = 0; *bw = 32;
1459a2f3d83cSJiri Slaby (SUSE) 				ret |= SETIREG(SISSR, 0x14, 0x00);
1460a2f3d83cSJiri Slaby (SUSE) 				done = 1;
1461a2f3d83cSJiri Slaby (SUSE) 			}
1462a2f3d83cSJiri Slaby (SUSE) 		}
1463a2f3d83cSJiri Slaby (SUSE) 
1464a2f3d83cSJiri Slaby (SUSE) 		if (!done) {
1465a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREG(SISSR, 0x14, 0x03);
1466a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_triggersr16(sisusb, ramtype);
1467a2f3d83cSJiri Slaby (SUSE) 
1468a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr +  0, 0x01234567);
1469a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr +  4, 0x456789ab);
1470a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr +  8, 0x89abcdef);
1471a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr + 12, 0xcdef0123);
1472a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr + 16, 0x55555555);
1473a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr + 20, 0x55555555);
1474a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr + 24, 0xffffffff);
1475a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEL(ramptr + 28, 0xffffffff);
1476a2f3d83cSJiri Slaby (SUSE) 			ret |= READL(ramptr +  0, &t0);
1477a2f3d83cSJiri Slaby (SUSE) 			ret |= READL(ramptr +  4, &t1);
1478a2f3d83cSJiri Slaby (SUSE) 
1479a2f3d83cSJiri Slaby (SUSE) 			if (t1 == 0x456789ab) {
1480a2f3d83cSJiri Slaby (SUSE) 				if (t0 == 0x01234567) {
1481a2f3d83cSJiri Slaby (SUSE) 					*chab = 1; *bw = 64;
1482a2f3d83cSJiri Slaby (SUSE) 					return ret;
1483a2f3d83cSJiri Slaby (SUSE) 				} /* else error */
1484a2f3d83cSJiri Slaby (SUSE) 			} else {
1485a2f3d83cSJiri Slaby (SUSE) 				if (t0 == 0x01234567) {
1486a2f3d83cSJiri Slaby (SUSE) 					*chab = 1; *bw = 32;
1487a2f3d83cSJiri Slaby (SUSE) 					ret |= SETIREG(SISSR, 0x14, 0x01);
1488a2f3d83cSJiri Slaby (SUSE) 				} /* else error */
1489a2f3d83cSJiri Slaby (SUSE) 			}
1490a2f3d83cSJiri Slaby (SUSE) 		}
1491a2f3d83cSJiri Slaby (SUSE) 	}
1492a2f3d83cSJiri Slaby (SUSE) 	return ret;
1493a2f3d83cSJiri Slaby (SUSE) }
1494a2f3d83cSJiri Slaby (SUSE) 
sisusb_verify_mclk(struct sisusb_usb_data * sisusb)1495a2f3d83cSJiri Slaby (SUSE) static int sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1496a2f3d83cSJiri Slaby (SUSE) {
1497a2f3d83cSJiri Slaby (SUSE) 	int ret = 0;
1498a2f3d83cSJiri Slaby (SUSE) 	u32 ramptr = SISUSB_PCI_MEMBASE;
1499a2f3d83cSJiri Slaby (SUSE) 	u8 tmp1, tmp2, i, j;
1500a2f3d83cSJiri Slaby (SUSE) 
1501a2f3d83cSJiri Slaby (SUSE) 	ret |= WRITEB(ramptr, 0xaa);
1502a2f3d83cSJiri Slaby (SUSE) 	ret |= WRITEB(ramptr + 16, 0x55);
1503a2f3d83cSJiri Slaby (SUSE) 	ret |= READB(ramptr, &tmp1);
1504a2f3d83cSJiri Slaby (SUSE) 	ret |= READB(ramptr + 16, &tmp2);
1505a2f3d83cSJiri Slaby (SUSE) 	if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1506a2f3d83cSJiri Slaby (SUSE) 		for (i = 0, j = 16; i < 2; i++, j += 16) {
1507a2f3d83cSJiri Slaby (SUSE) 			ret |= GETIREG(SISSR, 0x21, &tmp1);
1508a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1509a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREGOR(SISSR, 0x3c, 0x01);  /* not on 330 */
1510a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1511a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREG(SISSR, 0x21, tmp1);
1512a2f3d83cSJiri Slaby (SUSE) 			ret |= WRITEB(ramptr + 16 + j, j);
1513a2f3d83cSJiri Slaby (SUSE) 			ret |= READB(ramptr + 16 + j, &tmp1);
1514a2f3d83cSJiri Slaby (SUSE) 			if (tmp1 == j) {
1515a2f3d83cSJiri Slaby (SUSE) 				ret |= WRITEB(ramptr + j, j);
1516a2f3d83cSJiri Slaby (SUSE) 				break;
1517a2f3d83cSJiri Slaby (SUSE) 			}
1518a2f3d83cSJiri Slaby (SUSE) 		}
1519a2f3d83cSJiri Slaby (SUSE) 	}
1520a2f3d83cSJiri Slaby (SUSE) 	return ret;
1521a2f3d83cSJiri Slaby (SUSE) }
1522a2f3d83cSJiri Slaby (SUSE) 
sisusb_set_rank(struct sisusb_usb_data * sisusb,int * iret,int index,u8 rankno,u8 chab,const u8 dramtype[][5],int bw)1523a2f3d83cSJiri Slaby (SUSE) static int sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret,
1524a2f3d83cSJiri Slaby (SUSE) 		int index, u8 rankno, u8 chab, const u8 dramtype[][5], int bw)
1525a2f3d83cSJiri Slaby (SUSE) {
1526a2f3d83cSJiri Slaby (SUSE) 	int ret = 0, ranksize;
1527a2f3d83cSJiri Slaby (SUSE) 	u8 tmp;
1528a2f3d83cSJiri Slaby (SUSE) 
1529a2f3d83cSJiri Slaby (SUSE) 	*iret = 0;
1530a2f3d83cSJiri Slaby (SUSE) 
1531a2f3d83cSJiri Slaby (SUSE) 	if ((rankno == 2) && (dramtype[index][0] == 2))
1532a2f3d83cSJiri Slaby (SUSE) 		return ret;
1533a2f3d83cSJiri Slaby (SUSE) 
1534a2f3d83cSJiri Slaby (SUSE) 	ranksize = dramtype[index][3] / 2 * bw / 32;
1535a2f3d83cSJiri Slaby (SUSE) 
1536a2f3d83cSJiri Slaby (SUSE) 	if ((ranksize * rankno) > 128)
1537a2f3d83cSJiri Slaby (SUSE) 		return ret;
1538a2f3d83cSJiri Slaby (SUSE) 
1539a2f3d83cSJiri Slaby (SUSE) 	tmp = 0;
1540a2f3d83cSJiri Slaby (SUSE) 	while ((ranksize >>= 1) > 0)
1541a2f3d83cSJiri Slaby (SUSE) 		tmp += 0x10;
1542a2f3d83cSJiri Slaby (SUSE) 
1543a2f3d83cSJiri Slaby (SUSE) 	tmp |= ((rankno - 1) << 2);
1544a2f3d83cSJiri Slaby (SUSE) 	tmp |= ((bw / 64) & 0x02);
1545a2f3d83cSJiri Slaby (SUSE) 	tmp |= (chab & 0x01);
1546a2f3d83cSJiri Slaby (SUSE) 
1547a2f3d83cSJiri Slaby (SUSE) 	ret = SETIREG(SISSR, 0x14, tmp);
1548a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1549a2f3d83cSJiri Slaby (SUSE) 
1550a2f3d83cSJiri Slaby (SUSE) 	*iret = 1;
1551a2f3d83cSJiri Slaby (SUSE) 
1552a2f3d83cSJiri Slaby (SUSE) 	return ret;
1553a2f3d83cSJiri Slaby (SUSE) }
1554a2f3d83cSJiri Slaby (SUSE) 
sisusb_check_rbc(struct sisusb_usb_data * sisusb,int * iret,u32 inc,int testn)1555a2f3d83cSJiri Slaby (SUSE) static int sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret,
1556a2f3d83cSJiri Slaby (SUSE) 		u32 inc, int testn)
1557a2f3d83cSJiri Slaby (SUSE) {
1558a2f3d83cSJiri Slaby (SUSE) 	int ret = 0, i;
1559a2f3d83cSJiri Slaby (SUSE) 	u32 j, tmp;
1560a2f3d83cSJiri Slaby (SUSE) 
1561a2f3d83cSJiri Slaby (SUSE) 	*iret = 0;
1562a2f3d83cSJiri Slaby (SUSE) 
1563a2f3d83cSJiri Slaby (SUSE) 	for (i = 0, j = 0; i < testn; i++) {
1564a2f3d83cSJiri Slaby (SUSE) 		ret |= WRITEL(sisusb->vrambase + j, j);
1565a2f3d83cSJiri Slaby (SUSE) 		j += inc;
1566a2f3d83cSJiri Slaby (SUSE) 	}
1567a2f3d83cSJiri Slaby (SUSE) 
1568a2f3d83cSJiri Slaby (SUSE) 	for (i = 0, j = 0; i < testn; i++) {
1569a2f3d83cSJiri Slaby (SUSE) 		ret |= READL(sisusb->vrambase + j, &tmp);
1570a2f3d83cSJiri Slaby (SUSE) 		if (tmp != j)
1571a2f3d83cSJiri Slaby (SUSE) 			return ret;
1572a2f3d83cSJiri Slaby (SUSE) 
1573a2f3d83cSJiri Slaby (SUSE) 		j += inc;
1574a2f3d83cSJiri Slaby (SUSE) 	}
1575a2f3d83cSJiri Slaby (SUSE) 
1576a2f3d83cSJiri Slaby (SUSE) 	*iret = 1;
1577a2f3d83cSJiri Slaby (SUSE) 	return ret;
1578a2f3d83cSJiri Slaby (SUSE) }
1579a2f3d83cSJiri Slaby (SUSE) 
sisusb_check_ranks(struct sisusb_usb_data * sisusb,int * iret,int rankno,int idx,int bw,const u8 rtype[][5])1580a2f3d83cSJiri Slaby (SUSE) static int sisusb_check_ranks(struct sisusb_usb_data *sisusb,
1581a2f3d83cSJiri Slaby (SUSE) 		int *iret, int rankno, int idx, int bw, const u8 rtype[][5])
1582a2f3d83cSJiri Slaby (SUSE) {
1583a2f3d83cSJiri Slaby (SUSE) 	int ret = 0, i, i2ret;
1584a2f3d83cSJiri Slaby (SUSE) 	u32 inc;
1585a2f3d83cSJiri Slaby (SUSE) 
1586a2f3d83cSJiri Slaby (SUSE) 	*iret = 0;
1587a2f3d83cSJiri Slaby (SUSE) 
1588a2f3d83cSJiri Slaby (SUSE) 	for (i = rankno; i >= 1; i--) {
1589a2f3d83cSJiri Slaby (SUSE) 		inc = 1 << (rtype[idx][2] + rtype[idx][1] + rtype[idx][0] +
1590a2f3d83cSJiri Slaby (SUSE) 				bw / 64 + i);
1591a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1592a2f3d83cSJiri Slaby (SUSE) 		if (!i2ret)
1593a2f3d83cSJiri Slaby (SUSE) 			return ret;
1594a2f3d83cSJiri Slaby (SUSE) 	}
1595a2f3d83cSJiri Slaby (SUSE) 
1596a2f3d83cSJiri Slaby (SUSE) 	inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1597a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1598a2f3d83cSJiri Slaby (SUSE) 	if (!i2ret)
1599a2f3d83cSJiri Slaby (SUSE) 		return ret;
1600a2f3d83cSJiri Slaby (SUSE) 
1601a2f3d83cSJiri Slaby (SUSE) 	inc = 1 << (10 + bw / 64);
1602a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1603a2f3d83cSJiri Slaby (SUSE) 	if (!i2ret)
1604a2f3d83cSJiri Slaby (SUSE) 		return ret;
1605a2f3d83cSJiri Slaby (SUSE) 
1606a2f3d83cSJiri Slaby (SUSE) 	*iret = 1;
1607a2f3d83cSJiri Slaby (SUSE) 	return ret;
1608a2f3d83cSJiri Slaby (SUSE) }
1609a2f3d83cSJiri Slaby (SUSE) 
sisusb_get_sdram_size(struct sisusb_usb_data * sisusb,int * iret,int bw,int chab)1610a2f3d83cSJiri Slaby (SUSE) static int sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret,
1611a2f3d83cSJiri Slaby (SUSE) 		int bw, int chab)
1612a2f3d83cSJiri Slaby (SUSE) {
1613a2f3d83cSJiri Slaby (SUSE) 	int ret = 0, i2ret = 0, i, j;
1614a2f3d83cSJiri Slaby (SUSE) 	static const u8 sdramtype[13][5] = {
1615a2f3d83cSJiri Slaby (SUSE) 		{ 2, 12, 9, 64, 0x35 },
1616a2f3d83cSJiri Slaby (SUSE) 		{ 1, 13, 9, 64, 0x44 },
1617a2f3d83cSJiri Slaby (SUSE) 		{ 2, 12, 8, 32, 0x31 },
1618a2f3d83cSJiri Slaby (SUSE) 		{ 2, 11, 9, 32, 0x25 },
1619a2f3d83cSJiri Slaby (SUSE) 		{ 1, 12, 9, 32, 0x34 },
1620a2f3d83cSJiri Slaby (SUSE) 		{ 1, 13, 8, 32, 0x40 },
1621a2f3d83cSJiri Slaby (SUSE) 		{ 2, 11, 8, 16, 0x21 },
1622a2f3d83cSJiri Slaby (SUSE) 		{ 1, 12, 8, 16, 0x30 },
1623a2f3d83cSJiri Slaby (SUSE) 		{ 1, 11, 9, 16, 0x24 },
1624a2f3d83cSJiri Slaby (SUSE) 		{ 1, 11, 8,  8, 0x20 },
1625a2f3d83cSJiri Slaby (SUSE) 		{ 2,  9, 8,  4, 0x01 },
1626a2f3d83cSJiri Slaby (SUSE) 		{ 1, 10, 8,  4, 0x10 },
1627a2f3d83cSJiri Slaby (SUSE) 		{ 1,  9, 8,  2, 0x00 }
1628a2f3d83cSJiri Slaby (SUSE) 	};
1629a2f3d83cSJiri Slaby (SUSE) 
1630a2f3d83cSJiri Slaby (SUSE) 	*iret = 1; /* error */
1631a2f3d83cSJiri Slaby (SUSE) 
1632a2f3d83cSJiri Slaby (SUSE) 	for (i = 0; i < 13; i++) {
1633a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1634a2f3d83cSJiri Slaby (SUSE) 		for (j = 2; j > 0; j--) {
1635a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_set_rank(sisusb, &i2ret, i, j, chab,
1636a2f3d83cSJiri Slaby (SUSE) 					sdramtype, bw);
1637a2f3d83cSJiri Slaby (SUSE) 			if (!i2ret)
1638a2f3d83cSJiri Slaby (SUSE) 				continue;
1639a2f3d83cSJiri Slaby (SUSE) 
1640a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_check_ranks(sisusb, &i2ret, j, i, bw,
1641a2f3d83cSJiri Slaby (SUSE) 					sdramtype);
1642a2f3d83cSJiri Slaby (SUSE) 			if (i2ret) {
1643a2f3d83cSJiri Slaby (SUSE) 				*iret = 0;	/* ram size found */
1644a2f3d83cSJiri Slaby (SUSE) 				return ret;
1645a2f3d83cSJiri Slaby (SUSE) 			}
1646a2f3d83cSJiri Slaby (SUSE) 		}
1647a2f3d83cSJiri Slaby (SUSE) 	}
1648a2f3d83cSJiri Slaby (SUSE) 
1649a2f3d83cSJiri Slaby (SUSE) 	return ret;
1650a2f3d83cSJiri Slaby (SUSE) }
1651a2f3d83cSJiri Slaby (SUSE) 
sisusb_setup_screen(struct sisusb_usb_data * sisusb,int clrall,int drwfr)1652a2f3d83cSJiri Slaby (SUSE) static int sisusb_setup_screen(struct sisusb_usb_data *sisusb,
1653a2f3d83cSJiri Slaby (SUSE) 		int clrall, int drwfr)
1654a2f3d83cSJiri Slaby (SUSE) {
1655a2f3d83cSJiri Slaby (SUSE) 	int ret = 0;
1656a2f3d83cSJiri Slaby (SUSE) 	u32 address;
1657a2f3d83cSJiri Slaby (SUSE) 	int i, length, modex, modey, bpp;
1658a2f3d83cSJiri Slaby (SUSE) 
1659a2f3d83cSJiri Slaby (SUSE) 	modex = 640; modey = 480; bpp = 2;
1660a2f3d83cSJiri Slaby (SUSE) 
1661a2f3d83cSJiri Slaby (SUSE) 	address = sisusb->vrambase;	/* Clear video ram */
1662a2f3d83cSJiri Slaby (SUSE) 
1663a2f3d83cSJiri Slaby (SUSE) 	if (clrall)
1664a2f3d83cSJiri Slaby (SUSE) 		length = sisusb->vramsize;
1665a2f3d83cSJiri Slaby (SUSE) 	else
1666a2f3d83cSJiri Slaby (SUSE) 		length = modex * bpp * modey;
1667a2f3d83cSJiri Slaby (SUSE) 
1668a2f3d83cSJiri Slaby (SUSE) 	ret = sisusb_clear_vram(sisusb, address, length);
1669a2f3d83cSJiri Slaby (SUSE) 
1670a2f3d83cSJiri Slaby (SUSE) 	if (!ret && drwfr) {
1671a2f3d83cSJiri Slaby (SUSE) 		for (i = 0; i < modex; i++) {
1672a2f3d83cSJiri Slaby (SUSE) 			address = sisusb->vrambase + (i * bpp);
1673a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1674a2f3d83cSJiri Slaby (SUSE) 					address, 0xf100);
1675a2f3d83cSJiri Slaby (SUSE) 			address += (modex * (modey-1) * bpp);
1676a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1677a2f3d83cSJiri Slaby (SUSE) 					address, 0xf100);
1678a2f3d83cSJiri Slaby (SUSE) 		}
1679a2f3d83cSJiri Slaby (SUSE) 		for (i = 0; i < modey; i++) {
1680a2f3d83cSJiri Slaby (SUSE) 			address = sisusb->vrambase + ((i * modex) * bpp);
1681a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1682a2f3d83cSJiri Slaby (SUSE) 					address, 0xf100);
1683a2f3d83cSJiri Slaby (SUSE) 			address += ((modex - 1) * bpp);
1684a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1685a2f3d83cSJiri Slaby (SUSE) 					address, 0xf100);
1686a2f3d83cSJiri Slaby (SUSE) 		}
1687a2f3d83cSJiri Slaby (SUSE) 	}
1688a2f3d83cSJiri Slaby (SUSE) 
1689a2f3d83cSJiri Slaby (SUSE) 	return ret;
1690a2f3d83cSJiri Slaby (SUSE) }
1691a2f3d83cSJiri Slaby (SUSE) 
sisusb_set_default_mode(struct sisusb_usb_data * sisusb,int touchengines)1692a2f3d83cSJiri Slaby (SUSE) static void sisusb_set_default_mode(struct sisusb_usb_data *sisusb,
1693a2f3d83cSJiri Slaby (SUSE) 		int touchengines)
1694a2f3d83cSJiri Slaby (SUSE) {
1695a2f3d83cSJiri Slaby (SUSE) 	int i, j, modex, bpp, du;
1696a2f3d83cSJiri Slaby (SUSE) 	u8 sr31, cr63, tmp8;
1697a2f3d83cSJiri Slaby (SUSE) 	static const char attrdata[] = {
1698a2f3d83cSJiri Slaby (SUSE) 		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1699a2f3d83cSJiri Slaby (SUSE) 		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
1700a2f3d83cSJiri Slaby (SUSE) 		0x01, 0x00, 0x00, 0x00
1701a2f3d83cSJiri Slaby (SUSE) 	};
1702a2f3d83cSJiri Slaby (SUSE) 	static const char crtcrdata[] = {
1703a2f3d83cSJiri Slaby (SUSE) 		0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
1704a2f3d83cSJiri Slaby (SUSE) 		0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1705a2f3d83cSJiri Slaby (SUSE) 		0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
1706a2f3d83cSJiri Slaby (SUSE) 		0xff
1707a2f3d83cSJiri Slaby (SUSE) 	};
1708a2f3d83cSJiri Slaby (SUSE) 	static const char grcdata[] = {
1709a2f3d83cSJiri Slaby (SUSE) 		0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
1710a2f3d83cSJiri Slaby (SUSE) 		0xff
1711a2f3d83cSJiri Slaby (SUSE) 	};
1712a2f3d83cSJiri Slaby (SUSE) 	static const char crtcdata[] = {
1713a2f3d83cSJiri Slaby (SUSE) 		0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e,
1714a2f3d83cSJiri Slaby (SUSE) 		0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05,
1715a2f3d83cSJiri Slaby (SUSE) 		0x00
1716a2f3d83cSJiri Slaby (SUSE) 	};
1717a2f3d83cSJiri Slaby (SUSE) 
1718a2f3d83cSJiri Slaby (SUSE) 	modex = 640; bpp = 2;
1719a2f3d83cSJiri Slaby (SUSE) 
1720a2f3d83cSJiri Slaby (SUSE) 	GETIREG(SISSR, 0x31, &sr31);
1721a2f3d83cSJiri Slaby (SUSE) 	GETIREG(SISCR, 0x63, &cr63);
1722a2f3d83cSJiri Slaby (SUSE) 	SETIREGOR(SISSR, 0x01, 0x20);
1723a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISCR, 0x63, cr63 & 0xbf);
1724a2f3d83cSJiri Slaby (SUSE) 	SETIREGOR(SISCR, 0x17, 0x80);
1725a2f3d83cSJiri Slaby (SUSE) 	SETIREGOR(SISSR, 0x1f, 0x04);
1726a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISSR, 0x07, 0xfb);
1727a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x00, 0x03);	/* seq */
1728a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x01, 0x21);
1729a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x02, 0x0f);
1730a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x03, 0x00);
1731a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x04, 0x0e);
1732a2f3d83cSJiri Slaby (SUSE) 	SETREG(SISMISCW, 0x23);		/* misc */
1733a2f3d83cSJiri Slaby (SUSE) 	for (i = 0; i <= 0x18; i++) {	/* crtc */
1734a2f3d83cSJiri Slaby (SUSE) 		SETIREG(SISCR, i, crtcrdata[i]);
1735a2f3d83cSJiri Slaby (SUSE) 	}
1736a2f3d83cSJiri Slaby (SUSE) 	for (i = 0; i <= 0x13; i++) {	/* att */
1737a2f3d83cSJiri Slaby (SUSE) 		GETREG(SISINPSTAT, &tmp8);
1738a2f3d83cSJiri Slaby (SUSE) 		SETREG(SISAR, i);
1739a2f3d83cSJiri Slaby (SUSE) 		SETREG(SISAR, attrdata[i]);
1740a2f3d83cSJiri Slaby (SUSE) 	}
1741a2f3d83cSJiri Slaby (SUSE) 	GETREG(SISINPSTAT, &tmp8);
1742a2f3d83cSJiri Slaby (SUSE) 	SETREG(SISAR, 0x14);
1743a2f3d83cSJiri Slaby (SUSE) 	SETREG(SISAR, 0x00);
1744a2f3d83cSJiri Slaby (SUSE) 	GETREG(SISINPSTAT, &tmp8);
1745a2f3d83cSJiri Slaby (SUSE) 	SETREG(SISAR, 0x20);
1746a2f3d83cSJiri Slaby (SUSE) 	GETREG(SISINPSTAT, &tmp8);
1747a2f3d83cSJiri Slaby (SUSE) 	for (i = 0; i <= 0x08; i++) {	/* grc */
1748a2f3d83cSJiri Slaby (SUSE) 		SETIREG(SISGR, i, grcdata[i]);
1749a2f3d83cSJiri Slaby (SUSE) 	}
1750a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISGR, 0x05, 0xbf);
1751a2f3d83cSJiri Slaby (SUSE) 	for (i = 0x0A; i <= 0x0E; i++) {	/* clr ext */
1752a2f3d83cSJiri Slaby (SUSE) 		SETIREG(SISSR, i, 0x00);
1753a2f3d83cSJiri Slaby (SUSE) 	}
1754a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISSR, 0x37, 0xfe);
1755a2f3d83cSJiri Slaby (SUSE) 	SETREG(SISMISCW, 0xef);		/* sync */
1756a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISCR, 0x11, 0x00);	/* crtc */
1757a2f3d83cSJiri Slaby (SUSE) 	for (j = 0x00, i = 0; i <= 7; i++, j++)
1758a2f3d83cSJiri Slaby (SUSE) 		SETIREG(SISCR, j, crtcdata[i]);
1759a2f3d83cSJiri Slaby (SUSE) 
1760a2f3d83cSJiri Slaby (SUSE) 	for (j = 0x10; i <= 10; i++, j++)
1761a2f3d83cSJiri Slaby (SUSE) 		SETIREG(SISCR, j, crtcdata[i]);
1762a2f3d83cSJiri Slaby (SUSE) 
1763a2f3d83cSJiri Slaby (SUSE) 	for (j = 0x15; i <= 12; i++, j++)
1764a2f3d83cSJiri Slaby (SUSE) 		SETIREG(SISCR, j, crtcdata[i]);
1765a2f3d83cSJiri Slaby (SUSE) 
1766a2f3d83cSJiri Slaby (SUSE) 	for (j = 0x0A; i <= 15; i++, j++)
1767a2f3d83cSJiri Slaby (SUSE) 		SETIREG(SISSR, j, crtcdata[i]);
1768a2f3d83cSJiri Slaby (SUSE) 
1769a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
1770a2f3d83cSJiri Slaby (SUSE) 	SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
1771a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISCR, 0x14, 0x4f);
1772a2f3d83cSJiri Slaby (SUSE) 	du = (modex / 16) * (bpp * 2);	/* offset/pitch */
1773a2f3d83cSJiri Slaby (SUSE) 	SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
1774a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISCR, 0x13, (du & 0xff));
1775a2f3d83cSJiri Slaby (SUSE) 	du <<= 5;
1776a2f3d83cSJiri Slaby (SUSE) 	tmp8 = du >> 8;
1777a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x10, tmp8);
1778a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x31, 0x00);	/* VCLK */
1779a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x2b, 0x1b);
1780a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x2c, 0xe1);
1781a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x2d, 0x01);
1782a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISSR, 0x3d, 0xfe);	/* FIFO */
1783a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x08, 0xae);
1784a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISSR, 0x09, 0xf0);
1785a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x08, 0x34);
1786a2f3d83cSJiri Slaby (SUSE) 	SETIREGOR(SISSR, 0x3d, 0x01);
1787a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISSR, 0x1f, 0x3f);	/* mode regs */
1788a2f3d83cSJiri Slaby (SUSE) 	SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
1789a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISCR, 0x19, 0x00);
1790a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISCR, 0x1a, 0xfc);
1791a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISSR, 0x0f, 0xb7);
1792a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISSR, 0x31, 0xfb);
1793a2f3d83cSJiri Slaby (SUSE) 	SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
1794a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISSR, 0x32, 0xf3);
1795a2f3d83cSJiri Slaby (SUSE) 	SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
1796a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISCR, 0x52, 0x6c);
1797a2f3d83cSJiri Slaby (SUSE) 
1798a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISCR, 0x0d, 0x00);	/* adjust frame */
1799a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISCR, 0x0c, 0x00);
1800a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x0d, 0x00);
1801a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISSR, 0x37, 0xfe);
1802a2f3d83cSJiri Slaby (SUSE) 
1803a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISCR, 0x32, 0x20);
1804a2f3d83cSJiri Slaby (SUSE) 	SETIREGAND(SISSR, 0x01, 0xdf);	/* enable display */
1805a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISCR, 0x63, (cr63 & 0xbf));
1806a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISSR, 0x31, (sr31 & 0xfb));
1807a2f3d83cSJiri Slaby (SUSE) 
1808a2f3d83cSJiri Slaby (SUSE) 	if (touchengines) {
1809a2f3d83cSJiri Slaby (SUSE) 		SETIREG(SISSR, 0x20, 0xa1);	/* enable engines */
1810a2f3d83cSJiri Slaby (SUSE) 		SETIREGOR(SISSR, 0x1e, 0x5a);
1811a2f3d83cSJiri Slaby (SUSE) 
1812a2f3d83cSJiri Slaby (SUSE) 		SETIREG(SISSR, 0x26, 0x01);	/* disable cmdqueue */
1813a2f3d83cSJiri Slaby (SUSE) 		SETIREG(SISSR, 0x27, 0x1f);
1814a2f3d83cSJiri Slaby (SUSE) 		SETIREG(SISSR, 0x26, 0x00);
1815a2f3d83cSJiri Slaby (SUSE) 	}
1816a2f3d83cSJiri Slaby (SUSE) 
1817a2f3d83cSJiri Slaby (SUSE) 	SETIREG(SISCR, 0x34, 0x44);	/* we just set std mode #44 */
1818a2f3d83cSJiri Slaby (SUSE) }
1819a2f3d83cSJiri Slaby (SUSE) 
sisusb_init_gfxcore(struct sisusb_usb_data * sisusb)1820a2f3d83cSJiri Slaby (SUSE) static int sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
1821a2f3d83cSJiri Slaby (SUSE) {
1822a2f3d83cSJiri Slaby (SUSE) 	int ret = 0, i, j, bw, chab, iret, retry = 3;
1823a2f3d83cSJiri Slaby (SUSE) 	u8 tmp8, ramtype;
1824a2f3d83cSJiri Slaby (SUSE) 	u32 tmp32;
1825a2f3d83cSJiri Slaby (SUSE) 	static const char mclktable[] = {
1826a2f3d83cSJiri Slaby (SUSE) 		0x3b, 0x22, 0x01, 143,
1827a2f3d83cSJiri Slaby (SUSE) 		0x3b, 0x22, 0x01, 143,
1828a2f3d83cSJiri Slaby (SUSE) 		0x3b, 0x22, 0x01, 143,
1829a2f3d83cSJiri Slaby (SUSE) 		0x3b, 0x22, 0x01, 143
1830a2f3d83cSJiri Slaby (SUSE) 	};
1831a2f3d83cSJiri Slaby (SUSE) 	static const char eclktable[] = {
1832a2f3d83cSJiri Slaby (SUSE) 		0x3b, 0x22, 0x01, 143,
1833a2f3d83cSJiri Slaby (SUSE) 		0x3b, 0x22, 0x01, 143,
1834a2f3d83cSJiri Slaby (SUSE) 		0x3b, 0x22, 0x01, 143,
1835a2f3d83cSJiri Slaby (SUSE) 		0x3b, 0x22, 0x01, 143
1836a2f3d83cSJiri Slaby (SUSE) 	};
1837a2f3d83cSJiri Slaby (SUSE) 	static const char ramtypetable1[] = {
1838a2f3d83cSJiri Slaby (SUSE) 		0x00, 0x04, 0x60, 0x60,
1839a2f3d83cSJiri Slaby (SUSE) 		0x0f, 0x0f, 0x1f, 0x1f,
1840a2f3d83cSJiri Slaby (SUSE) 		0xba, 0xba, 0xba, 0xba,
1841a2f3d83cSJiri Slaby (SUSE) 		0xa9, 0xa9, 0xac, 0xac,
1842a2f3d83cSJiri Slaby (SUSE) 		0xa0, 0xa0, 0xa0, 0xa8,
1843a2f3d83cSJiri Slaby (SUSE) 		0x00, 0x00, 0x02, 0x02,
1844a2f3d83cSJiri Slaby (SUSE) 		0x30, 0x30, 0x40, 0x40
1845a2f3d83cSJiri Slaby (SUSE) 	};
1846a2f3d83cSJiri Slaby (SUSE) 	static const char ramtypetable2[] = {
1847a2f3d83cSJiri Slaby (SUSE) 		0x77, 0x77, 0x44, 0x44,
1848a2f3d83cSJiri Slaby (SUSE) 		0x77, 0x77, 0x44, 0x44,
1849a2f3d83cSJiri Slaby (SUSE) 		0x00, 0x00, 0x00, 0x00,
1850a2f3d83cSJiri Slaby (SUSE) 		0x5b, 0x5b, 0xab, 0xab,
1851a2f3d83cSJiri Slaby (SUSE) 		0x00, 0x00, 0xf0, 0xf8
1852a2f3d83cSJiri Slaby (SUSE) 	};
1853a2f3d83cSJiri Slaby (SUSE) 
1854a2f3d83cSJiri Slaby (SUSE) 	while (retry--) {
1855a2f3d83cSJiri Slaby (SUSE) 
1856a2f3d83cSJiri Slaby (SUSE) 		/* Enable VGA */
1857a2f3d83cSJiri Slaby (SUSE) 		ret = GETREG(SISVGAEN, &tmp8);
1858a2f3d83cSJiri Slaby (SUSE) 		ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
1859a2f3d83cSJiri Slaby (SUSE) 
1860a2f3d83cSJiri Slaby (SUSE) 		/* Enable GPU access to VRAM */
1861a2f3d83cSJiri Slaby (SUSE) 		ret |= GETREG(SISMISCR, &tmp8);
1862a2f3d83cSJiri Slaby (SUSE) 		ret |= SETREG(SISMISCW, (tmp8 | 0x01));
1863a2f3d83cSJiri Slaby (SUSE) 
1864a2f3d83cSJiri Slaby (SUSE) 		if (ret)
1865a2f3d83cSJiri Slaby (SUSE) 			continue;
1866a2f3d83cSJiri Slaby (SUSE) 
1867a2f3d83cSJiri Slaby (SUSE) 		/* Reset registers */
1868a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
1869a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x05, 0x86);
1870a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGOR(SISSR, 0x20, 0x01);
1871a2f3d83cSJiri Slaby (SUSE) 
1872a2f3d83cSJiri Slaby (SUSE) 		ret |= SETREG(SISMISCW, 0x67);
1873a2f3d83cSJiri Slaby (SUSE) 
1874a2f3d83cSJiri Slaby (SUSE) 		for (i = 0x06; i <= 0x1f; i++)
1875a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREG(SISSR, i, 0x00);
1876a2f3d83cSJiri Slaby (SUSE) 
1877a2f3d83cSJiri Slaby (SUSE) 		for (i = 0x21; i <= 0x27; i++)
1878a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREG(SISSR, i, 0x00);
1879a2f3d83cSJiri Slaby (SUSE) 
1880a2f3d83cSJiri Slaby (SUSE) 		for (i = 0x31; i <= 0x3d; i++)
1881a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREG(SISSR, i, 0x00);
1882a2f3d83cSJiri Slaby (SUSE) 
1883a2f3d83cSJiri Slaby (SUSE) 		for (i = 0x12; i <= 0x1b; i++)
1884a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREG(SISSR, i, 0x00);
1885a2f3d83cSJiri Slaby (SUSE) 
1886a2f3d83cSJiri Slaby (SUSE) 		for (i = 0x79; i <= 0x7c; i++)
1887a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREG(SISCR, i, 0x00);
1888a2f3d83cSJiri Slaby (SUSE) 
1889a2f3d83cSJiri Slaby (SUSE) 		if (ret)
1890a2f3d83cSJiri Slaby (SUSE) 			continue;
1891a2f3d83cSJiri Slaby (SUSE) 
1892a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISCR, 0x63, 0x80);
1893a2f3d83cSJiri Slaby (SUSE) 
1894a2f3d83cSJiri Slaby (SUSE) 		ret |= GETIREG(SISSR, 0x3a, &ramtype);
1895a2f3d83cSJiri Slaby (SUSE) 		ramtype &= 0x03;
1896a2f3d83cSJiri Slaby (SUSE) 
1897a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
1898a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
1899a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
1900a2f3d83cSJiri Slaby (SUSE) 
1901a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
1902a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
1903a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
1904a2f3d83cSJiri Slaby (SUSE) 
1905a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x07, 0x18);
1906a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x11, 0x0f);
1907a2f3d83cSJiri Slaby (SUSE) 
1908a2f3d83cSJiri Slaby (SUSE) 		if (ret)
1909a2f3d83cSJiri Slaby (SUSE) 			continue;
1910a2f3d83cSJiri Slaby (SUSE) 
1911a2f3d83cSJiri Slaby (SUSE) 		for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
1912a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREG(SISSR, i,
1913a2f3d83cSJiri Slaby (SUSE) 					ramtypetable1[(j*4) + ramtype]);
1914a2f3d83cSJiri Slaby (SUSE) 		}
1915a2f3d83cSJiri Slaby (SUSE) 		for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
1916a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREG(SISCR, i,
1917a2f3d83cSJiri Slaby (SUSE) 					ramtypetable2[(j*4) + ramtype]);
1918a2f3d83cSJiri Slaby (SUSE) 		}
1919a2f3d83cSJiri Slaby (SUSE) 
1920a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISCR, 0x49, 0xaa);
1921a2f3d83cSJiri Slaby (SUSE) 
1922a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x1f, 0x00);
1923a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x20, 0xa0);
1924a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x23, 0xf6);
1925a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x24, 0x0d);
1926a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x25, 0x33);
1927a2f3d83cSJiri Slaby (SUSE) 
1928a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x11, 0x0f);
1929a2f3d83cSJiri Slaby (SUSE) 
1930a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
1931a2f3d83cSJiri Slaby (SUSE) 
1932a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
1933a2f3d83cSJiri Slaby (SUSE) 
1934a2f3d83cSJiri Slaby (SUSE) 		if (ret)
1935a2f3d83cSJiri Slaby (SUSE) 			continue;
1936a2f3d83cSJiri Slaby (SUSE) 
1937a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISPART1, 0x00, 0x00);
1938a2f3d83cSJiri Slaby (SUSE) 
1939a2f3d83cSJiri Slaby (SUSE) 		ret |= GETIREG(SISSR, 0x13, &tmp8);
1940a2f3d83cSJiri Slaby (SUSE) 		tmp8 >>= 4;
1941a2f3d83cSJiri Slaby (SUSE) 
1942a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISPART1, 0x02, 0x00);
1943a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISPART1, 0x2e, 0x08);
1944a2f3d83cSJiri Slaby (SUSE) 
1945a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
1946a2f3d83cSJiri Slaby (SUSE) 		tmp32 &= 0x00f00000;
1947a2f3d83cSJiri Slaby (SUSE) 		tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
1948a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x25, tmp8);
1949a2f3d83cSJiri Slaby (SUSE) 		tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
1950a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISCR, 0x49, tmp8);
1951a2f3d83cSJiri Slaby (SUSE) 
1952a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x27, 0x1f);
1953a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x31, 0x00);
1954a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x32, 0x11);
1955a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x33, 0x00);
1956a2f3d83cSJiri Slaby (SUSE) 
1957a2f3d83cSJiri Slaby (SUSE) 		if (ret)
1958a2f3d83cSJiri Slaby (SUSE) 			continue;
1959a2f3d83cSJiri Slaby (SUSE) 
1960a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISCR, 0x83, 0x00);
1961a2f3d83cSJiri Slaby (SUSE) 
1962a2f3d83cSJiri Slaby (SUSE) 		sisusb_set_default_mode(sisusb, 0);
1963a2f3d83cSJiri Slaby (SUSE) 
1964a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGAND(SISSR, 0x21, 0xdf);
1965a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGOR(SISSR, 0x01, 0x20);
1966a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGOR(SISSR, 0x16, 0x0f);
1967a2f3d83cSJiri Slaby (SUSE) 
1968a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_triggersr16(sisusb, ramtype);
1969a2f3d83cSJiri Slaby (SUSE) 
1970a2f3d83cSJiri Slaby (SUSE) 		/* Disable refresh */
1971a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGAND(SISSR, 0x17, 0xf8);
1972a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGOR(SISSR, 0x19, 0x03);
1973a2f3d83cSJiri Slaby (SUSE) 
1974a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
1975a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_verify_mclk(sisusb);
1976a2f3d83cSJiri Slaby (SUSE) 
1977a2f3d83cSJiri Slaby (SUSE) 		if (ramtype <= 1) {
1978a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
1979a2f3d83cSJiri Slaby (SUSE) 			if (iret) {
1980a2f3d83cSJiri Slaby (SUSE) 				dev_err(&sisusb->sisusb_dev->dev,
1981a2f3d83cSJiri Slaby (SUSE) 						"RAM size detection failed, assuming 8MB video RAM\n");
1982a2f3d83cSJiri Slaby (SUSE) 				ret |= SETIREG(SISSR, 0x14, 0x31);
1983a2f3d83cSJiri Slaby (SUSE) 				/* TODO */
1984a2f3d83cSJiri Slaby (SUSE) 			}
1985a2f3d83cSJiri Slaby (SUSE) 		} else {
1986a2f3d83cSJiri Slaby (SUSE) 			dev_err(&sisusb->sisusb_dev->dev,
1987a2f3d83cSJiri Slaby (SUSE) 					"DDR RAM device found, assuming 8MB video RAM\n");
1988a2f3d83cSJiri Slaby (SUSE) 			ret |= SETIREG(SISSR, 0x14, 0x31);
1989a2f3d83cSJiri Slaby (SUSE) 			/* *** TODO *** */
1990a2f3d83cSJiri Slaby (SUSE) 		}
1991a2f3d83cSJiri Slaby (SUSE) 
1992a2f3d83cSJiri Slaby (SUSE) 		/* Enable refresh */
1993a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
1994a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
1995a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
1996a2f3d83cSJiri Slaby (SUSE) 
1997a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREGOR(SISSR, 0x21, 0x20);
1998a2f3d83cSJiri Slaby (SUSE) 
1999a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x22, 0xfb);
2000a2f3d83cSJiri Slaby (SUSE) 		ret |= SETIREG(SISSR, 0x21, 0xa5);
2001a2f3d83cSJiri Slaby (SUSE) 
2002a2f3d83cSJiri Slaby (SUSE) 		if (ret == 0)
2003a2f3d83cSJiri Slaby (SUSE) 			break;
2004a2f3d83cSJiri Slaby (SUSE) 	}
2005a2f3d83cSJiri Slaby (SUSE) 
2006a2f3d83cSJiri Slaby (SUSE) 	return ret;
2007a2f3d83cSJiri Slaby (SUSE) }
2008a2f3d83cSJiri Slaby (SUSE) 
2009a2f3d83cSJiri Slaby (SUSE) #undef SETREG
2010a2f3d83cSJiri Slaby (SUSE) #undef GETREG
2011a2f3d83cSJiri Slaby (SUSE) #undef SETIREG
2012a2f3d83cSJiri Slaby (SUSE) #undef GETIREG
2013a2f3d83cSJiri Slaby (SUSE) #undef SETIREGOR
2014a2f3d83cSJiri Slaby (SUSE) #undef SETIREGAND
2015a2f3d83cSJiri Slaby (SUSE) #undef SETIREGANDOR
2016a2f3d83cSJiri Slaby (SUSE) #undef READL
2017a2f3d83cSJiri Slaby (SUSE) #undef WRITEL
2018a2f3d83cSJiri Slaby (SUSE) 
sisusb_get_ramconfig(struct sisusb_usb_data * sisusb)2019a2f3d83cSJiri Slaby (SUSE) static void sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2020a2f3d83cSJiri Slaby (SUSE) {
2021a2f3d83cSJiri Slaby (SUSE) 	u8 tmp8, tmp82, ramtype;
2022a2f3d83cSJiri Slaby (SUSE) 	int bw = 0;
2023a2f3d83cSJiri Slaby (SUSE) 	char *ramtypetext1 = NULL;
2024a2f3d83cSJiri Slaby (SUSE) 	static const char ram_datarate[4] = {'S', 'S', 'D', 'D'};
2025a2f3d83cSJiri Slaby (SUSE) 	static const char ram_dynamictype[4] = {'D', 'G', 'D', 'G'};
2026a2f3d83cSJiri Slaby (SUSE) 	static const int busSDR[4]  = {64, 64, 128, 128};
2027a2f3d83cSJiri Slaby (SUSE) 	static const int busDDR[4]  = {32, 32,  64,  64};
2028a2f3d83cSJiri Slaby (SUSE) 	static const int busDDRA[4] = {64+32, 64+32, (64+32)*2, (64+32)*2};
2029a2f3d83cSJiri Slaby (SUSE) 
2030a2f3d83cSJiri Slaby (SUSE) 	sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2031a2f3d83cSJiri Slaby (SUSE) 	sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2032a2f3d83cSJiri Slaby (SUSE) 	sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2033a2f3d83cSJiri Slaby (SUSE) 	sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2034a2f3d83cSJiri Slaby (SUSE) 	ramtype &= 0x03;
2035a2f3d83cSJiri Slaby (SUSE) 	switch ((tmp8 >> 2) & 0x03) {
2036a2f3d83cSJiri Slaby (SUSE) 	case 0:
2037a2f3d83cSJiri Slaby (SUSE) 		ramtypetext1 = "1 ch/1 r";
2038a2f3d83cSJiri Slaby (SUSE) 		if (tmp82 & 0x10)
2039a2f3d83cSJiri Slaby (SUSE) 			bw = 32;
2040a2f3d83cSJiri Slaby (SUSE) 		else
2041a2f3d83cSJiri Slaby (SUSE) 			bw = busSDR[(tmp8 & 0x03)];
2042a2f3d83cSJiri Slaby (SUSE) 
2043a2f3d83cSJiri Slaby (SUSE) 		break;
2044a2f3d83cSJiri Slaby (SUSE) 	case 1:
2045a2f3d83cSJiri Slaby (SUSE) 		ramtypetext1 = "1 ch/2 r";
2046a2f3d83cSJiri Slaby (SUSE) 		sisusb->vramsize <<= 1;
2047a2f3d83cSJiri Slaby (SUSE) 		bw = busSDR[(tmp8 & 0x03)];
2048a2f3d83cSJiri Slaby (SUSE) 		break;
2049a2f3d83cSJiri Slaby (SUSE) 	case 2:
2050a2f3d83cSJiri Slaby (SUSE) 		ramtypetext1 = "asymmetric";
2051a2f3d83cSJiri Slaby (SUSE) 		sisusb->vramsize += sisusb->vramsize/2;
2052a2f3d83cSJiri Slaby (SUSE) 		bw = busDDRA[(tmp8 & 0x03)];
2053a2f3d83cSJiri Slaby (SUSE) 		break;
2054a2f3d83cSJiri Slaby (SUSE) 	case 3:
2055a2f3d83cSJiri Slaby (SUSE) 		ramtypetext1 = "2 channel";
2056a2f3d83cSJiri Slaby (SUSE) 		sisusb->vramsize <<= 1;
2057a2f3d83cSJiri Slaby (SUSE) 		bw = busDDR[(tmp8 & 0x03)];
2058a2f3d83cSJiri Slaby (SUSE) 		break;
2059a2f3d83cSJiri Slaby (SUSE) 	}
2060a2f3d83cSJiri Slaby (SUSE) 
2061a2f3d83cSJiri Slaby (SUSE) 	dev_info(&sisusb->sisusb_dev->dev,
2062a2f3d83cSJiri Slaby (SUSE) 			"%dMB %s %cDR S%cRAM, bus width %d\n",
2063a2f3d83cSJiri Slaby (SUSE) 			sisusb->vramsize >> 20, ramtypetext1,
2064a2f3d83cSJiri Slaby (SUSE) 			ram_datarate[ramtype], ram_dynamictype[ramtype], bw);
2065a2f3d83cSJiri Slaby (SUSE) }
2066a2f3d83cSJiri Slaby (SUSE) 
sisusb_do_init_gfxdevice(struct sisusb_usb_data * sisusb)2067a2f3d83cSJiri Slaby (SUSE) static int sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2068a2f3d83cSJiri Slaby (SUSE) {
2069a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_packet packet;
2070a2f3d83cSJiri Slaby (SUSE) 	int ret;
2071a2f3d83cSJiri Slaby (SUSE) 	u32 tmp32;
2072a2f3d83cSJiri Slaby (SUSE) 
2073a2f3d83cSJiri Slaby (SUSE) 	/* Do some magic */
2074a2f3d83cSJiri Slaby (SUSE) 	packet.header  = 0x001f;
2075a2f3d83cSJiri Slaby (SUSE) 	packet.address = 0x00000324;
2076a2f3d83cSJiri Slaby (SUSE) 	packet.data    = 0x00000004;
2077a2f3d83cSJiri Slaby (SUSE) 	ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2078a2f3d83cSJiri Slaby (SUSE) 
2079a2f3d83cSJiri Slaby (SUSE) 	packet.header  = 0x001f;
2080a2f3d83cSJiri Slaby (SUSE) 	packet.address = 0x00000364;
2081a2f3d83cSJiri Slaby (SUSE) 	packet.data    = 0x00000004;
2082a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2083a2f3d83cSJiri Slaby (SUSE) 
2084a2f3d83cSJiri Slaby (SUSE) 	packet.header  = 0x001f;
2085a2f3d83cSJiri Slaby (SUSE) 	packet.address = 0x00000384;
2086a2f3d83cSJiri Slaby (SUSE) 	packet.data    = 0x00000004;
2087a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2088a2f3d83cSJiri Slaby (SUSE) 
2089a2f3d83cSJiri Slaby (SUSE) 	packet.header  = 0x001f;
2090a2f3d83cSJiri Slaby (SUSE) 	packet.address = 0x00000100;
2091a2f3d83cSJiri Slaby (SUSE) 	packet.data    = 0x00000700;
2092a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2093a2f3d83cSJiri Slaby (SUSE) 
2094a2f3d83cSJiri Slaby (SUSE) 	packet.header  = 0x000f;
2095a2f3d83cSJiri Slaby (SUSE) 	packet.address = 0x00000004;
2096a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2097a2f3d83cSJiri Slaby (SUSE) 	packet.data |= 0x17;
2098a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2099a2f3d83cSJiri Slaby (SUSE) 
2100a2f3d83cSJiri Slaby (SUSE) 	/* Init BAR 0 (VRAM) */
2101a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2102a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2103a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2104a2f3d83cSJiri Slaby (SUSE) 	tmp32 &= 0x0f;
2105a2f3d83cSJiri Slaby (SUSE) 	tmp32 |= SISUSB_PCI_MEMBASE;
2106a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2107a2f3d83cSJiri Slaby (SUSE) 
2108a2f3d83cSJiri Slaby (SUSE) 	/* Init BAR 1 (MMIO) */
2109a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2110a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2111a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2112a2f3d83cSJiri Slaby (SUSE) 	tmp32 &= 0x0f;
2113a2f3d83cSJiri Slaby (SUSE) 	tmp32 |= SISUSB_PCI_MMIOBASE;
2114a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2115a2f3d83cSJiri Slaby (SUSE) 
2116a2f3d83cSJiri Slaby (SUSE) 	/* Init BAR 2 (i/o ports) */
2117a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2118a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2119a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2120a2f3d83cSJiri Slaby (SUSE) 	tmp32 &= 0x0f;
2121a2f3d83cSJiri Slaby (SUSE) 	tmp32 |= SISUSB_PCI_IOPORTBASE;
2122a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2123a2f3d83cSJiri Slaby (SUSE) 
2124a2f3d83cSJiri Slaby (SUSE) 	/* Enable memory and i/o access */
2125a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2126a2f3d83cSJiri Slaby (SUSE) 	tmp32 |= 0x3;
2127a2f3d83cSJiri Slaby (SUSE) 	ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2128a2f3d83cSJiri Slaby (SUSE) 
2129a2f3d83cSJiri Slaby (SUSE) 	if (ret == 0) {
2130a2f3d83cSJiri Slaby (SUSE) 		/* Some further magic */
2131a2f3d83cSJiri Slaby (SUSE) 		packet.header  = 0x001f;
2132a2f3d83cSJiri Slaby (SUSE) 		packet.address = 0x00000050;
2133a2f3d83cSJiri Slaby (SUSE) 		packet.data    = 0x000000ff;
2134a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2135a2f3d83cSJiri Slaby (SUSE) 	}
2136a2f3d83cSJiri Slaby (SUSE) 
2137a2f3d83cSJiri Slaby (SUSE) 	return ret;
2138a2f3d83cSJiri Slaby (SUSE) }
2139a2f3d83cSJiri Slaby (SUSE) 
2140a2f3d83cSJiri Slaby (SUSE) /* Initialize the graphics device (return 0 on success)
2141a2f3d83cSJiri Slaby (SUSE)  * This initializes the net2280 as well as the PCI registers
2142a2f3d83cSJiri Slaby (SUSE)  * of the graphics board.
2143a2f3d83cSJiri Slaby (SUSE)  */
2144a2f3d83cSJiri Slaby (SUSE) 
sisusb_init_gfxdevice(struct sisusb_usb_data * sisusb,int initscreen)2145a2f3d83cSJiri Slaby (SUSE) static int sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2146a2f3d83cSJiri Slaby (SUSE) {
2147a2f3d83cSJiri Slaby (SUSE) 	int ret = 0, test = 0;
2148a2f3d83cSJiri Slaby (SUSE) 	u32 tmp32;
2149a2f3d83cSJiri Slaby (SUSE) 
2150a2f3d83cSJiri Slaby (SUSE) 	if (sisusb->devinit == 1) {
2151a2f3d83cSJiri Slaby (SUSE) 		/* Read PCI BARs and see if they have been set up */
2152a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2153a2f3d83cSJiri Slaby (SUSE) 		if (ret)
2154a2f3d83cSJiri Slaby (SUSE) 			return ret;
2155a2f3d83cSJiri Slaby (SUSE) 
2156a2f3d83cSJiri Slaby (SUSE) 		if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE)
2157a2f3d83cSJiri Slaby (SUSE) 			test++;
2158a2f3d83cSJiri Slaby (SUSE) 
2159a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2160a2f3d83cSJiri Slaby (SUSE) 		if (ret)
2161a2f3d83cSJiri Slaby (SUSE) 			return ret;
2162a2f3d83cSJiri Slaby (SUSE) 
2163a2f3d83cSJiri Slaby (SUSE) 		if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE)
2164a2f3d83cSJiri Slaby (SUSE) 			test++;
2165a2f3d83cSJiri Slaby (SUSE) 
2166a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2167a2f3d83cSJiri Slaby (SUSE) 		if (ret)
2168a2f3d83cSJiri Slaby (SUSE) 			return ret;
2169a2f3d83cSJiri Slaby (SUSE) 
2170a2f3d83cSJiri Slaby (SUSE) 		if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE)
2171a2f3d83cSJiri Slaby (SUSE) 			test++;
2172a2f3d83cSJiri Slaby (SUSE) 	}
2173a2f3d83cSJiri Slaby (SUSE) 
2174a2f3d83cSJiri Slaby (SUSE) 	/* No? So reset the device */
2175a2f3d83cSJiri Slaby (SUSE) 	if ((sisusb->devinit == 0) || (test != 3)) {
2176a2f3d83cSJiri Slaby (SUSE) 
2177a2f3d83cSJiri Slaby (SUSE) 		ret |= sisusb_do_init_gfxdevice(sisusb);
2178a2f3d83cSJiri Slaby (SUSE) 
2179a2f3d83cSJiri Slaby (SUSE) 		if (ret == 0)
2180a2f3d83cSJiri Slaby (SUSE) 			sisusb->devinit = 1;
2181a2f3d83cSJiri Slaby (SUSE) 
2182a2f3d83cSJiri Slaby (SUSE) 	}
2183a2f3d83cSJiri Slaby (SUSE) 
2184a2f3d83cSJiri Slaby (SUSE) 	if (sisusb->devinit) {
2185a2f3d83cSJiri Slaby (SUSE) 		/* Initialize the graphics core */
2186a2f3d83cSJiri Slaby (SUSE) 		if (sisusb_init_gfxcore(sisusb) == 0) {
2187a2f3d83cSJiri Slaby (SUSE) 			sisusb->gfxinit = 1;
2188a2f3d83cSJiri Slaby (SUSE) 			sisusb_get_ramconfig(sisusb);
2189a2f3d83cSJiri Slaby (SUSE) 			sisusb_set_default_mode(sisusb, 1);
2190a2f3d83cSJiri Slaby (SUSE) 			ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2191a2f3d83cSJiri Slaby (SUSE) 		}
2192a2f3d83cSJiri Slaby (SUSE) 	}
2193a2f3d83cSJiri Slaby (SUSE) 
2194a2f3d83cSJiri Slaby (SUSE) 	return ret;
2195a2f3d83cSJiri Slaby (SUSE) }
2196a2f3d83cSJiri Slaby (SUSE) 
2197a2f3d83cSJiri Slaby (SUSE) /* fops */
2198a2f3d83cSJiri Slaby (SUSE) 
sisusb_open(struct inode * inode,struct file * file)2199a2f3d83cSJiri Slaby (SUSE) static int sisusb_open(struct inode *inode, struct file *file)
2200a2f3d83cSJiri Slaby (SUSE) {
2201a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_usb_data *sisusb;
2202a2f3d83cSJiri Slaby (SUSE) 	struct usb_interface *interface;
2203a2f3d83cSJiri Slaby (SUSE) 	int subminor = iminor(inode);
2204a2f3d83cSJiri Slaby (SUSE) 
2205a2f3d83cSJiri Slaby (SUSE) 	interface = usb_find_interface(&sisusb_driver, subminor);
2206a2f3d83cSJiri Slaby (SUSE) 	if (!interface)
2207a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2208a2f3d83cSJiri Slaby (SUSE) 
2209a2f3d83cSJiri Slaby (SUSE) 	sisusb = usb_get_intfdata(interface);
2210a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb)
2211a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2212a2f3d83cSJiri Slaby (SUSE) 
2213a2f3d83cSJiri Slaby (SUSE) 	mutex_lock(&sisusb->lock);
2214a2f3d83cSJiri Slaby (SUSE) 
2215a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb->present || !sisusb->ready) {
2216a2f3d83cSJiri Slaby (SUSE) 		mutex_unlock(&sisusb->lock);
2217a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2218a2f3d83cSJiri Slaby (SUSE) 	}
2219a2f3d83cSJiri Slaby (SUSE) 
2220a2f3d83cSJiri Slaby (SUSE) 	if (sisusb->isopen) {
2221a2f3d83cSJiri Slaby (SUSE) 		mutex_unlock(&sisusb->lock);
2222a2f3d83cSJiri Slaby (SUSE) 		return -EBUSY;
2223a2f3d83cSJiri Slaby (SUSE) 	}
2224a2f3d83cSJiri Slaby (SUSE) 
2225a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb->devinit) {
2226a2f3d83cSJiri Slaby (SUSE) 		if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH ||
2227a2f3d83cSJiri Slaby (SUSE) 				sisusb->sisusb_dev->speed >= USB_SPEED_SUPER) {
2228a2f3d83cSJiri Slaby (SUSE) 			if (sisusb_init_gfxdevice(sisusb, 0)) {
2229a2f3d83cSJiri Slaby (SUSE) 				mutex_unlock(&sisusb->lock);
2230a2f3d83cSJiri Slaby (SUSE) 				dev_err(&sisusb->sisusb_dev->dev,
2231a2f3d83cSJiri Slaby (SUSE) 						"Failed to initialize device\n");
2232a2f3d83cSJiri Slaby (SUSE) 				return -EIO;
2233a2f3d83cSJiri Slaby (SUSE) 			}
2234a2f3d83cSJiri Slaby (SUSE) 		} else {
2235a2f3d83cSJiri Slaby (SUSE) 			mutex_unlock(&sisusb->lock);
2236a2f3d83cSJiri Slaby (SUSE) 			dev_err(&sisusb->sisusb_dev->dev,
2237a2f3d83cSJiri Slaby (SUSE) 					"Device not attached to USB 2.0 hub\n");
2238a2f3d83cSJiri Slaby (SUSE) 			return -EIO;
2239a2f3d83cSJiri Slaby (SUSE) 		}
2240a2f3d83cSJiri Slaby (SUSE) 	}
2241a2f3d83cSJiri Slaby (SUSE) 
2242a2f3d83cSJiri Slaby (SUSE) 	/* Increment usage count for our sisusb */
2243a2f3d83cSJiri Slaby (SUSE) 	kref_get(&sisusb->kref);
2244a2f3d83cSJiri Slaby (SUSE) 
2245a2f3d83cSJiri Slaby (SUSE) 	sisusb->isopen = 1;
2246a2f3d83cSJiri Slaby (SUSE) 
2247a2f3d83cSJiri Slaby (SUSE) 	file->private_data = sisusb;
2248a2f3d83cSJiri Slaby (SUSE) 
2249a2f3d83cSJiri Slaby (SUSE) 	mutex_unlock(&sisusb->lock);
2250a2f3d83cSJiri Slaby (SUSE) 
2251a2f3d83cSJiri Slaby (SUSE) 	return 0;
2252a2f3d83cSJiri Slaby (SUSE) }
2253a2f3d83cSJiri Slaby (SUSE) 
sisusb_delete(struct kref * kref)2254a2f3d83cSJiri Slaby (SUSE) static void sisusb_delete(struct kref *kref)
2255a2f3d83cSJiri Slaby (SUSE) {
2256a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2257a2f3d83cSJiri Slaby (SUSE) 
2258a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb)
2259a2f3d83cSJiri Slaby (SUSE) 		return;
2260a2f3d83cSJiri Slaby (SUSE) 
2261a2f3d83cSJiri Slaby (SUSE) 	usb_put_dev(sisusb->sisusb_dev);
2262a2f3d83cSJiri Slaby (SUSE) 
2263a2f3d83cSJiri Slaby (SUSE) 	sisusb->sisusb_dev = NULL;
2264a2f3d83cSJiri Slaby (SUSE) 	sisusb_free_buffers(sisusb);
2265a2f3d83cSJiri Slaby (SUSE) 	sisusb_free_urbs(sisusb);
2266a2f3d83cSJiri Slaby (SUSE) 	kfree(sisusb);
2267a2f3d83cSJiri Slaby (SUSE) }
2268a2f3d83cSJiri Slaby (SUSE) 
sisusb_release(struct inode * inode,struct file * file)2269a2f3d83cSJiri Slaby (SUSE) static int sisusb_release(struct inode *inode, struct file *file)
2270a2f3d83cSJiri Slaby (SUSE) {
2271a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_usb_data *sisusb;
2272a2f3d83cSJiri Slaby (SUSE) 
2273a2f3d83cSJiri Slaby (SUSE) 	sisusb = file->private_data;
2274a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb)
2275a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2276a2f3d83cSJiri Slaby (SUSE) 
2277a2f3d83cSJiri Slaby (SUSE) 	mutex_lock(&sisusb->lock);
2278a2f3d83cSJiri Slaby (SUSE) 
2279a2f3d83cSJiri Slaby (SUSE) 	if (sisusb->present) {
2280a2f3d83cSJiri Slaby (SUSE) 		/* Wait for all URBs to finish if device still present */
2281a2f3d83cSJiri Slaby (SUSE) 		if (!sisusb_wait_all_out_complete(sisusb))
2282a2f3d83cSJiri Slaby (SUSE) 			sisusb_kill_all_busy(sisusb);
2283a2f3d83cSJiri Slaby (SUSE) 	}
2284a2f3d83cSJiri Slaby (SUSE) 
2285a2f3d83cSJiri Slaby (SUSE) 	sisusb->isopen = 0;
2286a2f3d83cSJiri Slaby (SUSE) 	file->private_data = NULL;
2287a2f3d83cSJiri Slaby (SUSE) 
2288a2f3d83cSJiri Slaby (SUSE) 	mutex_unlock(&sisusb->lock);
2289a2f3d83cSJiri Slaby (SUSE) 
2290a2f3d83cSJiri Slaby (SUSE) 	/* decrement the usage count on our device */
2291a2f3d83cSJiri Slaby (SUSE) 	kref_put(&sisusb->kref, sisusb_delete);
2292a2f3d83cSJiri Slaby (SUSE) 
2293a2f3d83cSJiri Slaby (SUSE) 	return 0;
2294a2f3d83cSJiri Slaby (SUSE) }
2295a2f3d83cSJiri Slaby (SUSE) 
sisusb_read(struct file * file,char __user * buffer,size_t count,loff_t * ppos)2296a2f3d83cSJiri Slaby (SUSE) static ssize_t sisusb_read(struct file *file, char __user *buffer,
2297a2f3d83cSJiri Slaby (SUSE) 		size_t count, loff_t *ppos)
2298a2f3d83cSJiri Slaby (SUSE) {
2299a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_usb_data *sisusb;
2300a2f3d83cSJiri Slaby (SUSE) 	ssize_t bytes_read = 0;
2301a2f3d83cSJiri Slaby (SUSE) 	int errno = 0;
2302a2f3d83cSJiri Slaby (SUSE) 	u8 buf8;
2303a2f3d83cSJiri Slaby (SUSE) 	u16 buf16;
2304a2f3d83cSJiri Slaby (SUSE) 	u32 buf32, address;
2305a2f3d83cSJiri Slaby (SUSE) 
2306a2f3d83cSJiri Slaby (SUSE) 	sisusb = file->private_data;
2307a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb)
2308a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2309a2f3d83cSJiri Slaby (SUSE) 
2310a2f3d83cSJiri Slaby (SUSE) 	mutex_lock(&sisusb->lock);
2311a2f3d83cSJiri Slaby (SUSE) 
2312a2f3d83cSJiri Slaby (SUSE) 	/* Sanity check */
2313a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2314a2f3d83cSJiri Slaby (SUSE) 		mutex_unlock(&sisusb->lock);
2315a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2316a2f3d83cSJiri Slaby (SUSE) 	}
2317a2f3d83cSJiri Slaby (SUSE) 
2318a2f3d83cSJiri Slaby (SUSE) 	if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2319a2f3d83cSJiri Slaby (SUSE) 			(*ppos) <  SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2320a2f3d83cSJiri Slaby (SUSE) 
2321a2f3d83cSJiri Slaby (SUSE) 		address = (*ppos) - SISUSB_PCI_PSEUDO_IOPORTBASE +
2322a2f3d83cSJiri Slaby (SUSE) 				SISUSB_PCI_IOPORTBASE;
2323a2f3d83cSJiri Slaby (SUSE) 
2324a2f3d83cSJiri Slaby (SUSE) 		/* Read i/o ports
2325a2f3d83cSJiri Slaby (SUSE) 		 * Byte, word and long(32) can be read. As this
2326a2f3d83cSJiri Slaby (SUSE) 		 * emulates inX instructions, the data returned is
2327a2f3d83cSJiri Slaby (SUSE) 		 * in machine-endianness.
2328a2f3d83cSJiri Slaby (SUSE) 		 */
2329a2f3d83cSJiri Slaby (SUSE) 		switch (count) {
2330a2f3d83cSJiri Slaby (SUSE) 		case 1:
2331a2f3d83cSJiri Slaby (SUSE) 			if (sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO,
2332a2f3d83cSJiri Slaby (SUSE) 					address, &buf8))
2333a2f3d83cSJiri Slaby (SUSE) 				errno = -EIO;
2334a2f3d83cSJiri Slaby (SUSE) 			else if (put_user(buf8, (u8 __user *)buffer))
2335a2f3d83cSJiri Slaby (SUSE) 				errno = -EFAULT;
2336a2f3d83cSJiri Slaby (SUSE) 			else
2337a2f3d83cSJiri Slaby (SUSE) 				bytes_read = 1;
2338a2f3d83cSJiri Slaby (SUSE) 
2339a2f3d83cSJiri Slaby (SUSE) 			break;
2340a2f3d83cSJiri Slaby (SUSE) 
2341a2f3d83cSJiri Slaby (SUSE) 		case 2:
2342a2f3d83cSJiri Slaby (SUSE) 			if (sisusb_read_memio_word(sisusb, SISUSB_TYPE_IO,
2343a2f3d83cSJiri Slaby (SUSE) 					address, &buf16))
2344a2f3d83cSJiri Slaby (SUSE) 				errno = -EIO;
2345a2f3d83cSJiri Slaby (SUSE) 			else if (put_user(buf16, (u16 __user *)buffer))
2346a2f3d83cSJiri Slaby (SUSE) 				errno = -EFAULT;
2347a2f3d83cSJiri Slaby (SUSE) 			else
2348a2f3d83cSJiri Slaby (SUSE) 				bytes_read = 2;
2349a2f3d83cSJiri Slaby (SUSE) 
2350a2f3d83cSJiri Slaby (SUSE) 			break;
2351a2f3d83cSJiri Slaby (SUSE) 
2352a2f3d83cSJiri Slaby (SUSE) 		case 4:
2353a2f3d83cSJiri Slaby (SUSE) 			if (sisusb_read_memio_long(sisusb, SISUSB_TYPE_IO,
2354a2f3d83cSJiri Slaby (SUSE) 					address, &buf32))
2355a2f3d83cSJiri Slaby (SUSE) 				errno = -EIO;
2356a2f3d83cSJiri Slaby (SUSE) 			else if (put_user(buf32, (u32 __user *)buffer))
2357a2f3d83cSJiri Slaby (SUSE) 				errno = -EFAULT;
2358a2f3d83cSJiri Slaby (SUSE) 			else
2359a2f3d83cSJiri Slaby (SUSE) 				bytes_read = 4;
2360a2f3d83cSJiri Slaby (SUSE) 
2361a2f3d83cSJiri Slaby (SUSE) 			break;
2362a2f3d83cSJiri Slaby (SUSE) 
2363a2f3d83cSJiri Slaby (SUSE) 		default:
2364a2f3d83cSJiri Slaby (SUSE) 			errno = -EIO;
2365a2f3d83cSJiri Slaby (SUSE) 
2366a2f3d83cSJiri Slaby (SUSE) 		}
2367a2f3d83cSJiri Slaby (SUSE) 
2368a2f3d83cSJiri Slaby (SUSE) 	} else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE && (*ppos) <
2369a2f3d83cSJiri Slaby (SUSE) 			SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2370a2f3d83cSJiri Slaby (SUSE) 
2371a2f3d83cSJiri Slaby (SUSE) 		address = (*ppos) - SISUSB_PCI_PSEUDO_MEMBASE +
2372a2f3d83cSJiri Slaby (SUSE) 				SISUSB_PCI_MEMBASE;
2373a2f3d83cSJiri Slaby (SUSE) 
2374a2f3d83cSJiri Slaby (SUSE) 		/* Read video ram
2375a2f3d83cSJiri Slaby (SUSE) 		 * Remember: Data delivered is never endian-corrected
2376a2f3d83cSJiri Slaby (SUSE) 		 */
2377a2f3d83cSJiri Slaby (SUSE) 		errno = sisusb_read_mem_bulk(sisusb, address,
2378a2f3d83cSJiri Slaby (SUSE) 				NULL, count, buffer, &bytes_read);
2379a2f3d83cSJiri Slaby (SUSE) 
2380a2f3d83cSJiri Slaby (SUSE) 		if (bytes_read)
2381a2f3d83cSJiri Slaby (SUSE) 			errno = bytes_read;
2382a2f3d83cSJiri Slaby (SUSE) 
2383a2f3d83cSJiri Slaby (SUSE) 	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2384a2f3d83cSJiri Slaby (SUSE) 				(*ppos) <  SISUSB_PCI_PSEUDO_MMIOBASE +
2385a2f3d83cSJiri Slaby (SUSE) 				SISUSB_PCI_MMIOSIZE) {
2386a2f3d83cSJiri Slaby (SUSE) 
2387a2f3d83cSJiri Slaby (SUSE) 		address = (*ppos) - SISUSB_PCI_PSEUDO_MMIOBASE +
2388a2f3d83cSJiri Slaby (SUSE) 				SISUSB_PCI_MMIOBASE;
2389a2f3d83cSJiri Slaby (SUSE) 
2390a2f3d83cSJiri Slaby (SUSE) 		/* Read MMIO
2391a2f3d83cSJiri Slaby (SUSE) 		 * Remember: Data delivered is never endian-corrected
2392a2f3d83cSJiri Slaby (SUSE) 		 */
2393a2f3d83cSJiri Slaby (SUSE) 		errno = sisusb_read_mem_bulk(sisusb, address,
2394a2f3d83cSJiri Slaby (SUSE) 				NULL, count, buffer, &bytes_read);
2395a2f3d83cSJiri Slaby (SUSE) 
2396a2f3d83cSJiri Slaby (SUSE) 		if (bytes_read)
2397a2f3d83cSJiri Slaby (SUSE) 			errno = bytes_read;
2398a2f3d83cSJiri Slaby (SUSE) 
2399a2f3d83cSJiri Slaby (SUSE) 	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2400a2f3d83cSJiri Slaby (SUSE) 			(*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2401a2f3d83cSJiri Slaby (SUSE) 
2402a2f3d83cSJiri Slaby (SUSE) 		if (count != 4) {
2403a2f3d83cSJiri Slaby (SUSE) 			mutex_unlock(&sisusb->lock);
2404a2f3d83cSJiri Slaby (SUSE) 			return -EINVAL;
2405a2f3d83cSJiri Slaby (SUSE) 		}
2406a2f3d83cSJiri Slaby (SUSE) 
2407a2f3d83cSJiri Slaby (SUSE) 		address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2408a2f3d83cSJiri Slaby (SUSE) 
2409a2f3d83cSJiri Slaby (SUSE) 		/* Read PCI config register
2410a2f3d83cSJiri Slaby (SUSE) 		 * Return value delivered in machine endianness.
2411a2f3d83cSJiri Slaby (SUSE) 		 */
2412a2f3d83cSJiri Slaby (SUSE) 		if (sisusb_read_pci_config(sisusb, address, &buf32))
2413a2f3d83cSJiri Slaby (SUSE) 			errno = -EIO;
2414a2f3d83cSJiri Slaby (SUSE) 		else if (put_user(buf32, (u32 __user *)buffer))
2415a2f3d83cSJiri Slaby (SUSE) 			errno = -EFAULT;
2416a2f3d83cSJiri Slaby (SUSE) 		else
2417a2f3d83cSJiri Slaby (SUSE) 			bytes_read = 4;
2418a2f3d83cSJiri Slaby (SUSE) 
2419a2f3d83cSJiri Slaby (SUSE) 	} else {
2420a2f3d83cSJiri Slaby (SUSE) 
2421a2f3d83cSJiri Slaby (SUSE) 		errno = -EBADFD;
2422a2f3d83cSJiri Slaby (SUSE) 
2423a2f3d83cSJiri Slaby (SUSE) 	}
2424a2f3d83cSJiri Slaby (SUSE) 
2425a2f3d83cSJiri Slaby (SUSE) 	(*ppos) += bytes_read;
2426a2f3d83cSJiri Slaby (SUSE) 
2427a2f3d83cSJiri Slaby (SUSE) 	mutex_unlock(&sisusb->lock);
2428a2f3d83cSJiri Slaby (SUSE) 
2429a2f3d83cSJiri Slaby (SUSE) 	return errno ? errno : bytes_read;
2430a2f3d83cSJiri Slaby (SUSE) }
2431a2f3d83cSJiri Slaby (SUSE) 
sisusb_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)2432a2f3d83cSJiri Slaby (SUSE) static ssize_t sisusb_write(struct file *file, const char __user *buffer,
2433a2f3d83cSJiri Slaby (SUSE) 		size_t count, loff_t *ppos)
2434a2f3d83cSJiri Slaby (SUSE) {
2435a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_usb_data *sisusb;
2436a2f3d83cSJiri Slaby (SUSE) 	int errno = 0;
2437a2f3d83cSJiri Slaby (SUSE) 	ssize_t bytes_written = 0;
2438a2f3d83cSJiri Slaby (SUSE) 	u8 buf8;
2439a2f3d83cSJiri Slaby (SUSE) 	u16 buf16;
2440a2f3d83cSJiri Slaby (SUSE) 	u32 buf32, address;
2441a2f3d83cSJiri Slaby (SUSE) 
2442a2f3d83cSJiri Slaby (SUSE) 	sisusb = file->private_data;
2443a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb)
2444a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2445a2f3d83cSJiri Slaby (SUSE) 
2446a2f3d83cSJiri Slaby (SUSE) 	mutex_lock(&sisusb->lock);
2447a2f3d83cSJiri Slaby (SUSE) 
2448a2f3d83cSJiri Slaby (SUSE) 	/* Sanity check */
2449a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2450a2f3d83cSJiri Slaby (SUSE) 		mutex_unlock(&sisusb->lock);
2451a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2452a2f3d83cSJiri Slaby (SUSE) 	}
2453a2f3d83cSJiri Slaby (SUSE) 
2454a2f3d83cSJiri Slaby (SUSE) 	if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2455a2f3d83cSJiri Slaby (SUSE) 			(*ppos) <  SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2456a2f3d83cSJiri Slaby (SUSE) 
2457a2f3d83cSJiri Slaby (SUSE) 		address = (*ppos) - SISUSB_PCI_PSEUDO_IOPORTBASE +
2458a2f3d83cSJiri Slaby (SUSE) 				SISUSB_PCI_IOPORTBASE;
2459a2f3d83cSJiri Slaby (SUSE) 
2460a2f3d83cSJiri Slaby (SUSE) 		/* Write i/o ports
2461a2f3d83cSJiri Slaby (SUSE) 		 * Byte, word and long(32) can be written. As this
2462a2f3d83cSJiri Slaby (SUSE) 		 * emulates outX instructions, the data is expected
2463a2f3d83cSJiri Slaby (SUSE) 		 * in machine-endianness.
2464a2f3d83cSJiri Slaby (SUSE) 		 */
2465a2f3d83cSJiri Slaby (SUSE) 		switch (count) {
2466a2f3d83cSJiri Slaby (SUSE) 		case 1:
2467a2f3d83cSJiri Slaby (SUSE) 			if (get_user(buf8, (u8 __user *)buffer))
2468a2f3d83cSJiri Slaby (SUSE) 				errno = -EFAULT;
2469a2f3d83cSJiri Slaby (SUSE) 			else if (sisusb_write_memio_byte(sisusb,
2470a2f3d83cSJiri Slaby (SUSE) 					SISUSB_TYPE_IO, address, buf8))
2471a2f3d83cSJiri Slaby (SUSE) 				errno = -EIO;
2472a2f3d83cSJiri Slaby (SUSE) 			else
2473a2f3d83cSJiri Slaby (SUSE) 				bytes_written = 1;
2474a2f3d83cSJiri Slaby (SUSE) 
2475a2f3d83cSJiri Slaby (SUSE) 			break;
2476a2f3d83cSJiri Slaby (SUSE) 
2477a2f3d83cSJiri Slaby (SUSE) 		case 2:
2478a2f3d83cSJiri Slaby (SUSE) 			if (get_user(buf16, (u16 __user *)buffer))
2479a2f3d83cSJiri Slaby (SUSE) 				errno = -EFAULT;
2480a2f3d83cSJiri Slaby (SUSE) 			else if (sisusb_write_memio_word(sisusb,
2481a2f3d83cSJiri Slaby (SUSE) 					SISUSB_TYPE_IO, address, buf16))
2482a2f3d83cSJiri Slaby (SUSE) 				errno = -EIO;
2483a2f3d83cSJiri Slaby (SUSE) 			else
2484a2f3d83cSJiri Slaby (SUSE) 				bytes_written = 2;
2485a2f3d83cSJiri Slaby (SUSE) 
2486a2f3d83cSJiri Slaby (SUSE) 			break;
2487a2f3d83cSJiri Slaby (SUSE) 
2488a2f3d83cSJiri Slaby (SUSE) 		case 4:
2489a2f3d83cSJiri Slaby (SUSE) 			if (get_user(buf32, (u32 __user *)buffer))
2490a2f3d83cSJiri Slaby (SUSE) 				errno = -EFAULT;
2491a2f3d83cSJiri Slaby (SUSE) 			else if (sisusb_write_memio_long(sisusb,
2492a2f3d83cSJiri Slaby (SUSE) 					SISUSB_TYPE_IO, address, buf32))
2493a2f3d83cSJiri Slaby (SUSE) 				errno = -EIO;
2494a2f3d83cSJiri Slaby (SUSE) 			else
2495a2f3d83cSJiri Slaby (SUSE) 				bytes_written = 4;
2496a2f3d83cSJiri Slaby (SUSE) 
2497a2f3d83cSJiri Slaby (SUSE) 			break;
2498a2f3d83cSJiri Slaby (SUSE) 
2499a2f3d83cSJiri Slaby (SUSE) 		default:
2500a2f3d83cSJiri Slaby (SUSE) 			errno = -EIO;
2501a2f3d83cSJiri Slaby (SUSE) 		}
2502a2f3d83cSJiri Slaby (SUSE) 
2503a2f3d83cSJiri Slaby (SUSE) 	} else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2504a2f3d83cSJiri Slaby (SUSE) 			(*ppos) <  SISUSB_PCI_PSEUDO_MEMBASE +
2505a2f3d83cSJiri Slaby (SUSE) 			sisusb->vramsize) {
2506a2f3d83cSJiri Slaby (SUSE) 
2507a2f3d83cSJiri Slaby (SUSE) 		address = (*ppos) - SISUSB_PCI_PSEUDO_MEMBASE +
2508a2f3d83cSJiri Slaby (SUSE) 				SISUSB_PCI_MEMBASE;
2509a2f3d83cSJiri Slaby (SUSE) 
2510a2f3d83cSJiri Slaby (SUSE) 		/* Write video ram.
2511a2f3d83cSJiri Slaby (SUSE) 		 * Buffer is copied 1:1, therefore, on big-endian
2512a2f3d83cSJiri Slaby (SUSE) 		 * machines, the data must be swapped by userland
2513a2f3d83cSJiri Slaby (SUSE) 		 * in advance (if applicable; no swapping in 8bpp
2514a2f3d83cSJiri Slaby (SUSE) 		 * mode or if YUV data is being transferred).
2515a2f3d83cSJiri Slaby (SUSE) 		 */
2516a2f3d83cSJiri Slaby (SUSE) 		errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2517a2f3d83cSJiri Slaby (SUSE) 				count, buffer, 0, &bytes_written);
2518a2f3d83cSJiri Slaby (SUSE) 
2519a2f3d83cSJiri Slaby (SUSE) 		if (bytes_written)
2520a2f3d83cSJiri Slaby (SUSE) 			errno = bytes_written;
2521a2f3d83cSJiri Slaby (SUSE) 
2522a2f3d83cSJiri Slaby (SUSE) 	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2523a2f3d83cSJiri Slaby (SUSE) 			(*ppos) <  SISUSB_PCI_PSEUDO_MMIOBASE +
2524a2f3d83cSJiri Slaby (SUSE) 			SISUSB_PCI_MMIOSIZE) {
2525a2f3d83cSJiri Slaby (SUSE) 
2526a2f3d83cSJiri Slaby (SUSE) 		address = (*ppos) - SISUSB_PCI_PSEUDO_MMIOBASE +
2527a2f3d83cSJiri Slaby (SUSE) 				SISUSB_PCI_MMIOBASE;
2528a2f3d83cSJiri Slaby (SUSE) 
2529a2f3d83cSJiri Slaby (SUSE) 		/* Write MMIO.
2530a2f3d83cSJiri Slaby (SUSE) 		 * Buffer is copied 1:1, therefore, on big-endian
2531a2f3d83cSJiri Slaby (SUSE) 		 * machines, the data must be swapped by userland
2532a2f3d83cSJiri Slaby (SUSE) 		 * in advance.
2533a2f3d83cSJiri Slaby (SUSE) 		 */
2534a2f3d83cSJiri Slaby (SUSE) 		errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2535a2f3d83cSJiri Slaby (SUSE) 				count, buffer, 0, &bytes_written);
2536a2f3d83cSJiri Slaby (SUSE) 
2537a2f3d83cSJiri Slaby (SUSE) 		if (bytes_written)
2538a2f3d83cSJiri Slaby (SUSE) 			errno = bytes_written;
2539a2f3d83cSJiri Slaby (SUSE) 
2540a2f3d83cSJiri Slaby (SUSE) 	} else  if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2541a2f3d83cSJiri Slaby (SUSE) 				(*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE +
2542a2f3d83cSJiri Slaby (SUSE) 				SISUSB_PCI_PCONFSIZE) {
2543a2f3d83cSJiri Slaby (SUSE) 
2544a2f3d83cSJiri Slaby (SUSE) 		if (count != 4) {
2545a2f3d83cSJiri Slaby (SUSE) 			mutex_unlock(&sisusb->lock);
2546a2f3d83cSJiri Slaby (SUSE) 			return -EINVAL;
2547a2f3d83cSJiri Slaby (SUSE) 		}
2548a2f3d83cSJiri Slaby (SUSE) 
2549a2f3d83cSJiri Slaby (SUSE) 		address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2550a2f3d83cSJiri Slaby (SUSE) 
2551a2f3d83cSJiri Slaby (SUSE) 		/* Write PCI config register.
2552a2f3d83cSJiri Slaby (SUSE) 		 * Given value expected in machine endianness.
2553a2f3d83cSJiri Slaby (SUSE) 		 */
2554a2f3d83cSJiri Slaby (SUSE) 		if (get_user(buf32, (u32 __user *)buffer))
2555a2f3d83cSJiri Slaby (SUSE) 			errno = -EFAULT;
2556a2f3d83cSJiri Slaby (SUSE) 		else if (sisusb_write_pci_config(sisusb, address, buf32))
2557a2f3d83cSJiri Slaby (SUSE) 			errno = -EIO;
2558a2f3d83cSJiri Slaby (SUSE) 		else
2559a2f3d83cSJiri Slaby (SUSE) 			bytes_written = 4;
2560a2f3d83cSJiri Slaby (SUSE) 
2561a2f3d83cSJiri Slaby (SUSE) 
2562a2f3d83cSJiri Slaby (SUSE) 	} else {
2563a2f3d83cSJiri Slaby (SUSE) 
2564a2f3d83cSJiri Slaby (SUSE) 		/* Error */
2565a2f3d83cSJiri Slaby (SUSE) 		errno = -EBADFD;
2566a2f3d83cSJiri Slaby (SUSE) 
2567a2f3d83cSJiri Slaby (SUSE) 	}
2568a2f3d83cSJiri Slaby (SUSE) 
2569a2f3d83cSJiri Slaby (SUSE) 	(*ppos) += bytes_written;
2570a2f3d83cSJiri Slaby (SUSE) 
2571a2f3d83cSJiri Slaby (SUSE) 	mutex_unlock(&sisusb->lock);
2572a2f3d83cSJiri Slaby (SUSE) 
2573a2f3d83cSJiri Slaby (SUSE) 	return errno ? errno : bytes_written;
2574a2f3d83cSJiri Slaby (SUSE) }
2575a2f3d83cSJiri Slaby (SUSE) 
sisusb_lseek(struct file * file,loff_t offset,int orig)2576a2f3d83cSJiri Slaby (SUSE) static loff_t sisusb_lseek(struct file *file, loff_t offset, int orig)
2577a2f3d83cSJiri Slaby (SUSE) {
2578a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_usb_data *sisusb;
2579a2f3d83cSJiri Slaby (SUSE) 	loff_t ret;
2580a2f3d83cSJiri Slaby (SUSE) 
2581a2f3d83cSJiri Slaby (SUSE) 	sisusb = file->private_data;
2582a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb)
2583a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2584a2f3d83cSJiri Slaby (SUSE) 
2585a2f3d83cSJiri Slaby (SUSE) 	mutex_lock(&sisusb->lock);
2586a2f3d83cSJiri Slaby (SUSE) 
2587a2f3d83cSJiri Slaby (SUSE) 	/* Sanity check */
2588a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2589a2f3d83cSJiri Slaby (SUSE) 		mutex_unlock(&sisusb->lock);
2590a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2591a2f3d83cSJiri Slaby (SUSE) 	}
2592a2f3d83cSJiri Slaby (SUSE) 
2593a2f3d83cSJiri Slaby (SUSE) 	ret = no_seek_end_llseek(file, offset, orig);
2594a2f3d83cSJiri Slaby (SUSE) 
2595a2f3d83cSJiri Slaby (SUSE) 	mutex_unlock(&sisusb->lock);
2596a2f3d83cSJiri Slaby (SUSE) 	return ret;
2597a2f3d83cSJiri Slaby (SUSE) }
2598a2f3d83cSJiri Slaby (SUSE) 
sisusb_handle_command(struct sisusb_usb_data * sisusb,struct sisusb_command * y,unsigned long arg)2599a2f3d83cSJiri Slaby (SUSE) static int sisusb_handle_command(struct sisusb_usb_data *sisusb,
2600a2f3d83cSJiri Slaby (SUSE) 		struct sisusb_command *y, unsigned long arg)
2601a2f3d83cSJiri Slaby (SUSE) {
2602a2f3d83cSJiri Slaby (SUSE) 	int	retval, length;
2603a2f3d83cSJiri Slaby (SUSE) 	u32	port, address;
2604a2f3d83cSJiri Slaby (SUSE) 
2605a2f3d83cSJiri Slaby (SUSE) 	/* All our commands require the device
2606a2f3d83cSJiri Slaby (SUSE) 	 * to be initialized.
2607a2f3d83cSJiri Slaby (SUSE) 	 */
2608a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb->devinit)
2609a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2610a2f3d83cSJiri Slaby (SUSE) 
2611a2f3d83cSJiri Slaby (SUSE) 	port = y->data3 -
2612a2f3d83cSJiri Slaby (SUSE) 		SISUSB_PCI_PSEUDO_IOPORTBASE +
2613a2f3d83cSJiri Slaby (SUSE) 		SISUSB_PCI_IOPORTBASE;
2614a2f3d83cSJiri Slaby (SUSE) 
2615a2f3d83cSJiri Slaby (SUSE) 	switch (y->operation) {
2616a2f3d83cSJiri Slaby (SUSE) 	case SUCMD_GET:
2617a2f3d83cSJiri Slaby (SUSE) 		retval = sisusb_getidxreg(sisusb, port, y->data0, &y->data1);
2618a2f3d83cSJiri Slaby (SUSE) 		if (!retval) {
2619a2f3d83cSJiri Slaby (SUSE) 			if (copy_to_user((void __user *)arg, y, sizeof(*y)))
2620a2f3d83cSJiri Slaby (SUSE) 				retval = -EFAULT;
2621a2f3d83cSJiri Slaby (SUSE) 		}
2622a2f3d83cSJiri Slaby (SUSE) 		break;
2623a2f3d83cSJiri Slaby (SUSE) 
2624a2f3d83cSJiri Slaby (SUSE) 	case SUCMD_SET:
2625a2f3d83cSJiri Slaby (SUSE) 		retval = sisusb_setidxreg(sisusb, port, y->data0, y->data1);
2626a2f3d83cSJiri Slaby (SUSE) 		break;
2627a2f3d83cSJiri Slaby (SUSE) 
2628a2f3d83cSJiri Slaby (SUSE) 	case SUCMD_SETOR:
2629a2f3d83cSJiri Slaby (SUSE) 		retval = sisusb_setidxregor(sisusb, port, y->data0, y->data1);
2630a2f3d83cSJiri Slaby (SUSE) 		break;
2631a2f3d83cSJiri Slaby (SUSE) 
2632a2f3d83cSJiri Slaby (SUSE) 	case SUCMD_SETAND:
2633a2f3d83cSJiri Slaby (SUSE) 		retval = sisusb_setidxregand(sisusb, port, y->data0, y->data1);
2634a2f3d83cSJiri Slaby (SUSE) 		break;
2635a2f3d83cSJiri Slaby (SUSE) 
2636a2f3d83cSJiri Slaby (SUSE) 	case SUCMD_SETANDOR:
2637a2f3d83cSJiri Slaby (SUSE) 		retval = sisusb_setidxregandor(sisusb, port, y->data0,
2638a2f3d83cSJiri Slaby (SUSE) 				y->data1, y->data2);
2639a2f3d83cSJiri Slaby (SUSE) 		break;
2640a2f3d83cSJiri Slaby (SUSE) 
2641a2f3d83cSJiri Slaby (SUSE) 	case SUCMD_SETMASK:
2642a2f3d83cSJiri Slaby (SUSE) 		retval = sisusb_setidxregmask(sisusb, port, y->data0,
2643a2f3d83cSJiri Slaby (SUSE) 				y->data1, y->data2);
2644a2f3d83cSJiri Slaby (SUSE) 		break;
2645a2f3d83cSJiri Slaby (SUSE) 
2646a2f3d83cSJiri Slaby (SUSE) 	case SUCMD_CLRSCR:
2647a2f3d83cSJiri Slaby (SUSE) 		/* Gfx core must be initialized */
2648a2f3d83cSJiri Slaby (SUSE) 		if (!sisusb->gfxinit)
2649a2f3d83cSJiri Slaby (SUSE) 			return -ENODEV;
2650a2f3d83cSJiri Slaby (SUSE) 
2651a2f3d83cSJiri Slaby (SUSE) 		length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
2652a2f3d83cSJiri Slaby (SUSE) 		address = y->data3 - SISUSB_PCI_PSEUDO_MEMBASE +
2653a2f3d83cSJiri Slaby (SUSE) 				SISUSB_PCI_MEMBASE;
2654a2f3d83cSJiri Slaby (SUSE) 		retval = sisusb_clear_vram(sisusb, address, length);
2655a2f3d83cSJiri Slaby (SUSE) 		break;
2656a2f3d83cSJiri Slaby (SUSE) 
2657a2f3d83cSJiri Slaby (SUSE) 	case SUCMD_HANDLETEXTMODE:
2658a2f3d83cSJiri Slaby (SUSE) 		retval = 0;
2659a2f3d83cSJiri Slaby (SUSE) 		break;
2660a2f3d83cSJiri Slaby (SUSE) 
2661a2f3d83cSJiri Slaby (SUSE) 	default:
2662a2f3d83cSJiri Slaby (SUSE) 		retval = -EINVAL;
2663a2f3d83cSJiri Slaby (SUSE) 	}
2664a2f3d83cSJiri Slaby (SUSE) 
2665a2f3d83cSJiri Slaby (SUSE) 	if (retval > 0)
2666a2f3d83cSJiri Slaby (SUSE) 		retval = -EIO;
2667a2f3d83cSJiri Slaby (SUSE) 
2668a2f3d83cSJiri Slaby (SUSE) 	return retval;
2669a2f3d83cSJiri Slaby (SUSE) }
2670a2f3d83cSJiri Slaby (SUSE) 
sisusb_ioctl(struct file * file,unsigned int cmd,unsigned long arg)2671a2f3d83cSJiri Slaby (SUSE) static long sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2672a2f3d83cSJiri Slaby (SUSE) {
2673a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_usb_data *sisusb;
2674a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_info x;
2675a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_command y;
2676a2f3d83cSJiri Slaby (SUSE) 	long retval = 0;
2677a2f3d83cSJiri Slaby (SUSE) 	u32 __user *argp = (u32 __user *)arg;
2678a2f3d83cSJiri Slaby (SUSE) 
2679a2f3d83cSJiri Slaby (SUSE) 	sisusb = file->private_data;
2680a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb)
2681a2f3d83cSJiri Slaby (SUSE) 		return -ENODEV;
2682a2f3d83cSJiri Slaby (SUSE) 
2683a2f3d83cSJiri Slaby (SUSE) 	mutex_lock(&sisusb->lock);
2684a2f3d83cSJiri Slaby (SUSE) 
2685a2f3d83cSJiri Slaby (SUSE) 	/* Sanity check */
2686a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2687a2f3d83cSJiri Slaby (SUSE) 		retval = -ENODEV;
2688a2f3d83cSJiri Slaby (SUSE) 		goto err_out;
2689a2f3d83cSJiri Slaby (SUSE) 	}
2690a2f3d83cSJiri Slaby (SUSE) 
2691a2f3d83cSJiri Slaby (SUSE) 	switch (cmd) {
2692a2f3d83cSJiri Slaby (SUSE) 	case SISUSB_GET_CONFIG_SIZE:
2693a2f3d83cSJiri Slaby (SUSE) 
2694a2f3d83cSJiri Slaby (SUSE) 		if (put_user(sizeof(x), argp))
2695a2f3d83cSJiri Slaby (SUSE) 			retval = -EFAULT;
2696a2f3d83cSJiri Slaby (SUSE) 
2697a2f3d83cSJiri Slaby (SUSE) 		break;
2698a2f3d83cSJiri Slaby (SUSE) 
2699a2f3d83cSJiri Slaby (SUSE) 	case SISUSB_GET_CONFIG:
2700a2f3d83cSJiri Slaby (SUSE) 
2701a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_id = SISUSB_ID;
2702a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_version = SISUSB_VERSION;
2703a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_revision = SISUSB_REVISION;
2704a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
2705a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_gfxinit = sisusb->gfxinit;
2706a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
2707a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
2708a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
2709a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
2710a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_vramsize = sisusb->vramsize;
2711a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_minor = sisusb->minor;
2712a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_fbdevactive = 0;
2713a2f3d83cSJiri Slaby (SUSE) 		x.sisusb_conactive  = 0;
2714a2f3d83cSJiri Slaby (SUSE) 		memset(x.sisusb_reserved, 0, sizeof(x.sisusb_reserved));
2715a2f3d83cSJiri Slaby (SUSE) 
2716a2f3d83cSJiri Slaby (SUSE) 		if (copy_to_user((void __user *)arg, &x, sizeof(x)))
2717a2f3d83cSJiri Slaby (SUSE) 			retval = -EFAULT;
2718a2f3d83cSJiri Slaby (SUSE) 
2719a2f3d83cSJiri Slaby (SUSE) 		break;
2720a2f3d83cSJiri Slaby (SUSE) 
2721a2f3d83cSJiri Slaby (SUSE) 	case SISUSB_COMMAND:
2722a2f3d83cSJiri Slaby (SUSE) 
2723a2f3d83cSJiri Slaby (SUSE) 		if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
2724a2f3d83cSJiri Slaby (SUSE) 			retval = -EFAULT;
2725a2f3d83cSJiri Slaby (SUSE) 		else
2726a2f3d83cSJiri Slaby (SUSE) 			retval = sisusb_handle_command(sisusb, &y, arg);
2727a2f3d83cSJiri Slaby (SUSE) 
2728a2f3d83cSJiri Slaby (SUSE) 		break;
2729a2f3d83cSJiri Slaby (SUSE) 
2730a2f3d83cSJiri Slaby (SUSE) 	default:
2731a2f3d83cSJiri Slaby (SUSE) 		retval = -ENOTTY;
2732a2f3d83cSJiri Slaby (SUSE) 		break;
2733a2f3d83cSJiri Slaby (SUSE) 	}
2734a2f3d83cSJiri Slaby (SUSE) 
2735a2f3d83cSJiri Slaby (SUSE) err_out:
2736a2f3d83cSJiri Slaby (SUSE) 	mutex_unlock(&sisusb->lock);
2737a2f3d83cSJiri Slaby (SUSE) 	return retval;
2738a2f3d83cSJiri Slaby (SUSE) }
2739a2f3d83cSJiri Slaby (SUSE) 
2740a2f3d83cSJiri Slaby (SUSE) #ifdef CONFIG_COMPAT
sisusb_compat_ioctl(struct file * f,unsigned int cmd,unsigned long arg)2741a2f3d83cSJiri Slaby (SUSE) static long sisusb_compat_ioctl(struct file *f, unsigned int cmd,
2742a2f3d83cSJiri Slaby (SUSE) 		unsigned long arg)
2743a2f3d83cSJiri Slaby (SUSE) {
2744a2f3d83cSJiri Slaby (SUSE) 	switch (cmd) {
2745a2f3d83cSJiri Slaby (SUSE) 	case SISUSB_GET_CONFIG_SIZE:
2746a2f3d83cSJiri Slaby (SUSE) 	case SISUSB_GET_CONFIG:
2747a2f3d83cSJiri Slaby (SUSE) 	case SISUSB_COMMAND:
2748a2f3d83cSJiri Slaby (SUSE) 		return sisusb_ioctl(f, cmd, arg);
2749a2f3d83cSJiri Slaby (SUSE) 
2750a2f3d83cSJiri Slaby (SUSE) 	default:
2751a2f3d83cSJiri Slaby (SUSE) 		return -ENOIOCTLCMD;
2752a2f3d83cSJiri Slaby (SUSE) 	}
2753a2f3d83cSJiri Slaby (SUSE) }
2754a2f3d83cSJiri Slaby (SUSE) #endif
2755a2f3d83cSJiri Slaby (SUSE) 
2756a2f3d83cSJiri Slaby (SUSE) static const struct file_operations usb_sisusb_fops = {
2757a2f3d83cSJiri Slaby (SUSE) 	.owner =	THIS_MODULE,
2758a2f3d83cSJiri Slaby (SUSE) 	.open =		sisusb_open,
2759a2f3d83cSJiri Slaby (SUSE) 	.release =	sisusb_release,
2760a2f3d83cSJiri Slaby (SUSE) 	.read =		sisusb_read,
2761a2f3d83cSJiri Slaby (SUSE) 	.write =	sisusb_write,
2762a2f3d83cSJiri Slaby (SUSE) 	.llseek =	sisusb_lseek,
2763a2f3d83cSJiri Slaby (SUSE) #ifdef CONFIG_COMPAT
2764a2f3d83cSJiri Slaby (SUSE) 	.compat_ioctl = sisusb_compat_ioctl,
2765a2f3d83cSJiri Slaby (SUSE) #endif
2766a2f3d83cSJiri Slaby (SUSE) 	.unlocked_ioctl = sisusb_ioctl
2767a2f3d83cSJiri Slaby (SUSE) };
2768a2f3d83cSJiri Slaby (SUSE) 
2769a2f3d83cSJiri Slaby (SUSE) static struct usb_class_driver usb_sisusb_class = {
2770a2f3d83cSJiri Slaby (SUSE) 	.name =		"sisusbvga%d",
2771a2f3d83cSJiri Slaby (SUSE) 	.fops =		&usb_sisusb_fops,
2772a2f3d83cSJiri Slaby (SUSE) 	.minor_base =	SISUSB_MINOR
2773a2f3d83cSJiri Slaby (SUSE) };
2774a2f3d83cSJiri Slaby (SUSE) 
sisusb_probe(struct usb_interface * intf,const struct usb_device_id * id)2775a2f3d83cSJiri Slaby (SUSE) static int sisusb_probe(struct usb_interface *intf,
2776a2f3d83cSJiri Slaby (SUSE) 		const struct usb_device_id *id)
2777a2f3d83cSJiri Slaby (SUSE) {
2778a2f3d83cSJiri Slaby (SUSE) 	struct usb_device *dev = interface_to_usbdev(intf);
2779a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_usb_data *sisusb;
2780a2f3d83cSJiri Slaby (SUSE) 	int retval = 0, i;
2781*df05a9b0SAlan Stern 	static const u8 ep_addresses[] = {
2782*df05a9b0SAlan Stern 		SISUSB_EP_GFX_IN | USB_DIR_IN,
2783*df05a9b0SAlan Stern 		SISUSB_EP_GFX_OUT | USB_DIR_OUT,
2784*df05a9b0SAlan Stern 		SISUSB_EP_GFX_BULK_OUT | USB_DIR_OUT,
2785*df05a9b0SAlan Stern 		SISUSB_EP_GFX_LBULK_OUT | USB_DIR_OUT,
2786*df05a9b0SAlan Stern 		SISUSB_EP_BRIDGE_IN | USB_DIR_IN,
2787*df05a9b0SAlan Stern 		SISUSB_EP_BRIDGE_OUT | USB_DIR_OUT,
2788*df05a9b0SAlan Stern 		0};
2789*df05a9b0SAlan Stern 
2790*df05a9b0SAlan Stern 	/* Are the expected endpoints present? */
2791*df05a9b0SAlan Stern 	if (!usb_check_bulk_endpoints(intf, ep_addresses)) {
2792*df05a9b0SAlan Stern 		dev_err(&intf->dev, "Invalid USB2VGA device\n");
2793*df05a9b0SAlan Stern 		return -EINVAL;
2794*df05a9b0SAlan Stern 	}
2795a2f3d83cSJiri Slaby (SUSE) 
2796a2f3d83cSJiri Slaby (SUSE) 	dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
2797a2f3d83cSJiri Slaby (SUSE) 			dev->devnum);
2798a2f3d83cSJiri Slaby (SUSE) 
2799a2f3d83cSJiri Slaby (SUSE) 	/* Allocate memory for our private */
2800a2f3d83cSJiri Slaby (SUSE) 	sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL);
2801a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb)
2802a2f3d83cSJiri Slaby (SUSE) 		return -ENOMEM;
2803a2f3d83cSJiri Slaby (SUSE) 
2804a2f3d83cSJiri Slaby (SUSE) 	kref_init(&sisusb->kref);
2805a2f3d83cSJiri Slaby (SUSE) 
2806a2f3d83cSJiri Slaby (SUSE) 	mutex_init(&(sisusb->lock));
2807a2f3d83cSJiri Slaby (SUSE) 
2808a2f3d83cSJiri Slaby (SUSE) 	sisusb->sisusb_dev = dev;
2809a2f3d83cSJiri Slaby (SUSE) 	sisusb->vrambase   = SISUSB_PCI_MEMBASE;
2810a2f3d83cSJiri Slaby (SUSE) 	sisusb->mmiobase   = SISUSB_PCI_MMIOBASE;
2811a2f3d83cSJiri Slaby (SUSE) 	sisusb->mmiosize   = SISUSB_PCI_MMIOSIZE;
2812a2f3d83cSJiri Slaby (SUSE) 	sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
2813a2f3d83cSJiri Slaby (SUSE) 	/* Everything else is zero */
2814a2f3d83cSJiri Slaby (SUSE) 
2815a2f3d83cSJiri Slaby (SUSE) 	/* Register device */
2816a2f3d83cSJiri Slaby (SUSE) 	retval = usb_register_dev(intf, &usb_sisusb_class);
2817a2f3d83cSJiri Slaby (SUSE) 	if (retval) {
2818a2f3d83cSJiri Slaby (SUSE) 		dev_err(&sisusb->sisusb_dev->dev,
2819a2f3d83cSJiri Slaby (SUSE) 				"Failed to get a minor for device %d\n",
2820a2f3d83cSJiri Slaby (SUSE) 				dev->devnum);
2821a2f3d83cSJiri Slaby (SUSE) 		retval = -ENODEV;
2822a2f3d83cSJiri Slaby (SUSE) 		goto error_1;
2823a2f3d83cSJiri Slaby (SUSE) 	}
2824a2f3d83cSJiri Slaby (SUSE) 
2825a2f3d83cSJiri Slaby (SUSE) 	sisusb->minor = intf->minor;
2826a2f3d83cSJiri Slaby (SUSE) 
2827a2f3d83cSJiri Slaby (SUSE) 	/* Allocate buffers */
2828a2f3d83cSJiri Slaby (SUSE) 	sisusb->ibufsize = SISUSB_IBUF_SIZE;
2829a2f3d83cSJiri Slaby (SUSE) 	sisusb->ibuf = kmalloc(SISUSB_IBUF_SIZE, GFP_KERNEL);
2830a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb->ibuf) {
2831a2f3d83cSJiri Slaby (SUSE) 		retval = -ENOMEM;
2832a2f3d83cSJiri Slaby (SUSE) 		goto error_2;
2833a2f3d83cSJiri Slaby (SUSE) 	}
2834a2f3d83cSJiri Slaby (SUSE) 
2835a2f3d83cSJiri Slaby (SUSE) 	sisusb->numobufs = 0;
2836a2f3d83cSJiri Slaby (SUSE) 	sisusb->obufsize = SISUSB_OBUF_SIZE;
2837a2f3d83cSJiri Slaby (SUSE) 	for (i = 0; i < NUMOBUFS; i++) {
2838a2f3d83cSJiri Slaby (SUSE) 		sisusb->obuf[i] = kmalloc(SISUSB_OBUF_SIZE, GFP_KERNEL);
2839a2f3d83cSJiri Slaby (SUSE) 		if (!sisusb->obuf[i]) {
2840a2f3d83cSJiri Slaby (SUSE) 			if (i == 0) {
2841a2f3d83cSJiri Slaby (SUSE) 				retval = -ENOMEM;
2842a2f3d83cSJiri Slaby (SUSE) 				goto error_3;
2843a2f3d83cSJiri Slaby (SUSE) 			}
2844a2f3d83cSJiri Slaby (SUSE) 			break;
2845a2f3d83cSJiri Slaby (SUSE) 		}
2846a2f3d83cSJiri Slaby (SUSE) 		sisusb->numobufs++;
2847a2f3d83cSJiri Slaby (SUSE) 	}
2848a2f3d83cSJiri Slaby (SUSE) 
2849a2f3d83cSJiri Slaby (SUSE) 	/* Allocate URBs */
2850a2f3d83cSJiri Slaby (SUSE) 	sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL);
2851a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb->sisurbin) {
2852a2f3d83cSJiri Slaby (SUSE) 		retval = -ENOMEM;
2853a2f3d83cSJiri Slaby (SUSE) 		goto error_3;
2854a2f3d83cSJiri Slaby (SUSE) 	}
2855a2f3d83cSJiri Slaby (SUSE) 	sisusb->completein = 1;
2856a2f3d83cSJiri Slaby (SUSE) 
2857a2f3d83cSJiri Slaby (SUSE) 	for (i = 0; i < sisusb->numobufs; i++) {
2858a2f3d83cSJiri Slaby (SUSE) 		sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL);
2859a2f3d83cSJiri Slaby (SUSE) 		if (!sisusb->sisurbout[i]) {
2860a2f3d83cSJiri Slaby (SUSE) 			retval = -ENOMEM;
2861a2f3d83cSJiri Slaby (SUSE) 			goto error_4;
2862a2f3d83cSJiri Slaby (SUSE) 		}
2863a2f3d83cSJiri Slaby (SUSE) 		sisusb->urbout_context[i].sisusb = (void *)sisusb;
2864a2f3d83cSJiri Slaby (SUSE) 		sisusb->urbout_context[i].urbindex = i;
2865a2f3d83cSJiri Slaby (SUSE) 		sisusb->urbstatus[i] = 0;
2866a2f3d83cSJiri Slaby (SUSE) 	}
2867a2f3d83cSJiri Slaby (SUSE) 
2868a2f3d83cSJiri Slaby (SUSE) 	dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n",
2869a2f3d83cSJiri Slaby (SUSE) 			sisusb->numobufs);
2870a2f3d83cSJiri Slaby (SUSE) 
2871a2f3d83cSJiri Slaby (SUSE) 	/* Do remaining init stuff */
2872a2f3d83cSJiri Slaby (SUSE) 
2873a2f3d83cSJiri Slaby (SUSE) 	init_waitqueue_head(&sisusb->wait_q);
2874a2f3d83cSJiri Slaby (SUSE) 
2875a2f3d83cSJiri Slaby (SUSE) 	usb_set_intfdata(intf, sisusb);
2876a2f3d83cSJiri Slaby (SUSE) 
2877a2f3d83cSJiri Slaby (SUSE) 	usb_get_dev(sisusb->sisusb_dev);
2878a2f3d83cSJiri Slaby (SUSE) 
2879a2f3d83cSJiri Slaby (SUSE) 	sisusb->present = 1;
2880a2f3d83cSJiri Slaby (SUSE) 
2881a2f3d83cSJiri Slaby (SUSE) 	if (dev->speed == USB_SPEED_HIGH || dev->speed >= USB_SPEED_SUPER) {
2882a2f3d83cSJiri Slaby (SUSE) 		int initscreen = 1;
2883a2f3d83cSJiri Slaby (SUSE) 		if (sisusb_init_gfxdevice(sisusb, initscreen))
2884a2f3d83cSJiri Slaby (SUSE) 			dev_err(&sisusb->sisusb_dev->dev,
2885a2f3d83cSJiri Slaby (SUSE) 					"Failed to early initialize device\n");
2886a2f3d83cSJiri Slaby (SUSE) 
2887a2f3d83cSJiri Slaby (SUSE) 	} else
2888a2f3d83cSJiri Slaby (SUSE) 		dev_info(&sisusb->sisusb_dev->dev,
2889a2f3d83cSJiri Slaby (SUSE) 				"Not attached to USB 2.0 hub, deferring init\n");
2890a2f3d83cSJiri Slaby (SUSE) 
2891a2f3d83cSJiri Slaby (SUSE) 	sisusb->ready = 1;
2892a2f3d83cSJiri Slaby (SUSE) 
2893a2f3d83cSJiri Slaby (SUSE) #ifdef SISUSBENDIANTEST
2894a2f3d83cSJiri Slaby (SUSE) 	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
2895a2f3d83cSJiri Slaby (SUSE) 	sisusb_testreadwrite(sisusb);
2896a2f3d83cSJiri Slaby (SUSE) 	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
2897a2f3d83cSJiri Slaby (SUSE) #endif
2898a2f3d83cSJiri Slaby (SUSE) 
2899a2f3d83cSJiri Slaby (SUSE) 	return 0;
2900a2f3d83cSJiri Slaby (SUSE) 
2901a2f3d83cSJiri Slaby (SUSE) error_4:
2902a2f3d83cSJiri Slaby (SUSE) 	sisusb_free_urbs(sisusb);
2903a2f3d83cSJiri Slaby (SUSE) error_3:
2904a2f3d83cSJiri Slaby (SUSE) 	sisusb_free_buffers(sisusb);
2905a2f3d83cSJiri Slaby (SUSE) error_2:
2906a2f3d83cSJiri Slaby (SUSE) 	usb_deregister_dev(intf, &usb_sisusb_class);
2907a2f3d83cSJiri Slaby (SUSE) error_1:
2908a2f3d83cSJiri Slaby (SUSE) 	kfree(sisusb);
2909a2f3d83cSJiri Slaby (SUSE) 	return retval;
2910a2f3d83cSJiri Slaby (SUSE) }
2911a2f3d83cSJiri Slaby (SUSE) 
sisusb_disconnect(struct usb_interface * intf)2912a2f3d83cSJiri Slaby (SUSE) static void sisusb_disconnect(struct usb_interface *intf)
2913a2f3d83cSJiri Slaby (SUSE) {
2914a2f3d83cSJiri Slaby (SUSE) 	struct sisusb_usb_data *sisusb;
2915a2f3d83cSJiri Slaby (SUSE) 
2916a2f3d83cSJiri Slaby (SUSE) 	/* This should *not* happen */
2917a2f3d83cSJiri Slaby (SUSE) 	sisusb = usb_get_intfdata(intf);
2918a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb)
2919a2f3d83cSJiri Slaby (SUSE) 		return;
2920a2f3d83cSJiri Slaby (SUSE) 
2921a2f3d83cSJiri Slaby (SUSE) 	usb_deregister_dev(intf, &usb_sisusb_class);
2922a2f3d83cSJiri Slaby (SUSE) 
2923a2f3d83cSJiri Slaby (SUSE) 	mutex_lock(&sisusb->lock);
2924a2f3d83cSJiri Slaby (SUSE) 
2925a2f3d83cSJiri Slaby (SUSE) 	/* Wait for all URBs to complete and kill them in case (MUST do) */
2926a2f3d83cSJiri Slaby (SUSE) 	if (!sisusb_wait_all_out_complete(sisusb))
2927a2f3d83cSJiri Slaby (SUSE) 		sisusb_kill_all_busy(sisusb);
2928a2f3d83cSJiri Slaby (SUSE) 
2929a2f3d83cSJiri Slaby (SUSE) 	usb_set_intfdata(intf, NULL);
2930a2f3d83cSJiri Slaby (SUSE) 
2931a2f3d83cSJiri Slaby (SUSE) 	sisusb->present = 0;
2932a2f3d83cSJiri Slaby (SUSE) 	sisusb->ready = 0;
2933a2f3d83cSJiri Slaby (SUSE) 
2934a2f3d83cSJiri Slaby (SUSE) 	mutex_unlock(&sisusb->lock);
2935a2f3d83cSJiri Slaby (SUSE) 
2936a2f3d83cSJiri Slaby (SUSE) 	/* decrement our usage count */
2937a2f3d83cSJiri Slaby (SUSE) 	kref_put(&sisusb->kref, sisusb_delete);
2938a2f3d83cSJiri Slaby (SUSE) }
2939a2f3d83cSJiri Slaby (SUSE) 
2940a2f3d83cSJiri Slaby (SUSE) static const struct usb_device_id sisusb_table[] = {
2941a2f3d83cSJiri Slaby (SUSE) 	{ USB_DEVICE(0x0711, 0x0550) },
2942a2f3d83cSJiri Slaby (SUSE) 	{ USB_DEVICE(0x0711, 0x0900) },
2943a2f3d83cSJiri Slaby (SUSE) 	{ USB_DEVICE(0x0711, 0x0901) },
2944a2f3d83cSJiri Slaby (SUSE) 	{ USB_DEVICE(0x0711, 0x0902) },
2945a2f3d83cSJiri Slaby (SUSE) 	{ USB_DEVICE(0x0711, 0x0903) },
2946a2f3d83cSJiri Slaby (SUSE) 	{ USB_DEVICE(0x0711, 0x0918) },
2947a2f3d83cSJiri Slaby (SUSE) 	{ USB_DEVICE(0x0711, 0x0920) },
2948a2f3d83cSJiri Slaby (SUSE) 	{ USB_DEVICE(0x0711, 0x0950) },
2949a2f3d83cSJiri Slaby (SUSE) 	{ USB_DEVICE(0x0711, 0x5200) },
2950a2f3d83cSJiri Slaby (SUSE) 	{ USB_DEVICE(0x182d, 0x021c) },
2951a2f3d83cSJiri Slaby (SUSE) 	{ USB_DEVICE(0x182d, 0x0269) },
2952a2f3d83cSJiri Slaby (SUSE) 	{ }
2953a2f3d83cSJiri Slaby (SUSE) };
2954a2f3d83cSJiri Slaby (SUSE) 
2955a2f3d83cSJiri Slaby (SUSE) MODULE_DEVICE_TABLE(usb, sisusb_table);
2956a2f3d83cSJiri Slaby (SUSE) 
2957a2f3d83cSJiri Slaby (SUSE) static struct usb_driver sisusb_driver = {
2958a2f3d83cSJiri Slaby (SUSE) 	.name =		"sisusb",
2959a2f3d83cSJiri Slaby (SUSE) 	.probe =	sisusb_probe,
2960a2f3d83cSJiri Slaby (SUSE) 	.disconnect =	sisusb_disconnect,
2961a2f3d83cSJiri Slaby (SUSE) 	.id_table =	sisusb_table,
2962a2f3d83cSJiri Slaby (SUSE) };
2963a2f3d83cSJiri Slaby (SUSE) 
29644b6be020SJiri Slaby (SUSE) module_usb_driver(sisusb_driver);
2965a2f3d83cSJiri Slaby (SUSE) 
2966a2f3d83cSJiri Slaby (SUSE) MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
2967a2f3d83cSJiri Slaby (SUSE) MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
2968a2f3d83cSJiri Slaby (SUSE) MODULE_LICENSE("GPL");
2969a2f3d83cSJiri Slaby (SUSE) 
2970