[PATCH] USB: sisusb[vga] update
[linux-2.6/btrfs-unstable.git] / drivers / usb / misc / sisusbvga / sisusb.c
blob39db3155723a567ee21e777d455904305c1f1497
1 /*
2 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
4 * Main part
6 * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
8 * If distributed as part of the Linux kernel, this code is licensed under the
9 * terms of the GPL v2.
11 * Otherwise, the following license terms apply:
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.
35 * Author: Thomas Winischhofer <thomas@winischhofer.net>
39 #include <linux/config.h>
40 #include <linux/version.h>
41 #include <linux/module.h>
42 #include <linux/kernel.h>
43 #include <linux/signal.h>
44 #include <linux/sched.h>
45 #include <linux/errno.h>
46 #include <linux/poll.h>
47 #include <linux/init.h>
48 #include <linux/slab.h>
49 #include <linux/spinlock.h>
50 #include <linux/kref.h>
51 #include <linux/usb.h>
52 #include <linux/smp_lock.h>
53 #include <linux/vmalloc.h>
55 #include "sisusb.h"
57 #ifdef INCL_SISUSB_CON
58 #include <linux/font.h>
59 #endif
61 #define SISUSB_DONTSYNC
63 /* Forward declarations / clean-up routines */
65 #ifdef INCL_SISUSB_CON
66 int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
67 int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
68 int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data);
69 int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data);
70 int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand, u8 myor);
71 int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor);
72 int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand);
74 int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
75 int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
76 int sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data);
77 int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data);
78 int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
79 u32 dest, int length, size_t *bytes_written);
81 int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
83 extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
84 extern int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
86 extern void sisusb_init_concode(void);
87 extern int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
88 extern void sisusb_console_exit(struct sisusb_usb_data *sisusb);
90 extern void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
92 extern int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
93 u8 *arg, int cmapsz, int ch512, int dorecalc,
94 struct vc_data *c, int fh, int uplock);
96 static int sisusb_first_vc = 0;
97 static int sisusb_last_vc = 0;
98 module_param_named(first, sisusb_first_vc, int, 0);
99 module_param_named(last, sisusb_last_vc, int, 0);
100 MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)");
101 MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)");
102 #endif
104 static struct usb_driver sisusb_driver;
106 DECLARE_MUTEX(disconnect_sem);
108 static void
109 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
111 int i;
113 for (i = 0; i < NUMOBUFS; i++) {
114 if (sisusb->obuf[i]) {
115 usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize,
116 sisusb->obuf[i], sisusb->transfer_dma_out[i]);
117 sisusb->obuf[i] = NULL;
120 if (sisusb->ibuf) {
121 usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
122 sisusb->ibuf, sisusb->transfer_dma_in);
123 sisusb->ibuf = NULL;
127 static void
128 sisusb_free_urbs(struct sisusb_usb_data *sisusb)
130 int i;
132 for (i = 0; i < NUMOBUFS; i++) {
133 usb_free_urb(sisusb->sisurbout[i]);
134 sisusb->sisurbout[i] = NULL;
136 usb_free_urb(sisusb->sisurbin);
137 sisusb->sisurbin = NULL;
140 /* Level 0: USB transport layer */
142 /* 1. out-bulks */
144 /* out-urb management */
146 /* Return 1 if all free, 0 otherwise */
147 static int
148 sisusb_all_free(struct sisusb_usb_data *sisusb)
150 int i;
152 for (i = 0; i < sisusb->numobufs; i++) {
154 if (sisusb->urbstatus[i] & SU_URB_BUSY)
155 return 0;
159 return 1;
162 /* Kill all busy URBs */
163 static void
164 sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
166 int i;
168 if (sisusb_all_free(sisusb))
169 return;
171 for (i = 0; i < sisusb->numobufs; i++) {
173 if (sisusb->urbstatus[i] & SU_URB_BUSY)
174 usb_kill_urb(sisusb->sisurbout[i]);
179 /* Return 1 if ok, 0 if error (not all complete within timeout) */
180 static int
181 sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
183 int timeout = 5 * HZ, i = 1;
185 wait_event_timeout(sisusb->wait_q,
186 (i = sisusb_all_free(sisusb)),
187 timeout);
189 return i;
192 static int
193 sisusb_outurb_available(struct sisusb_usb_data *sisusb)
195 int i;
197 for (i = 0; i < sisusb->numobufs; i++) {
199 if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
200 return i;
204 return -1;
207 static int
208 sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
210 int i, timeout = 5 * HZ;
212 wait_event_timeout(sisusb->wait_q,
213 ((i = sisusb_outurb_available(sisusb)) >= 0),
214 timeout);
216 return i;
219 static int
220 sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
222 int i;
224 i = sisusb_outurb_available(sisusb);
226 if (i >= 0)
227 sisusb->urbstatus[i] |= SU_URB_ALLOC;
229 return i;
232 static void
233 sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
235 if ((index >= 0) && (index < sisusb->numobufs))
236 sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
239 /* completion callback */
241 static void
242 sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
244 struct sisusb_urb_context *context = urb->context;
245 struct sisusb_usb_data *sisusb;
247 if (!context)
248 return;
250 sisusb = context->sisusb;
252 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
253 return;
255 #ifndef SISUSB_DONTSYNC
256 if (context->actual_length)
257 *(context->actual_length) += urb->actual_length;
258 #endif
260 sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
261 wake_up(&sisusb->wait_q);
264 static int
265 sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
266 int len, int *actual_length, int timeout, unsigned int tflags,
267 dma_addr_t transfer_dma)
269 struct urb *urb = sisusb->sisurbout[index];
270 int retval, byteswritten = 0;
272 /* Set up URB */
273 urb->transfer_flags = 0;
275 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
276 sisusb_bulk_completeout, &sisusb->urbout_context[index]);
278 urb->transfer_flags |= tflags;
279 urb->actual_length = 0;
281 if ((urb->transfer_dma = transfer_dma))
282 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
284 /* Set up context */
285 sisusb->urbout_context[index].actual_length = (timeout) ?
286 NULL : actual_length;
288 /* Declare this urb/buffer in use */
289 sisusb->urbstatus[index] |= SU_URB_BUSY;
291 /* Submit URB */
292 retval = usb_submit_urb(urb, GFP_ATOMIC);
294 /* If OK, and if timeout > 0, wait for completion */
295 if ((retval == 0) && timeout) {
296 wait_event_timeout(sisusb->wait_q,
297 (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
298 timeout);
299 if (sisusb->urbstatus[index] & SU_URB_BUSY) {
300 /* URB timed out... kill it and report error */
301 usb_kill_urb(urb);
302 retval = -ETIMEDOUT;
303 } else {
304 /* Otherwise, report urb status */
305 retval = urb->status;
306 byteswritten = urb->actual_length;
310 if (actual_length)
311 *actual_length = byteswritten;
313 return retval;
316 /* 2. in-bulks */
318 /* completion callback */
320 static void
321 sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
323 struct sisusb_usb_data *sisusb = urb->context;
325 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
326 return;
328 sisusb->completein = 1;
329 wake_up(&sisusb->wait_q);
332 static int
333 sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len,
334 int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma)
336 struct urb *urb = sisusb->sisurbin;
337 int retval, readbytes = 0;
339 urb->transfer_flags = 0;
341 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
342 sisusb_bulk_completein, sisusb);
344 urb->transfer_flags |= tflags;
345 urb->actual_length = 0;
347 if ((urb->transfer_dma = transfer_dma))
348 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
350 sisusb->completein = 0;
351 retval = usb_submit_urb(urb, GFP_ATOMIC);
352 if (retval == 0) {
353 wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
354 if (!sisusb->completein) {
355 /* URB timed out... kill it and report error */
356 usb_kill_urb(urb);
357 retval = -ETIMEDOUT;
358 } else {
359 /* URB completed within timout */
360 retval = urb->status;
361 readbytes = urb->actual_length;
365 if (actual_length)
366 *actual_length = readbytes;
368 return retval;
372 /* Level 1: */
374 /* Send a bulk message of variable size
376 * To copy the data from userspace, give pointer to "userbuffer",
377 * to copy from (non-DMA) kernel memory, give "kernbuffer". If
378 * both of these are NULL, it is assumed, that the transfer
379 * buffer "sisusb->obuf[index]" is set up with the data to send.
380 * Index is ignored if either kernbuffer or userbuffer is set.
381 * If async is nonzero, URBs will be sent without waiting for
382 * completion of the previous URB.
384 * (return 0 on success)
387 static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
388 char *kernbuffer, const char __user *userbuffer, int index,
389 ssize_t *bytes_written, unsigned int tflags, int async)
391 int result = 0, retry, count = len;
392 int passsize, thispass, transferred_len = 0;
393 int fromuser = (userbuffer != NULL) ? 1 : 0;
394 int fromkern = (kernbuffer != NULL) ? 1 : 0;
395 unsigned int pipe;
396 char *buffer;
398 (*bytes_written) = 0;
400 /* Sanity check */
401 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
402 return -ENODEV;
404 /* If we copy data from kernel or userspace, force the
405 * allocation of a buffer/urb. If we have the data in
406 * the transfer buffer[index] already, reuse the buffer/URB
407 * if the length is > buffer size. (So, transmitting
408 * large data amounts directly from the transfer buffer
409 * treats the buffer as a ring buffer. However, we need
410 * to sync in this case.)
412 if (fromuser || fromkern)
413 index = -1;
414 else if (len > sisusb->obufsize)
415 async = 0;
417 pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
419 do {
420 passsize = thispass = (sisusb->obufsize < count) ?
421 sisusb->obufsize : count;
423 if (index < 0)
424 index = sisusb_get_free_outbuf(sisusb);
426 if (index < 0)
427 return -EIO;
429 buffer = sisusb->obuf[index];
431 if (fromuser) {
433 if (copy_from_user(buffer, userbuffer, passsize))
434 return -EFAULT;
436 userbuffer += passsize;
438 } else if (fromkern) {
440 memcpy(buffer, kernbuffer, passsize);
441 kernbuffer += passsize;
445 retry = 5;
446 while (thispass) {
448 if (!sisusb->sisusb_dev)
449 return -ENODEV;
451 result = sisusb_bulkout_msg(sisusb,
452 index,
453 pipe,
454 buffer,
455 thispass,
456 &transferred_len,
457 async ? 0 : 5 * HZ,
458 tflags,
459 sisusb->transfer_dma_out[index]);
461 if (result == -ETIMEDOUT) {
463 /* Will not happen if async */
464 if (!retry--)
465 return -ETIME;
467 continue;
469 } else if ((result == 0) && !async && transferred_len) {
471 thispass -= transferred_len;
472 if (thispass) {
473 if (sisusb->transfer_dma_out) {
474 /* If DMA, copy remaining
475 * to beginning of buffer
477 memcpy(buffer,
478 buffer + transferred_len,
479 thispass);
480 } else {
481 /* If not DMA, simply increase
482 * the pointer
484 buffer += transferred_len;
488 } else
489 break;
492 if (result)
493 return result;
495 (*bytes_written) += passsize;
496 count -= passsize;
498 /* Force new allocation in next iteration */
499 if (fromuser || fromkern)
500 index = -1;
502 } while (count > 0);
504 if (async) {
505 #ifdef SISUSB_DONTSYNC
506 (*bytes_written) = len;
507 /* Some URBs/buffers might be busy */
508 #else
509 sisusb_wait_all_out_complete(sisusb);
510 (*bytes_written) = transferred_len;
511 /* All URBs and all buffers are available */
512 #endif
515 return ((*bytes_written) == len) ? 0 : -EIO;
518 /* Receive a bulk message of variable size
520 * To copy the data to userspace, give pointer to "userbuffer",
521 * to copy to kernel memory, give "kernbuffer". One of them
522 * MUST be set. (There is no technique for letting the caller
523 * read directly from the ibuf.)
527 static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
528 void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
529 unsigned int tflags)
531 int result = 0, retry, count = len;
532 int bufsize, thispass, transferred_len;
533 unsigned int pipe;
534 char *buffer;
536 (*bytes_read) = 0;
538 /* Sanity check */
539 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
540 return -ENODEV;
542 pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
543 buffer = sisusb->ibuf;
544 bufsize = sisusb->ibufsize;
546 retry = 5;
548 #ifdef SISUSB_DONTSYNC
549 if (!(sisusb_wait_all_out_complete(sisusb)))
550 return -EIO;
551 #endif
553 while (count > 0) {
555 if (!sisusb->sisusb_dev)
556 return -ENODEV;
558 thispass = (bufsize < count) ? bufsize : count;
560 result = sisusb_bulkin_msg(sisusb,
561 pipe,
562 buffer,
563 thispass,
564 &transferred_len,
565 5 * HZ,
566 tflags,
567 sisusb->transfer_dma_in);
569 if (transferred_len)
570 thispass = transferred_len;
572 else if (result == -ETIMEDOUT) {
574 if (!retry--)
575 return -ETIME;
577 continue;
579 } else
580 return -EIO;
583 if (thispass) {
585 (*bytes_read) += thispass;
586 count -= thispass;
588 if (userbuffer) {
590 if (copy_to_user(userbuffer, buffer, thispass))
591 return -EFAULT;
593 userbuffer += thispass;
595 } else {
597 memcpy(kernbuffer, buffer, thispass);
598 kernbuffer += thispass;
606 return ((*bytes_read) == len) ? 0 : -EIO;
609 static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
610 struct sisusb_packet *packet)
612 int ret;
613 ssize_t bytes_transferred = 0;
614 __le32 tmp;
616 if (len == 6)
617 packet->data = 0;
619 #ifdef SISUSB_DONTSYNC
620 if (!(sisusb_wait_all_out_complete(sisusb)))
621 return 1;
622 #endif
624 /* Eventually correct endianness */
625 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
627 /* 1. send the packet */
628 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
629 (char *)packet, NULL, 0, &bytes_transferred, 0, 0);
631 if ((ret == 0) && (len == 6)) {
633 /* 2. if packet len == 6, it means we read, so wait for 32bit
634 * return value and write it to packet->data
636 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
637 (char *)&tmp, NULL, &bytes_transferred, 0);
639 packet->data = le32_to_cpu(tmp);
642 return ret;
645 static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
646 struct sisusb_packet *packet,
647 unsigned int tflags)
649 int ret;
650 ssize_t bytes_transferred = 0;
651 __le32 tmp;
653 if (len == 6)
654 packet->data = 0;
656 #ifdef SISUSB_DONTSYNC
657 if (!(sisusb_wait_all_out_complete(sisusb)))
658 return 1;
659 #endif
661 /* Eventually correct endianness */
662 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
664 /* 1. send the packet */
665 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
666 (char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
668 if ((ret == 0) && (len == 6)) {
670 /* 2. if packet len == 6, it means we read, so wait for 32bit
671 * return value and write it to packet->data
673 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
674 (char *)&tmp, NULL, &bytes_transferred, 0);
676 packet->data = le32_to_cpu(tmp);
679 return ret;
682 /* access video memory and mmio (return 0 on success) */
684 /* Low level */
686 /* The following routines assume being used to transfer byte, word,
687 * long etc.
688 * This means that
689 * - the write routines expect "data" in machine endianness format.
690 * The data will be converted to leXX in sisusb_xxx_packet.
691 * - the read routines can expect read data in machine-endianess.
694 static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
695 u32 addr, u8 data)
697 struct sisusb_packet packet;
698 int ret;
700 packet.header = (1 << (addr & 3)) | (type << 6);
701 packet.address = addr & ~3;
702 packet.data = data << ((addr & 3) << 3);
703 ret = sisusb_send_packet(sisusb, 10, &packet);
704 return ret;
707 static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
708 u32 addr, u16 data)
710 struct sisusb_packet packet;
711 int ret = 0;
713 packet.address = addr & ~3;
715 switch (addr & 3) {
716 case 0:
717 packet.header = (type << 6) | 0x0003;
718 packet.data = (u32)data;
719 ret = sisusb_send_packet(sisusb, 10, &packet);
720 break;
721 case 1:
722 packet.header = (type << 6) | 0x0006;
723 packet.data = (u32)data << 8;
724 ret = sisusb_send_packet(sisusb, 10, &packet);
725 break;
726 case 2:
727 packet.header = (type << 6) | 0x000c;
728 packet.data = (u32)data << 16;
729 ret = sisusb_send_packet(sisusb, 10, &packet);
730 break;
731 case 3:
732 packet.header = (type << 6) | 0x0008;
733 packet.data = (u32)data << 24;
734 ret = sisusb_send_packet(sisusb, 10, &packet);
735 packet.header = (type << 6) | 0x0001;
736 packet.address = (addr & ~3) + 4;
737 packet.data = (u32)data >> 8;
738 ret |= sisusb_send_packet(sisusb, 10, &packet);
741 return ret;
744 static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
745 u32 addr, u32 data)
747 struct sisusb_packet packet;
748 int ret = 0;
750 packet.address = addr & ~3;
752 switch (addr & 3) {
753 case 0:
754 packet.header = (type << 6) | 0x0007;
755 packet.data = data & 0x00ffffff;
756 ret = sisusb_send_packet(sisusb, 10, &packet);
757 break;
758 case 1:
759 packet.header = (type << 6) | 0x000e;
760 packet.data = data << 8;
761 ret = sisusb_send_packet(sisusb, 10, &packet);
762 break;
763 case 2:
764 packet.header = (type << 6) | 0x000c;
765 packet.data = data << 16;
766 ret = sisusb_send_packet(sisusb, 10, &packet);
767 packet.header = (type << 6) | 0x0001;
768 packet.address = (addr & ~3) + 4;
769 packet.data = (data >> 16) & 0x00ff;
770 ret |= sisusb_send_packet(sisusb, 10, &packet);
771 break;
772 case 3:
773 packet.header = (type << 6) | 0x0008;
774 packet.data = data << 24;
775 ret = sisusb_send_packet(sisusb, 10, &packet);
776 packet.header = (type << 6) | 0x0003;
777 packet.address = (addr & ~3) + 4;
778 packet.data = (data >> 8) & 0xffff;
779 ret |= sisusb_send_packet(sisusb, 10, &packet);
782 return ret;
785 static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
786 u32 addr, u32 data)
788 struct sisusb_packet packet;
789 int ret = 0;
791 packet.address = addr & ~3;
793 switch (addr & 3) {
794 case 0:
795 packet.header = (type << 6) | 0x000f;
796 packet.data = data;
797 ret = sisusb_send_packet(sisusb, 10, &packet);
798 break;
799 case 1:
800 packet.header = (type << 6) | 0x000e;
801 packet.data = data << 8;
802 ret = sisusb_send_packet(sisusb, 10, &packet);
803 packet.header = (type << 6) | 0x0001;
804 packet.address = (addr & ~3) + 4;
805 packet.data = data >> 24;
806 ret |= sisusb_send_packet(sisusb, 10, &packet);
807 break;
808 case 2:
809 packet.header = (type << 6) | 0x000c;
810 packet.data = data << 16;
811 ret = sisusb_send_packet(sisusb, 10, &packet);
812 packet.header = (type << 6) | 0x0003;
813 packet.address = (addr & ~3) + 4;
814 packet.data = data >> 16;
815 ret |= sisusb_send_packet(sisusb, 10, &packet);
816 break;
817 case 3:
818 packet.header = (type << 6) | 0x0008;
819 packet.data = data << 24;
820 ret = sisusb_send_packet(sisusb, 10, &packet);
821 packet.header = (type << 6) | 0x0007;
822 packet.address = (addr & ~3) + 4;
823 packet.data = data >> 8;
824 ret |= sisusb_send_packet(sisusb, 10, &packet);
827 return ret;
830 /* The xxx_bulk routines copy a buffer of variable size. They treat the
831 * buffer as chars, therefore lsb/msb has to be corrected if using the
832 * byte/word/long/etc routines for speed-up
834 * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
835 * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
836 * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
837 * that the data already is in the transfer buffer "sisusb->obuf[index]".
840 static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
841 char *kernbuffer, int length,
842 const char __user *userbuffer, int index,
843 ssize_t *bytes_written)
845 struct sisusb_packet packet;
846 int ret = 0;
847 static int msgcount = 0;
848 u8 swap8, fromkern = kernbuffer ? 1 : 0;
849 u16 swap16;
850 u32 swap32, flag = (length >> 28) & 1;
851 char buf[4];
853 /* if neither kernbuffer not userbuffer are given, assume
854 * data in obuf
856 if (!fromkern && !userbuffer)
857 kernbuffer = sisusb->obuf[index];
859 (*bytes_written = 0);
861 length &= 0x00ffffff;
863 while (length) {
865 switch (length) {
867 case 0:
868 return ret;
870 case 1:
871 if (userbuffer) {
872 if (get_user(swap8, (u8 __user *)userbuffer))
873 return -EFAULT;
874 } else
875 swap8 = kernbuffer[0];
877 ret = sisusb_write_memio_byte(sisusb,
878 SISUSB_TYPE_MEM,
879 addr, swap8);
881 if (!ret)
882 (*bytes_written)++;
884 return ret;
886 case 2:
887 if (userbuffer) {
888 if (get_user(swap16, (u16 __user *)userbuffer))
889 return -EFAULT;
890 } else
891 swap16 = *((u16 *)kernbuffer);
893 ret = sisusb_write_memio_word(sisusb,
894 SISUSB_TYPE_MEM,
895 addr,
896 swap16);
898 if (!ret)
899 (*bytes_written) += 2;
901 return ret;
903 case 3:
904 if (userbuffer) {
905 if (copy_from_user(&buf, userbuffer, 3))
906 return -EFAULT;
907 #ifdef __BIG_ENDIAN
908 swap32 = (buf[0] << 16) |
909 (buf[1] << 8) |
910 buf[2];
911 #else
912 swap32 = (buf[2] << 16) |
913 (buf[1] << 8) |
914 buf[0];
915 #endif
916 } else
917 #ifdef __BIG_ENDIAN
918 swap32 = (kernbuffer[0] << 16) |
919 (kernbuffer[1] << 8) |
920 kernbuffer[2];
921 #else
922 swap32 = (kernbuffer[2] << 16) |
923 (kernbuffer[1] << 8) |
924 kernbuffer[0];
925 #endif
927 ret = sisusb_write_memio_24bit(sisusb,
928 SISUSB_TYPE_MEM,
929 addr,
930 swap32);
932 if (!ret)
933 (*bytes_written) += 3;
935 return ret;
937 case 4:
938 if (userbuffer) {
939 if (get_user(swap32, (u32 __user *)userbuffer))
940 return -EFAULT;
941 } else
942 swap32 = *((u32 *)kernbuffer);
944 ret = sisusb_write_memio_long(sisusb,
945 SISUSB_TYPE_MEM,
946 addr,
947 swap32);
948 if (!ret)
949 (*bytes_written) += 4;
951 return ret;
953 default:
954 if ((length & ~3) > 0x10000) {
956 packet.header = 0x001f;
957 packet.address = 0x000001d4;
958 packet.data = addr;
959 ret = sisusb_send_bridge_packet(sisusb, 10,
960 &packet, 0);
961 packet.header = 0x001f;
962 packet.address = 0x000001d0;
963 packet.data = (length & ~3);
964 ret |= sisusb_send_bridge_packet(sisusb, 10,
965 &packet, 0);
966 packet.header = 0x001f;
967 packet.address = 0x000001c0;
968 packet.data = flag | 0x16;
969 ret |= sisusb_send_bridge_packet(sisusb, 10,
970 &packet, 0);
971 if (userbuffer) {
972 ret |= sisusb_send_bulk_msg(sisusb,
973 SISUSB_EP_GFX_LBULK_OUT,
974 (length & ~3),
975 NULL, userbuffer, 0,
976 bytes_written, 0, 1);
977 userbuffer += (*bytes_written);
978 } else if (fromkern) {
979 ret |= sisusb_send_bulk_msg(sisusb,
980 SISUSB_EP_GFX_LBULK_OUT,
981 (length & ~3),
982 kernbuffer, NULL, 0,
983 bytes_written, 0, 1);
984 kernbuffer += (*bytes_written);
985 } else {
986 ret |= sisusb_send_bulk_msg(sisusb,
987 SISUSB_EP_GFX_LBULK_OUT,
988 (length & ~3),
989 NULL, NULL, index,
990 bytes_written, 0, 1);
991 kernbuffer += ((*bytes_written) &
992 (sisusb->obufsize-1));
995 } else {
997 packet.header = 0x001f;
998 packet.address = 0x00000194;
999 packet.data = addr;
1000 ret = sisusb_send_bridge_packet(sisusb, 10,
1001 &packet, 0);
1002 packet.header = 0x001f;
1003 packet.address = 0x00000190;
1004 packet.data = (length & ~3);
1005 ret |= sisusb_send_bridge_packet(sisusb, 10,
1006 &packet, 0);
1007 if (sisusb->flagb0 != 0x16) {
1008 packet.header = 0x001f;
1009 packet.address = 0x00000180;
1010 packet.data = flag | 0x16;
1011 ret |= sisusb_send_bridge_packet(sisusb, 10,
1012 &packet, 0);
1013 sisusb->flagb0 = 0x16;
1015 if (userbuffer) {
1016 ret |= sisusb_send_bulk_msg(sisusb,
1017 SISUSB_EP_GFX_BULK_OUT,
1018 (length & ~3),
1019 NULL, userbuffer, 0,
1020 bytes_written, 0, 1);
1021 userbuffer += (*bytes_written);
1022 } else if (fromkern) {
1023 ret |= sisusb_send_bulk_msg(sisusb,
1024 SISUSB_EP_GFX_BULK_OUT,
1025 (length & ~3),
1026 kernbuffer, NULL, 0,
1027 bytes_written, 0, 1);
1028 kernbuffer += (*bytes_written);
1029 } else {
1030 ret |= sisusb_send_bulk_msg(sisusb,
1031 SISUSB_EP_GFX_BULK_OUT,
1032 (length & ~3),
1033 NULL, NULL, index,
1034 bytes_written, 0, 1);
1035 kernbuffer += ((*bytes_written) &
1036 (sisusb->obufsize-1));
1039 if (ret) {
1040 msgcount++;
1041 if (msgcount < 500)
1042 printk(KERN_ERR
1043 "sisusbvga[%d]: Wrote %zd of "
1044 "%d bytes, error %d\n",
1045 sisusb->minor, *bytes_written,
1046 length, ret);
1047 else if (msgcount == 500)
1048 printk(KERN_ERR
1049 "sisusbvga[%d]: Too many errors"
1050 ", logging stopped\n",
1051 sisusb->minor);
1053 addr += (*bytes_written);
1054 length -= (*bytes_written);
1057 if (ret)
1058 break;
1062 return ret ? -EIO : 0;
1065 /* Remember: Read data in packet is in machine-endianess! So for
1066 * byte, word, 24bit, long no endian correction is necessary.
1069 static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1070 u32 addr, u8 *data)
1072 struct sisusb_packet packet;
1073 int ret;
1075 CLEARPACKET(&packet);
1076 packet.header = (1 << (addr & 3)) | (type << 6);
1077 packet.address = addr & ~3;
1078 ret = sisusb_send_packet(sisusb, 6, &packet);
1079 *data = (u8)(packet.data >> ((addr & 3) << 3));
1080 return ret;
1083 static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1084 u32 addr, u16 *data)
1086 struct sisusb_packet packet;
1087 int ret = 0;
1089 CLEARPACKET(&packet);
1091 packet.address = addr & ~3;
1093 switch (addr & 3) {
1094 case 0:
1095 packet.header = (type << 6) | 0x0003;
1096 ret = sisusb_send_packet(sisusb, 6, &packet);
1097 *data = (u16)(packet.data);
1098 break;
1099 case 1:
1100 packet.header = (type << 6) | 0x0006;
1101 ret = sisusb_send_packet(sisusb, 6, &packet);
1102 *data = (u16)(packet.data >> 8);
1103 break;
1104 case 2:
1105 packet.header = (type << 6) | 0x000c;
1106 ret = sisusb_send_packet(sisusb, 6, &packet);
1107 *data = (u16)(packet.data >> 16);
1108 break;
1109 case 3:
1110 packet.header = (type << 6) | 0x0008;
1111 ret = sisusb_send_packet(sisusb, 6, &packet);
1112 *data = (u16)(packet.data >> 24);
1113 packet.header = (type << 6) | 0x0001;
1114 packet.address = (addr & ~3) + 4;
1115 ret |= sisusb_send_packet(sisusb, 6, &packet);
1116 *data |= (u16)(packet.data << 8);
1119 return ret;
1122 static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1123 u32 addr, u32 *data)
1125 struct sisusb_packet packet;
1126 int ret = 0;
1128 packet.address = addr & ~3;
1130 switch (addr & 3) {
1131 case 0:
1132 packet.header = (type << 6) | 0x0007;
1133 ret = sisusb_send_packet(sisusb, 6, &packet);
1134 *data = packet.data & 0x00ffffff;
1135 break;
1136 case 1:
1137 packet.header = (type << 6) | 0x000e;
1138 ret = sisusb_send_packet(sisusb, 6, &packet);
1139 *data = packet.data >> 8;
1140 break;
1141 case 2:
1142 packet.header = (type << 6) | 0x000c;
1143 ret = sisusb_send_packet(sisusb, 6, &packet);
1144 *data = packet.data >> 16;
1145 packet.header = (type << 6) | 0x0001;
1146 packet.address = (addr & ~3) + 4;
1147 ret |= sisusb_send_packet(sisusb, 6, &packet);
1148 *data |= ((packet.data & 0xff) << 16);
1149 break;
1150 case 3:
1151 packet.header = (type << 6) | 0x0008;
1152 ret = sisusb_send_packet(sisusb, 6, &packet);
1153 *data = packet.data >> 24;
1154 packet.header = (type << 6) | 0x0003;
1155 packet.address = (addr & ~3) + 4;
1156 ret |= sisusb_send_packet(sisusb, 6, &packet);
1157 *data |= ((packet.data & 0xffff) << 8);
1160 return ret;
1163 static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1164 u32 addr, u32 *data)
1166 struct sisusb_packet packet;
1167 int ret = 0;
1169 packet.address = addr & ~3;
1171 switch (addr & 3) {
1172 case 0:
1173 packet.header = (type << 6) | 0x000f;
1174 ret = sisusb_send_packet(sisusb, 6, &packet);
1175 *data = packet.data;
1176 break;
1177 case 1:
1178 packet.header = (type << 6) | 0x000e;
1179 ret = sisusb_send_packet(sisusb, 6, &packet);
1180 *data = packet.data >> 8;
1181 packet.header = (type << 6) | 0x0001;
1182 packet.address = (addr & ~3) + 4;
1183 ret |= sisusb_send_packet(sisusb, 6, &packet);
1184 *data |= (packet.data << 24);
1185 break;
1186 case 2:
1187 packet.header = (type << 6) | 0x000c;
1188 ret = sisusb_send_packet(sisusb, 6, &packet);
1189 *data = packet.data >> 16;
1190 packet.header = (type << 6) | 0x0003;
1191 packet.address = (addr & ~3) + 4;
1192 ret |= sisusb_send_packet(sisusb, 6, &packet);
1193 *data |= (packet.data << 16);
1194 break;
1195 case 3:
1196 packet.header = (type << 6) | 0x0008;
1197 ret = sisusb_send_packet(sisusb, 6, &packet);
1198 *data = packet.data >> 24;
1199 packet.header = (type << 6) | 0x0007;
1200 packet.address = (addr & ~3) + 4;
1201 ret |= sisusb_send_packet(sisusb, 6, &packet);
1202 *data |= (packet.data << 8);
1205 return ret;
1208 static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1209 char *kernbuffer, int length,
1210 char __user *userbuffer, ssize_t *bytes_read)
1212 int ret = 0;
1213 char buf[4];
1214 u16 swap16;
1215 u32 swap32;
1217 (*bytes_read = 0);
1219 length &= 0x00ffffff;
1221 while (length) {
1223 switch (length) {
1225 case 0:
1226 return ret;
1228 case 1:
1230 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1231 addr, &buf[0]);
1232 if (!ret) {
1233 (*bytes_read)++;
1234 if (userbuffer) {
1235 if (put_user(buf[0],
1236 (u8 __user *)userbuffer)) {
1237 return -EFAULT;
1239 } else {
1240 kernbuffer[0] = buf[0];
1243 return ret;
1245 case 2:
1246 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1247 addr, &swap16);
1248 if (!ret) {
1249 (*bytes_read) += 2;
1250 if (userbuffer) {
1251 if (put_user(swap16,
1252 (u16 __user *)userbuffer))
1253 return -EFAULT;
1254 } else {
1255 *((u16 *)kernbuffer) = swap16;
1258 return ret;
1260 case 3:
1261 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1262 addr, &swap32);
1263 if (!ret) {
1264 (*bytes_read) += 3;
1265 #ifdef __BIG_ENDIAN
1266 buf[0] = (swap32 >> 16) & 0xff;
1267 buf[1] = (swap32 >> 8) & 0xff;
1268 buf[2] = swap32 & 0xff;
1269 #else
1270 buf[2] = (swap32 >> 16) & 0xff;
1271 buf[1] = (swap32 >> 8) & 0xff;
1272 buf[0] = swap32 & 0xff;
1273 #endif
1274 if (userbuffer) {
1275 if (copy_to_user(userbuffer, &buf[0], 3))
1276 return -EFAULT;
1277 } else {
1278 kernbuffer[0] = buf[0];
1279 kernbuffer[1] = buf[1];
1280 kernbuffer[2] = buf[2];
1283 return ret;
1285 default:
1286 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1287 addr, &swap32);
1288 if (!ret) {
1289 (*bytes_read) += 4;
1290 if (userbuffer) {
1291 if (put_user(swap32,
1292 (u32 __user *)userbuffer))
1293 return -EFAULT;
1295 userbuffer += 4;
1296 } else {
1297 *((u32 *)kernbuffer) = swap32;
1298 kernbuffer += 4;
1300 addr += 4;
1301 length -= 4;
1303 #if 0 /* That does not work, as EP 2 is an OUT EP! */
1304 default:
1305 CLEARPACKET(&packet);
1306 packet.header = 0x001f;
1307 packet.address = 0x000001a0;
1308 packet.data = 0x00000006;
1309 ret |= sisusb_send_bridge_packet(sisusb, 10,
1310 &packet, 0);
1311 packet.header = 0x001f;
1312 packet.address = 0x000001b0;
1313 packet.data = (length & ~3) | 0x40000000;
1314 ret |= sisusb_send_bridge_packet(sisusb, 10,
1315 &packet, 0);
1316 packet.header = 0x001f;
1317 packet.address = 0x000001b4;
1318 packet.data = addr;
1319 ret |= sisusb_send_bridge_packet(sisusb, 10,
1320 &packet, 0);
1321 packet.header = 0x001f;
1322 packet.address = 0x000001a4;
1323 packet.data = 0x00000001;
1324 ret |= sisusb_send_bridge_packet(sisusb, 10,
1325 &packet, 0);
1326 if (userbuffer) {
1327 ret |= sisusb_recv_bulk_msg(sisusb,
1328 SISUSB_EP_GFX_BULK_IN,
1329 (length & ~3),
1330 NULL, userbuffer,
1331 bytes_read, 0);
1332 if (!ret) userbuffer += (*bytes_read);
1333 } else {
1334 ret |= sisusb_recv_bulk_msg(sisusb,
1335 SISUSB_EP_GFX_BULK_IN,
1336 (length & ~3),
1337 kernbuffer, NULL,
1338 bytes_read, 0);
1339 if (!ret) kernbuffer += (*bytes_read);
1341 addr += (*bytes_read);
1342 length -= (*bytes_read);
1343 #endif
1346 if (ret)
1347 break;
1350 return ret;
1353 /* High level: Gfx (indexed) register access */
1355 #ifdef INCL_SISUSB_CON
1357 sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
1359 return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1363 sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
1365 return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1367 #endif
1369 #ifndef INCL_SISUSB_CON
1370 static
1371 #endif
1373 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1375 int ret;
1376 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1377 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1378 return ret;
1381 #ifndef INCL_SISUSB_CON
1382 static
1383 #endif
1385 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1387 int ret;
1388 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1389 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1390 return ret;
1393 #ifndef INCL_SISUSB_CON
1394 static
1395 #endif
1397 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1398 u8 myand, u8 myor)
1400 int ret;
1401 u8 tmp;
1403 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1404 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1405 tmp &= myand;
1406 tmp |= myor;
1407 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1408 return ret;
1411 static int
1412 sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1413 u8 data, u8 mask)
1415 int ret;
1416 u8 tmp;
1417 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1418 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1419 tmp &= ~(mask);
1420 tmp |= (data & mask);
1421 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1422 return ret;
1425 #ifndef INCL_SISUSB_CON
1426 static
1427 #endif
1429 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1431 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1434 #ifndef INCL_SISUSB_CON
1435 static
1436 #endif
1438 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1440 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1443 /* Write/read video ram */
1445 #ifdef INCL_SISUSB_CON
1447 sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
1449 return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1453 sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
1455 return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1459 sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
1461 return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1465 sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
1467 return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1471 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
1472 u32 dest, int length, size_t *bytes_written)
1474 return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
1477 #ifdef SISUSBENDIANTEST
1479 sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
1480 u32 src, int length, size_t *bytes_written)
1482 return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
1484 #endif
1485 #endif
1487 #ifdef SISUSBENDIANTEST
1488 static void
1489 sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
1491 static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
1492 char destbuffer[10];
1493 size_t dummy;
1494 int i,j;
1496 sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
1498 for(i = 1; i <= 7; i++) {
1499 printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
1500 sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
1501 for(j = 0; j < i; j++) {
1502 printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
1506 #endif
1508 /* access pci config registers (reg numbers 0, 4, 8, etc) */
1510 static int
1511 sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1513 struct sisusb_packet packet;
1514 int ret;
1516 packet.header = 0x008f;
1517 packet.address = regnum | 0x10000;
1518 packet.data = data;
1519 ret = sisusb_send_packet(sisusb, 10, &packet);
1520 return ret;
1523 static int
1524 sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1526 struct sisusb_packet packet;
1527 int ret;
1529 packet.header = 0x008f;
1530 packet.address = (u32)regnum | 0x10000;
1531 ret = sisusb_send_packet(sisusb, 6, &packet);
1532 *data = packet.data;
1533 return ret;
1536 /* Clear video RAM */
1538 static int
1539 sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1541 int ret, i;
1542 ssize_t j;
1544 if (address < sisusb->vrambase)
1545 return 1;
1547 if (address >= sisusb->vrambase + sisusb->vramsize)
1548 return 1;
1550 if (address + length > sisusb->vrambase + sisusb->vramsize)
1551 length = sisusb->vrambase + sisusb->vramsize - address;
1553 if (length <= 0)
1554 return 0;
1556 /* allocate free buffer/urb and clear the buffer */
1557 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1558 return -EBUSY;
1560 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1562 /* We can write a length > buffer size here. The buffer
1563 * data will simply be re-used (like a ring-buffer).
1565 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1567 /* Free the buffer/urb */
1568 sisusb_free_outbuf(sisusb, i);
1570 return ret;
1573 /* Initialize the graphics core (return 0 on success)
1574 * This resets the graphics hardware and puts it into
1575 * a defined mode (640x480@60Hz)
1578 #define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1579 #define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1580 #define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
1581 #define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
1582 #define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
1583 #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
1584 #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
1585 #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1586 #define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1587 #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1588 #define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1590 static int
1591 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1593 int ret;
1594 u8 tmp8;
1596 ret = GETIREG(SISSR, 0x16, &tmp8);
1597 if (ramtype <= 1) {
1598 tmp8 &= 0x3f;
1599 ret |= SETIREG(SISSR, 0x16, tmp8);
1600 tmp8 |= 0x80;
1601 ret |= SETIREG(SISSR, 0x16, tmp8);
1602 } else {
1603 tmp8 |= 0xc0;
1604 ret |= SETIREG(SISSR, 0x16, tmp8);
1605 tmp8 &= 0x0f;
1606 ret |= SETIREG(SISSR, 0x16, tmp8);
1607 tmp8 |= 0x80;
1608 ret |= SETIREG(SISSR, 0x16, tmp8);
1609 tmp8 &= 0x0f;
1610 ret |= SETIREG(SISSR, 0x16, tmp8);
1611 tmp8 |= 0xd0;
1612 ret |= SETIREG(SISSR, 0x16, tmp8);
1613 tmp8 &= 0x0f;
1614 ret |= SETIREG(SISSR, 0x16, tmp8);
1615 tmp8 |= 0xa0;
1616 ret |= SETIREG(SISSR, 0x16, tmp8);
1618 return ret;
1621 static int
1622 sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1624 int ret;
1625 u8 ramtype, done = 0;
1626 u32 t0, t1, t2, t3;
1627 u32 ramptr = SISUSB_PCI_MEMBASE;
1629 ret = GETIREG(SISSR, 0x3a, &ramtype);
1630 ramtype &= 3;
1632 ret |= SETIREG(SISSR, 0x13, 0x00);
1634 if (ramtype <= 1) {
1635 ret |= SETIREG(SISSR, 0x14, 0x12);
1636 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1637 } else {
1638 ret |= SETIREG(SISSR, 0x14, 0x02);
1641 ret |= sisusb_triggersr16(sisusb, ramtype);
1642 ret |= WRITEL(ramptr + 0, 0x01234567);
1643 ret |= WRITEL(ramptr + 4, 0x456789ab);
1644 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1645 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1646 ret |= WRITEL(ramptr + 16, 0x55555555);
1647 ret |= WRITEL(ramptr + 20, 0x55555555);
1648 ret |= WRITEL(ramptr + 24, 0xffffffff);
1649 ret |= WRITEL(ramptr + 28, 0xffffffff);
1650 ret |= READL(ramptr + 0, &t0);
1651 ret |= READL(ramptr + 4, &t1);
1652 ret |= READL(ramptr + 8, &t2);
1653 ret |= READL(ramptr + 12, &t3);
1655 if (ramtype <= 1) {
1657 *chab = 0; *bw = 64;
1659 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1660 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1661 *chab = 0; *bw = 64;
1662 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1665 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1666 *chab = 1; *bw = 64;
1667 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1669 ret |= sisusb_triggersr16(sisusb, ramtype);
1670 ret |= WRITEL(ramptr + 0, 0x89abcdef);
1671 ret |= WRITEL(ramptr + 4, 0xcdef0123);
1672 ret |= WRITEL(ramptr + 8, 0x55555555);
1673 ret |= WRITEL(ramptr + 12, 0x55555555);
1674 ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1675 ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1676 ret |= READL(ramptr + 4, &t1);
1678 if (t1 != 0xcdef0123) {
1679 *bw = 32;
1680 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1684 } else {
1686 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1688 done = 0;
1690 if (t1 == 0x456789ab) {
1691 if (t0 == 0x01234567) {
1692 *chab = 0; *bw = 64;
1693 done = 1;
1695 } else {
1696 if (t0 == 0x01234567) {
1697 *chab = 0; *bw = 32;
1698 ret |= SETIREG(SISSR, 0x14, 0x00);
1699 done = 1;
1703 if (!done) {
1704 ret |= SETIREG(SISSR, 0x14, 0x03);
1705 ret |= sisusb_triggersr16(sisusb, ramtype);
1707 ret |= WRITEL(ramptr + 0, 0x01234567);
1708 ret |= WRITEL(ramptr + 4, 0x456789ab);
1709 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1710 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1711 ret |= WRITEL(ramptr + 16, 0x55555555);
1712 ret |= WRITEL(ramptr + 20, 0x55555555);
1713 ret |= WRITEL(ramptr + 24, 0xffffffff);
1714 ret |= WRITEL(ramptr + 28, 0xffffffff);
1715 ret |= READL(ramptr + 0, &t0);
1716 ret |= READL(ramptr + 4, &t1);
1718 if (t1 == 0x456789ab) {
1719 if (t0 == 0x01234567) {
1720 *chab = 1; *bw = 64;
1721 return ret;
1722 } /* else error */
1723 } else {
1724 if (t0 == 0x01234567) {
1725 *chab = 1; *bw = 32;
1726 ret |= SETIREG(SISSR, 0x14, 0x01);
1727 } /* else error */
1731 return ret;
1734 static int
1735 sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1737 int ret = 0;
1738 u32 ramptr = SISUSB_PCI_MEMBASE;
1739 u8 tmp1, tmp2, i, j;
1741 ret |= WRITEB(ramptr, 0xaa);
1742 ret |= WRITEB(ramptr + 16, 0x55);
1743 ret |= READB(ramptr, &tmp1);
1744 ret |= READB(ramptr + 16, &tmp2);
1745 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1746 for (i = 0, j = 16; i < 2; i++, j += 16) {
1747 ret |= GETIREG(SISSR, 0x21, &tmp1);
1748 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1749 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1750 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1751 ret |= SETIREG(SISSR, 0x21, tmp1);
1752 ret |= WRITEB(ramptr + 16 + j, j);
1753 ret |= READB(ramptr + 16 + j, &tmp1);
1754 if (tmp1 == j) {
1755 ret |= WRITEB(ramptr + j, j);
1756 break;
1760 return ret;
1763 static int
1764 sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1765 u8 rankno, u8 chab, const u8 dramtype[][5],
1766 int bw)
1768 int ret = 0, ranksize;
1769 u8 tmp;
1771 *iret = 0;
1773 if ((rankno == 2) && (dramtype[index][0] == 2))
1774 return ret;
1776 ranksize = dramtype[index][3] / 2 * bw / 32;
1778 if ((ranksize * rankno) > 128)
1779 return ret;
1781 tmp = 0;
1782 while ((ranksize >>= 1) > 0) tmp += 0x10;
1783 tmp |= ((rankno - 1) << 2);
1784 tmp |= ((bw / 64) & 0x02);
1785 tmp |= (chab & 0x01);
1787 ret = SETIREG(SISSR, 0x14, tmp);
1788 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1790 *iret = 1;
1792 return ret;
1795 static int
1796 sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1798 int ret = 0, i;
1799 u32 j, tmp;
1801 *iret = 0;
1803 for (i = 0, j = 0; i < testn; i++) {
1804 ret |= WRITEL(sisusb->vrambase + j, j);
1805 j += inc;
1808 for (i = 0, j = 0; i < testn; i++) {
1809 ret |= READL(sisusb->vrambase + j, &tmp);
1810 if (tmp != j) return ret;
1811 j += inc;
1814 *iret = 1;
1815 return ret;
1818 static int
1819 sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1820 int idx, int bw, const u8 rtype[][5])
1822 int ret = 0, i, i2ret;
1823 u32 inc;
1825 *iret = 0;
1827 for (i = rankno; i >= 1; i--) {
1828 inc = 1 << (rtype[idx][2] +
1829 rtype[idx][1] +
1830 rtype[idx][0] +
1831 bw / 64 + i);
1832 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1833 if (!i2ret)
1834 return ret;
1837 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1838 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1839 if (!i2ret)
1840 return ret;
1842 inc = 1 << (10 + bw / 64);
1843 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1844 if (!i2ret)
1845 return ret;
1847 *iret = 1;
1848 return ret;
1851 static int
1852 sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1853 int chab)
1855 int ret = 0, i2ret = 0, i, j;
1856 static const u8 sdramtype[13][5] = {
1857 { 2, 12, 9, 64, 0x35 },
1858 { 1, 13, 9, 64, 0x44 },
1859 { 2, 12, 8, 32, 0x31 },
1860 { 2, 11, 9, 32, 0x25 },
1861 { 1, 12, 9, 32, 0x34 },
1862 { 1, 13, 8, 32, 0x40 },
1863 { 2, 11, 8, 16, 0x21 },
1864 { 1, 12, 8, 16, 0x30 },
1865 { 1, 11, 9, 16, 0x24 },
1866 { 1, 11, 8, 8, 0x20 },
1867 { 2, 9, 8, 4, 0x01 },
1868 { 1, 10, 8, 4, 0x10 },
1869 { 1, 9, 8, 2, 0x00 }
1872 *iret = 1; /* error */
1874 for (i = 0; i < 13; i++) {
1875 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1876 for (j = 2; j > 0; j--) {
1877 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1878 chab, sdramtype, bw);
1879 if (!i2ret)
1880 continue;
1882 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1883 bw, sdramtype);
1884 if (i2ret) {
1885 *iret = 0; /* ram size found */
1886 return ret;
1891 return ret;
1894 static int
1895 sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1897 int ret = 0;
1898 u32 address;
1899 int i, length, modex, modey, bpp;
1901 modex = 640; modey = 480; bpp = 2;
1903 address = sisusb->vrambase; /* Clear video ram */
1905 if (clrall)
1906 length = sisusb->vramsize;
1907 else
1908 length = modex * bpp * modey;
1910 ret = sisusb_clear_vram(sisusb, address, length);
1912 if (!ret && drwfr) {
1913 for (i = 0; i < modex; i++) {
1914 address = sisusb->vrambase + (i * bpp);
1915 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1916 address, 0xf100);
1917 address += (modex * (modey-1) * bpp);
1918 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1919 address, 0xf100);
1921 for (i = 0; i < modey; i++) {
1922 address = sisusb->vrambase + ((i * modex) * bpp);
1923 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1924 address, 0xf100);
1925 address += ((modex - 1) * bpp);
1926 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1927 address, 0xf100);
1931 return ret;
1934 static int
1935 sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1937 int ret = 0, i, j, modex, modey, bpp, du;
1938 u8 sr31, cr63, tmp8;
1939 static const char attrdata[] = {
1940 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1941 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1942 0x01,0x00,0x00,0x00
1944 static const char crtcrdata[] = {
1945 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1946 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1947 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1948 0xff
1950 static const char grcdata[] = {
1951 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1952 0xff
1954 static const char crtcdata[] = {
1955 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1956 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1957 0x00
1960 modex = 640; modey = 480; bpp = 2;
1962 GETIREG(SISSR, 0x31, &sr31);
1963 GETIREG(SISCR, 0x63, &cr63);
1964 SETIREGOR(SISSR, 0x01, 0x20);
1965 SETIREG(SISCR, 0x63, cr63 & 0xbf);
1966 SETIREGOR(SISCR, 0x17, 0x80);
1967 SETIREGOR(SISSR, 0x1f, 0x04);
1968 SETIREGAND(SISSR, 0x07, 0xfb);
1969 SETIREG(SISSR, 0x00, 0x03); /* seq */
1970 SETIREG(SISSR, 0x01, 0x21);
1971 SETIREG(SISSR, 0x02, 0x0f);
1972 SETIREG(SISSR, 0x03, 0x00);
1973 SETIREG(SISSR, 0x04, 0x0e);
1974 SETREG(SISMISCW, 0x23); /* misc */
1975 for (i = 0; i <= 0x18; i++) { /* crtc */
1976 SETIREG(SISCR, i, crtcrdata[i]);
1978 for (i = 0; i <= 0x13; i++) { /* att */
1979 GETREG(SISINPSTAT, &tmp8);
1980 SETREG(SISAR, i);
1981 SETREG(SISAR, attrdata[i]);
1983 GETREG(SISINPSTAT, &tmp8);
1984 SETREG(SISAR, 0x14);
1985 SETREG(SISAR, 0x00);
1986 GETREG(SISINPSTAT, &tmp8);
1987 SETREG(SISAR, 0x20);
1988 GETREG(SISINPSTAT, &tmp8);
1989 for (i = 0; i <= 0x08; i++) { /* grc */
1990 SETIREG(SISGR, i, grcdata[i]);
1992 SETIREGAND(SISGR, 0x05, 0xbf);
1993 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1994 SETIREG(SISSR, i, 0x00);
1996 SETIREGAND(SISSR, 0x37, 0xfe);
1997 SETREG(SISMISCW, 0xef); /* sync */
1998 SETIREG(SISCR, 0x11, 0x00); /* crtc */
1999 for (j = 0x00, i = 0; i <= 7; i++, j++) {
2000 SETIREG(SISCR, j, crtcdata[i]);
2002 for (j = 0x10; i <= 10; i++, j++) {
2003 SETIREG(SISCR, j, crtcdata[i]);
2005 for (j = 0x15; i <= 12; i++, j++) {
2006 SETIREG(SISCR, j, crtcdata[i]);
2008 for (j = 0x0A; i <= 15; i++, j++) {
2009 SETIREG(SISSR, j, crtcdata[i]);
2011 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
2012 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
2013 SETIREG(SISCR, 0x14, 0x4f);
2014 du = (modex / 16) * (bpp * 2); /* offset/pitch */
2015 if (modex % 16) du += bpp;
2016 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
2017 SETIREG(SISCR, 0x13, (du & 0xff));
2018 du <<= 5;
2019 tmp8 = du >> 8;
2020 if (du & 0xff) tmp8++;
2021 SETIREG(SISSR, 0x10, tmp8);
2022 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
2023 SETIREG(SISSR, 0x2b, 0x1b);
2024 SETIREG(SISSR, 0x2c, 0xe1);
2025 SETIREG(SISSR, 0x2d, 0x01);
2026 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
2027 SETIREG(SISSR, 0x08, 0xae);
2028 SETIREGAND(SISSR, 0x09, 0xf0);
2029 SETIREG(SISSR, 0x08, 0x34);
2030 SETIREGOR(SISSR, 0x3d, 0x01);
2031 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
2032 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
2033 SETIREG(SISCR, 0x19, 0x00);
2034 SETIREGAND(SISCR, 0x1a, 0xfc);
2035 SETIREGAND(SISSR, 0x0f, 0xb7);
2036 SETIREGAND(SISSR, 0x31, 0xfb);
2037 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
2038 SETIREGAND(SISSR, 0x32, 0xf3);
2039 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
2040 SETIREG(SISCR, 0x52, 0x6c);
2042 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
2043 SETIREG(SISCR, 0x0c, 0x00);
2044 SETIREG(SISSR, 0x0d, 0x00);
2045 SETIREGAND(SISSR, 0x37, 0xfe);
2047 SETIREG(SISCR, 0x32, 0x20);
2048 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
2049 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
2050 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
2052 if (touchengines) {
2053 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
2054 SETIREGOR(SISSR, 0x1e, 0x5a);
2056 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
2057 SETIREG(SISSR, 0x27, 0x1f);
2058 SETIREG(SISSR, 0x26, 0x00);
2061 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
2063 return ret;
2066 static int
2067 sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
2069 int ret = 0, i, j, bw, chab, iret, retry = 3;
2070 u8 tmp8, ramtype;
2071 u32 tmp32;
2072 static const char mclktable[] = {
2073 0x3b, 0x22, 0x01, 143,
2074 0x3b, 0x22, 0x01, 143,
2075 0x3b, 0x22, 0x01, 143,
2076 0x3b, 0x22, 0x01, 143
2078 static const char eclktable[] = {
2079 0x3b, 0x22, 0x01, 143,
2080 0x3b, 0x22, 0x01, 143,
2081 0x3b, 0x22, 0x01, 143,
2082 0x3b, 0x22, 0x01, 143
2084 static const char ramtypetable1[] = {
2085 0x00, 0x04, 0x60, 0x60,
2086 0x0f, 0x0f, 0x1f, 0x1f,
2087 0xba, 0xba, 0xba, 0xba,
2088 0xa9, 0xa9, 0xac, 0xac,
2089 0xa0, 0xa0, 0xa0, 0xa8,
2090 0x00, 0x00, 0x02, 0x02,
2091 0x30, 0x30, 0x40, 0x40
2093 static const char ramtypetable2[] = {
2094 0x77, 0x77, 0x44, 0x44,
2095 0x77, 0x77, 0x44, 0x44,
2096 0x00, 0x00, 0x00, 0x00,
2097 0x5b, 0x5b, 0xab, 0xab,
2098 0x00, 0x00, 0xf0, 0xf8
2101 while (retry--) {
2103 /* Enable VGA */
2104 ret = GETREG(SISVGAEN, &tmp8);
2105 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
2107 /* Enable GPU access to VRAM */
2108 ret |= GETREG(SISMISCR, &tmp8);
2109 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
2111 if (ret) continue;
2113 /* Reset registers */
2114 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
2115 ret |= SETIREG(SISSR, 0x05, 0x86);
2116 ret |= SETIREGOR(SISSR, 0x20, 0x01);
2118 ret |= SETREG(SISMISCW, 0x67);
2120 for (i = 0x06; i <= 0x1f; i++) {
2121 ret |= SETIREG(SISSR, i, 0x00);
2123 for (i = 0x21; i <= 0x27; i++) {
2124 ret |= SETIREG(SISSR, i, 0x00);
2126 for (i = 0x31; i <= 0x3d; i++) {
2127 ret |= SETIREG(SISSR, i, 0x00);
2129 for (i = 0x12; i <= 0x1b; i++) {
2130 ret |= SETIREG(SISSR, i, 0x00);
2132 for (i = 0x79; i <= 0x7c; i++) {
2133 ret |= SETIREG(SISCR, i, 0x00);
2136 if (ret) continue;
2138 ret |= SETIREG(SISCR, 0x63, 0x80);
2140 ret |= GETIREG(SISSR, 0x3a, &ramtype);
2141 ramtype &= 0x03;
2143 ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
2144 ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
2145 ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
2147 ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
2148 ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
2149 ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
2151 ret |= SETIREG(SISSR, 0x07, 0x18);
2152 ret |= SETIREG(SISSR, 0x11, 0x0f);
2154 if (ret) continue;
2156 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2157 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2159 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2160 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2163 ret |= SETIREG(SISCR, 0x49, 0xaa);
2165 ret |= SETIREG(SISSR, 0x1f, 0x00);
2166 ret |= SETIREG(SISSR, 0x20, 0xa0);
2167 ret |= SETIREG(SISSR, 0x23, 0xf6);
2168 ret |= SETIREG(SISSR, 0x24, 0x0d);
2169 ret |= SETIREG(SISSR, 0x25, 0x33);
2171 ret |= SETIREG(SISSR, 0x11, 0x0f);
2173 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2175 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2177 if (ret) continue;
2179 ret |= SETIREG(SISPART1, 0x00, 0x00);
2181 ret |= GETIREG(SISSR, 0x13, &tmp8);
2182 tmp8 >>= 4;
2184 ret |= SETIREG(SISPART1, 0x02, 0x00);
2185 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2187 ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
2188 tmp32 &= 0x00f00000;
2189 tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
2190 ret |= SETIREG(SISSR, 0x25, tmp8);
2191 tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
2192 ret |= SETIREG(SISCR, 0x49, tmp8);
2194 ret |= SETIREG(SISSR, 0x27, 0x1f);
2195 ret |= SETIREG(SISSR, 0x31, 0x00);
2196 ret |= SETIREG(SISSR, 0x32, 0x11);
2197 ret |= SETIREG(SISSR, 0x33, 0x00);
2199 if (ret) continue;
2201 ret |= SETIREG(SISCR, 0x83, 0x00);
2203 ret |= sisusb_set_default_mode(sisusb, 0);
2205 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2206 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2207 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2209 ret |= sisusb_triggersr16(sisusb, ramtype);
2211 /* Disable refresh */
2212 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2213 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2215 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2216 ret |= sisusb_verify_mclk(sisusb);
2218 if (ramtype <= 1) {
2219 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2220 if (iret) {
2221 printk(KERN_ERR "sisusbvga[%d]: RAM size "
2222 "detection failed, "
2223 "assuming 8MB video RAM\n",
2224 sisusb->minor);
2225 ret |= SETIREG(SISSR,0x14,0x31);
2226 /* TODO */
2228 } else {
2229 printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
2230 "assuming 8MB video RAM\n",
2231 sisusb->minor);
2232 ret |= SETIREG(SISSR,0x14,0x31);
2233 /* *** TODO *** */
2236 /* Enable refresh */
2237 ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
2238 ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
2239 ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
2241 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2243 ret |= SETIREG(SISSR, 0x22, 0xfb);
2244 ret |= SETIREG(SISSR, 0x21, 0xa5);
2246 if (ret == 0)
2247 break;
2250 return ret;
2253 #undef SETREG
2254 #undef GETREG
2255 #undef SETIREG
2256 #undef GETIREG
2257 #undef SETIREGOR
2258 #undef SETIREGAND
2259 #undef SETIREGANDOR
2260 #undef READL
2261 #undef WRITEL
2263 static void
2264 sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2266 u8 tmp8, tmp82, ramtype;
2267 int bw = 0;
2268 char *ramtypetext1 = NULL;
2269 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2270 "DDR SDRAM", "DDR SGRAM" };
2271 static const int busSDR[4] = {64, 64, 128, 128};
2272 static const int busDDR[4] = {32, 32, 64, 64};
2273 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2275 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2276 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2277 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2278 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2279 ramtype &= 0x03;
2280 switch ((tmp8 >> 2) & 0x03) {
2281 case 0: ramtypetext1 = "1 ch/1 r";
2282 if (tmp82 & 0x10) {
2283 bw = 32;
2284 } else {
2285 bw = busSDR[(tmp8 & 0x03)];
2287 break;
2288 case 1: ramtypetext1 = "1 ch/2 r";
2289 sisusb->vramsize <<= 1;
2290 bw = busSDR[(tmp8 & 0x03)];
2291 break;
2292 case 2: ramtypetext1 = "asymmeric";
2293 sisusb->vramsize += sisusb->vramsize/2;
2294 bw = busDDRA[(tmp8 & 0x03)];
2295 break;
2296 case 3: ramtypetext1 = "2 channel";
2297 sisusb->vramsize <<= 1;
2298 bw = busDDR[(tmp8 & 0x03)];
2299 break;
2302 printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2303 sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
2304 ramtypetext2[ramtype], bw);
2307 static int
2308 sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2310 struct sisusb_packet packet;
2311 int ret;
2312 u32 tmp32;
2314 /* Do some magic */
2315 packet.header = 0x001f;
2316 packet.address = 0x00000324;
2317 packet.data = 0x00000004;
2318 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2320 packet.header = 0x001f;
2321 packet.address = 0x00000364;
2322 packet.data = 0x00000004;
2323 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2325 packet.header = 0x001f;
2326 packet.address = 0x00000384;
2327 packet.data = 0x00000004;
2328 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2330 packet.header = 0x001f;
2331 packet.address = 0x00000100;
2332 packet.data = 0x00000700;
2333 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2335 packet.header = 0x000f;
2336 packet.address = 0x00000004;
2337 ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2338 packet.data |= 0x17;
2339 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2341 /* Init BAR 0 (VRAM) */
2342 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2343 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2344 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2345 tmp32 &= 0x0f;
2346 tmp32 |= SISUSB_PCI_MEMBASE;
2347 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2349 /* Init BAR 1 (MMIO) */
2350 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2351 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2352 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2353 tmp32 &= 0x0f;
2354 tmp32 |= SISUSB_PCI_MMIOBASE;
2355 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2357 /* Init BAR 2 (i/o ports) */
2358 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2359 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2360 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2361 tmp32 &= 0x0f;
2362 tmp32 |= SISUSB_PCI_IOPORTBASE;
2363 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2365 /* Enable memory and i/o access */
2366 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2367 tmp32 |= 0x3;
2368 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2370 if (ret == 0) {
2371 /* Some further magic */
2372 packet.header = 0x001f;
2373 packet.address = 0x00000050;
2374 packet.data = 0x000000ff;
2375 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2378 return ret;
2381 /* Initialize the graphics device (return 0 on success)
2382 * This initializes the net2280 as well as the PCI registers
2383 * of the graphics board.
2386 static int
2387 sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2389 int ret = 0, test = 0;
2390 u32 tmp32;
2392 if (sisusb->devinit == 1) {
2393 /* Read PCI BARs and see if they have been set up */
2394 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2395 if (ret) return ret;
2396 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
2398 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2399 if (ret) return ret;
2400 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2402 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2403 if (ret) return ret;
2404 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2407 /* No? So reset the device */
2408 if ((sisusb->devinit == 0) || (test != 3)) {
2410 ret |= sisusb_do_init_gfxdevice(sisusb);
2412 if (ret == 0)
2413 sisusb->devinit = 1;
2417 if (sisusb->devinit) {
2418 /* Initialize the graphics core */
2419 if (sisusb_init_gfxcore(sisusb) == 0) {
2420 sisusb->gfxinit = 1;
2421 sisusb_get_ramconfig(sisusb);
2422 ret |= sisusb_set_default_mode(sisusb, 1);
2423 ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2427 return ret;
2431 #ifdef INCL_SISUSB_CON
2433 /* Set up default text mode:
2434 - Set text mode (0x03)
2435 - Upload default font
2436 - Upload user font (if available)
2440 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
2442 int ret = 0, slot = sisusb->font_slot, i;
2443 struct font_desc *myfont;
2444 u8 *tempbuf;
2445 u16 *tempbufb;
2446 size_t written;
2447 static char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
2448 static char bootlogo[] = "(o_ //\\ V_/_";
2450 /* sisusb->lock is down */
2452 if (!sisusb->SiS_Pr)
2453 return 1;
2455 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2456 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2458 /* Set mode 0x03 */
2459 SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
2461 if (!(myfont = find_font("VGA8x16")))
2462 return 1;
2464 if (!(tempbuf = vmalloc(8192)))
2465 return 1;
2467 for (i = 0; i < 256; i++)
2468 memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
2470 /* Upload default font */
2471 ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
2473 vfree(tempbuf);
2475 /* Upload user font (and reset current slot) */
2476 if (sisusb->font_backup) {
2477 ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
2478 8192, sisusb->font_backup_512, 1, NULL,
2479 sisusb->font_backup_height, 0);
2480 if (slot != 2)
2481 sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
2482 NULL, 16, 0);
2485 if (init && !sisusb->scrbuf) {
2487 if ((tempbuf = vmalloc(8192))) {
2489 i = 4096;
2490 tempbufb = (u16 *)tempbuf;
2491 while (i--)
2492 *(tempbufb++) = 0x0720;
2494 i = 0;
2495 tempbufb = (u16 *)tempbuf;
2496 while (bootlogo[i]) {
2497 *(tempbufb++) = 0x0700 | bootlogo[i++];
2498 if (!(i % 4))
2499 tempbufb += 76;
2502 i = 0;
2503 tempbufb = (u16 *)tempbuf + 6;
2504 while (bootstring[i])
2505 *(tempbufb++) = 0x0700 | bootstring[i++];
2507 ret |= sisusb_copy_memory(sisusb, tempbuf,
2508 sisusb->vrambase, 8192, &written);
2510 vfree(tempbuf);
2514 } else if (sisusb->scrbuf) {
2516 ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
2517 sisusb->vrambase, sisusb->scrbuf_size, &written);
2521 if (sisusb->sisusb_cursor_size_from >= 0 &&
2522 sisusb->sisusb_cursor_size_to >= 0) {
2523 sisusb_setidxreg(sisusb, SISCR, 0x0a,
2524 sisusb->sisusb_cursor_size_from);
2525 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
2526 sisusb->sisusb_cursor_size_to);
2527 } else {
2528 sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
2529 sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
2530 sisusb->sisusb_cursor_size_to = -1;
2533 slot = sisusb->sisusb_cursor_loc;
2534 if(slot < 0) slot = 0;
2536 sisusb->sisusb_cursor_loc = -1;
2537 sisusb->bad_cursor_pos = 1;
2539 sisusb_set_cursor(sisusb, slot);
2541 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
2542 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
2544 sisusb->textmodedestroyed = 0;
2546 /* sisusb->lock is down */
2548 return ret;
2551 #endif
2553 /* fops */
2555 static int
2556 sisusb_open(struct inode *inode, struct file *file)
2558 struct sisusb_usb_data *sisusb;
2559 struct usb_interface *interface;
2560 int subminor = iminor(inode);
2562 down(&disconnect_sem);
2564 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
2565 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
2566 subminor);
2567 up(&disconnect_sem);
2568 return -ENODEV;
2571 if (!(sisusb = usb_get_intfdata(interface))) {
2572 up(&disconnect_sem);
2573 return -ENODEV;
2576 down(&sisusb->lock);
2578 if (!sisusb->present || !sisusb->ready) {
2579 up(&sisusb->lock);
2580 up(&disconnect_sem);
2581 return -ENODEV;
2584 if (sisusb->isopen) {
2585 up(&sisusb->lock);
2586 up(&disconnect_sem);
2587 return -EBUSY;
2590 if (!sisusb->devinit) {
2591 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2592 if (sisusb_init_gfxdevice(sisusb, 0)) {
2593 up(&sisusb->lock);
2594 up(&disconnect_sem);
2595 printk(KERN_ERR
2596 "sisusbvga[%d]: Failed to initialize "
2597 "device\n",
2598 sisusb->minor);
2599 return -EIO;
2601 } else {
2602 up(&sisusb->lock);
2603 up(&disconnect_sem);
2604 printk(KERN_ERR
2605 "sisusbvga[%d]: Device not attached to "
2606 "USB 2.0 hub\n",
2607 sisusb->minor);
2608 return -EIO;
2612 /* Increment usage count for our sisusb */
2613 kref_get(&sisusb->kref);
2615 sisusb->isopen = 1;
2617 file->private_data = sisusb;
2619 up(&sisusb->lock);
2621 up(&disconnect_sem);
2623 return 0;
2626 void
2627 sisusb_delete(struct kref *kref)
2629 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2631 if (!sisusb)
2632 return;
2634 if (sisusb->sisusb_dev)
2635 usb_put_dev(sisusb->sisusb_dev);
2637 sisusb->sisusb_dev = NULL;
2638 sisusb_free_buffers(sisusb);
2639 sisusb_free_urbs(sisusb);
2640 #ifdef INCL_SISUSB_CON
2641 kfree(sisusb->SiS_Pr);
2642 #endif
2643 kfree(sisusb);
2646 static int
2647 sisusb_release(struct inode *inode, struct file *file)
2649 struct sisusb_usb_data *sisusb;
2650 int myminor;
2652 down(&disconnect_sem);
2654 if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
2655 up(&disconnect_sem);
2656 return -ENODEV;
2659 down(&sisusb->lock);
2661 if (sisusb->present) {
2662 /* Wait for all URBs to finish if device still present */
2663 if (!sisusb_wait_all_out_complete(sisusb))
2664 sisusb_kill_all_busy(sisusb);
2667 myminor = sisusb->minor;
2669 sisusb->isopen = 0;
2670 file->private_data = NULL;
2672 up(&sisusb->lock);
2674 /* decrement the usage count on our device */
2675 kref_put(&sisusb->kref, sisusb_delete);
2677 up(&disconnect_sem);
2679 return 0;
2682 static ssize_t
2683 sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2685 struct sisusb_usb_data *sisusb;
2686 ssize_t bytes_read = 0;
2687 int errno = 0;
2688 u8 buf8;
2689 u16 buf16;
2690 u32 buf32, address;
2692 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2693 return -ENODEV;
2695 down(&sisusb->lock);
2697 /* Sanity check */
2698 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2699 up(&sisusb->lock);
2700 return -ENODEV;
2703 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2704 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2706 address = (*ppos) -
2707 SISUSB_PCI_PSEUDO_IOPORTBASE +
2708 SISUSB_PCI_IOPORTBASE;
2710 /* Read i/o ports
2711 * Byte, word and long(32) can be read. As this
2712 * emulates inX instructions, the data returned is
2713 * in machine-endianness.
2715 switch (count) {
2717 case 1:
2718 if (sisusb_read_memio_byte(sisusb,
2719 SISUSB_TYPE_IO,
2720 address, &buf8))
2721 errno = -EIO;
2722 else if (put_user(buf8, (u8 __user *)buffer))
2723 errno = -EFAULT;
2724 else
2725 bytes_read = 1;
2727 break;
2729 case 2:
2730 if (sisusb_read_memio_word(sisusb,
2731 SISUSB_TYPE_IO,
2732 address, &buf16))
2733 errno = -EIO;
2734 else if (put_user(buf16, (u16 __user *)buffer))
2735 errno = -EFAULT;
2736 else
2737 bytes_read = 2;
2739 break;
2741 case 4:
2742 if (sisusb_read_memio_long(sisusb,
2743 SISUSB_TYPE_IO,
2744 address, &buf32))
2745 errno = -EIO;
2746 else if (put_user(buf32, (u32 __user *)buffer))
2747 errno = -EFAULT;
2748 else
2749 bytes_read = 4;
2751 break;
2753 default:
2754 errno = -EIO;
2758 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2759 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2761 address = (*ppos) -
2762 SISUSB_PCI_PSEUDO_MEMBASE +
2763 SISUSB_PCI_MEMBASE;
2765 /* Read video ram
2766 * Remember: Data delivered is never endian-corrected
2768 errno = sisusb_read_mem_bulk(sisusb, address,
2769 NULL, count, buffer, &bytes_read);
2771 if (bytes_read)
2772 errno = bytes_read;
2774 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2775 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2777 address = (*ppos) -
2778 SISUSB_PCI_PSEUDO_MMIOBASE +
2779 SISUSB_PCI_MMIOBASE;
2781 /* Read MMIO
2782 * Remember: Data delivered is never endian-corrected
2784 errno = sisusb_read_mem_bulk(sisusb, address,
2785 NULL, count, buffer, &bytes_read);
2787 if (bytes_read)
2788 errno = bytes_read;
2790 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2791 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2793 if (count != 4) {
2794 up(&sisusb->lock);
2795 return -EINVAL;
2798 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2800 /* Read PCI config register
2801 * Return value delivered in machine endianness.
2803 if (sisusb_read_pci_config(sisusb, address, &buf32))
2804 errno = -EIO;
2805 else if (put_user(buf32, (u32 __user *)buffer))
2806 errno = -EFAULT;
2807 else
2808 bytes_read = 4;
2810 } else {
2812 errno = -EBADFD;
2816 (*ppos) += bytes_read;
2818 up(&sisusb->lock);
2820 return errno ? errno : bytes_read;
2823 static ssize_t
2824 sisusb_write(struct file *file, const char __user *buffer, size_t count,
2825 loff_t *ppos)
2827 struct sisusb_usb_data *sisusb;
2828 int errno = 0;
2829 ssize_t bytes_written = 0;
2830 u8 buf8;
2831 u16 buf16;
2832 u32 buf32, address;
2834 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2835 return -ENODEV;
2837 down(&sisusb->lock);
2839 /* Sanity check */
2840 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2841 up(&sisusb->lock);
2842 return -ENODEV;
2845 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2846 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2848 address = (*ppos) -
2849 SISUSB_PCI_PSEUDO_IOPORTBASE +
2850 SISUSB_PCI_IOPORTBASE;
2852 /* Write i/o ports
2853 * Byte, word and long(32) can be written. As this
2854 * emulates outX instructions, the data is expected
2855 * in machine-endianness.
2857 switch (count) {
2859 case 1:
2860 if (get_user(buf8, (u8 __user *)buffer))
2861 errno = -EFAULT;
2862 else if (sisusb_write_memio_byte(sisusb,
2863 SISUSB_TYPE_IO,
2864 address, buf8))
2865 errno = -EIO;
2866 else
2867 bytes_written = 1;
2869 break;
2871 case 2:
2872 if (get_user(buf16, (u16 __user *)buffer))
2873 errno = -EFAULT;
2874 else if (sisusb_write_memio_word(sisusb,
2875 SISUSB_TYPE_IO,
2876 address, buf16))
2877 errno = -EIO;
2878 else
2879 bytes_written = 2;
2881 break;
2883 case 4:
2884 if (get_user(buf32, (u32 __user *)buffer))
2885 errno = -EFAULT;
2886 else if (sisusb_write_memio_long(sisusb,
2887 SISUSB_TYPE_IO,
2888 address, buf32))
2889 errno = -EIO;
2890 else
2891 bytes_written = 4;
2893 break;
2895 default:
2896 errno = -EIO;
2899 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2900 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2902 address = (*ppos) -
2903 SISUSB_PCI_PSEUDO_MEMBASE +
2904 SISUSB_PCI_MEMBASE;
2906 /* Write video ram.
2907 * Buffer is copied 1:1, therefore, on big-endian
2908 * machines, the data must be swapped by userland
2909 * in advance (if applicable; no swapping in 8bpp
2910 * mode or if YUV data is being transferred).
2912 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2913 count, buffer, 0, &bytes_written);
2915 if (bytes_written)
2916 errno = bytes_written;
2918 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2919 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2921 address = (*ppos) -
2922 SISUSB_PCI_PSEUDO_MMIOBASE +
2923 SISUSB_PCI_MMIOBASE;
2925 /* Write MMIO.
2926 * Buffer is copied 1:1, therefore, on big-endian
2927 * machines, the data must be swapped by userland
2928 * in advance.
2930 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2931 count, buffer, 0, &bytes_written);
2933 if (bytes_written)
2934 errno = bytes_written;
2936 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2937 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2939 if (count != 4) {
2940 up(&sisusb->lock);
2941 return -EINVAL;
2944 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2946 /* Write PCI config register.
2947 * Given value expected in machine endianness.
2949 if (get_user(buf32, (u32 __user *)buffer))
2950 errno = -EFAULT;
2951 else if (sisusb_write_pci_config(sisusb, address, buf32))
2952 errno = -EIO;
2953 else
2954 bytes_written = 4;
2957 } else {
2959 /* Error */
2960 errno = -EBADFD;
2964 (*ppos) += bytes_written;
2966 up(&sisusb->lock);
2968 return errno ? errno : bytes_written;
2971 static loff_t
2972 sisusb_lseek(struct file *file, loff_t offset, int orig)
2974 struct sisusb_usb_data *sisusb;
2975 loff_t ret;
2977 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2978 return -ENODEV;
2980 down(&sisusb->lock);
2982 /* Sanity check */
2983 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2984 up(&sisusb->lock);
2985 return -ENODEV;
2988 switch (orig) {
2989 case 0:
2990 file->f_pos = offset;
2991 ret = file->f_pos;
2992 /* never negative, no force_successful_syscall needed */
2993 break;
2994 case 1:
2995 file->f_pos += offset;
2996 ret = file->f_pos;
2997 /* never negative, no force_successful_syscall needed */
2998 break;
2999 default:
3000 /* seeking relative to "end of file" is not supported */
3001 ret = -EINVAL;
3004 up(&sisusb->lock);
3005 return ret;
3008 static int
3009 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
3010 unsigned long arg)
3012 int retval, port, length;
3013 u32 address;
3015 /* All our commands require the device
3016 * to be initialized.
3018 if (!sisusb->devinit)
3019 return -ENODEV;
3021 port = y->data3 -
3022 SISUSB_PCI_PSEUDO_IOPORTBASE +
3023 SISUSB_PCI_IOPORTBASE;
3025 switch (y->operation) {
3026 case SUCMD_GET:
3027 retval = sisusb_getidxreg(sisusb, port,
3028 y->data0, &y->data1);
3029 if (!retval) {
3030 if (copy_to_user((void __user *)arg, y,
3031 sizeof(*y)))
3032 retval = -EFAULT;
3034 break;
3036 case SUCMD_SET:
3037 retval = sisusb_setidxreg(sisusb, port,
3038 y->data0, y->data1);
3039 break;
3041 case SUCMD_SETOR:
3042 retval = sisusb_setidxregor(sisusb, port,
3043 y->data0, y->data1);
3044 break;
3046 case SUCMD_SETAND:
3047 retval = sisusb_setidxregand(sisusb, port,
3048 y->data0, y->data1);
3049 break;
3051 case SUCMD_SETANDOR:
3052 retval = sisusb_setidxregandor(sisusb, port,
3053 y->data0, y->data1, y->data2);
3054 break;
3056 case SUCMD_SETMASK:
3057 retval = sisusb_setidxregmask(sisusb, port,
3058 y->data0, y->data1, y->data2);
3059 break;
3061 case SUCMD_CLRSCR:
3062 /* Gfx core must be initialized */
3063 if (!sisusb->gfxinit)
3064 return -ENODEV;
3066 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
3067 address = y->data3 -
3068 SISUSB_PCI_PSEUDO_MEMBASE +
3069 SISUSB_PCI_MEMBASE;
3070 retval = sisusb_clear_vram(sisusb, address, length);
3071 break;
3073 case SUCMD_HANDLETEXTMODE:
3074 retval = 0;
3075 #ifdef INCL_SISUSB_CON
3076 /* Gfx core must be initialized, SiS_Pr must exist */
3077 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3078 return -ENODEV;
3080 switch (y->data0) {
3081 case 0:
3082 retval = sisusb_reset_text_mode(sisusb, 0);
3083 break;
3084 case 1:
3085 sisusb->textmodedestroyed = 1;
3086 break;
3088 #endif
3089 break;
3091 #ifdef INCL_SISUSB_CON
3092 case SUCMD_SETMODE:
3093 /* Gfx core must be initialized, SiS_Pr must exist */
3094 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3095 return -ENODEV;
3097 retval = 0;
3099 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3100 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3102 if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
3103 retval = -EINVAL;
3105 break;
3107 case SUCMD_SETVESAMODE:
3108 /* Gfx core must be initialized, SiS_Pr must exist */
3109 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3110 return -ENODEV;
3112 retval = 0;
3114 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3115 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3117 if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
3118 retval = -EINVAL;
3120 break;
3121 #endif
3123 default:
3124 retval = -EINVAL;
3127 if (retval > 0)
3128 retval = -EIO;
3130 return retval;
3133 static int
3134 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
3135 unsigned long arg)
3137 struct sisusb_usb_data *sisusb;
3138 struct sisusb_info x;
3139 struct sisusb_command y;
3140 int retval = 0;
3141 u32 __user *argp = (u32 __user *)arg;
3143 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
3144 return -ENODEV;
3146 down(&sisusb->lock);
3148 /* Sanity check */
3149 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
3150 retval = -ENODEV;
3151 goto err_out;
3154 switch (cmd) {
3156 case SISUSB_GET_CONFIG_SIZE:
3158 if (put_user(sizeof(x), argp))
3159 retval = -EFAULT;
3161 break;
3163 case SISUSB_GET_CONFIG:
3165 x.sisusb_id = SISUSB_ID;
3166 x.sisusb_version = SISUSB_VERSION;
3167 x.sisusb_revision = SISUSB_REVISION;
3168 x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
3169 x.sisusb_gfxinit = sisusb->gfxinit;
3170 x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
3171 x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
3172 x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
3173 x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
3174 x.sisusb_vramsize = sisusb->vramsize;
3175 x.sisusb_minor = sisusb->minor;
3176 x.sisusb_fbdevactive= 0;
3177 #ifdef INCL_SISUSB_CON
3178 x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
3179 #else
3180 x.sisusb_conactive = 0;
3181 #endif
3183 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
3184 retval = -EFAULT;
3186 break;
3188 case SISUSB_COMMAND:
3190 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
3191 retval = -EFAULT;
3192 else
3193 retval = sisusb_handle_command(sisusb, &y, arg);
3195 break;
3197 default:
3198 retval = -EINVAL;
3199 break;
3202 err_out:
3203 up(&sisusb->lock);
3204 return retval;
3207 #ifdef SISUSB_NEW_CONFIG_COMPAT
3208 static long
3209 sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
3211 long retval;
3213 switch (cmd) {
3214 case SISUSB_GET_CONFIG_SIZE:
3215 case SISUSB_GET_CONFIG:
3216 case SISUSB_COMMAND:
3217 lock_kernel();
3218 retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
3219 unlock_kernel();
3220 return retval;
3222 default:
3223 return -ENOIOCTLCMD;
3226 #endif
3228 static struct file_operations usb_sisusb_fops = {
3229 .owner = THIS_MODULE,
3230 .open = sisusb_open,
3231 .release = sisusb_release,
3232 .read = sisusb_read,
3233 .write = sisusb_write,
3234 .llseek = sisusb_lseek,
3235 #ifdef SISUSB_NEW_CONFIG_COMPAT
3236 .compat_ioctl = sisusb_compat_ioctl,
3237 #endif
3238 .ioctl = sisusb_ioctl
3241 static struct usb_class_driver usb_sisusb_class = {
3242 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
3243 .name = "usb/sisusbvga%d",
3244 .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
3245 #else
3246 .name = "sisusbvga%d",
3247 #endif
3248 .fops = &usb_sisusb_fops,
3249 .minor_base = SISUSB_MINOR
3252 static int sisusb_probe(struct usb_interface *intf,
3253 const struct usb_device_id *id)
3255 struct usb_device *dev = interface_to_usbdev(intf);
3256 struct sisusb_usb_data *sisusb;
3257 int retval = 0, i;
3258 const char *memfail =
3259 KERN_ERR
3260 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
3262 printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
3263 dev->devnum);
3265 /* Allocate memory for our private */
3266 if (!(sisusb = kmalloc(sizeof(*sisusb), GFP_KERNEL))) {
3267 printk(KERN_ERR
3268 "sisusb: Failed to allocate memory for private data\n");
3269 return -ENOMEM;
3271 memset(sisusb, 0, sizeof(*sisusb));
3272 kref_init(&sisusb->kref);
3274 init_MUTEX(&(sisusb->lock));
3276 /* Register device */
3277 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
3278 printk(KERN_ERR
3279 "sisusb: Failed to get a minor for device %d\n",
3280 dev->devnum);
3281 retval = -ENODEV;
3282 goto error_1;
3285 sisusb->sisusb_dev = dev;
3286 sisusb->minor = intf->minor;
3287 sisusb->vrambase = SISUSB_PCI_MEMBASE;
3288 sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
3289 sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
3290 sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
3291 /* Everything else is zero */
3293 /* Allocate buffers */
3294 sisusb->ibufsize = SISUSB_IBUF_SIZE;
3295 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
3296 GFP_KERNEL, &sisusb->transfer_dma_in))) {
3297 printk(memfail, "input", sisusb->minor);
3298 retval = -ENOMEM;
3299 goto error_2;
3302 sisusb->numobufs = 0;
3303 sisusb->obufsize = SISUSB_OBUF_SIZE;
3304 for (i = 0; i < NUMOBUFS; i++) {
3305 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
3306 GFP_KERNEL,
3307 &sisusb->transfer_dma_out[i]))) {
3308 if (i == 0) {
3309 printk(memfail, "output", sisusb->minor);
3310 retval = -ENOMEM;
3311 goto error_3;
3313 break;
3314 } else
3315 sisusb->numobufs++;
3319 /* Allocate URBs */
3320 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
3321 printk(KERN_ERR
3322 "sisusbvga[%d]: Failed to allocate URBs\n",
3323 sisusb->minor);
3324 retval = -ENOMEM;
3325 goto error_3;
3327 sisusb->completein = 1;
3329 for (i = 0; i < sisusb->numobufs; i++) {
3330 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
3331 printk(KERN_ERR
3332 "sisusbvga[%d]: Failed to allocate URBs\n",
3333 sisusb->minor);
3334 retval = -ENOMEM;
3335 goto error_4;
3337 sisusb->urbout_context[i].sisusb = (void *)sisusb;
3338 sisusb->urbout_context[i].urbindex = i;
3339 sisusb->urbstatus[i] = 0;
3342 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
3343 sisusb->minor, sisusb->numobufs);
3345 #ifdef INCL_SISUSB_CON
3346 /* Allocate our SiS_Pr */
3347 if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
3348 printk(KERN_ERR
3349 "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
3350 sisusb->minor);
3352 #endif
3354 /* Do remaining init stuff */
3356 init_waitqueue_head(&sisusb->wait_q);
3358 usb_set_intfdata(intf, sisusb);
3360 usb_get_dev(sisusb->sisusb_dev);
3362 sisusb->present = 1;
3364 #ifdef SISUSB_OLD_CONFIG_COMPAT
3366 int ret;
3367 /* Our ioctls are all "32/64bit compatible" */
3368 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3369 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3370 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3371 if (ret)
3372 printk(KERN_ERR
3373 "sisusbvga[%d]: Error registering ioctl32 "
3374 "translations\n",
3375 sisusb->minor);
3376 else
3377 sisusb->ioctl32registered = 1;
3379 #endif
3381 if (dev->speed == USB_SPEED_HIGH) {
3382 int initscreen = 1;
3383 #ifdef INCL_SISUSB_CON
3384 if (sisusb_first_vc > 0 &&
3385 sisusb_last_vc > 0 &&
3386 sisusb_first_vc <= sisusb_last_vc &&
3387 sisusb_last_vc <= MAX_NR_CONSOLES)
3388 initscreen = 0;
3389 #endif
3390 if (sisusb_init_gfxdevice(sisusb, initscreen))
3391 printk(KERN_ERR
3392 "sisusbvga[%d]: Failed to early "
3393 "initialize device\n",
3394 sisusb->minor);
3396 } else
3397 printk(KERN_INFO
3398 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3399 "deferring init\n",
3400 sisusb->minor);
3402 sisusb->ready = 1;
3404 #ifdef SISUSBENDIANTEST
3405 printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
3406 sisusb_testreadwrite(sisusb);
3407 printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
3408 #endif
3410 #ifdef INCL_SISUSB_CON
3411 sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
3412 #endif
3414 return 0;
3416 error_4:
3417 sisusb_free_urbs(sisusb);
3418 error_3:
3419 sisusb_free_buffers(sisusb);
3420 error_2:
3421 usb_deregister_dev(intf, &usb_sisusb_class);
3422 error_1:
3423 kfree(sisusb);
3424 return retval;
3427 static void sisusb_disconnect(struct usb_interface *intf)
3429 struct sisusb_usb_data *sisusb;
3430 int minor;
3432 /* This should *not* happen */
3433 if (!(sisusb = usb_get_intfdata(intf)))
3434 return;
3436 #ifdef INCL_SISUSB_CON
3437 sisusb_console_exit(sisusb);
3438 #endif
3440 /* The above code doesn't need the disconnect
3441 * semaphore to be down; its meaning is to
3442 * protect all other routines from the disconnect
3443 * case, not the other way round.
3445 down(&disconnect_sem);
3447 down(&sisusb->lock);
3449 /* Wait for all URBs to complete and kill them in case (MUST do) */
3450 if (!sisusb_wait_all_out_complete(sisusb))
3451 sisusb_kill_all_busy(sisusb);
3453 minor = sisusb->minor;
3455 usb_set_intfdata(intf, NULL);
3457 usb_deregister_dev(intf, &usb_sisusb_class);
3459 #ifdef SISUSB_OLD_CONFIG_COMPAT
3460 if (sisusb->ioctl32registered) {
3461 int ret;
3462 sisusb->ioctl32registered = 0;
3463 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3464 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3465 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3466 if (ret) {
3467 printk(KERN_ERR
3468 "sisusbvga[%d]: Error unregistering "
3469 "ioctl32 translations\n",
3470 minor);
3473 #endif
3475 sisusb->present = 0;
3476 sisusb->ready = 0;
3478 up(&sisusb->lock);
3480 /* decrement our usage count */
3481 kref_put(&sisusb->kref, sisusb_delete);
3483 up(&disconnect_sem);
3485 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
3488 static struct usb_device_id sisusb_table [] = {
3489 { USB_DEVICE(0x0711, 0x0900) },
3490 { USB_DEVICE(0x182d, 0x021c) },
3491 { USB_DEVICE(0x182d, 0x0269) },
3495 MODULE_DEVICE_TABLE (usb, sisusb_table);
3497 static struct usb_driver sisusb_driver = {
3498 .owner = THIS_MODULE,
3499 .name = "sisusb",
3500 .probe = sisusb_probe,
3501 .disconnect = sisusb_disconnect,
3502 .id_table = sisusb_table,
3505 static int __init usb_sisusb_init(void)
3507 int retval;
3509 #ifdef INCL_SISUSB_CON
3510 sisusb_init_concode();
3511 #endif
3513 if (!(retval = usb_register(&sisusb_driver))) {
3515 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3516 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3517 printk(KERN_INFO
3518 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3522 return retval;
3525 static void __exit usb_sisusb_exit(void)
3527 usb_deregister(&sisusb_driver);
3530 module_init(usb_sisusb_init);
3531 module_exit(usb_sisusb_exit);
3533 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3534 MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
3535 MODULE_LICENSE("GPL");