[PATCH] USB: convert the semaphores in the sisusb driver to mutexes
[linux-2.6/suspend2-2.6.18.git] / drivers / usb / misc / sisusbvga / sisusb.c
blob19aedbc85ea4735200ace707efa9deab27d0383b
1 /*
2 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
4 * Main part
6 * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
8 * If distributed as part of the Linux kernel, this code is licensed under the
9 * terms of the GPL v2.
11 * Otherwise, the following license terms apply:
13 * * Redistribution and use in source and binary forms, with or without
14 * * modification, are permitted provided that the following conditions
15 * * are met:
16 * * 1) Redistributions of source code must retain the above copyright
17 * * notice, this list of conditions and the following disclaimer.
18 * * 2) Redistributions in binary form must reproduce the above copyright
19 * * notice, this list of conditions and the following disclaimer in the
20 * * documentation and/or other materials provided with the distribution.
21 * * 3) The name of the author may not be used to endorse or promote products
22 * * derived from this software without specific psisusbr written permission.
23 * *
24 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
25 * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * Author: Thomas Winischhofer <thomas@winischhofer.net>
39 #include <linux/config.h>
40 #include <linux/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>
55 #include "sisusb.h"
57 #ifdef INCL_SISUSB_CON
58 #include <linux/font.h>
59 #endif
61 #define SISUSB_DONTSYNC
63 /* Forward declarations / clean-up routines */
65 #ifdef INCL_SISUSB_CON
66 int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
67 int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
68 int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data);
69 int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data);
70 int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand, u8 myor);
71 int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor);
72 int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand);
74 int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
75 int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
76 int sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data);
77 int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data);
78 int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
79 u32 dest, int length, size_t *bytes_written);
81 int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
83 extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
84 extern int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
86 extern void sisusb_init_concode(void);
87 extern int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
88 extern void sisusb_console_exit(struct sisusb_usb_data *sisusb);
90 extern void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
92 extern int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
93 u8 *arg, int cmapsz, int ch512, int dorecalc,
94 struct vc_data *c, int fh, int uplock);
96 static int sisusb_first_vc = 0;
97 static int sisusb_last_vc = 0;
98 module_param_named(first, sisusb_first_vc, int, 0);
99 module_param_named(last, sisusb_last_vc, int, 0);
100 MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)");
101 MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)");
102 #endif
104 static struct usb_driver sisusb_driver;
106 DEFINE_MUTEX(disconnect_mutex);
108 static void
109 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
111 int i;
113 for (i = 0; i < NUMOBUFS; i++) {
114 if (sisusb->obuf[i]) {
115 usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize,
116 sisusb->obuf[i], sisusb->transfer_dma_out[i]);
117 sisusb->obuf[i] = NULL;
120 if (sisusb->ibuf) {
121 usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
122 sisusb->ibuf, sisusb->transfer_dma_in);
123 sisusb->ibuf = NULL;
127 static void
128 sisusb_free_urbs(struct sisusb_usb_data *sisusb)
130 int i;
132 for (i = 0; i < NUMOBUFS; i++) {
133 usb_free_urb(sisusb->sisurbout[i]);
134 sisusb->sisurbout[i] = NULL;
136 usb_free_urb(sisusb->sisurbin);
137 sisusb->sisurbin = NULL;
140 /* Level 0: USB transport layer */
142 /* 1. out-bulks */
144 /* out-urb management */
146 /* Return 1 if all free, 0 otherwise */
147 static int
148 sisusb_all_free(struct sisusb_usb_data *sisusb)
150 int i;
152 for (i = 0; i < sisusb->numobufs; i++) {
154 if (sisusb->urbstatus[i] & SU_URB_BUSY)
155 return 0;
159 return 1;
162 /* Kill all busy URBs */
163 static void
164 sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
166 int i;
168 if (sisusb_all_free(sisusb))
169 return;
171 for (i = 0; i < sisusb->numobufs; i++) {
173 if (sisusb->urbstatus[i] & SU_URB_BUSY)
174 usb_kill_urb(sisusb->sisurbout[i]);
179 /* Return 1 if ok, 0 if error (not all complete within timeout) */
180 static int
181 sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
183 int timeout = 5 * HZ, i = 1;
185 wait_event_timeout(sisusb->wait_q,
186 (i = sisusb_all_free(sisusb)),
187 timeout);
189 return i;
192 static int
193 sisusb_outurb_available(struct sisusb_usb_data *sisusb)
195 int i;
197 for (i = 0; i < sisusb->numobufs; i++) {
199 if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
200 return i;
204 return -1;
207 static int
208 sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
210 int i, timeout = 5 * HZ;
212 wait_event_timeout(sisusb->wait_q,
213 ((i = sisusb_outurb_available(sisusb)) >= 0),
214 timeout);
216 return i;
219 static int
220 sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
222 int i;
224 i = sisusb_outurb_available(sisusb);
226 if (i >= 0)
227 sisusb->urbstatus[i] |= SU_URB_ALLOC;
229 return i;
232 static void
233 sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
235 if ((index >= 0) && (index < sisusb->numobufs))
236 sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
239 /* completion callback */
241 static void
242 sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
244 struct sisusb_urb_context *context = urb->context;
245 struct sisusb_usb_data *sisusb;
247 if (!context)
248 return;
250 sisusb = context->sisusb;
252 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
253 return;
255 #ifndef SISUSB_DONTSYNC
256 if (context->actual_length)
257 *(context->actual_length) += urb->actual_length;
258 #endif
260 sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
261 wake_up(&sisusb->wait_q);
264 static int
265 sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
266 int len, int *actual_length, int timeout, unsigned int tflags,
267 dma_addr_t transfer_dma)
269 struct urb *urb = sisusb->sisurbout[index];
270 int retval, byteswritten = 0;
272 /* Set up URB */
273 urb->transfer_flags = 0;
275 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
276 sisusb_bulk_completeout, &sisusb->urbout_context[index]);
278 urb->transfer_flags |= tflags;
279 urb->actual_length = 0;
281 if ((urb->transfer_dma = transfer_dma))
282 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
284 /* Set up context */
285 sisusb->urbout_context[index].actual_length = (timeout) ?
286 NULL : actual_length;
288 /* Declare this urb/buffer in use */
289 sisusb->urbstatus[index] |= SU_URB_BUSY;
291 /* Submit URB */
292 retval = usb_submit_urb(urb, GFP_ATOMIC);
294 /* If OK, and if timeout > 0, wait for completion */
295 if ((retval == 0) && timeout) {
296 wait_event_timeout(sisusb->wait_q,
297 (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
298 timeout);
299 if (sisusb->urbstatus[index] & SU_URB_BUSY) {
300 /* URB timed out... kill it and report error */
301 usb_kill_urb(urb);
302 retval = -ETIMEDOUT;
303 } else {
304 /* Otherwise, report urb status */
305 retval = urb->status;
306 byteswritten = urb->actual_length;
310 if (actual_length)
311 *actual_length = byteswritten;
313 return retval;
316 /* 2. in-bulks */
318 /* completion callback */
320 static void
321 sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
323 struct sisusb_usb_data *sisusb = urb->context;
325 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
326 return;
328 sisusb->completein = 1;
329 wake_up(&sisusb->wait_q);
332 static int
333 sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len,
334 int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma)
336 struct urb *urb = sisusb->sisurbin;
337 int retval, readbytes = 0;
339 urb->transfer_flags = 0;
341 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
342 sisusb_bulk_completein, sisusb);
344 urb->transfer_flags |= tflags;
345 urb->actual_length = 0;
347 if ((urb->transfer_dma = transfer_dma))
348 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
350 sisusb->completein = 0;
351 retval = usb_submit_urb(urb, GFP_ATOMIC);
352 if (retval == 0) {
353 wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
354 if (!sisusb->completein) {
355 /* URB timed out... kill it and report error */
356 usb_kill_urb(urb);
357 retval = -ETIMEDOUT;
358 } else {
359 /* URB completed within timout */
360 retval = urb->status;
361 readbytes = urb->actual_length;
365 if (actual_length)
366 *actual_length = readbytes;
368 return retval;
372 /* Level 1: */
374 /* Send a bulk message of variable size
376 * To copy the data from userspace, give pointer to "userbuffer",
377 * to copy from (non-DMA) kernel memory, give "kernbuffer". If
378 * both of these are NULL, it is assumed, that the transfer
379 * buffer "sisusb->obuf[index]" is set up with the data to send.
380 * Index is ignored if either kernbuffer or userbuffer is set.
381 * If async is nonzero, URBs will be sent without waiting for
382 * completion of the previous URB.
384 * (return 0 on success)
387 static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
388 char *kernbuffer, const char __user *userbuffer, int index,
389 ssize_t *bytes_written, unsigned int tflags, int async)
391 int result = 0, retry, count = len;
392 int passsize, thispass, transferred_len = 0;
393 int fromuser = (userbuffer != NULL) ? 1 : 0;
394 int fromkern = (kernbuffer != NULL) ? 1 : 0;
395 unsigned int pipe;
396 char *buffer;
398 (*bytes_written) = 0;
400 /* Sanity check */
401 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
402 return -ENODEV;
404 /* If we copy data from kernel or userspace, force the
405 * allocation of a buffer/urb. If we have the data in
406 * the transfer buffer[index] already, reuse the buffer/URB
407 * if the length is > buffer size. (So, transmitting
408 * large data amounts directly from the transfer buffer
409 * treats the buffer as a ring buffer. However, we need
410 * to sync in this case.)
412 if (fromuser || fromkern)
413 index = -1;
414 else if (len > sisusb->obufsize)
415 async = 0;
417 pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
419 do {
420 passsize = thispass = (sisusb->obufsize < count) ?
421 sisusb->obufsize : count;
423 if (index < 0)
424 index = sisusb_get_free_outbuf(sisusb);
426 if (index < 0)
427 return -EIO;
429 buffer = sisusb->obuf[index];
431 if (fromuser) {
433 if (copy_from_user(buffer, userbuffer, passsize))
434 return -EFAULT;
436 userbuffer += passsize;
438 } else if (fromkern) {
440 memcpy(buffer, kernbuffer, passsize);
441 kernbuffer += passsize;
445 retry = 5;
446 while (thispass) {
448 if (!sisusb->sisusb_dev)
449 return -ENODEV;
451 result = sisusb_bulkout_msg(sisusb,
452 index,
453 pipe,
454 buffer,
455 thispass,
456 &transferred_len,
457 async ? 0 : 5 * HZ,
458 tflags,
459 sisusb->transfer_dma_out[index]);
461 if (result == -ETIMEDOUT) {
463 /* Will not happen if async */
464 if (!retry--)
465 return -ETIME;
467 continue;
469 } else if ((result == 0) && !async && transferred_len) {
471 thispass -= transferred_len;
472 if (thispass) {
473 if (sisusb->transfer_dma_out) {
474 /* If DMA, copy remaining
475 * to beginning of buffer
477 memcpy(buffer,
478 buffer + transferred_len,
479 thispass);
480 } else {
481 /* If not DMA, simply increase
482 * the pointer
484 buffer += transferred_len;
488 } else
489 break;
492 if (result)
493 return result;
495 (*bytes_written) += passsize;
496 count -= passsize;
498 /* Force new allocation in next iteration */
499 if (fromuser || fromkern)
500 index = -1;
502 } while (count > 0);
504 if (async) {
505 #ifdef SISUSB_DONTSYNC
506 (*bytes_written) = len;
507 /* Some URBs/buffers might be busy */
508 #else
509 sisusb_wait_all_out_complete(sisusb);
510 (*bytes_written) = transferred_len;
511 /* All URBs and all buffers are available */
512 #endif
515 return ((*bytes_written) == len) ? 0 : -EIO;
518 /* Receive a bulk message of variable size
520 * To copy the data to userspace, give pointer to "userbuffer",
521 * to copy to kernel memory, give "kernbuffer". One of them
522 * MUST be set. (There is no technique for letting the caller
523 * read directly from the ibuf.)
527 static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
528 void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
529 unsigned int tflags)
531 int result = 0, retry, count = len;
532 int bufsize, thispass, transferred_len;
533 unsigned int pipe;
534 char *buffer;
536 (*bytes_read) = 0;
538 /* Sanity check */
539 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
540 return -ENODEV;
542 pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
543 buffer = sisusb->ibuf;
544 bufsize = sisusb->ibufsize;
546 retry = 5;
548 #ifdef SISUSB_DONTSYNC
549 if (!(sisusb_wait_all_out_complete(sisusb)))
550 return -EIO;
551 #endif
553 while (count > 0) {
555 if (!sisusb->sisusb_dev)
556 return -ENODEV;
558 thispass = (bufsize < count) ? bufsize : count;
560 result = sisusb_bulkin_msg(sisusb,
561 pipe,
562 buffer,
563 thispass,
564 &transferred_len,
565 5 * HZ,
566 tflags,
567 sisusb->transfer_dma_in);
569 if (transferred_len)
570 thispass = transferred_len;
572 else if (result == -ETIMEDOUT) {
574 if (!retry--)
575 return -ETIME;
577 continue;
579 } else
580 return -EIO;
583 if (thispass) {
585 (*bytes_read) += thispass;
586 count -= thispass;
588 if (userbuffer) {
590 if (copy_to_user(userbuffer, buffer, thispass))
591 return -EFAULT;
593 userbuffer += thispass;
595 } else {
597 memcpy(kernbuffer, buffer, thispass);
598 kernbuffer += thispass;
606 return ((*bytes_read) == len) ? 0 : -EIO;
609 static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
610 struct sisusb_packet *packet)
612 int ret;
613 ssize_t bytes_transferred = 0;
614 __le32 tmp;
616 if (len == 6)
617 packet->data = 0;
619 #ifdef SISUSB_DONTSYNC
620 if (!(sisusb_wait_all_out_complete(sisusb)))
621 return 1;
622 #endif
624 /* Eventually correct endianness */
625 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
627 /* 1. send the packet */
628 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
629 (char *)packet, NULL, 0, &bytes_transferred, 0, 0);
631 if ((ret == 0) && (len == 6)) {
633 /* 2. if packet len == 6, it means we read, so wait for 32bit
634 * return value and write it to packet->data
636 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
637 (char *)&tmp, NULL, &bytes_transferred, 0);
639 packet->data = le32_to_cpu(tmp);
642 return ret;
645 static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
646 struct sisusb_packet *packet,
647 unsigned int tflags)
649 int ret;
650 ssize_t bytes_transferred = 0;
651 __le32 tmp;
653 if (len == 6)
654 packet->data = 0;
656 #ifdef SISUSB_DONTSYNC
657 if (!(sisusb_wait_all_out_complete(sisusb)))
658 return 1;
659 #endif
661 /* Eventually correct endianness */
662 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
664 /* 1. send the packet */
665 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
666 (char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
668 if ((ret == 0) && (len == 6)) {
670 /* 2. if packet len == 6, it means we read, so wait for 32bit
671 * return value and write it to packet->data
673 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
674 (char *)&tmp, NULL, &bytes_transferred, 0);
676 packet->data = le32_to_cpu(tmp);
679 return ret;
682 /* access video memory and mmio (return 0 on success) */
684 /* Low level */
686 /* The following routines assume being used to transfer byte, word,
687 * long etc.
688 * This means that
689 * - the write routines expect "data" in machine endianness format.
690 * The data will be converted to leXX in sisusb_xxx_packet.
691 * - the read routines can expect read data in machine-endianess.
694 static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
695 u32 addr, u8 data)
697 struct sisusb_packet packet;
698 int ret;
700 packet.header = (1 << (addr & 3)) | (type << 6);
701 packet.address = addr & ~3;
702 packet.data = data << ((addr & 3) << 3);
703 ret = sisusb_send_packet(sisusb, 10, &packet);
704 return ret;
707 static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
708 u32 addr, u16 data)
710 struct sisusb_packet packet;
711 int ret = 0;
713 packet.address = addr & ~3;
715 switch (addr & 3) {
716 case 0:
717 packet.header = (type << 6) | 0x0003;
718 packet.data = (u32)data;
719 ret = sisusb_send_packet(sisusb, 10, &packet);
720 break;
721 case 1:
722 packet.header = (type << 6) | 0x0006;
723 packet.data = (u32)data << 8;
724 ret = sisusb_send_packet(sisusb, 10, &packet);
725 break;
726 case 2:
727 packet.header = (type << 6) | 0x000c;
728 packet.data = (u32)data << 16;
729 ret = sisusb_send_packet(sisusb, 10, &packet);
730 break;
731 case 3:
732 packet.header = (type << 6) | 0x0008;
733 packet.data = (u32)data << 24;
734 ret = sisusb_send_packet(sisusb, 10, &packet);
735 packet.header = (type << 6) | 0x0001;
736 packet.address = (addr & ~3) + 4;
737 packet.data = (u32)data >> 8;
738 ret |= sisusb_send_packet(sisusb, 10, &packet);
741 return ret;
744 static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
745 u32 addr, u32 data)
747 struct sisusb_packet packet;
748 int ret = 0;
750 packet.address = addr & ~3;
752 switch (addr & 3) {
753 case 0:
754 packet.header = (type << 6) | 0x0007;
755 packet.data = data & 0x00ffffff;
756 ret = sisusb_send_packet(sisusb, 10, &packet);
757 break;
758 case 1:
759 packet.header = (type << 6) | 0x000e;
760 packet.data = data << 8;
761 ret = sisusb_send_packet(sisusb, 10, &packet);
762 break;
763 case 2:
764 packet.header = (type << 6) | 0x000c;
765 packet.data = data << 16;
766 ret = sisusb_send_packet(sisusb, 10, &packet);
767 packet.header = (type << 6) | 0x0001;
768 packet.address = (addr & ~3) + 4;
769 packet.data = (data >> 16) & 0x00ff;
770 ret |= sisusb_send_packet(sisusb, 10, &packet);
771 break;
772 case 3:
773 packet.header = (type << 6) | 0x0008;
774 packet.data = data << 24;
775 ret = sisusb_send_packet(sisusb, 10, &packet);
776 packet.header = (type << 6) | 0x0003;
777 packet.address = (addr & ~3) + 4;
778 packet.data = (data >> 8) & 0xffff;
779 ret |= sisusb_send_packet(sisusb, 10, &packet);
782 return ret;
785 static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
786 u32 addr, u32 data)
788 struct sisusb_packet packet;
789 int ret = 0;
791 packet.address = addr & ~3;
793 switch (addr & 3) {
794 case 0:
795 packet.header = (type << 6) | 0x000f;
796 packet.data = data;
797 ret = sisusb_send_packet(sisusb, 10, &packet);
798 break;
799 case 1:
800 packet.header = (type << 6) | 0x000e;
801 packet.data = data << 8;
802 ret = sisusb_send_packet(sisusb, 10, &packet);
803 packet.header = (type << 6) | 0x0001;
804 packet.address = (addr & ~3) + 4;
805 packet.data = data >> 24;
806 ret |= sisusb_send_packet(sisusb, 10, &packet);
807 break;
808 case 2:
809 packet.header = (type << 6) | 0x000c;
810 packet.data = data << 16;
811 ret = sisusb_send_packet(sisusb, 10, &packet);
812 packet.header = (type << 6) | 0x0003;
813 packet.address = (addr & ~3) + 4;
814 packet.data = data >> 16;
815 ret |= sisusb_send_packet(sisusb, 10, &packet);
816 break;
817 case 3:
818 packet.header = (type << 6) | 0x0008;
819 packet.data = data << 24;
820 ret = sisusb_send_packet(sisusb, 10, &packet);
821 packet.header = (type << 6) | 0x0007;
822 packet.address = (addr & ~3) + 4;
823 packet.data = data >> 8;
824 ret |= sisusb_send_packet(sisusb, 10, &packet);
827 return ret;
830 /* The xxx_bulk routines copy a buffer of variable size. They treat the
831 * buffer as chars, therefore lsb/msb has to be corrected if using the
832 * byte/word/long/etc routines for speed-up
834 * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
835 * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
836 * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
837 * that the data already is in the transfer buffer "sisusb->obuf[index]".
840 static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
841 char *kernbuffer, int length,
842 const char __user *userbuffer, int index,
843 ssize_t *bytes_written)
845 struct sisusb_packet packet;
846 int ret = 0;
847 static int msgcount = 0;
848 u8 swap8, fromkern = kernbuffer ? 1 : 0;
849 u16 swap16;
850 u32 swap32, flag = (length >> 28) & 1;
851 char buf[4];
853 /* if neither kernbuffer not userbuffer are given, assume
854 * data in obuf
856 if (!fromkern && !userbuffer)
857 kernbuffer = sisusb->obuf[index];
859 (*bytes_written = 0);
861 length &= 0x00ffffff;
863 while (length) {
865 switch (length) {
867 case 1:
868 if (userbuffer) {
869 if (get_user(swap8, (u8 __user *)userbuffer))
870 return -EFAULT;
871 } else
872 swap8 = kernbuffer[0];
874 ret = sisusb_write_memio_byte(sisusb,
875 SISUSB_TYPE_MEM,
876 addr, swap8);
878 if (!ret)
879 (*bytes_written)++;
881 return ret;
883 case 2:
884 if (userbuffer) {
885 if (get_user(swap16, (u16 __user *)userbuffer))
886 return -EFAULT;
887 } else
888 swap16 = *((u16 *)kernbuffer);
890 ret = sisusb_write_memio_word(sisusb,
891 SISUSB_TYPE_MEM,
892 addr,
893 swap16);
895 if (!ret)
896 (*bytes_written) += 2;
898 return ret;
900 case 3:
901 if (userbuffer) {
902 if (copy_from_user(&buf, userbuffer, 3))
903 return -EFAULT;
904 #ifdef __BIG_ENDIAN
905 swap32 = (buf[0] << 16) |
906 (buf[1] << 8) |
907 buf[2];
908 #else
909 swap32 = (buf[2] << 16) |
910 (buf[1] << 8) |
911 buf[0];
912 #endif
913 } else
914 #ifdef __BIG_ENDIAN
915 swap32 = (kernbuffer[0] << 16) |
916 (kernbuffer[1] << 8) |
917 kernbuffer[2];
918 #else
919 swap32 = (kernbuffer[2] << 16) |
920 (kernbuffer[1] << 8) |
921 kernbuffer[0];
922 #endif
924 ret = sisusb_write_memio_24bit(sisusb,
925 SISUSB_TYPE_MEM,
926 addr,
927 swap32);
929 if (!ret)
930 (*bytes_written) += 3;
932 return ret;
934 case 4:
935 if (userbuffer) {
936 if (get_user(swap32, (u32 __user *)userbuffer))
937 return -EFAULT;
938 } else
939 swap32 = *((u32 *)kernbuffer);
941 ret = sisusb_write_memio_long(sisusb,
942 SISUSB_TYPE_MEM,
943 addr,
944 swap32);
945 if (!ret)
946 (*bytes_written) += 4;
948 return ret;
950 default:
951 if ((length & ~3) > 0x10000) {
953 packet.header = 0x001f;
954 packet.address = 0x000001d4;
955 packet.data = addr;
956 ret = sisusb_send_bridge_packet(sisusb, 10,
957 &packet, 0);
958 packet.header = 0x001f;
959 packet.address = 0x000001d0;
960 packet.data = (length & ~3);
961 ret |= sisusb_send_bridge_packet(sisusb, 10,
962 &packet, 0);
963 packet.header = 0x001f;
964 packet.address = 0x000001c0;
965 packet.data = flag | 0x16;
966 ret |= sisusb_send_bridge_packet(sisusb, 10,
967 &packet, 0);
968 if (userbuffer) {
969 ret |= sisusb_send_bulk_msg(sisusb,
970 SISUSB_EP_GFX_LBULK_OUT,
971 (length & ~3),
972 NULL, userbuffer, 0,
973 bytes_written, 0, 1);
974 userbuffer += (*bytes_written);
975 } else if (fromkern) {
976 ret |= sisusb_send_bulk_msg(sisusb,
977 SISUSB_EP_GFX_LBULK_OUT,
978 (length & ~3),
979 kernbuffer, NULL, 0,
980 bytes_written, 0, 1);
981 kernbuffer += (*bytes_written);
982 } else {
983 ret |= sisusb_send_bulk_msg(sisusb,
984 SISUSB_EP_GFX_LBULK_OUT,
985 (length & ~3),
986 NULL, NULL, index,
987 bytes_written, 0, 1);
988 kernbuffer += ((*bytes_written) &
989 (sisusb->obufsize-1));
992 } else {
994 packet.header = 0x001f;
995 packet.address = 0x00000194;
996 packet.data = addr;
997 ret = sisusb_send_bridge_packet(sisusb, 10,
998 &packet, 0);
999 packet.header = 0x001f;
1000 packet.address = 0x00000190;
1001 packet.data = (length & ~3);
1002 ret |= sisusb_send_bridge_packet(sisusb, 10,
1003 &packet, 0);
1004 if (sisusb->flagb0 != 0x16) {
1005 packet.header = 0x001f;
1006 packet.address = 0x00000180;
1007 packet.data = flag | 0x16;
1008 ret |= sisusb_send_bridge_packet(sisusb, 10,
1009 &packet, 0);
1010 sisusb->flagb0 = 0x16;
1012 if (userbuffer) {
1013 ret |= sisusb_send_bulk_msg(sisusb,
1014 SISUSB_EP_GFX_BULK_OUT,
1015 (length & ~3),
1016 NULL, userbuffer, 0,
1017 bytes_written, 0, 1);
1018 userbuffer += (*bytes_written);
1019 } else if (fromkern) {
1020 ret |= sisusb_send_bulk_msg(sisusb,
1021 SISUSB_EP_GFX_BULK_OUT,
1022 (length & ~3),
1023 kernbuffer, NULL, 0,
1024 bytes_written, 0, 1);
1025 kernbuffer += (*bytes_written);
1026 } else {
1027 ret |= sisusb_send_bulk_msg(sisusb,
1028 SISUSB_EP_GFX_BULK_OUT,
1029 (length & ~3),
1030 NULL, NULL, index,
1031 bytes_written, 0, 1);
1032 kernbuffer += ((*bytes_written) &
1033 (sisusb->obufsize-1));
1036 if (ret) {
1037 msgcount++;
1038 if (msgcount < 500)
1039 printk(KERN_ERR
1040 "sisusbvga[%d]: Wrote %zd of "
1041 "%d bytes, error %d\n",
1042 sisusb->minor, *bytes_written,
1043 length, ret);
1044 else if (msgcount == 500)
1045 printk(KERN_ERR
1046 "sisusbvga[%d]: Too many errors"
1047 ", logging stopped\n",
1048 sisusb->minor);
1050 addr += (*bytes_written);
1051 length -= (*bytes_written);
1054 if (ret)
1055 break;
1059 return ret ? -EIO : 0;
1062 /* Remember: Read data in packet is in machine-endianess! So for
1063 * byte, word, 24bit, long no endian correction is necessary.
1066 static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1067 u32 addr, u8 *data)
1069 struct sisusb_packet packet;
1070 int ret;
1072 CLEARPACKET(&packet);
1073 packet.header = (1 << (addr & 3)) | (type << 6);
1074 packet.address = addr & ~3;
1075 ret = sisusb_send_packet(sisusb, 6, &packet);
1076 *data = (u8)(packet.data >> ((addr & 3) << 3));
1077 return ret;
1080 static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1081 u32 addr, u16 *data)
1083 struct sisusb_packet packet;
1084 int ret = 0;
1086 CLEARPACKET(&packet);
1088 packet.address = addr & ~3;
1090 switch (addr & 3) {
1091 case 0:
1092 packet.header = (type << 6) | 0x0003;
1093 ret = sisusb_send_packet(sisusb, 6, &packet);
1094 *data = (u16)(packet.data);
1095 break;
1096 case 1:
1097 packet.header = (type << 6) | 0x0006;
1098 ret = sisusb_send_packet(sisusb, 6, &packet);
1099 *data = (u16)(packet.data >> 8);
1100 break;
1101 case 2:
1102 packet.header = (type << 6) | 0x000c;
1103 ret = sisusb_send_packet(sisusb, 6, &packet);
1104 *data = (u16)(packet.data >> 16);
1105 break;
1106 case 3:
1107 packet.header = (type << 6) | 0x0008;
1108 ret = sisusb_send_packet(sisusb, 6, &packet);
1109 *data = (u16)(packet.data >> 24);
1110 packet.header = (type << 6) | 0x0001;
1111 packet.address = (addr & ~3) + 4;
1112 ret |= sisusb_send_packet(sisusb, 6, &packet);
1113 *data |= (u16)(packet.data << 8);
1116 return ret;
1119 static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1120 u32 addr, u32 *data)
1122 struct sisusb_packet packet;
1123 int ret = 0;
1125 packet.address = addr & ~3;
1127 switch (addr & 3) {
1128 case 0:
1129 packet.header = (type << 6) | 0x0007;
1130 ret = sisusb_send_packet(sisusb, 6, &packet);
1131 *data = packet.data & 0x00ffffff;
1132 break;
1133 case 1:
1134 packet.header = (type << 6) | 0x000e;
1135 ret = sisusb_send_packet(sisusb, 6, &packet);
1136 *data = packet.data >> 8;
1137 break;
1138 case 2:
1139 packet.header = (type << 6) | 0x000c;
1140 ret = sisusb_send_packet(sisusb, 6, &packet);
1141 *data = packet.data >> 16;
1142 packet.header = (type << 6) | 0x0001;
1143 packet.address = (addr & ~3) + 4;
1144 ret |= sisusb_send_packet(sisusb, 6, &packet);
1145 *data |= ((packet.data & 0xff) << 16);
1146 break;
1147 case 3:
1148 packet.header = (type << 6) | 0x0008;
1149 ret = sisusb_send_packet(sisusb, 6, &packet);
1150 *data = packet.data >> 24;
1151 packet.header = (type << 6) | 0x0003;
1152 packet.address = (addr & ~3) + 4;
1153 ret |= sisusb_send_packet(sisusb, 6, &packet);
1154 *data |= ((packet.data & 0xffff) << 8);
1157 return ret;
1160 static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1161 u32 addr, u32 *data)
1163 struct sisusb_packet packet;
1164 int ret = 0;
1166 packet.address = addr & ~3;
1168 switch (addr & 3) {
1169 case 0:
1170 packet.header = (type << 6) | 0x000f;
1171 ret = sisusb_send_packet(sisusb, 6, &packet);
1172 *data = packet.data;
1173 break;
1174 case 1:
1175 packet.header = (type << 6) | 0x000e;
1176 ret = sisusb_send_packet(sisusb, 6, &packet);
1177 *data = packet.data >> 8;
1178 packet.header = (type << 6) | 0x0001;
1179 packet.address = (addr & ~3) + 4;
1180 ret |= sisusb_send_packet(sisusb, 6, &packet);
1181 *data |= (packet.data << 24);
1182 break;
1183 case 2:
1184 packet.header = (type << 6) | 0x000c;
1185 ret = sisusb_send_packet(sisusb, 6, &packet);
1186 *data = packet.data >> 16;
1187 packet.header = (type << 6) | 0x0003;
1188 packet.address = (addr & ~3) + 4;
1189 ret |= sisusb_send_packet(sisusb, 6, &packet);
1190 *data |= (packet.data << 16);
1191 break;
1192 case 3:
1193 packet.header = (type << 6) | 0x0008;
1194 ret = sisusb_send_packet(sisusb, 6, &packet);
1195 *data = packet.data >> 24;
1196 packet.header = (type << 6) | 0x0007;
1197 packet.address = (addr & ~3) + 4;
1198 ret |= sisusb_send_packet(sisusb, 6, &packet);
1199 *data |= (packet.data << 8);
1202 return ret;
1205 static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1206 char *kernbuffer, int length,
1207 char __user *userbuffer, ssize_t *bytes_read)
1209 int ret = 0;
1210 char buf[4];
1211 u16 swap16;
1212 u32 swap32;
1214 (*bytes_read = 0);
1216 length &= 0x00ffffff;
1218 while (length) {
1220 switch (length) {
1222 case 1:
1224 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1225 addr, &buf[0]);
1226 if (!ret) {
1227 (*bytes_read)++;
1228 if (userbuffer) {
1229 if (put_user(buf[0],
1230 (u8 __user *)userbuffer)) {
1231 return -EFAULT;
1233 } else {
1234 kernbuffer[0] = buf[0];
1237 return ret;
1239 case 2:
1240 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1241 addr, &swap16);
1242 if (!ret) {
1243 (*bytes_read) += 2;
1244 if (userbuffer) {
1245 if (put_user(swap16,
1246 (u16 __user *)userbuffer))
1247 return -EFAULT;
1248 } else {
1249 *((u16 *)kernbuffer) = swap16;
1252 return ret;
1254 case 3:
1255 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1256 addr, &swap32);
1257 if (!ret) {
1258 (*bytes_read) += 3;
1259 #ifdef __BIG_ENDIAN
1260 buf[0] = (swap32 >> 16) & 0xff;
1261 buf[1] = (swap32 >> 8) & 0xff;
1262 buf[2] = swap32 & 0xff;
1263 #else
1264 buf[2] = (swap32 >> 16) & 0xff;
1265 buf[1] = (swap32 >> 8) & 0xff;
1266 buf[0] = swap32 & 0xff;
1267 #endif
1268 if (userbuffer) {
1269 if (copy_to_user(userbuffer, &buf[0], 3))
1270 return -EFAULT;
1271 } else {
1272 kernbuffer[0] = buf[0];
1273 kernbuffer[1] = buf[1];
1274 kernbuffer[2] = buf[2];
1277 return ret;
1279 default:
1280 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1281 addr, &swap32);
1282 if (!ret) {
1283 (*bytes_read) += 4;
1284 if (userbuffer) {
1285 if (put_user(swap32,
1286 (u32 __user *)userbuffer))
1287 return -EFAULT;
1289 userbuffer += 4;
1290 } else {
1291 *((u32 *)kernbuffer) = swap32;
1292 kernbuffer += 4;
1294 addr += 4;
1295 length -= 4;
1297 #if 0 /* That does not work, as EP 2 is an OUT EP! */
1298 default:
1299 CLEARPACKET(&packet);
1300 packet.header = 0x001f;
1301 packet.address = 0x000001a0;
1302 packet.data = 0x00000006;
1303 ret |= sisusb_send_bridge_packet(sisusb, 10,
1304 &packet, 0);
1305 packet.header = 0x001f;
1306 packet.address = 0x000001b0;
1307 packet.data = (length & ~3) | 0x40000000;
1308 ret |= sisusb_send_bridge_packet(sisusb, 10,
1309 &packet, 0);
1310 packet.header = 0x001f;
1311 packet.address = 0x000001b4;
1312 packet.data = addr;
1313 ret |= sisusb_send_bridge_packet(sisusb, 10,
1314 &packet, 0);
1315 packet.header = 0x001f;
1316 packet.address = 0x000001a4;
1317 packet.data = 0x00000001;
1318 ret |= sisusb_send_bridge_packet(sisusb, 10,
1319 &packet, 0);
1320 if (userbuffer) {
1321 ret |= sisusb_recv_bulk_msg(sisusb,
1322 SISUSB_EP_GFX_BULK_IN,
1323 (length & ~3),
1324 NULL, userbuffer,
1325 bytes_read, 0);
1326 if (!ret) userbuffer += (*bytes_read);
1327 } else {
1328 ret |= sisusb_recv_bulk_msg(sisusb,
1329 SISUSB_EP_GFX_BULK_IN,
1330 (length & ~3),
1331 kernbuffer, NULL,
1332 bytes_read, 0);
1333 if (!ret) kernbuffer += (*bytes_read);
1335 addr += (*bytes_read);
1336 length -= (*bytes_read);
1337 #endif
1340 if (ret)
1341 break;
1344 return ret;
1347 /* High level: Gfx (indexed) register access */
1349 #ifdef INCL_SISUSB_CON
1351 sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
1353 return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1357 sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
1359 return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1361 #endif
1363 #ifndef INCL_SISUSB_CON
1364 static
1365 #endif
1367 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1369 int ret;
1370 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1371 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1372 return ret;
1375 #ifndef INCL_SISUSB_CON
1376 static
1377 #endif
1379 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1381 int ret;
1382 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1383 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1384 return ret;
1387 #ifndef INCL_SISUSB_CON
1388 static
1389 #endif
1391 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1392 u8 myand, u8 myor)
1394 int ret;
1395 u8 tmp;
1397 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1398 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1399 tmp &= myand;
1400 tmp |= myor;
1401 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1402 return ret;
1405 static int
1406 sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1407 u8 data, u8 mask)
1409 int ret;
1410 u8 tmp;
1411 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1412 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1413 tmp &= ~(mask);
1414 tmp |= (data & mask);
1415 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1416 return ret;
1419 #ifndef INCL_SISUSB_CON
1420 static
1421 #endif
1423 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1425 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1428 #ifndef INCL_SISUSB_CON
1429 static
1430 #endif
1432 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1434 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1437 /* Write/read video ram */
1439 #ifdef INCL_SISUSB_CON
1441 sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
1443 return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1447 sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
1449 return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1453 sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
1455 return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1459 sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
1461 return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1465 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
1466 u32 dest, int length, size_t *bytes_written)
1468 return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
1471 #ifdef SISUSBENDIANTEST
1473 sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
1474 u32 src, int length, size_t *bytes_written)
1476 return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
1478 #endif
1479 #endif
1481 #ifdef SISUSBENDIANTEST
1482 static void
1483 sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
1485 static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
1486 char destbuffer[10];
1487 size_t dummy;
1488 int i,j;
1490 sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
1492 for(i = 1; i <= 7; i++) {
1493 printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
1494 sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
1495 for(j = 0; j < i; j++) {
1496 printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
1500 #endif
1502 /* access pci config registers (reg numbers 0, 4, 8, etc) */
1504 static int
1505 sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1507 struct sisusb_packet packet;
1508 int ret;
1510 packet.header = 0x008f;
1511 packet.address = regnum | 0x10000;
1512 packet.data = data;
1513 ret = sisusb_send_packet(sisusb, 10, &packet);
1514 return ret;
1517 static int
1518 sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1520 struct sisusb_packet packet;
1521 int ret;
1523 packet.header = 0x008f;
1524 packet.address = (u32)regnum | 0x10000;
1525 ret = sisusb_send_packet(sisusb, 6, &packet);
1526 *data = packet.data;
1527 return ret;
1530 /* Clear video RAM */
1532 static int
1533 sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1535 int ret, i;
1536 ssize_t j;
1538 if (address < sisusb->vrambase)
1539 return 1;
1541 if (address >= sisusb->vrambase + sisusb->vramsize)
1542 return 1;
1544 if (address + length > sisusb->vrambase + sisusb->vramsize)
1545 length = sisusb->vrambase + sisusb->vramsize - address;
1547 if (length <= 0)
1548 return 0;
1550 /* allocate free buffer/urb and clear the buffer */
1551 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1552 return -EBUSY;
1554 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1556 /* We can write a length > buffer size here. The buffer
1557 * data will simply be re-used (like a ring-buffer).
1559 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1561 /* Free the buffer/urb */
1562 sisusb_free_outbuf(sisusb, i);
1564 return ret;
1567 /* Initialize the graphics core (return 0 on success)
1568 * This resets the graphics hardware and puts it into
1569 * a defined mode (640x480@60Hz)
1572 #define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1573 #define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1574 #define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
1575 #define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
1576 #define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
1577 #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
1578 #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
1579 #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1580 #define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1581 #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1582 #define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1584 static int
1585 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1587 int ret;
1588 u8 tmp8;
1590 ret = GETIREG(SISSR, 0x16, &tmp8);
1591 if (ramtype <= 1) {
1592 tmp8 &= 0x3f;
1593 ret |= SETIREG(SISSR, 0x16, tmp8);
1594 tmp8 |= 0x80;
1595 ret |= SETIREG(SISSR, 0x16, tmp8);
1596 } else {
1597 tmp8 |= 0xc0;
1598 ret |= SETIREG(SISSR, 0x16, tmp8);
1599 tmp8 &= 0x0f;
1600 ret |= SETIREG(SISSR, 0x16, tmp8);
1601 tmp8 |= 0x80;
1602 ret |= SETIREG(SISSR, 0x16, tmp8);
1603 tmp8 &= 0x0f;
1604 ret |= SETIREG(SISSR, 0x16, tmp8);
1605 tmp8 |= 0xd0;
1606 ret |= SETIREG(SISSR, 0x16, tmp8);
1607 tmp8 &= 0x0f;
1608 ret |= SETIREG(SISSR, 0x16, tmp8);
1609 tmp8 |= 0xa0;
1610 ret |= SETIREG(SISSR, 0x16, tmp8);
1612 return ret;
1615 static int
1616 sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1618 int ret;
1619 u8 ramtype, done = 0;
1620 u32 t0, t1, t2, t3;
1621 u32 ramptr = SISUSB_PCI_MEMBASE;
1623 ret = GETIREG(SISSR, 0x3a, &ramtype);
1624 ramtype &= 3;
1626 ret |= SETIREG(SISSR, 0x13, 0x00);
1628 if (ramtype <= 1) {
1629 ret |= SETIREG(SISSR, 0x14, 0x12);
1630 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1631 } else {
1632 ret |= SETIREG(SISSR, 0x14, 0x02);
1635 ret |= sisusb_triggersr16(sisusb, ramtype);
1636 ret |= WRITEL(ramptr + 0, 0x01234567);
1637 ret |= WRITEL(ramptr + 4, 0x456789ab);
1638 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1639 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1640 ret |= WRITEL(ramptr + 16, 0x55555555);
1641 ret |= WRITEL(ramptr + 20, 0x55555555);
1642 ret |= WRITEL(ramptr + 24, 0xffffffff);
1643 ret |= WRITEL(ramptr + 28, 0xffffffff);
1644 ret |= READL(ramptr + 0, &t0);
1645 ret |= READL(ramptr + 4, &t1);
1646 ret |= READL(ramptr + 8, &t2);
1647 ret |= READL(ramptr + 12, &t3);
1649 if (ramtype <= 1) {
1651 *chab = 0; *bw = 64;
1653 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1654 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1655 *chab = 0; *bw = 64;
1656 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1659 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1660 *chab = 1; *bw = 64;
1661 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1663 ret |= sisusb_triggersr16(sisusb, ramtype);
1664 ret |= WRITEL(ramptr + 0, 0x89abcdef);
1665 ret |= WRITEL(ramptr + 4, 0xcdef0123);
1666 ret |= WRITEL(ramptr + 8, 0x55555555);
1667 ret |= WRITEL(ramptr + 12, 0x55555555);
1668 ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1669 ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1670 ret |= READL(ramptr + 4, &t1);
1672 if (t1 != 0xcdef0123) {
1673 *bw = 32;
1674 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1678 } else {
1680 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1682 done = 0;
1684 if (t1 == 0x456789ab) {
1685 if (t0 == 0x01234567) {
1686 *chab = 0; *bw = 64;
1687 done = 1;
1689 } else {
1690 if (t0 == 0x01234567) {
1691 *chab = 0; *bw = 32;
1692 ret |= SETIREG(SISSR, 0x14, 0x00);
1693 done = 1;
1697 if (!done) {
1698 ret |= SETIREG(SISSR, 0x14, 0x03);
1699 ret |= sisusb_triggersr16(sisusb, ramtype);
1701 ret |= WRITEL(ramptr + 0, 0x01234567);
1702 ret |= WRITEL(ramptr + 4, 0x456789ab);
1703 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1704 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1705 ret |= WRITEL(ramptr + 16, 0x55555555);
1706 ret |= WRITEL(ramptr + 20, 0x55555555);
1707 ret |= WRITEL(ramptr + 24, 0xffffffff);
1708 ret |= WRITEL(ramptr + 28, 0xffffffff);
1709 ret |= READL(ramptr + 0, &t0);
1710 ret |= READL(ramptr + 4, &t1);
1712 if (t1 == 0x456789ab) {
1713 if (t0 == 0x01234567) {
1714 *chab = 1; *bw = 64;
1715 return ret;
1716 } /* else error */
1717 } else {
1718 if (t0 == 0x01234567) {
1719 *chab = 1; *bw = 32;
1720 ret |= SETIREG(SISSR, 0x14, 0x01);
1721 } /* else error */
1725 return ret;
1728 static int
1729 sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1731 int ret = 0;
1732 u32 ramptr = SISUSB_PCI_MEMBASE;
1733 u8 tmp1, tmp2, i, j;
1735 ret |= WRITEB(ramptr, 0xaa);
1736 ret |= WRITEB(ramptr + 16, 0x55);
1737 ret |= READB(ramptr, &tmp1);
1738 ret |= READB(ramptr + 16, &tmp2);
1739 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1740 for (i = 0, j = 16; i < 2; i++, j += 16) {
1741 ret |= GETIREG(SISSR, 0x21, &tmp1);
1742 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1743 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1744 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1745 ret |= SETIREG(SISSR, 0x21, tmp1);
1746 ret |= WRITEB(ramptr + 16 + j, j);
1747 ret |= READB(ramptr + 16 + j, &tmp1);
1748 if (tmp1 == j) {
1749 ret |= WRITEB(ramptr + j, j);
1750 break;
1754 return ret;
1757 static int
1758 sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1759 u8 rankno, u8 chab, const u8 dramtype[][5],
1760 int bw)
1762 int ret = 0, ranksize;
1763 u8 tmp;
1765 *iret = 0;
1767 if ((rankno == 2) && (dramtype[index][0] == 2))
1768 return ret;
1770 ranksize = dramtype[index][3] / 2 * bw / 32;
1772 if ((ranksize * rankno) > 128)
1773 return ret;
1775 tmp = 0;
1776 while ((ranksize >>= 1) > 0) tmp += 0x10;
1777 tmp |= ((rankno - 1) << 2);
1778 tmp |= ((bw / 64) & 0x02);
1779 tmp |= (chab & 0x01);
1781 ret = SETIREG(SISSR, 0x14, tmp);
1782 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1784 *iret = 1;
1786 return ret;
1789 static int
1790 sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1792 int ret = 0, i;
1793 u32 j, tmp;
1795 *iret = 0;
1797 for (i = 0, j = 0; i < testn; i++) {
1798 ret |= WRITEL(sisusb->vrambase + j, j);
1799 j += inc;
1802 for (i = 0, j = 0; i < testn; i++) {
1803 ret |= READL(sisusb->vrambase + j, &tmp);
1804 if (tmp != j) return ret;
1805 j += inc;
1808 *iret = 1;
1809 return ret;
1812 static int
1813 sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1814 int idx, int bw, const u8 rtype[][5])
1816 int ret = 0, i, i2ret;
1817 u32 inc;
1819 *iret = 0;
1821 for (i = rankno; i >= 1; i--) {
1822 inc = 1 << (rtype[idx][2] +
1823 rtype[idx][1] +
1824 rtype[idx][0] +
1825 bw / 64 + i);
1826 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1827 if (!i2ret)
1828 return ret;
1831 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1832 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1833 if (!i2ret)
1834 return ret;
1836 inc = 1 << (10 + bw / 64);
1837 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1838 if (!i2ret)
1839 return ret;
1841 *iret = 1;
1842 return ret;
1845 static int
1846 sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1847 int chab)
1849 int ret = 0, i2ret = 0, i, j;
1850 static const u8 sdramtype[13][5] = {
1851 { 2, 12, 9, 64, 0x35 },
1852 { 1, 13, 9, 64, 0x44 },
1853 { 2, 12, 8, 32, 0x31 },
1854 { 2, 11, 9, 32, 0x25 },
1855 { 1, 12, 9, 32, 0x34 },
1856 { 1, 13, 8, 32, 0x40 },
1857 { 2, 11, 8, 16, 0x21 },
1858 { 1, 12, 8, 16, 0x30 },
1859 { 1, 11, 9, 16, 0x24 },
1860 { 1, 11, 8, 8, 0x20 },
1861 { 2, 9, 8, 4, 0x01 },
1862 { 1, 10, 8, 4, 0x10 },
1863 { 1, 9, 8, 2, 0x00 }
1866 *iret = 1; /* error */
1868 for (i = 0; i < 13; i++) {
1869 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1870 for (j = 2; j > 0; j--) {
1871 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1872 chab, sdramtype, bw);
1873 if (!i2ret)
1874 continue;
1876 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1877 bw, sdramtype);
1878 if (i2ret) {
1879 *iret = 0; /* ram size found */
1880 return ret;
1885 return ret;
1888 static int
1889 sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1891 int ret = 0;
1892 u32 address;
1893 int i, length, modex, modey, bpp;
1895 modex = 640; modey = 480; bpp = 2;
1897 address = sisusb->vrambase; /* Clear video ram */
1899 if (clrall)
1900 length = sisusb->vramsize;
1901 else
1902 length = modex * bpp * modey;
1904 ret = sisusb_clear_vram(sisusb, address, length);
1906 if (!ret && drwfr) {
1907 for (i = 0; i < modex; i++) {
1908 address = sisusb->vrambase + (i * bpp);
1909 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1910 address, 0xf100);
1911 address += (modex * (modey-1) * bpp);
1912 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1913 address, 0xf100);
1915 for (i = 0; i < modey; i++) {
1916 address = sisusb->vrambase + ((i * modex) * bpp);
1917 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1918 address, 0xf100);
1919 address += ((modex - 1) * bpp);
1920 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1921 address, 0xf100);
1925 return ret;
1928 static int
1929 sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1931 int ret = 0, i, j, modex, modey, bpp, du;
1932 u8 sr31, cr63, tmp8;
1933 static const char attrdata[] = {
1934 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1935 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1936 0x01,0x00,0x00,0x00
1938 static const char crtcrdata[] = {
1939 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1940 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1941 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1942 0xff
1944 static const char grcdata[] = {
1945 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1946 0xff
1948 static const char crtcdata[] = {
1949 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1950 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1951 0x00
1954 modex = 640; modey = 480; bpp = 2;
1956 GETIREG(SISSR, 0x31, &sr31);
1957 GETIREG(SISCR, 0x63, &cr63);
1958 SETIREGOR(SISSR, 0x01, 0x20);
1959 SETIREG(SISCR, 0x63, cr63 & 0xbf);
1960 SETIREGOR(SISCR, 0x17, 0x80);
1961 SETIREGOR(SISSR, 0x1f, 0x04);
1962 SETIREGAND(SISSR, 0x07, 0xfb);
1963 SETIREG(SISSR, 0x00, 0x03); /* seq */
1964 SETIREG(SISSR, 0x01, 0x21);
1965 SETIREG(SISSR, 0x02, 0x0f);
1966 SETIREG(SISSR, 0x03, 0x00);
1967 SETIREG(SISSR, 0x04, 0x0e);
1968 SETREG(SISMISCW, 0x23); /* misc */
1969 for (i = 0; i <= 0x18; i++) { /* crtc */
1970 SETIREG(SISCR, i, crtcrdata[i]);
1972 for (i = 0; i <= 0x13; i++) { /* att */
1973 GETREG(SISINPSTAT, &tmp8);
1974 SETREG(SISAR, i);
1975 SETREG(SISAR, attrdata[i]);
1977 GETREG(SISINPSTAT, &tmp8);
1978 SETREG(SISAR, 0x14);
1979 SETREG(SISAR, 0x00);
1980 GETREG(SISINPSTAT, &tmp8);
1981 SETREG(SISAR, 0x20);
1982 GETREG(SISINPSTAT, &tmp8);
1983 for (i = 0; i <= 0x08; i++) { /* grc */
1984 SETIREG(SISGR, i, grcdata[i]);
1986 SETIREGAND(SISGR, 0x05, 0xbf);
1987 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1988 SETIREG(SISSR, i, 0x00);
1990 SETIREGAND(SISSR, 0x37, 0xfe);
1991 SETREG(SISMISCW, 0xef); /* sync */
1992 SETIREG(SISCR, 0x11, 0x00); /* crtc */
1993 for (j = 0x00, i = 0; i <= 7; i++, j++) {
1994 SETIREG(SISCR, j, crtcdata[i]);
1996 for (j = 0x10; i <= 10; i++, j++) {
1997 SETIREG(SISCR, j, crtcdata[i]);
1999 for (j = 0x15; i <= 12; i++, j++) {
2000 SETIREG(SISCR, j, crtcdata[i]);
2002 for (j = 0x0A; i <= 15; i++, j++) {
2003 SETIREG(SISSR, j, crtcdata[i]);
2005 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
2006 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
2007 SETIREG(SISCR, 0x14, 0x4f);
2008 du = (modex / 16) * (bpp * 2); /* offset/pitch */
2009 if (modex % 16) du += bpp;
2010 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
2011 SETIREG(SISCR, 0x13, (du & 0xff));
2012 du <<= 5;
2013 tmp8 = du >> 8;
2014 if (du & 0xff) tmp8++;
2015 SETIREG(SISSR, 0x10, tmp8);
2016 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
2017 SETIREG(SISSR, 0x2b, 0x1b);
2018 SETIREG(SISSR, 0x2c, 0xe1);
2019 SETIREG(SISSR, 0x2d, 0x01);
2020 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
2021 SETIREG(SISSR, 0x08, 0xae);
2022 SETIREGAND(SISSR, 0x09, 0xf0);
2023 SETIREG(SISSR, 0x08, 0x34);
2024 SETIREGOR(SISSR, 0x3d, 0x01);
2025 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
2026 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
2027 SETIREG(SISCR, 0x19, 0x00);
2028 SETIREGAND(SISCR, 0x1a, 0xfc);
2029 SETIREGAND(SISSR, 0x0f, 0xb7);
2030 SETIREGAND(SISSR, 0x31, 0xfb);
2031 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
2032 SETIREGAND(SISSR, 0x32, 0xf3);
2033 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
2034 SETIREG(SISCR, 0x52, 0x6c);
2036 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
2037 SETIREG(SISCR, 0x0c, 0x00);
2038 SETIREG(SISSR, 0x0d, 0x00);
2039 SETIREGAND(SISSR, 0x37, 0xfe);
2041 SETIREG(SISCR, 0x32, 0x20);
2042 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
2043 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
2044 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
2046 if (touchengines) {
2047 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
2048 SETIREGOR(SISSR, 0x1e, 0x5a);
2050 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
2051 SETIREG(SISSR, 0x27, 0x1f);
2052 SETIREG(SISSR, 0x26, 0x00);
2055 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
2057 return ret;
2060 static int
2061 sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
2063 int ret = 0, i, j, bw, chab, iret, retry = 3;
2064 u8 tmp8, ramtype;
2065 u32 tmp32;
2066 static const char mclktable[] = {
2067 0x3b, 0x22, 0x01, 143,
2068 0x3b, 0x22, 0x01, 143,
2069 0x3b, 0x22, 0x01, 143,
2070 0x3b, 0x22, 0x01, 143
2072 static const char eclktable[] = {
2073 0x3b, 0x22, 0x01, 143,
2074 0x3b, 0x22, 0x01, 143,
2075 0x3b, 0x22, 0x01, 143,
2076 0x3b, 0x22, 0x01, 143
2078 static const char ramtypetable1[] = {
2079 0x00, 0x04, 0x60, 0x60,
2080 0x0f, 0x0f, 0x1f, 0x1f,
2081 0xba, 0xba, 0xba, 0xba,
2082 0xa9, 0xa9, 0xac, 0xac,
2083 0xa0, 0xa0, 0xa0, 0xa8,
2084 0x00, 0x00, 0x02, 0x02,
2085 0x30, 0x30, 0x40, 0x40
2087 static const char ramtypetable2[] = {
2088 0x77, 0x77, 0x44, 0x44,
2089 0x77, 0x77, 0x44, 0x44,
2090 0x00, 0x00, 0x00, 0x00,
2091 0x5b, 0x5b, 0xab, 0xab,
2092 0x00, 0x00, 0xf0, 0xf8
2095 while (retry--) {
2097 /* Enable VGA */
2098 ret = GETREG(SISVGAEN, &tmp8);
2099 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
2101 /* Enable GPU access to VRAM */
2102 ret |= GETREG(SISMISCR, &tmp8);
2103 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
2105 if (ret) continue;
2107 /* Reset registers */
2108 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
2109 ret |= SETIREG(SISSR, 0x05, 0x86);
2110 ret |= SETIREGOR(SISSR, 0x20, 0x01);
2112 ret |= SETREG(SISMISCW, 0x67);
2114 for (i = 0x06; i <= 0x1f; i++) {
2115 ret |= SETIREG(SISSR, i, 0x00);
2117 for (i = 0x21; i <= 0x27; i++) {
2118 ret |= SETIREG(SISSR, i, 0x00);
2120 for (i = 0x31; i <= 0x3d; i++) {
2121 ret |= SETIREG(SISSR, i, 0x00);
2123 for (i = 0x12; i <= 0x1b; i++) {
2124 ret |= SETIREG(SISSR, i, 0x00);
2126 for (i = 0x79; i <= 0x7c; i++) {
2127 ret |= SETIREG(SISCR, i, 0x00);
2130 if (ret) continue;
2132 ret |= SETIREG(SISCR, 0x63, 0x80);
2134 ret |= GETIREG(SISSR, 0x3a, &ramtype);
2135 ramtype &= 0x03;
2137 ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
2138 ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
2139 ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
2141 ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
2142 ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
2143 ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
2145 ret |= SETIREG(SISSR, 0x07, 0x18);
2146 ret |= SETIREG(SISSR, 0x11, 0x0f);
2148 if (ret) continue;
2150 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2151 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2153 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2154 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2157 ret |= SETIREG(SISCR, 0x49, 0xaa);
2159 ret |= SETIREG(SISSR, 0x1f, 0x00);
2160 ret |= SETIREG(SISSR, 0x20, 0xa0);
2161 ret |= SETIREG(SISSR, 0x23, 0xf6);
2162 ret |= SETIREG(SISSR, 0x24, 0x0d);
2163 ret |= SETIREG(SISSR, 0x25, 0x33);
2165 ret |= SETIREG(SISSR, 0x11, 0x0f);
2167 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2169 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2171 if (ret) continue;
2173 ret |= SETIREG(SISPART1, 0x00, 0x00);
2175 ret |= GETIREG(SISSR, 0x13, &tmp8);
2176 tmp8 >>= 4;
2178 ret |= SETIREG(SISPART1, 0x02, 0x00);
2179 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2181 ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
2182 tmp32 &= 0x00f00000;
2183 tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
2184 ret |= SETIREG(SISSR, 0x25, tmp8);
2185 tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
2186 ret |= SETIREG(SISCR, 0x49, tmp8);
2188 ret |= SETIREG(SISSR, 0x27, 0x1f);
2189 ret |= SETIREG(SISSR, 0x31, 0x00);
2190 ret |= SETIREG(SISSR, 0x32, 0x11);
2191 ret |= SETIREG(SISSR, 0x33, 0x00);
2193 if (ret) continue;
2195 ret |= SETIREG(SISCR, 0x83, 0x00);
2197 ret |= sisusb_set_default_mode(sisusb, 0);
2199 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2200 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2201 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2203 ret |= sisusb_triggersr16(sisusb, ramtype);
2205 /* Disable refresh */
2206 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2207 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2209 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2210 ret |= sisusb_verify_mclk(sisusb);
2212 if (ramtype <= 1) {
2213 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2214 if (iret) {
2215 printk(KERN_ERR "sisusbvga[%d]: RAM size "
2216 "detection failed, "
2217 "assuming 8MB video RAM\n",
2218 sisusb->minor);
2219 ret |= SETIREG(SISSR,0x14,0x31);
2220 /* TODO */
2222 } else {
2223 printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
2224 "assuming 8MB video RAM\n",
2225 sisusb->minor);
2226 ret |= SETIREG(SISSR,0x14,0x31);
2227 /* *** TODO *** */
2230 /* Enable refresh */
2231 ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
2232 ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
2233 ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
2235 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2237 ret |= SETIREG(SISSR, 0x22, 0xfb);
2238 ret |= SETIREG(SISSR, 0x21, 0xa5);
2240 if (ret == 0)
2241 break;
2244 return ret;
2247 #undef SETREG
2248 #undef GETREG
2249 #undef SETIREG
2250 #undef GETIREG
2251 #undef SETIREGOR
2252 #undef SETIREGAND
2253 #undef SETIREGANDOR
2254 #undef READL
2255 #undef WRITEL
2257 static void
2258 sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2260 u8 tmp8, tmp82, ramtype;
2261 int bw = 0;
2262 char *ramtypetext1 = NULL;
2263 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2264 "DDR SDRAM", "DDR SGRAM" };
2265 static const int busSDR[4] = {64, 64, 128, 128};
2266 static const int busDDR[4] = {32, 32, 64, 64};
2267 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2269 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2270 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2271 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2272 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2273 ramtype &= 0x03;
2274 switch ((tmp8 >> 2) & 0x03) {
2275 case 0: ramtypetext1 = "1 ch/1 r";
2276 if (tmp82 & 0x10) {
2277 bw = 32;
2278 } else {
2279 bw = busSDR[(tmp8 & 0x03)];
2281 break;
2282 case 1: ramtypetext1 = "1 ch/2 r";
2283 sisusb->vramsize <<= 1;
2284 bw = busSDR[(tmp8 & 0x03)];
2285 break;
2286 case 2: ramtypetext1 = "asymmeric";
2287 sisusb->vramsize += sisusb->vramsize/2;
2288 bw = busDDRA[(tmp8 & 0x03)];
2289 break;
2290 case 3: ramtypetext1 = "2 channel";
2291 sisusb->vramsize <<= 1;
2292 bw = busDDR[(tmp8 & 0x03)];
2293 break;
2296 printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2297 sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
2298 ramtypetext2[ramtype], bw);
2301 static int
2302 sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2304 struct sisusb_packet packet;
2305 int ret;
2306 u32 tmp32;
2308 /* Do some magic */
2309 packet.header = 0x001f;
2310 packet.address = 0x00000324;
2311 packet.data = 0x00000004;
2312 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2314 packet.header = 0x001f;
2315 packet.address = 0x00000364;
2316 packet.data = 0x00000004;
2317 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2319 packet.header = 0x001f;
2320 packet.address = 0x00000384;
2321 packet.data = 0x00000004;
2322 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2324 packet.header = 0x001f;
2325 packet.address = 0x00000100;
2326 packet.data = 0x00000700;
2327 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2329 packet.header = 0x000f;
2330 packet.address = 0x00000004;
2331 ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2332 packet.data |= 0x17;
2333 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2335 /* Init BAR 0 (VRAM) */
2336 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2337 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2338 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2339 tmp32 &= 0x0f;
2340 tmp32 |= SISUSB_PCI_MEMBASE;
2341 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2343 /* Init BAR 1 (MMIO) */
2344 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2345 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2346 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2347 tmp32 &= 0x0f;
2348 tmp32 |= SISUSB_PCI_MMIOBASE;
2349 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2351 /* Init BAR 2 (i/o ports) */
2352 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2353 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2354 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2355 tmp32 &= 0x0f;
2356 tmp32 |= SISUSB_PCI_IOPORTBASE;
2357 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2359 /* Enable memory and i/o access */
2360 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2361 tmp32 |= 0x3;
2362 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2364 if (ret == 0) {
2365 /* Some further magic */
2366 packet.header = 0x001f;
2367 packet.address = 0x00000050;
2368 packet.data = 0x000000ff;
2369 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2372 return ret;
2375 /* Initialize the graphics device (return 0 on success)
2376 * This initializes the net2280 as well as the PCI registers
2377 * of the graphics board.
2380 static int
2381 sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2383 int ret = 0, test = 0;
2384 u32 tmp32;
2386 if (sisusb->devinit == 1) {
2387 /* Read PCI BARs and see if they have been set up */
2388 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2389 if (ret) return ret;
2390 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
2392 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2393 if (ret) return ret;
2394 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2396 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2397 if (ret) return ret;
2398 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2401 /* No? So reset the device */
2402 if ((sisusb->devinit == 0) || (test != 3)) {
2404 ret |= sisusb_do_init_gfxdevice(sisusb);
2406 if (ret == 0)
2407 sisusb->devinit = 1;
2411 if (sisusb->devinit) {
2412 /* Initialize the graphics core */
2413 if (sisusb_init_gfxcore(sisusb) == 0) {
2414 sisusb->gfxinit = 1;
2415 sisusb_get_ramconfig(sisusb);
2416 ret |= sisusb_set_default_mode(sisusb, 1);
2417 ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2421 return ret;
2425 #ifdef INCL_SISUSB_CON
2427 /* Set up default text mode:
2428 - Set text mode (0x03)
2429 - Upload default font
2430 - Upload user font (if available)
2434 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
2436 int ret = 0, slot = sisusb->font_slot, i;
2437 const struct font_desc *myfont;
2438 u8 *tempbuf;
2439 u16 *tempbufb;
2440 size_t written;
2441 static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
2442 static const char bootlogo[] = "(o_ //\\ V_/_";
2444 /* sisusb->lock is down */
2446 if (!sisusb->SiS_Pr)
2447 return 1;
2449 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2450 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2452 /* Set mode 0x03 */
2453 SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
2455 if (!(myfont = find_font("VGA8x16")))
2456 return 1;
2458 if (!(tempbuf = vmalloc(8192)))
2459 return 1;
2461 for (i = 0; i < 256; i++)
2462 memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
2464 /* Upload default font */
2465 ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
2467 vfree(tempbuf);
2469 /* Upload user font (and reset current slot) */
2470 if (sisusb->font_backup) {
2471 ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
2472 8192, sisusb->font_backup_512, 1, NULL,
2473 sisusb->font_backup_height, 0);
2474 if (slot != 2)
2475 sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
2476 NULL, 16, 0);
2479 if (init && !sisusb->scrbuf) {
2481 if ((tempbuf = vmalloc(8192))) {
2483 i = 4096;
2484 tempbufb = (u16 *)tempbuf;
2485 while (i--)
2486 *(tempbufb++) = 0x0720;
2488 i = 0;
2489 tempbufb = (u16 *)tempbuf;
2490 while (bootlogo[i]) {
2491 *(tempbufb++) = 0x0700 | bootlogo[i++];
2492 if (!(i % 4))
2493 tempbufb += 76;
2496 i = 0;
2497 tempbufb = (u16 *)tempbuf + 6;
2498 while (bootstring[i])
2499 *(tempbufb++) = 0x0700 | bootstring[i++];
2501 ret |= sisusb_copy_memory(sisusb, tempbuf,
2502 sisusb->vrambase, 8192, &written);
2504 vfree(tempbuf);
2508 } else if (sisusb->scrbuf) {
2510 ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
2511 sisusb->vrambase, sisusb->scrbuf_size, &written);
2515 if (sisusb->sisusb_cursor_size_from >= 0 &&
2516 sisusb->sisusb_cursor_size_to >= 0) {
2517 sisusb_setidxreg(sisusb, SISCR, 0x0a,
2518 sisusb->sisusb_cursor_size_from);
2519 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
2520 sisusb->sisusb_cursor_size_to);
2521 } else {
2522 sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
2523 sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
2524 sisusb->sisusb_cursor_size_to = -1;
2527 slot = sisusb->sisusb_cursor_loc;
2528 if(slot < 0) slot = 0;
2530 sisusb->sisusb_cursor_loc = -1;
2531 sisusb->bad_cursor_pos = 1;
2533 sisusb_set_cursor(sisusb, slot);
2535 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
2536 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
2538 sisusb->textmodedestroyed = 0;
2540 /* sisusb->lock is down */
2542 return ret;
2545 #endif
2547 /* fops */
2549 static int
2550 sisusb_open(struct inode *inode, struct file *file)
2552 struct sisusb_usb_data *sisusb;
2553 struct usb_interface *interface;
2554 int subminor = iminor(inode);
2556 mutex_lock(&disconnect_mutex);
2558 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
2559 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
2560 subminor);
2561 mutex_unlock(&disconnect_mutex);
2562 return -ENODEV;
2565 if (!(sisusb = usb_get_intfdata(interface))) {
2566 mutex_unlock(&disconnect_mutex);
2567 return -ENODEV;
2570 mutex_lock(&sisusb->lock);
2572 if (!sisusb->present || !sisusb->ready) {
2573 mutex_unlock(&sisusb->lock);
2574 mutex_unlock(&disconnect_mutex);
2575 return -ENODEV;
2578 if (sisusb->isopen) {
2579 mutex_unlock(&sisusb->lock);
2580 mutex_unlock(&disconnect_mutex);
2581 return -EBUSY;
2584 if (!sisusb->devinit) {
2585 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2586 if (sisusb_init_gfxdevice(sisusb, 0)) {
2587 mutex_unlock(&sisusb->lock);
2588 mutex_unlock(&disconnect_mutex);
2589 printk(KERN_ERR
2590 "sisusbvga[%d]: Failed to initialize "
2591 "device\n",
2592 sisusb->minor);
2593 return -EIO;
2595 } else {
2596 mutex_unlock(&sisusb->lock);
2597 mutex_unlock(&disconnect_mutex);
2598 printk(KERN_ERR
2599 "sisusbvga[%d]: Device not attached to "
2600 "USB 2.0 hub\n",
2601 sisusb->minor);
2602 return -EIO;
2606 /* Increment usage count for our sisusb */
2607 kref_get(&sisusb->kref);
2609 sisusb->isopen = 1;
2611 file->private_data = sisusb;
2613 mutex_unlock(&sisusb->lock);
2615 mutex_unlock(&disconnect_mutex);
2617 return 0;
2620 void
2621 sisusb_delete(struct kref *kref)
2623 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2625 if (!sisusb)
2626 return;
2628 if (sisusb->sisusb_dev)
2629 usb_put_dev(sisusb->sisusb_dev);
2631 sisusb->sisusb_dev = NULL;
2632 sisusb_free_buffers(sisusb);
2633 sisusb_free_urbs(sisusb);
2634 #ifdef INCL_SISUSB_CON
2635 kfree(sisusb->SiS_Pr);
2636 #endif
2637 kfree(sisusb);
2640 static int
2641 sisusb_release(struct inode *inode, struct file *file)
2643 struct sisusb_usb_data *sisusb;
2644 int myminor;
2646 mutex_lock(&disconnect_mutex);
2648 if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
2649 mutex_unlock(&disconnect_mutex);
2650 return -ENODEV;
2653 mutex_lock(&sisusb->lock);
2655 if (sisusb->present) {
2656 /* Wait for all URBs to finish if device still present */
2657 if (!sisusb_wait_all_out_complete(sisusb))
2658 sisusb_kill_all_busy(sisusb);
2661 myminor = sisusb->minor;
2663 sisusb->isopen = 0;
2664 file->private_data = NULL;
2666 mutex_unlock(&sisusb->lock);
2668 /* decrement the usage count on our device */
2669 kref_put(&sisusb->kref, sisusb_delete);
2671 mutex_unlock(&disconnect_mutex);
2673 return 0;
2676 static ssize_t
2677 sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2679 struct sisusb_usb_data *sisusb;
2680 ssize_t bytes_read = 0;
2681 int errno = 0;
2682 u8 buf8;
2683 u16 buf16;
2684 u32 buf32, address;
2686 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2687 return -ENODEV;
2689 mutex_lock(&sisusb->lock);
2691 /* Sanity check */
2692 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2693 mutex_unlock(&sisusb->lock);
2694 return -ENODEV;
2697 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2698 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2700 address = (*ppos) -
2701 SISUSB_PCI_PSEUDO_IOPORTBASE +
2702 SISUSB_PCI_IOPORTBASE;
2704 /* Read i/o ports
2705 * Byte, word and long(32) can be read. As this
2706 * emulates inX instructions, the data returned is
2707 * in machine-endianness.
2709 switch (count) {
2711 case 1:
2712 if (sisusb_read_memio_byte(sisusb,
2713 SISUSB_TYPE_IO,
2714 address, &buf8))
2715 errno = -EIO;
2716 else if (put_user(buf8, (u8 __user *)buffer))
2717 errno = -EFAULT;
2718 else
2719 bytes_read = 1;
2721 break;
2723 case 2:
2724 if (sisusb_read_memio_word(sisusb,
2725 SISUSB_TYPE_IO,
2726 address, &buf16))
2727 errno = -EIO;
2728 else if (put_user(buf16, (u16 __user *)buffer))
2729 errno = -EFAULT;
2730 else
2731 bytes_read = 2;
2733 break;
2735 case 4:
2736 if (sisusb_read_memio_long(sisusb,
2737 SISUSB_TYPE_IO,
2738 address, &buf32))
2739 errno = -EIO;
2740 else if (put_user(buf32, (u32 __user *)buffer))
2741 errno = -EFAULT;
2742 else
2743 bytes_read = 4;
2745 break;
2747 default:
2748 errno = -EIO;
2752 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2753 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2755 address = (*ppos) -
2756 SISUSB_PCI_PSEUDO_MEMBASE +
2757 SISUSB_PCI_MEMBASE;
2759 /* Read video ram
2760 * Remember: Data delivered is never endian-corrected
2762 errno = sisusb_read_mem_bulk(sisusb, address,
2763 NULL, count, buffer, &bytes_read);
2765 if (bytes_read)
2766 errno = bytes_read;
2768 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2769 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2771 address = (*ppos) -
2772 SISUSB_PCI_PSEUDO_MMIOBASE +
2773 SISUSB_PCI_MMIOBASE;
2775 /* Read MMIO
2776 * Remember: Data delivered is never endian-corrected
2778 errno = sisusb_read_mem_bulk(sisusb, address,
2779 NULL, count, buffer, &bytes_read);
2781 if (bytes_read)
2782 errno = bytes_read;
2784 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2785 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2787 if (count != 4) {
2788 mutex_unlock(&sisusb->lock);
2789 return -EINVAL;
2792 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2794 /* Read PCI config register
2795 * Return value delivered in machine endianness.
2797 if (sisusb_read_pci_config(sisusb, address, &buf32))
2798 errno = -EIO;
2799 else if (put_user(buf32, (u32 __user *)buffer))
2800 errno = -EFAULT;
2801 else
2802 bytes_read = 4;
2804 } else {
2806 errno = -EBADFD;
2810 (*ppos) += bytes_read;
2812 mutex_unlock(&sisusb->lock);
2814 return errno ? errno : bytes_read;
2817 static ssize_t
2818 sisusb_write(struct file *file, const char __user *buffer, size_t count,
2819 loff_t *ppos)
2821 struct sisusb_usb_data *sisusb;
2822 int errno = 0;
2823 ssize_t bytes_written = 0;
2824 u8 buf8;
2825 u16 buf16;
2826 u32 buf32, address;
2828 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2829 return -ENODEV;
2831 mutex_lock(&sisusb->lock);
2833 /* Sanity check */
2834 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2835 mutex_unlock(&sisusb->lock);
2836 return -ENODEV;
2839 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2840 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2842 address = (*ppos) -
2843 SISUSB_PCI_PSEUDO_IOPORTBASE +
2844 SISUSB_PCI_IOPORTBASE;
2846 /* Write i/o ports
2847 * Byte, word and long(32) can be written. As this
2848 * emulates outX instructions, the data is expected
2849 * in machine-endianness.
2851 switch (count) {
2853 case 1:
2854 if (get_user(buf8, (u8 __user *)buffer))
2855 errno = -EFAULT;
2856 else if (sisusb_write_memio_byte(sisusb,
2857 SISUSB_TYPE_IO,
2858 address, buf8))
2859 errno = -EIO;
2860 else
2861 bytes_written = 1;
2863 break;
2865 case 2:
2866 if (get_user(buf16, (u16 __user *)buffer))
2867 errno = -EFAULT;
2868 else if (sisusb_write_memio_word(sisusb,
2869 SISUSB_TYPE_IO,
2870 address, buf16))
2871 errno = -EIO;
2872 else
2873 bytes_written = 2;
2875 break;
2877 case 4:
2878 if (get_user(buf32, (u32 __user *)buffer))
2879 errno = -EFAULT;
2880 else if (sisusb_write_memio_long(sisusb,
2881 SISUSB_TYPE_IO,
2882 address, buf32))
2883 errno = -EIO;
2884 else
2885 bytes_written = 4;
2887 break;
2889 default:
2890 errno = -EIO;
2893 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2894 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2896 address = (*ppos) -
2897 SISUSB_PCI_PSEUDO_MEMBASE +
2898 SISUSB_PCI_MEMBASE;
2900 /* Write video ram.
2901 * Buffer is copied 1:1, therefore, on big-endian
2902 * machines, the data must be swapped by userland
2903 * in advance (if applicable; no swapping in 8bpp
2904 * mode or if YUV data is being transferred).
2906 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2907 count, buffer, 0, &bytes_written);
2909 if (bytes_written)
2910 errno = bytes_written;
2912 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2913 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2915 address = (*ppos) -
2916 SISUSB_PCI_PSEUDO_MMIOBASE +
2917 SISUSB_PCI_MMIOBASE;
2919 /* Write MMIO.
2920 * Buffer is copied 1:1, therefore, on big-endian
2921 * machines, the data must be swapped by userland
2922 * in advance.
2924 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2925 count, buffer, 0, &bytes_written);
2927 if (bytes_written)
2928 errno = bytes_written;
2930 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2931 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2933 if (count != 4) {
2934 mutex_unlock(&sisusb->lock);
2935 return -EINVAL;
2938 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2940 /* Write PCI config register.
2941 * Given value expected in machine endianness.
2943 if (get_user(buf32, (u32 __user *)buffer))
2944 errno = -EFAULT;
2945 else if (sisusb_write_pci_config(sisusb, address, buf32))
2946 errno = -EIO;
2947 else
2948 bytes_written = 4;
2951 } else {
2953 /* Error */
2954 errno = -EBADFD;
2958 (*ppos) += bytes_written;
2960 mutex_unlock(&sisusb->lock);
2962 return errno ? errno : bytes_written;
2965 static loff_t
2966 sisusb_lseek(struct file *file, loff_t offset, int orig)
2968 struct sisusb_usb_data *sisusb;
2969 loff_t ret;
2971 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2972 return -ENODEV;
2974 mutex_lock(&sisusb->lock);
2976 /* Sanity check */
2977 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2978 mutex_unlock(&sisusb->lock);
2979 return -ENODEV;
2982 switch (orig) {
2983 case 0:
2984 file->f_pos = offset;
2985 ret = file->f_pos;
2986 /* never negative, no force_successful_syscall needed */
2987 break;
2988 case 1:
2989 file->f_pos += offset;
2990 ret = file->f_pos;
2991 /* never negative, no force_successful_syscall needed */
2992 break;
2993 default:
2994 /* seeking relative to "end of file" is not supported */
2995 ret = -EINVAL;
2998 mutex_unlock(&sisusb->lock);
2999 return ret;
3002 static int
3003 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
3004 unsigned long arg)
3006 int retval, port, length;
3007 u32 address;
3009 /* All our commands require the device
3010 * to be initialized.
3012 if (!sisusb->devinit)
3013 return -ENODEV;
3015 port = y->data3 -
3016 SISUSB_PCI_PSEUDO_IOPORTBASE +
3017 SISUSB_PCI_IOPORTBASE;
3019 switch (y->operation) {
3020 case SUCMD_GET:
3021 retval = sisusb_getidxreg(sisusb, port,
3022 y->data0, &y->data1);
3023 if (!retval) {
3024 if (copy_to_user((void __user *)arg, y,
3025 sizeof(*y)))
3026 retval = -EFAULT;
3028 break;
3030 case SUCMD_SET:
3031 retval = sisusb_setidxreg(sisusb, port,
3032 y->data0, y->data1);
3033 break;
3035 case SUCMD_SETOR:
3036 retval = sisusb_setidxregor(sisusb, port,
3037 y->data0, y->data1);
3038 break;
3040 case SUCMD_SETAND:
3041 retval = sisusb_setidxregand(sisusb, port,
3042 y->data0, y->data1);
3043 break;
3045 case SUCMD_SETANDOR:
3046 retval = sisusb_setidxregandor(sisusb, port,
3047 y->data0, y->data1, y->data2);
3048 break;
3050 case SUCMD_SETMASK:
3051 retval = sisusb_setidxregmask(sisusb, port,
3052 y->data0, y->data1, y->data2);
3053 break;
3055 case SUCMD_CLRSCR:
3056 /* Gfx core must be initialized */
3057 if (!sisusb->gfxinit)
3058 return -ENODEV;
3060 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
3061 address = y->data3 -
3062 SISUSB_PCI_PSEUDO_MEMBASE +
3063 SISUSB_PCI_MEMBASE;
3064 retval = sisusb_clear_vram(sisusb, address, length);
3065 break;
3067 case SUCMD_HANDLETEXTMODE:
3068 retval = 0;
3069 #ifdef INCL_SISUSB_CON
3070 /* Gfx core must be initialized, SiS_Pr must exist */
3071 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3072 return -ENODEV;
3074 switch (y->data0) {
3075 case 0:
3076 retval = sisusb_reset_text_mode(sisusb, 0);
3077 break;
3078 case 1:
3079 sisusb->textmodedestroyed = 1;
3080 break;
3082 #endif
3083 break;
3085 #ifdef INCL_SISUSB_CON
3086 case SUCMD_SETMODE:
3087 /* Gfx core must be initialized, SiS_Pr must exist */
3088 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3089 return -ENODEV;
3091 retval = 0;
3093 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3094 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3096 if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
3097 retval = -EINVAL;
3099 break;
3101 case SUCMD_SETVESAMODE:
3102 /* Gfx core must be initialized, SiS_Pr must exist */
3103 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3104 return -ENODEV;
3106 retval = 0;
3108 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3109 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3111 if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
3112 retval = -EINVAL;
3114 break;
3115 #endif
3117 default:
3118 retval = -EINVAL;
3121 if (retval > 0)
3122 retval = -EIO;
3124 return retval;
3127 static int
3128 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
3129 unsigned long arg)
3131 struct sisusb_usb_data *sisusb;
3132 struct sisusb_info x;
3133 struct sisusb_command y;
3134 int retval = 0;
3135 u32 __user *argp = (u32 __user *)arg;
3137 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
3138 return -ENODEV;
3140 mutex_lock(&sisusb->lock);
3142 /* Sanity check */
3143 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
3144 retval = -ENODEV;
3145 goto err_out;
3148 switch (cmd) {
3150 case SISUSB_GET_CONFIG_SIZE:
3152 if (put_user(sizeof(x), argp))
3153 retval = -EFAULT;
3155 break;
3157 case SISUSB_GET_CONFIG:
3159 x.sisusb_id = SISUSB_ID;
3160 x.sisusb_version = SISUSB_VERSION;
3161 x.sisusb_revision = SISUSB_REVISION;
3162 x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
3163 x.sisusb_gfxinit = sisusb->gfxinit;
3164 x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
3165 x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
3166 x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
3167 x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
3168 x.sisusb_vramsize = sisusb->vramsize;
3169 x.sisusb_minor = sisusb->minor;
3170 x.sisusb_fbdevactive= 0;
3171 #ifdef INCL_SISUSB_CON
3172 x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
3173 #else
3174 x.sisusb_conactive = 0;
3175 #endif
3177 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
3178 retval = -EFAULT;
3180 break;
3182 case SISUSB_COMMAND:
3184 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
3185 retval = -EFAULT;
3186 else
3187 retval = sisusb_handle_command(sisusb, &y, arg);
3189 break;
3191 default:
3192 retval = -ENOTTY;
3193 break;
3196 err_out:
3197 mutex_unlock(&sisusb->lock);
3198 return retval;
3201 #ifdef SISUSB_NEW_CONFIG_COMPAT
3202 static long
3203 sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
3205 long retval;
3207 switch (cmd) {
3208 case SISUSB_GET_CONFIG_SIZE:
3209 case SISUSB_GET_CONFIG:
3210 case SISUSB_COMMAND:
3211 lock_kernel();
3212 retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
3213 unlock_kernel();
3214 return retval;
3216 default:
3217 return -ENOIOCTLCMD;
3220 #endif
3222 static struct file_operations usb_sisusb_fops = {
3223 .owner = THIS_MODULE,
3224 .open = sisusb_open,
3225 .release = sisusb_release,
3226 .read = sisusb_read,
3227 .write = sisusb_write,
3228 .llseek = sisusb_lseek,
3229 #ifdef SISUSB_NEW_CONFIG_COMPAT
3230 .compat_ioctl = sisusb_compat_ioctl,
3231 #endif
3232 .ioctl = sisusb_ioctl
3235 static struct usb_class_driver usb_sisusb_class = {
3236 .name = "sisusbvga%d",
3237 .fops = &usb_sisusb_fops,
3238 .minor_base = SISUSB_MINOR
3241 static int sisusb_probe(struct usb_interface *intf,
3242 const struct usb_device_id *id)
3244 struct usb_device *dev = interface_to_usbdev(intf);
3245 struct sisusb_usb_data *sisusb;
3246 int retval = 0, i;
3247 const char *memfail =
3248 KERN_ERR
3249 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
3251 printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
3252 dev->devnum);
3254 /* Allocate memory for our private */
3255 if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
3256 printk(KERN_ERR
3257 "sisusb: Failed to allocate memory for private data\n");
3258 return -ENOMEM;
3260 kref_init(&sisusb->kref);
3262 mutex_init(&(sisusb->lock));
3264 /* Register device */
3265 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
3266 printk(KERN_ERR
3267 "sisusb: Failed to get a minor for device %d\n",
3268 dev->devnum);
3269 retval = -ENODEV;
3270 goto error_1;
3273 sisusb->sisusb_dev = dev;
3274 sisusb->minor = intf->minor;
3275 sisusb->vrambase = SISUSB_PCI_MEMBASE;
3276 sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
3277 sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
3278 sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
3279 /* Everything else is zero */
3281 /* Allocate buffers */
3282 sisusb->ibufsize = SISUSB_IBUF_SIZE;
3283 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
3284 GFP_KERNEL, &sisusb->transfer_dma_in))) {
3285 printk(memfail, "input", sisusb->minor);
3286 retval = -ENOMEM;
3287 goto error_2;
3290 sisusb->numobufs = 0;
3291 sisusb->obufsize = SISUSB_OBUF_SIZE;
3292 for (i = 0; i < NUMOBUFS; i++) {
3293 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
3294 GFP_KERNEL,
3295 &sisusb->transfer_dma_out[i]))) {
3296 if (i == 0) {
3297 printk(memfail, "output", sisusb->minor);
3298 retval = -ENOMEM;
3299 goto error_3;
3301 break;
3302 } else
3303 sisusb->numobufs++;
3307 /* Allocate URBs */
3308 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
3309 printk(KERN_ERR
3310 "sisusbvga[%d]: Failed to allocate URBs\n",
3311 sisusb->minor);
3312 retval = -ENOMEM;
3313 goto error_3;
3315 sisusb->completein = 1;
3317 for (i = 0; i < sisusb->numobufs; i++) {
3318 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
3319 printk(KERN_ERR
3320 "sisusbvga[%d]: Failed to allocate URBs\n",
3321 sisusb->minor);
3322 retval = -ENOMEM;
3323 goto error_4;
3325 sisusb->urbout_context[i].sisusb = (void *)sisusb;
3326 sisusb->urbout_context[i].urbindex = i;
3327 sisusb->urbstatus[i] = 0;
3330 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
3331 sisusb->minor, sisusb->numobufs);
3333 #ifdef INCL_SISUSB_CON
3334 /* Allocate our SiS_Pr */
3335 if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
3336 printk(KERN_ERR
3337 "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
3338 sisusb->minor);
3340 #endif
3342 /* Do remaining init stuff */
3344 init_waitqueue_head(&sisusb->wait_q);
3346 usb_set_intfdata(intf, sisusb);
3348 usb_get_dev(sisusb->sisusb_dev);
3350 sisusb->present = 1;
3352 #ifdef SISUSB_OLD_CONFIG_COMPAT
3354 int ret;
3355 /* Our ioctls are all "32/64bit compatible" */
3356 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3357 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3358 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3359 if (ret)
3360 printk(KERN_ERR
3361 "sisusbvga[%d]: Error registering ioctl32 "
3362 "translations\n",
3363 sisusb->minor);
3364 else
3365 sisusb->ioctl32registered = 1;
3367 #endif
3369 if (dev->speed == USB_SPEED_HIGH) {
3370 int initscreen = 1;
3371 #ifdef INCL_SISUSB_CON
3372 if (sisusb_first_vc > 0 &&
3373 sisusb_last_vc > 0 &&
3374 sisusb_first_vc <= sisusb_last_vc &&
3375 sisusb_last_vc <= MAX_NR_CONSOLES)
3376 initscreen = 0;
3377 #endif
3378 if (sisusb_init_gfxdevice(sisusb, initscreen))
3379 printk(KERN_ERR
3380 "sisusbvga[%d]: Failed to early "
3381 "initialize device\n",
3382 sisusb->minor);
3384 } else
3385 printk(KERN_INFO
3386 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3387 "deferring init\n",
3388 sisusb->minor);
3390 sisusb->ready = 1;
3392 #ifdef SISUSBENDIANTEST
3393 printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
3394 sisusb_testreadwrite(sisusb);
3395 printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
3396 #endif
3398 #ifdef INCL_SISUSB_CON
3399 sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
3400 #endif
3402 return 0;
3404 error_4:
3405 sisusb_free_urbs(sisusb);
3406 error_3:
3407 sisusb_free_buffers(sisusb);
3408 error_2:
3409 usb_deregister_dev(intf, &usb_sisusb_class);
3410 error_1:
3411 kfree(sisusb);
3412 return retval;
3415 static void sisusb_disconnect(struct usb_interface *intf)
3417 struct sisusb_usb_data *sisusb;
3418 int minor;
3420 /* This should *not* happen */
3421 if (!(sisusb = usb_get_intfdata(intf)))
3422 return;
3424 #ifdef INCL_SISUSB_CON
3425 sisusb_console_exit(sisusb);
3426 #endif
3428 /* The above code doesn't need the disconnect
3429 * semaphore to be down; its meaning is to
3430 * protect all other routines from the disconnect
3431 * case, not the other way round.
3433 mutex_lock(&disconnect_mutex);
3435 mutex_lock(&sisusb->lock);
3437 /* Wait for all URBs to complete and kill them in case (MUST do) */
3438 if (!sisusb_wait_all_out_complete(sisusb))
3439 sisusb_kill_all_busy(sisusb);
3441 minor = sisusb->minor;
3443 usb_set_intfdata(intf, NULL);
3445 usb_deregister_dev(intf, &usb_sisusb_class);
3447 #ifdef SISUSB_OLD_CONFIG_COMPAT
3448 if (sisusb->ioctl32registered) {
3449 int ret;
3450 sisusb->ioctl32registered = 0;
3451 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3452 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3453 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3454 if (ret) {
3455 printk(KERN_ERR
3456 "sisusbvga[%d]: Error unregistering "
3457 "ioctl32 translations\n",
3458 minor);
3461 #endif
3463 sisusb->present = 0;
3464 sisusb->ready = 0;
3466 mutex_unlock(&sisusb->lock);
3468 /* decrement our usage count */
3469 kref_put(&sisusb->kref, sisusb_delete);
3471 mutex_unlock(&disconnect_mutex);
3473 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
3476 static struct usb_device_id sisusb_table [] = {
3477 { USB_DEVICE(0x0711, 0x0900) },
3478 { USB_DEVICE(0x182d, 0x021c) },
3479 { USB_DEVICE(0x182d, 0x0269) },
3483 MODULE_DEVICE_TABLE (usb, sisusb_table);
3485 static struct usb_driver sisusb_driver = {
3486 .name = "sisusb",
3487 .probe = sisusb_probe,
3488 .disconnect = sisusb_disconnect,
3489 .id_table = sisusb_table,
3492 static int __init usb_sisusb_init(void)
3494 int retval;
3496 #ifdef INCL_SISUSB_CON
3497 sisusb_init_concode();
3498 #endif
3500 if (!(retval = usb_register(&sisusb_driver))) {
3502 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3503 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3504 printk(KERN_INFO
3505 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3509 return retval;
3512 static void __exit usb_sisusb_exit(void)
3514 usb_deregister(&sisusb_driver);
3517 module_init(usb_sisusb_init);
3518 module_exit(usb_sisusb_exit);
3520 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3521 MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
3522 MODULE_LICENSE("GPL");