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/errno.h>
44 #include <linux/poll.h>
45 #include <linux/init.h>
46 #include <linux/slab.h>
47 #include <linux/spinlock.h>
48 #include <linux/kref.h>
49 #include <linux/usb.h>
50 #include <linux/smp_lock.h>
51 #include <linux/vmalloc.h>
54 #include "sisusb_init.h"
56 #ifdef INCL_SISUSB_CON
57 #include <linux/font.h>
60 #define SISUSB_DONTSYNC
62 /* Forward declarations / clean-up routines */
64 #ifdef INCL_SISUSB_CON
65 static int sisusb_first_vc = 0;
66 static int sisusb_last_vc = 0;
67 module_param_named(first, sisusb_first_vc, int, 0);
68 module_param_named(last, sisusb_last_vc, int, 0);
69 MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)");
70 MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)");
73 static struct usb_driver sisusb_driver;
76 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
80 for (i = 0; i < NUMOBUFS; i++) {
81 if (sisusb->obuf[i]) {
82 usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize,
83 sisusb->obuf[i], sisusb->transfer_dma_out[i]);
84 sisusb->obuf[i] = NULL;
88 usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
89 sisusb->ibuf, sisusb->transfer_dma_in);
95 sisusb_free_urbs(struct sisusb_usb_data *sisusb)
99 for (i = 0; i < NUMOBUFS; i++) {
100 usb_free_urb(sisusb->sisurbout[i]);
101 sisusb->sisurbout[i] = NULL;
103 usb_free_urb(sisusb->sisurbin);
104 sisusb->sisurbin = NULL;
107 /* Level 0: USB transport layer */
111 /* out-urb management */
113 /* Return 1 if all free, 0 otherwise */
115 sisusb_all_free(struct sisusb_usb_data *sisusb)
119 for (i = 0; i < sisusb->numobufs; i++) {
121 if (sisusb->urbstatus[i] & SU_URB_BUSY)
129 /* Kill all busy URBs */
131 sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
135 if (sisusb_all_free(sisusb))
138 for (i = 0; i < sisusb->numobufs; i++) {
140 if (sisusb->urbstatus[i] & SU_URB_BUSY)
141 usb_kill_urb(sisusb->sisurbout[i]);
146 /* Return 1 if ok, 0 if error (not all complete within timeout) */
148 sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
150 int timeout = 5 * HZ, i = 1;
152 wait_event_timeout(sisusb->wait_q,
153 (i = sisusb_all_free(sisusb)),
160 sisusb_outurb_available(struct sisusb_usb_data *sisusb)
164 for (i = 0; i < sisusb->numobufs; i++) {
166 if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
175 sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
177 int i, timeout = 5 * HZ;
179 wait_event_timeout(sisusb->wait_q,
180 ((i = sisusb_outurb_available(sisusb)) >= 0),
187 sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
191 i = sisusb_outurb_available(sisusb);
194 sisusb->urbstatus[i] |= SU_URB_ALLOC;
200 sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
202 if ((index >= 0) && (index < sisusb->numobufs))
203 sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
206 /* completion callback */
209 sisusb_bulk_completeout(struct urb *urb)
211 struct sisusb_urb_context *context = urb->context;
212 struct sisusb_usb_data *sisusb;
217 sisusb = context->sisusb;
219 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
222 #ifndef SISUSB_DONTSYNC
223 if (context->actual_length)
224 *(context->actual_length) += urb->actual_length;
227 sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
228 wake_up(&sisusb->wait_q);
232 sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
233 int len, int *actual_length, int timeout, unsigned int tflags,
234 dma_addr_t transfer_dma)
236 struct urb *urb = sisusb->sisurbout[index];
237 int retval, byteswritten = 0;
240 urb->transfer_flags = 0;
242 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
243 sisusb_bulk_completeout, &sisusb->urbout_context[index]);
245 urb->transfer_flags |= tflags;
246 urb->actual_length = 0;
248 if ((urb->transfer_dma = transfer_dma))
249 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
252 sisusb->urbout_context[index].actual_length = (timeout) ?
253 NULL : actual_length;
255 /* Declare this urb/buffer in use */
256 sisusb->urbstatus[index] |= SU_URB_BUSY;
259 retval = usb_submit_urb(urb, GFP_ATOMIC);
261 /* If OK, and if timeout > 0, wait for completion */
262 if ((retval == 0) && timeout) {
263 wait_event_timeout(sisusb->wait_q,
264 (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
266 if (sisusb->urbstatus[index] & SU_URB_BUSY) {
267 /* URB timed out... kill it and report error */
271 /* Otherwise, report urb status */
272 retval = urb->status;
273 byteswritten = urb->actual_length;
278 *actual_length = byteswritten;
285 /* completion callback */
288 sisusb_bulk_completein(struct urb *urb)
290 struct sisusb_usb_data *sisusb = urb->context;
292 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
295 sisusb->completein = 1;
296 wake_up(&sisusb->wait_q);
300 sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len,
301 int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma)
303 struct urb *urb = sisusb->sisurbin;
304 int retval, readbytes = 0;
306 urb->transfer_flags = 0;
308 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
309 sisusb_bulk_completein, sisusb);
311 urb->transfer_flags |= tflags;
312 urb->actual_length = 0;
314 if ((urb->transfer_dma = transfer_dma))
315 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
317 sisusb->completein = 0;
318 retval = usb_submit_urb(urb, GFP_ATOMIC);
320 wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
321 if (!sisusb->completein) {
322 /* URB timed out... kill it and report error */
326 /* URB completed within timout */
327 retval = urb->status;
328 readbytes = urb->actual_length;
333 *actual_length = readbytes;
341 /* Send a bulk message of variable size
343 * To copy the data from userspace, give pointer to "userbuffer",
344 * to copy from (non-DMA) kernel memory, give "kernbuffer". If
345 * both of these are NULL, it is assumed, that the transfer
346 * buffer "sisusb->obuf[index]" is set up with the data to send.
347 * Index is ignored if either kernbuffer or userbuffer is set.
348 * If async is nonzero, URBs will be sent without waiting for
349 * completion of the previous URB.
351 * (return 0 on success)
354 static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
355 char *kernbuffer, const char __user *userbuffer, int index,
356 ssize_t *bytes_written, unsigned int tflags, int async)
358 int result = 0, retry, count = len;
359 int passsize, thispass, transferred_len = 0;
360 int fromuser = (userbuffer != NULL) ? 1 : 0;
361 int fromkern = (kernbuffer != NULL) ? 1 : 0;
365 (*bytes_written) = 0;
368 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
371 /* If we copy data from kernel or userspace, force the
372 * allocation of a buffer/urb. If we have the data in
373 * the transfer buffer[index] already, reuse the buffer/URB
374 * if the length is > buffer size. (So, transmitting
375 * large data amounts directly from the transfer buffer
376 * treats the buffer as a ring buffer. However, we need
377 * to sync in this case.)
379 if (fromuser || fromkern)
381 else if (len > sisusb->obufsize)
384 pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
387 passsize = thispass = (sisusb->obufsize < count) ?
388 sisusb->obufsize : count;
391 index = sisusb_get_free_outbuf(sisusb);
396 buffer = sisusb->obuf[index];
400 if (copy_from_user(buffer, userbuffer, passsize))
403 userbuffer += passsize;
405 } else if (fromkern) {
407 memcpy(buffer, kernbuffer, passsize);
408 kernbuffer += passsize;
415 if (!sisusb->sisusb_dev)
418 result = sisusb_bulkout_msg(sisusb,
426 sisusb->transfer_dma_out[index]);
428 if (result == -ETIMEDOUT) {
430 /* Will not happen if async */
436 } else if ((result == 0) && !async && transferred_len) {
438 thispass -= transferred_len;
440 if (sisusb->transfer_dma_out) {
441 /* If DMA, copy remaining
442 * to beginning of buffer
445 buffer + transferred_len,
448 /* If not DMA, simply increase
451 buffer += transferred_len;
462 (*bytes_written) += passsize;
465 /* Force new allocation in next iteration */
466 if (fromuser || fromkern)
472 #ifdef SISUSB_DONTSYNC
473 (*bytes_written) = len;
474 /* Some URBs/buffers might be busy */
476 sisusb_wait_all_out_complete(sisusb);
477 (*bytes_written) = transferred_len;
478 /* All URBs and all buffers are available */
482 return ((*bytes_written) == len) ? 0 : -EIO;
485 /* Receive a bulk message of variable size
487 * To copy the data to userspace, give pointer to "userbuffer",
488 * to copy to kernel memory, give "kernbuffer". One of them
489 * MUST be set. (There is no technique for letting the caller
490 * read directly from the ibuf.)
494 static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
495 void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
498 int result = 0, retry, count = len;
499 int bufsize, thispass, transferred_len;
506 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
509 pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
510 buffer = sisusb->ibuf;
511 bufsize = sisusb->ibufsize;
515 #ifdef SISUSB_DONTSYNC
516 if (!(sisusb_wait_all_out_complete(sisusb)))
522 if (!sisusb->sisusb_dev)
525 thispass = (bufsize < count) ? bufsize : count;
527 result = sisusb_bulkin_msg(sisusb,
534 sisusb->transfer_dma_in);
537 thispass = transferred_len;
539 else if (result == -ETIMEDOUT) {
552 (*bytes_read) += thispass;
557 if (copy_to_user(userbuffer, buffer, thispass))
560 userbuffer += thispass;
564 memcpy(kernbuffer, buffer, thispass);
565 kernbuffer += thispass;
573 return ((*bytes_read) == len) ? 0 : -EIO;
576 static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
577 struct sisusb_packet *packet)
580 ssize_t bytes_transferred = 0;
586 #ifdef SISUSB_DONTSYNC
587 if (!(sisusb_wait_all_out_complete(sisusb)))
591 /* Eventually correct endianness */
592 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
594 /* 1. send the packet */
595 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
596 (char *)packet, NULL, 0, &bytes_transferred, 0, 0);
598 if ((ret == 0) && (len == 6)) {
600 /* 2. if packet len == 6, it means we read, so wait for 32bit
601 * return value and write it to packet->data
603 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
604 (char *)&tmp, NULL, &bytes_transferred, 0);
606 packet->data = le32_to_cpu(tmp);
612 static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
613 struct sisusb_packet *packet,
617 ssize_t bytes_transferred = 0;
623 #ifdef SISUSB_DONTSYNC
624 if (!(sisusb_wait_all_out_complete(sisusb)))
628 /* Eventually correct endianness */
629 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
631 /* 1. send the packet */
632 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
633 (char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
635 if ((ret == 0) && (len == 6)) {
637 /* 2. if packet len == 6, it means we read, so wait for 32bit
638 * return value and write it to packet->data
640 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
641 (char *)&tmp, NULL, &bytes_transferred, 0);
643 packet->data = le32_to_cpu(tmp);
649 /* access video memory and mmio (return 0 on success) */
653 /* The following routines assume being used to transfer byte, word,
656 * - the write routines expect "data" in machine endianness format.
657 * The data will be converted to leXX in sisusb_xxx_packet.
658 * - the read routines can expect read data in machine-endianess.
661 static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
664 struct sisusb_packet packet;
667 packet.header = (1 << (addr & 3)) | (type << 6);
668 packet.address = addr & ~3;
669 packet.data = data << ((addr & 3) << 3);
670 ret = sisusb_send_packet(sisusb, 10, &packet);
674 static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
677 struct sisusb_packet packet;
680 packet.address = addr & ~3;
684 packet.header = (type << 6) | 0x0003;
685 packet.data = (u32)data;
686 ret = sisusb_send_packet(sisusb, 10, &packet);
689 packet.header = (type << 6) | 0x0006;
690 packet.data = (u32)data << 8;
691 ret = sisusb_send_packet(sisusb, 10, &packet);
694 packet.header = (type << 6) | 0x000c;
695 packet.data = (u32)data << 16;
696 ret = sisusb_send_packet(sisusb, 10, &packet);
699 packet.header = (type << 6) | 0x0008;
700 packet.data = (u32)data << 24;
701 ret = sisusb_send_packet(sisusb, 10, &packet);
702 packet.header = (type << 6) | 0x0001;
703 packet.address = (addr & ~3) + 4;
704 packet.data = (u32)data >> 8;
705 ret |= sisusb_send_packet(sisusb, 10, &packet);
711 static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
714 struct sisusb_packet packet;
717 packet.address = addr & ~3;
721 packet.header = (type << 6) | 0x0007;
722 packet.data = data & 0x00ffffff;
723 ret = sisusb_send_packet(sisusb, 10, &packet);
726 packet.header = (type << 6) | 0x000e;
727 packet.data = data << 8;
728 ret = sisusb_send_packet(sisusb, 10, &packet);
731 packet.header = (type << 6) | 0x000c;
732 packet.data = data << 16;
733 ret = sisusb_send_packet(sisusb, 10, &packet);
734 packet.header = (type << 6) | 0x0001;
735 packet.address = (addr & ~3) + 4;
736 packet.data = (data >> 16) & 0x00ff;
737 ret |= sisusb_send_packet(sisusb, 10, &packet);
740 packet.header = (type << 6) | 0x0008;
741 packet.data = data << 24;
742 ret = sisusb_send_packet(sisusb, 10, &packet);
743 packet.header = (type << 6) | 0x0003;
744 packet.address = (addr & ~3) + 4;
745 packet.data = (data >> 8) & 0xffff;
746 ret |= sisusb_send_packet(sisusb, 10, &packet);
752 static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
755 struct sisusb_packet packet;
758 packet.address = addr & ~3;
762 packet.header = (type << 6) | 0x000f;
764 ret = sisusb_send_packet(sisusb, 10, &packet);
767 packet.header = (type << 6) | 0x000e;
768 packet.data = data << 8;
769 ret = sisusb_send_packet(sisusb, 10, &packet);
770 packet.header = (type << 6) | 0x0001;
771 packet.address = (addr & ~3) + 4;
772 packet.data = data >> 24;
773 ret |= sisusb_send_packet(sisusb, 10, &packet);
776 packet.header = (type << 6) | 0x000c;
777 packet.data = data << 16;
778 ret = sisusb_send_packet(sisusb, 10, &packet);
779 packet.header = (type << 6) | 0x0003;
780 packet.address = (addr & ~3) + 4;
781 packet.data = data >> 16;
782 ret |= sisusb_send_packet(sisusb, 10, &packet);
785 packet.header = (type << 6) | 0x0008;
786 packet.data = data << 24;
787 ret = sisusb_send_packet(sisusb, 10, &packet);
788 packet.header = (type << 6) | 0x0007;
789 packet.address = (addr & ~3) + 4;
790 packet.data = data >> 8;
791 ret |= sisusb_send_packet(sisusb, 10, &packet);
797 /* The xxx_bulk routines copy a buffer of variable size. They treat the
798 * buffer as chars, therefore lsb/msb has to be corrected if using the
799 * byte/word/long/etc routines for speed-up
801 * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
802 * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
803 * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
804 * that the data already is in the transfer buffer "sisusb->obuf[index]".
807 static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
808 char *kernbuffer, int length,
809 const char __user *userbuffer, int index,
810 ssize_t *bytes_written)
812 struct sisusb_packet packet;
814 static int msgcount = 0;
815 u8 swap8, fromkern = kernbuffer ? 1 : 0;
817 u32 swap32, flag = (length >> 28) & 1;
820 /* if neither kernbuffer not userbuffer are given, assume
823 if (!fromkern && !userbuffer)
824 kernbuffer = sisusb->obuf[index];
826 (*bytes_written = 0);
828 length &= 0x00ffffff;
836 if (get_user(swap8, (u8 __user *)userbuffer))
839 swap8 = kernbuffer[0];
841 ret = sisusb_write_memio_byte(sisusb,
852 if (get_user(swap16, (u16 __user *)userbuffer))
855 swap16 = *((u16 *)kernbuffer);
857 ret = sisusb_write_memio_word(sisusb,
863 (*bytes_written) += 2;
869 if (copy_from_user(&buf, userbuffer, 3))
872 swap32 = (buf[0] << 16) |
876 swap32 = (buf[2] << 16) |
882 swap32 = (kernbuffer[0] << 16) |
883 (kernbuffer[1] << 8) |
886 swap32 = (kernbuffer[2] << 16) |
887 (kernbuffer[1] << 8) |
891 ret = sisusb_write_memio_24bit(sisusb,
897 (*bytes_written) += 3;
903 if (get_user(swap32, (u32 __user *)userbuffer))
906 swap32 = *((u32 *)kernbuffer);
908 ret = sisusb_write_memio_long(sisusb,
913 (*bytes_written) += 4;
918 if ((length & ~3) > 0x10000) {
920 packet.header = 0x001f;
921 packet.address = 0x000001d4;
923 ret = sisusb_send_bridge_packet(sisusb, 10,
925 packet.header = 0x001f;
926 packet.address = 0x000001d0;
927 packet.data = (length & ~3);
928 ret |= sisusb_send_bridge_packet(sisusb, 10,
930 packet.header = 0x001f;
931 packet.address = 0x000001c0;
932 packet.data = flag | 0x16;
933 ret |= sisusb_send_bridge_packet(sisusb, 10,
936 ret |= sisusb_send_bulk_msg(sisusb,
937 SISUSB_EP_GFX_LBULK_OUT,
940 bytes_written, 0, 1);
941 userbuffer += (*bytes_written);
942 } else if (fromkern) {
943 ret |= sisusb_send_bulk_msg(sisusb,
944 SISUSB_EP_GFX_LBULK_OUT,
947 bytes_written, 0, 1);
948 kernbuffer += (*bytes_written);
950 ret |= sisusb_send_bulk_msg(sisusb,
951 SISUSB_EP_GFX_LBULK_OUT,
954 bytes_written, 0, 1);
955 kernbuffer += ((*bytes_written) &
956 (sisusb->obufsize-1));
961 packet.header = 0x001f;
962 packet.address = 0x00000194;
964 ret = sisusb_send_bridge_packet(sisusb, 10,
966 packet.header = 0x001f;
967 packet.address = 0x00000190;
968 packet.data = (length & ~3);
969 ret |= sisusb_send_bridge_packet(sisusb, 10,
971 if (sisusb->flagb0 != 0x16) {
972 packet.header = 0x001f;
973 packet.address = 0x00000180;
974 packet.data = flag | 0x16;
975 ret |= sisusb_send_bridge_packet(sisusb, 10,
977 sisusb->flagb0 = 0x16;
980 ret |= sisusb_send_bulk_msg(sisusb,
981 SISUSB_EP_GFX_BULK_OUT,
984 bytes_written, 0, 1);
985 userbuffer += (*bytes_written);
986 } else if (fromkern) {
987 ret |= sisusb_send_bulk_msg(sisusb,
988 SISUSB_EP_GFX_BULK_OUT,
991 bytes_written, 0, 1);
992 kernbuffer += (*bytes_written);
994 ret |= sisusb_send_bulk_msg(sisusb,
995 SISUSB_EP_GFX_BULK_OUT,
998 bytes_written, 0, 1);
999 kernbuffer += ((*bytes_written) &
1000 (sisusb->obufsize-1));
1007 "sisusbvga[%d]: Wrote %zd of "
1008 "%d bytes, error %d\n",
1009 sisusb->minor, *bytes_written,
1011 else if (msgcount == 500)
1013 "sisusbvga[%d]: Too many errors"
1014 ", logging stopped\n",
1017 addr += (*bytes_written);
1018 length -= (*bytes_written);
1026 return ret ? -EIO : 0;
1029 /* Remember: Read data in packet is in machine-endianess! So for
1030 * byte, word, 24bit, long no endian correction is necessary.
1033 static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1036 struct sisusb_packet packet;
1039 CLEARPACKET(&packet);
1040 packet.header = (1 << (addr & 3)) | (type << 6);
1041 packet.address = addr & ~3;
1042 ret = sisusb_send_packet(sisusb, 6, &packet);
1043 *data = (u8)(packet.data >> ((addr & 3) << 3));
1047 static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1048 u32 addr, u16 *data)
1050 struct sisusb_packet packet;
1053 CLEARPACKET(&packet);
1055 packet.address = addr & ~3;
1059 packet.header = (type << 6) | 0x0003;
1060 ret = sisusb_send_packet(sisusb, 6, &packet);
1061 *data = (u16)(packet.data);
1064 packet.header = (type << 6) | 0x0006;
1065 ret = sisusb_send_packet(sisusb, 6, &packet);
1066 *data = (u16)(packet.data >> 8);
1069 packet.header = (type << 6) | 0x000c;
1070 ret = sisusb_send_packet(sisusb, 6, &packet);
1071 *data = (u16)(packet.data >> 16);
1074 packet.header = (type << 6) | 0x0008;
1075 ret = sisusb_send_packet(sisusb, 6, &packet);
1076 *data = (u16)(packet.data >> 24);
1077 packet.header = (type << 6) | 0x0001;
1078 packet.address = (addr & ~3) + 4;
1079 ret |= sisusb_send_packet(sisusb, 6, &packet);
1080 *data |= (u16)(packet.data << 8);
1086 static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1087 u32 addr, u32 *data)
1089 struct sisusb_packet packet;
1092 packet.address = addr & ~3;
1096 packet.header = (type << 6) | 0x0007;
1097 ret = sisusb_send_packet(sisusb, 6, &packet);
1098 *data = packet.data & 0x00ffffff;
1101 packet.header = (type << 6) | 0x000e;
1102 ret = sisusb_send_packet(sisusb, 6, &packet);
1103 *data = packet.data >> 8;
1106 packet.header = (type << 6) | 0x000c;
1107 ret = sisusb_send_packet(sisusb, 6, &packet);
1108 *data = packet.data >> 16;
1109 packet.header = (type << 6) | 0x0001;
1110 packet.address = (addr & ~3) + 4;
1111 ret |= sisusb_send_packet(sisusb, 6, &packet);
1112 *data |= ((packet.data & 0xff) << 16);
1115 packet.header = (type << 6) | 0x0008;
1116 ret = sisusb_send_packet(sisusb, 6, &packet);
1117 *data = packet.data >> 24;
1118 packet.header = (type << 6) | 0x0003;
1119 packet.address = (addr & ~3) + 4;
1120 ret |= sisusb_send_packet(sisusb, 6, &packet);
1121 *data |= ((packet.data & 0xffff) << 8);
1127 static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1128 u32 addr, u32 *data)
1130 struct sisusb_packet packet;
1133 packet.address = addr & ~3;
1137 packet.header = (type << 6) | 0x000f;
1138 ret = sisusb_send_packet(sisusb, 6, &packet);
1139 *data = packet.data;
1142 packet.header = (type << 6) | 0x000e;
1143 ret = sisusb_send_packet(sisusb, 6, &packet);
1144 *data = packet.data >> 8;
1145 packet.header = (type << 6) | 0x0001;
1146 packet.address = (addr & ~3) + 4;
1147 ret |= sisusb_send_packet(sisusb, 6, &packet);
1148 *data |= (packet.data << 24);
1151 packet.header = (type << 6) | 0x000c;
1152 ret = sisusb_send_packet(sisusb, 6, &packet);
1153 *data = packet.data >> 16;
1154 packet.header = (type << 6) | 0x0003;
1155 packet.address = (addr & ~3) + 4;
1156 ret |= sisusb_send_packet(sisusb, 6, &packet);
1157 *data |= (packet.data << 16);
1160 packet.header = (type << 6) | 0x0008;
1161 ret = sisusb_send_packet(sisusb, 6, &packet);
1162 *data = packet.data >> 24;
1163 packet.header = (type << 6) | 0x0007;
1164 packet.address = (addr & ~3) + 4;
1165 ret |= sisusb_send_packet(sisusb, 6, &packet);
1166 *data |= (packet.data << 8);
1172 static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1173 char *kernbuffer, int length,
1174 char __user *userbuffer, ssize_t *bytes_read)
1183 length &= 0x00ffffff;
1191 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1196 if (put_user(buf[0],
1197 (u8 __user *)userbuffer)) {
1201 kernbuffer[0] = buf[0];
1207 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1212 if (put_user(swap16,
1213 (u16 __user *)userbuffer))
1216 *((u16 *)kernbuffer) = swap16;
1222 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1227 buf[0] = (swap32 >> 16) & 0xff;
1228 buf[1] = (swap32 >> 8) & 0xff;
1229 buf[2] = swap32 & 0xff;
1231 buf[2] = (swap32 >> 16) & 0xff;
1232 buf[1] = (swap32 >> 8) & 0xff;
1233 buf[0] = swap32 & 0xff;
1236 if (copy_to_user(userbuffer, &buf[0], 3))
1239 kernbuffer[0] = buf[0];
1240 kernbuffer[1] = buf[1];
1241 kernbuffer[2] = buf[2];
1247 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1252 if (put_user(swap32,
1253 (u32 __user *)userbuffer))
1258 *((u32 *)kernbuffer) = swap32;
1273 /* High level: Gfx (indexed) register access */
1275 #ifdef INCL_SISUSB_CON
1277 sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
1279 return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1283 sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
1285 return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1290 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1293 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1294 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1299 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1302 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1303 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1308 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1314 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1315 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1318 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1323 sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1328 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1329 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1331 tmp |= (data & mask);
1332 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1337 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1339 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1343 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1345 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1348 /* Write/read video ram */
1350 #ifdef INCL_SISUSB_CON
1352 sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
1354 return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1358 sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
1360 return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1364 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
1365 u32 dest, int length, size_t *bytes_written)
1367 return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
1370 #ifdef SISUSBENDIANTEST
1372 sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
1373 u32 src, int length, size_t *bytes_written)
1375 return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
1380 #ifdef SISUSBENDIANTEST
1382 sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
1384 static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
1385 char destbuffer[10];
1389 sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
1391 for(i = 1; i <= 7; i++) {
1392 printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
1393 sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
1394 for(j = 0; j < i; j++) {
1395 printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
1401 /* access pci config registers (reg numbers 0, 4, 8, etc) */
1404 sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1406 struct sisusb_packet packet;
1409 packet.header = 0x008f;
1410 packet.address = regnum | 0x10000;
1412 ret = sisusb_send_packet(sisusb, 10, &packet);
1417 sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1419 struct sisusb_packet packet;
1422 packet.header = 0x008f;
1423 packet.address = (u32)regnum | 0x10000;
1424 ret = sisusb_send_packet(sisusb, 6, &packet);
1425 *data = packet.data;
1429 /* Clear video RAM */
1432 sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1437 if (address < sisusb->vrambase)
1440 if (address >= sisusb->vrambase + sisusb->vramsize)
1443 if (address + length > sisusb->vrambase + sisusb->vramsize)
1444 length = sisusb->vrambase + sisusb->vramsize - address;
1449 /* allocate free buffer/urb and clear the buffer */
1450 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1453 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1455 /* We can write a length > buffer size here. The buffer
1456 * data will simply be re-used (like a ring-buffer).
1458 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1460 /* Free the buffer/urb */
1461 sisusb_free_outbuf(sisusb, i);
1466 /* Initialize the graphics core (return 0 on success)
1467 * This resets the graphics hardware and puts it into
1468 * a defined mode (640x480@60Hz)
1471 #define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1472 #define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1473 #define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
1474 #define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
1475 #define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
1476 #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
1477 #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
1478 #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1479 #define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1480 #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1481 #define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1484 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1489 ret = GETIREG(SISSR, 0x16, &tmp8);
1492 ret |= SETIREG(SISSR, 0x16, tmp8);
1494 ret |= SETIREG(SISSR, 0x16, tmp8);
1497 ret |= SETIREG(SISSR, 0x16, tmp8);
1499 ret |= SETIREG(SISSR, 0x16, tmp8);
1501 ret |= SETIREG(SISSR, 0x16, tmp8);
1503 ret |= SETIREG(SISSR, 0x16, tmp8);
1505 ret |= SETIREG(SISSR, 0x16, tmp8);
1507 ret |= SETIREG(SISSR, 0x16, tmp8);
1509 ret |= SETIREG(SISSR, 0x16, tmp8);
1515 sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1518 u8 ramtype, done = 0;
1520 u32 ramptr = SISUSB_PCI_MEMBASE;
1522 ret = GETIREG(SISSR, 0x3a, &ramtype);
1525 ret |= SETIREG(SISSR, 0x13, 0x00);
1528 ret |= SETIREG(SISSR, 0x14, 0x12);
1529 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1531 ret |= SETIREG(SISSR, 0x14, 0x02);
1534 ret |= sisusb_triggersr16(sisusb, ramtype);
1535 ret |= WRITEL(ramptr + 0, 0x01234567);
1536 ret |= WRITEL(ramptr + 4, 0x456789ab);
1537 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1538 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1539 ret |= WRITEL(ramptr + 16, 0x55555555);
1540 ret |= WRITEL(ramptr + 20, 0x55555555);
1541 ret |= WRITEL(ramptr + 24, 0xffffffff);
1542 ret |= WRITEL(ramptr + 28, 0xffffffff);
1543 ret |= READL(ramptr + 0, &t0);
1544 ret |= READL(ramptr + 4, &t1);
1545 ret |= READL(ramptr + 8, &t2);
1546 ret |= READL(ramptr + 12, &t3);
1550 *chab = 0; *bw = 64;
1552 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1553 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1554 *chab = 0; *bw = 64;
1555 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1558 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1559 *chab = 1; *bw = 64;
1560 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1562 ret |= sisusb_triggersr16(sisusb, ramtype);
1563 ret |= WRITEL(ramptr + 0, 0x89abcdef);
1564 ret |= WRITEL(ramptr + 4, 0xcdef0123);
1565 ret |= WRITEL(ramptr + 8, 0x55555555);
1566 ret |= WRITEL(ramptr + 12, 0x55555555);
1567 ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1568 ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1569 ret |= READL(ramptr + 4, &t1);
1571 if (t1 != 0xcdef0123) {
1573 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1579 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1583 if (t1 == 0x456789ab) {
1584 if (t0 == 0x01234567) {
1585 *chab = 0; *bw = 64;
1589 if (t0 == 0x01234567) {
1590 *chab = 0; *bw = 32;
1591 ret |= SETIREG(SISSR, 0x14, 0x00);
1597 ret |= SETIREG(SISSR, 0x14, 0x03);
1598 ret |= sisusb_triggersr16(sisusb, ramtype);
1600 ret |= WRITEL(ramptr + 0, 0x01234567);
1601 ret |= WRITEL(ramptr + 4, 0x456789ab);
1602 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1603 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1604 ret |= WRITEL(ramptr + 16, 0x55555555);
1605 ret |= WRITEL(ramptr + 20, 0x55555555);
1606 ret |= WRITEL(ramptr + 24, 0xffffffff);
1607 ret |= WRITEL(ramptr + 28, 0xffffffff);
1608 ret |= READL(ramptr + 0, &t0);
1609 ret |= READL(ramptr + 4, &t1);
1611 if (t1 == 0x456789ab) {
1612 if (t0 == 0x01234567) {
1613 *chab = 1; *bw = 64;
1617 if (t0 == 0x01234567) {
1618 *chab = 1; *bw = 32;
1619 ret |= SETIREG(SISSR, 0x14, 0x01);
1628 sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1631 u32 ramptr = SISUSB_PCI_MEMBASE;
1632 u8 tmp1, tmp2, i, j;
1634 ret |= WRITEB(ramptr, 0xaa);
1635 ret |= WRITEB(ramptr + 16, 0x55);
1636 ret |= READB(ramptr, &tmp1);
1637 ret |= READB(ramptr + 16, &tmp2);
1638 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1639 for (i = 0, j = 16; i < 2; i++, j += 16) {
1640 ret |= GETIREG(SISSR, 0x21, &tmp1);
1641 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1642 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1643 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1644 ret |= SETIREG(SISSR, 0x21, tmp1);
1645 ret |= WRITEB(ramptr + 16 + j, j);
1646 ret |= READB(ramptr + 16 + j, &tmp1);
1648 ret |= WRITEB(ramptr + j, j);
1657 sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1658 u8 rankno, u8 chab, const u8 dramtype[][5],
1661 int ret = 0, ranksize;
1666 if ((rankno == 2) && (dramtype[index][0] == 2))
1669 ranksize = dramtype[index][3] / 2 * bw / 32;
1671 if ((ranksize * rankno) > 128)
1675 while ((ranksize >>= 1) > 0) tmp += 0x10;
1676 tmp |= ((rankno - 1) << 2);
1677 tmp |= ((bw / 64) & 0x02);
1678 tmp |= (chab & 0x01);
1680 ret = SETIREG(SISSR, 0x14, tmp);
1681 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1689 sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1696 for (i = 0, j = 0; i < testn; i++) {
1697 ret |= WRITEL(sisusb->vrambase + j, j);
1701 for (i = 0, j = 0; i < testn; i++) {
1702 ret |= READL(sisusb->vrambase + j, &tmp);
1703 if (tmp != j) return ret;
1712 sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1713 int idx, int bw, const u8 rtype[][5])
1715 int ret = 0, i, i2ret;
1720 for (i = rankno; i >= 1; i--) {
1721 inc = 1 << (rtype[idx][2] +
1725 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1730 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1731 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1735 inc = 1 << (10 + bw / 64);
1736 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1745 sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1748 int ret = 0, i2ret = 0, i, j;
1749 static const u8 sdramtype[13][5] = {
1750 { 2, 12, 9, 64, 0x35 },
1751 { 1, 13, 9, 64, 0x44 },
1752 { 2, 12, 8, 32, 0x31 },
1753 { 2, 11, 9, 32, 0x25 },
1754 { 1, 12, 9, 32, 0x34 },
1755 { 1, 13, 8, 32, 0x40 },
1756 { 2, 11, 8, 16, 0x21 },
1757 { 1, 12, 8, 16, 0x30 },
1758 { 1, 11, 9, 16, 0x24 },
1759 { 1, 11, 8, 8, 0x20 },
1760 { 2, 9, 8, 4, 0x01 },
1761 { 1, 10, 8, 4, 0x10 },
1762 { 1, 9, 8, 2, 0x00 }
1765 *iret = 1; /* error */
1767 for (i = 0; i < 13; i++) {
1768 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1769 for (j = 2; j > 0; j--) {
1770 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1771 chab, sdramtype, bw);
1775 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1778 *iret = 0; /* ram size found */
1788 sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1792 int i, length, modex, modey, bpp;
1794 modex = 640; modey = 480; bpp = 2;
1796 address = sisusb->vrambase; /* Clear video ram */
1799 length = sisusb->vramsize;
1801 length = modex * bpp * modey;
1803 ret = sisusb_clear_vram(sisusb, address, length);
1805 if (!ret && drwfr) {
1806 for (i = 0; i < modex; i++) {
1807 address = sisusb->vrambase + (i * bpp);
1808 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1810 address += (modex * (modey-1) * bpp);
1811 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1814 for (i = 0; i < modey; i++) {
1815 address = sisusb->vrambase + ((i * modex) * bpp);
1816 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1818 address += ((modex - 1) * bpp);
1819 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1828 sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1830 int ret = 0, i, j, modex, modey, bpp, du;
1831 u8 sr31, cr63, tmp8;
1832 static const char attrdata[] = {
1833 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1834 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1837 static const char crtcrdata[] = {
1838 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1839 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1840 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1843 static const char grcdata[] = {
1844 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1847 static const char crtcdata[] = {
1848 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1849 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1853 modex = 640; modey = 480; bpp = 2;
1855 GETIREG(SISSR, 0x31, &sr31);
1856 GETIREG(SISCR, 0x63, &cr63);
1857 SETIREGOR(SISSR, 0x01, 0x20);
1858 SETIREG(SISCR, 0x63, cr63 & 0xbf);
1859 SETIREGOR(SISCR, 0x17, 0x80);
1860 SETIREGOR(SISSR, 0x1f, 0x04);
1861 SETIREGAND(SISSR, 0x07, 0xfb);
1862 SETIREG(SISSR, 0x00, 0x03); /* seq */
1863 SETIREG(SISSR, 0x01, 0x21);
1864 SETIREG(SISSR, 0x02, 0x0f);
1865 SETIREG(SISSR, 0x03, 0x00);
1866 SETIREG(SISSR, 0x04, 0x0e);
1867 SETREG(SISMISCW, 0x23); /* misc */
1868 for (i = 0; i <= 0x18; i++) { /* crtc */
1869 SETIREG(SISCR, i, crtcrdata[i]);
1871 for (i = 0; i <= 0x13; i++) { /* att */
1872 GETREG(SISINPSTAT, &tmp8);
1874 SETREG(SISAR, attrdata[i]);
1876 GETREG(SISINPSTAT, &tmp8);
1877 SETREG(SISAR, 0x14);
1878 SETREG(SISAR, 0x00);
1879 GETREG(SISINPSTAT, &tmp8);
1880 SETREG(SISAR, 0x20);
1881 GETREG(SISINPSTAT, &tmp8);
1882 for (i = 0; i <= 0x08; i++) { /* grc */
1883 SETIREG(SISGR, i, grcdata[i]);
1885 SETIREGAND(SISGR, 0x05, 0xbf);
1886 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1887 SETIREG(SISSR, i, 0x00);
1889 SETIREGAND(SISSR, 0x37, 0xfe);
1890 SETREG(SISMISCW, 0xef); /* sync */
1891 SETIREG(SISCR, 0x11, 0x00); /* crtc */
1892 for (j = 0x00, i = 0; i <= 7; i++, j++) {
1893 SETIREG(SISCR, j, crtcdata[i]);
1895 for (j = 0x10; i <= 10; i++, j++) {
1896 SETIREG(SISCR, j, crtcdata[i]);
1898 for (j = 0x15; i <= 12; i++, j++) {
1899 SETIREG(SISCR, j, crtcdata[i]);
1901 for (j = 0x0A; i <= 15; i++, j++) {
1902 SETIREG(SISSR, j, crtcdata[i]);
1904 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
1905 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
1906 SETIREG(SISCR, 0x14, 0x4f);
1907 du = (modex / 16) * (bpp * 2); /* offset/pitch */
1908 if (modex % 16) du += bpp;
1909 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
1910 SETIREG(SISCR, 0x13, (du & 0xff));
1913 if (du & 0xff) tmp8++;
1914 SETIREG(SISSR, 0x10, tmp8);
1915 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
1916 SETIREG(SISSR, 0x2b, 0x1b);
1917 SETIREG(SISSR, 0x2c, 0xe1);
1918 SETIREG(SISSR, 0x2d, 0x01);
1919 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
1920 SETIREG(SISSR, 0x08, 0xae);
1921 SETIREGAND(SISSR, 0x09, 0xf0);
1922 SETIREG(SISSR, 0x08, 0x34);
1923 SETIREGOR(SISSR, 0x3d, 0x01);
1924 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
1925 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
1926 SETIREG(SISCR, 0x19, 0x00);
1927 SETIREGAND(SISCR, 0x1a, 0xfc);
1928 SETIREGAND(SISSR, 0x0f, 0xb7);
1929 SETIREGAND(SISSR, 0x31, 0xfb);
1930 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
1931 SETIREGAND(SISSR, 0x32, 0xf3);
1932 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
1933 SETIREG(SISCR, 0x52, 0x6c);
1935 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
1936 SETIREG(SISCR, 0x0c, 0x00);
1937 SETIREG(SISSR, 0x0d, 0x00);
1938 SETIREGAND(SISSR, 0x37, 0xfe);
1940 SETIREG(SISCR, 0x32, 0x20);
1941 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
1942 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
1943 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
1946 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
1947 SETIREGOR(SISSR, 0x1e, 0x5a);
1949 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
1950 SETIREG(SISSR, 0x27, 0x1f);
1951 SETIREG(SISSR, 0x26, 0x00);
1954 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
1960 sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
1962 int ret = 0, i, j, bw, chab, iret, retry = 3;
1965 static const char mclktable[] = {
1966 0x3b, 0x22, 0x01, 143,
1967 0x3b, 0x22, 0x01, 143,
1968 0x3b, 0x22, 0x01, 143,
1969 0x3b, 0x22, 0x01, 143
1971 static const char eclktable[] = {
1972 0x3b, 0x22, 0x01, 143,
1973 0x3b, 0x22, 0x01, 143,
1974 0x3b, 0x22, 0x01, 143,
1975 0x3b, 0x22, 0x01, 143
1977 static const char ramtypetable1[] = {
1978 0x00, 0x04, 0x60, 0x60,
1979 0x0f, 0x0f, 0x1f, 0x1f,
1980 0xba, 0xba, 0xba, 0xba,
1981 0xa9, 0xa9, 0xac, 0xac,
1982 0xa0, 0xa0, 0xa0, 0xa8,
1983 0x00, 0x00, 0x02, 0x02,
1984 0x30, 0x30, 0x40, 0x40
1986 static const char ramtypetable2[] = {
1987 0x77, 0x77, 0x44, 0x44,
1988 0x77, 0x77, 0x44, 0x44,
1989 0x00, 0x00, 0x00, 0x00,
1990 0x5b, 0x5b, 0xab, 0xab,
1991 0x00, 0x00, 0xf0, 0xf8
1997 ret = GETREG(SISVGAEN, &tmp8);
1998 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
2000 /* Enable GPU access to VRAM */
2001 ret |= GETREG(SISMISCR, &tmp8);
2002 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
2006 /* Reset registers */
2007 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
2008 ret |= SETIREG(SISSR, 0x05, 0x86);
2009 ret |= SETIREGOR(SISSR, 0x20, 0x01);
2011 ret |= SETREG(SISMISCW, 0x67);
2013 for (i = 0x06; i <= 0x1f; i++) {
2014 ret |= SETIREG(SISSR, i, 0x00);
2016 for (i = 0x21; i <= 0x27; i++) {
2017 ret |= SETIREG(SISSR, i, 0x00);
2019 for (i = 0x31; i <= 0x3d; i++) {
2020 ret |= SETIREG(SISSR, i, 0x00);
2022 for (i = 0x12; i <= 0x1b; i++) {
2023 ret |= SETIREG(SISSR, i, 0x00);
2025 for (i = 0x79; i <= 0x7c; i++) {
2026 ret |= SETIREG(SISCR, i, 0x00);
2031 ret |= SETIREG(SISCR, 0x63, 0x80);
2033 ret |= GETIREG(SISSR, 0x3a, &ramtype);
2036 ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
2037 ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
2038 ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
2040 ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
2041 ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
2042 ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
2044 ret |= SETIREG(SISSR, 0x07, 0x18);
2045 ret |= SETIREG(SISSR, 0x11, 0x0f);
2049 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2050 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2052 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2053 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2056 ret |= SETIREG(SISCR, 0x49, 0xaa);
2058 ret |= SETIREG(SISSR, 0x1f, 0x00);
2059 ret |= SETIREG(SISSR, 0x20, 0xa0);
2060 ret |= SETIREG(SISSR, 0x23, 0xf6);
2061 ret |= SETIREG(SISSR, 0x24, 0x0d);
2062 ret |= SETIREG(SISSR, 0x25, 0x33);
2064 ret |= SETIREG(SISSR, 0x11, 0x0f);
2066 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2068 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2072 ret |= SETIREG(SISPART1, 0x00, 0x00);
2074 ret |= GETIREG(SISSR, 0x13, &tmp8);
2077 ret |= SETIREG(SISPART1, 0x02, 0x00);
2078 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2080 ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
2081 tmp32 &= 0x00f00000;
2082 tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
2083 ret |= SETIREG(SISSR, 0x25, tmp8);
2084 tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
2085 ret |= SETIREG(SISCR, 0x49, tmp8);
2087 ret |= SETIREG(SISSR, 0x27, 0x1f);
2088 ret |= SETIREG(SISSR, 0x31, 0x00);
2089 ret |= SETIREG(SISSR, 0x32, 0x11);
2090 ret |= SETIREG(SISSR, 0x33, 0x00);
2094 ret |= SETIREG(SISCR, 0x83, 0x00);
2096 ret |= sisusb_set_default_mode(sisusb, 0);
2098 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2099 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2100 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2102 ret |= sisusb_triggersr16(sisusb, ramtype);
2104 /* Disable refresh */
2105 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2106 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2108 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2109 ret |= sisusb_verify_mclk(sisusb);
2112 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2114 printk(KERN_ERR "sisusbvga[%d]: RAM size "
2115 "detection failed, "
2116 "assuming 8MB video RAM\n",
2118 ret |= SETIREG(SISSR,0x14,0x31);
2122 printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
2123 "assuming 8MB video RAM\n",
2125 ret |= SETIREG(SISSR,0x14,0x31);
2129 /* Enable refresh */
2130 ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
2131 ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
2132 ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
2134 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2136 ret |= SETIREG(SISSR, 0x22, 0xfb);
2137 ret |= SETIREG(SISSR, 0x21, 0xa5);
2157 sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2159 u8 tmp8, tmp82, ramtype;
2161 char *ramtypetext1 = NULL;
2162 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2163 "DDR SDRAM", "DDR SGRAM" };
2164 static const int busSDR[4] = {64, 64, 128, 128};
2165 static const int busDDR[4] = {32, 32, 64, 64};
2166 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2168 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2169 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2170 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2171 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2173 switch ((tmp8 >> 2) & 0x03) {
2174 case 0: ramtypetext1 = "1 ch/1 r";
2178 bw = busSDR[(tmp8 & 0x03)];
2181 case 1: ramtypetext1 = "1 ch/2 r";
2182 sisusb->vramsize <<= 1;
2183 bw = busSDR[(tmp8 & 0x03)];
2185 case 2: ramtypetext1 = "asymmeric";
2186 sisusb->vramsize += sisusb->vramsize/2;
2187 bw = busDDRA[(tmp8 & 0x03)];
2189 case 3: ramtypetext1 = "2 channel";
2190 sisusb->vramsize <<= 1;
2191 bw = busDDR[(tmp8 & 0x03)];
2195 printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2196 sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
2197 ramtypetext2[ramtype], bw);
2201 sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2203 struct sisusb_packet packet;
2208 packet.header = 0x001f;
2209 packet.address = 0x00000324;
2210 packet.data = 0x00000004;
2211 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2213 packet.header = 0x001f;
2214 packet.address = 0x00000364;
2215 packet.data = 0x00000004;
2216 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2218 packet.header = 0x001f;
2219 packet.address = 0x00000384;
2220 packet.data = 0x00000004;
2221 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2223 packet.header = 0x001f;
2224 packet.address = 0x00000100;
2225 packet.data = 0x00000700;
2226 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2228 packet.header = 0x000f;
2229 packet.address = 0x00000004;
2230 ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2231 packet.data |= 0x17;
2232 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2234 /* Init BAR 0 (VRAM) */
2235 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2236 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2237 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2239 tmp32 |= SISUSB_PCI_MEMBASE;
2240 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2242 /* Init BAR 1 (MMIO) */
2243 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2244 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2245 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2247 tmp32 |= SISUSB_PCI_MMIOBASE;
2248 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2250 /* Init BAR 2 (i/o ports) */
2251 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2252 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2253 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2255 tmp32 |= SISUSB_PCI_IOPORTBASE;
2256 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2258 /* Enable memory and i/o access */
2259 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2261 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2264 /* Some further magic */
2265 packet.header = 0x001f;
2266 packet.address = 0x00000050;
2267 packet.data = 0x000000ff;
2268 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2274 /* Initialize the graphics device (return 0 on success)
2275 * This initializes the net2280 as well as the PCI registers
2276 * of the graphics board.
2280 sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2282 int ret = 0, test = 0;
2285 if (sisusb->devinit == 1) {
2286 /* Read PCI BARs and see if they have been set up */
2287 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2288 if (ret) return ret;
2289 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
2291 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2292 if (ret) return ret;
2293 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2295 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2296 if (ret) return ret;
2297 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2300 /* No? So reset the device */
2301 if ((sisusb->devinit == 0) || (test != 3)) {
2303 ret |= sisusb_do_init_gfxdevice(sisusb);
2306 sisusb->devinit = 1;
2310 if (sisusb->devinit) {
2311 /* Initialize the graphics core */
2312 if (sisusb_init_gfxcore(sisusb) == 0) {
2313 sisusb->gfxinit = 1;
2314 sisusb_get_ramconfig(sisusb);
2315 ret |= sisusb_set_default_mode(sisusb, 1);
2316 ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2324 #ifdef INCL_SISUSB_CON
2326 /* Set up default text mode:
2327 - Set text mode (0x03)
2328 - Upload default font
2329 - Upload user font (if available)
2333 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
2335 int ret = 0, slot = sisusb->font_slot, i;
2336 const struct font_desc *myfont;
2340 static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
2341 static const char bootlogo[] = "(o_ //\\ V_/_";
2343 /* sisusb->lock is down */
2345 if (!sisusb->SiS_Pr)
2348 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2349 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2352 SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
2354 if (!(myfont = find_font("VGA8x16")))
2357 if (!(tempbuf = vmalloc(8192)))
2360 for (i = 0; i < 256; i++)
2361 memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
2363 /* Upload default font */
2364 ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
2368 /* Upload user font (and reset current slot) */
2369 if (sisusb->font_backup) {
2370 ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
2371 8192, sisusb->font_backup_512, 1, NULL,
2372 sisusb->font_backup_height, 0);
2374 sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
2378 if (init && !sisusb->scrbuf) {
2380 if ((tempbuf = vmalloc(8192))) {
2383 tempbufb = (u16 *)tempbuf;
2385 *(tempbufb++) = 0x0720;
2388 tempbufb = (u16 *)tempbuf;
2389 while (bootlogo[i]) {
2390 *(tempbufb++) = 0x0700 | bootlogo[i++];
2396 tempbufb = (u16 *)tempbuf + 6;
2397 while (bootstring[i])
2398 *(tempbufb++) = 0x0700 | bootstring[i++];
2400 ret |= sisusb_copy_memory(sisusb, tempbuf,
2401 sisusb->vrambase, 8192, &written);
2407 } else if (sisusb->scrbuf) {
2409 ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
2410 sisusb->vrambase, sisusb->scrbuf_size, &written);
2414 if (sisusb->sisusb_cursor_size_from >= 0 &&
2415 sisusb->sisusb_cursor_size_to >= 0) {
2416 sisusb_setidxreg(sisusb, SISCR, 0x0a,
2417 sisusb->sisusb_cursor_size_from);
2418 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
2419 sisusb->sisusb_cursor_size_to);
2421 sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
2422 sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
2423 sisusb->sisusb_cursor_size_to = -1;
2426 slot = sisusb->sisusb_cursor_loc;
2427 if(slot < 0) slot = 0;
2429 sisusb->sisusb_cursor_loc = -1;
2430 sisusb->bad_cursor_pos = 1;
2432 sisusb_set_cursor(sisusb, slot);
2434 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
2435 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
2437 sisusb->textmodedestroyed = 0;
2439 /* sisusb->lock is down */
2449 sisusb_open(struct inode *inode, struct file *file)
2451 struct sisusb_usb_data *sisusb;
2452 struct usb_interface *interface;
2453 int subminor = iminor(inode);
2455 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
2456 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
2461 if (!(sisusb = usb_get_intfdata(interface)))
2464 mutex_lock(&sisusb->lock);
2466 if (!sisusb->present || !sisusb->ready) {
2467 mutex_unlock(&sisusb->lock);
2471 if (sisusb->isopen) {
2472 mutex_unlock(&sisusb->lock);
2476 if (!sisusb->devinit) {
2477 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2478 if (sisusb_init_gfxdevice(sisusb, 0)) {
2479 mutex_unlock(&sisusb->lock);
2481 "sisusbvga[%d]: Failed to initialize "
2487 mutex_unlock(&sisusb->lock);
2489 "sisusbvga[%d]: Device not attached to "
2496 /* Increment usage count for our sisusb */
2497 kref_get(&sisusb->kref);
2501 file->private_data = sisusb;
2503 mutex_unlock(&sisusb->lock);
2509 sisusb_delete(struct kref *kref)
2511 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2516 if (sisusb->sisusb_dev)
2517 usb_put_dev(sisusb->sisusb_dev);
2519 sisusb->sisusb_dev = NULL;
2520 sisusb_free_buffers(sisusb);
2521 sisusb_free_urbs(sisusb);
2522 #ifdef INCL_SISUSB_CON
2523 kfree(sisusb->SiS_Pr);
2529 sisusb_release(struct inode *inode, struct file *file)
2531 struct sisusb_usb_data *sisusb;
2534 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2537 mutex_lock(&sisusb->lock);
2539 if (sisusb->present) {
2540 /* Wait for all URBs to finish if device still present */
2541 if (!sisusb_wait_all_out_complete(sisusb))
2542 sisusb_kill_all_busy(sisusb);
2545 myminor = sisusb->minor;
2548 file->private_data = NULL;
2550 mutex_unlock(&sisusb->lock);
2552 /* decrement the usage count on our device */
2553 kref_put(&sisusb->kref, sisusb_delete);
2559 sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2561 struct sisusb_usb_data *sisusb;
2562 ssize_t bytes_read = 0;
2568 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2571 mutex_lock(&sisusb->lock);
2574 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2575 mutex_unlock(&sisusb->lock);
2579 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2580 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2583 SISUSB_PCI_PSEUDO_IOPORTBASE +
2584 SISUSB_PCI_IOPORTBASE;
2587 * Byte, word and long(32) can be read. As this
2588 * emulates inX instructions, the data returned is
2589 * in machine-endianness.
2594 if (sisusb_read_memio_byte(sisusb,
2598 else if (put_user(buf8, (u8 __user *)buffer))
2606 if (sisusb_read_memio_word(sisusb,
2610 else if (put_user(buf16, (u16 __user *)buffer))
2618 if (sisusb_read_memio_long(sisusb,
2622 else if (put_user(buf32, (u32 __user *)buffer))
2634 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2635 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2638 SISUSB_PCI_PSEUDO_MEMBASE +
2642 * Remember: Data delivered is never endian-corrected
2644 errno = sisusb_read_mem_bulk(sisusb, address,
2645 NULL, count, buffer, &bytes_read);
2650 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2651 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2654 SISUSB_PCI_PSEUDO_MMIOBASE +
2655 SISUSB_PCI_MMIOBASE;
2658 * Remember: Data delivered is never endian-corrected
2660 errno = sisusb_read_mem_bulk(sisusb, address,
2661 NULL, count, buffer, &bytes_read);
2666 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2667 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2670 mutex_unlock(&sisusb->lock);
2674 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2676 /* Read PCI config register
2677 * Return value delivered in machine endianness.
2679 if (sisusb_read_pci_config(sisusb, address, &buf32))
2681 else if (put_user(buf32, (u32 __user *)buffer))
2692 (*ppos) += bytes_read;
2694 mutex_unlock(&sisusb->lock);
2696 return errno ? errno : bytes_read;
2700 sisusb_write(struct file *file, const char __user *buffer, size_t count,
2703 struct sisusb_usb_data *sisusb;
2705 ssize_t bytes_written = 0;
2710 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2713 mutex_lock(&sisusb->lock);
2716 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2717 mutex_unlock(&sisusb->lock);
2721 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2722 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2725 SISUSB_PCI_PSEUDO_IOPORTBASE +
2726 SISUSB_PCI_IOPORTBASE;
2729 * Byte, word and long(32) can be written. As this
2730 * emulates outX instructions, the data is expected
2731 * in machine-endianness.
2736 if (get_user(buf8, (u8 __user *)buffer))
2738 else if (sisusb_write_memio_byte(sisusb,
2748 if (get_user(buf16, (u16 __user *)buffer))
2750 else if (sisusb_write_memio_word(sisusb,
2760 if (get_user(buf32, (u32 __user *)buffer))
2762 else if (sisusb_write_memio_long(sisusb,
2775 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2776 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2779 SISUSB_PCI_PSEUDO_MEMBASE +
2783 * Buffer is copied 1:1, therefore, on big-endian
2784 * machines, the data must be swapped by userland
2785 * in advance (if applicable; no swapping in 8bpp
2786 * mode or if YUV data is being transferred).
2788 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2789 count, buffer, 0, &bytes_written);
2792 errno = bytes_written;
2794 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2795 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2798 SISUSB_PCI_PSEUDO_MMIOBASE +
2799 SISUSB_PCI_MMIOBASE;
2802 * Buffer is copied 1:1, therefore, on big-endian
2803 * machines, the data must be swapped by userland
2806 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2807 count, buffer, 0, &bytes_written);
2810 errno = bytes_written;
2812 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2813 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2816 mutex_unlock(&sisusb->lock);
2820 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2822 /* Write PCI config register.
2823 * Given value expected in machine endianness.
2825 if (get_user(buf32, (u32 __user *)buffer))
2827 else if (sisusb_write_pci_config(sisusb, address, buf32))
2840 (*ppos) += bytes_written;
2842 mutex_unlock(&sisusb->lock);
2844 return errno ? errno : bytes_written;
2848 sisusb_lseek(struct file *file, loff_t offset, int orig)
2850 struct sisusb_usb_data *sisusb;
2853 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2856 mutex_lock(&sisusb->lock);
2859 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2860 mutex_unlock(&sisusb->lock);
2866 file->f_pos = offset;
2868 /* never negative, no force_successful_syscall needed */
2871 file->f_pos += offset;
2873 /* never negative, no force_successful_syscall needed */
2876 /* seeking relative to "end of file" is not supported */
2880 mutex_unlock(&sisusb->lock);
2885 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2888 int retval, port, length;
2891 /* All our commands require the device
2892 * to be initialized.
2894 if (!sisusb->devinit)
2898 SISUSB_PCI_PSEUDO_IOPORTBASE +
2899 SISUSB_PCI_IOPORTBASE;
2901 switch (y->operation) {
2903 retval = sisusb_getidxreg(sisusb, port,
2904 y->data0, &y->data1);
2906 if (copy_to_user((void __user *)arg, y,
2913 retval = sisusb_setidxreg(sisusb, port,
2914 y->data0, y->data1);
2918 retval = sisusb_setidxregor(sisusb, port,
2919 y->data0, y->data1);
2923 retval = sisusb_setidxregand(sisusb, port,
2924 y->data0, y->data1);
2927 case SUCMD_SETANDOR:
2928 retval = sisusb_setidxregandor(sisusb, port,
2929 y->data0, y->data1, y->data2);
2933 retval = sisusb_setidxregmask(sisusb, port,
2934 y->data0, y->data1, y->data2);
2938 /* Gfx core must be initialized */
2939 if (!sisusb->gfxinit)
2942 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
2943 address = y->data3 -
2944 SISUSB_PCI_PSEUDO_MEMBASE +
2946 retval = sisusb_clear_vram(sisusb, address, length);
2949 case SUCMD_HANDLETEXTMODE:
2951 #ifdef INCL_SISUSB_CON
2952 /* Gfx core must be initialized, SiS_Pr must exist */
2953 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
2958 retval = sisusb_reset_text_mode(sisusb, 0);
2961 sisusb->textmodedestroyed = 1;
2967 #ifdef INCL_SISUSB_CON
2969 /* Gfx core must be initialized, SiS_Pr must exist */
2970 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
2975 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2976 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2978 if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
2983 case SUCMD_SETVESAMODE:
2984 /* Gfx core must be initialized, SiS_Pr must exist */
2985 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
2990 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2991 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2993 if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
3010 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
3013 struct sisusb_usb_data *sisusb;
3014 struct sisusb_info x;
3015 struct sisusb_command y;
3017 u32 __user *argp = (u32 __user *)arg;
3019 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
3022 mutex_lock(&sisusb->lock);
3025 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
3032 case SISUSB_GET_CONFIG_SIZE:
3034 if (put_user(sizeof(x), argp))
3039 case SISUSB_GET_CONFIG:
3041 x.sisusb_id = SISUSB_ID;
3042 x.sisusb_version = SISUSB_VERSION;
3043 x.sisusb_revision = SISUSB_REVISION;
3044 x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
3045 x.sisusb_gfxinit = sisusb->gfxinit;
3046 x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
3047 x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
3048 x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
3049 x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
3050 x.sisusb_vramsize = sisusb->vramsize;
3051 x.sisusb_minor = sisusb->minor;
3052 x.sisusb_fbdevactive= 0;
3053 #ifdef INCL_SISUSB_CON
3054 x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
3056 x.sisusb_conactive = 0;
3059 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
3064 case SISUSB_COMMAND:
3066 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
3069 retval = sisusb_handle_command(sisusb, &y, arg);
3079 mutex_unlock(&sisusb->lock);
3083 #ifdef SISUSB_NEW_CONFIG_COMPAT
3085 sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
3090 case SISUSB_GET_CONFIG_SIZE:
3091 case SISUSB_GET_CONFIG:
3092 case SISUSB_COMMAND:
3094 retval = sisusb_ioctl(f->f_path.dentry->d_inode, f, cmd, arg);
3099 return -ENOIOCTLCMD;
3104 static const struct file_operations usb_sisusb_fops = {
3105 .owner = THIS_MODULE,
3106 .open = sisusb_open,
3107 .release = sisusb_release,
3108 .read = sisusb_read,
3109 .write = sisusb_write,
3110 .llseek = sisusb_lseek,
3111 #ifdef SISUSB_NEW_CONFIG_COMPAT
3112 .compat_ioctl = sisusb_compat_ioctl,
3114 .ioctl = sisusb_ioctl
3117 static struct usb_class_driver usb_sisusb_class = {
3118 .name = "sisusbvga%d",
3119 .fops = &usb_sisusb_fops,
3120 .minor_base = SISUSB_MINOR
3123 static int sisusb_probe(struct usb_interface *intf,
3124 const struct usb_device_id *id)
3126 struct usb_device *dev = interface_to_usbdev(intf);
3127 struct sisusb_usb_data *sisusb;
3129 const char *memfail =
3131 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
3133 printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
3136 /* Allocate memory for our private */
3137 if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
3139 "sisusb: Failed to allocate memory for private data\n");
3142 kref_init(&sisusb->kref);
3144 mutex_init(&(sisusb->lock));
3146 /* Register device */
3147 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
3149 "sisusb: Failed to get a minor for device %d\n",
3155 sisusb->sisusb_dev = dev;
3156 sisusb->minor = intf->minor;
3157 sisusb->vrambase = SISUSB_PCI_MEMBASE;
3158 sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
3159 sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
3160 sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
3161 /* Everything else is zero */
3163 /* Allocate buffers */
3164 sisusb->ibufsize = SISUSB_IBUF_SIZE;
3165 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
3166 GFP_KERNEL, &sisusb->transfer_dma_in))) {
3167 printk(memfail, "input", sisusb->minor);
3172 sisusb->numobufs = 0;
3173 sisusb->obufsize = SISUSB_OBUF_SIZE;
3174 for (i = 0; i < NUMOBUFS; i++) {
3175 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
3177 &sisusb->transfer_dma_out[i]))) {
3179 printk(memfail, "output", sisusb->minor);
3190 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
3192 "sisusbvga[%d]: Failed to allocate URBs\n",
3197 sisusb->completein = 1;
3199 for (i = 0; i < sisusb->numobufs; i++) {
3200 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
3202 "sisusbvga[%d]: Failed to allocate URBs\n",
3207 sisusb->urbout_context[i].sisusb = (void *)sisusb;
3208 sisusb->urbout_context[i].urbindex = i;
3209 sisusb->urbstatus[i] = 0;
3212 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
3213 sisusb->minor, sisusb->numobufs);
3215 #ifdef INCL_SISUSB_CON
3216 /* Allocate our SiS_Pr */
3217 if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
3219 "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
3224 /* Do remaining init stuff */
3226 init_waitqueue_head(&sisusb->wait_q);
3228 usb_set_intfdata(intf, sisusb);
3230 usb_get_dev(sisusb->sisusb_dev);
3232 sisusb->present = 1;
3234 #ifdef SISUSB_OLD_CONFIG_COMPAT
3237 /* Our ioctls are all "32/64bit compatible" */
3238 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3239 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3240 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3243 "sisusbvga[%d]: Error registering ioctl32 "
3247 sisusb->ioctl32registered = 1;
3251 if (dev->speed == USB_SPEED_HIGH) {
3253 #ifdef INCL_SISUSB_CON
3254 if (sisusb_first_vc > 0 &&
3255 sisusb_last_vc > 0 &&
3256 sisusb_first_vc <= sisusb_last_vc &&
3257 sisusb_last_vc <= MAX_NR_CONSOLES)
3260 if (sisusb_init_gfxdevice(sisusb, initscreen))
3262 "sisusbvga[%d]: Failed to early "
3263 "initialize device\n",
3268 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3274 #ifdef SISUSBENDIANTEST
3275 printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
3276 sisusb_testreadwrite(sisusb);
3277 printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
3280 #ifdef INCL_SISUSB_CON
3281 sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
3287 sisusb_free_urbs(sisusb);
3289 sisusb_free_buffers(sisusb);
3291 usb_deregister_dev(intf, &usb_sisusb_class);
3297 static void sisusb_disconnect(struct usb_interface *intf)
3299 struct sisusb_usb_data *sisusb;
3302 /* This should *not* happen */
3303 if (!(sisusb = usb_get_intfdata(intf)))
3306 #ifdef INCL_SISUSB_CON
3307 sisusb_console_exit(sisusb);
3310 minor = sisusb->minor;
3312 usb_deregister_dev(intf, &usb_sisusb_class);
3314 mutex_lock(&sisusb->lock);
3316 /* Wait for all URBs to complete and kill them in case (MUST do) */
3317 if (!sisusb_wait_all_out_complete(sisusb))
3318 sisusb_kill_all_busy(sisusb);
3320 usb_set_intfdata(intf, NULL);
3322 #ifdef SISUSB_OLD_CONFIG_COMPAT
3323 if (sisusb->ioctl32registered) {
3325 sisusb->ioctl32registered = 0;
3326 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3327 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3328 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3331 "sisusbvga[%d]: Error unregistering "
3332 "ioctl32 translations\n",
3338 sisusb->present = 0;
3341 mutex_unlock(&sisusb->lock);
3343 /* decrement our usage count */
3344 kref_put(&sisusb->kref, sisusb_delete);
3346 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
3349 static struct usb_device_id sisusb_table [] = {
3350 { USB_DEVICE(0x0711, 0x0550) },
3351 { USB_DEVICE(0x0711, 0x0900) },
3352 { USB_DEVICE(0x0711, 0x0901) },
3353 { USB_DEVICE(0x0711, 0x0902) },
3354 { USB_DEVICE(0x182d, 0x021c) },
3355 { USB_DEVICE(0x182d, 0x0269) },
3359 MODULE_DEVICE_TABLE (usb, sisusb_table);
3361 static struct usb_driver sisusb_driver = {
3363 .probe = sisusb_probe,
3364 .disconnect = sisusb_disconnect,
3365 .id_table = sisusb_table,
3368 static int __init usb_sisusb_init(void)
3372 #ifdef INCL_SISUSB_CON
3373 sisusb_init_concode();
3376 if (!(retval = usb_register(&sisusb_driver))) {
3378 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3379 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3381 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3388 static void __exit usb_sisusb_exit(void)
3390 usb_deregister(&sisusb_driver);
3393 module_init(usb_sisusb_init);
3394 module_exit(usb_sisusb_exit);
3396 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3397 MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
3398 MODULE_LICENSE("GPL");