allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / drivers / usb / misc / sisusbvga / sisusb.c
blobb64ca91d9b02353cb43fe51655f2dc7d78f73a6c
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/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>
53 #include "sisusb.h"
54 #include "sisusb_init.h"
56 #ifdef INCL_SISUSB_CON
57 #include <linux/font.h>
58 #endif
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)");
71 #endif
73 static struct usb_driver sisusb_driver;
75 static void
76 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
78 int i;
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;
87 if (sisusb->ibuf) {
88 usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
89 sisusb->ibuf, sisusb->transfer_dma_in);
90 sisusb->ibuf = NULL;
94 static void
95 sisusb_free_urbs(struct sisusb_usb_data *sisusb)
97 int i;
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 */
109 /* 1. out-bulks */
111 /* out-urb management */
113 /* Return 1 if all free, 0 otherwise */
114 static int
115 sisusb_all_free(struct sisusb_usb_data *sisusb)
117 int i;
119 for (i = 0; i < sisusb->numobufs; i++) {
121 if (sisusb->urbstatus[i] & SU_URB_BUSY)
122 return 0;
126 return 1;
129 /* Kill all busy URBs */
130 static void
131 sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
133 int i;
135 if (sisusb_all_free(sisusb))
136 return;
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) */
147 static int
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)),
154 timeout);
156 return i;
159 static int
160 sisusb_outurb_available(struct sisusb_usb_data *sisusb)
162 int i;
164 for (i = 0; i < sisusb->numobufs; i++) {
166 if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
167 return i;
171 return -1;
174 static int
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),
181 timeout);
183 return i;
186 static int
187 sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
189 int i;
191 i = sisusb_outurb_available(sisusb);
193 if (i >= 0)
194 sisusb->urbstatus[i] |= SU_URB_ALLOC;
196 return i;
199 static void
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 */
208 static void
209 sisusb_bulk_completeout(struct urb *urb)
211 struct sisusb_urb_context *context = urb->context;
212 struct sisusb_usb_data *sisusb;
214 if (!context)
215 return;
217 sisusb = context->sisusb;
219 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
220 return;
222 #ifndef SISUSB_DONTSYNC
223 if (context->actual_length)
224 *(context->actual_length) += urb->actual_length;
225 #endif
227 sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
228 wake_up(&sisusb->wait_q);
231 static int
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;
239 /* Set up URB */
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;
251 /* Set up context */
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;
258 /* Submit URB */
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)),
265 timeout);
266 if (sisusb->urbstatus[index] & SU_URB_BUSY) {
267 /* URB timed out... kill it and report error */
268 usb_kill_urb(urb);
269 retval = -ETIMEDOUT;
270 } else {
271 /* Otherwise, report urb status */
272 retval = urb->status;
273 byteswritten = urb->actual_length;
277 if (actual_length)
278 *actual_length = byteswritten;
280 return retval;
283 /* 2. in-bulks */
285 /* completion callback */
287 static void
288 sisusb_bulk_completein(struct urb *urb)
290 struct sisusb_usb_data *sisusb = urb->context;
292 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
293 return;
295 sisusb->completein = 1;
296 wake_up(&sisusb->wait_q);
299 static int
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);
319 if (retval == 0) {
320 wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
321 if (!sisusb->completein) {
322 /* URB timed out... kill it and report error */
323 usb_kill_urb(urb);
324 retval = -ETIMEDOUT;
325 } else {
326 /* URB completed within timout */
327 retval = urb->status;
328 readbytes = urb->actual_length;
332 if (actual_length)
333 *actual_length = readbytes;
335 return retval;
339 /* Level 1: */
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;
362 unsigned int pipe;
363 char *buffer;
365 (*bytes_written) = 0;
367 /* Sanity check */
368 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
369 return -ENODEV;
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)
380 index = -1;
381 else if (len > sisusb->obufsize)
382 async = 0;
384 pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
386 do {
387 passsize = thispass = (sisusb->obufsize < count) ?
388 sisusb->obufsize : count;
390 if (index < 0)
391 index = sisusb_get_free_outbuf(sisusb);
393 if (index < 0)
394 return -EIO;
396 buffer = sisusb->obuf[index];
398 if (fromuser) {
400 if (copy_from_user(buffer, userbuffer, passsize))
401 return -EFAULT;
403 userbuffer += passsize;
405 } else if (fromkern) {
407 memcpy(buffer, kernbuffer, passsize);
408 kernbuffer += passsize;
412 retry = 5;
413 while (thispass) {
415 if (!sisusb->sisusb_dev)
416 return -ENODEV;
418 result = sisusb_bulkout_msg(sisusb,
419 index,
420 pipe,
421 buffer,
422 thispass,
423 &transferred_len,
424 async ? 0 : 5 * HZ,
425 tflags,
426 sisusb->transfer_dma_out[index]);
428 if (result == -ETIMEDOUT) {
430 /* Will not happen if async */
431 if (!retry--)
432 return -ETIME;
434 continue;
436 } else if ((result == 0) && !async && transferred_len) {
438 thispass -= transferred_len;
439 if (thispass) {
440 if (sisusb->transfer_dma_out) {
441 /* If DMA, copy remaining
442 * to beginning of buffer
444 memcpy(buffer,
445 buffer + transferred_len,
446 thispass);
447 } else {
448 /* If not DMA, simply increase
449 * the pointer
451 buffer += transferred_len;
455 } else
456 break;
459 if (result)
460 return result;
462 (*bytes_written) += passsize;
463 count -= passsize;
465 /* Force new allocation in next iteration */
466 if (fromuser || fromkern)
467 index = -1;
469 } while (count > 0);
471 if (async) {
472 #ifdef SISUSB_DONTSYNC
473 (*bytes_written) = len;
474 /* Some URBs/buffers might be busy */
475 #else
476 sisusb_wait_all_out_complete(sisusb);
477 (*bytes_written) = transferred_len;
478 /* All URBs and all buffers are available */
479 #endif
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,
496 unsigned int tflags)
498 int result = 0, retry, count = len;
499 int bufsize, thispass, transferred_len;
500 unsigned int pipe;
501 char *buffer;
503 (*bytes_read) = 0;
505 /* Sanity check */
506 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
507 return -ENODEV;
509 pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
510 buffer = sisusb->ibuf;
511 bufsize = sisusb->ibufsize;
513 retry = 5;
515 #ifdef SISUSB_DONTSYNC
516 if (!(sisusb_wait_all_out_complete(sisusb)))
517 return -EIO;
518 #endif
520 while (count > 0) {
522 if (!sisusb->sisusb_dev)
523 return -ENODEV;
525 thispass = (bufsize < count) ? bufsize : count;
527 result = sisusb_bulkin_msg(sisusb,
528 pipe,
529 buffer,
530 thispass,
531 &transferred_len,
532 5 * HZ,
533 tflags,
534 sisusb->transfer_dma_in);
536 if (transferred_len)
537 thispass = transferred_len;
539 else if (result == -ETIMEDOUT) {
541 if (!retry--)
542 return -ETIME;
544 continue;
546 } else
547 return -EIO;
550 if (thispass) {
552 (*bytes_read) += thispass;
553 count -= thispass;
555 if (userbuffer) {
557 if (copy_to_user(userbuffer, buffer, thispass))
558 return -EFAULT;
560 userbuffer += thispass;
562 } else {
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)
579 int ret;
580 ssize_t bytes_transferred = 0;
581 __le32 tmp;
583 if (len == 6)
584 packet->data = 0;
586 #ifdef SISUSB_DONTSYNC
587 if (!(sisusb_wait_all_out_complete(sisusb)))
588 return 1;
589 #endif
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);
609 return ret;
612 static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
613 struct sisusb_packet *packet,
614 unsigned int tflags)
616 int ret;
617 ssize_t bytes_transferred = 0;
618 __le32 tmp;
620 if (len == 6)
621 packet->data = 0;
623 #ifdef SISUSB_DONTSYNC
624 if (!(sisusb_wait_all_out_complete(sisusb)))
625 return 1;
626 #endif
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);
646 return ret;
649 /* access video memory and mmio (return 0 on success) */
651 /* Low level */
653 /* The following routines assume being used to transfer byte, word,
654 * long etc.
655 * This means that
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,
662 u32 addr, u8 data)
664 struct sisusb_packet packet;
665 int ret;
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);
671 return ret;
674 static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
675 u32 addr, u16 data)
677 struct sisusb_packet packet;
678 int ret = 0;
680 packet.address = addr & ~3;
682 switch (addr & 3) {
683 case 0:
684 packet.header = (type << 6) | 0x0003;
685 packet.data = (u32)data;
686 ret = sisusb_send_packet(sisusb, 10, &packet);
687 break;
688 case 1:
689 packet.header = (type << 6) | 0x0006;
690 packet.data = (u32)data << 8;
691 ret = sisusb_send_packet(sisusb, 10, &packet);
692 break;
693 case 2:
694 packet.header = (type << 6) | 0x000c;
695 packet.data = (u32)data << 16;
696 ret = sisusb_send_packet(sisusb, 10, &packet);
697 break;
698 case 3:
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);
708 return ret;
711 static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
712 u32 addr, u32 data)
714 struct sisusb_packet packet;
715 int ret = 0;
717 packet.address = addr & ~3;
719 switch (addr & 3) {
720 case 0:
721 packet.header = (type << 6) | 0x0007;
722 packet.data = data & 0x00ffffff;
723 ret = sisusb_send_packet(sisusb, 10, &packet);
724 break;
725 case 1:
726 packet.header = (type << 6) | 0x000e;
727 packet.data = data << 8;
728 ret = sisusb_send_packet(sisusb, 10, &packet);
729 break;
730 case 2:
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);
738 break;
739 case 3:
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);
749 return ret;
752 static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
753 u32 addr, u32 data)
755 struct sisusb_packet packet;
756 int ret = 0;
758 packet.address = addr & ~3;
760 switch (addr & 3) {
761 case 0:
762 packet.header = (type << 6) | 0x000f;
763 packet.data = data;
764 ret = sisusb_send_packet(sisusb, 10, &packet);
765 break;
766 case 1:
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);
774 break;
775 case 2:
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);
783 break;
784 case 3:
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);
794 return ret;
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;
813 int ret = 0;
814 static int msgcount = 0;
815 u8 swap8, fromkern = kernbuffer ? 1 : 0;
816 u16 swap16;
817 u32 swap32, flag = (length >> 28) & 1;
818 char buf[4];
820 /* if neither kernbuffer not userbuffer are given, assume
821 * data in obuf
823 if (!fromkern && !userbuffer)
824 kernbuffer = sisusb->obuf[index];
826 (*bytes_written = 0);
828 length &= 0x00ffffff;
830 while (length) {
832 switch (length) {
834 case 1:
835 if (userbuffer) {
836 if (get_user(swap8, (u8 __user *)userbuffer))
837 return -EFAULT;
838 } else
839 swap8 = kernbuffer[0];
841 ret = sisusb_write_memio_byte(sisusb,
842 SISUSB_TYPE_MEM,
843 addr, swap8);
845 if (!ret)
846 (*bytes_written)++;
848 return ret;
850 case 2:
851 if (userbuffer) {
852 if (get_user(swap16, (u16 __user *)userbuffer))
853 return -EFAULT;
854 } else
855 swap16 = *((u16 *)kernbuffer);
857 ret = sisusb_write_memio_word(sisusb,
858 SISUSB_TYPE_MEM,
859 addr,
860 swap16);
862 if (!ret)
863 (*bytes_written) += 2;
865 return ret;
867 case 3:
868 if (userbuffer) {
869 if (copy_from_user(&buf, userbuffer, 3))
870 return -EFAULT;
871 #ifdef __BIG_ENDIAN
872 swap32 = (buf[0] << 16) |
873 (buf[1] << 8) |
874 buf[2];
875 #else
876 swap32 = (buf[2] << 16) |
877 (buf[1] << 8) |
878 buf[0];
879 #endif
880 } else
881 #ifdef __BIG_ENDIAN
882 swap32 = (kernbuffer[0] << 16) |
883 (kernbuffer[1] << 8) |
884 kernbuffer[2];
885 #else
886 swap32 = (kernbuffer[2] << 16) |
887 (kernbuffer[1] << 8) |
888 kernbuffer[0];
889 #endif
891 ret = sisusb_write_memio_24bit(sisusb,
892 SISUSB_TYPE_MEM,
893 addr,
894 swap32);
896 if (!ret)
897 (*bytes_written) += 3;
899 return ret;
901 case 4:
902 if (userbuffer) {
903 if (get_user(swap32, (u32 __user *)userbuffer))
904 return -EFAULT;
905 } else
906 swap32 = *((u32 *)kernbuffer);
908 ret = sisusb_write_memio_long(sisusb,
909 SISUSB_TYPE_MEM,
910 addr,
911 swap32);
912 if (!ret)
913 (*bytes_written) += 4;
915 return ret;
917 default:
918 if ((length & ~3) > 0x10000) {
920 packet.header = 0x001f;
921 packet.address = 0x000001d4;
922 packet.data = addr;
923 ret = sisusb_send_bridge_packet(sisusb, 10,
924 &packet, 0);
925 packet.header = 0x001f;
926 packet.address = 0x000001d0;
927 packet.data = (length & ~3);
928 ret |= sisusb_send_bridge_packet(sisusb, 10,
929 &packet, 0);
930 packet.header = 0x001f;
931 packet.address = 0x000001c0;
932 packet.data = flag | 0x16;
933 ret |= sisusb_send_bridge_packet(sisusb, 10,
934 &packet, 0);
935 if (userbuffer) {
936 ret |= sisusb_send_bulk_msg(sisusb,
937 SISUSB_EP_GFX_LBULK_OUT,
938 (length & ~3),
939 NULL, userbuffer, 0,
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,
945 (length & ~3),
946 kernbuffer, NULL, 0,
947 bytes_written, 0, 1);
948 kernbuffer += (*bytes_written);
949 } else {
950 ret |= sisusb_send_bulk_msg(sisusb,
951 SISUSB_EP_GFX_LBULK_OUT,
952 (length & ~3),
953 NULL, NULL, index,
954 bytes_written, 0, 1);
955 kernbuffer += ((*bytes_written) &
956 (sisusb->obufsize-1));
959 } else {
961 packet.header = 0x001f;
962 packet.address = 0x00000194;
963 packet.data = addr;
964 ret = sisusb_send_bridge_packet(sisusb, 10,
965 &packet, 0);
966 packet.header = 0x001f;
967 packet.address = 0x00000190;
968 packet.data = (length & ~3);
969 ret |= sisusb_send_bridge_packet(sisusb, 10,
970 &packet, 0);
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,
976 &packet, 0);
977 sisusb->flagb0 = 0x16;
979 if (userbuffer) {
980 ret |= sisusb_send_bulk_msg(sisusb,
981 SISUSB_EP_GFX_BULK_OUT,
982 (length & ~3),
983 NULL, userbuffer, 0,
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,
989 (length & ~3),
990 kernbuffer, NULL, 0,
991 bytes_written, 0, 1);
992 kernbuffer += (*bytes_written);
993 } else {
994 ret |= sisusb_send_bulk_msg(sisusb,
995 SISUSB_EP_GFX_BULK_OUT,
996 (length & ~3),
997 NULL, NULL, index,
998 bytes_written, 0, 1);
999 kernbuffer += ((*bytes_written) &
1000 (sisusb->obufsize-1));
1003 if (ret) {
1004 msgcount++;
1005 if (msgcount < 500)
1006 printk(KERN_ERR
1007 "sisusbvga[%d]: Wrote %zd of "
1008 "%d bytes, error %d\n",
1009 sisusb->minor, *bytes_written,
1010 length, ret);
1011 else if (msgcount == 500)
1012 printk(KERN_ERR
1013 "sisusbvga[%d]: Too many errors"
1014 ", logging stopped\n",
1015 sisusb->minor);
1017 addr += (*bytes_written);
1018 length -= (*bytes_written);
1021 if (ret)
1022 break;
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,
1034 u32 addr, u8 *data)
1036 struct sisusb_packet packet;
1037 int ret;
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));
1044 return ret;
1047 static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1048 u32 addr, u16 *data)
1050 struct sisusb_packet packet;
1051 int ret = 0;
1053 CLEARPACKET(&packet);
1055 packet.address = addr & ~3;
1057 switch (addr & 3) {
1058 case 0:
1059 packet.header = (type << 6) | 0x0003;
1060 ret = sisusb_send_packet(sisusb, 6, &packet);
1061 *data = (u16)(packet.data);
1062 break;
1063 case 1:
1064 packet.header = (type << 6) | 0x0006;
1065 ret = sisusb_send_packet(sisusb, 6, &packet);
1066 *data = (u16)(packet.data >> 8);
1067 break;
1068 case 2:
1069 packet.header = (type << 6) | 0x000c;
1070 ret = sisusb_send_packet(sisusb, 6, &packet);
1071 *data = (u16)(packet.data >> 16);
1072 break;
1073 case 3:
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);
1083 return ret;
1086 static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1087 u32 addr, u32 *data)
1089 struct sisusb_packet packet;
1090 int ret = 0;
1092 packet.address = addr & ~3;
1094 switch (addr & 3) {
1095 case 0:
1096 packet.header = (type << 6) | 0x0007;
1097 ret = sisusb_send_packet(sisusb, 6, &packet);
1098 *data = packet.data & 0x00ffffff;
1099 break;
1100 case 1:
1101 packet.header = (type << 6) | 0x000e;
1102 ret = sisusb_send_packet(sisusb, 6, &packet);
1103 *data = packet.data >> 8;
1104 break;
1105 case 2:
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);
1113 break;
1114 case 3:
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);
1124 return ret;
1127 static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1128 u32 addr, u32 *data)
1130 struct sisusb_packet packet;
1131 int ret = 0;
1133 packet.address = addr & ~3;
1135 switch (addr & 3) {
1136 case 0:
1137 packet.header = (type << 6) | 0x000f;
1138 ret = sisusb_send_packet(sisusb, 6, &packet);
1139 *data = packet.data;
1140 break;
1141 case 1:
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);
1149 break;
1150 case 2:
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);
1158 break;
1159 case 3:
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);
1169 return ret;
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)
1176 int ret = 0;
1177 char buf[4];
1178 u16 swap16;
1179 u32 swap32;
1181 (*bytes_read = 0);
1183 length &= 0x00ffffff;
1185 while (length) {
1187 switch (length) {
1189 case 1:
1191 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1192 addr, &buf[0]);
1193 if (!ret) {
1194 (*bytes_read)++;
1195 if (userbuffer) {
1196 if (put_user(buf[0],
1197 (u8 __user *)userbuffer)) {
1198 return -EFAULT;
1200 } else {
1201 kernbuffer[0] = buf[0];
1204 return ret;
1206 case 2:
1207 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1208 addr, &swap16);
1209 if (!ret) {
1210 (*bytes_read) += 2;
1211 if (userbuffer) {
1212 if (put_user(swap16,
1213 (u16 __user *)userbuffer))
1214 return -EFAULT;
1215 } else {
1216 *((u16 *)kernbuffer) = swap16;
1219 return ret;
1221 case 3:
1222 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1223 addr, &swap32);
1224 if (!ret) {
1225 (*bytes_read) += 3;
1226 #ifdef __BIG_ENDIAN
1227 buf[0] = (swap32 >> 16) & 0xff;
1228 buf[1] = (swap32 >> 8) & 0xff;
1229 buf[2] = swap32 & 0xff;
1230 #else
1231 buf[2] = (swap32 >> 16) & 0xff;
1232 buf[1] = (swap32 >> 8) & 0xff;
1233 buf[0] = swap32 & 0xff;
1234 #endif
1235 if (userbuffer) {
1236 if (copy_to_user(userbuffer, &buf[0], 3))
1237 return -EFAULT;
1238 } else {
1239 kernbuffer[0] = buf[0];
1240 kernbuffer[1] = buf[1];
1241 kernbuffer[2] = buf[2];
1244 return ret;
1246 default:
1247 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1248 addr, &swap32);
1249 if (!ret) {
1250 (*bytes_read) += 4;
1251 if (userbuffer) {
1252 if (put_user(swap32,
1253 (u32 __user *)userbuffer))
1254 return -EFAULT;
1256 userbuffer += 4;
1257 } else {
1258 *((u32 *)kernbuffer) = swap32;
1259 kernbuffer += 4;
1261 addr += 4;
1262 length -= 4;
1264 #if 0 /* That does not work, as EP 2 is an OUT EP! */
1265 default:
1266 CLEARPACKET(&packet);
1267 packet.header = 0x001f;
1268 packet.address = 0x000001a0;
1269 packet.data = 0x00000006;
1270 ret |= sisusb_send_bridge_packet(sisusb, 10,
1271 &packet, 0);
1272 packet.header = 0x001f;
1273 packet.address = 0x000001b0;
1274 packet.data = (length & ~3) | 0x40000000;
1275 ret |= sisusb_send_bridge_packet(sisusb, 10,
1276 &packet, 0);
1277 packet.header = 0x001f;
1278 packet.address = 0x000001b4;
1279 packet.data = addr;
1280 ret |= sisusb_send_bridge_packet(sisusb, 10,
1281 &packet, 0);
1282 packet.header = 0x001f;
1283 packet.address = 0x000001a4;
1284 packet.data = 0x00000001;
1285 ret |= sisusb_send_bridge_packet(sisusb, 10,
1286 &packet, 0);
1287 if (userbuffer) {
1288 ret |= sisusb_recv_bulk_msg(sisusb,
1289 SISUSB_EP_GFX_BULK_IN,
1290 (length & ~3),
1291 NULL, userbuffer,
1292 bytes_read, 0);
1293 if (!ret) userbuffer += (*bytes_read);
1294 } else {
1295 ret |= sisusb_recv_bulk_msg(sisusb,
1296 SISUSB_EP_GFX_BULK_IN,
1297 (length & ~3),
1298 kernbuffer, NULL,
1299 bytes_read, 0);
1300 if (!ret) kernbuffer += (*bytes_read);
1302 addr += (*bytes_read);
1303 length -= (*bytes_read);
1304 #endif
1307 if (ret)
1308 break;
1311 return ret;
1314 /* High level: Gfx (indexed) register access */
1316 #ifdef INCL_SISUSB_CON
1318 sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
1320 return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1324 sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
1326 return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1328 #endif
1331 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1333 int ret;
1334 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1335 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1336 return ret;
1340 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1342 int ret;
1343 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1344 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1345 return ret;
1349 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1350 u8 myand, u8 myor)
1352 int ret;
1353 u8 tmp;
1355 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1356 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1357 tmp &= myand;
1358 tmp |= myor;
1359 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1360 return ret;
1363 static int
1364 sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1365 u8 data, u8 mask)
1367 int ret;
1368 u8 tmp;
1369 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1370 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1371 tmp &= ~(mask);
1372 tmp |= (data & mask);
1373 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1374 return ret;
1378 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1380 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1384 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1386 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1389 /* Write/read video ram */
1391 #ifdef INCL_SISUSB_CON
1393 sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
1395 return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1399 sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
1401 return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1404 #if 0
1407 sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
1409 return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1413 sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
1415 return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1418 #endif /* 0 */
1421 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
1422 u32 dest, int length, size_t *bytes_written)
1424 return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
1427 #ifdef SISUSBENDIANTEST
1429 sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
1430 u32 src, int length, size_t *bytes_written)
1432 return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
1434 #endif
1435 #endif
1437 #ifdef SISUSBENDIANTEST
1438 static void
1439 sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
1441 static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
1442 char destbuffer[10];
1443 size_t dummy;
1444 int i,j;
1446 sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
1448 for(i = 1; i <= 7; i++) {
1449 printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
1450 sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
1451 for(j = 0; j < i; j++) {
1452 printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
1456 #endif
1458 /* access pci config registers (reg numbers 0, 4, 8, etc) */
1460 static int
1461 sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1463 struct sisusb_packet packet;
1464 int ret;
1466 packet.header = 0x008f;
1467 packet.address = regnum | 0x10000;
1468 packet.data = data;
1469 ret = sisusb_send_packet(sisusb, 10, &packet);
1470 return ret;
1473 static int
1474 sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1476 struct sisusb_packet packet;
1477 int ret;
1479 packet.header = 0x008f;
1480 packet.address = (u32)regnum | 0x10000;
1481 ret = sisusb_send_packet(sisusb, 6, &packet);
1482 *data = packet.data;
1483 return ret;
1486 /* Clear video RAM */
1488 static int
1489 sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1491 int ret, i;
1492 ssize_t j;
1494 if (address < sisusb->vrambase)
1495 return 1;
1497 if (address >= sisusb->vrambase + sisusb->vramsize)
1498 return 1;
1500 if (address + length > sisusb->vrambase + sisusb->vramsize)
1501 length = sisusb->vrambase + sisusb->vramsize - address;
1503 if (length <= 0)
1504 return 0;
1506 /* allocate free buffer/urb and clear the buffer */
1507 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1508 return -EBUSY;
1510 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1512 /* We can write a length > buffer size here. The buffer
1513 * data will simply be re-used (like a ring-buffer).
1515 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1517 /* Free the buffer/urb */
1518 sisusb_free_outbuf(sisusb, i);
1520 return ret;
1523 /* Initialize the graphics core (return 0 on success)
1524 * This resets the graphics hardware and puts it into
1525 * a defined mode (640x480@60Hz)
1528 #define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1529 #define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1530 #define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
1531 #define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
1532 #define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
1533 #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
1534 #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
1535 #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1536 #define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1537 #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1538 #define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1540 static int
1541 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1543 int ret;
1544 u8 tmp8;
1546 ret = GETIREG(SISSR, 0x16, &tmp8);
1547 if (ramtype <= 1) {
1548 tmp8 &= 0x3f;
1549 ret |= SETIREG(SISSR, 0x16, tmp8);
1550 tmp8 |= 0x80;
1551 ret |= SETIREG(SISSR, 0x16, tmp8);
1552 } else {
1553 tmp8 |= 0xc0;
1554 ret |= SETIREG(SISSR, 0x16, tmp8);
1555 tmp8 &= 0x0f;
1556 ret |= SETIREG(SISSR, 0x16, tmp8);
1557 tmp8 |= 0x80;
1558 ret |= SETIREG(SISSR, 0x16, tmp8);
1559 tmp8 &= 0x0f;
1560 ret |= SETIREG(SISSR, 0x16, tmp8);
1561 tmp8 |= 0xd0;
1562 ret |= SETIREG(SISSR, 0x16, tmp8);
1563 tmp8 &= 0x0f;
1564 ret |= SETIREG(SISSR, 0x16, tmp8);
1565 tmp8 |= 0xa0;
1566 ret |= SETIREG(SISSR, 0x16, tmp8);
1568 return ret;
1571 static int
1572 sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1574 int ret;
1575 u8 ramtype, done = 0;
1576 u32 t0, t1, t2, t3;
1577 u32 ramptr = SISUSB_PCI_MEMBASE;
1579 ret = GETIREG(SISSR, 0x3a, &ramtype);
1580 ramtype &= 3;
1582 ret |= SETIREG(SISSR, 0x13, 0x00);
1584 if (ramtype <= 1) {
1585 ret |= SETIREG(SISSR, 0x14, 0x12);
1586 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1587 } else {
1588 ret |= SETIREG(SISSR, 0x14, 0x02);
1591 ret |= sisusb_triggersr16(sisusb, ramtype);
1592 ret |= WRITEL(ramptr + 0, 0x01234567);
1593 ret |= WRITEL(ramptr + 4, 0x456789ab);
1594 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1595 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1596 ret |= WRITEL(ramptr + 16, 0x55555555);
1597 ret |= WRITEL(ramptr + 20, 0x55555555);
1598 ret |= WRITEL(ramptr + 24, 0xffffffff);
1599 ret |= WRITEL(ramptr + 28, 0xffffffff);
1600 ret |= READL(ramptr + 0, &t0);
1601 ret |= READL(ramptr + 4, &t1);
1602 ret |= READL(ramptr + 8, &t2);
1603 ret |= READL(ramptr + 12, &t3);
1605 if (ramtype <= 1) {
1607 *chab = 0; *bw = 64;
1609 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1610 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1611 *chab = 0; *bw = 64;
1612 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1615 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1616 *chab = 1; *bw = 64;
1617 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1619 ret |= sisusb_triggersr16(sisusb, ramtype);
1620 ret |= WRITEL(ramptr + 0, 0x89abcdef);
1621 ret |= WRITEL(ramptr + 4, 0xcdef0123);
1622 ret |= WRITEL(ramptr + 8, 0x55555555);
1623 ret |= WRITEL(ramptr + 12, 0x55555555);
1624 ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1625 ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1626 ret |= READL(ramptr + 4, &t1);
1628 if (t1 != 0xcdef0123) {
1629 *bw = 32;
1630 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1634 } else {
1636 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1638 done = 0;
1640 if (t1 == 0x456789ab) {
1641 if (t0 == 0x01234567) {
1642 *chab = 0; *bw = 64;
1643 done = 1;
1645 } else {
1646 if (t0 == 0x01234567) {
1647 *chab = 0; *bw = 32;
1648 ret |= SETIREG(SISSR, 0x14, 0x00);
1649 done = 1;
1653 if (!done) {
1654 ret |= SETIREG(SISSR, 0x14, 0x03);
1655 ret |= sisusb_triggersr16(sisusb, ramtype);
1657 ret |= WRITEL(ramptr + 0, 0x01234567);
1658 ret |= WRITEL(ramptr + 4, 0x456789ab);
1659 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1660 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1661 ret |= WRITEL(ramptr + 16, 0x55555555);
1662 ret |= WRITEL(ramptr + 20, 0x55555555);
1663 ret |= WRITEL(ramptr + 24, 0xffffffff);
1664 ret |= WRITEL(ramptr + 28, 0xffffffff);
1665 ret |= READL(ramptr + 0, &t0);
1666 ret |= READL(ramptr + 4, &t1);
1668 if (t1 == 0x456789ab) {
1669 if (t0 == 0x01234567) {
1670 *chab = 1; *bw = 64;
1671 return ret;
1672 } /* else error */
1673 } else {
1674 if (t0 == 0x01234567) {
1675 *chab = 1; *bw = 32;
1676 ret |= SETIREG(SISSR, 0x14, 0x01);
1677 } /* else error */
1681 return ret;
1684 static int
1685 sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1687 int ret = 0;
1688 u32 ramptr = SISUSB_PCI_MEMBASE;
1689 u8 tmp1, tmp2, i, j;
1691 ret |= WRITEB(ramptr, 0xaa);
1692 ret |= WRITEB(ramptr + 16, 0x55);
1693 ret |= READB(ramptr, &tmp1);
1694 ret |= READB(ramptr + 16, &tmp2);
1695 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1696 for (i = 0, j = 16; i < 2; i++, j += 16) {
1697 ret |= GETIREG(SISSR, 0x21, &tmp1);
1698 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1699 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1700 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1701 ret |= SETIREG(SISSR, 0x21, tmp1);
1702 ret |= WRITEB(ramptr + 16 + j, j);
1703 ret |= READB(ramptr + 16 + j, &tmp1);
1704 if (tmp1 == j) {
1705 ret |= WRITEB(ramptr + j, j);
1706 break;
1710 return ret;
1713 static int
1714 sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1715 u8 rankno, u8 chab, const u8 dramtype[][5],
1716 int bw)
1718 int ret = 0, ranksize;
1719 u8 tmp;
1721 *iret = 0;
1723 if ((rankno == 2) && (dramtype[index][0] == 2))
1724 return ret;
1726 ranksize = dramtype[index][3] / 2 * bw / 32;
1728 if ((ranksize * rankno) > 128)
1729 return ret;
1731 tmp = 0;
1732 while ((ranksize >>= 1) > 0) tmp += 0x10;
1733 tmp |= ((rankno - 1) << 2);
1734 tmp |= ((bw / 64) & 0x02);
1735 tmp |= (chab & 0x01);
1737 ret = SETIREG(SISSR, 0x14, tmp);
1738 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1740 *iret = 1;
1742 return ret;
1745 static int
1746 sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1748 int ret = 0, i;
1749 u32 j, tmp;
1751 *iret = 0;
1753 for (i = 0, j = 0; i < testn; i++) {
1754 ret |= WRITEL(sisusb->vrambase + j, j);
1755 j += inc;
1758 for (i = 0, j = 0; i < testn; i++) {
1759 ret |= READL(sisusb->vrambase + j, &tmp);
1760 if (tmp != j) return ret;
1761 j += inc;
1764 *iret = 1;
1765 return ret;
1768 static int
1769 sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1770 int idx, int bw, const u8 rtype[][5])
1772 int ret = 0, i, i2ret;
1773 u32 inc;
1775 *iret = 0;
1777 for (i = rankno; i >= 1; i--) {
1778 inc = 1 << (rtype[idx][2] +
1779 rtype[idx][1] +
1780 rtype[idx][0] +
1781 bw / 64 + i);
1782 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1783 if (!i2ret)
1784 return ret;
1787 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1788 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1789 if (!i2ret)
1790 return ret;
1792 inc = 1 << (10 + bw / 64);
1793 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1794 if (!i2ret)
1795 return ret;
1797 *iret = 1;
1798 return ret;
1801 static int
1802 sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1803 int chab)
1805 int ret = 0, i2ret = 0, i, j;
1806 static const u8 sdramtype[13][5] = {
1807 { 2, 12, 9, 64, 0x35 },
1808 { 1, 13, 9, 64, 0x44 },
1809 { 2, 12, 8, 32, 0x31 },
1810 { 2, 11, 9, 32, 0x25 },
1811 { 1, 12, 9, 32, 0x34 },
1812 { 1, 13, 8, 32, 0x40 },
1813 { 2, 11, 8, 16, 0x21 },
1814 { 1, 12, 8, 16, 0x30 },
1815 { 1, 11, 9, 16, 0x24 },
1816 { 1, 11, 8, 8, 0x20 },
1817 { 2, 9, 8, 4, 0x01 },
1818 { 1, 10, 8, 4, 0x10 },
1819 { 1, 9, 8, 2, 0x00 }
1822 *iret = 1; /* error */
1824 for (i = 0; i < 13; i++) {
1825 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1826 for (j = 2; j > 0; j--) {
1827 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1828 chab, sdramtype, bw);
1829 if (!i2ret)
1830 continue;
1832 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1833 bw, sdramtype);
1834 if (i2ret) {
1835 *iret = 0; /* ram size found */
1836 return ret;
1841 return ret;
1844 static int
1845 sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1847 int ret = 0;
1848 u32 address;
1849 int i, length, modex, modey, bpp;
1851 modex = 640; modey = 480; bpp = 2;
1853 address = sisusb->vrambase; /* Clear video ram */
1855 if (clrall)
1856 length = sisusb->vramsize;
1857 else
1858 length = modex * bpp * modey;
1860 ret = sisusb_clear_vram(sisusb, address, length);
1862 if (!ret && drwfr) {
1863 for (i = 0; i < modex; i++) {
1864 address = sisusb->vrambase + (i * bpp);
1865 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1866 address, 0xf100);
1867 address += (modex * (modey-1) * bpp);
1868 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1869 address, 0xf100);
1871 for (i = 0; i < modey; i++) {
1872 address = sisusb->vrambase + ((i * modex) * bpp);
1873 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1874 address, 0xf100);
1875 address += ((modex - 1) * bpp);
1876 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1877 address, 0xf100);
1881 return ret;
1884 static int
1885 sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1887 int ret = 0, i, j, modex, modey, bpp, du;
1888 u8 sr31, cr63, tmp8;
1889 static const char attrdata[] = {
1890 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1891 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1892 0x01,0x00,0x00,0x00
1894 static const char crtcrdata[] = {
1895 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1896 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1897 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1898 0xff
1900 static const char grcdata[] = {
1901 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1902 0xff
1904 static const char crtcdata[] = {
1905 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1906 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1907 0x00
1910 modex = 640; modey = 480; bpp = 2;
1912 GETIREG(SISSR, 0x31, &sr31);
1913 GETIREG(SISCR, 0x63, &cr63);
1914 SETIREGOR(SISSR, 0x01, 0x20);
1915 SETIREG(SISCR, 0x63, cr63 & 0xbf);
1916 SETIREGOR(SISCR, 0x17, 0x80);
1917 SETIREGOR(SISSR, 0x1f, 0x04);
1918 SETIREGAND(SISSR, 0x07, 0xfb);
1919 SETIREG(SISSR, 0x00, 0x03); /* seq */
1920 SETIREG(SISSR, 0x01, 0x21);
1921 SETIREG(SISSR, 0x02, 0x0f);
1922 SETIREG(SISSR, 0x03, 0x00);
1923 SETIREG(SISSR, 0x04, 0x0e);
1924 SETREG(SISMISCW, 0x23); /* misc */
1925 for (i = 0; i <= 0x18; i++) { /* crtc */
1926 SETIREG(SISCR, i, crtcrdata[i]);
1928 for (i = 0; i <= 0x13; i++) { /* att */
1929 GETREG(SISINPSTAT, &tmp8);
1930 SETREG(SISAR, i);
1931 SETREG(SISAR, attrdata[i]);
1933 GETREG(SISINPSTAT, &tmp8);
1934 SETREG(SISAR, 0x14);
1935 SETREG(SISAR, 0x00);
1936 GETREG(SISINPSTAT, &tmp8);
1937 SETREG(SISAR, 0x20);
1938 GETREG(SISINPSTAT, &tmp8);
1939 for (i = 0; i <= 0x08; i++) { /* grc */
1940 SETIREG(SISGR, i, grcdata[i]);
1942 SETIREGAND(SISGR, 0x05, 0xbf);
1943 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1944 SETIREG(SISSR, i, 0x00);
1946 SETIREGAND(SISSR, 0x37, 0xfe);
1947 SETREG(SISMISCW, 0xef); /* sync */
1948 SETIREG(SISCR, 0x11, 0x00); /* crtc */
1949 for (j = 0x00, i = 0; i <= 7; i++, j++) {
1950 SETIREG(SISCR, j, crtcdata[i]);
1952 for (j = 0x10; i <= 10; i++, j++) {
1953 SETIREG(SISCR, j, crtcdata[i]);
1955 for (j = 0x15; i <= 12; i++, j++) {
1956 SETIREG(SISCR, j, crtcdata[i]);
1958 for (j = 0x0A; i <= 15; i++, j++) {
1959 SETIREG(SISSR, j, crtcdata[i]);
1961 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
1962 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
1963 SETIREG(SISCR, 0x14, 0x4f);
1964 du = (modex / 16) * (bpp * 2); /* offset/pitch */
1965 if (modex % 16) du += bpp;
1966 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
1967 SETIREG(SISCR, 0x13, (du & 0xff));
1968 du <<= 5;
1969 tmp8 = du >> 8;
1970 if (du & 0xff) tmp8++;
1971 SETIREG(SISSR, 0x10, tmp8);
1972 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
1973 SETIREG(SISSR, 0x2b, 0x1b);
1974 SETIREG(SISSR, 0x2c, 0xe1);
1975 SETIREG(SISSR, 0x2d, 0x01);
1976 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
1977 SETIREG(SISSR, 0x08, 0xae);
1978 SETIREGAND(SISSR, 0x09, 0xf0);
1979 SETIREG(SISSR, 0x08, 0x34);
1980 SETIREGOR(SISSR, 0x3d, 0x01);
1981 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
1982 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
1983 SETIREG(SISCR, 0x19, 0x00);
1984 SETIREGAND(SISCR, 0x1a, 0xfc);
1985 SETIREGAND(SISSR, 0x0f, 0xb7);
1986 SETIREGAND(SISSR, 0x31, 0xfb);
1987 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
1988 SETIREGAND(SISSR, 0x32, 0xf3);
1989 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
1990 SETIREG(SISCR, 0x52, 0x6c);
1992 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
1993 SETIREG(SISCR, 0x0c, 0x00);
1994 SETIREG(SISSR, 0x0d, 0x00);
1995 SETIREGAND(SISSR, 0x37, 0xfe);
1997 SETIREG(SISCR, 0x32, 0x20);
1998 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
1999 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
2000 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
2002 if (touchengines) {
2003 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
2004 SETIREGOR(SISSR, 0x1e, 0x5a);
2006 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
2007 SETIREG(SISSR, 0x27, 0x1f);
2008 SETIREG(SISSR, 0x26, 0x00);
2011 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
2013 return ret;
2016 static int
2017 sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
2019 int ret = 0, i, j, bw, chab, iret, retry = 3;
2020 u8 tmp8, ramtype;
2021 u32 tmp32;
2022 static const char mclktable[] = {
2023 0x3b, 0x22, 0x01, 143,
2024 0x3b, 0x22, 0x01, 143,
2025 0x3b, 0x22, 0x01, 143,
2026 0x3b, 0x22, 0x01, 143
2028 static const char eclktable[] = {
2029 0x3b, 0x22, 0x01, 143,
2030 0x3b, 0x22, 0x01, 143,
2031 0x3b, 0x22, 0x01, 143,
2032 0x3b, 0x22, 0x01, 143
2034 static const char ramtypetable1[] = {
2035 0x00, 0x04, 0x60, 0x60,
2036 0x0f, 0x0f, 0x1f, 0x1f,
2037 0xba, 0xba, 0xba, 0xba,
2038 0xa9, 0xa9, 0xac, 0xac,
2039 0xa0, 0xa0, 0xa0, 0xa8,
2040 0x00, 0x00, 0x02, 0x02,
2041 0x30, 0x30, 0x40, 0x40
2043 static const char ramtypetable2[] = {
2044 0x77, 0x77, 0x44, 0x44,
2045 0x77, 0x77, 0x44, 0x44,
2046 0x00, 0x00, 0x00, 0x00,
2047 0x5b, 0x5b, 0xab, 0xab,
2048 0x00, 0x00, 0xf0, 0xf8
2051 while (retry--) {
2053 /* Enable VGA */
2054 ret = GETREG(SISVGAEN, &tmp8);
2055 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
2057 /* Enable GPU access to VRAM */
2058 ret |= GETREG(SISMISCR, &tmp8);
2059 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
2061 if (ret) continue;
2063 /* Reset registers */
2064 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
2065 ret |= SETIREG(SISSR, 0x05, 0x86);
2066 ret |= SETIREGOR(SISSR, 0x20, 0x01);
2068 ret |= SETREG(SISMISCW, 0x67);
2070 for (i = 0x06; i <= 0x1f; i++) {
2071 ret |= SETIREG(SISSR, i, 0x00);
2073 for (i = 0x21; i <= 0x27; i++) {
2074 ret |= SETIREG(SISSR, i, 0x00);
2076 for (i = 0x31; i <= 0x3d; i++) {
2077 ret |= SETIREG(SISSR, i, 0x00);
2079 for (i = 0x12; i <= 0x1b; i++) {
2080 ret |= SETIREG(SISSR, i, 0x00);
2082 for (i = 0x79; i <= 0x7c; i++) {
2083 ret |= SETIREG(SISCR, i, 0x00);
2086 if (ret) continue;
2088 ret |= SETIREG(SISCR, 0x63, 0x80);
2090 ret |= GETIREG(SISSR, 0x3a, &ramtype);
2091 ramtype &= 0x03;
2093 ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
2094 ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
2095 ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
2097 ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
2098 ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
2099 ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
2101 ret |= SETIREG(SISSR, 0x07, 0x18);
2102 ret |= SETIREG(SISSR, 0x11, 0x0f);
2104 if (ret) continue;
2106 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2107 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2109 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2110 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2113 ret |= SETIREG(SISCR, 0x49, 0xaa);
2115 ret |= SETIREG(SISSR, 0x1f, 0x00);
2116 ret |= SETIREG(SISSR, 0x20, 0xa0);
2117 ret |= SETIREG(SISSR, 0x23, 0xf6);
2118 ret |= SETIREG(SISSR, 0x24, 0x0d);
2119 ret |= SETIREG(SISSR, 0x25, 0x33);
2121 ret |= SETIREG(SISSR, 0x11, 0x0f);
2123 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2125 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2127 if (ret) continue;
2129 ret |= SETIREG(SISPART1, 0x00, 0x00);
2131 ret |= GETIREG(SISSR, 0x13, &tmp8);
2132 tmp8 >>= 4;
2134 ret |= SETIREG(SISPART1, 0x02, 0x00);
2135 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2137 ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
2138 tmp32 &= 0x00f00000;
2139 tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
2140 ret |= SETIREG(SISSR, 0x25, tmp8);
2141 tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
2142 ret |= SETIREG(SISCR, 0x49, tmp8);
2144 ret |= SETIREG(SISSR, 0x27, 0x1f);
2145 ret |= SETIREG(SISSR, 0x31, 0x00);
2146 ret |= SETIREG(SISSR, 0x32, 0x11);
2147 ret |= SETIREG(SISSR, 0x33, 0x00);
2149 if (ret) continue;
2151 ret |= SETIREG(SISCR, 0x83, 0x00);
2153 ret |= sisusb_set_default_mode(sisusb, 0);
2155 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2156 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2157 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2159 ret |= sisusb_triggersr16(sisusb, ramtype);
2161 /* Disable refresh */
2162 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2163 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2165 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2166 ret |= sisusb_verify_mclk(sisusb);
2168 if (ramtype <= 1) {
2169 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2170 if (iret) {
2171 printk(KERN_ERR "sisusbvga[%d]: RAM size "
2172 "detection failed, "
2173 "assuming 8MB video RAM\n",
2174 sisusb->minor);
2175 ret |= SETIREG(SISSR,0x14,0x31);
2176 /* TODO */
2178 } else {
2179 printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
2180 "assuming 8MB video RAM\n",
2181 sisusb->minor);
2182 ret |= SETIREG(SISSR,0x14,0x31);
2183 /* *** TODO *** */
2186 /* Enable refresh */
2187 ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
2188 ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
2189 ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
2191 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2193 ret |= SETIREG(SISSR, 0x22, 0xfb);
2194 ret |= SETIREG(SISSR, 0x21, 0xa5);
2196 if (ret == 0)
2197 break;
2200 return ret;
2203 #undef SETREG
2204 #undef GETREG
2205 #undef SETIREG
2206 #undef GETIREG
2207 #undef SETIREGOR
2208 #undef SETIREGAND
2209 #undef SETIREGANDOR
2210 #undef READL
2211 #undef WRITEL
2213 static void
2214 sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2216 u8 tmp8, tmp82, ramtype;
2217 int bw = 0;
2218 char *ramtypetext1 = NULL;
2219 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2220 "DDR SDRAM", "DDR SGRAM" };
2221 static const int busSDR[4] = {64, 64, 128, 128};
2222 static const int busDDR[4] = {32, 32, 64, 64};
2223 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2225 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2226 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2227 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2228 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2229 ramtype &= 0x03;
2230 switch ((tmp8 >> 2) & 0x03) {
2231 case 0: ramtypetext1 = "1 ch/1 r";
2232 if (tmp82 & 0x10) {
2233 bw = 32;
2234 } else {
2235 bw = busSDR[(tmp8 & 0x03)];
2237 break;
2238 case 1: ramtypetext1 = "1 ch/2 r";
2239 sisusb->vramsize <<= 1;
2240 bw = busSDR[(tmp8 & 0x03)];
2241 break;
2242 case 2: ramtypetext1 = "asymmeric";
2243 sisusb->vramsize += sisusb->vramsize/2;
2244 bw = busDDRA[(tmp8 & 0x03)];
2245 break;
2246 case 3: ramtypetext1 = "2 channel";
2247 sisusb->vramsize <<= 1;
2248 bw = busDDR[(tmp8 & 0x03)];
2249 break;
2252 printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2253 sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
2254 ramtypetext2[ramtype], bw);
2257 static int
2258 sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2260 struct sisusb_packet packet;
2261 int ret;
2262 u32 tmp32;
2264 /* Do some magic */
2265 packet.header = 0x001f;
2266 packet.address = 0x00000324;
2267 packet.data = 0x00000004;
2268 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2270 packet.header = 0x001f;
2271 packet.address = 0x00000364;
2272 packet.data = 0x00000004;
2273 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2275 packet.header = 0x001f;
2276 packet.address = 0x00000384;
2277 packet.data = 0x00000004;
2278 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2280 packet.header = 0x001f;
2281 packet.address = 0x00000100;
2282 packet.data = 0x00000700;
2283 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2285 packet.header = 0x000f;
2286 packet.address = 0x00000004;
2287 ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2288 packet.data |= 0x17;
2289 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2291 /* Init BAR 0 (VRAM) */
2292 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2293 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2294 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2295 tmp32 &= 0x0f;
2296 tmp32 |= SISUSB_PCI_MEMBASE;
2297 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2299 /* Init BAR 1 (MMIO) */
2300 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2301 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2302 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2303 tmp32 &= 0x0f;
2304 tmp32 |= SISUSB_PCI_MMIOBASE;
2305 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2307 /* Init BAR 2 (i/o ports) */
2308 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2309 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2310 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2311 tmp32 &= 0x0f;
2312 tmp32 |= SISUSB_PCI_IOPORTBASE;
2313 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2315 /* Enable memory and i/o access */
2316 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2317 tmp32 |= 0x3;
2318 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2320 if (ret == 0) {
2321 /* Some further magic */
2322 packet.header = 0x001f;
2323 packet.address = 0x00000050;
2324 packet.data = 0x000000ff;
2325 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2328 return ret;
2331 /* Initialize the graphics device (return 0 on success)
2332 * This initializes the net2280 as well as the PCI registers
2333 * of the graphics board.
2336 static int
2337 sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2339 int ret = 0, test = 0;
2340 u32 tmp32;
2342 if (sisusb->devinit == 1) {
2343 /* Read PCI BARs and see if they have been set up */
2344 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2345 if (ret) return ret;
2346 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
2348 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2349 if (ret) return ret;
2350 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2352 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2353 if (ret) return ret;
2354 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2357 /* No? So reset the device */
2358 if ((sisusb->devinit == 0) || (test != 3)) {
2360 ret |= sisusb_do_init_gfxdevice(sisusb);
2362 if (ret == 0)
2363 sisusb->devinit = 1;
2367 if (sisusb->devinit) {
2368 /* Initialize the graphics core */
2369 if (sisusb_init_gfxcore(sisusb) == 0) {
2370 sisusb->gfxinit = 1;
2371 sisusb_get_ramconfig(sisusb);
2372 ret |= sisusb_set_default_mode(sisusb, 1);
2373 ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2377 return ret;
2381 #ifdef INCL_SISUSB_CON
2383 /* Set up default text mode:
2384 - Set text mode (0x03)
2385 - Upload default font
2386 - Upload user font (if available)
2390 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
2392 int ret = 0, slot = sisusb->font_slot, i;
2393 const struct font_desc *myfont;
2394 u8 *tempbuf;
2395 u16 *tempbufb;
2396 size_t written;
2397 static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
2398 static const char bootlogo[] = "(o_ //\\ V_/_";
2400 /* sisusb->lock is down */
2402 if (!sisusb->SiS_Pr)
2403 return 1;
2405 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2406 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2408 /* Set mode 0x03 */
2409 SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
2411 if (!(myfont = find_font("VGA8x16")))
2412 return 1;
2414 if (!(tempbuf = vmalloc(8192)))
2415 return 1;
2417 for (i = 0; i < 256; i++)
2418 memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
2420 /* Upload default font */
2421 ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
2423 vfree(tempbuf);
2425 /* Upload user font (and reset current slot) */
2426 if (sisusb->font_backup) {
2427 ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
2428 8192, sisusb->font_backup_512, 1, NULL,
2429 sisusb->font_backup_height, 0);
2430 if (slot != 2)
2431 sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
2432 NULL, 16, 0);
2435 if (init && !sisusb->scrbuf) {
2437 if ((tempbuf = vmalloc(8192))) {
2439 i = 4096;
2440 tempbufb = (u16 *)tempbuf;
2441 while (i--)
2442 *(tempbufb++) = 0x0720;
2444 i = 0;
2445 tempbufb = (u16 *)tempbuf;
2446 while (bootlogo[i]) {
2447 *(tempbufb++) = 0x0700 | bootlogo[i++];
2448 if (!(i % 4))
2449 tempbufb += 76;
2452 i = 0;
2453 tempbufb = (u16 *)tempbuf + 6;
2454 while (bootstring[i])
2455 *(tempbufb++) = 0x0700 | bootstring[i++];
2457 ret |= sisusb_copy_memory(sisusb, tempbuf,
2458 sisusb->vrambase, 8192, &written);
2460 vfree(tempbuf);
2464 } else if (sisusb->scrbuf) {
2466 ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
2467 sisusb->vrambase, sisusb->scrbuf_size, &written);
2471 if (sisusb->sisusb_cursor_size_from >= 0 &&
2472 sisusb->sisusb_cursor_size_to >= 0) {
2473 sisusb_setidxreg(sisusb, SISCR, 0x0a,
2474 sisusb->sisusb_cursor_size_from);
2475 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
2476 sisusb->sisusb_cursor_size_to);
2477 } else {
2478 sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
2479 sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
2480 sisusb->sisusb_cursor_size_to = -1;
2483 slot = sisusb->sisusb_cursor_loc;
2484 if(slot < 0) slot = 0;
2486 sisusb->sisusb_cursor_loc = -1;
2487 sisusb->bad_cursor_pos = 1;
2489 sisusb_set_cursor(sisusb, slot);
2491 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
2492 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
2494 sisusb->textmodedestroyed = 0;
2496 /* sisusb->lock is down */
2498 return ret;
2501 #endif
2503 /* fops */
2505 static int
2506 sisusb_open(struct inode *inode, struct file *file)
2508 struct sisusb_usb_data *sisusb;
2509 struct usb_interface *interface;
2510 int subminor = iminor(inode);
2512 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
2513 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
2514 subminor);
2515 return -ENODEV;
2518 if (!(sisusb = usb_get_intfdata(interface)))
2519 return -ENODEV;
2521 mutex_lock(&sisusb->lock);
2523 if (!sisusb->present || !sisusb->ready) {
2524 mutex_unlock(&sisusb->lock);
2525 return -ENODEV;
2528 if (sisusb->isopen) {
2529 mutex_unlock(&sisusb->lock);
2530 return -EBUSY;
2533 if (!sisusb->devinit) {
2534 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2535 if (sisusb_init_gfxdevice(sisusb, 0)) {
2536 mutex_unlock(&sisusb->lock);
2537 printk(KERN_ERR
2538 "sisusbvga[%d]: Failed to initialize "
2539 "device\n",
2540 sisusb->minor);
2541 return -EIO;
2543 } else {
2544 mutex_unlock(&sisusb->lock);
2545 printk(KERN_ERR
2546 "sisusbvga[%d]: Device not attached to "
2547 "USB 2.0 hub\n",
2548 sisusb->minor);
2549 return -EIO;
2553 /* Increment usage count for our sisusb */
2554 kref_get(&sisusb->kref);
2556 sisusb->isopen = 1;
2558 file->private_data = sisusb;
2560 mutex_unlock(&sisusb->lock);
2562 return 0;
2565 void
2566 sisusb_delete(struct kref *kref)
2568 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2570 if (!sisusb)
2571 return;
2573 if (sisusb->sisusb_dev)
2574 usb_put_dev(sisusb->sisusb_dev);
2576 sisusb->sisusb_dev = NULL;
2577 sisusb_free_buffers(sisusb);
2578 sisusb_free_urbs(sisusb);
2579 #ifdef INCL_SISUSB_CON
2580 kfree(sisusb->SiS_Pr);
2581 #endif
2582 kfree(sisusb);
2585 static int
2586 sisusb_release(struct inode *inode, struct file *file)
2588 struct sisusb_usb_data *sisusb;
2589 int myminor;
2591 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2592 return -ENODEV;
2594 mutex_lock(&sisusb->lock);
2596 if (sisusb->present) {
2597 /* Wait for all URBs to finish if device still present */
2598 if (!sisusb_wait_all_out_complete(sisusb))
2599 sisusb_kill_all_busy(sisusb);
2602 myminor = sisusb->minor;
2604 sisusb->isopen = 0;
2605 file->private_data = NULL;
2607 mutex_unlock(&sisusb->lock);
2609 /* decrement the usage count on our device */
2610 kref_put(&sisusb->kref, sisusb_delete);
2612 return 0;
2615 static ssize_t
2616 sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2618 struct sisusb_usb_data *sisusb;
2619 ssize_t bytes_read = 0;
2620 int errno = 0;
2621 u8 buf8;
2622 u16 buf16;
2623 u32 buf32, address;
2625 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2626 return -ENODEV;
2628 mutex_lock(&sisusb->lock);
2630 /* Sanity check */
2631 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2632 mutex_unlock(&sisusb->lock);
2633 return -ENODEV;
2636 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2637 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2639 address = (*ppos) -
2640 SISUSB_PCI_PSEUDO_IOPORTBASE +
2641 SISUSB_PCI_IOPORTBASE;
2643 /* Read i/o ports
2644 * Byte, word and long(32) can be read. As this
2645 * emulates inX instructions, the data returned is
2646 * in machine-endianness.
2648 switch (count) {
2650 case 1:
2651 if (sisusb_read_memio_byte(sisusb,
2652 SISUSB_TYPE_IO,
2653 address, &buf8))
2654 errno = -EIO;
2655 else if (put_user(buf8, (u8 __user *)buffer))
2656 errno = -EFAULT;
2657 else
2658 bytes_read = 1;
2660 break;
2662 case 2:
2663 if (sisusb_read_memio_word(sisusb,
2664 SISUSB_TYPE_IO,
2665 address, &buf16))
2666 errno = -EIO;
2667 else if (put_user(buf16, (u16 __user *)buffer))
2668 errno = -EFAULT;
2669 else
2670 bytes_read = 2;
2672 break;
2674 case 4:
2675 if (sisusb_read_memio_long(sisusb,
2676 SISUSB_TYPE_IO,
2677 address, &buf32))
2678 errno = -EIO;
2679 else if (put_user(buf32, (u32 __user *)buffer))
2680 errno = -EFAULT;
2681 else
2682 bytes_read = 4;
2684 break;
2686 default:
2687 errno = -EIO;
2691 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2692 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2694 address = (*ppos) -
2695 SISUSB_PCI_PSEUDO_MEMBASE +
2696 SISUSB_PCI_MEMBASE;
2698 /* Read video ram
2699 * Remember: Data delivered is never endian-corrected
2701 errno = sisusb_read_mem_bulk(sisusb, address,
2702 NULL, count, buffer, &bytes_read);
2704 if (bytes_read)
2705 errno = bytes_read;
2707 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2708 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2710 address = (*ppos) -
2711 SISUSB_PCI_PSEUDO_MMIOBASE +
2712 SISUSB_PCI_MMIOBASE;
2714 /* Read MMIO
2715 * Remember: Data delivered is never endian-corrected
2717 errno = sisusb_read_mem_bulk(sisusb, address,
2718 NULL, count, buffer, &bytes_read);
2720 if (bytes_read)
2721 errno = bytes_read;
2723 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2724 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2726 if (count != 4) {
2727 mutex_unlock(&sisusb->lock);
2728 return -EINVAL;
2731 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2733 /* Read PCI config register
2734 * Return value delivered in machine endianness.
2736 if (sisusb_read_pci_config(sisusb, address, &buf32))
2737 errno = -EIO;
2738 else if (put_user(buf32, (u32 __user *)buffer))
2739 errno = -EFAULT;
2740 else
2741 bytes_read = 4;
2743 } else {
2745 errno = -EBADFD;
2749 (*ppos) += bytes_read;
2751 mutex_unlock(&sisusb->lock);
2753 return errno ? errno : bytes_read;
2756 static ssize_t
2757 sisusb_write(struct file *file, const char __user *buffer, size_t count,
2758 loff_t *ppos)
2760 struct sisusb_usb_data *sisusb;
2761 int errno = 0;
2762 ssize_t bytes_written = 0;
2763 u8 buf8;
2764 u16 buf16;
2765 u32 buf32, address;
2767 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2768 return -ENODEV;
2770 mutex_lock(&sisusb->lock);
2772 /* Sanity check */
2773 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2774 mutex_unlock(&sisusb->lock);
2775 return -ENODEV;
2778 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2779 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2781 address = (*ppos) -
2782 SISUSB_PCI_PSEUDO_IOPORTBASE +
2783 SISUSB_PCI_IOPORTBASE;
2785 /* Write i/o ports
2786 * Byte, word and long(32) can be written. As this
2787 * emulates outX instructions, the data is expected
2788 * in machine-endianness.
2790 switch (count) {
2792 case 1:
2793 if (get_user(buf8, (u8 __user *)buffer))
2794 errno = -EFAULT;
2795 else if (sisusb_write_memio_byte(sisusb,
2796 SISUSB_TYPE_IO,
2797 address, buf8))
2798 errno = -EIO;
2799 else
2800 bytes_written = 1;
2802 break;
2804 case 2:
2805 if (get_user(buf16, (u16 __user *)buffer))
2806 errno = -EFAULT;
2807 else if (sisusb_write_memio_word(sisusb,
2808 SISUSB_TYPE_IO,
2809 address, buf16))
2810 errno = -EIO;
2811 else
2812 bytes_written = 2;
2814 break;
2816 case 4:
2817 if (get_user(buf32, (u32 __user *)buffer))
2818 errno = -EFAULT;
2819 else if (sisusb_write_memio_long(sisusb,
2820 SISUSB_TYPE_IO,
2821 address, buf32))
2822 errno = -EIO;
2823 else
2824 bytes_written = 4;
2826 break;
2828 default:
2829 errno = -EIO;
2832 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2833 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2835 address = (*ppos) -
2836 SISUSB_PCI_PSEUDO_MEMBASE +
2837 SISUSB_PCI_MEMBASE;
2839 /* Write video ram.
2840 * Buffer is copied 1:1, therefore, on big-endian
2841 * machines, the data must be swapped by userland
2842 * in advance (if applicable; no swapping in 8bpp
2843 * mode or if YUV data is being transferred).
2845 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2846 count, buffer, 0, &bytes_written);
2848 if (bytes_written)
2849 errno = bytes_written;
2851 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2852 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2854 address = (*ppos) -
2855 SISUSB_PCI_PSEUDO_MMIOBASE +
2856 SISUSB_PCI_MMIOBASE;
2858 /* Write MMIO.
2859 * Buffer is copied 1:1, therefore, on big-endian
2860 * machines, the data must be swapped by userland
2861 * in advance.
2863 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2864 count, buffer, 0, &bytes_written);
2866 if (bytes_written)
2867 errno = bytes_written;
2869 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2870 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2872 if (count != 4) {
2873 mutex_unlock(&sisusb->lock);
2874 return -EINVAL;
2877 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2879 /* Write PCI config register.
2880 * Given value expected in machine endianness.
2882 if (get_user(buf32, (u32 __user *)buffer))
2883 errno = -EFAULT;
2884 else if (sisusb_write_pci_config(sisusb, address, buf32))
2885 errno = -EIO;
2886 else
2887 bytes_written = 4;
2890 } else {
2892 /* Error */
2893 errno = -EBADFD;
2897 (*ppos) += bytes_written;
2899 mutex_unlock(&sisusb->lock);
2901 return errno ? errno : bytes_written;
2904 static loff_t
2905 sisusb_lseek(struct file *file, loff_t offset, int orig)
2907 struct sisusb_usb_data *sisusb;
2908 loff_t ret;
2910 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2911 return -ENODEV;
2913 mutex_lock(&sisusb->lock);
2915 /* Sanity check */
2916 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2917 mutex_unlock(&sisusb->lock);
2918 return -ENODEV;
2921 switch (orig) {
2922 case 0:
2923 file->f_pos = offset;
2924 ret = file->f_pos;
2925 /* never negative, no force_successful_syscall needed */
2926 break;
2927 case 1:
2928 file->f_pos += offset;
2929 ret = file->f_pos;
2930 /* never negative, no force_successful_syscall needed */
2931 break;
2932 default:
2933 /* seeking relative to "end of file" is not supported */
2934 ret = -EINVAL;
2937 mutex_unlock(&sisusb->lock);
2938 return ret;
2941 static int
2942 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2943 unsigned long arg)
2945 int retval, port, length;
2946 u32 address;
2948 /* All our commands require the device
2949 * to be initialized.
2951 if (!sisusb->devinit)
2952 return -ENODEV;
2954 port = y->data3 -
2955 SISUSB_PCI_PSEUDO_IOPORTBASE +
2956 SISUSB_PCI_IOPORTBASE;
2958 switch (y->operation) {
2959 case SUCMD_GET:
2960 retval = sisusb_getidxreg(sisusb, port,
2961 y->data0, &y->data1);
2962 if (!retval) {
2963 if (copy_to_user((void __user *)arg, y,
2964 sizeof(*y)))
2965 retval = -EFAULT;
2967 break;
2969 case SUCMD_SET:
2970 retval = sisusb_setidxreg(sisusb, port,
2971 y->data0, y->data1);
2972 break;
2974 case SUCMD_SETOR:
2975 retval = sisusb_setidxregor(sisusb, port,
2976 y->data0, y->data1);
2977 break;
2979 case SUCMD_SETAND:
2980 retval = sisusb_setidxregand(sisusb, port,
2981 y->data0, y->data1);
2982 break;
2984 case SUCMD_SETANDOR:
2985 retval = sisusb_setidxregandor(sisusb, port,
2986 y->data0, y->data1, y->data2);
2987 break;
2989 case SUCMD_SETMASK:
2990 retval = sisusb_setidxregmask(sisusb, port,
2991 y->data0, y->data1, y->data2);
2992 break;
2994 case SUCMD_CLRSCR:
2995 /* Gfx core must be initialized */
2996 if (!sisusb->gfxinit)
2997 return -ENODEV;
2999 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
3000 address = y->data3 -
3001 SISUSB_PCI_PSEUDO_MEMBASE +
3002 SISUSB_PCI_MEMBASE;
3003 retval = sisusb_clear_vram(sisusb, address, length);
3004 break;
3006 case SUCMD_HANDLETEXTMODE:
3007 retval = 0;
3008 #ifdef INCL_SISUSB_CON
3009 /* Gfx core must be initialized, SiS_Pr must exist */
3010 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3011 return -ENODEV;
3013 switch (y->data0) {
3014 case 0:
3015 retval = sisusb_reset_text_mode(sisusb, 0);
3016 break;
3017 case 1:
3018 sisusb->textmodedestroyed = 1;
3019 break;
3021 #endif
3022 break;
3024 #ifdef INCL_SISUSB_CON
3025 case SUCMD_SETMODE:
3026 /* Gfx core must be initialized, SiS_Pr must exist */
3027 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3028 return -ENODEV;
3030 retval = 0;
3032 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3033 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3035 if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
3036 retval = -EINVAL;
3038 break;
3040 case SUCMD_SETVESAMODE:
3041 /* Gfx core must be initialized, SiS_Pr must exist */
3042 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3043 return -ENODEV;
3045 retval = 0;
3047 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3048 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3050 if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
3051 retval = -EINVAL;
3053 break;
3054 #endif
3056 default:
3057 retval = -EINVAL;
3060 if (retval > 0)
3061 retval = -EIO;
3063 return retval;
3066 static int
3067 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
3068 unsigned long arg)
3070 struct sisusb_usb_data *sisusb;
3071 struct sisusb_info x;
3072 struct sisusb_command y;
3073 int retval = 0;
3074 u32 __user *argp = (u32 __user *)arg;
3076 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
3077 return -ENODEV;
3079 mutex_lock(&sisusb->lock);
3081 /* Sanity check */
3082 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
3083 retval = -ENODEV;
3084 goto err_out;
3087 switch (cmd) {
3089 case SISUSB_GET_CONFIG_SIZE:
3091 if (put_user(sizeof(x), argp))
3092 retval = -EFAULT;
3094 break;
3096 case SISUSB_GET_CONFIG:
3098 x.sisusb_id = SISUSB_ID;
3099 x.sisusb_version = SISUSB_VERSION;
3100 x.sisusb_revision = SISUSB_REVISION;
3101 x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
3102 x.sisusb_gfxinit = sisusb->gfxinit;
3103 x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
3104 x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
3105 x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
3106 x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
3107 x.sisusb_vramsize = sisusb->vramsize;
3108 x.sisusb_minor = sisusb->minor;
3109 x.sisusb_fbdevactive= 0;
3110 #ifdef INCL_SISUSB_CON
3111 x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
3112 #else
3113 x.sisusb_conactive = 0;
3114 #endif
3116 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
3117 retval = -EFAULT;
3119 break;
3121 case SISUSB_COMMAND:
3123 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
3124 retval = -EFAULT;
3125 else
3126 retval = sisusb_handle_command(sisusb, &y, arg);
3128 break;
3130 default:
3131 retval = -ENOTTY;
3132 break;
3135 err_out:
3136 mutex_unlock(&sisusb->lock);
3137 return retval;
3140 #ifdef SISUSB_NEW_CONFIG_COMPAT
3141 static long
3142 sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
3144 long retval;
3146 switch (cmd) {
3147 case SISUSB_GET_CONFIG_SIZE:
3148 case SISUSB_GET_CONFIG:
3149 case SISUSB_COMMAND:
3150 lock_kernel();
3151 retval = sisusb_ioctl(f->f_path.dentry->d_inode, f, cmd, arg);
3152 unlock_kernel();
3153 return retval;
3155 default:
3156 return -ENOIOCTLCMD;
3159 #endif
3161 static const struct file_operations usb_sisusb_fops = {
3162 .owner = THIS_MODULE,
3163 .open = sisusb_open,
3164 .release = sisusb_release,
3165 .read = sisusb_read,
3166 .write = sisusb_write,
3167 .llseek = sisusb_lseek,
3168 #ifdef SISUSB_NEW_CONFIG_COMPAT
3169 .compat_ioctl = sisusb_compat_ioctl,
3170 #endif
3171 .ioctl = sisusb_ioctl
3174 static struct usb_class_driver usb_sisusb_class = {
3175 .name = "sisusbvga%d",
3176 .fops = &usb_sisusb_fops,
3177 .minor_base = SISUSB_MINOR
3180 static int sisusb_probe(struct usb_interface *intf,
3181 const struct usb_device_id *id)
3183 struct usb_device *dev = interface_to_usbdev(intf);
3184 struct sisusb_usb_data *sisusb;
3185 int retval = 0, i;
3186 const char *memfail =
3187 KERN_ERR
3188 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
3190 printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
3191 dev->devnum);
3193 /* Allocate memory for our private */
3194 if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
3195 printk(KERN_ERR
3196 "sisusb: Failed to allocate memory for private data\n");
3197 return -ENOMEM;
3199 kref_init(&sisusb->kref);
3201 mutex_init(&(sisusb->lock));
3203 /* Register device */
3204 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
3205 printk(KERN_ERR
3206 "sisusb: Failed to get a minor for device %d\n",
3207 dev->devnum);
3208 retval = -ENODEV;
3209 goto error_1;
3212 sisusb->sisusb_dev = dev;
3213 sisusb->minor = intf->minor;
3214 sisusb->vrambase = SISUSB_PCI_MEMBASE;
3215 sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
3216 sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
3217 sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
3218 /* Everything else is zero */
3220 /* Allocate buffers */
3221 sisusb->ibufsize = SISUSB_IBUF_SIZE;
3222 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
3223 GFP_KERNEL, &sisusb->transfer_dma_in))) {
3224 printk(memfail, "input", sisusb->minor);
3225 retval = -ENOMEM;
3226 goto error_2;
3229 sisusb->numobufs = 0;
3230 sisusb->obufsize = SISUSB_OBUF_SIZE;
3231 for (i = 0; i < NUMOBUFS; i++) {
3232 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
3233 GFP_KERNEL,
3234 &sisusb->transfer_dma_out[i]))) {
3235 if (i == 0) {
3236 printk(memfail, "output", sisusb->minor);
3237 retval = -ENOMEM;
3238 goto error_3;
3240 break;
3241 } else
3242 sisusb->numobufs++;
3246 /* Allocate URBs */
3247 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
3248 printk(KERN_ERR
3249 "sisusbvga[%d]: Failed to allocate URBs\n",
3250 sisusb->minor);
3251 retval = -ENOMEM;
3252 goto error_3;
3254 sisusb->completein = 1;
3256 for (i = 0; i < sisusb->numobufs; i++) {
3257 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
3258 printk(KERN_ERR
3259 "sisusbvga[%d]: Failed to allocate URBs\n",
3260 sisusb->minor);
3261 retval = -ENOMEM;
3262 goto error_4;
3264 sisusb->urbout_context[i].sisusb = (void *)sisusb;
3265 sisusb->urbout_context[i].urbindex = i;
3266 sisusb->urbstatus[i] = 0;
3269 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
3270 sisusb->minor, sisusb->numobufs);
3272 #ifdef INCL_SISUSB_CON
3273 /* Allocate our SiS_Pr */
3274 if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
3275 printk(KERN_ERR
3276 "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
3277 sisusb->minor);
3279 #endif
3281 /* Do remaining init stuff */
3283 init_waitqueue_head(&sisusb->wait_q);
3285 usb_set_intfdata(intf, sisusb);
3287 usb_get_dev(sisusb->sisusb_dev);
3289 sisusb->present = 1;
3291 #ifdef SISUSB_OLD_CONFIG_COMPAT
3293 int ret;
3294 /* Our ioctls are all "32/64bit compatible" */
3295 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3296 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3297 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3298 if (ret)
3299 printk(KERN_ERR
3300 "sisusbvga[%d]: Error registering ioctl32 "
3301 "translations\n",
3302 sisusb->minor);
3303 else
3304 sisusb->ioctl32registered = 1;
3306 #endif
3308 if (dev->speed == USB_SPEED_HIGH) {
3309 int initscreen = 1;
3310 #ifdef INCL_SISUSB_CON
3311 if (sisusb_first_vc > 0 &&
3312 sisusb_last_vc > 0 &&
3313 sisusb_first_vc <= sisusb_last_vc &&
3314 sisusb_last_vc <= MAX_NR_CONSOLES)
3315 initscreen = 0;
3316 #endif
3317 if (sisusb_init_gfxdevice(sisusb, initscreen))
3318 printk(KERN_ERR
3319 "sisusbvga[%d]: Failed to early "
3320 "initialize device\n",
3321 sisusb->minor);
3323 } else
3324 printk(KERN_INFO
3325 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3326 "deferring init\n",
3327 sisusb->minor);
3329 sisusb->ready = 1;
3331 #ifdef SISUSBENDIANTEST
3332 printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
3333 sisusb_testreadwrite(sisusb);
3334 printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
3335 #endif
3337 #ifdef INCL_SISUSB_CON
3338 sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
3339 #endif
3341 return 0;
3343 error_4:
3344 sisusb_free_urbs(sisusb);
3345 error_3:
3346 sisusb_free_buffers(sisusb);
3347 error_2:
3348 usb_deregister_dev(intf, &usb_sisusb_class);
3349 error_1:
3350 kfree(sisusb);
3351 return retval;
3354 static void sisusb_disconnect(struct usb_interface *intf)
3356 struct sisusb_usb_data *sisusb;
3357 int minor;
3359 /* This should *not* happen */
3360 if (!(sisusb = usb_get_intfdata(intf)))
3361 return;
3363 #ifdef INCL_SISUSB_CON
3364 sisusb_console_exit(sisusb);
3365 #endif
3367 minor = sisusb->minor;
3369 usb_deregister_dev(intf, &usb_sisusb_class);
3371 mutex_lock(&sisusb->lock);
3373 /* Wait for all URBs to complete and kill them in case (MUST do) */
3374 if (!sisusb_wait_all_out_complete(sisusb))
3375 sisusb_kill_all_busy(sisusb);
3377 usb_set_intfdata(intf, NULL);
3379 #ifdef SISUSB_OLD_CONFIG_COMPAT
3380 if (sisusb->ioctl32registered) {
3381 int ret;
3382 sisusb->ioctl32registered = 0;
3383 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3384 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3385 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3386 if (ret) {
3387 printk(KERN_ERR
3388 "sisusbvga[%d]: Error unregistering "
3389 "ioctl32 translations\n",
3390 minor);
3393 #endif
3395 sisusb->present = 0;
3396 sisusb->ready = 0;
3398 mutex_unlock(&sisusb->lock);
3400 /* decrement our usage count */
3401 kref_put(&sisusb->kref, sisusb_delete);
3403 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
3406 static struct usb_device_id sisusb_table [] = {
3407 { USB_DEVICE(0x0711, 0x0550) },
3408 { USB_DEVICE(0x0711, 0x0900) },
3409 { USB_DEVICE(0x0711, 0x0901) },
3410 { USB_DEVICE(0x0711, 0x0902) },
3411 { USB_DEVICE(0x182d, 0x021c) },
3412 { USB_DEVICE(0x182d, 0x0269) },
3416 MODULE_DEVICE_TABLE (usb, sisusb_table);
3418 static struct usb_driver sisusb_driver = {
3419 .name = "sisusb",
3420 .probe = sisusb_probe,
3421 .disconnect = sisusb_disconnect,
3422 .id_table = sisusb_table,
3425 static int __init usb_sisusb_init(void)
3427 int retval;
3429 #ifdef INCL_SISUSB_CON
3430 sisusb_init_concode();
3431 #endif
3433 if (!(retval = usb_register(&sisusb_driver))) {
3435 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3436 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3437 printk(KERN_INFO
3438 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3442 return retval;
3445 static void __exit usb_sisusb_exit(void)
3447 usb_deregister(&sisusb_driver);
3450 module_init(usb_sisusb_init);
3451 module_exit(usb_sisusb_exit);
3453 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3454 MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
3455 MODULE_LICENSE("GPL");