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