Remove all inclusions of <linux/config.h>
[linux-2.6/btrfs-unstable.git] / drivers / usb / misc / sisusbvga / sisusb.c
bloba287836e39f19178d3b62ee2ccc208ec94e22863
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/sched.h>
44 #include <linux/errno.h>
45 #include <linux/poll.h>
46 #include <linux/init.h>
47 #include <linux/slab.h>
48 #include <linux/spinlock.h>
49 #include <linux/kref.h>
50 #include <linux/usb.h>
51 #include <linux/smp_lock.h>
52 #include <linux/vmalloc.h>
54 #include "sisusb.h"
55 #include "sisusb_init.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 static int sisusb_first_vc = 0;
67 static int sisusb_last_vc = 0;
68 module_param_named(first, sisusb_first_vc, int, 0);
69 module_param_named(last, sisusb_last_vc, int, 0);
70 MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)");
71 MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)");
72 #endif
74 static struct usb_driver sisusb_driver;
76 DEFINE_MUTEX(disconnect_mutex);
78 static void
79 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
81 int i;
83 for (i = 0; i < NUMOBUFS; i++) {
84 if (sisusb->obuf[i]) {
85 usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize,
86 sisusb->obuf[i], sisusb->transfer_dma_out[i]);
87 sisusb->obuf[i] = NULL;
90 if (sisusb->ibuf) {
91 usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
92 sisusb->ibuf, sisusb->transfer_dma_in);
93 sisusb->ibuf = NULL;
97 static void
98 sisusb_free_urbs(struct sisusb_usb_data *sisusb)
100 int i;
102 for (i = 0; i < NUMOBUFS; i++) {
103 usb_free_urb(sisusb->sisurbout[i]);
104 sisusb->sisurbout[i] = NULL;
106 usb_free_urb(sisusb->sisurbin);
107 sisusb->sisurbin = NULL;
110 /* Level 0: USB transport layer */
112 /* 1. out-bulks */
114 /* out-urb management */
116 /* Return 1 if all free, 0 otherwise */
117 static int
118 sisusb_all_free(struct sisusb_usb_data *sisusb)
120 int i;
122 for (i = 0; i < sisusb->numobufs; i++) {
124 if (sisusb->urbstatus[i] & SU_URB_BUSY)
125 return 0;
129 return 1;
132 /* Kill all busy URBs */
133 static void
134 sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
136 int i;
138 if (sisusb_all_free(sisusb))
139 return;
141 for (i = 0; i < sisusb->numobufs; i++) {
143 if (sisusb->urbstatus[i] & SU_URB_BUSY)
144 usb_kill_urb(sisusb->sisurbout[i]);
149 /* Return 1 if ok, 0 if error (not all complete within timeout) */
150 static int
151 sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
153 int timeout = 5 * HZ, i = 1;
155 wait_event_timeout(sisusb->wait_q,
156 (i = sisusb_all_free(sisusb)),
157 timeout);
159 return i;
162 static int
163 sisusb_outurb_available(struct sisusb_usb_data *sisusb)
165 int i;
167 for (i = 0; i < sisusb->numobufs; i++) {
169 if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
170 return i;
174 return -1;
177 static int
178 sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
180 int i, timeout = 5 * HZ;
182 wait_event_timeout(sisusb->wait_q,
183 ((i = sisusb_outurb_available(sisusb)) >= 0),
184 timeout);
186 return i;
189 static int
190 sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
192 int i;
194 i = sisusb_outurb_available(sisusb);
196 if (i >= 0)
197 sisusb->urbstatus[i] |= SU_URB_ALLOC;
199 return i;
202 static void
203 sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
205 if ((index >= 0) && (index < sisusb->numobufs))
206 sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
209 /* completion callback */
211 static void
212 sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
214 struct sisusb_urb_context *context = urb->context;
215 struct sisusb_usb_data *sisusb;
217 if (!context)
218 return;
220 sisusb = context->sisusb;
222 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
223 return;
225 #ifndef SISUSB_DONTSYNC
226 if (context->actual_length)
227 *(context->actual_length) += urb->actual_length;
228 #endif
230 sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
231 wake_up(&sisusb->wait_q);
234 static int
235 sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
236 int len, int *actual_length, int timeout, unsigned int tflags,
237 dma_addr_t transfer_dma)
239 struct urb *urb = sisusb->sisurbout[index];
240 int retval, byteswritten = 0;
242 /* Set up URB */
243 urb->transfer_flags = 0;
245 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
246 sisusb_bulk_completeout, &sisusb->urbout_context[index]);
248 urb->transfer_flags |= tflags;
249 urb->actual_length = 0;
251 if ((urb->transfer_dma = transfer_dma))
252 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
254 /* Set up context */
255 sisusb->urbout_context[index].actual_length = (timeout) ?
256 NULL : actual_length;
258 /* Declare this urb/buffer in use */
259 sisusb->urbstatus[index] |= SU_URB_BUSY;
261 /* Submit URB */
262 retval = usb_submit_urb(urb, GFP_ATOMIC);
264 /* If OK, and if timeout > 0, wait for completion */
265 if ((retval == 0) && timeout) {
266 wait_event_timeout(sisusb->wait_q,
267 (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
268 timeout);
269 if (sisusb->urbstatus[index] & SU_URB_BUSY) {
270 /* URB timed out... kill it and report error */
271 usb_kill_urb(urb);
272 retval = -ETIMEDOUT;
273 } else {
274 /* Otherwise, report urb status */
275 retval = urb->status;
276 byteswritten = urb->actual_length;
280 if (actual_length)
281 *actual_length = byteswritten;
283 return retval;
286 /* 2. in-bulks */
288 /* completion callback */
290 static void
291 sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
293 struct sisusb_usb_data *sisusb = urb->context;
295 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
296 return;
298 sisusb->completein = 1;
299 wake_up(&sisusb->wait_q);
302 static int
303 sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len,
304 int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma)
306 struct urb *urb = sisusb->sisurbin;
307 int retval, readbytes = 0;
309 urb->transfer_flags = 0;
311 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
312 sisusb_bulk_completein, sisusb);
314 urb->transfer_flags |= tflags;
315 urb->actual_length = 0;
317 if ((urb->transfer_dma = transfer_dma))
318 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
320 sisusb->completein = 0;
321 retval = usb_submit_urb(urb, GFP_ATOMIC);
322 if (retval == 0) {
323 wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
324 if (!sisusb->completein) {
325 /* URB timed out... kill it and report error */
326 usb_kill_urb(urb);
327 retval = -ETIMEDOUT;
328 } else {
329 /* URB completed within timout */
330 retval = urb->status;
331 readbytes = urb->actual_length;
335 if (actual_length)
336 *actual_length = readbytes;
338 return retval;
342 /* Level 1: */
344 /* Send a bulk message of variable size
346 * To copy the data from userspace, give pointer to "userbuffer",
347 * to copy from (non-DMA) kernel memory, give "kernbuffer". If
348 * both of these are NULL, it is assumed, that the transfer
349 * buffer "sisusb->obuf[index]" is set up with the data to send.
350 * Index is ignored if either kernbuffer or userbuffer is set.
351 * If async is nonzero, URBs will be sent without waiting for
352 * completion of the previous URB.
354 * (return 0 on success)
357 static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
358 char *kernbuffer, const char __user *userbuffer, int index,
359 ssize_t *bytes_written, unsigned int tflags, int async)
361 int result = 0, retry, count = len;
362 int passsize, thispass, transferred_len = 0;
363 int fromuser = (userbuffer != NULL) ? 1 : 0;
364 int fromkern = (kernbuffer != NULL) ? 1 : 0;
365 unsigned int pipe;
366 char *buffer;
368 (*bytes_written) = 0;
370 /* Sanity check */
371 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
372 return -ENODEV;
374 /* If we copy data from kernel or userspace, force the
375 * allocation of a buffer/urb. If we have the data in
376 * the transfer buffer[index] already, reuse the buffer/URB
377 * if the length is > buffer size. (So, transmitting
378 * large data amounts directly from the transfer buffer
379 * treats the buffer as a ring buffer. However, we need
380 * to sync in this case.)
382 if (fromuser || fromkern)
383 index = -1;
384 else if (len > sisusb->obufsize)
385 async = 0;
387 pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
389 do {
390 passsize = thispass = (sisusb->obufsize < count) ?
391 sisusb->obufsize : count;
393 if (index < 0)
394 index = sisusb_get_free_outbuf(sisusb);
396 if (index < 0)
397 return -EIO;
399 buffer = sisusb->obuf[index];
401 if (fromuser) {
403 if (copy_from_user(buffer, userbuffer, passsize))
404 return -EFAULT;
406 userbuffer += passsize;
408 } else if (fromkern) {
410 memcpy(buffer, kernbuffer, passsize);
411 kernbuffer += passsize;
415 retry = 5;
416 while (thispass) {
418 if (!sisusb->sisusb_dev)
419 return -ENODEV;
421 result = sisusb_bulkout_msg(sisusb,
422 index,
423 pipe,
424 buffer,
425 thispass,
426 &transferred_len,
427 async ? 0 : 5 * HZ,
428 tflags,
429 sisusb->transfer_dma_out[index]);
431 if (result == -ETIMEDOUT) {
433 /* Will not happen if async */
434 if (!retry--)
435 return -ETIME;
437 continue;
439 } else if ((result == 0) && !async && transferred_len) {
441 thispass -= transferred_len;
442 if (thispass) {
443 if (sisusb->transfer_dma_out) {
444 /* If DMA, copy remaining
445 * to beginning of buffer
447 memcpy(buffer,
448 buffer + transferred_len,
449 thispass);
450 } else {
451 /* If not DMA, simply increase
452 * the pointer
454 buffer += transferred_len;
458 } else
459 break;
462 if (result)
463 return result;
465 (*bytes_written) += passsize;
466 count -= passsize;
468 /* Force new allocation in next iteration */
469 if (fromuser || fromkern)
470 index = -1;
472 } while (count > 0);
474 if (async) {
475 #ifdef SISUSB_DONTSYNC
476 (*bytes_written) = len;
477 /* Some URBs/buffers might be busy */
478 #else
479 sisusb_wait_all_out_complete(sisusb);
480 (*bytes_written) = transferred_len;
481 /* All URBs and all buffers are available */
482 #endif
485 return ((*bytes_written) == len) ? 0 : -EIO;
488 /* Receive a bulk message of variable size
490 * To copy the data to userspace, give pointer to "userbuffer",
491 * to copy to kernel memory, give "kernbuffer". One of them
492 * MUST be set. (There is no technique for letting the caller
493 * read directly from the ibuf.)
497 static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
498 void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
499 unsigned int tflags)
501 int result = 0, retry, count = len;
502 int bufsize, thispass, transferred_len;
503 unsigned int pipe;
504 char *buffer;
506 (*bytes_read) = 0;
508 /* Sanity check */
509 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
510 return -ENODEV;
512 pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
513 buffer = sisusb->ibuf;
514 bufsize = sisusb->ibufsize;
516 retry = 5;
518 #ifdef SISUSB_DONTSYNC
519 if (!(sisusb_wait_all_out_complete(sisusb)))
520 return -EIO;
521 #endif
523 while (count > 0) {
525 if (!sisusb->sisusb_dev)
526 return -ENODEV;
528 thispass = (bufsize < count) ? bufsize : count;
530 result = sisusb_bulkin_msg(sisusb,
531 pipe,
532 buffer,
533 thispass,
534 &transferred_len,
535 5 * HZ,
536 tflags,
537 sisusb->transfer_dma_in);
539 if (transferred_len)
540 thispass = transferred_len;
542 else if (result == -ETIMEDOUT) {
544 if (!retry--)
545 return -ETIME;
547 continue;
549 } else
550 return -EIO;
553 if (thispass) {
555 (*bytes_read) += thispass;
556 count -= thispass;
558 if (userbuffer) {
560 if (copy_to_user(userbuffer, buffer, thispass))
561 return -EFAULT;
563 userbuffer += thispass;
565 } else {
567 memcpy(kernbuffer, buffer, thispass);
568 kernbuffer += thispass;
576 return ((*bytes_read) == len) ? 0 : -EIO;
579 static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
580 struct sisusb_packet *packet)
582 int ret;
583 ssize_t bytes_transferred = 0;
584 __le32 tmp;
586 if (len == 6)
587 packet->data = 0;
589 #ifdef SISUSB_DONTSYNC
590 if (!(sisusb_wait_all_out_complete(sisusb)))
591 return 1;
592 #endif
594 /* Eventually correct endianness */
595 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
597 /* 1. send the packet */
598 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
599 (char *)packet, NULL, 0, &bytes_transferred, 0, 0);
601 if ((ret == 0) && (len == 6)) {
603 /* 2. if packet len == 6, it means we read, so wait for 32bit
604 * return value and write it to packet->data
606 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
607 (char *)&tmp, NULL, &bytes_transferred, 0);
609 packet->data = le32_to_cpu(tmp);
612 return ret;
615 static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
616 struct sisusb_packet *packet,
617 unsigned int tflags)
619 int ret;
620 ssize_t bytes_transferred = 0;
621 __le32 tmp;
623 if (len == 6)
624 packet->data = 0;
626 #ifdef SISUSB_DONTSYNC
627 if (!(sisusb_wait_all_out_complete(sisusb)))
628 return 1;
629 #endif
631 /* Eventually correct endianness */
632 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
634 /* 1. send the packet */
635 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
636 (char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
638 if ((ret == 0) && (len == 6)) {
640 /* 2. if packet len == 6, it means we read, so wait for 32bit
641 * return value and write it to packet->data
643 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
644 (char *)&tmp, NULL, &bytes_transferred, 0);
646 packet->data = le32_to_cpu(tmp);
649 return ret;
652 /* access video memory and mmio (return 0 on success) */
654 /* Low level */
656 /* The following routines assume being used to transfer byte, word,
657 * long etc.
658 * This means that
659 * - the write routines expect "data" in machine endianness format.
660 * The data will be converted to leXX in sisusb_xxx_packet.
661 * - the read routines can expect read data in machine-endianess.
664 static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
665 u32 addr, u8 data)
667 struct sisusb_packet packet;
668 int ret;
670 packet.header = (1 << (addr & 3)) | (type << 6);
671 packet.address = addr & ~3;
672 packet.data = data << ((addr & 3) << 3);
673 ret = sisusb_send_packet(sisusb, 10, &packet);
674 return ret;
677 static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
678 u32 addr, u16 data)
680 struct sisusb_packet packet;
681 int ret = 0;
683 packet.address = addr & ~3;
685 switch (addr & 3) {
686 case 0:
687 packet.header = (type << 6) | 0x0003;
688 packet.data = (u32)data;
689 ret = sisusb_send_packet(sisusb, 10, &packet);
690 break;
691 case 1:
692 packet.header = (type << 6) | 0x0006;
693 packet.data = (u32)data << 8;
694 ret = sisusb_send_packet(sisusb, 10, &packet);
695 break;
696 case 2:
697 packet.header = (type << 6) | 0x000c;
698 packet.data = (u32)data << 16;
699 ret = sisusb_send_packet(sisusb, 10, &packet);
700 break;
701 case 3:
702 packet.header = (type << 6) | 0x0008;
703 packet.data = (u32)data << 24;
704 ret = sisusb_send_packet(sisusb, 10, &packet);
705 packet.header = (type << 6) | 0x0001;
706 packet.address = (addr & ~3) + 4;
707 packet.data = (u32)data >> 8;
708 ret |= sisusb_send_packet(sisusb, 10, &packet);
711 return ret;
714 static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
715 u32 addr, u32 data)
717 struct sisusb_packet packet;
718 int ret = 0;
720 packet.address = addr & ~3;
722 switch (addr & 3) {
723 case 0:
724 packet.header = (type << 6) | 0x0007;
725 packet.data = data & 0x00ffffff;
726 ret = sisusb_send_packet(sisusb, 10, &packet);
727 break;
728 case 1:
729 packet.header = (type << 6) | 0x000e;
730 packet.data = data << 8;
731 ret = sisusb_send_packet(sisusb, 10, &packet);
732 break;
733 case 2:
734 packet.header = (type << 6) | 0x000c;
735 packet.data = data << 16;
736 ret = sisusb_send_packet(sisusb, 10, &packet);
737 packet.header = (type << 6) | 0x0001;
738 packet.address = (addr & ~3) + 4;
739 packet.data = (data >> 16) & 0x00ff;
740 ret |= sisusb_send_packet(sisusb, 10, &packet);
741 break;
742 case 3:
743 packet.header = (type << 6) | 0x0008;
744 packet.data = data << 24;
745 ret = sisusb_send_packet(sisusb, 10, &packet);
746 packet.header = (type << 6) | 0x0003;
747 packet.address = (addr & ~3) + 4;
748 packet.data = (data >> 8) & 0xffff;
749 ret |= sisusb_send_packet(sisusb, 10, &packet);
752 return ret;
755 static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
756 u32 addr, u32 data)
758 struct sisusb_packet packet;
759 int ret = 0;
761 packet.address = addr & ~3;
763 switch (addr & 3) {
764 case 0:
765 packet.header = (type << 6) | 0x000f;
766 packet.data = data;
767 ret = sisusb_send_packet(sisusb, 10, &packet);
768 break;
769 case 1:
770 packet.header = (type << 6) | 0x000e;
771 packet.data = data << 8;
772 ret = sisusb_send_packet(sisusb, 10, &packet);
773 packet.header = (type << 6) | 0x0001;
774 packet.address = (addr & ~3) + 4;
775 packet.data = data >> 24;
776 ret |= sisusb_send_packet(sisusb, 10, &packet);
777 break;
778 case 2:
779 packet.header = (type << 6) | 0x000c;
780 packet.data = data << 16;
781 ret = sisusb_send_packet(sisusb, 10, &packet);
782 packet.header = (type << 6) | 0x0003;
783 packet.address = (addr & ~3) + 4;
784 packet.data = data >> 16;
785 ret |= sisusb_send_packet(sisusb, 10, &packet);
786 break;
787 case 3:
788 packet.header = (type << 6) | 0x0008;
789 packet.data = data << 24;
790 ret = sisusb_send_packet(sisusb, 10, &packet);
791 packet.header = (type << 6) | 0x0007;
792 packet.address = (addr & ~3) + 4;
793 packet.data = data >> 8;
794 ret |= sisusb_send_packet(sisusb, 10, &packet);
797 return ret;
800 /* The xxx_bulk routines copy a buffer of variable size. They treat the
801 * buffer as chars, therefore lsb/msb has to be corrected if using the
802 * byte/word/long/etc routines for speed-up
804 * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
805 * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
806 * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
807 * that the data already is in the transfer buffer "sisusb->obuf[index]".
810 static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
811 char *kernbuffer, int length,
812 const char __user *userbuffer, int index,
813 ssize_t *bytes_written)
815 struct sisusb_packet packet;
816 int ret = 0;
817 static int msgcount = 0;
818 u8 swap8, fromkern = kernbuffer ? 1 : 0;
819 u16 swap16;
820 u32 swap32, flag = (length >> 28) & 1;
821 char buf[4];
823 /* if neither kernbuffer not userbuffer are given, assume
824 * data in obuf
826 if (!fromkern && !userbuffer)
827 kernbuffer = sisusb->obuf[index];
829 (*bytes_written = 0);
831 length &= 0x00ffffff;
833 while (length) {
835 switch (length) {
837 case 1:
838 if (userbuffer) {
839 if (get_user(swap8, (u8 __user *)userbuffer))
840 return -EFAULT;
841 } else
842 swap8 = kernbuffer[0];
844 ret = sisusb_write_memio_byte(sisusb,
845 SISUSB_TYPE_MEM,
846 addr, swap8);
848 if (!ret)
849 (*bytes_written)++;
851 return ret;
853 case 2:
854 if (userbuffer) {
855 if (get_user(swap16, (u16 __user *)userbuffer))
856 return -EFAULT;
857 } else
858 swap16 = *((u16 *)kernbuffer);
860 ret = sisusb_write_memio_word(sisusb,
861 SISUSB_TYPE_MEM,
862 addr,
863 swap16);
865 if (!ret)
866 (*bytes_written) += 2;
868 return ret;
870 case 3:
871 if (userbuffer) {
872 if (copy_from_user(&buf, userbuffer, 3))
873 return -EFAULT;
874 #ifdef __BIG_ENDIAN
875 swap32 = (buf[0] << 16) |
876 (buf[1] << 8) |
877 buf[2];
878 #else
879 swap32 = (buf[2] << 16) |
880 (buf[1] << 8) |
881 buf[0];
882 #endif
883 } else
884 #ifdef __BIG_ENDIAN
885 swap32 = (kernbuffer[0] << 16) |
886 (kernbuffer[1] << 8) |
887 kernbuffer[2];
888 #else
889 swap32 = (kernbuffer[2] << 16) |
890 (kernbuffer[1] << 8) |
891 kernbuffer[0];
892 #endif
894 ret = sisusb_write_memio_24bit(sisusb,
895 SISUSB_TYPE_MEM,
896 addr,
897 swap32);
899 if (!ret)
900 (*bytes_written) += 3;
902 return ret;
904 case 4:
905 if (userbuffer) {
906 if (get_user(swap32, (u32 __user *)userbuffer))
907 return -EFAULT;
908 } else
909 swap32 = *((u32 *)kernbuffer);
911 ret = sisusb_write_memio_long(sisusb,
912 SISUSB_TYPE_MEM,
913 addr,
914 swap32);
915 if (!ret)
916 (*bytes_written) += 4;
918 return ret;
920 default:
921 if ((length & ~3) > 0x10000) {
923 packet.header = 0x001f;
924 packet.address = 0x000001d4;
925 packet.data = addr;
926 ret = sisusb_send_bridge_packet(sisusb, 10,
927 &packet, 0);
928 packet.header = 0x001f;
929 packet.address = 0x000001d0;
930 packet.data = (length & ~3);
931 ret |= sisusb_send_bridge_packet(sisusb, 10,
932 &packet, 0);
933 packet.header = 0x001f;
934 packet.address = 0x000001c0;
935 packet.data = flag | 0x16;
936 ret |= sisusb_send_bridge_packet(sisusb, 10,
937 &packet, 0);
938 if (userbuffer) {
939 ret |= sisusb_send_bulk_msg(sisusb,
940 SISUSB_EP_GFX_LBULK_OUT,
941 (length & ~3),
942 NULL, userbuffer, 0,
943 bytes_written, 0, 1);
944 userbuffer += (*bytes_written);
945 } else if (fromkern) {
946 ret |= sisusb_send_bulk_msg(sisusb,
947 SISUSB_EP_GFX_LBULK_OUT,
948 (length & ~3),
949 kernbuffer, NULL, 0,
950 bytes_written, 0, 1);
951 kernbuffer += (*bytes_written);
952 } else {
953 ret |= sisusb_send_bulk_msg(sisusb,
954 SISUSB_EP_GFX_LBULK_OUT,
955 (length & ~3),
956 NULL, NULL, index,
957 bytes_written, 0, 1);
958 kernbuffer += ((*bytes_written) &
959 (sisusb->obufsize-1));
962 } else {
964 packet.header = 0x001f;
965 packet.address = 0x00000194;
966 packet.data = addr;
967 ret = sisusb_send_bridge_packet(sisusb, 10,
968 &packet, 0);
969 packet.header = 0x001f;
970 packet.address = 0x00000190;
971 packet.data = (length & ~3);
972 ret |= sisusb_send_bridge_packet(sisusb, 10,
973 &packet, 0);
974 if (sisusb->flagb0 != 0x16) {
975 packet.header = 0x001f;
976 packet.address = 0x00000180;
977 packet.data = flag | 0x16;
978 ret |= sisusb_send_bridge_packet(sisusb, 10,
979 &packet, 0);
980 sisusb->flagb0 = 0x16;
982 if (userbuffer) {
983 ret |= sisusb_send_bulk_msg(sisusb,
984 SISUSB_EP_GFX_BULK_OUT,
985 (length & ~3),
986 NULL, userbuffer, 0,
987 bytes_written, 0, 1);
988 userbuffer += (*bytes_written);
989 } else if (fromkern) {
990 ret |= sisusb_send_bulk_msg(sisusb,
991 SISUSB_EP_GFX_BULK_OUT,
992 (length & ~3),
993 kernbuffer, NULL, 0,
994 bytes_written, 0, 1);
995 kernbuffer += (*bytes_written);
996 } else {
997 ret |= sisusb_send_bulk_msg(sisusb,
998 SISUSB_EP_GFX_BULK_OUT,
999 (length & ~3),
1000 NULL, NULL, index,
1001 bytes_written, 0, 1);
1002 kernbuffer += ((*bytes_written) &
1003 (sisusb->obufsize-1));
1006 if (ret) {
1007 msgcount++;
1008 if (msgcount < 500)
1009 printk(KERN_ERR
1010 "sisusbvga[%d]: Wrote %zd of "
1011 "%d bytes, error %d\n",
1012 sisusb->minor, *bytes_written,
1013 length, ret);
1014 else if (msgcount == 500)
1015 printk(KERN_ERR
1016 "sisusbvga[%d]: Too many errors"
1017 ", logging stopped\n",
1018 sisusb->minor);
1020 addr += (*bytes_written);
1021 length -= (*bytes_written);
1024 if (ret)
1025 break;
1029 return ret ? -EIO : 0;
1032 /* Remember: Read data in packet is in machine-endianess! So for
1033 * byte, word, 24bit, long no endian correction is necessary.
1036 static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1037 u32 addr, u8 *data)
1039 struct sisusb_packet packet;
1040 int ret;
1042 CLEARPACKET(&packet);
1043 packet.header = (1 << (addr & 3)) | (type << 6);
1044 packet.address = addr & ~3;
1045 ret = sisusb_send_packet(sisusb, 6, &packet);
1046 *data = (u8)(packet.data >> ((addr & 3) << 3));
1047 return ret;
1050 static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1051 u32 addr, u16 *data)
1053 struct sisusb_packet packet;
1054 int ret = 0;
1056 CLEARPACKET(&packet);
1058 packet.address = addr & ~3;
1060 switch (addr & 3) {
1061 case 0:
1062 packet.header = (type << 6) | 0x0003;
1063 ret = sisusb_send_packet(sisusb, 6, &packet);
1064 *data = (u16)(packet.data);
1065 break;
1066 case 1:
1067 packet.header = (type << 6) | 0x0006;
1068 ret = sisusb_send_packet(sisusb, 6, &packet);
1069 *data = (u16)(packet.data >> 8);
1070 break;
1071 case 2:
1072 packet.header = (type << 6) | 0x000c;
1073 ret = sisusb_send_packet(sisusb, 6, &packet);
1074 *data = (u16)(packet.data >> 16);
1075 break;
1076 case 3:
1077 packet.header = (type << 6) | 0x0008;
1078 ret = sisusb_send_packet(sisusb, 6, &packet);
1079 *data = (u16)(packet.data >> 24);
1080 packet.header = (type << 6) | 0x0001;
1081 packet.address = (addr & ~3) + 4;
1082 ret |= sisusb_send_packet(sisusb, 6, &packet);
1083 *data |= (u16)(packet.data << 8);
1086 return ret;
1089 static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1090 u32 addr, u32 *data)
1092 struct sisusb_packet packet;
1093 int ret = 0;
1095 packet.address = addr & ~3;
1097 switch (addr & 3) {
1098 case 0:
1099 packet.header = (type << 6) | 0x0007;
1100 ret = sisusb_send_packet(sisusb, 6, &packet);
1101 *data = packet.data & 0x00ffffff;
1102 break;
1103 case 1:
1104 packet.header = (type << 6) | 0x000e;
1105 ret = sisusb_send_packet(sisusb, 6, &packet);
1106 *data = packet.data >> 8;
1107 break;
1108 case 2:
1109 packet.header = (type << 6) | 0x000c;
1110 ret = sisusb_send_packet(sisusb, 6, &packet);
1111 *data = packet.data >> 16;
1112 packet.header = (type << 6) | 0x0001;
1113 packet.address = (addr & ~3) + 4;
1114 ret |= sisusb_send_packet(sisusb, 6, &packet);
1115 *data |= ((packet.data & 0xff) << 16);
1116 break;
1117 case 3:
1118 packet.header = (type << 6) | 0x0008;
1119 ret = sisusb_send_packet(sisusb, 6, &packet);
1120 *data = packet.data >> 24;
1121 packet.header = (type << 6) | 0x0003;
1122 packet.address = (addr & ~3) + 4;
1123 ret |= sisusb_send_packet(sisusb, 6, &packet);
1124 *data |= ((packet.data & 0xffff) << 8);
1127 return ret;
1130 static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1131 u32 addr, u32 *data)
1133 struct sisusb_packet packet;
1134 int ret = 0;
1136 packet.address = addr & ~3;
1138 switch (addr & 3) {
1139 case 0:
1140 packet.header = (type << 6) | 0x000f;
1141 ret = sisusb_send_packet(sisusb, 6, &packet);
1142 *data = packet.data;
1143 break;
1144 case 1:
1145 packet.header = (type << 6) | 0x000e;
1146 ret = sisusb_send_packet(sisusb, 6, &packet);
1147 *data = packet.data >> 8;
1148 packet.header = (type << 6) | 0x0001;
1149 packet.address = (addr & ~3) + 4;
1150 ret |= sisusb_send_packet(sisusb, 6, &packet);
1151 *data |= (packet.data << 24);
1152 break;
1153 case 2:
1154 packet.header = (type << 6) | 0x000c;
1155 ret = sisusb_send_packet(sisusb, 6, &packet);
1156 *data = packet.data >> 16;
1157 packet.header = (type << 6) | 0x0003;
1158 packet.address = (addr & ~3) + 4;
1159 ret |= sisusb_send_packet(sisusb, 6, &packet);
1160 *data |= (packet.data << 16);
1161 break;
1162 case 3:
1163 packet.header = (type << 6) | 0x0008;
1164 ret = sisusb_send_packet(sisusb, 6, &packet);
1165 *data = packet.data >> 24;
1166 packet.header = (type << 6) | 0x0007;
1167 packet.address = (addr & ~3) + 4;
1168 ret |= sisusb_send_packet(sisusb, 6, &packet);
1169 *data |= (packet.data << 8);
1172 return ret;
1175 static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1176 char *kernbuffer, int length,
1177 char __user *userbuffer, ssize_t *bytes_read)
1179 int ret = 0;
1180 char buf[4];
1181 u16 swap16;
1182 u32 swap32;
1184 (*bytes_read = 0);
1186 length &= 0x00ffffff;
1188 while (length) {
1190 switch (length) {
1192 case 1:
1194 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1195 addr, &buf[0]);
1196 if (!ret) {
1197 (*bytes_read)++;
1198 if (userbuffer) {
1199 if (put_user(buf[0],
1200 (u8 __user *)userbuffer)) {
1201 return -EFAULT;
1203 } else {
1204 kernbuffer[0] = buf[0];
1207 return ret;
1209 case 2:
1210 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1211 addr, &swap16);
1212 if (!ret) {
1213 (*bytes_read) += 2;
1214 if (userbuffer) {
1215 if (put_user(swap16,
1216 (u16 __user *)userbuffer))
1217 return -EFAULT;
1218 } else {
1219 *((u16 *)kernbuffer) = swap16;
1222 return ret;
1224 case 3:
1225 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1226 addr, &swap32);
1227 if (!ret) {
1228 (*bytes_read) += 3;
1229 #ifdef __BIG_ENDIAN
1230 buf[0] = (swap32 >> 16) & 0xff;
1231 buf[1] = (swap32 >> 8) & 0xff;
1232 buf[2] = swap32 & 0xff;
1233 #else
1234 buf[2] = (swap32 >> 16) & 0xff;
1235 buf[1] = (swap32 >> 8) & 0xff;
1236 buf[0] = swap32 & 0xff;
1237 #endif
1238 if (userbuffer) {
1239 if (copy_to_user(userbuffer, &buf[0], 3))
1240 return -EFAULT;
1241 } else {
1242 kernbuffer[0] = buf[0];
1243 kernbuffer[1] = buf[1];
1244 kernbuffer[2] = buf[2];
1247 return ret;
1249 default:
1250 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1251 addr, &swap32);
1252 if (!ret) {
1253 (*bytes_read) += 4;
1254 if (userbuffer) {
1255 if (put_user(swap32,
1256 (u32 __user *)userbuffer))
1257 return -EFAULT;
1259 userbuffer += 4;
1260 } else {
1261 *((u32 *)kernbuffer) = swap32;
1262 kernbuffer += 4;
1264 addr += 4;
1265 length -= 4;
1267 #if 0 /* That does not work, as EP 2 is an OUT EP! */
1268 default:
1269 CLEARPACKET(&packet);
1270 packet.header = 0x001f;
1271 packet.address = 0x000001a0;
1272 packet.data = 0x00000006;
1273 ret |= sisusb_send_bridge_packet(sisusb, 10,
1274 &packet, 0);
1275 packet.header = 0x001f;
1276 packet.address = 0x000001b0;
1277 packet.data = (length & ~3) | 0x40000000;
1278 ret |= sisusb_send_bridge_packet(sisusb, 10,
1279 &packet, 0);
1280 packet.header = 0x001f;
1281 packet.address = 0x000001b4;
1282 packet.data = addr;
1283 ret |= sisusb_send_bridge_packet(sisusb, 10,
1284 &packet, 0);
1285 packet.header = 0x001f;
1286 packet.address = 0x000001a4;
1287 packet.data = 0x00000001;
1288 ret |= sisusb_send_bridge_packet(sisusb, 10,
1289 &packet, 0);
1290 if (userbuffer) {
1291 ret |= sisusb_recv_bulk_msg(sisusb,
1292 SISUSB_EP_GFX_BULK_IN,
1293 (length & ~3),
1294 NULL, userbuffer,
1295 bytes_read, 0);
1296 if (!ret) userbuffer += (*bytes_read);
1297 } else {
1298 ret |= sisusb_recv_bulk_msg(sisusb,
1299 SISUSB_EP_GFX_BULK_IN,
1300 (length & ~3),
1301 kernbuffer, NULL,
1302 bytes_read, 0);
1303 if (!ret) kernbuffer += (*bytes_read);
1305 addr += (*bytes_read);
1306 length -= (*bytes_read);
1307 #endif
1310 if (ret)
1311 break;
1314 return ret;
1317 /* High level: Gfx (indexed) register access */
1319 #ifdef INCL_SISUSB_CON
1321 sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
1323 return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1327 sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
1329 return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1331 #endif
1334 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1336 int ret;
1337 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1338 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1339 return ret;
1343 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1345 int ret;
1346 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1347 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1348 return ret;
1352 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1353 u8 myand, u8 myor)
1355 int ret;
1356 u8 tmp;
1358 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1359 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1360 tmp &= myand;
1361 tmp |= myor;
1362 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1363 return ret;
1366 static int
1367 sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1368 u8 data, u8 mask)
1370 int ret;
1371 u8 tmp;
1372 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1373 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1374 tmp &= ~(mask);
1375 tmp |= (data & mask);
1376 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1377 return ret;
1381 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1383 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1387 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1389 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1392 /* Write/read video ram */
1394 #ifdef INCL_SISUSB_CON
1396 sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
1398 return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1402 sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
1404 return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1407 #if 0
1410 sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
1412 return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1416 sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
1418 return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1421 #endif /* 0 */
1424 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
1425 u32 dest, int length, size_t *bytes_written)
1427 return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
1430 #ifdef SISUSBENDIANTEST
1432 sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
1433 u32 src, int length, size_t *bytes_written)
1435 return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
1437 #endif
1438 #endif
1440 #ifdef SISUSBENDIANTEST
1441 static void
1442 sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
1444 static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
1445 char destbuffer[10];
1446 size_t dummy;
1447 int i,j;
1449 sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
1451 for(i = 1; i <= 7; i++) {
1452 printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
1453 sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
1454 for(j = 0; j < i; j++) {
1455 printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
1459 #endif
1461 /* access pci config registers (reg numbers 0, 4, 8, etc) */
1463 static int
1464 sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1466 struct sisusb_packet packet;
1467 int ret;
1469 packet.header = 0x008f;
1470 packet.address = regnum | 0x10000;
1471 packet.data = data;
1472 ret = sisusb_send_packet(sisusb, 10, &packet);
1473 return ret;
1476 static int
1477 sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1479 struct sisusb_packet packet;
1480 int ret;
1482 packet.header = 0x008f;
1483 packet.address = (u32)regnum | 0x10000;
1484 ret = sisusb_send_packet(sisusb, 6, &packet);
1485 *data = packet.data;
1486 return ret;
1489 /* Clear video RAM */
1491 static int
1492 sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1494 int ret, i;
1495 ssize_t j;
1497 if (address < sisusb->vrambase)
1498 return 1;
1500 if (address >= sisusb->vrambase + sisusb->vramsize)
1501 return 1;
1503 if (address + length > sisusb->vrambase + sisusb->vramsize)
1504 length = sisusb->vrambase + sisusb->vramsize - address;
1506 if (length <= 0)
1507 return 0;
1509 /* allocate free buffer/urb and clear the buffer */
1510 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1511 return -EBUSY;
1513 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1515 /* We can write a length > buffer size here. The buffer
1516 * data will simply be re-used (like a ring-buffer).
1518 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1520 /* Free the buffer/urb */
1521 sisusb_free_outbuf(sisusb, i);
1523 return ret;
1526 /* Initialize the graphics core (return 0 on success)
1527 * This resets the graphics hardware and puts it into
1528 * a defined mode (640x480@60Hz)
1531 #define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1532 #define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1533 #define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
1534 #define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
1535 #define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
1536 #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
1537 #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
1538 #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1539 #define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1540 #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1541 #define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1543 static int
1544 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1546 int ret;
1547 u8 tmp8;
1549 ret = GETIREG(SISSR, 0x16, &tmp8);
1550 if (ramtype <= 1) {
1551 tmp8 &= 0x3f;
1552 ret |= SETIREG(SISSR, 0x16, tmp8);
1553 tmp8 |= 0x80;
1554 ret |= SETIREG(SISSR, 0x16, tmp8);
1555 } else {
1556 tmp8 |= 0xc0;
1557 ret |= SETIREG(SISSR, 0x16, tmp8);
1558 tmp8 &= 0x0f;
1559 ret |= SETIREG(SISSR, 0x16, tmp8);
1560 tmp8 |= 0x80;
1561 ret |= SETIREG(SISSR, 0x16, tmp8);
1562 tmp8 &= 0x0f;
1563 ret |= SETIREG(SISSR, 0x16, tmp8);
1564 tmp8 |= 0xd0;
1565 ret |= SETIREG(SISSR, 0x16, tmp8);
1566 tmp8 &= 0x0f;
1567 ret |= SETIREG(SISSR, 0x16, tmp8);
1568 tmp8 |= 0xa0;
1569 ret |= SETIREG(SISSR, 0x16, tmp8);
1571 return ret;
1574 static int
1575 sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1577 int ret;
1578 u8 ramtype, done = 0;
1579 u32 t0, t1, t2, t3;
1580 u32 ramptr = SISUSB_PCI_MEMBASE;
1582 ret = GETIREG(SISSR, 0x3a, &ramtype);
1583 ramtype &= 3;
1585 ret |= SETIREG(SISSR, 0x13, 0x00);
1587 if (ramtype <= 1) {
1588 ret |= SETIREG(SISSR, 0x14, 0x12);
1589 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1590 } else {
1591 ret |= SETIREG(SISSR, 0x14, 0x02);
1594 ret |= sisusb_triggersr16(sisusb, ramtype);
1595 ret |= WRITEL(ramptr + 0, 0x01234567);
1596 ret |= WRITEL(ramptr + 4, 0x456789ab);
1597 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1598 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1599 ret |= WRITEL(ramptr + 16, 0x55555555);
1600 ret |= WRITEL(ramptr + 20, 0x55555555);
1601 ret |= WRITEL(ramptr + 24, 0xffffffff);
1602 ret |= WRITEL(ramptr + 28, 0xffffffff);
1603 ret |= READL(ramptr + 0, &t0);
1604 ret |= READL(ramptr + 4, &t1);
1605 ret |= READL(ramptr + 8, &t2);
1606 ret |= READL(ramptr + 12, &t3);
1608 if (ramtype <= 1) {
1610 *chab = 0; *bw = 64;
1612 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1613 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1614 *chab = 0; *bw = 64;
1615 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1618 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1619 *chab = 1; *bw = 64;
1620 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1622 ret |= sisusb_triggersr16(sisusb, ramtype);
1623 ret |= WRITEL(ramptr + 0, 0x89abcdef);
1624 ret |= WRITEL(ramptr + 4, 0xcdef0123);
1625 ret |= WRITEL(ramptr + 8, 0x55555555);
1626 ret |= WRITEL(ramptr + 12, 0x55555555);
1627 ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1628 ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1629 ret |= READL(ramptr + 4, &t1);
1631 if (t1 != 0xcdef0123) {
1632 *bw = 32;
1633 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1637 } else {
1639 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1641 done = 0;
1643 if (t1 == 0x456789ab) {
1644 if (t0 == 0x01234567) {
1645 *chab = 0; *bw = 64;
1646 done = 1;
1648 } else {
1649 if (t0 == 0x01234567) {
1650 *chab = 0; *bw = 32;
1651 ret |= SETIREG(SISSR, 0x14, 0x00);
1652 done = 1;
1656 if (!done) {
1657 ret |= SETIREG(SISSR, 0x14, 0x03);
1658 ret |= sisusb_triggersr16(sisusb, ramtype);
1660 ret |= WRITEL(ramptr + 0, 0x01234567);
1661 ret |= WRITEL(ramptr + 4, 0x456789ab);
1662 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1663 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1664 ret |= WRITEL(ramptr + 16, 0x55555555);
1665 ret |= WRITEL(ramptr + 20, 0x55555555);
1666 ret |= WRITEL(ramptr + 24, 0xffffffff);
1667 ret |= WRITEL(ramptr + 28, 0xffffffff);
1668 ret |= READL(ramptr + 0, &t0);
1669 ret |= READL(ramptr + 4, &t1);
1671 if (t1 == 0x456789ab) {
1672 if (t0 == 0x01234567) {
1673 *chab = 1; *bw = 64;
1674 return ret;
1675 } /* else error */
1676 } else {
1677 if (t0 == 0x01234567) {
1678 *chab = 1; *bw = 32;
1679 ret |= SETIREG(SISSR, 0x14, 0x01);
1680 } /* else error */
1684 return ret;
1687 static int
1688 sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1690 int ret = 0;
1691 u32 ramptr = SISUSB_PCI_MEMBASE;
1692 u8 tmp1, tmp2, i, j;
1694 ret |= WRITEB(ramptr, 0xaa);
1695 ret |= WRITEB(ramptr + 16, 0x55);
1696 ret |= READB(ramptr, &tmp1);
1697 ret |= READB(ramptr + 16, &tmp2);
1698 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1699 for (i = 0, j = 16; i < 2; i++, j += 16) {
1700 ret |= GETIREG(SISSR, 0x21, &tmp1);
1701 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1702 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1703 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1704 ret |= SETIREG(SISSR, 0x21, tmp1);
1705 ret |= WRITEB(ramptr + 16 + j, j);
1706 ret |= READB(ramptr + 16 + j, &tmp1);
1707 if (tmp1 == j) {
1708 ret |= WRITEB(ramptr + j, j);
1709 break;
1713 return ret;
1716 static int
1717 sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1718 u8 rankno, u8 chab, const u8 dramtype[][5],
1719 int bw)
1721 int ret = 0, ranksize;
1722 u8 tmp;
1724 *iret = 0;
1726 if ((rankno == 2) && (dramtype[index][0] == 2))
1727 return ret;
1729 ranksize = dramtype[index][3] / 2 * bw / 32;
1731 if ((ranksize * rankno) > 128)
1732 return ret;
1734 tmp = 0;
1735 while ((ranksize >>= 1) > 0) tmp += 0x10;
1736 tmp |= ((rankno - 1) << 2);
1737 tmp |= ((bw / 64) & 0x02);
1738 tmp |= (chab & 0x01);
1740 ret = SETIREG(SISSR, 0x14, tmp);
1741 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1743 *iret = 1;
1745 return ret;
1748 static int
1749 sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1751 int ret = 0, i;
1752 u32 j, tmp;
1754 *iret = 0;
1756 for (i = 0, j = 0; i < testn; i++) {
1757 ret |= WRITEL(sisusb->vrambase + j, j);
1758 j += inc;
1761 for (i = 0, j = 0; i < testn; i++) {
1762 ret |= READL(sisusb->vrambase + j, &tmp);
1763 if (tmp != j) return ret;
1764 j += inc;
1767 *iret = 1;
1768 return ret;
1771 static int
1772 sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1773 int idx, int bw, const u8 rtype[][5])
1775 int ret = 0, i, i2ret;
1776 u32 inc;
1778 *iret = 0;
1780 for (i = rankno; i >= 1; i--) {
1781 inc = 1 << (rtype[idx][2] +
1782 rtype[idx][1] +
1783 rtype[idx][0] +
1784 bw / 64 + i);
1785 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1786 if (!i2ret)
1787 return ret;
1790 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1791 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1792 if (!i2ret)
1793 return ret;
1795 inc = 1 << (10 + bw / 64);
1796 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1797 if (!i2ret)
1798 return ret;
1800 *iret = 1;
1801 return ret;
1804 static int
1805 sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1806 int chab)
1808 int ret = 0, i2ret = 0, i, j;
1809 static const u8 sdramtype[13][5] = {
1810 { 2, 12, 9, 64, 0x35 },
1811 { 1, 13, 9, 64, 0x44 },
1812 { 2, 12, 8, 32, 0x31 },
1813 { 2, 11, 9, 32, 0x25 },
1814 { 1, 12, 9, 32, 0x34 },
1815 { 1, 13, 8, 32, 0x40 },
1816 { 2, 11, 8, 16, 0x21 },
1817 { 1, 12, 8, 16, 0x30 },
1818 { 1, 11, 9, 16, 0x24 },
1819 { 1, 11, 8, 8, 0x20 },
1820 { 2, 9, 8, 4, 0x01 },
1821 { 1, 10, 8, 4, 0x10 },
1822 { 1, 9, 8, 2, 0x00 }
1825 *iret = 1; /* error */
1827 for (i = 0; i < 13; i++) {
1828 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1829 for (j = 2; j > 0; j--) {
1830 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1831 chab, sdramtype, bw);
1832 if (!i2ret)
1833 continue;
1835 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1836 bw, sdramtype);
1837 if (i2ret) {
1838 *iret = 0; /* ram size found */
1839 return ret;
1844 return ret;
1847 static int
1848 sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1850 int ret = 0;
1851 u32 address;
1852 int i, length, modex, modey, bpp;
1854 modex = 640; modey = 480; bpp = 2;
1856 address = sisusb->vrambase; /* Clear video ram */
1858 if (clrall)
1859 length = sisusb->vramsize;
1860 else
1861 length = modex * bpp * modey;
1863 ret = sisusb_clear_vram(sisusb, address, length);
1865 if (!ret && drwfr) {
1866 for (i = 0; i < modex; i++) {
1867 address = sisusb->vrambase + (i * bpp);
1868 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1869 address, 0xf100);
1870 address += (modex * (modey-1) * bpp);
1871 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1872 address, 0xf100);
1874 for (i = 0; i < modey; i++) {
1875 address = sisusb->vrambase + ((i * modex) * bpp);
1876 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1877 address, 0xf100);
1878 address += ((modex - 1) * bpp);
1879 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1880 address, 0xf100);
1884 return ret;
1887 static int
1888 sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1890 int ret = 0, i, j, modex, modey, bpp, du;
1891 u8 sr31, cr63, tmp8;
1892 static const char attrdata[] = {
1893 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1894 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1895 0x01,0x00,0x00,0x00
1897 static const char crtcrdata[] = {
1898 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1899 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1900 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1901 0xff
1903 static const char grcdata[] = {
1904 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1905 0xff
1907 static const char crtcdata[] = {
1908 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1909 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1910 0x00
1913 modex = 640; modey = 480; bpp = 2;
1915 GETIREG(SISSR, 0x31, &sr31);
1916 GETIREG(SISCR, 0x63, &cr63);
1917 SETIREGOR(SISSR, 0x01, 0x20);
1918 SETIREG(SISCR, 0x63, cr63 & 0xbf);
1919 SETIREGOR(SISCR, 0x17, 0x80);
1920 SETIREGOR(SISSR, 0x1f, 0x04);
1921 SETIREGAND(SISSR, 0x07, 0xfb);
1922 SETIREG(SISSR, 0x00, 0x03); /* seq */
1923 SETIREG(SISSR, 0x01, 0x21);
1924 SETIREG(SISSR, 0x02, 0x0f);
1925 SETIREG(SISSR, 0x03, 0x00);
1926 SETIREG(SISSR, 0x04, 0x0e);
1927 SETREG(SISMISCW, 0x23); /* misc */
1928 for (i = 0; i <= 0x18; i++) { /* crtc */
1929 SETIREG(SISCR, i, crtcrdata[i]);
1931 for (i = 0; i <= 0x13; i++) { /* att */
1932 GETREG(SISINPSTAT, &tmp8);
1933 SETREG(SISAR, i);
1934 SETREG(SISAR, attrdata[i]);
1936 GETREG(SISINPSTAT, &tmp8);
1937 SETREG(SISAR, 0x14);
1938 SETREG(SISAR, 0x00);
1939 GETREG(SISINPSTAT, &tmp8);
1940 SETREG(SISAR, 0x20);
1941 GETREG(SISINPSTAT, &tmp8);
1942 for (i = 0; i <= 0x08; i++) { /* grc */
1943 SETIREG(SISGR, i, grcdata[i]);
1945 SETIREGAND(SISGR, 0x05, 0xbf);
1946 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1947 SETIREG(SISSR, i, 0x00);
1949 SETIREGAND(SISSR, 0x37, 0xfe);
1950 SETREG(SISMISCW, 0xef); /* sync */
1951 SETIREG(SISCR, 0x11, 0x00); /* crtc */
1952 for (j = 0x00, i = 0; i <= 7; i++, j++) {
1953 SETIREG(SISCR, j, crtcdata[i]);
1955 for (j = 0x10; i <= 10; i++, j++) {
1956 SETIREG(SISCR, j, crtcdata[i]);
1958 for (j = 0x15; i <= 12; i++, j++) {
1959 SETIREG(SISCR, j, crtcdata[i]);
1961 for (j = 0x0A; i <= 15; i++, j++) {
1962 SETIREG(SISSR, j, crtcdata[i]);
1964 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
1965 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
1966 SETIREG(SISCR, 0x14, 0x4f);
1967 du = (modex / 16) * (bpp * 2); /* offset/pitch */
1968 if (modex % 16) du += bpp;
1969 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
1970 SETIREG(SISCR, 0x13, (du & 0xff));
1971 du <<= 5;
1972 tmp8 = du >> 8;
1973 if (du & 0xff) tmp8++;
1974 SETIREG(SISSR, 0x10, tmp8);
1975 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
1976 SETIREG(SISSR, 0x2b, 0x1b);
1977 SETIREG(SISSR, 0x2c, 0xe1);
1978 SETIREG(SISSR, 0x2d, 0x01);
1979 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
1980 SETIREG(SISSR, 0x08, 0xae);
1981 SETIREGAND(SISSR, 0x09, 0xf0);
1982 SETIREG(SISSR, 0x08, 0x34);
1983 SETIREGOR(SISSR, 0x3d, 0x01);
1984 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
1985 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
1986 SETIREG(SISCR, 0x19, 0x00);
1987 SETIREGAND(SISCR, 0x1a, 0xfc);
1988 SETIREGAND(SISSR, 0x0f, 0xb7);
1989 SETIREGAND(SISSR, 0x31, 0xfb);
1990 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
1991 SETIREGAND(SISSR, 0x32, 0xf3);
1992 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
1993 SETIREG(SISCR, 0x52, 0x6c);
1995 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
1996 SETIREG(SISCR, 0x0c, 0x00);
1997 SETIREG(SISSR, 0x0d, 0x00);
1998 SETIREGAND(SISSR, 0x37, 0xfe);
2000 SETIREG(SISCR, 0x32, 0x20);
2001 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
2002 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
2003 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
2005 if (touchengines) {
2006 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
2007 SETIREGOR(SISSR, 0x1e, 0x5a);
2009 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
2010 SETIREG(SISSR, 0x27, 0x1f);
2011 SETIREG(SISSR, 0x26, 0x00);
2014 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
2016 return ret;
2019 static int
2020 sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
2022 int ret = 0, i, j, bw, chab, iret, retry = 3;
2023 u8 tmp8, ramtype;
2024 u32 tmp32;
2025 static const char mclktable[] = {
2026 0x3b, 0x22, 0x01, 143,
2027 0x3b, 0x22, 0x01, 143,
2028 0x3b, 0x22, 0x01, 143,
2029 0x3b, 0x22, 0x01, 143
2031 static const char eclktable[] = {
2032 0x3b, 0x22, 0x01, 143,
2033 0x3b, 0x22, 0x01, 143,
2034 0x3b, 0x22, 0x01, 143,
2035 0x3b, 0x22, 0x01, 143
2037 static const char ramtypetable1[] = {
2038 0x00, 0x04, 0x60, 0x60,
2039 0x0f, 0x0f, 0x1f, 0x1f,
2040 0xba, 0xba, 0xba, 0xba,
2041 0xa9, 0xa9, 0xac, 0xac,
2042 0xa0, 0xa0, 0xa0, 0xa8,
2043 0x00, 0x00, 0x02, 0x02,
2044 0x30, 0x30, 0x40, 0x40
2046 static const char ramtypetable2[] = {
2047 0x77, 0x77, 0x44, 0x44,
2048 0x77, 0x77, 0x44, 0x44,
2049 0x00, 0x00, 0x00, 0x00,
2050 0x5b, 0x5b, 0xab, 0xab,
2051 0x00, 0x00, 0xf0, 0xf8
2054 while (retry--) {
2056 /* Enable VGA */
2057 ret = GETREG(SISVGAEN, &tmp8);
2058 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
2060 /* Enable GPU access to VRAM */
2061 ret |= GETREG(SISMISCR, &tmp8);
2062 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
2064 if (ret) continue;
2066 /* Reset registers */
2067 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
2068 ret |= SETIREG(SISSR, 0x05, 0x86);
2069 ret |= SETIREGOR(SISSR, 0x20, 0x01);
2071 ret |= SETREG(SISMISCW, 0x67);
2073 for (i = 0x06; i <= 0x1f; i++) {
2074 ret |= SETIREG(SISSR, i, 0x00);
2076 for (i = 0x21; i <= 0x27; i++) {
2077 ret |= SETIREG(SISSR, i, 0x00);
2079 for (i = 0x31; i <= 0x3d; i++) {
2080 ret |= SETIREG(SISSR, i, 0x00);
2082 for (i = 0x12; i <= 0x1b; i++) {
2083 ret |= SETIREG(SISSR, i, 0x00);
2085 for (i = 0x79; i <= 0x7c; i++) {
2086 ret |= SETIREG(SISCR, i, 0x00);
2089 if (ret) continue;
2091 ret |= SETIREG(SISCR, 0x63, 0x80);
2093 ret |= GETIREG(SISSR, 0x3a, &ramtype);
2094 ramtype &= 0x03;
2096 ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
2097 ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
2098 ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
2100 ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
2101 ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
2102 ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
2104 ret |= SETIREG(SISSR, 0x07, 0x18);
2105 ret |= SETIREG(SISSR, 0x11, 0x0f);
2107 if (ret) continue;
2109 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2110 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2112 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2113 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2116 ret |= SETIREG(SISCR, 0x49, 0xaa);
2118 ret |= SETIREG(SISSR, 0x1f, 0x00);
2119 ret |= SETIREG(SISSR, 0x20, 0xa0);
2120 ret |= SETIREG(SISSR, 0x23, 0xf6);
2121 ret |= SETIREG(SISSR, 0x24, 0x0d);
2122 ret |= SETIREG(SISSR, 0x25, 0x33);
2124 ret |= SETIREG(SISSR, 0x11, 0x0f);
2126 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2128 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2130 if (ret) continue;
2132 ret |= SETIREG(SISPART1, 0x00, 0x00);
2134 ret |= GETIREG(SISSR, 0x13, &tmp8);
2135 tmp8 >>= 4;
2137 ret |= SETIREG(SISPART1, 0x02, 0x00);
2138 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2140 ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
2141 tmp32 &= 0x00f00000;
2142 tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
2143 ret |= SETIREG(SISSR, 0x25, tmp8);
2144 tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
2145 ret |= SETIREG(SISCR, 0x49, tmp8);
2147 ret |= SETIREG(SISSR, 0x27, 0x1f);
2148 ret |= SETIREG(SISSR, 0x31, 0x00);
2149 ret |= SETIREG(SISSR, 0x32, 0x11);
2150 ret |= SETIREG(SISSR, 0x33, 0x00);
2152 if (ret) continue;
2154 ret |= SETIREG(SISCR, 0x83, 0x00);
2156 ret |= sisusb_set_default_mode(sisusb, 0);
2158 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2159 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2160 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2162 ret |= sisusb_triggersr16(sisusb, ramtype);
2164 /* Disable refresh */
2165 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2166 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2168 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2169 ret |= sisusb_verify_mclk(sisusb);
2171 if (ramtype <= 1) {
2172 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2173 if (iret) {
2174 printk(KERN_ERR "sisusbvga[%d]: RAM size "
2175 "detection failed, "
2176 "assuming 8MB video RAM\n",
2177 sisusb->minor);
2178 ret |= SETIREG(SISSR,0x14,0x31);
2179 /* TODO */
2181 } else {
2182 printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
2183 "assuming 8MB video RAM\n",
2184 sisusb->minor);
2185 ret |= SETIREG(SISSR,0x14,0x31);
2186 /* *** TODO *** */
2189 /* Enable refresh */
2190 ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
2191 ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
2192 ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
2194 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2196 ret |= SETIREG(SISSR, 0x22, 0xfb);
2197 ret |= SETIREG(SISSR, 0x21, 0xa5);
2199 if (ret == 0)
2200 break;
2203 return ret;
2206 #undef SETREG
2207 #undef GETREG
2208 #undef SETIREG
2209 #undef GETIREG
2210 #undef SETIREGOR
2211 #undef SETIREGAND
2212 #undef SETIREGANDOR
2213 #undef READL
2214 #undef WRITEL
2216 static void
2217 sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2219 u8 tmp8, tmp82, ramtype;
2220 int bw = 0;
2221 char *ramtypetext1 = NULL;
2222 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2223 "DDR SDRAM", "DDR SGRAM" };
2224 static const int busSDR[4] = {64, 64, 128, 128};
2225 static const int busDDR[4] = {32, 32, 64, 64};
2226 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2228 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2229 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2230 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2231 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2232 ramtype &= 0x03;
2233 switch ((tmp8 >> 2) & 0x03) {
2234 case 0: ramtypetext1 = "1 ch/1 r";
2235 if (tmp82 & 0x10) {
2236 bw = 32;
2237 } else {
2238 bw = busSDR[(tmp8 & 0x03)];
2240 break;
2241 case 1: ramtypetext1 = "1 ch/2 r";
2242 sisusb->vramsize <<= 1;
2243 bw = busSDR[(tmp8 & 0x03)];
2244 break;
2245 case 2: ramtypetext1 = "asymmeric";
2246 sisusb->vramsize += sisusb->vramsize/2;
2247 bw = busDDRA[(tmp8 & 0x03)];
2248 break;
2249 case 3: ramtypetext1 = "2 channel";
2250 sisusb->vramsize <<= 1;
2251 bw = busDDR[(tmp8 & 0x03)];
2252 break;
2255 printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2256 sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
2257 ramtypetext2[ramtype], bw);
2260 static int
2261 sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2263 struct sisusb_packet packet;
2264 int ret;
2265 u32 tmp32;
2267 /* Do some magic */
2268 packet.header = 0x001f;
2269 packet.address = 0x00000324;
2270 packet.data = 0x00000004;
2271 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2273 packet.header = 0x001f;
2274 packet.address = 0x00000364;
2275 packet.data = 0x00000004;
2276 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2278 packet.header = 0x001f;
2279 packet.address = 0x00000384;
2280 packet.data = 0x00000004;
2281 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2283 packet.header = 0x001f;
2284 packet.address = 0x00000100;
2285 packet.data = 0x00000700;
2286 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2288 packet.header = 0x000f;
2289 packet.address = 0x00000004;
2290 ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2291 packet.data |= 0x17;
2292 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2294 /* Init BAR 0 (VRAM) */
2295 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2296 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2297 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2298 tmp32 &= 0x0f;
2299 tmp32 |= SISUSB_PCI_MEMBASE;
2300 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2302 /* Init BAR 1 (MMIO) */
2303 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2304 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2305 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2306 tmp32 &= 0x0f;
2307 tmp32 |= SISUSB_PCI_MMIOBASE;
2308 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2310 /* Init BAR 2 (i/o ports) */
2311 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2312 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2313 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2314 tmp32 &= 0x0f;
2315 tmp32 |= SISUSB_PCI_IOPORTBASE;
2316 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2318 /* Enable memory and i/o access */
2319 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2320 tmp32 |= 0x3;
2321 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2323 if (ret == 0) {
2324 /* Some further magic */
2325 packet.header = 0x001f;
2326 packet.address = 0x00000050;
2327 packet.data = 0x000000ff;
2328 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2331 return ret;
2334 /* Initialize the graphics device (return 0 on success)
2335 * This initializes the net2280 as well as the PCI registers
2336 * of the graphics board.
2339 static int
2340 sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2342 int ret = 0, test = 0;
2343 u32 tmp32;
2345 if (sisusb->devinit == 1) {
2346 /* Read PCI BARs and see if they have been set up */
2347 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2348 if (ret) return ret;
2349 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
2351 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2352 if (ret) return ret;
2353 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2355 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2356 if (ret) return ret;
2357 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2360 /* No? So reset the device */
2361 if ((sisusb->devinit == 0) || (test != 3)) {
2363 ret |= sisusb_do_init_gfxdevice(sisusb);
2365 if (ret == 0)
2366 sisusb->devinit = 1;
2370 if (sisusb->devinit) {
2371 /* Initialize the graphics core */
2372 if (sisusb_init_gfxcore(sisusb) == 0) {
2373 sisusb->gfxinit = 1;
2374 sisusb_get_ramconfig(sisusb);
2375 ret |= sisusb_set_default_mode(sisusb, 1);
2376 ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2380 return ret;
2384 #ifdef INCL_SISUSB_CON
2386 /* Set up default text mode:
2387 - Set text mode (0x03)
2388 - Upload default font
2389 - Upload user font (if available)
2393 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
2395 int ret = 0, slot = sisusb->font_slot, i;
2396 const struct font_desc *myfont;
2397 u8 *tempbuf;
2398 u16 *tempbufb;
2399 size_t written;
2400 static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
2401 static const char bootlogo[] = "(o_ //\\ V_/_";
2403 /* sisusb->lock is down */
2405 if (!sisusb->SiS_Pr)
2406 return 1;
2408 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2409 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2411 /* Set mode 0x03 */
2412 SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
2414 if (!(myfont = find_font("VGA8x16")))
2415 return 1;
2417 if (!(tempbuf = vmalloc(8192)))
2418 return 1;
2420 for (i = 0; i < 256; i++)
2421 memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
2423 /* Upload default font */
2424 ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
2426 vfree(tempbuf);
2428 /* Upload user font (and reset current slot) */
2429 if (sisusb->font_backup) {
2430 ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
2431 8192, sisusb->font_backup_512, 1, NULL,
2432 sisusb->font_backup_height, 0);
2433 if (slot != 2)
2434 sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
2435 NULL, 16, 0);
2438 if (init && !sisusb->scrbuf) {
2440 if ((tempbuf = vmalloc(8192))) {
2442 i = 4096;
2443 tempbufb = (u16 *)tempbuf;
2444 while (i--)
2445 *(tempbufb++) = 0x0720;
2447 i = 0;
2448 tempbufb = (u16 *)tempbuf;
2449 while (bootlogo[i]) {
2450 *(tempbufb++) = 0x0700 | bootlogo[i++];
2451 if (!(i % 4))
2452 tempbufb += 76;
2455 i = 0;
2456 tempbufb = (u16 *)tempbuf + 6;
2457 while (bootstring[i])
2458 *(tempbufb++) = 0x0700 | bootstring[i++];
2460 ret |= sisusb_copy_memory(sisusb, tempbuf,
2461 sisusb->vrambase, 8192, &written);
2463 vfree(tempbuf);
2467 } else if (sisusb->scrbuf) {
2469 ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
2470 sisusb->vrambase, sisusb->scrbuf_size, &written);
2474 if (sisusb->sisusb_cursor_size_from >= 0 &&
2475 sisusb->sisusb_cursor_size_to >= 0) {
2476 sisusb_setidxreg(sisusb, SISCR, 0x0a,
2477 sisusb->sisusb_cursor_size_from);
2478 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
2479 sisusb->sisusb_cursor_size_to);
2480 } else {
2481 sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
2482 sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
2483 sisusb->sisusb_cursor_size_to = -1;
2486 slot = sisusb->sisusb_cursor_loc;
2487 if(slot < 0) slot = 0;
2489 sisusb->sisusb_cursor_loc = -1;
2490 sisusb->bad_cursor_pos = 1;
2492 sisusb_set_cursor(sisusb, slot);
2494 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
2495 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
2497 sisusb->textmodedestroyed = 0;
2499 /* sisusb->lock is down */
2501 return ret;
2504 #endif
2506 /* fops */
2508 static int
2509 sisusb_open(struct inode *inode, struct file *file)
2511 struct sisusb_usb_data *sisusb;
2512 struct usb_interface *interface;
2513 int subminor = iminor(inode);
2515 mutex_lock(&disconnect_mutex);
2517 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
2518 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
2519 subminor);
2520 mutex_unlock(&disconnect_mutex);
2521 return -ENODEV;
2524 if (!(sisusb = usb_get_intfdata(interface))) {
2525 mutex_unlock(&disconnect_mutex);
2526 return -ENODEV;
2529 mutex_lock(&sisusb->lock);
2531 if (!sisusb->present || !sisusb->ready) {
2532 mutex_unlock(&sisusb->lock);
2533 mutex_unlock(&disconnect_mutex);
2534 return -ENODEV;
2537 if (sisusb->isopen) {
2538 mutex_unlock(&sisusb->lock);
2539 mutex_unlock(&disconnect_mutex);
2540 return -EBUSY;
2543 if (!sisusb->devinit) {
2544 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2545 if (sisusb_init_gfxdevice(sisusb, 0)) {
2546 mutex_unlock(&sisusb->lock);
2547 mutex_unlock(&disconnect_mutex);
2548 printk(KERN_ERR
2549 "sisusbvga[%d]: Failed to initialize "
2550 "device\n",
2551 sisusb->minor);
2552 return -EIO;
2554 } else {
2555 mutex_unlock(&sisusb->lock);
2556 mutex_unlock(&disconnect_mutex);
2557 printk(KERN_ERR
2558 "sisusbvga[%d]: Device not attached to "
2559 "USB 2.0 hub\n",
2560 sisusb->minor);
2561 return -EIO;
2565 /* Increment usage count for our sisusb */
2566 kref_get(&sisusb->kref);
2568 sisusb->isopen = 1;
2570 file->private_data = sisusb;
2572 mutex_unlock(&sisusb->lock);
2574 mutex_unlock(&disconnect_mutex);
2576 return 0;
2579 void
2580 sisusb_delete(struct kref *kref)
2582 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2584 if (!sisusb)
2585 return;
2587 if (sisusb->sisusb_dev)
2588 usb_put_dev(sisusb->sisusb_dev);
2590 sisusb->sisusb_dev = NULL;
2591 sisusb_free_buffers(sisusb);
2592 sisusb_free_urbs(sisusb);
2593 #ifdef INCL_SISUSB_CON
2594 kfree(sisusb->SiS_Pr);
2595 #endif
2596 kfree(sisusb);
2599 static int
2600 sisusb_release(struct inode *inode, struct file *file)
2602 struct sisusb_usb_data *sisusb;
2603 int myminor;
2605 mutex_lock(&disconnect_mutex);
2607 if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
2608 mutex_unlock(&disconnect_mutex);
2609 return -ENODEV;
2612 mutex_lock(&sisusb->lock);
2614 if (sisusb->present) {
2615 /* Wait for all URBs to finish if device still present */
2616 if (!sisusb_wait_all_out_complete(sisusb))
2617 sisusb_kill_all_busy(sisusb);
2620 myminor = sisusb->minor;
2622 sisusb->isopen = 0;
2623 file->private_data = NULL;
2625 mutex_unlock(&sisusb->lock);
2627 /* decrement the usage count on our device */
2628 kref_put(&sisusb->kref, sisusb_delete);
2630 mutex_unlock(&disconnect_mutex);
2632 return 0;
2635 static ssize_t
2636 sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2638 struct sisusb_usb_data *sisusb;
2639 ssize_t bytes_read = 0;
2640 int errno = 0;
2641 u8 buf8;
2642 u16 buf16;
2643 u32 buf32, address;
2645 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2646 return -ENODEV;
2648 mutex_lock(&sisusb->lock);
2650 /* Sanity check */
2651 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2652 mutex_unlock(&sisusb->lock);
2653 return -ENODEV;
2656 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2657 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2659 address = (*ppos) -
2660 SISUSB_PCI_PSEUDO_IOPORTBASE +
2661 SISUSB_PCI_IOPORTBASE;
2663 /* Read i/o ports
2664 * Byte, word and long(32) can be read. As this
2665 * emulates inX instructions, the data returned is
2666 * in machine-endianness.
2668 switch (count) {
2670 case 1:
2671 if (sisusb_read_memio_byte(sisusb,
2672 SISUSB_TYPE_IO,
2673 address, &buf8))
2674 errno = -EIO;
2675 else if (put_user(buf8, (u8 __user *)buffer))
2676 errno = -EFAULT;
2677 else
2678 bytes_read = 1;
2680 break;
2682 case 2:
2683 if (sisusb_read_memio_word(sisusb,
2684 SISUSB_TYPE_IO,
2685 address, &buf16))
2686 errno = -EIO;
2687 else if (put_user(buf16, (u16 __user *)buffer))
2688 errno = -EFAULT;
2689 else
2690 bytes_read = 2;
2692 break;
2694 case 4:
2695 if (sisusb_read_memio_long(sisusb,
2696 SISUSB_TYPE_IO,
2697 address, &buf32))
2698 errno = -EIO;
2699 else if (put_user(buf32, (u32 __user *)buffer))
2700 errno = -EFAULT;
2701 else
2702 bytes_read = 4;
2704 break;
2706 default:
2707 errno = -EIO;
2711 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2712 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2714 address = (*ppos) -
2715 SISUSB_PCI_PSEUDO_MEMBASE +
2716 SISUSB_PCI_MEMBASE;
2718 /* Read video ram
2719 * Remember: Data delivered is never endian-corrected
2721 errno = sisusb_read_mem_bulk(sisusb, address,
2722 NULL, count, buffer, &bytes_read);
2724 if (bytes_read)
2725 errno = bytes_read;
2727 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2728 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2730 address = (*ppos) -
2731 SISUSB_PCI_PSEUDO_MMIOBASE +
2732 SISUSB_PCI_MMIOBASE;
2734 /* Read MMIO
2735 * Remember: Data delivered is never endian-corrected
2737 errno = sisusb_read_mem_bulk(sisusb, address,
2738 NULL, count, buffer, &bytes_read);
2740 if (bytes_read)
2741 errno = bytes_read;
2743 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2744 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2746 if (count != 4) {
2747 mutex_unlock(&sisusb->lock);
2748 return -EINVAL;
2751 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2753 /* Read PCI config register
2754 * Return value delivered in machine endianness.
2756 if (sisusb_read_pci_config(sisusb, address, &buf32))
2757 errno = -EIO;
2758 else if (put_user(buf32, (u32 __user *)buffer))
2759 errno = -EFAULT;
2760 else
2761 bytes_read = 4;
2763 } else {
2765 errno = -EBADFD;
2769 (*ppos) += bytes_read;
2771 mutex_unlock(&sisusb->lock);
2773 return errno ? errno : bytes_read;
2776 static ssize_t
2777 sisusb_write(struct file *file, const char __user *buffer, size_t count,
2778 loff_t *ppos)
2780 struct sisusb_usb_data *sisusb;
2781 int errno = 0;
2782 ssize_t bytes_written = 0;
2783 u8 buf8;
2784 u16 buf16;
2785 u32 buf32, address;
2787 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2788 return -ENODEV;
2790 mutex_lock(&sisusb->lock);
2792 /* Sanity check */
2793 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2794 mutex_unlock(&sisusb->lock);
2795 return -ENODEV;
2798 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2799 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2801 address = (*ppos) -
2802 SISUSB_PCI_PSEUDO_IOPORTBASE +
2803 SISUSB_PCI_IOPORTBASE;
2805 /* Write i/o ports
2806 * Byte, word and long(32) can be written. As this
2807 * emulates outX instructions, the data is expected
2808 * in machine-endianness.
2810 switch (count) {
2812 case 1:
2813 if (get_user(buf8, (u8 __user *)buffer))
2814 errno = -EFAULT;
2815 else if (sisusb_write_memio_byte(sisusb,
2816 SISUSB_TYPE_IO,
2817 address, buf8))
2818 errno = -EIO;
2819 else
2820 bytes_written = 1;
2822 break;
2824 case 2:
2825 if (get_user(buf16, (u16 __user *)buffer))
2826 errno = -EFAULT;
2827 else if (sisusb_write_memio_word(sisusb,
2828 SISUSB_TYPE_IO,
2829 address, buf16))
2830 errno = -EIO;
2831 else
2832 bytes_written = 2;
2834 break;
2836 case 4:
2837 if (get_user(buf32, (u32 __user *)buffer))
2838 errno = -EFAULT;
2839 else if (sisusb_write_memio_long(sisusb,
2840 SISUSB_TYPE_IO,
2841 address, buf32))
2842 errno = -EIO;
2843 else
2844 bytes_written = 4;
2846 break;
2848 default:
2849 errno = -EIO;
2852 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2853 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2855 address = (*ppos) -
2856 SISUSB_PCI_PSEUDO_MEMBASE +
2857 SISUSB_PCI_MEMBASE;
2859 /* Write video ram.
2860 * Buffer is copied 1:1, therefore, on big-endian
2861 * machines, the data must be swapped by userland
2862 * in advance (if applicable; no swapping in 8bpp
2863 * mode or if YUV data is being transferred).
2865 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2866 count, buffer, 0, &bytes_written);
2868 if (bytes_written)
2869 errno = bytes_written;
2871 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2872 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2874 address = (*ppos) -
2875 SISUSB_PCI_PSEUDO_MMIOBASE +
2876 SISUSB_PCI_MMIOBASE;
2878 /* Write MMIO.
2879 * Buffer is copied 1:1, therefore, on big-endian
2880 * machines, the data must be swapped by userland
2881 * in advance.
2883 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2884 count, buffer, 0, &bytes_written);
2886 if (bytes_written)
2887 errno = bytes_written;
2889 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2890 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2892 if (count != 4) {
2893 mutex_unlock(&sisusb->lock);
2894 return -EINVAL;
2897 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2899 /* Write PCI config register.
2900 * Given value expected in machine endianness.
2902 if (get_user(buf32, (u32 __user *)buffer))
2903 errno = -EFAULT;
2904 else if (sisusb_write_pci_config(sisusb, address, buf32))
2905 errno = -EIO;
2906 else
2907 bytes_written = 4;
2910 } else {
2912 /* Error */
2913 errno = -EBADFD;
2917 (*ppos) += bytes_written;
2919 mutex_unlock(&sisusb->lock);
2921 return errno ? errno : bytes_written;
2924 static loff_t
2925 sisusb_lseek(struct file *file, loff_t offset, int orig)
2927 struct sisusb_usb_data *sisusb;
2928 loff_t ret;
2930 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2931 return -ENODEV;
2933 mutex_lock(&sisusb->lock);
2935 /* Sanity check */
2936 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2937 mutex_unlock(&sisusb->lock);
2938 return -ENODEV;
2941 switch (orig) {
2942 case 0:
2943 file->f_pos = offset;
2944 ret = file->f_pos;
2945 /* never negative, no force_successful_syscall needed */
2946 break;
2947 case 1:
2948 file->f_pos += offset;
2949 ret = file->f_pos;
2950 /* never negative, no force_successful_syscall needed */
2951 break;
2952 default:
2953 /* seeking relative to "end of file" is not supported */
2954 ret = -EINVAL;
2957 mutex_unlock(&sisusb->lock);
2958 return ret;
2961 static int
2962 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2963 unsigned long arg)
2965 int retval, port, length;
2966 u32 address;
2968 /* All our commands require the device
2969 * to be initialized.
2971 if (!sisusb->devinit)
2972 return -ENODEV;
2974 port = y->data3 -
2975 SISUSB_PCI_PSEUDO_IOPORTBASE +
2976 SISUSB_PCI_IOPORTBASE;
2978 switch (y->operation) {
2979 case SUCMD_GET:
2980 retval = sisusb_getidxreg(sisusb, port,
2981 y->data0, &y->data1);
2982 if (!retval) {
2983 if (copy_to_user((void __user *)arg, y,
2984 sizeof(*y)))
2985 retval = -EFAULT;
2987 break;
2989 case SUCMD_SET:
2990 retval = sisusb_setidxreg(sisusb, port,
2991 y->data0, y->data1);
2992 break;
2994 case SUCMD_SETOR:
2995 retval = sisusb_setidxregor(sisusb, port,
2996 y->data0, y->data1);
2997 break;
2999 case SUCMD_SETAND:
3000 retval = sisusb_setidxregand(sisusb, port,
3001 y->data0, y->data1);
3002 break;
3004 case SUCMD_SETANDOR:
3005 retval = sisusb_setidxregandor(sisusb, port,
3006 y->data0, y->data1, y->data2);
3007 break;
3009 case SUCMD_SETMASK:
3010 retval = sisusb_setidxregmask(sisusb, port,
3011 y->data0, y->data1, y->data2);
3012 break;
3014 case SUCMD_CLRSCR:
3015 /* Gfx core must be initialized */
3016 if (!sisusb->gfxinit)
3017 return -ENODEV;
3019 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
3020 address = y->data3 -
3021 SISUSB_PCI_PSEUDO_MEMBASE +
3022 SISUSB_PCI_MEMBASE;
3023 retval = sisusb_clear_vram(sisusb, address, length);
3024 break;
3026 case SUCMD_HANDLETEXTMODE:
3027 retval = 0;
3028 #ifdef INCL_SISUSB_CON
3029 /* Gfx core must be initialized, SiS_Pr must exist */
3030 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3031 return -ENODEV;
3033 switch (y->data0) {
3034 case 0:
3035 retval = sisusb_reset_text_mode(sisusb, 0);
3036 break;
3037 case 1:
3038 sisusb->textmodedestroyed = 1;
3039 break;
3041 #endif
3042 break;
3044 #ifdef INCL_SISUSB_CON
3045 case SUCMD_SETMODE:
3046 /* Gfx core must be initialized, SiS_Pr must exist */
3047 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3048 return -ENODEV;
3050 retval = 0;
3052 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3053 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3055 if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
3056 retval = -EINVAL;
3058 break;
3060 case SUCMD_SETVESAMODE:
3061 /* Gfx core must be initialized, SiS_Pr must exist */
3062 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3063 return -ENODEV;
3065 retval = 0;
3067 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3068 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3070 if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
3071 retval = -EINVAL;
3073 break;
3074 #endif
3076 default:
3077 retval = -EINVAL;
3080 if (retval > 0)
3081 retval = -EIO;
3083 return retval;
3086 static int
3087 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
3088 unsigned long arg)
3090 struct sisusb_usb_data *sisusb;
3091 struct sisusb_info x;
3092 struct sisusb_command y;
3093 int retval = 0;
3094 u32 __user *argp = (u32 __user *)arg;
3096 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
3097 return -ENODEV;
3099 mutex_lock(&sisusb->lock);
3101 /* Sanity check */
3102 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
3103 retval = -ENODEV;
3104 goto err_out;
3107 switch (cmd) {
3109 case SISUSB_GET_CONFIG_SIZE:
3111 if (put_user(sizeof(x), argp))
3112 retval = -EFAULT;
3114 break;
3116 case SISUSB_GET_CONFIG:
3118 x.sisusb_id = SISUSB_ID;
3119 x.sisusb_version = SISUSB_VERSION;
3120 x.sisusb_revision = SISUSB_REVISION;
3121 x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
3122 x.sisusb_gfxinit = sisusb->gfxinit;
3123 x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
3124 x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
3125 x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
3126 x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
3127 x.sisusb_vramsize = sisusb->vramsize;
3128 x.sisusb_minor = sisusb->minor;
3129 x.sisusb_fbdevactive= 0;
3130 #ifdef INCL_SISUSB_CON
3131 x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
3132 #else
3133 x.sisusb_conactive = 0;
3134 #endif
3136 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
3137 retval = -EFAULT;
3139 break;
3141 case SISUSB_COMMAND:
3143 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
3144 retval = -EFAULT;
3145 else
3146 retval = sisusb_handle_command(sisusb, &y, arg);
3148 break;
3150 default:
3151 retval = -ENOTTY;
3152 break;
3155 err_out:
3156 mutex_unlock(&sisusb->lock);
3157 return retval;
3160 #ifdef SISUSB_NEW_CONFIG_COMPAT
3161 static long
3162 sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
3164 long retval;
3166 switch (cmd) {
3167 case SISUSB_GET_CONFIG_SIZE:
3168 case SISUSB_GET_CONFIG:
3169 case SISUSB_COMMAND:
3170 lock_kernel();
3171 retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
3172 unlock_kernel();
3173 return retval;
3175 default:
3176 return -ENOIOCTLCMD;
3179 #endif
3181 static const struct file_operations usb_sisusb_fops = {
3182 .owner = THIS_MODULE,
3183 .open = sisusb_open,
3184 .release = sisusb_release,
3185 .read = sisusb_read,
3186 .write = sisusb_write,
3187 .llseek = sisusb_lseek,
3188 #ifdef SISUSB_NEW_CONFIG_COMPAT
3189 .compat_ioctl = sisusb_compat_ioctl,
3190 #endif
3191 .ioctl = sisusb_ioctl
3194 static struct usb_class_driver usb_sisusb_class = {
3195 .name = "sisusbvga%d",
3196 .fops = &usb_sisusb_fops,
3197 .minor_base = SISUSB_MINOR
3200 static int sisusb_probe(struct usb_interface *intf,
3201 const struct usb_device_id *id)
3203 struct usb_device *dev = interface_to_usbdev(intf);
3204 struct sisusb_usb_data *sisusb;
3205 int retval = 0, i;
3206 const char *memfail =
3207 KERN_ERR
3208 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
3210 printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
3211 dev->devnum);
3213 /* Allocate memory for our private */
3214 if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
3215 printk(KERN_ERR
3216 "sisusb: Failed to allocate memory for private data\n");
3217 return -ENOMEM;
3219 kref_init(&sisusb->kref);
3221 mutex_init(&(sisusb->lock));
3223 /* Register device */
3224 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
3225 printk(KERN_ERR
3226 "sisusb: Failed to get a minor for device %d\n",
3227 dev->devnum);
3228 retval = -ENODEV;
3229 goto error_1;
3232 sisusb->sisusb_dev = dev;
3233 sisusb->minor = intf->minor;
3234 sisusb->vrambase = SISUSB_PCI_MEMBASE;
3235 sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
3236 sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
3237 sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
3238 /* Everything else is zero */
3240 /* Allocate buffers */
3241 sisusb->ibufsize = SISUSB_IBUF_SIZE;
3242 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
3243 GFP_KERNEL, &sisusb->transfer_dma_in))) {
3244 printk(memfail, "input", sisusb->minor);
3245 retval = -ENOMEM;
3246 goto error_2;
3249 sisusb->numobufs = 0;
3250 sisusb->obufsize = SISUSB_OBUF_SIZE;
3251 for (i = 0; i < NUMOBUFS; i++) {
3252 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
3253 GFP_KERNEL,
3254 &sisusb->transfer_dma_out[i]))) {
3255 if (i == 0) {
3256 printk(memfail, "output", sisusb->minor);
3257 retval = -ENOMEM;
3258 goto error_3;
3260 break;
3261 } else
3262 sisusb->numobufs++;
3266 /* Allocate URBs */
3267 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
3268 printk(KERN_ERR
3269 "sisusbvga[%d]: Failed to allocate URBs\n",
3270 sisusb->minor);
3271 retval = -ENOMEM;
3272 goto error_3;
3274 sisusb->completein = 1;
3276 for (i = 0; i < sisusb->numobufs; i++) {
3277 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
3278 printk(KERN_ERR
3279 "sisusbvga[%d]: Failed to allocate URBs\n",
3280 sisusb->minor);
3281 retval = -ENOMEM;
3282 goto error_4;
3284 sisusb->urbout_context[i].sisusb = (void *)sisusb;
3285 sisusb->urbout_context[i].urbindex = i;
3286 sisusb->urbstatus[i] = 0;
3289 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
3290 sisusb->minor, sisusb->numobufs);
3292 #ifdef INCL_SISUSB_CON
3293 /* Allocate our SiS_Pr */
3294 if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
3295 printk(KERN_ERR
3296 "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
3297 sisusb->minor);
3299 #endif
3301 /* Do remaining init stuff */
3303 init_waitqueue_head(&sisusb->wait_q);
3305 usb_set_intfdata(intf, sisusb);
3307 usb_get_dev(sisusb->sisusb_dev);
3309 sisusb->present = 1;
3311 #ifdef SISUSB_OLD_CONFIG_COMPAT
3313 int ret;
3314 /* Our ioctls are all "32/64bit compatible" */
3315 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3316 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3317 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3318 if (ret)
3319 printk(KERN_ERR
3320 "sisusbvga[%d]: Error registering ioctl32 "
3321 "translations\n",
3322 sisusb->minor);
3323 else
3324 sisusb->ioctl32registered = 1;
3326 #endif
3328 if (dev->speed == USB_SPEED_HIGH) {
3329 int initscreen = 1;
3330 #ifdef INCL_SISUSB_CON
3331 if (sisusb_first_vc > 0 &&
3332 sisusb_last_vc > 0 &&
3333 sisusb_first_vc <= sisusb_last_vc &&
3334 sisusb_last_vc <= MAX_NR_CONSOLES)
3335 initscreen = 0;
3336 #endif
3337 if (sisusb_init_gfxdevice(sisusb, initscreen))
3338 printk(KERN_ERR
3339 "sisusbvga[%d]: Failed to early "
3340 "initialize device\n",
3341 sisusb->minor);
3343 } else
3344 printk(KERN_INFO
3345 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3346 "deferring init\n",
3347 sisusb->minor);
3349 sisusb->ready = 1;
3351 #ifdef SISUSBENDIANTEST
3352 printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
3353 sisusb_testreadwrite(sisusb);
3354 printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
3355 #endif
3357 #ifdef INCL_SISUSB_CON
3358 sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
3359 #endif
3361 return 0;
3363 error_4:
3364 sisusb_free_urbs(sisusb);
3365 error_3:
3366 sisusb_free_buffers(sisusb);
3367 error_2:
3368 usb_deregister_dev(intf, &usb_sisusb_class);
3369 error_1:
3370 kfree(sisusb);
3371 return retval;
3374 static void sisusb_disconnect(struct usb_interface *intf)
3376 struct sisusb_usb_data *sisusb;
3377 int minor;
3379 /* This should *not* happen */
3380 if (!(sisusb = usb_get_intfdata(intf)))
3381 return;
3383 #ifdef INCL_SISUSB_CON
3384 sisusb_console_exit(sisusb);
3385 #endif
3387 /* The above code doesn't need the disconnect
3388 * semaphore to be down; its meaning is to
3389 * protect all other routines from the disconnect
3390 * case, not the other way round.
3392 mutex_lock(&disconnect_mutex);
3394 mutex_lock(&sisusb->lock);
3396 /* Wait for all URBs to complete and kill them in case (MUST do) */
3397 if (!sisusb_wait_all_out_complete(sisusb))
3398 sisusb_kill_all_busy(sisusb);
3400 minor = sisusb->minor;
3402 usb_set_intfdata(intf, NULL);
3404 usb_deregister_dev(intf, &usb_sisusb_class);
3406 #ifdef SISUSB_OLD_CONFIG_COMPAT
3407 if (sisusb->ioctl32registered) {
3408 int ret;
3409 sisusb->ioctl32registered = 0;
3410 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3411 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3412 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3413 if (ret) {
3414 printk(KERN_ERR
3415 "sisusbvga[%d]: Error unregistering "
3416 "ioctl32 translations\n",
3417 minor);
3420 #endif
3422 sisusb->present = 0;
3423 sisusb->ready = 0;
3425 mutex_unlock(&sisusb->lock);
3427 /* decrement our usage count */
3428 kref_put(&sisusb->kref, sisusb_delete);
3430 mutex_unlock(&disconnect_mutex);
3432 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
3435 static struct usb_device_id sisusb_table [] = {
3436 { USB_DEVICE(0x0711, 0x0900) },
3437 { USB_DEVICE(0x0711, 0x0901) },
3438 { USB_DEVICE(0x0711, 0x0902) },
3439 { USB_DEVICE(0x182d, 0x021c) },
3440 { USB_DEVICE(0x182d, 0x0269) },
3444 MODULE_DEVICE_TABLE (usb, sisusb_table);
3446 static struct usb_driver sisusb_driver = {
3447 .name = "sisusb",
3448 .probe = sisusb_probe,
3449 .disconnect = sisusb_disconnect,
3450 .id_table = sisusb_table,
3453 static int __init usb_sisusb_init(void)
3455 int retval;
3457 #ifdef INCL_SISUSB_CON
3458 sisusb_init_concode();
3459 #endif
3461 if (!(retval = usb_register(&sisusb_driver))) {
3463 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3464 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3465 printk(KERN_INFO
3466 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3470 return retval;
3473 static void __exit usb_sisusb_exit(void)
3475 usb_deregister(&sisusb_driver);
3478 module_init(usb_sisusb_init);
3479 module_exit(usb_sisusb_exit);
3481 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3482 MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
3483 MODULE_LICENSE("GPL");