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