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/config.h>
40 #include <linux/mutex.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>
56 #include "sisusb_init.h"
58 #ifdef INCL_SISUSB_CON
59 #include <linux/font.h>
62 #define SISUSB_DONTSYNC
64 /* Forward declarations / clean-up routines */
66 #ifdef INCL_SISUSB_CON
67 static int sisusb_first_vc = 0;
68 static int sisusb_last_vc = 0;
69 module_param_named(first, sisusb_first_vc, int, 0);
70 module_param_named(last, sisusb_last_vc, int, 0);
71 MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)");
72 MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)");
75 static struct usb_driver sisusb_driver;
77 DEFINE_MUTEX(disconnect_mutex);
80 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
84 for (i = 0; i < NUMOBUFS; i++) {
85 if (sisusb->obuf[i]) {
86 usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize,
87 sisusb->obuf[i], sisusb->transfer_dma_out[i]);
88 sisusb->obuf[i] = NULL;
92 usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
93 sisusb->ibuf, sisusb->transfer_dma_in);
99 sisusb_free_urbs(struct sisusb_usb_data *sisusb)
103 for (i = 0; i < NUMOBUFS; i++) {
104 usb_free_urb(sisusb->sisurbout[i]);
105 sisusb->sisurbout[i] = NULL;
107 usb_free_urb(sisusb->sisurbin);
108 sisusb->sisurbin = NULL;
111 /* Level 0: USB transport layer */
115 /* out-urb management */
117 /* Return 1 if all free, 0 otherwise */
119 sisusb_all_free(struct sisusb_usb_data *sisusb)
123 for (i = 0; i < sisusb->numobufs; i++) {
125 if (sisusb->urbstatus[i] & SU_URB_BUSY)
133 /* Kill all busy URBs */
135 sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
139 if (sisusb_all_free(sisusb))
142 for (i = 0; i < sisusb->numobufs; i++) {
144 if (sisusb->urbstatus[i] & SU_URB_BUSY)
145 usb_kill_urb(sisusb->sisurbout[i]);
150 /* Return 1 if ok, 0 if error (not all complete within timeout) */
152 sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
154 int timeout = 5 * HZ, i = 1;
156 wait_event_timeout(sisusb->wait_q,
157 (i = sisusb_all_free(sisusb)),
164 sisusb_outurb_available(struct sisusb_usb_data *sisusb)
168 for (i = 0; i < sisusb->numobufs; i++) {
170 if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
179 sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
181 int i, timeout = 5 * HZ;
183 wait_event_timeout(sisusb->wait_q,
184 ((i = sisusb_outurb_available(sisusb)) >= 0),
191 sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
195 i = sisusb_outurb_available(sisusb);
198 sisusb->urbstatus[i] |= SU_URB_ALLOC;
204 sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
206 if ((index >= 0) && (index < sisusb->numobufs))
207 sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
210 /* completion callback */
213 sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
215 struct sisusb_urb_context *context = urb->context;
216 struct sisusb_usb_data *sisusb;
221 sisusb = context->sisusb;
223 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
226 #ifndef SISUSB_DONTSYNC
227 if (context->actual_length)
228 *(context->actual_length) += urb->actual_length;
231 sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
232 wake_up(&sisusb->wait_q);
236 sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
237 int len, int *actual_length, int timeout, unsigned int tflags,
238 dma_addr_t transfer_dma)
240 struct urb *urb = sisusb->sisurbout[index];
241 int retval, byteswritten = 0;
244 urb->transfer_flags = 0;
246 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
247 sisusb_bulk_completeout, &sisusb->urbout_context[index]);
249 urb->transfer_flags |= tflags;
250 urb->actual_length = 0;
252 if ((urb->transfer_dma = transfer_dma))
253 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
256 sisusb->urbout_context[index].actual_length = (timeout) ?
257 NULL : actual_length;
259 /* Declare this urb/buffer in use */
260 sisusb->urbstatus[index] |= SU_URB_BUSY;
263 retval = usb_submit_urb(urb, GFP_ATOMIC);
265 /* If OK, and if timeout > 0, wait for completion */
266 if ((retval == 0) && timeout) {
267 wait_event_timeout(sisusb->wait_q,
268 (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
270 if (sisusb->urbstatus[index] & SU_URB_BUSY) {
271 /* URB timed out... kill it and report error */
275 /* Otherwise, report urb status */
276 retval = urb->status;
277 byteswritten = urb->actual_length;
282 *actual_length = byteswritten;
289 /* completion callback */
292 sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
294 struct sisusb_usb_data *sisusb = urb->context;
296 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
299 sisusb->completein = 1;
300 wake_up(&sisusb->wait_q);
304 sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len,
305 int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma)
307 struct urb *urb = sisusb->sisurbin;
308 int retval, readbytes = 0;
310 urb->transfer_flags = 0;
312 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
313 sisusb_bulk_completein, sisusb);
315 urb->transfer_flags |= tflags;
316 urb->actual_length = 0;
318 if ((urb->transfer_dma = transfer_dma))
319 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
321 sisusb->completein = 0;
322 retval = usb_submit_urb(urb, GFP_ATOMIC);
324 wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
325 if (!sisusb->completein) {
326 /* URB timed out... kill it and report error */
330 /* URB completed within timout */
331 retval = urb->status;
332 readbytes = urb->actual_length;
337 *actual_length = readbytes;
345 /* Send a bulk message of variable size
347 * To copy the data from userspace, give pointer to "userbuffer",
348 * to copy from (non-DMA) kernel memory, give "kernbuffer". If
349 * both of these are NULL, it is assumed, that the transfer
350 * buffer "sisusb->obuf[index]" is set up with the data to send.
351 * Index is ignored if either kernbuffer or userbuffer is set.
352 * If async is nonzero, URBs will be sent without waiting for
353 * completion of the previous URB.
355 * (return 0 on success)
358 static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
359 char *kernbuffer, const char __user *userbuffer, int index,
360 ssize_t *bytes_written, unsigned int tflags, int async)
362 int result = 0, retry, count = len;
363 int passsize, thispass, transferred_len = 0;
364 int fromuser = (userbuffer != NULL) ? 1 : 0;
365 int fromkern = (kernbuffer != NULL) ? 1 : 0;
369 (*bytes_written) = 0;
372 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
375 /* If we copy data from kernel or userspace, force the
376 * allocation of a buffer/urb. If we have the data in
377 * the transfer buffer[index] already, reuse the buffer/URB
378 * if the length is > buffer size. (So, transmitting
379 * large data amounts directly from the transfer buffer
380 * treats the buffer as a ring buffer. However, we need
381 * to sync in this case.)
383 if (fromuser || fromkern)
385 else if (len > sisusb->obufsize)
388 pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
391 passsize = thispass = (sisusb->obufsize < count) ?
392 sisusb->obufsize : count;
395 index = sisusb_get_free_outbuf(sisusb);
400 buffer = sisusb->obuf[index];
404 if (copy_from_user(buffer, userbuffer, passsize))
407 userbuffer += passsize;
409 } else if (fromkern) {
411 memcpy(buffer, kernbuffer, passsize);
412 kernbuffer += passsize;
419 if (!sisusb->sisusb_dev)
422 result = sisusb_bulkout_msg(sisusb,
430 sisusb->transfer_dma_out[index]);
432 if (result == -ETIMEDOUT) {
434 /* Will not happen if async */
440 } else if ((result == 0) && !async && transferred_len) {
442 thispass -= transferred_len;
444 if (sisusb->transfer_dma_out) {
445 /* If DMA, copy remaining
446 * to beginning of buffer
449 buffer + transferred_len,
452 /* If not DMA, simply increase
455 buffer += transferred_len;
466 (*bytes_written) += passsize;
469 /* Force new allocation in next iteration */
470 if (fromuser || fromkern)
476 #ifdef SISUSB_DONTSYNC
477 (*bytes_written) = len;
478 /* Some URBs/buffers might be busy */
480 sisusb_wait_all_out_complete(sisusb);
481 (*bytes_written) = transferred_len;
482 /* All URBs and all buffers are available */
486 return ((*bytes_written) == len) ? 0 : -EIO;
489 /* Receive a bulk message of variable size
491 * To copy the data to userspace, give pointer to "userbuffer",
492 * to copy to kernel memory, give "kernbuffer". One of them
493 * MUST be set. (There is no technique for letting the caller
494 * read directly from the ibuf.)
498 static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
499 void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
502 int result = 0, retry, count = len;
503 int bufsize, thispass, transferred_len;
510 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
513 pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
514 buffer = sisusb->ibuf;
515 bufsize = sisusb->ibufsize;
519 #ifdef SISUSB_DONTSYNC
520 if (!(sisusb_wait_all_out_complete(sisusb)))
526 if (!sisusb->sisusb_dev)
529 thispass = (bufsize < count) ? bufsize : count;
531 result = sisusb_bulkin_msg(sisusb,
538 sisusb->transfer_dma_in);
541 thispass = transferred_len;
543 else if (result == -ETIMEDOUT) {
556 (*bytes_read) += thispass;
561 if (copy_to_user(userbuffer, buffer, thispass))
564 userbuffer += thispass;
568 memcpy(kernbuffer, buffer, thispass);
569 kernbuffer += thispass;
577 return ((*bytes_read) == len) ? 0 : -EIO;
580 static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
581 struct sisusb_packet *packet)
584 ssize_t bytes_transferred = 0;
590 #ifdef SISUSB_DONTSYNC
591 if (!(sisusb_wait_all_out_complete(sisusb)))
595 /* Eventually correct endianness */
596 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
598 /* 1. send the packet */
599 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
600 (char *)packet, NULL, 0, &bytes_transferred, 0, 0);
602 if ((ret == 0) && (len == 6)) {
604 /* 2. if packet len == 6, it means we read, so wait for 32bit
605 * return value and write it to packet->data
607 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
608 (char *)&tmp, NULL, &bytes_transferred, 0);
610 packet->data = le32_to_cpu(tmp);
616 static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
617 struct sisusb_packet *packet,
621 ssize_t bytes_transferred = 0;
627 #ifdef SISUSB_DONTSYNC
628 if (!(sisusb_wait_all_out_complete(sisusb)))
632 /* Eventually correct endianness */
633 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
635 /* 1. send the packet */
636 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
637 (char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
639 if ((ret == 0) && (len == 6)) {
641 /* 2. if packet len == 6, it means we read, so wait for 32bit
642 * return value and write it to packet->data
644 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
645 (char *)&tmp, NULL, &bytes_transferred, 0);
647 packet->data = le32_to_cpu(tmp);
653 /* access video memory and mmio (return 0 on success) */
657 /* The following routines assume being used to transfer byte, word,
660 * - the write routines expect "data" in machine endianness format.
661 * The data will be converted to leXX in sisusb_xxx_packet.
662 * - the read routines can expect read data in machine-endianess.
665 static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
668 struct sisusb_packet packet;
671 packet.header = (1 << (addr & 3)) | (type << 6);
672 packet.address = addr & ~3;
673 packet.data = data << ((addr & 3) << 3);
674 ret = sisusb_send_packet(sisusb, 10, &packet);
678 static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
681 struct sisusb_packet packet;
684 packet.address = addr & ~3;
688 packet.header = (type << 6) | 0x0003;
689 packet.data = (u32)data;
690 ret = sisusb_send_packet(sisusb, 10, &packet);
693 packet.header = (type << 6) | 0x0006;
694 packet.data = (u32)data << 8;
695 ret = sisusb_send_packet(sisusb, 10, &packet);
698 packet.header = (type << 6) | 0x000c;
699 packet.data = (u32)data << 16;
700 ret = sisusb_send_packet(sisusb, 10, &packet);
703 packet.header = (type << 6) | 0x0008;
704 packet.data = (u32)data << 24;
705 ret = sisusb_send_packet(sisusb, 10, &packet);
706 packet.header = (type << 6) | 0x0001;
707 packet.address = (addr & ~3) + 4;
708 packet.data = (u32)data >> 8;
709 ret |= sisusb_send_packet(sisusb, 10, &packet);
715 static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
718 struct sisusb_packet packet;
721 packet.address = addr & ~3;
725 packet.header = (type << 6) | 0x0007;
726 packet.data = data & 0x00ffffff;
727 ret = sisusb_send_packet(sisusb, 10, &packet);
730 packet.header = (type << 6) | 0x000e;
731 packet.data = data << 8;
732 ret = sisusb_send_packet(sisusb, 10, &packet);
735 packet.header = (type << 6) | 0x000c;
736 packet.data = data << 16;
737 ret = sisusb_send_packet(sisusb, 10, &packet);
738 packet.header = (type << 6) | 0x0001;
739 packet.address = (addr & ~3) + 4;
740 packet.data = (data >> 16) & 0x00ff;
741 ret |= sisusb_send_packet(sisusb, 10, &packet);
744 packet.header = (type << 6) | 0x0008;
745 packet.data = data << 24;
746 ret = sisusb_send_packet(sisusb, 10, &packet);
747 packet.header = (type << 6) | 0x0003;
748 packet.address = (addr & ~3) + 4;
749 packet.data = (data >> 8) & 0xffff;
750 ret |= sisusb_send_packet(sisusb, 10, &packet);
756 static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
759 struct sisusb_packet packet;
762 packet.address = addr & ~3;
766 packet.header = (type << 6) | 0x000f;
768 ret = sisusb_send_packet(sisusb, 10, &packet);
771 packet.header = (type << 6) | 0x000e;
772 packet.data = data << 8;
773 ret = sisusb_send_packet(sisusb, 10, &packet);
774 packet.header = (type << 6) | 0x0001;
775 packet.address = (addr & ~3) + 4;
776 packet.data = data >> 24;
777 ret |= sisusb_send_packet(sisusb, 10, &packet);
780 packet.header = (type << 6) | 0x000c;
781 packet.data = data << 16;
782 ret = sisusb_send_packet(sisusb, 10, &packet);
783 packet.header = (type << 6) | 0x0003;
784 packet.address = (addr & ~3) + 4;
785 packet.data = data >> 16;
786 ret |= sisusb_send_packet(sisusb, 10, &packet);
789 packet.header = (type << 6) | 0x0008;
790 packet.data = data << 24;
791 ret = sisusb_send_packet(sisusb, 10, &packet);
792 packet.header = (type << 6) | 0x0007;
793 packet.address = (addr & ~3) + 4;
794 packet.data = data >> 8;
795 ret |= sisusb_send_packet(sisusb, 10, &packet);
801 /* The xxx_bulk routines copy a buffer of variable size. They treat the
802 * buffer as chars, therefore lsb/msb has to be corrected if using the
803 * byte/word/long/etc routines for speed-up
805 * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
806 * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
807 * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
808 * that the data already is in the transfer buffer "sisusb->obuf[index]".
811 static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
812 char *kernbuffer, int length,
813 const char __user *userbuffer, int index,
814 ssize_t *bytes_written)
816 struct sisusb_packet packet;
818 static int msgcount = 0;
819 u8 swap8, fromkern = kernbuffer ? 1 : 0;
821 u32 swap32, flag = (length >> 28) & 1;
824 /* if neither kernbuffer not userbuffer are given, assume
827 if (!fromkern && !userbuffer)
828 kernbuffer = sisusb->obuf[index];
830 (*bytes_written = 0);
832 length &= 0x00ffffff;
840 if (get_user(swap8, (u8 __user *)userbuffer))
843 swap8 = kernbuffer[0];
845 ret = sisusb_write_memio_byte(sisusb,
856 if (get_user(swap16, (u16 __user *)userbuffer))
859 swap16 = *((u16 *)kernbuffer);
861 ret = sisusb_write_memio_word(sisusb,
867 (*bytes_written) += 2;
873 if (copy_from_user(&buf, userbuffer, 3))
876 swap32 = (buf[0] << 16) |
880 swap32 = (buf[2] << 16) |
886 swap32 = (kernbuffer[0] << 16) |
887 (kernbuffer[1] << 8) |
890 swap32 = (kernbuffer[2] << 16) |
891 (kernbuffer[1] << 8) |
895 ret = sisusb_write_memio_24bit(sisusb,
901 (*bytes_written) += 3;
907 if (get_user(swap32, (u32 __user *)userbuffer))
910 swap32 = *((u32 *)kernbuffer);
912 ret = sisusb_write_memio_long(sisusb,
917 (*bytes_written) += 4;
922 if ((length & ~3) > 0x10000) {
924 packet.header = 0x001f;
925 packet.address = 0x000001d4;
927 ret = sisusb_send_bridge_packet(sisusb, 10,
929 packet.header = 0x001f;
930 packet.address = 0x000001d0;
931 packet.data = (length & ~3);
932 ret |= sisusb_send_bridge_packet(sisusb, 10,
934 packet.header = 0x001f;
935 packet.address = 0x000001c0;
936 packet.data = flag | 0x16;
937 ret |= sisusb_send_bridge_packet(sisusb, 10,
940 ret |= sisusb_send_bulk_msg(sisusb,
941 SISUSB_EP_GFX_LBULK_OUT,
944 bytes_written, 0, 1);
945 userbuffer += (*bytes_written);
946 } else if (fromkern) {
947 ret |= sisusb_send_bulk_msg(sisusb,
948 SISUSB_EP_GFX_LBULK_OUT,
951 bytes_written, 0, 1);
952 kernbuffer += (*bytes_written);
954 ret |= sisusb_send_bulk_msg(sisusb,
955 SISUSB_EP_GFX_LBULK_OUT,
958 bytes_written, 0, 1);
959 kernbuffer += ((*bytes_written) &
960 (sisusb->obufsize-1));
965 packet.header = 0x001f;
966 packet.address = 0x00000194;
968 ret = sisusb_send_bridge_packet(sisusb, 10,
970 packet.header = 0x001f;
971 packet.address = 0x00000190;
972 packet.data = (length & ~3);
973 ret |= sisusb_send_bridge_packet(sisusb, 10,
975 if (sisusb->flagb0 != 0x16) {
976 packet.header = 0x001f;
977 packet.address = 0x00000180;
978 packet.data = flag | 0x16;
979 ret |= sisusb_send_bridge_packet(sisusb, 10,
981 sisusb->flagb0 = 0x16;
984 ret |= sisusb_send_bulk_msg(sisusb,
985 SISUSB_EP_GFX_BULK_OUT,
988 bytes_written, 0, 1);
989 userbuffer += (*bytes_written);
990 } else if (fromkern) {
991 ret |= sisusb_send_bulk_msg(sisusb,
992 SISUSB_EP_GFX_BULK_OUT,
995 bytes_written, 0, 1);
996 kernbuffer += (*bytes_written);
998 ret |= sisusb_send_bulk_msg(sisusb,
999 SISUSB_EP_GFX_BULK_OUT,
1002 bytes_written, 0, 1);
1003 kernbuffer += ((*bytes_written) &
1004 (sisusb->obufsize-1));
1011 "sisusbvga[%d]: Wrote %zd of "
1012 "%d bytes, error %d\n",
1013 sisusb->minor, *bytes_written,
1015 else if (msgcount == 500)
1017 "sisusbvga[%d]: Too many errors"
1018 ", logging stopped\n",
1021 addr += (*bytes_written);
1022 length -= (*bytes_written);
1030 return ret ? -EIO : 0;
1033 /* Remember: Read data in packet is in machine-endianess! So for
1034 * byte, word, 24bit, long no endian correction is necessary.
1037 static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1040 struct sisusb_packet packet;
1043 CLEARPACKET(&packet);
1044 packet.header = (1 << (addr & 3)) | (type << 6);
1045 packet.address = addr & ~3;
1046 ret = sisusb_send_packet(sisusb, 6, &packet);
1047 *data = (u8)(packet.data >> ((addr & 3) << 3));
1051 static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1052 u32 addr, u16 *data)
1054 struct sisusb_packet packet;
1057 CLEARPACKET(&packet);
1059 packet.address = addr & ~3;
1063 packet.header = (type << 6) | 0x0003;
1064 ret = sisusb_send_packet(sisusb, 6, &packet);
1065 *data = (u16)(packet.data);
1068 packet.header = (type << 6) | 0x0006;
1069 ret = sisusb_send_packet(sisusb, 6, &packet);
1070 *data = (u16)(packet.data >> 8);
1073 packet.header = (type << 6) | 0x000c;
1074 ret = sisusb_send_packet(sisusb, 6, &packet);
1075 *data = (u16)(packet.data >> 16);
1078 packet.header = (type << 6) | 0x0008;
1079 ret = sisusb_send_packet(sisusb, 6, &packet);
1080 *data = (u16)(packet.data >> 24);
1081 packet.header = (type << 6) | 0x0001;
1082 packet.address = (addr & ~3) + 4;
1083 ret |= sisusb_send_packet(sisusb, 6, &packet);
1084 *data |= (u16)(packet.data << 8);
1090 static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1091 u32 addr, u32 *data)
1093 struct sisusb_packet packet;
1096 packet.address = addr & ~3;
1100 packet.header = (type << 6) | 0x0007;
1101 ret = sisusb_send_packet(sisusb, 6, &packet);
1102 *data = packet.data & 0x00ffffff;
1105 packet.header = (type << 6) | 0x000e;
1106 ret = sisusb_send_packet(sisusb, 6, &packet);
1107 *data = packet.data >> 8;
1110 packet.header = (type << 6) | 0x000c;
1111 ret = sisusb_send_packet(sisusb, 6, &packet);
1112 *data = packet.data >> 16;
1113 packet.header = (type << 6) | 0x0001;
1114 packet.address = (addr & ~3) + 4;
1115 ret |= sisusb_send_packet(sisusb, 6, &packet);
1116 *data |= ((packet.data & 0xff) << 16);
1119 packet.header = (type << 6) | 0x0008;
1120 ret = sisusb_send_packet(sisusb, 6, &packet);
1121 *data = packet.data >> 24;
1122 packet.header = (type << 6) | 0x0003;
1123 packet.address = (addr & ~3) + 4;
1124 ret |= sisusb_send_packet(sisusb, 6, &packet);
1125 *data |= ((packet.data & 0xffff) << 8);
1131 static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1132 u32 addr, u32 *data)
1134 struct sisusb_packet packet;
1137 packet.address = addr & ~3;
1141 packet.header = (type << 6) | 0x000f;
1142 ret = sisusb_send_packet(sisusb, 6, &packet);
1143 *data = packet.data;
1146 packet.header = (type << 6) | 0x000e;
1147 ret = sisusb_send_packet(sisusb, 6, &packet);
1148 *data = packet.data >> 8;
1149 packet.header = (type << 6) | 0x0001;
1150 packet.address = (addr & ~3) + 4;
1151 ret |= sisusb_send_packet(sisusb, 6, &packet);
1152 *data |= (packet.data << 24);
1155 packet.header = (type << 6) | 0x000c;
1156 ret = sisusb_send_packet(sisusb, 6, &packet);
1157 *data = packet.data >> 16;
1158 packet.header = (type << 6) | 0x0003;
1159 packet.address = (addr & ~3) + 4;
1160 ret |= sisusb_send_packet(sisusb, 6, &packet);
1161 *data |= (packet.data << 16);
1164 packet.header = (type << 6) | 0x0008;
1165 ret = sisusb_send_packet(sisusb, 6, &packet);
1166 *data = packet.data >> 24;
1167 packet.header = (type << 6) | 0x0007;
1168 packet.address = (addr & ~3) + 4;
1169 ret |= sisusb_send_packet(sisusb, 6, &packet);
1170 *data |= (packet.data << 8);
1176 static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1177 char *kernbuffer, int length,
1178 char __user *userbuffer, ssize_t *bytes_read)
1187 length &= 0x00ffffff;
1195 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1200 if (put_user(buf[0],
1201 (u8 __user *)userbuffer)) {
1205 kernbuffer[0] = buf[0];
1211 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1216 if (put_user(swap16,
1217 (u16 __user *)userbuffer))
1220 *((u16 *)kernbuffer) = swap16;
1226 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1231 buf[0] = (swap32 >> 16) & 0xff;
1232 buf[1] = (swap32 >> 8) & 0xff;
1233 buf[2] = swap32 & 0xff;
1235 buf[2] = (swap32 >> 16) & 0xff;
1236 buf[1] = (swap32 >> 8) & 0xff;
1237 buf[0] = swap32 & 0xff;
1240 if (copy_to_user(userbuffer, &buf[0], 3))
1243 kernbuffer[0] = buf[0];
1244 kernbuffer[1] = buf[1];
1245 kernbuffer[2] = buf[2];
1251 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1256 if (put_user(swap32,
1257 (u32 __user *)userbuffer))
1262 *((u32 *)kernbuffer) = swap32;
1268 #if 0 /* That does not work, as EP 2 is an OUT EP! */
1270 CLEARPACKET(&packet);
1271 packet.header = 0x001f;
1272 packet.address = 0x000001a0;
1273 packet.data = 0x00000006;
1274 ret |= sisusb_send_bridge_packet(sisusb, 10,
1276 packet.header = 0x001f;
1277 packet.address = 0x000001b0;
1278 packet.data = (length & ~3) | 0x40000000;
1279 ret |= sisusb_send_bridge_packet(sisusb, 10,
1281 packet.header = 0x001f;
1282 packet.address = 0x000001b4;
1284 ret |= sisusb_send_bridge_packet(sisusb, 10,
1286 packet.header = 0x001f;
1287 packet.address = 0x000001a4;
1288 packet.data = 0x00000001;
1289 ret |= sisusb_send_bridge_packet(sisusb, 10,
1292 ret |= sisusb_recv_bulk_msg(sisusb,
1293 SISUSB_EP_GFX_BULK_IN,
1297 if (!ret) userbuffer += (*bytes_read);
1299 ret |= sisusb_recv_bulk_msg(sisusb,
1300 SISUSB_EP_GFX_BULK_IN,
1304 if (!ret) kernbuffer += (*bytes_read);
1306 addr += (*bytes_read);
1307 length -= (*bytes_read);
1318 /* High level: Gfx (indexed) register access */
1320 #ifdef INCL_SISUSB_CON
1322 sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
1324 return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1328 sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
1330 return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1335 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1338 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1339 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1344 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1347 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1348 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1353 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1359 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1360 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1363 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1368 sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1373 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1374 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1376 tmp |= (data & mask);
1377 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1382 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1384 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1388 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1390 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1393 /* Write/read video ram */
1395 #ifdef INCL_SISUSB_CON
1397 sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
1399 return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1403 sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
1405 return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1411 sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
1413 return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1417 sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
1419 return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1425 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
1426 u32 dest, int length, size_t *bytes_written)
1428 return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
1431 #ifdef SISUSBENDIANTEST
1433 sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
1434 u32 src, int length, size_t *bytes_written)
1436 return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
1441 #ifdef SISUSBENDIANTEST
1443 sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
1445 static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
1446 char destbuffer[10];
1450 sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
1452 for(i = 1; i <= 7; i++) {
1453 printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
1454 sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
1455 for(j = 0; j < i; j++) {
1456 printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
1462 /* access pci config registers (reg numbers 0, 4, 8, etc) */
1465 sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1467 struct sisusb_packet packet;
1470 packet.header = 0x008f;
1471 packet.address = regnum | 0x10000;
1473 ret = sisusb_send_packet(sisusb, 10, &packet);
1478 sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1480 struct sisusb_packet packet;
1483 packet.header = 0x008f;
1484 packet.address = (u32)regnum | 0x10000;
1485 ret = sisusb_send_packet(sisusb, 6, &packet);
1486 *data = packet.data;
1490 /* Clear video RAM */
1493 sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1498 if (address < sisusb->vrambase)
1501 if (address >= sisusb->vrambase + sisusb->vramsize)
1504 if (address + length > sisusb->vrambase + sisusb->vramsize)
1505 length = sisusb->vrambase + sisusb->vramsize - address;
1510 /* allocate free buffer/urb and clear the buffer */
1511 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1514 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1516 /* We can write a length > buffer size here. The buffer
1517 * data will simply be re-used (like a ring-buffer).
1519 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1521 /* Free the buffer/urb */
1522 sisusb_free_outbuf(sisusb, i);
1527 /* Initialize the graphics core (return 0 on success)
1528 * This resets the graphics hardware and puts it into
1529 * a defined mode (640x480@60Hz)
1532 #define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1533 #define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1534 #define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
1535 #define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
1536 #define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
1537 #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
1538 #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
1539 #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1540 #define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1541 #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1542 #define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1545 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1550 ret = GETIREG(SISSR, 0x16, &tmp8);
1553 ret |= SETIREG(SISSR, 0x16, tmp8);
1555 ret |= SETIREG(SISSR, 0x16, tmp8);
1558 ret |= SETIREG(SISSR, 0x16, tmp8);
1560 ret |= SETIREG(SISSR, 0x16, tmp8);
1562 ret |= SETIREG(SISSR, 0x16, tmp8);
1564 ret |= SETIREG(SISSR, 0x16, tmp8);
1566 ret |= SETIREG(SISSR, 0x16, tmp8);
1568 ret |= SETIREG(SISSR, 0x16, tmp8);
1570 ret |= SETIREG(SISSR, 0x16, tmp8);
1576 sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1579 u8 ramtype, done = 0;
1581 u32 ramptr = SISUSB_PCI_MEMBASE;
1583 ret = GETIREG(SISSR, 0x3a, &ramtype);
1586 ret |= SETIREG(SISSR, 0x13, 0x00);
1589 ret |= SETIREG(SISSR, 0x14, 0x12);
1590 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1592 ret |= SETIREG(SISSR, 0x14, 0x02);
1595 ret |= sisusb_triggersr16(sisusb, ramtype);
1596 ret |= WRITEL(ramptr + 0, 0x01234567);
1597 ret |= WRITEL(ramptr + 4, 0x456789ab);
1598 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1599 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1600 ret |= WRITEL(ramptr + 16, 0x55555555);
1601 ret |= WRITEL(ramptr + 20, 0x55555555);
1602 ret |= WRITEL(ramptr + 24, 0xffffffff);
1603 ret |= WRITEL(ramptr + 28, 0xffffffff);
1604 ret |= READL(ramptr + 0, &t0);
1605 ret |= READL(ramptr + 4, &t1);
1606 ret |= READL(ramptr + 8, &t2);
1607 ret |= READL(ramptr + 12, &t3);
1611 *chab = 0; *bw = 64;
1613 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1614 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1615 *chab = 0; *bw = 64;
1616 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1619 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1620 *chab = 1; *bw = 64;
1621 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1623 ret |= sisusb_triggersr16(sisusb, ramtype);
1624 ret |= WRITEL(ramptr + 0, 0x89abcdef);
1625 ret |= WRITEL(ramptr + 4, 0xcdef0123);
1626 ret |= WRITEL(ramptr + 8, 0x55555555);
1627 ret |= WRITEL(ramptr + 12, 0x55555555);
1628 ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1629 ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1630 ret |= READL(ramptr + 4, &t1);
1632 if (t1 != 0xcdef0123) {
1634 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1640 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1644 if (t1 == 0x456789ab) {
1645 if (t0 == 0x01234567) {
1646 *chab = 0; *bw = 64;
1650 if (t0 == 0x01234567) {
1651 *chab = 0; *bw = 32;
1652 ret |= SETIREG(SISSR, 0x14, 0x00);
1658 ret |= SETIREG(SISSR, 0x14, 0x03);
1659 ret |= sisusb_triggersr16(sisusb, ramtype);
1661 ret |= WRITEL(ramptr + 0, 0x01234567);
1662 ret |= WRITEL(ramptr + 4, 0x456789ab);
1663 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1664 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1665 ret |= WRITEL(ramptr + 16, 0x55555555);
1666 ret |= WRITEL(ramptr + 20, 0x55555555);
1667 ret |= WRITEL(ramptr + 24, 0xffffffff);
1668 ret |= WRITEL(ramptr + 28, 0xffffffff);
1669 ret |= READL(ramptr + 0, &t0);
1670 ret |= READL(ramptr + 4, &t1);
1672 if (t1 == 0x456789ab) {
1673 if (t0 == 0x01234567) {
1674 *chab = 1; *bw = 64;
1678 if (t0 == 0x01234567) {
1679 *chab = 1; *bw = 32;
1680 ret |= SETIREG(SISSR, 0x14, 0x01);
1689 sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1692 u32 ramptr = SISUSB_PCI_MEMBASE;
1693 u8 tmp1, tmp2, i, j;
1695 ret |= WRITEB(ramptr, 0xaa);
1696 ret |= WRITEB(ramptr + 16, 0x55);
1697 ret |= READB(ramptr, &tmp1);
1698 ret |= READB(ramptr + 16, &tmp2);
1699 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1700 for (i = 0, j = 16; i < 2; i++, j += 16) {
1701 ret |= GETIREG(SISSR, 0x21, &tmp1);
1702 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1703 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1704 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1705 ret |= SETIREG(SISSR, 0x21, tmp1);
1706 ret |= WRITEB(ramptr + 16 + j, j);
1707 ret |= READB(ramptr + 16 + j, &tmp1);
1709 ret |= WRITEB(ramptr + j, j);
1718 sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1719 u8 rankno, u8 chab, const u8 dramtype[][5],
1722 int ret = 0, ranksize;
1727 if ((rankno == 2) && (dramtype[index][0] == 2))
1730 ranksize = dramtype[index][3] / 2 * bw / 32;
1732 if ((ranksize * rankno) > 128)
1736 while ((ranksize >>= 1) > 0) tmp += 0x10;
1737 tmp |= ((rankno - 1) << 2);
1738 tmp |= ((bw / 64) & 0x02);
1739 tmp |= (chab & 0x01);
1741 ret = SETIREG(SISSR, 0x14, tmp);
1742 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1750 sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1757 for (i = 0, j = 0; i < testn; i++) {
1758 ret |= WRITEL(sisusb->vrambase + j, j);
1762 for (i = 0, j = 0; i < testn; i++) {
1763 ret |= READL(sisusb->vrambase + j, &tmp);
1764 if (tmp != j) return ret;
1773 sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1774 int idx, int bw, const u8 rtype[][5])
1776 int ret = 0, i, i2ret;
1781 for (i = rankno; i >= 1; i--) {
1782 inc = 1 << (rtype[idx][2] +
1786 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1791 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1792 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1796 inc = 1 << (10 + bw / 64);
1797 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1806 sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1809 int ret = 0, i2ret = 0, i, j;
1810 static const u8 sdramtype[13][5] = {
1811 { 2, 12, 9, 64, 0x35 },
1812 { 1, 13, 9, 64, 0x44 },
1813 { 2, 12, 8, 32, 0x31 },
1814 { 2, 11, 9, 32, 0x25 },
1815 { 1, 12, 9, 32, 0x34 },
1816 { 1, 13, 8, 32, 0x40 },
1817 { 2, 11, 8, 16, 0x21 },
1818 { 1, 12, 8, 16, 0x30 },
1819 { 1, 11, 9, 16, 0x24 },
1820 { 1, 11, 8, 8, 0x20 },
1821 { 2, 9, 8, 4, 0x01 },
1822 { 1, 10, 8, 4, 0x10 },
1823 { 1, 9, 8, 2, 0x00 }
1826 *iret = 1; /* error */
1828 for (i = 0; i < 13; i++) {
1829 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1830 for (j = 2; j > 0; j--) {
1831 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1832 chab, sdramtype, bw);
1836 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1839 *iret = 0; /* ram size found */
1849 sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1853 int i, length, modex, modey, bpp;
1855 modex = 640; modey = 480; bpp = 2;
1857 address = sisusb->vrambase; /* Clear video ram */
1860 length = sisusb->vramsize;
1862 length = modex * bpp * modey;
1864 ret = sisusb_clear_vram(sisusb, address, length);
1866 if (!ret && drwfr) {
1867 for (i = 0; i < modex; i++) {
1868 address = sisusb->vrambase + (i * bpp);
1869 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1871 address += (modex * (modey-1) * bpp);
1872 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1875 for (i = 0; i < modey; i++) {
1876 address = sisusb->vrambase + ((i * modex) * bpp);
1877 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1879 address += ((modex - 1) * bpp);
1880 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1889 sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1891 int ret = 0, i, j, modex, modey, bpp, du;
1892 u8 sr31, cr63, tmp8;
1893 static const char attrdata[] = {
1894 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1895 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1898 static const char crtcrdata[] = {
1899 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1900 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1901 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1904 static const char grcdata[] = {
1905 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1908 static const char crtcdata[] = {
1909 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1910 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1914 modex = 640; modey = 480; bpp = 2;
1916 GETIREG(SISSR, 0x31, &sr31);
1917 GETIREG(SISCR, 0x63, &cr63);
1918 SETIREGOR(SISSR, 0x01, 0x20);
1919 SETIREG(SISCR, 0x63, cr63 & 0xbf);
1920 SETIREGOR(SISCR, 0x17, 0x80);
1921 SETIREGOR(SISSR, 0x1f, 0x04);
1922 SETIREGAND(SISSR, 0x07, 0xfb);
1923 SETIREG(SISSR, 0x00, 0x03); /* seq */
1924 SETIREG(SISSR, 0x01, 0x21);
1925 SETIREG(SISSR, 0x02, 0x0f);
1926 SETIREG(SISSR, 0x03, 0x00);
1927 SETIREG(SISSR, 0x04, 0x0e);
1928 SETREG(SISMISCW, 0x23); /* misc */
1929 for (i = 0; i <= 0x18; i++) { /* crtc */
1930 SETIREG(SISCR, i, crtcrdata[i]);
1932 for (i = 0; i <= 0x13; i++) { /* att */
1933 GETREG(SISINPSTAT, &tmp8);
1935 SETREG(SISAR, attrdata[i]);
1937 GETREG(SISINPSTAT, &tmp8);
1938 SETREG(SISAR, 0x14);
1939 SETREG(SISAR, 0x00);
1940 GETREG(SISINPSTAT, &tmp8);
1941 SETREG(SISAR, 0x20);
1942 GETREG(SISINPSTAT, &tmp8);
1943 for (i = 0; i <= 0x08; i++) { /* grc */
1944 SETIREG(SISGR, i, grcdata[i]);
1946 SETIREGAND(SISGR, 0x05, 0xbf);
1947 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1948 SETIREG(SISSR, i, 0x00);
1950 SETIREGAND(SISSR, 0x37, 0xfe);
1951 SETREG(SISMISCW, 0xef); /* sync */
1952 SETIREG(SISCR, 0x11, 0x00); /* crtc */
1953 for (j = 0x00, i = 0; i <= 7; i++, j++) {
1954 SETIREG(SISCR, j, crtcdata[i]);
1956 for (j = 0x10; i <= 10; i++, j++) {
1957 SETIREG(SISCR, j, crtcdata[i]);
1959 for (j = 0x15; i <= 12; i++, j++) {
1960 SETIREG(SISCR, j, crtcdata[i]);
1962 for (j = 0x0A; i <= 15; i++, j++) {
1963 SETIREG(SISSR, j, crtcdata[i]);
1965 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
1966 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
1967 SETIREG(SISCR, 0x14, 0x4f);
1968 du = (modex / 16) * (bpp * 2); /* offset/pitch */
1969 if (modex % 16) du += bpp;
1970 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
1971 SETIREG(SISCR, 0x13, (du & 0xff));
1974 if (du & 0xff) tmp8++;
1975 SETIREG(SISSR, 0x10, tmp8);
1976 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
1977 SETIREG(SISSR, 0x2b, 0x1b);
1978 SETIREG(SISSR, 0x2c, 0xe1);
1979 SETIREG(SISSR, 0x2d, 0x01);
1980 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
1981 SETIREG(SISSR, 0x08, 0xae);
1982 SETIREGAND(SISSR, 0x09, 0xf0);
1983 SETIREG(SISSR, 0x08, 0x34);
1984 SETIREGOR(SISSR, 0x3d, 0x01);
1985 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
1986 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
1987 SETIREG(SISCR, 0x19, 0x00);
1988 SETIREGAND(SISCR, 0x1a, 0xfc);
1989 SETIREGAND(SISSR, 0x0f, 0xb7);
1990 SETIREGAND(SISSR, 0x31, 0xfb);
1991 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
1992 SETIREGAND(SISSR, 0x32, 0xf3);
1993 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
1994 SETIREG(SISCR, 0x52, 0x6c);
1996 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
1997 SETIREG(SISCR, 0x0c, 0x00);
1998 SETIREG(SISSR, 0x0d, 0x00);
1999 SETIREGAND(SISSR, 0x37, 0xfe);
2001 SETIREG(SISCR, 0x32, 0x20);
2002 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
2003 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
2004 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
2007 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
2008 SETIREGOR(SISSR, 0x1e, 0x5a);
2010 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
2011 SETIREG(SISSR, 0x27, 0x1f);
2012 SETIREG(SISSR, 0x26, 0x00);
2015 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
2021 sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
2023 int ret = 0, i, j, bw, chab, iret, retry = 3;
2026 static const char mclktable[] = {
2027 0x3b, 0x22, 0x01, 143,
2028 0x3b, 0x22, 0x01, 143,
2029 0x3b, 0x22, 0x01, 143,
2030 0x3b, 0x22, 0x01, 143
2032 static const char eclktable[] = {
2033 0x3b, 0x22, 0x01, 143,
2034 0x3b, 0x22, 0x01, 143,
2035 0x3b, 0x22, 0x01, 143,
2036 0x3b, 0x22, 0x01, 143
2038 static const char ramtypetable1[] = {
2039 0x00, 0x04, 0x60, 0x60,
2040 0x0f, 0x0f, 0x1f, 0x1f,
2041 0xba, 0xba, 0xba, 0xba,
2042 0xa9, 0xa9, 0xac, 0xac,
2043 0xa0, 0xa0, 0xa0, 0xa8,
2044 0x00, 0x00, 0x02, 0x02,
2045 0x30, 0x30, 0x40, 0x40
2047 static const char ramtypetable2[] = {
2048 0x77, 0x77, 0x44, 0x44,
2049 0x77, 0x77, 0x44, 0x44,
2050 0x00, 0x00, 0x00, 0x00,
2051 0x5b, 0x5b, 0xab, 0xab,
2052 0x00, 0x00, 0xf0, 0xf8
2058 ret = GETREG(SISVGAEN, &tmp8);
2059 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
2061 /* Enable GPU access to VRAM */
2062 ret |= GETREG(SISMISCR, &tmp8);
2063 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
2067 /* Reset registers */
2068 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
2069 ret |= SETIREG(SISSR, 0x05, 0x86);
2070 ret |= SETIREGOR(SISSR, 0x20, 0x01);
2072 ret |= SETREG(SISMISCW, 0x67);
2074 for (i = 0x06; i <= 0x1f; i++) {
2075 ret |= SETIREG(SISSR, i, 0x00);
2077 for (i = 0x21; i <= 0x27; i++) {
2078 ret |= SETIREG(SISSR, i, 0x00);
2080 for (i = 0x31; i <= 0x3d; i++) {
2081 ret |= SETIREG(SISSR, i, 0x00);
2083 for (i = 0x12; i <= 0x1b; i++) {
2084 ret |= SETIREG(SISSR, i, 0x00);
2086 for (i = 0x79; i <= 0x7c; i++) {
2087 ret |= SETIREG(SISCR, i, 0x00);
2092 ret |= SETIREG(SISCR, 0x63, 0x80);
2094 ret |= GETIREG(SISSR, 0x3a, &ramtype);
2097 ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
2098 ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
2099 ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
2101 ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
2102 ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
2103 ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
2105 ret |= SETIREG(SISSR, 0x07, 0x18);
2106 ret |= SETIREG(SISSR, 0x11, 0x0f);
2110 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2111 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2113 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2114 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2117 ret |= SETIREG(SISCR, 0x49, 0xaa);
2119 ret |= SETIREG(SISSR, 0x1f, 0x00);
2120 ret |= SETIREG(SISSR, 0x20, 0xa0);
2121 ret |= SETIREG(SISSR, 0x23, 0xf6);
2122 ret |= SETIREG(SISSR, 0x24, 0x0d);
2123 ret |= SETIREG(SISSR, 0x25, 0x33);
2125 ret |= SETIREG(SISSR, 0x11, 0x0f);
2127 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2129 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2133 ret |= SETIREG(SISPART1, 0x00, 0x00);
2135 ret |= GETIREG(SISSR, 0x13, &tmp8);
2138 ret |= SETIREG(SISPART1, 0x02, 0x00);
2139 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2141 ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
2142 tmp32 &= 0x00f00000;
2143 tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
2144 ret |= SETIREG(SISSR, 0x25, tmp8);
2145 tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
2146 ret |= SETIREG(SISCR, 0x49, tmp8);
2148 ret |= SETIREG(SISSR, 0x27, 0x1f);
2149 ret |= SETIREG(SISSR, 0x31, 0x00);
2150 ret |= SETIREG(SISSR, 0x32, 0x11);
2151 ret |= SETIREG(SISSR, 0x33, 0x00);
2155 ret |= SETIREG(SISCR, 0x83, 0x00);
2157 ret |= sisusb_set_default_mode(sisusb, 0);
2159 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2160 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2161 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2163 ret |= sisusb_triggersr16(sisusb, ramtype);
2165 /* Disable refresh */
2166 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2167 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2169 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2170 ret |= sisusb_verify_mclk(sisusb);
2173 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2175 printk(KERN_ERR "sisusbvga[%d]: RAM size "
2176 "detection failed, "
2177 "assuming 8MB video RAM\n",
2179 ret |= SETIREG(SISSR,0x14,0x31);
2183 printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
2184 "assuming 8MB video RAM\n",
2186 ret |= SETIREG(SISSR,0x14,0x31);
2190 /* Enable refresh */
2191 ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
2192 ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
2193 ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
2195 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2197 ret |= SETIREG(SISSR, 0x22, 0xfb);
2198 ret |= SETIREG(SISSR, 0x21, 0xa5);
2218 sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2220 u8 tmp8, tmp82, ramtype;
2222 char *ramtypetext1 = NULL;
2223 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2224 "DDR SDRAM", "DDR SGRAM" };
2225 static const int busSDR[4] = {64, 64, 128, 128};
2226 static const int busDDR[4] = {32, 32, 64, 64};
2227 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2229 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2230 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2231 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2232 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2234 switch ((tmp8 >> 2) & 0x03) {
2235 case 0: ramtypetext1 = "1 ch/1 r";
2239 bw = busSDR[(tmp8 & 0x03)];
2242 case 1: ramtypetext1 = "1 ch/2 r";
2243 sisusb->vramsize <<= 1;
2244 bw = busSDR[(tmp8 & 0x03)];
2246 case 2: ramtypetext1 = "asymmeric";
2247 sisusb->vramsize += sisusb->vramsize/2;
2248 bw = busDDRA[(tmp8 & 0x03)];
2250 case 3: ramtypetext1 = "2 channel";
2251 sisusb->vramsize <<= 1;
2252 bw = busDDR[(tmp8 & 0x03)];
2256 printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2257 sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
2258 ramtypetext2[ramtype], bw);
2262 sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2264 struct sisusb_packet packet;
2269 packet.header = 0x001f;
2270 packet.address = 0x00000324;
2271 packet.data = 0x00000004;
2272 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2274 packet.header = 0x001f;
2275 packet.address = 0x00000364;
2276 packet.data = 0x00000004;
2277 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2279 packet.header = 0x001f;
2280 packet.address = 0x00000384;
2281 packet.data = 0x00000004;
2282 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2284 packet.header = 0x001f;
2285 packet.address = 0x00000100;
2286 packet.data = 0x00000700;
2287 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2289 packet.header = 0x000f;
2290 packet.address = 0x00000004;
2291 ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2292 packet.data |= 0x17;
2293 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2295 /* Init BAR 0 (VRAM) */
2296 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2297 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2298 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2300 tmp32 |= SISUSB_PCI_MEMBASE;
2301 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2303 /* Init BAR 1 (MMIO) */
2304 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2305 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2306 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2308 tmp32 |= SISUSB_PCI_MMIOBASE;
2309 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2311 /* Init BAR 2 (i/o ports) */
2312 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2313 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2314 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2316 tmp32 |= SISUSB_PCI_IOPORTBASE;
2317 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2319 /* Enable memory and i/o access */
2320 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2322 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2325 /* Some further magic */
2326 packet.header = 0x001f;
2327 packet.address = 0x00000050;
2328 packet.data = 0x000000ff;
2329 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2335 /* Initialize the graphics device (return 0 on success)
2336 * This initializes the net2280 as well as the PCI registers
2337 * of the graphics board.
2341 sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2343 int ret = 0, test = 0;
2346 if (sisusb->devinit == 1) {
2347 /* Read PCI BARs and see if they have been set up */
2348 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2349 if (ret) return ret;
2350 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
2352 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2353 if (ret) return ret;
2354 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2356 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2357 if (ret) return ret;
2358 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2361 /* No? So reset the device */
2362 if ((sisusb->devinit == 0) || (test != 3)) {
2364 ret |= sisusb_do_init_gfxdevice(sisusb);
2367 sisusb->devinit = 1;
2371 if (sisusb->devinit) {
2372 /* Initialize the graphics core */
2373 if (sisusb_init_gfxcore(sisusb) == 0) {
2374 sisusb->gfxinit = 1;
2375 sisusb_get_ramconfig(sisusb);
2376 ret |= sisusb_set_default_mode(sisusb, 1);
2377 ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2385 #ifdef INCL_SISUSB_CON
2387 /* Set up default text mode:
2388 - Set text mode (0x03)
2389 - Upload default font
2390 - Upload user font (if available)
2394 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
2396 int ret = 0, slot = sisusb->font_slot, i;
2397 const struct font_desc *myfont;
2401 static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
2402 static const char bootlogo[] = "(o_ //\\ V_/_";
2404 /* sisusb->lock is down */
2406 if (!sisusb->SiS_Pr)
2409 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2410 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2413 SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
2415 if (!(myfont = find_font("VGA8x16")))
2418 if (!(tempbuf = vmalloc(8192)))
2421 for (i = 0; i < 256; i++)
2422 memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
2424 /* Upload default font */
2425 ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
2429 /* Upload user font (and reset current slot) */
2430 if (sisusb->font_backup) {
2431 ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
2432 8192, sisusb->font_backup_512, 1, NULL,
2433 sisusb->font_backup_height, 0);
2435 sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
2439 if (init && !sisusb->scrbuf) {
2441 if ((tempbuf = vmalloc(8192))) {
2444 tempbufb = (u16 *)tempbuf;
2446 *(tempbufb++) = 0x0720;
2449 tempbufb = (u16 *)tempbuf;
2450 while (bootlogo[i]) {
2451 *(tempbufb++) = 0x0700 | bootlogo[i++];
2457 tempbufb = (u16 *)tempbuf + 6;
2458 while (bootstring[i])
2459 *(tempbufb++) = 0x0700 | bootstring[i++];
2461 ret |= sisusb_copy_memory(sisusb, tempbuf,
2462 sisusb->vrambase, 8192, &written);
2468 } else if (sisusb->scrbuf) {
2470 ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
2471 sisusb->vrambase, sisusb->scrbuf_size, &written);
2475 if (sisusb->sisusb_cursor_size_from >= 0 &&
2476 sisusb->sisusb_cursor_size_to >= 0) {
2477 sisusb_setidxreg(sisusb, SISCR, 0x0a,
2478 sisusb->sisusb_cursor_size_from);
2479 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
2480 sisusb->sisusb_cursor_size_to);
2482 sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
2483 sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
2484 sisusb->sisusb_cursor_size_to = -1;
2487 slot = sisusb->sisusb_cursor_loc;
2488 if(slot < 0) slot = 0;
2490 sisusb->sisusb_cursor_loc = -1;
2491 sisusb->bad_cursor_pos = 1;
2493 sisusb_set_cursor(sisusb, slot);
2495 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
2496 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
2498 sisusb->textmodedestroyed = 0;
2500 /* sisusb->lock is down */
2510 sisusb_open(struct inode *inode, struct file *file)
2512 struct sisusb_usb_data *sisusb;
2513 struct usb_interface *interface;
2514 int subminor = iminor(inode);
2516 mutex_lock(&disconnect_mutex);
2518 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
2519 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
2521 mutex_unlock(&disconnect_mutex);
2525 if (!(sisusb = usb_get_intfdata(interface))) {
2526 mutex_unlock(&disconnect_mutex);
2530 mutex_lock(&sisusb->lock);
2532 if (!sisusb->present || !sisusb->ready) {
2533 mutex_unlock(&sisusb->lock);
2534 mutex_unlock(&disconnect_mutex);
2538 if (sisusb->isopen) {
2539 mutex_unlock(&sisusb->lock);
2540 mutex_unlock(&disconnect_mutex);
2544 if (!sisusb->devinit) {
2545 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2546 if (sisusb_init_gfxdevice(sisusb, 0)) {
2547 mutex_unlock(&sisusb->lock);
2548 mutex_unlock(&disconnect_mutex);
2550 "sisusbvga[%d]: Failed to initialize "
2556 mutex_unlock(&sisusb->lock);
2557 mutex_unlock(&disconnect_mutex);
2559 "sisusbvga[%d]: Device not attached to "
2566 /* Increment usage count for our sisusb */
2567 kref_get(&sisusb->kref);
2571 file->private_data = sisusb;
2573 mutex_unlock(&sisusb->lock);
2575 mutex_unlock(&disconnect_mutex);
2581 sisusb_delete(struct kref *kref)
2583 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2588 if (sisusb->sisusb_dev)
2589 usb_put_dev(sisusb->sisusb_dev);
2591 sisusb->sisusb_dev = NULL;
2592 sisusb_free_buffers(sisusb);
2593 sisusb_free_urbs(sisusb);
2594 #ifdef INCL_SISUSB_CON
2595 kfree(sisusb->SiS_Pr);
2601 sisusb_release(struct inode *inode, struct file *file)
2603 struct sisusb_usb_data *sisusb;
2606 mutex_lock(&disconnect_mutex);
2608 if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
2609 mutex_unlock(&disconnect_mutex);
2613 mutex_lock(&sisusb->lock);
2615 if (sisusb->present) {
2616 /* Wait for all URBs to finish if device still present */
2617 if (!sisusb_wait_all_out_complete(sisusb))
2618 sisusb_kill_all_busy(sisusb);
2621 myminor = sisusb->minor;
2624 file->private_data = NULL;
2626 mutex_unlock(&sisusb->lock);
2628 /* decrement the usage count on our device */
2629 kref_put(&sisusb->kref, sisusb_delete);
2631 mutex_unlock(&disconnect_mutex);
2637 sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2639 struct sisusb_usb_data *sisusb;
2640 ssize_t bytes_read = 0;
2646 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2649 mutex_lock(&sisusb->lock);
2652 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2653 mutex_unlock(&sisusb->lock);
2657 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2658 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2661 SISUSB_PCI_PSEUDO_IOPORTBASE +
2662 SISUSB_PCI_IOPORTBASE;
2665 * Byte, word and long(32) can be read. As this
2666 * emulates inX instructions, the data returned is
2667 * in machine-endianness.
2672 if (sisusb_read_memio_byte(sisusb,
2676 else if (put_user(buf8, (u8 __user *)buffer))
2684 if (sisusb_read_memio_word(sisusb,
2688 else if (put_user(buf16, (u16 __user *)buffer))
2696 if (sisusb_read_memio_long(sisusb,
2700 else if (put_user(buf32, (u32 __user *)buffer))
2712 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2713 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2716 SISUSB_PCI_PSEUDO_MEMBASE +
2720 * Remember: Data delivered is never endian-corrected
2722 errno = sisusb_read_mem_bulk(sisusb, address,
2723 NULL, count, buffer, &bytes_read);
2728 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2729 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2732 SISUSB_PCI_PSEUDO_MMIOBASE +
2733 SISUSB_PCI_MMIOBASE;
2736 * Remember: Data delivered is never endian-corrected
2738 errno = sisusb_read_mem_bulk(sisusb, address,
2739 NULL, count, buffer, &bytes_read);
2744 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2745 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2748 mutex_unlock(&sisusb->lock);
2752 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2754 /* Read PCI config register
2755 * Return value delivered in machine endianness.
2757 if (sisusb_read_pci_config(sisusb, address, &buf32))
2759 else if (put_user(buf32, (u32 __user *)buffer))
2770 (*ppos) += bytes_read;
2772 mutex_unlock(&sisusb->lock);
2774 return errno ? errno : bytes_read;
2778 sisusb_write(struct file *file, const char __user *buffer, size_t count,
2781 struct sisusb_usb_data *sisusb;
2783 ssize_t bytes_written = 0;
2788 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2791 mutex_lock(&sisusb->lock);
2794 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2795 mutex_unlock(&sisusb->lock);
2799 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2800 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2803 SISUSB_PCI_PSEUDO_IOPORTBASE +
2804 SISUSB_PCI_IOPORTBASE;
2807 * Byte, word and long(32) can be written. As this
2808 * emulates outX instructions, the data is expected
2809 * in machine-endianness.
2814 if (get_user(buf8, (u8 __user *)buffer))
2816 else if (sisusb_write_memio_byte(sisusb,
2826 if (get_user(buf16, (u16 __user *)buffer))
2828 else if (sisusb_write_memio_word(sisusb,
2838 if (get_user(buf32, (u32 __user *)buffer))
2840 else if (sisusb_write_memio_long(sisusb,
2853 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2854 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2857 SISUSB_PCI_PSEUDO_MEMBASE +
2861 * Buffer is copied 1:1, therefore, on big-endian
2862 * machines, the data must be swapped by userland
2863 * in advance (if applicable; no swapping in 8bpp
2864 * mode or if YUV data is being transferred).
2866 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2867 count, buffer, 0, &bytes_written);
2870 errno = bytes_written;
2872 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2873 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2876 SISUSB_PCI_PSEUDO_MMIOBASE +
2877 SISUSB_PCI_MMIOBASE;
2880 * Buffer is copied 1:1, therefore, on big-endian
2881 * machines, the data must be swapped by userland
2884 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2885 count, buffer, 0, &bytes_written);
2888 errno = bytes_written;
2890 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2891 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2894 mutex_unlock(&sisusb->lock);
2898 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2900 /* Write PCI config register.
2901 * Given value expected in machine endianness.
2903 if (get_user(buf32, (u32 __user *)buffer))
2905 else if (sisusb_write_pci_config(sisusb, address, buf32))
2918 (*ppos) += bytes_written;
2920 mutex_unlock(&sisusb->lock);
2922 return errno ? errno : bytes_written;
2926 sisusb_lseek(struct file *file, loff_t offset, int orig)
2928 struct sisusb_usb_data *sisusb;
2931 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2934 mutex_lock(&sisusb->lock);
2937 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2938 mutex_unlock(&sisusb->lock);
2944 file->f_pos = offset;
2946 /* never negative, no force_successful_syscall needed */
2949 file->f_pos += offset;
2951 /* never negative, no force_successful_syscall needed */
2954 /* seeking relative to "end of file" is not supported */
2958 mutex_unlock(&sisusb->lock);
2963 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2966 int retval, port, length;
2969 /* All our commands require the device
2970 * to be initialized.
2972 if (!sisusb->devinit)
2976 SISUSB_PCI_PSEUDO_IOPORTBASE +
2977 SISUSB_PCI_IOPORTBASE;
2979 switch (y->operation) {
2981 retval = sisusb_getidxreg(sisusb, port,
2982 y->data0, &y->data1);
2984 if (copy_to_user((void __user *)arg, y,
2991 retval = sisusb_setidxreg(sisusb, port,
2992 y->data0, y->data1);
2996 retval = sisusb_setidxregor(sisusb, port,
2997 y->data0, y->data1);
3001 retval = sisusb_setidxregand(sisusb, port,
3002 y->data0, y->data1);
3005 case SUCMD_SETANDOR:
3006 retval = sisusb_setidxregandor(sisusb, port,
3007 y->data0, y->data1, y->data2);
3011 retval = sisusb_setidxregmask(sisusb, port,
3012 y->data0, y->data1, y->data2);
3016 /* Gfx core must be initialized */
3017 if (!sisusb->gfxinit)
3020 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
3021 address = y->data3 -
3022 SISUSB_PCI_PSEUDO_MEMBASE +
3024 retval = sisusb_clear_vram(sisusb, address, length);
3027 case SUCMD_HANDLETEXTMODE:
3029 #ifdef INCL_SISUSB_CON
3030 /* Gfx core must be initialized, SiS_Pr must exist */
3031 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3036 retval = sisusb_reset_text_mode(sisusb, 0);
3039 sisusb->textmodedestroyed = 1;
3045 #ifdef INCL_SISUSB_CON
3047 /* Gfx core must be initialized, SiS_Pr must exist */
3048 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3053 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3054 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3056 if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
3061 case SUCMD_SETVESAMODE:
3062 /* Gfx core must be initialized, SiS_Pr must exist */
3063 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3068 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3069 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3071 if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
3088 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
3091 struct sisusb_usb_data *sisusb;
3092 struct sisusb_info x;
3093 struct sisusb_command y;
3095 u32 __user *argp = (u32 __user *)arg;
3097 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
3100 mutex_lock(&sisusb->lock);
3103 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
3110 case SISUSB_GET_CONFIG_SIZE:
3112 if (put_user(sizeof(x), argp))
3117 case SISUSB_GET_CONFIG:
3119 x.sisusb_id = SISUSB_ID;
3120 x.sisusb_version = SISUSB_VERSION;
3121 x.sisusb_revision = SISUSB_REVISION;
3122 x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
3123 x.sisusb_gfxinit = sisusb->gfxinit;
3124 x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
3125 x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
3126 x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
3127 x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
3128 x.sisusb_vramsize = sisusb->vramsize;
3129 x.sisusb_minor = sisusb->minor;
3130 x.sisusb_fbdevactive= 0;
3131 #ifdef INCL_SISUSB_CON
3132 x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
3134 x.sisusb_conactive = 0;
3137 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
3142 case SISUSB_COMMAND:
3144 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
3147 retval = sisusb_handle_command(sisusb, &y, arg);
3157 mutex_unlock(&sisusb->lock);
3161 #ifdef SISUSB_NEW_CONFIG_COMPAT
3163 sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
3168 case SISUSB_GET_CONFIG_SIZE:
3169 case SISUSB_GET_CONFIG:
3170 case SISUSB_COMMAND:
3172 retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
3177 return -ENOIOCTLCMD;
3182 static struct file_operations usb_sisusb_fops = {
3183 .owner = THIS_MODULE,
3184 .open = sisusb_open,
3185 .release = sisusb_release,
3186 .read = sisusb_read,
3187 .write = sisusb_write,
3188 .llseek = sisusb_lseek,
3189 #ifdef SISUSB_NEW_CONFIG_COMPAT
3190 .compat_ioctl = sisusb_compat_ioctl,
3192 .ioctl = sisusb_ioctl
3195 static struct usb_class_driver usb_sisusb_class = {
3196 .name = "sisusbvga%d",
3197 .fops = &usb_sisusb_fops,
3198 .minor_base = SISUSB_MINOR
3201 static int sisusb_probe(struct usb_interface *intf,
3202 const struct usb_device_id *id)
3204 struct usb_device *dev = interface_to_usbdev(intf);
3205 struct sisusb_usb_data *sisusb;
3207 const char *memfail =
3209 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
3211 printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
3214 /* Allocate memory for our private */
3215 if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
3217 "sisusb: Failed to allocate memory for private data\n");
3220 kref_init(&sisusb->kref);
3222 mutex_init(&(sisusb->lock));
3224 /* Register device */
3225 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
3227 "sisusb: Failed to get a minor for device %d\n",
3233 sisusb->sisusb_dev = dev;
3234 sisusb->minor = intf->minor;
3235 sisusb->vrambase = SISUSB_PCI_MEMBASE;
3236 sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
3237 sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
3238 sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
3239 /* Everything else is zero */
3241 /* Allocate buffers */
3242 sisusb->ibufsize = SISUSB_IBUF_SIZE;
3243 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
3244 GFP_KERNEL, &sisusb->transfer_dma_in))) {
3245 printk(memfail, "input", sisusb->minor);
3250 sisusb->numobufs = 0;
3251 sisusb->obufsize = SISUSB_OBUF_SIZE;
3252 for (i = 0; i < NUMOBUFS; i++) {
3253 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
3255 &sisusb->transfer_dma_out[i]))) {
3257 printk(memfail, "output", sisusb->minor);
3268 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
3270 "sisusbvga[%d]: Failed to allocate URBs\n",
3275 sisusb->completein = 1;
3277 for (i = 0; i < sisusb->numobufs; i++) {
3278 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
3280 "sisusbvga[%d]: Failed to allocate URBs\n",
3285 sisusb->urbout_context[i].sisusb = (void *)sisusb;
3286 sisusb->urbout_context[i].urbindex = i;
3287 sisusb->urbstatus[i] = 0;
3290 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
3291 sisusb->minor, sisusb->numobufs);
3293 #ifdef INCL_SISUSB_CON
3294 /* Allocate our SiS_Pr */
3295 if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
3297 "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
3302 /* Do remaining init stuff */
3304 init_waitqueue_head(&sisusb->wait_q);
3306 usb_set_intfdata(intf, sisusb);
3308 usb_get_dev(sisusb->sisusb_dev);
3310 sisusb->present = 1;
3312 #ifdef SISUSB_OLD_CONFIG_COMPAT
3315 /* Our ioctls are all "32/64bit compatible" */
3316 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3317 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3318 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3321 "sisusbvga[%d]: Error registering ioctl32 "
3325 sisusb->ioctl32registered = 1;
3329 if (dev->speed == USB_SPEED_HIGH) {
3331 #ifdef INCL_SISUSB_CON
3332 if (sisusb_first_vc > 0 &&
3333 sisusb_last_vc > 0 &&
3334 sisusb_first_vc <= sisusb_last_vc &&
3335 sisusb_last_vc <= MAX_NR_CONSOLES)
3338 if (sisusb_init_gfxdevice(sisusb, initscreen))
3340 "sisusbvga[%d]: Failed to early "
3341 "initialize device\n",
3346 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3352 #ifdef SISUSBENDIANTEST
3353 printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
3354 sisusb_testreadwrite(sisusb);
3355 printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
3358 #ifdef INCL_SISUSB_CON
3359 sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
3365 sisusb_free_urbs(sisusb);
3367 sisusb_free_buffers(sisusb);
3369 usb_deregister_dev(intf, &usb_sisusb_class);
3375 static void sisusb_disconnect(struct usb_interface *intf)
3377 struct sisusb_usb_data *sisusb;
3380 /* This should *not* happen */
3381 if (!(sisusb = usb_get_intfdata(intf)))
3384 #ifdef INCL_SISUSB_CON
3385 sisusb_console_exit(sisusb);
3388 /* The above code doesn't need the disconnect
3389 * semaphore to be down; its meaning is to
3390 * protect all other routines from the disconnect
3391 * case, not the other way round.
3393 mutex_lock(&disconnect_mutex);
3395 mutex_lock(&sisusb->lock);
3397 /* Wait for all URBs to complete and kill them in case (MUST do) */
3398 if (!sisusb_wait_all_out_complete(sisusb))
3399 sisusb_kill_all_busy(sisusb);
3401 minor = sisusb->minor;
3403 usb_set_intfdata(intf, NULL);
3405 usb_deregister_dev(intf, &usb_sisusb_class);
3407 #ifdef SISUSB_OLD_CONFIG_COMPAT
3408 if (sisusb->ioctl32registered) {
3410 sisusb->ioctl32registered = 0;
3411 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3412 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3413 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3416 "sisusbvga[%d]: Error unregistering "
3417 "ioctl32 translations\n",
3423 sisusb->present = 0;
3426 mutex_unlock(&sisusb->lock);
3428 /* decrement our usage count */
3429 kref_put(&sisusb->kref, sisusb_delete);
3431 mutex_unlock(&disconnect_mutex);
3433 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
3436 static struct usb_device_id sisusb_table [] = {
3437 { USB_DEVICE(0x0711, 0x0900) },
3438 { USB_DEVICE(0x182d, 0x021c) },
3439 { USB_DEVICE(0x182d, 0x0269) },
3443 MODULE_DEVICE_TABLE (usb, sisusb_table);
3445 static struct usb_driver sisusb_driver = {
3447 .probe = sisusb_probe,
3448 .disconnect = sisusb_disconnect,
3449 .id_table = sisusb_table,
3452 static int __init usb_sisusb_init(void)
3456 #ifdef INCL_SISUSB_CON
3457 sisusb_init_concode();
3460 if (!(retval = usb_register(&sisusb_driver))) {
3462 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3463 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3465 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3472 static void __exit usb_sisusb_exit(void)
3474 usb_deregister(&sisusb_driver);
3477 module_init(usb_sisusb_init);
3478 module_exit(usb_sisusb_exit);
3480 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3481 MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
3482 MODULE_LICENSE("GPL");