2 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
6 * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
8 * If distributed as part of the Linux kernel, this code is licensed under the
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
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.
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/mutex.h>
40 #include <linux/module.h>
41 #include <linux/kernel.h>
42 #include <linux/signal.h>
43 #include <linux/sched.h>
44 #include <linux/errno.h>
45 #include <linux/poll.h>
46 #include <linux/init.h>
47 #include <linux/slab.h>
48 #include <linux/spinlock.h>
49 #include <linux/kref.h>
50 #include <linux/usb.h>
51 #include <linux/smp_lock.h>
52 #include <linux/vmalloc.h>
55 #include "sisusb_init.h"
57 #ifdef INCL_SISUSB_CON
58 #include <linux/font.h>
61 #define SISUSB_DONTSYNC
63 /* Forward declarations / clean-up routines */
65 #ifdef INCL_SISUSB_CON
66 static int sisusb_first_vc = 0;
67 static int sisusb_last_vc = 0;
68 module_param_named(first, sisusb_first_vc, int, 0);
69 module_param_named(last, sisusb_last_vc, int, 0);
70 MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)");
71 MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)");
74 static struct usb_driver sisusb_driver;
76 DEFINE_MUTEX(disconnect_mutex);
79 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
83 for (i = 0; i < NUMOBUFS; i++) {
84 if (sisusb->obuf[i]) {
85 usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize,
86 sisusb->obuf[i], sisusb->transfer_dma_out[i]);
87 sisusb->obuf[i] = NULL;
91 usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
92 sisusb->ibuf, sisusb->transfer_dma_in);
98 sisusb_free_urbs(struct sisusb_usb_data *sisusb)
102 for (i = 0; i < NUMOBUFS; i++) {
103 usb_free_urb(sisusb->sisurbout[i]);
104 sisusb->sisurbout[i] = NULL;
106 usb_free_urb(sisusb->sisurbin);
107 sisusb->sisurbin = NULL;
110 /* Level 0: USB transport layer */
114 /* out-urb management */
116 /* Return 1 if all free, 0 otherwise */
118 sisusb_all_free(struct sisusb_usb_data *sisusb)
122 for (i = 0; i < sisusb->numobufs; i++) {
124 if (sisusb->urbstatus[i] & SU_URB_BUSY)
132 /* Kill all busy URBs */
134 sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
138 if (sisusb_all_free(sisusb))
141 for (i = 0; i < sisusb->numobufs; i++) {
143 if (sisusb->urbstatus[i] & SU_URB_BUSY)
144 usb_kill_urb(sisusb->sisurbout[i]);
149 /* Return 1 if ok, 0 if error (not all complete within timeout) */
151 sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
153 int timeout = 5 * HZ, i = 1;
155 wait_event_timeout(sisusb->wait_q,
156 (i = sisusb_all_free(sisusb)),
163 sisusb_outurb_available(struct sisusb_usb_data *sisusb)
167 for (i = 0; i < sisusb->numobufs; i++) {
169 if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
178 sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
180 int i, timeout = 5 * HZ;
182 wait_event_timeout(sisusb->wait_q,
183 ((i = sisusb_outurb_available(sisusb)) >= 0),
190 sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
194 i = sisusb_outurb_available(sisusb);
197 sisusb->urbstatus[i] |= SU_URB_ALLOC;
203 sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
205 if ((index >= 0) && (index < sisusb->numobufs))
206 sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
209 /* completion callback */
212 sisusb_bulk_completeout(struct urb *urb)
214 struct sisusb_urb_context *context = urb->context;
215 struct sisusb_usb_data *sisusb;
220 sisusb = context->sisusb;
222 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
225 #ifndef SISUSB_DONTSYNC
226 if (context->actual_length)
227 *(context->actual_length) += urb->actual_length;
230 sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
231 wake_up(&sisusb->wait_q);
235 sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
236 int len, int *actual_length, int timeout, unsigned int tflags,
237 dma_addr_t transfer_dma)
239 struct urb *urb = sisusb->sisurbout[index];
240 int retval, byteswritten = 0;
243 urb->transfer_flags = 0;
245 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
246 sisusb_bulk_completeout, &sisusb->urbout_context[index]);
248 urb->transfer_flags |= tflags;
249 urb->actual_length = 0;
251 if ((urb->transfer_dma = transfer_dma))
252 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
255 sisusb->urbout_context[index].actual_length = (timeout) ?
256 NULL : actual_length;
258 /* Declare this urb/buffer in use */
259 sisusb->urbstatus[index] |= SU_URB_BUSY;
262 retval = usb_submit_urb(urb, GFP_ATOMIC);
264 /* If OK, and if timeout > 0, wait for completion */
265 if ((retval == 0) && timeout) {
266 wait_event_timeout(sisusb->wait_q,
267 (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
269 if (sisusb->urbstatus[index] & SU_URB_BUSY) {
270 /* URB timed out... kill it and report error */
274 /* Otherwise, report urb status */
275 retval = urb->status;
276 byteswritten = urb->actual_length;
281 *actual_length = byteswritten;
288 /* completion callback */
291 sisusb_bulk_completein(struct urb *urb)
293 struct sisusb_usb_data *sisusb = urb->context;
295 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
298 sisusb->completein = 1;
299 wake_up(&sisusb->wait_q);
303 sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len,
304 int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma)
306 struct urb *urb = sisusb->sisurbin;
307 int retval, readbytes = 0;
309 urb->transfer_flags = 0;
311 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
312 sisusb_bulk_completein, sisusb);
314 urb->transfer_flags |= tflags;
315 urb->actual_length = 0;
317 if ((urb->transfer_dma = transfer_dma))
318 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
320 sisusb->completein = 0;
321 retval = usb_submit_urb(urb, GFP_ATOMIC);
323 wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
324 if (!sisusb->completein) {
325 /* URB timed out... kill it and report error */
329 /* URB completed within timout */
330 retval = urb->status;
331 readbytes = urb->actual_length;
336 *actual_length = readbytes;
344 /* Send a bulk message of variable size
346 * To copy the data from userspace, give pointer to "userbuffer",
347 * to copy from (non-DMA) kernel memory, give "kernbuffer". If
348 * both of these are NULL, it is assumed, that the transfer
349 * buffer "sisusb->obuf[index]" is set up with the data to send.
350 * Index is ignored if either kernbuffer or userbuffer is set.
351 * If async is nonzero, URBs will be sent without waiting for
352 * completion of the previous URB.
354 * (return 0 on success)
357 static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
358 char *kernbuffer, const char __user *userbuffer, int index,
359 ssize_t *bytes_written, unsigned int tflags, int async)
361 int result = 0, retry, count = len;
362 int passsize, thispass, transferred_len = 0;
363 int fromuser = (userbuffer != NULL) ? 1 : 0;
364 int fromkern = (kernbuffer != NULL) ? 1 : 0;
368 (*bytes_written) = 0;
371 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
374 /* If we copy data from kernel or userspace, force the
375 * allocation of a buffer/urb. If we have the data in
376 * the transfer buffer[index] already, reuse the buffer/URB
377 * if the length is > buffer size. (So, transmitting
378 * large data amounts directly from the transfer buffer
379 * treats the buffer as a ring buffer. However, we need
380 * to sync in this case.)
382 if (fromuser || fromkern)
384 else if (len > sisusb->obufsize)
387 pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
390 passsize = thispass = (sisusb->obufsize < count) ?
391 sisusb->obufsize : count;
394 index = sisusb_get_free_outbuf(sisusb);
399 buffer = sisusb->obuf[index];
403 if (copy_from_user(buffer, userbuffer, passsize))
406 userbuffer += passsize;
408 } else if (fromkern) {
410 memcpy(buffer, kernbuffer, passsize);
411 kernbuffer += passsize;
418 if (!sisusb->sisusb_dev)
421 result = sisusb_bulkout_msg(sisusb,
429 sisusb->transfer_dma_out[index]);
431 if (result == -ETIMEDOUT) {
433 /* Will not happen if async */
439 } else if ((result == 0) && !async && transferred_len) {
441 thispass -= transferred_len;
443 if (sisusb->transfer_dma_out) {
444 /* If DMA, copy remaining
445 * to beginning of buffer
448 buffer + transferred_len,
451 /* If not DMA, simply increase
454 buffer += transferred_len;
465 (*bytes_written) += passsize;
468 /* Force new allocation in next iteration */
469 if (fromuser || fromkern)
475 #ifdef SISUSB_DONTSYNC
476 (*bytes_written) = len;
477 /* Some URBs/buffers might be busy */
479 sisusb_wait_all_out_complete(sisusb);
480 (*bytes_written) = transferred_len;
481 /* All URBs and all buffers are available */
485 return ((*bytes_written) == len) ? 0 : -EIO;
488 /* Receive a bulk message of variable size
490 * To copy the data to userspace, give pointer to "userbuffer",
491 * to copy to kernel memory, give "kernbuffer". One of them
492 * MUST be set. (There is no technique for letting the caller
493 * read directly from the ibuf.)
497 static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
498 void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
501 int result = 0, retry, count = len;
502 int bufsize, thispass, transferred_len;
509 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
512 pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
513 buffer = sisusb->ibuf;
514 bufsize = sisusb->ibufsize;
518 #ifdef SISUSB_DONTSYNC
519 if (!(sisusb_wait_all_out_complete(sisusb)))
525 if (!sisusb->sisusb_dev)
528 thispass = (bufsize < count) ? bufsize : count;
530 result = sisusb_bulkin_msg(sisusb,
537 sisusb->transfer_dma_in);
540 thispass = transferred_len;
542 else if (result == -ETIMEDOUT) {
555 (*bytes_read) += thispass;
560 if (copy_to_user(userbuffer, buffer, thispass))
563 userbuffer += thispass;
567 memcpy(kernbuffer, buffer, thispass);
568 kernbuffer += thispass;
576 return ((*bytes_read) == len) ? 0 : -EIO;
579 static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
580 struct sisusb_packet *packet)
583 ssize_t bytes_transferred = 0;
589 #ifdef SISUSB_DONTSYNC
590 if (!(sisusb_wait_all_out_complete(sisusb)))
594 /* Eventually correct endianness */
595 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
597 /* 1. send the packet */
598 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
599 (char *)packet, NULL, 0, &bytes_transferred, 0, 0);
601 if ((ret == 0) && (len == 6)) {
603 /* 2. if packet len == 6, it means we read, so wait for 32bit
604 * return value and write it to packet->data
606 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
607 (char *)&tmp, NULL, &bytes_transferred, 0);
609 packet->data = le32_to_cpu(tmp);
615 static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
616 struct sisusb_packet *packet,
620 ssize_t bytes_transferred = 0;
626 #ifdef SISUSB_DONTSYNC
627 if (!(sisusb_wait_all_out_complete(sisusb)))
631 /* Eventually correct endianness */
632 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
634 /* 1. send the packet */
635 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
636 (char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
638 if ((ret == 0) && (len == 6)) {
640 /* 2. if packet len == 6, it means we read, so wait for 32bit
641 * return value and write it to packet->data
643 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
644 (char *)&tmp, NULL, &bytes_transferred, 0);
646 packet->data = le32_to_cpu(tmp);
652 /* access video memory and mmio (return 0 on success) */
656 /* The following routines assume being used to transfer byte, word,
659 * - the write routines expect "data" in machine endianness format.
660 * The data will be converted to leXX in sisusb_xxx_packet.
661 * - the read routines can expect read data in machine-endianess.
664 static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
667 struct sisusb_packet packet;
670 packet.header = (1 << (addr & 3)) | (type << 6);
671 packet.address = addr & ~3;
672 packet.data = data << ((addr & 3) << 3);
673 ret = sisusb_send_packet(sisusb, 10, &packet);
677 static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
680 struct sisusb_packet packet;
683 packet.address = addr & ~3;
687 packet.header = (type << 6) | 0x0003;
688 packet.data = (u32)data;
689 ret = sisusb_send_packet(sisusb, 10, &packet);
692 packet.header = (type << 6) | 0x0006;
693 packet.data = (u32)data << 8;
694 ret = sisusb_send_packet(sisusb, 10, &packet);
697 packet.header = (type << 6) | 0x000c;
698 packet.data = (u32)data << 16;
699 ret = sisusb_send_packet(sisusb, 10, &packet);
702 packet.header = (type << 6) | 0x0008;
703 packet.data = (u32)data << 24;
704 ret = sisusb_send_packet(sisusb, 10, &packet);
705 packet.header = (type << 6) | 0x0001;
706 packet.address = (addr & ~3) + 4;
707 packet.data = (u32)data >> 8;
708 ret |= sisusb_send_packet(sisusb, 10, &packet);
714 static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
717 struct sisusb_packet packet;
720 packet.address = addr & ~3;
724 packet.header = (type << 6) | 0x0007;
725 packet.data = data & 0x00ffffff;
726 ret = sisusb_send_packet(sisusb, 10, &packet);
729 packet.header = (type << 6) | 0x000e;
730 packet.data = data << 8;
731 ret = sisusb_send_packet(sisusb, 10, &packet);
734 packet.header = (type << 6) | 0x000c;
735 packet.data = data << 16;
736 ret = sisusb_send_packet(sisusb, 10, &packet);
737 packet.header = (type << 6) | 0x0001;
738 packet.address = (addr & ~3) + 4;
739 packet.data = (data >> 16) & 0x00ff;
740 ret |= sisusb_send_packet(sisusb, 10, &packet);
743 packet.header = (type << 6) | 0x0008;
744 packet.data = data << 24;
745 ret = sisusb_send_packet(sisusb, 10, &packet);
746 packet.header = (type << 6) | 0x0003;
747 packet.address = (addr & ~3) + 4;
748 packet.data = (data >> 8) & 0xffff;
749 ret |= sisusb_send_packet(sisusb, 10, &packet);
755 static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
758 struct sisusb_packet packet;
761 packet.address = addr & ~3;
765 packet.header = (type << 6) | 0x000f;
767 ret = sisusb_send_packet(sisusb, 10, &packet);
770 packet.header = (type << 6) | 0x000e;
771 packet.data = data << 8;
772 ret = sisusb_send_packet(sisusb, 10, &packet);
773 packet.header = (type << 6) | 0x0001;
774 packet.address = (addr & ~3) + 4;
775 packet.data = data >> 24;
776 ret |= sisusb_send_packet(sisusb, 10, &packet);
779 packet.header = (type << 6) | 0x000c;
780 packet.data = data << 16;
781 ret = sisusb_send_packet(sisusb, 10, &packet);
782 packet.header = (type << 6) | 0x0003;
783 packet.address = (addr & ~3) + 4;
784 packet.data = data >> 16;
785 ret |= sisusb_send_packet(sisusb, 10, &packet);
788 packet.header = (type << 6) | 0x0008;
789 packet.data = data << 24;
790 ret = sisusb_send_packet(sisusb, 10, &packet);
791 packet.header = (type << 6) | 0x0007;
792 packet.address = (addr & ~3) + 4;
793 packet.data = data >> 8;
794 ret |= sisusb_send_packet(sisusb, 10, &packet);
800 /* The xxx_bulk routines copy a buffer of variable size. They treat the
801 * buffer as chars, therefore lsb/msb has to be corrected if using the
802 * byte/word/long/etc routines for speed-up
804 * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
805 * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
806 * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
807 * that the data already is in the transfer buffer "sisusb->obuf[index]".
810 static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
811 char *kernbuffer, int length,
812 const char __user *userbuffer, int index,
813 ssize_t *bytes_written)
815 struct sisusb_packet packet;
817 static int msgcount = 0;
818 u8 swap8, fromkern = kernbuffer ? 1 : 0;
820 u32 swap32, flag = (length >> 28) & 1;
823 /* if neither kernbuffer not userbuffer are given, assume
826 if (!fromkern && !userbuffer)
827 kernbuffer = sisusb->obuf[index];
829 (*bytes_written = 0);
831 length &= 0x00ffffff;
839 if (get_user(swap8, (u8 __user *)userbuffer))
842 swap8 = kernbuffer[0];
844 ret = sisusb_write_memio_byte(sisusb,
855 if (get_user(swap16, (u16 __user *)userbuffer))
858 swap16 = *((u16 *)kernbuffer);
860 ret = sisusb_write_memio_word(sisusb,
866 (*bytes_written) += 2;
872 if (copy_from_user(&buf, userbuffer, 3))
875 swap32 = (buf[0] << 16) |
879 swap32 = (buf[2] << 16) |
885 swap32 = (kernbuffer[0] << 16) |
886 (kernbuffer[1] << 8) |
889 swap32 = (kernbuffer[2] << 16) |
890 (kernbuffer[1] << 8) |
894 ret = sisusb_write_memio_24bit(sisusb,
900 (*bytes_written) += 3;
906 if (get_user(swap32, (u32 __user *)userbuffer))
909 swap32 = *((u32 *)kernbuffer);
911 ret = sisusb_write_memio_long(sisusb,
916 (*bytes_written) += 4;
921 if ((length & ~3) > 0x10000) {
923 packet.header = 0x001f;
924 packet.address = 0x000001d4;
926 ret = sisusb_send_bridge_packet(sisusb, 10,
928 packet.header = 0x001f;
929 packet.address = 0x000001d0;
930 packet.data = (length & ~3);
931 ret |= sisusb_send_bridge_packet(sisusb, 10,
933 packet.header = 0x001f;
934 packet.address = 0x000001c0;
935 packet.data = flag | 0x16;
936 ret |= sisusb_send_bridge_packet(sisusb, 10,
939 ret |= sisusb_send_bulk_msg(sisusb,
940 SISUSB_EP_GFX_LBULK_OUT,
943 bytes_written, 0, 1);
944 userbuffer += (*bytes_written);
945 } else if (fromkern) {
946 ret |= sisusb_send_bulk_msg(sisusb,
947 SISUSB_EP_GFX_LBULK_OUT,
950 bytes_written, 0, 1);
951 kernbuffer += (*bytes_written);
953 ret |= sisusb_send_bulk_msg(sisusb,
954 SISUSB_EP_GFX_LBULK_OUT,
957 bytes_written, 0, 1);
958 kernbuffer += ((*bytes_written) &
959 (sisusb->obufsize-1));
964 packet.header = 0x001f;
965 packet.address = 0x00000194;
967 ret = sisusb_send_bridge_packet(sisusb, 10,
969 packet.header = 0x001f;
970 packet.address = 0x00000190;
971 packet.data = (length & ~3);
972 ret |= sisusb_send_bridge_packet(sisusb, 10,
974 if (sisusb->flagb0 != 0x16) {
975 packet.header = 0x001f;
976 packet.address = 0x00000180;
977 packet.data = flag | 0x16;
978 ret |= sisusb_send_bridge_packet(sisusb, 10,
980 sisusb->flagb0 = 0x16;
983 ret |= sisusb_send_bulk_msg(sisusb,
984 SISUSB_EP_GFX_BULK_OUT,
987 bytes_written, 0, 1);
988 userbuffer += (*bytes_written);
989 } else if (fromkern) {
990 ret |= sisusb_send_bulk_msg(sisusb,
991 SISUSB_EP_GFX_BULK_OUT,
994 bytes_written, 0, 1);
995 kernbuffer += (*bytes_written);
997 ret |= sisusb_send_bulk_msg(sisusb,
998 SISUSB_EP_GFX_BULK_OUT,
1001 bytes_written, 0, 1);
1002 kernbuffer += ((*bytes_written) &
1003 (sisusb->obufsize-1));
1010 "sisusbvga[%d]: Wrote %zd of "
1011 "%d bytes, error %d\n",
1012 sisusb->minor, *bytes_written,
1014 else if (msgcount == 500)
1016 "sisusbvga[%d]: Too many errors"
1017 ", logging stopped\n",
1020 addr += (*bytes_written);
1021 length -= (*bytes_written);
1029 return ret ? -EIO : 0;
1032 /* Remember: Read data in packet is in machine-endianess! So for
1033 * byte, word, 24bit, long no endian correction is necessary.
1036 static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1039 struct sisusb_packet packet;
1042 CLEARPACKET(&packet);
1043 packet.header = (1 << (addr & 3)) | (type << 6);
1044 packet.address = addr & ~3;
1045 ret = sisusb_send_packet(sisusb, 6, &packet);
1046 *data = (u8)(packet.data >> ((addr & 3) << 3));
1050 static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1051 u32 addr, u16 *data)
1053 struct sisusb_packet packet;
1056 CLEARPACKET(&packet);
1058 packet.address = addr & ~3;
1062 packet.header = (type << 6) | 0x0003;
1063 ret = sisusb_send_packet(sisusb, 6, &packet);
1064 *data = (u16)(packet.data);
1067 packet.header = (type << 6) | 0x0006;
1068 ret = sisusb_send_packet(sisusb, 6, &packet);
1069 *data = (u16)(packet.data >> 8);
1072 packet.header = (type << 6) | 0x000c;
1073 ret = sisusb_send_packet(sisusb, 6, &packet);
1074 *data = (u16)(packet.data >> 16);
1077 packet.header = (type << 6) | 0x0008;
1078 ret = sisusb_send_packet(sisusb, 6, &packet);
1079 *data = (u16)(packet.data >> 24);
1080 packet.header = (type << 6) | 0x0001;
1081 packet.address = (addr & ~3) + 4;
1082 ret |= sisusb_send_packet(sisusb, 6, &packet);
1083 *data |= (u16)(packet.data << 8);
1089 static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1090 u32 addr, u32 *data)
1092 struct sisusb_packet packet;
1095 packet.address = addr & ~3;
1099 packet.header = (type << 6) | 0x0007;
1100 ret = sisusb_send_packet(sisusb, 6, &packet);
1101 *data = packet.data & 0x00ffffff;
1104 packet.header = (type << 6) | 0x000e;
1105 ret = sisusb_send_packet(sisusb, 6, &packet);
1106 *data = packet.data >> 8;
1109 packet.header = (type << 6) | 0x000c;
1110 ret = sisusb_send_packet(sisusb, 6, &packet);
1111 *data = packet.data >> 16;
1112 packet.header = (type << 6) | 0x0001;
1113 packet.address = (addr & ~3) + 4;
1114 ret |= sisusb_send_packet(sisusb, 6, &packet);
1115 *data |= ((packet.data & 0xff) << 16);
1118 packet.header = (type << 6) | 0x0008;
1119 ret = sisusb_send_packet(sisusb, 6, &packet);
1120 *data = packet.data >> 24;
1121 packet.header = (type << 6) | 0x0003;
1122 packet.address = (addr & ~3) + 4;
1123 ret |= sisusb_send_packet(sisusb, 6, &packet);
1124 *data |= ((packet.data & 0xffff) << 8);
1130 static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1131 u32 addr, u32 *data)
1133 struct sisusb_packet packet;
1136 packet.address = addr & ~3;
1140 packet.header = (type << 6) | 0x000f;
1141 ret = sisusb_send_packet(sisusb, 6, &packet);
1142 *data = packet.data;
1145 packet.header = (type << 6) | 0x000e;
1146 ret = sisusb_send_packet(sisusb, 6, &packet);
1147 *data = packet.data >> 8;
1148 packet.header = (type << 6) | 0x0001;
1149 packet.address = (addr & ~3) + 4;
1150 ret |= sisusb_send_packet(sisusb, 6, &packet);
1151 *data |= (packet.data << 24);
1154 packet.header = (type << 6) | 0x000c;
1155 ret = sisusb_send_packet(sisusb, 6, &packet);
1156 *data = packet.data >> 16;
1157 packet.header = (type << 6) | 0x0003;
1158 packet.address = (addr & ~3) + 4;
1159 ret |= sisusb_send_packet(sisusb, 6, &packet);
1160 *data |= (packet.data << 16);
1163 packet.header = (type << 6) | 0x0008;
1164 ret = sisusb_send_packet(sisusb, 6, &packet);
1165 *data = packet.data >> 24;
1166 packet.header = (type << 6) | 0x0007;
1167 packet.address = (addr & ~3) + 4;
1168 ret |= sisusb_send_packet(sisusb, 6, &packet);
1169 *data |= (packet.data << 8);
1175 static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1176 char *kernbuffer, int length,
1177 char __user *userbuffer, ssize_t *bytes_read)
1186 length &= 0x00ffffff;
1194 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1199 if (put_user(buf[0],
1200 (u8 __user *)userbuffer)) {
1204 kernbuffer[0] = buf[0];
1210 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1215 if (put_user(swap16,
1216 (u16 __user *)userbuffer))
1219 *((u16 *)kernbuffer) = swap16;
1225 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1230 buf[0] = (swap32 >> 16) & 0xff;
1231 buf[1] = (swap32 >> 8) & 0xff;
1232 buf[2] = swap32 & 0xff;
1234 buf[2] = (swap32 >> 16) & 0xff;
1235 buf[1] = (swap32 >> 8) & 0xff;
1236 buf[0] = swap32 & 0xff;
1239 if (copy_to_user(userbuffer, &buf[0], 3))
1242 kernbuffer[0] = buf[0];
1243 kernbuffer[1] = buf[1];
1244 kernbuffer[2] = buf[2];
1250 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1255 if (put_user(swap32,
1256 (u32 __user *)userbuffer))
1261 *((u32 *)kernbuffer) = swap32;
1267 #if 0 /* That does not work, as EP 2 is an OUT EP! */
1269 CLEARPACKET(&packet);
1270 packet.header = 0x001f;
1271 packet.address = 0x000001a0;
1272 packet.data = 0x00000006;
1273 ret |= sisusb_send_bridge_packet(sisusb, 10,
1275 packet.header = 0x001f;
1276 packet.address = 0x000001b0;
1277 packet.data = (length & ~3) | 0x40000000;
1278 ret |= sisusb_send_bridge_packet(sisusb, 10,
1280 packet.header = 0x001f;
1281 packet.address = 0x000001b4;
1283 ret |= sisusb_send_bridge_packet(sisusb, 10,
1285 packet.header = 0x001f;
1286 packet.address = 0x000001a4;
1287 packet.data = 0x00000001;
1288 ret |= sisusb_send_bridge_packet(sisusb, 10,
1291 ret |= sisusb_recv_bulk_msg(sisusb,
1292 SISUSB_EP_GFX_BULK_IN,
1296 if (!ret) userbuffer += (*bytes_read);
1298 ret |= sisusb_recv_bulk_msg(sisusb,
1299 SISUSB_EP_GFX_BULK_IN,
1303 if (!ret) kernbuffer += (*bytes_read);
1305 addr += (*bytes_read);
1306 length -= (*bytes_read);
1317 /* High level: Gfx (indexed) register access */
1319 #ifdef INCL_SISUSB_CON
1321 sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
1323 return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1327 sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
1329 return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1334 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1337 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1338 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1343 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1346 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1347 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1352 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1358 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1359 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1362 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1367 sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1372 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1373 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1375 tmp |= (data & mask);
1376 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1381 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1383 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1387 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1389 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1392 /* Write/read video ram */
1394 #ifdef INCL_SISUSB_CON
1396 sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
1398 return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1402 sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
1404 return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1410 sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
1412 return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1416 sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
1418 return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1424 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
1425 u32 dest, int length, size_t *bytes_written)
1427 return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
1430 #ifdef SISUSBENDIANTEST
1432 sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
1433 u32 src, int length, size_t *bytes_written)
1435 return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
1440 #ifdef SISUSBENDIANTEST
1442 sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
1444 static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
1445 char destbuffer[10];
1449 sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
1451 for(i = 1; i <= 7; i++) {
1452 printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
1453 sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
1454 for(j = 0; j < i; j++) {
1455 printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
1461 /* access pci config registers (reg numbers 0, 4, 8, etc) */
1464 sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1466 struct sisusb_packet packet;
1469 packet.header = 0x008f;
1470 packet.address = regnum | 0x10000;
1472 ret = sisusb_send_packet(sisusb, 10, &packet);
1477 sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1479 struct sisusb_packet packet;
1482 packet.header = 0x008f;
1483 packet.address = (u32)regnum | 0x10000;
1484 ret = sisusb_send_packet(sisusb, 6, &packet);
1485 *data = packet.data;
1489 /* Clear video RAM */
1492 sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1497 if (address < sisusb->vrambase)
1500 if (address >= sisusb->vrambase + sisusb->vramsize)
1503 if (address + length > sisusb->vrambase + sisusb->vramsize)
1504 length = sisusb->vrambase + sisusb->vramsize - address;
1509 /* allocate free buffer/urb and clear the buffer */
1510 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1513 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1515 /* We can write a length > buffer size here. The buffer
1516 * data will simply be re-used (like a ring-buffer).
1518 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1520 /* Free the buffer/urb */
1521 sisusb_free_outbuf(sisusb, i);
1526 /* Initialize the graphics core (return 0 on success)
1527 * This resets the graphics hardware and puts it into
1528 * a defined mode (640x480@60Hz)
1531 #define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1532 #define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1533 #define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
1534 #define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
1535 #define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
1536 #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
1537 #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
1538 #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1539 #define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1540 #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1541 #define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1544 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1549 ret = GETIREG(SISSR, 0x16, &tmp8);
1552 ret |= SETIREG(SISSR, 0x16, tmp8);
1554 ret |= SETIREG(SISSR, 0x16, tmp8);
1557 ret |= SETIREG(SISSR, 0x16, tmp8);
1559 ret |= SETIREG(SISSR, 0x16, tmp8);
1561 ret |= SETIREG(SISSR, 0x16, tmp8);
1563 ret |= SETIREG(SISSR, 0x16, tmp8);
1565 ret |= SETIREG(SISSR, 0x16, tmp8);
1567 ret |= SETIREG(SISSR, 0x16, tmp8);
1569 ret |= SETIREG(SISSR, 0x16, tmp8);
1575 sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1578 u8 ramtype, done = 0;
1580 u32 ramptr = SISUSB_PCI_MEMBASE;
1582 ret = GETIREG(SISSR, 0x3a, &ramtype);
1585 ret |= SETIREG(SISSR, 0x13, 0x00);
1588 ret |= SETIREG(SISSR, 0x14, 0x12);
1589 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1591 ret |= SETIREG(SISSR, 0x14, 0x02);
1594 ret |= sisusb_triggersr16(sisusb, ramtype);
1595 ret |= WRITEL(ramptr + 0, 0x01234567);
1596 ret |= WRITEL(ramptr + 4, 0x456789ab);
1597 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1598 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1599 ret |= WRITEL(ramptr + 16, 0x55555555);
1600 ret |= WRITEL(ramptr + 20, 0x55555555);
1601 ret |= WRITEL(ramptr + 24, 0xffffffff);
1602 ret |= WRITEL(ramptr + 28, 0xffffffff);
1603 ret |= READL(ramptr + 0, &t0);
1604 ret |= READL(ramptr + 4, &t1);
1605 ret |= READL(ramptr + 8, &t2);
1606 ret |= READL(ramptr + 12, &t3);
1610 *chab = 0; *bw = 64;
1612 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1613 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1614 *chab = 0; *bw = 64;
1615 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1618 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1619 *chab = 1; *bw = 64;
1620 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1622 ret |= sisusb_triggersr16(sisusb, ramtype);
1623 ret |= WRITEL(ramptr + 0, 0x89abcdef);
1624 ret |= WRITEL(ramptr + 4, 0xcdef0123);
1625 ret |= WRITEL(ramptr + 8, 0x55555555);
1626 ret |= WRITEL(ramptr + 12, 0x55555555);
1627 ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1628 ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1629 ret |= READL(ramptr + 4, &t1);
1631 if (t1 != 0xcdef0123) {
1633 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1639 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1643 if (t1 == 0x456789ab) {
1644 if (t0 == 0x01234567) {
1645 *chab = 0; *bw = 64;
1649 if (t0 == 0x01234567) {
1650 *chab = 0; *bw = 32;
1651 ret |= SETIREG(SISSR, 0x14, 0x00);
1657 ret |= SETIREG(SISSR, 0x14, 0x03);
1658 ret |= sisusb_triggersr16(sisusb, ramtype);
1660 ret |= WRITEL(ramptr + 0, 0x01234567);
1661 ret |= WRITEL(ramptr + 4, 0x456789ab);
1662 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1663 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1664 ret |= WRITEL(ramptr + 16, 0x55555555);
1665 ret |= WRITEL(ramptr + 20, 0x55555555);
1666 ret |= WRITEL(ramptr + 24, 0xffffffff);
1667 ret |= WRITEL(ramptr + 28, 0xffffffff);
1668 ret |= READL(ramptr + 0, &t0);
1669 ret |= READL(ramptr + 4, &t1);
1671 if (t1 == 0x456789ab) {
1672 if (t0 == 0x01234567) {
1673 *chab = 1; *bw = 64;
1677 if (t0 == 0x01234567) {
1678 *chab = 1; *bw = 32;
1679 ret |= SETIREG(SISSR, 0x14, 0x01);
1688 sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1691 u32 ramptr = SISUSB_PCI_MEMBASE;
1692 u8 tmp1, tmp2, i, j;
1694 ret |= WRITEB(ramptr, 0xaa);
1695 ret |= WRITEB(ramptr + 16, 0x55);
1696 ret |= READB(ramptr, &tmp1);
1697 ret |= READB(ramptr + 16, &tmp2);
1698 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1699 for (i = 0, j = 16; i < 2; i++, j += 16) {
1700 ret |= GETIREG(SISSR, 0x21, &tmp1);
1701 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1702 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1703 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1704 ret |= SETIREG(SISSR, 0x21, tmp1);
1705 ret |= WRITEB(ramptr + 16 + j, j);
1706 ret |= READB(ramptr + 16 + j, &tmp1);
1708 ret |= WRITEB(ramptr + j, j);
1717 sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1718 u8 rankno, u8 chab, const u8 dramtype[][5],
1721 int ret = 0, ranksize;
1726 if ((rankno == 2) && (dramtype[index][0] == 2))
1729 ranksize = dramtype[index][3] / 2 * bw / 32;
1731 if ((ranksize * rankno) > 128)
1735 while ((ranksize >>= 1) > 0) tmp += 0x10;
1736 tmp |= ((rankno - 1) << 2);
1737 tmp |= ((bw / 64) & 0x02);
1738 tmp |= (chab & 0x01);
1740 ret = SETIREG(SISSR, 0x14, tmp);
1741 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1749 sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1756 for (i = 0, j = 0; i < testn; i++) {
1757 ret |= WRITEL(sisusb->vrambase + j, j);
1761 for (i = 0, j = 0; i < testn; i++) {
1762 ret |= READL(sisusb->vrambase + j, &tmp);
1763 if (tmp != j) return ret;
1772 sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1773 int idx, int bw, const u8 rtype[][5])
1775 int ret = 0, i, i2ret;
1780 for (i = rankno; i >= 1; i--) {
1781 inc = 1 << (rtype[idx][2] +
1785 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1790 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1791 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1795 inc = 1 << (10 + bw / 64);
1796 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1805 sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1808 int ret = 0, i2ret = 0, i, j;
1809 static const u8 sdramtype[13][5] = {
1810 { 2, 12, 9, 64, 0x35 },
1811 { 1, 13, 9, 64, 0x44 },
1812 { 2, 12, 8, 32, 0x31 },
1813 { 2, 11, 9, 32, 0x25 },
1814 { 1, 12, 9, 32, 0x34 },
1815 { 1, 13, 8, 32, 0x40 },
1816 { 2, 11, 8, 16, 0x21 },
1817 { 1, 12, 8, 16, 0x30 },
1818 { 1, 11, 9, 16, 0x24 },
1819 { 1, 11, 8, 8, 0x20 },
1820 { 2, 9, 8, 4, 0x01 },
1821 { 1, 10, 8, 4, 0x10 },
1822 { 1, 9, 8, 2, 0x00 }
1825 *iret = 1; /* error */
1827 for (i = 0; i < 13; i++) {
1828 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1829 for (j = 2; j > 0; j--) {
1830 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1831 chab, sdramtype, bw);
1835 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1838 *iret = 0; /* ram size found */
1848 sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1852 int i, length, modex, modey, bpp;
1854 modex = 640; modey = 480; bpp = 2;
1856 address = sisusb->vrambase; /* Clear video ram */
1859 length = sisusb->vramsize;
1861 length = modex * bpp * modey;
1863 ret = sisusb_clear_vram(sisusb, address, length);
1865 if (!ret && drwfr) {
1866 for (i = 0; i < modex; i++) {
1867 address = sisusb->vrambase + (i * bpp);
1868 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1870 address += (modex * (modey-1) * bpp);
1871 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1874 for (i = 0; i < modey; i++) {
1875 address = sisusb->vrambase + ((i * modex) * bpp);
1876 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1878 address += ((modex - 1) * bpp);
1879 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1888 sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1890 int ret = 0, i, j, modex, modey, bpp, du;
1891 u8 sr31, cr63, tmp8;
1892 static const char attrdata[] = {
1893 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1894 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1897 static const char crtcrdata[] = {
1898 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1899 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1900 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1903 static const char grcdata[] = {
1904 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1907 static const char crtcdata[] = {
1908 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1909 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1913 modex = 640; modey = 480; bpp = 2;
1915 GETIREG(SISSR, 0x31, &sr31);
1916 GETIREG(SISCR, 0x63, &cr63);
1917 SETIREGOR(SISSR, 0x01, 0x20);
1918 SETIREG(SISCR, 0x63, cr63 & 0xbf);
1919 SETIREGOR(SISCR, 0x17, 0x80);
1920 SETIREGOR(SISSR, 0x1f, 0x04);
1921 SETIREGAND(SISSR, 0x07, 0xfb);
1922 SETIREG(SISSR, 0x00, 0x03); /* seq */
1923 SETIREG(SISSR, 0x01, 0x21);
1924 SETIREG(SISSR, 0x02, 0x0f);
1925 SETIREG(SISSR, 0x03, 0x00);
1926 SETIREG(SISSR, 0x04, 0x0e);
1927 SETREG(SISMISCW, 0x23); /* misc */
1928 for (i = 0; i <= 0x18; i++) { /* crtc */
1929 SETIREG(SISCR, i, crtcrdata[i]);
1931 for (i = 0; i <= 0x13; i++) { /* att */
1932 GETREG(SISINPSTAT, &tmp8);
1934 SETREG(SISAR, attrdata[i]);
1936 GETREG(SISINPSTAT, &tmp8);
1937 SETREG(SISAR, 0x14);
1938 SETREG(SISAR, 0x00);
1939 GETREG(SISINPSTAT, &tmp8);
1940 SETREG(SISAR, 0x20);
1941 GETREG(SISINPSTAT, &tmp8);
1942 for (i = 0; i <= 0x08; i++) { /* grc */
1943 SETIREG(SISGR, i, grcdata[i]);
1945 SETIREGAND(SISGR, 0x05, 0xbf);
1946 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1947 SETIREG(SISSR, i, 0x00);
1949 SETIREGAND(SISSR, 0x37, 0xfe);
1950 SETREG(SISMISCW, 0xef); /* sync */
1951 SETIREG(SISCR, 0x11, 0x00); /* crtc */
1952 for (j = 0x00, i = 0; i <= 7; i++, j++) {
1953 SETIREG(SISCR, j, crtcdata[i]);
1955 for (j = 0x10; i <= 10; i++, j++) {
1956 SETIREG(SISCR, j, crtcdata[i]);
1958 for (j = 0x15; i <= 12; i++, j++) {
1959 SETIREG(SISCR, j, crtcdata[i]);
1961 for (j = 0x0A; i <= 15; i++, j++) {
1962 SETIREG(SISSR, j, crtcdata[i]);
1964 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
1965 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
1966 SETIREG(SISCR, 0x14, 0x4f);
1967 du = (modex / 16) * (bpp * 2); /* offset/pitch */
1968 if (modex % 16) du += bpp;
1969 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
1970 SETIREG(SISCR, 0x13, (du & 0xff));
1973 if (du & 0xff) tmp8++;
1974 SETIREG(SISSR, 0x10, tmp8);
1975 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
1976 SETIREG(SISSR, 0x2b, 0x1b);
1977 SETIREG(SISSR, 0x2c, 0xe1);
1978 SETIREG(SISSR, 0x2d, 0x01);
1979 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
1980 SETIREG(SISSR, 0x08, 0xae);
1981 SETIREGAND(SISSR, 0x09, 0xf0);
1982 SETIREG(SISSR, 0x08, 0x34);
1983 SETIREGOR(SISSR, 0x3d, 0x01);
1984 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
1985 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
1986 SETIREG(SISCR, 0x19, 0x00);
1987 SETIREGAND(SISCR, 0x1a, 0xfc);
1988 SETIREGAND(SISSR, 0x0f, 0xb7);
1989 SETIREGAND(SISSR, 0x31, 0xfb);
1990 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
1991 SETIREGAND(SISSR, 0x32, 0xf3);
1992 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
1993 SETIREG(SISCR, 0x52, 0x6c);
1995 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
1996 SETIREG(SISCR, 0x0c, 0x00);
1997 SETIREG(SISSR, 0x0d, 0x00);
1998 SETIREGAND(SISSR, 0x37, 0xfe);
2000 SETIREG(SISCR, 0x32, 0x20);
2001 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
2002 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
2003 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
2006 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
2007 SETIREGOR(SISSR, 0x1e, 0x5a);
2009 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
2010 SETIREG(SISSR, 0x27, 0x1f);
2011 SETIREG(SISSR, 0x26, 0x00);
2014 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
2020 sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
2022 int ret = 0, i, j, bw, chab, iret, retry = 3;
2025 static const char mclktable[] = {
2026 0x3b, 0x22, 0x01, 143,
2027 0x3b, 0x22, 0x01, 143,
2028 0x3b, 0x22, 0x01, 143,
2029 0x3b, 0x22, 0x01, 143
2031 static const char eclktable[] = {
2032 0x3b, 0x22, 0x01, 143,
2033 0x3b, 0x22, 0x01, 143,
2034 0x3b, 0x22, 0x01, 143,
2035 0x3b, 0x22, 0x01, 143
2037 static const char ramtypetable1[] = {
2038 0x00, 0x04, 0x60, 0x60,
2039 0x0f, 0x0f, 0x1f, 0x1f,
2040 0xba, 0xba, 0xba, 0xba,
2041 0xa9, 0xa9, 0xac, 0xac,
2042 0xa0, 0xa0, 0xa0, 0xa8,
2043 0x00, 0x00, 0x02, 0x02,
2044 0x30, 0x30, 0x40, 0x40
2046 static const char ramtypetable2[] = {
2047 0x77, 0x77, 0x44, 0x44,
2048 0x77, 0x77, 0x44, 0x44,
2049 0x00, 0x00, 0x00, 0x00,
2050 0x5b, 0x5b, 0xab, 0xab,
2051 0x00, 0x00, 0xf0, 0xf8
2057 ret = GETREG(SISVGAEN, &tmp8);
2058 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
2060 /* Enable GPU access to VRAM */
2061 ret |= GETREG(SISMISCR, &tmp8);
2062 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
2066 /* Reset registers */
2067 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
2068 ret |= SETIREG(SISSR, 0x05, 0x86);
2069 ret |= SETIREGOR(SISSR, 0x20, 0x01);
2071 ret |= SETREG(SISMISCW, 0x67);
2073 for (i = 0x06; i <= 0x1f; i++) {
2074 ret |= SETIREG(SISSR, i, 0x00);
2076 for (i = 0x21; i <= 0x27; i++) {
2077 ret |= SETIREG(SISSR, i, 0x00);
2079 for (i = 0x31; i <= 0x3d; i++) {
2080 ret |= SETIREG(SISSR, i, 0x00);
2082 for (i = 0x12; i <= 0x1b; i++) {
2083 ret |= SETIREG(SISSR, i, 0x00);
2085 for (i = 0x79; i <= 0x7c; i++) {
2086 ret |= SETIREG(SISCR, i, 0x00);
2091 ret |= SETIREG(SISCR, 0x63, 0x80);
2093 ret |= GETIREG(SISSR, 0x3a, &ramtype);
2096 ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
2097 ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
2098 ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
2100 ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
2101 ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
2102 ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
2104 ret |= SETIREG(SISSR, 0x07, 0x18);
2105 ret |= SETIREG(SISSR, 0x11, 0x0f);
2109 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2110 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2112 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2113 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2116 ret |= SETIREG(SISCR, 0x49, 0xaa);
2118 ret |= SETIREG(SISSR, 0x1f, 0x00);
2119 ret |= SETIREG(SISSR, 0x20, 0xa0);
2120 ret |= SETIREG(SISSR, 0x23, 0xf6);
2121 ret |= SETIREG(SISSR, 0x24, 0x0d);
2122 ret |= SETIREG(SISSR, 0x25, 0x33);
2124 ret |= SETIREG(SISSR, 0x11, 0x0f);
2126 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2128 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2132 ret |= SETIREG(SISPART1, 0x00, 0x00);
2134 ret |= GETIREG(SISSR, 0x13, &tmp8);
2137 ret |= SETIREG(SISPART1, 0x02, 0x00);
2138 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2140 ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
2141 tmp32 &= 0x00f00000;
2142 tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
2143 ret |= SETIREG(SISSR, 0x25, tmp8);
2144 tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
2145 ret |= SETIREG(SISCR, 0x49, tmp8);
2147 ret |= SETIREG(SISSR, 0x27, 0x1f);
2148 ret |= SETIREG(SISSR, 0x31, 0x00);
2149 ret |= SETIREG(SISSR, 0x32, 0x11);
2150 ret |= SETIREG(SISSR, 0x33, 0x00);
2154 ret |= SETIREG(SISCR, 0x83, 0x00);
2156 ret |= sisusb_set_default_mode(sisusb, 0);
2158 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2159 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2160 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2162 ret |= sisusb_triggersr16(sisusb, ramtype);
2164 /* Disable refresh */
2165 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2166 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2168 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2169 ret |= sisusb_verify_mclk(sisusb);
2172 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2174 printk(KERN_ERR "sisusbvga[%d]: RAM size "
2175 "detection failed, "
2176 "assuming 8MB video RAM\n",
2178 ret |= SETIREG(SISSR,0x14,0x31);
2182 printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
2183 "assuming 8MB video RAM\n",
2185 ret |= SETIREG(SISSR,0x14,0x31);
2189 /* Enable refresh */
2190 ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
2191 ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
2192 ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
2194 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2196 ret |= SETIREG(SISSR, 0x22, 0xfb);
2197 ret |= SETIREG(SISSR, 0x21, 0xa5);
2217 sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2219 u8 tmp8, tmp82, ramtype;
2221 char *ramtypetext1 = NULL;
2222 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2223 "DDR SDRAM", "DDR SGRAM" };
2224 static const int busSDR[4] = {64, 64, 128, 128};
2225 static const int busDDR[4] = {32, 32, 64, 64};
2226 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2228 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2229 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2230 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2231 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2233 switch ((tmp8 >> 2) & 0x03) {
2234 case 0: ramtypetext1 = "1 ch/1 r";
2238 bw = busSDR[(tmp8 & 0x03)];
2241 case 1: ramtypetext1 = "1 ch/2 r";
2242 sisusb->vramsize <<= 1;
2243 bw = busSDR[(tmp8 & 0x03)];
2245 case 2: ramtypetext1 = "asymmeric";
2246 sisusb->vramsize += sisusb->vramsize/2;
2247 bw = busDDRA[(tmp8 & 0x03)];
2249 case 3: ramtypetext1 = "2 channel";
2250 sisusb->vramsize <<= 1;
2251 bw = busDDR[(tmp8 & 0x03)];
2255 printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2256 sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
2257 ramtypetext2[ramtype], bw);
2261 sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2263 struct sisusb_packet packet;
2268 packet.header = 0x001f;
2269 packet.address = 0x00000324;
2270 packet.data = 0x00000004;
2271 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2273 packet.header = 0x001f;
2274 packet.address = 0x00000364;
2275 packet.data = 0x00000004;
2276 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2278 packet.header = 0x001f;
2279 packet.address = 0x00000384;
2280 packet.data = 0x00000004;
2281 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2283 packet.header = 0x001f;
2284 packet.address = 0x00000100;
2285 packet.data = 0x00000700;
2286 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2288 packet.header = 0x000f;
2289 packet.address = 0x00000004;
2290 ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2291 packet.data |= 0x17;
2292 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2294 /* Init BAR 0 (VRAM) */
2295 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2296 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2297 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2299 tmp32 |= SISUSB_PCI_MEMBASE;
2300 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2302 /* Init BAR 1 (MMIO) */
2303 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2304 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2305 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2307 tmp32 |= SISUSB_PCI_MMIOBASE;
2308 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2310 /* Init BAR 2 (i/o ports) */
2311 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2312 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2313 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2315 tmp32 |= SISUSB_PCI_IOPORTBASE;
2316 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2318 /* Enable memory and i/o access */
2319 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2321 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2324 /* Some further magic */
2325 packet.header = 0x001f;
2326 packet.address = 0x00000050;
2327 packet.data = 0x000000ff;
2328 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2334 /* Initialize the graphics device (return 0 on success)
2335 * This initializes the net2280 as well as the PCI registers
2336 * of the graphics board.
2340 sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2342 int ret = 0, test = 0;
2345 if (sisusb->devinit == 1) {
2346 /* Read PCI BARs and see if they have been set up */
2347 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2348 if (ret) return ret;
2349 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
2351 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2352 if (ret) return ret;
2353 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2355 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2356 if (ret) return ret;
2357 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2360 /* No? So reset the device */
2361 if ((sisusb->devinit == 0) || (test != 3)) {
2363 ret |= sisusb_do_init_gfxdevice(sisusb);
2366 sisusb->devinit = 1;
2370 if (sisusb->devinit) {
2371 /* Initialize the graphics core */
2372 if (sisusb_init_gfxcore(sisusb) == 0) {
2373 sisusb->gfxinit = 1;
2374 sisusb_get_ramconfig(sisusb);
2375 ret |= sisusb_set_default_mode(sisusb, 1);
2376 ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2384 #ifdef INCL_SISUSB_CON
2386 /* Set up default text mode:
2387 - Set text mode (0x03)
2388 - Upload default font
2389 - Upload user font (if available)
2393 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
2395 int ret = 0, slot = sisusb->font_slot, i;
2396 const struct font_desc *myfont;
2400 static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
2401 static const char bootlogo[] = "(o_ //\\ V_/_";
2403 /* sisusb->lock is down */
2405 if (!sisusb->SiS_Pr)
2408 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2409 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2412 SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
2414 if (!(myfont = find_font("VGA8x16")))
2417 if (!(tempbuf = vmalloc(8192)))
2420 for (i = 0; i < 256; i++)
2421 memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
2423 /* Upload default font */
2424 ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
2428 /* Upload user font (and reset current slot) */
2429 if (sisusb->font_backup) {
2430 ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
2431 8192, sisusb->font_backup_512, 1, NULL,
2432 sisusb->font_backup_height, 0);
2434 sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
2438 if (init && !sisusb->scrbuf) {
2440 if ((tempbuf = vmalloc(8192))) {
2443 tempbufb = (u16 *)tempbuf;
2445 *(tempbufb++) = 0x0720;
2448 tempbufb = (u16 *)tempbuf;
2449 while (bootlogo[i]) {
2450 *(tempbufb++) = 0x0700 | bootlogo[i++];
2456 tempbufb = (u16 *)tempbuf + 6;
2457 while (bootstring[i])
2458 *(tempbufb++) = 0x0700 | bootstring[i++];
2460 ret |= sisusb_copy_memory(sisusb, tempbuf,
2461 sisusb->vrambase, 8192, &written);
2467 } else if (sisusb->scrbuf) {
2469 ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
2470 sisusb->vrambase, sisusb->scrbuf_size, &written);
2474 if (sisusb->sisusb_cursor_size_from >= 0 &&
2475 sisusb->sisusb_cursor_size_to >= 0) {
2476 sisusb_setidxreg(sisusb, SISCR, 0x0a,
2477 sisusb->sisusb_cursor_size_from);
2478 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
2479 sisusb->sisusb_cursor_size_to);
2481 sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
2482 sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
2483 sisusb->sisusb_cursor_size_to = -1;
2486 slot = sisusb->sisusb_cursor_loc;
2487 if(slot < 0) slot = 0;
2489 sisusb->sisusb_cursor_loc = -1;
2490 sisusb->bad_cursor_pos = 1;
2492 sisusb_set_cursor(sisusb, slot);
2494 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
2495 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
2497 sisusb->textmodedestroyed = 0;
2499 /* sisusb->lock is down */
2509 sisusb_open(struct inode *inode, struct file *file)
2511 struct sisusb_usb_data *sisusb;
2512 struct usb_interface *interface;
2513 int subminor = iminor(inode);
2515 mutex_lock(&disconnect_mutex);
2517 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
2518 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
2520 mutex_unlock(&disconnect_mutex);
2524 if (!(sisusb = usb_get_intfdata(interface))) {
2525 mutex_unlock(&disconnect_mutex);
2529 mutex_lock(&sisusb->lock);
2531 if (!sisusb->present || !sisusb->ready) {
2532 mutex_unlock(&sisusb->lock);
2533 mutex_unlock(&disconnect_mutex);
2537 if (sisusb->isopen) {
2538 mutex_unlock(&sisusb->lock);
2539 mutex_unlock(&disconnect_mutex);
2543 if (!sisusb->devinit) {
2544 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2545 if (sisusb_init_gfxdevice(sisusb, 0)) {
2546 mutex_unlock(&sisusb->lock);
2547 mutex_unlock(&disconnect_mutex);
2549 "sisusbvga[%d]: Failed to initialize "
2555 mutex_unlock(&sisusb->lock);
2556 mutex_unlock(&disconnect_mutex);
2558 "sisusbvga[%d]: Device not attached to "
2565 /* Increment usage count for our sisusb */
2566 kref_get(&sisusb->kref);
2570 file->private_data = sisusb;
2572 mutex_unlock(&sisusb->lock);
2574 mutex_unlock(&disconnect_mutex);
2580 sisusb_delete(struct kref *kref)
2582 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2587 if (sisusb->sisusb_dev)
2588 usb_put_dev(sisusb->sisusb_dev);
2590 sisusb->sisusb_dev = NULL;
2591 sisusb_free_buffers(sisusb);
2592 sisusb_free_urbs(sisusb);
2593 #ifdef INCL_SISUSB_CON
2594 kfree(sisusb->SiS_Pr);
2600 sisusb_release(struct inode *inode, struct file *file)
2602 struct sisusb_usb_data *sisusb;
2605 mutex_lock(&disconnect_mutex);
2607 if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
2608 mutex_unlock(&disconnect_mutex);
2612 mutex_lock(&sisusb->lock);
2614 if (sisusb->present) {
2615 /* Wait for all URBs to finish if device still present */
2616 if (!sisusb_wait_all_out_complete(sisusb))
2617 sisusb_kill_all_busy(sisusb);
2620 myminor = sisusb->minor;
2623 file->private_data = NULL;
2625 mutex_unlock(&sisusb->lock);
2627 /* decrement the usage count on our device */
2628 kref_put(&sisusb->kref, sisusb_delete);
2630 mutex_unlock(&disconnect_mutex);
2636 sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2638 struct sisusb_usb_data *sisusb;
2639 ssize_t bytes_read = 0;
2645 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2648 mutex_lock(&sisusb->lock);
2651 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2652 mutex_unlock(&sisusb->lock);
2656 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2657 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2660 SISUSB_PCI_PSEUDO_IOPORTBASE +
2661 SISUSB_PCI_IOPORTBASE;
2664 * Byte, word and long(32) can be read. As this
2665 * emulates inX instructions, the data returned is
2666 * in machine-endianness.
2671 if (sisusb_read_memio_byte(sisusb,
2675 else if (put_user(buf8, (u8 __user *)buffer))
2683 if (sisusb_read_memio_word(sisusb,
2687 else if (put_user(buf16, (u16 __user *)buffer))
2695 if (sisusb_read_memio_long(sisusb,
2699 else if (put_user(buf32, (u32 __user *)buffer))
2711 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2712 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2715 SISUSB_PCI_PSEUDO_MEMBASE +
2719 * Remember: Data delivered is never endian-corrected
2721 errno = sisusb_read_mem_bulk(sisusb, address,
2722 NULL, count, buffer, &bytes_read);
2727 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2728 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2731 SISUSB_PCI_PSEUDO_MMIOBASE +
2732 SISUSB_PCI_MMIOBASE;
2735 * Remember: Data delivered is never endian-corrected
2737 errno = sisusb_read_mem_bulk(sisusb, address,
2738 NULL, count, buffer, &bytes_read);
2743 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2744 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2747 mutex_unlock(&sisusb->lock);
2751 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2753 /* Read PCI config register
2754 * Return value delivered in machine endianness.
2756 if (sisusb_read_pci_config(sisusb, address, &buf32))
2758 else if (put_user(buf32, (u32 __user *)buffer))
2769 (*ppos) += bytes_read;
2771 mutex_unlock(&sisusb->lock);
2773 return errno ? errno : bytes_read;
2777 sisusb_write(struct file *file, const char __user *buffer, size_t count,
2780 struct sisusb_usb_data *sisusb;
2782 ssize_t bytes_written = 0;
2787 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2790 mutex_lock(&sisusb->lock);
2793 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2794 mutex_unlock(&sisusb->lock);
2798 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2799 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2802 SISUSB_PCI_PSEUDO_IOPORTBASE +
2803 SISUSB_PCI_IOPORTBASE;
2806 * Byte, word and long(32) can be written. As this
2807 * emulates outX instructions, the data is expected
2808 * in machine-endianness.
2813 if (get_user(buf8, (u8 __user *)buffer))
2815 else if (sisusb_write_memio_byte(sisusb,
2825 if (get_user(buf16, (u16 __user *)buffer))
2827 else if (sisusb_write_memio_word(sisusb,
2837 if (get_user(buf32, (u32 __user *)buffer))
2839 else if (sisusb_write_memio_long(sisusb,
2852 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2853 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2856 SISUSB_PCI_PSEUDO_MEMBASE +
2860 * Buffer is copied 1:1, therefore, on big-endian
2861 * machines, the data must be swapped by userland
2862 * in advance (if applicable; no swapping in 8bpp
2863 * mode or if YUV data is being transferred).
2865 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2866 count, buffer, 0, &bytes_written);
2869 errno = bytes_written;
2871 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2872 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2875 SISUSB_PCI_PSEUDO_MMIOBASE +
2876 SISUSB_PCI_MMIOBASE;
2879 * Buffer is copied 1:1, therefore, on big-endian
2880 * machines, the data must be swapped by userland
2883 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2884 count, buffer, 0, &bytes_written);
2887 errno = bytes_written;
2889 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2890 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2893 mutex_unlock(&sisusb->lock);
2897 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2899 /* Write PCI config register.
2900 * Given value expected in machine endianness.
2902 if (get_user(buf32, (u32 __user *)buffer))
2904 else if (sisusb_write_pci_config(sisusb, address, buf32))
2917 (*ppos) += bytes_written;
2919 mutex_unlock(&sisusb->lock);
2921 return errno ? errno : bytes_written;
2925 sisusb_lseek(struct file *file, loff_t offset, int orig)
2927 struct sisusb_usb_data *sisusb;
2930 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2933 mutex_lock(&sisusb->lock);
2936 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2937 mutex_unlock(&sisusb->lock);
2943 file->f_pos = offset;
2945 /* never negative, no force_successful_syscall needed */
2948 file->f_pos += offset;
2950 /* never negative, no force_successful_syscall needed */
2953 /* seeking relative to "end of file" is not supported */
2957 mutex_unlock(&sisusb->lock);
2962 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2965 int retval, port, length;
2968 /* All our commands require the device
2969 * to be initialized.
2971 if (!sisusb->devinit)
2975 SISUSB_PCI_PSEUDO_IOPORTBASE +
2976 SISUSB_PCI_IOPORTBASE;
2978 switch (y->operation) {
2980 retval = sisusb_getidxreg(sisusb, port,
2981 y->data0, &y->data1);
2983 if (copy_to_user((void __user *)arg, y,
2990 retval = sisusb_setidxreg(sisusb, port,
2991 y->data0, y->data1);
2995 retval = sisusb_setidxregor(sisusb, port,
2996 y->data0, y->data1);
3000 retval = sisusb_setidxregand(sisusb, port,
3001 y->data0, y->data1);
3004 case SUCMD_SETANDOR:
3005 retval = sisusb_setidxregandor(sisusb, port,
3006 y->data0, y->data1, y->data2);
3010 retval = sisusb_setidxregmask(sisusb, port,
3011 y->data0, y->data1, y->data2);
3015 /* Gfx core must be initialized */
3016 if (!sisusb->gfxinit)
3019 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
3020 address = y->data3 -
3021 SISUSB_PCI_PSEUDO_MEMBASE +
3023 retval = sisusb_clear_vram(sisusb, address, length);
3026 case SUCMD_HANDLETEXTMODE:
3028 #ifdef INCL_SISUSB_CON
3029 /* Gfx core must be initialized, SiS_Pr must exist */
3030 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3035 retval = sisusb_reset_text_mode(sisusb, 0);
3038 sisusb->textmodedestroyed = 1;
3044 #ifdef INCL_SISUSB_CON
3046 /* Gfx core must be initialized, SiS_Pr must exist */
3047 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3052 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3053 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3055 if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
3060 case SUCMD_SETVESAMODE:
3061 /* Gfx core must be initialized, SiS_Pr must exist */
3062 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3067 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3068 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3070 if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
3087 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
3090 struct sisusb_usb_data *sisusb;
3091 struct sisusb_info x;
3092 struct sisusb_command y;
3094 u32 __user *argp = (u32 __user *)arg;
3096 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
3099 mutex_lock(&sisusb->lock);
3102 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
3109 case SISUSB_GET_CONFIG_SIZE:
3111 if (put_user(sizeof(x), argp))
3116 case SISUSB_GET_CONFIG:
3118 x.sisusb_id = SISUSB_ID;
3119 x.sisusb_version = SISUSB_VERSION;
3120 x.sisusb_revision = SISUSB_REVISION;
3121 x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
3122 x.sisusb_gfxinit = sisusb->gfxinit;
3123 x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
3124 x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
3125 x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
3126 x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
3127 x.sisusb_vramsize = sisusb->vramsize;
3128 x.sisusb_minor = sisusb->minor;
3129 x.sisusb_fbdevactive= 0;
3130 #ifdef INCL_SISUSB_CON
3131 x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
3133 x.sisusb_conactive = 0;
3136 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
3141 case SISUSB_COMMAND:
3143 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
3146 retval = sisusb_handle_command(sisusb, &y, arg);
3156 mutex_unlock(&sisusb->lock);
3160 #ifdef SISUSB_NEW_CONFIG_COMPAT
3162 sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
3167 case SISUSB_GET_CONFIG_SIZE:
3168 case SISUSB_GET_CONFIG:
3169 case SISUSB_COMMAND:
3171 retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
3176 return -ENOIOCTLCMD;
3181 static const struct file_operations usb_sisusb_fops = {
3182 .owner = THIS_MODULE,
3183 .open = sisusb_open,
3184 .release = sisusb_release,
3185 .read = sisusb_read,
3186 .write = sisusb_write,
3187 .llseek = sisusb_lseek,
3188 #ifdef SISUSB_NEW_CONFIG_COMPAT
3189 .compat_ioctl = sisusb_compat_ioctl,
3191 .ioctl = sisusb_ioctl
3194 static struct usb_class_driver usb_sisusb_class = {
3195 .name = "sisusbvga%d",
3196 .fops = &usb_sisusb_fops,
3197 .minor_base = SISUSB_MINOR
3200 static int sisusb_probe(struct usb_interface *intf,
3201 const struct usb_device_id *id)
3203 struct usb_device *dev = interface_to_usbdev(intf);
3204 struct sisusb_usb_data *sisusb;
3206 const char *memfail =
3208 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
3210 printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
3213 /* Allocate memory for our private */
3214 if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
3216 "sisusb: Failed to allocate memory for private data\n");
3219 kref_init(&sisusb->kref);
3221 mutex_init(&(sisusb->lock));
3223 /* Register device */
3224 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
3226 "sisusb: Failed to get a minor for device %d\n",
3232 sisusb->sisusb_dev = dev;
3233 sisusb->minor = intf->minor;
3234 sisusb->vrambase = SISUSB_PCI_MEMBASE;
3235 sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
3236 sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
3237 sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
3238 /* Everything else is zero */
3240 /* Allocate buffers */
3241 sisusb->ibufsize = SISUSB_IBUF_SIZE;
3242 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
3243 GFP_KERNEL, &sisusb->transfer_dma_in))) {
3244 printk(memfail, "input", sisusb->minor);
3249 sisusb->numobufs = 0;
3250 sisusb->obufsize = SISUSB_OBUF_SIZE;
3251 for (i = 0; i < NUMOBUFS; i++) {
3252 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
3254 &sisusb->transfer_dma_out[i]))) {
3256 printk(memfail, "output", sisusb->minor);
3267 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
3269 "sisusbvga[%d]: Failed to allocate URBs\n",
3274 sisusb->completein = 1;
3276 for (i = 0; i < sisusb->numobufs; i++) {
3277 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
3279 "sisusbvga[%d]: Failed to allocate URBs\n",
3284 sisusb->urbout_context[i].sisusb = (void *)sisusb;
3285 sisusb->urbout_context[i].urbindex = i;
3286 sisusb->urbstatus[i] = 0;
3289 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
3290 sisusb->minor, sisusb->numobufs);
3292 #ifdef INCL_SISUSB_CON
3293 /* Allocate our SiS_Pr */
3294 if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
3296 "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
3301 /* Do remaining init stuff */
3303 init_waitqueue_head(&sisusb->wait_q);
3305 usb_set_intfdata(intf, sisusb);
3307 usb_get_dev(sisusb->sisusb_dev);
3309 sisusb->present = 1;
3311 #ifdef SISUSB_OLD_CONFIG_COMPAT
3314 /* Our ioctls are all "32/64bit compatible" */
3315 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3316 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3317 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3320 "sisusbvga[%d]: Error registering ioctl32 "
3324 sisusb->ioctl32registered = 1;
3328 if (dev->speed == USB_SPEED_HIGH) {
3330 #ifdef INCL_SISUSB_CON
3331 if (sisusb_first_vc > 0 &&
3332 sisusb_last_vc > 0 &&
3333 sisusb_first_vc <= sisusb_last_vc &&
3334 sisusb_last_vc <= MAX_NR_CONSOLES)
3337 if (sisusb_init_gfxdevice(sisusb, initscreen))
3339 "sisusbvga[%d]: Failed to early "
3340 "initialize device\n",
3345 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3351 #ifdef SISUSBENDIANTEST
3352 printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
3353 sisusb_testreadwrite(sisusb);
3354 printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
3357 #ifdef INCL_SISUSB_CON
3358 sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
3364 sisusb_free_urbs(sisusb);
3366 sisusb_free_buffers(sisusb);
3368 usb_deregister_dev(intf, &usb_sisusb_class);
3374 static void sisusb_disconnect(struct usb_interface *intf)
3376 struct sisusb_usb_data *sisusb;
3379 /* This should *not* happen */
3380 if (!(sisusb = usb_get_intfdata(intf)))
3383 #ifdef INCL_SISUSB_CON
3384 sisusb_console_exit(sisusb);
3387 /* The above code doesn't need the disconnect
3388 * semaphore to be down; its meaning is to
3389 * protect all other routines from the disconnect
3390 * case, not the other way round.
3392 mutex_lock(&disconnect_mutex);
3394 mutex_lock(&sisusb->lock);
3396 /* Wait for all URBs to complete and kill them in case (MUST do) */
3397 if (!sisusb_wait_all_out_complete(sisusb))
3398 sisusb_kill_all_busy(sisusb);
3400 minor = sisusb->minor;
3402 usb_set_intfdata(intf, NULL);
3404 usb_deregister_dev(intf, &usb_sisusb_class);
3406 #ifdef SISUSB_OLD_CONFIG_COMPAT
3407 if (sisusb->ioctl32registered) {
3409 sisusb->ioctl32registered = 0;
3410 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3411 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3412 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3415 "sisusbvga[%d]: Error unregistering "
3416 "ioctl32 translations\n",
3422 sisusb->present = 0;
3425 mutex_unlock(&sisusb->lock);
3427 /* decrement our usage count */
3428 kref_put(&sisusb->kref, sisusb_delete);
3430 mutex_unlock(&disconnect_mutex);
3432 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
3435 static struct usb_device_id sisusb_table [] = {
3436 { USB_DEVICE(0x0711, 0x0900) },
3437 { USB_DEVICE(0x0711, 0x0901) },
3438 { USB_DEVICE(0x0711, 0x0902) },
3439 { USB_DEVICE(0x182d, 0x021c) },
3440 { USB_DEVICE(0x182d, 0x0269) },
3444 MODULE_DEVICE_TABLE (usb, sisusb_table);
3446 static struct usb_driver sisusb_driver = {
3448 .probe = sisusb_probe,
3449 .disconnect = sisusb_disconnect,
3450 .id_table = sisusb_table,
3453 static int __init usb_sisusb_init(void)
3457 #ifdef INCL_SISUSB_CON
3458 sisusb_init_concode();
3461 if (!(retval = usb_register(&sisusb_driver))) {
3463 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3464 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3466 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3473 static void __exit usb_sisusb_exit(void)
3475 usb_deregister(&sisusb_driver);
3478 module_init(usb_sisusb_init);
3479 module_exit(usb_sisusb_exit);
3481 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3482 MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
3483 MODULE_LICENSE("GPL");