[Bluetooth] Switch from OGF+OCF to using only opcodes
[linux-2.6/verdex.git] / drivers / usb / misc / sisusbvga / sisusb.c
blob9244d067cec1d9e3232d3379bae6cf46fa998925
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 dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
1007 *bytes_written, length, ret);
1008 else if (msgcount == 500)
1009 dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
1011 addr += (*bytes_written);
1012 length -= (*bytes_written);
1015 if (ret)
1016 break;
1020 return ret ? -EIO : 0;
1023 /* Remember: Read data in packet is in machine-endianess! So for
1024 * byte, word, 24bit, long no endian correction is necessary.
1027 static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1028 u32 addr, u8 *data)
1030 struct sisusb_packet packet;
1031 int ret;
1033 CLEARPACKET(&packet);
1034 packet.header = (1 << (addr & 3)) | (type << 6);
1035 packet.address = addr & ~3;
1036 ret = sisusb_send_packet(sisusb, 6, &packet);
1037 *data = (u8)(packet.data >> ((addr & 3) << 3));
1038 return ret;
1041 static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1042 u32 addr, u16 *data)
1044 struct sisusb_packet packet;
1045 int ret = 0;
1047 CLEARPACKET(&packet);
1049 packet.address = addr & ~3;
1051 switch (addr & 3) {
1052 case 0:
1053 packet.header = (type << 6) | 0x0003;
1054 ret = sisusb_send_packet(sisusb, 6, &packet);
1055 *data = (u16)(packet.data);
1056 break;
1057 case 1:
1058 packet.header = (type << 6) | 0x0006;
1059 ret = sisusb_send_packet(sisusb, 6, &packet);
1060 *data = (u16)(packet.data >> 8);
1061 break;
1062 case 2:
1063 packet.header = (type << 6) | 0x000c;
1064 ret = sisusb_send_packet(sisusb, 6, &packet);
1065 *data = (u16)(packet.data >> 16);
1066 break;
1067 case 3:
1068 packet.header = (type << 6) | 0x0008;
1069 ret = sisusb_send_packet(sisusb, 6, &packet);
1070 *data = (u16)(packet.data >> 24);
1071 packet.header = (type << 6) | 0x0001;
1072 packet.address = (addr & ~3) + 4;
1073 ret |= sisusb_send_packet(sisusb, 6, &packet);
1074 *data |= (u16)(packet.data << 8);
1077 return ret;
1080 static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1081 u32 addr, u32 *data)
1083 struct sisusb_packet packet;
1084 int ret = 0;
1086 packet.address = addr & ~3;
1088 switch (addr & 3) {
1089 case 0:
1090 packet.header = (type << 6) | 0x0007;
1091 ret = sisusb_send_packet(sisusb, 6, &packet);
1092 *data = packet.data & 0x00ffffff;
1093 break;
1094 case 1:
1095 packet.header = (type << 6) | 0x000e;
1096 ret = sisusb_send_packet(sisusb, 6, &packet);
1097 *data = packet.data >> 8;
1098 break;
1099 case 2:
1100 packet.header = (type << 6) | 0x000c;
1101 ret = sisusb_send_packet(sisusb, 6, &packet);
1102 *data = packet.data >> 16;
1103 packet.header = (type << 6) | 0x0001;
1104 packet.address = (addr & ~3) + 4;
1105 ret |= sisusb_send_packet(sisusb, 6, &packet);
1106 *data |= ((packet.data & 0xff) << 16);
1107 break;
1108 case 3:
1109 packet.header = (type << 6) | 0x0008;
1110 ret = sisusb_send_packet(sisusb, 6, &packet);
1111 *data = packet.data >> 24;
1112 packet.header = (type << 6) | 0x0003;
1113 packet.address = (addr & ~3) + 4;
1114 ret |= sisusb_send_packet(sisusb, 6, &packet);
1115 *data |= ((packet.data & 0xffff) << 8);
1118 return ret;
1121 static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1122 u32 addr, u32 *data)
1124 struct sisusb_packet packet;
1125 int ret = 0;
1127 packet.address = addr & ~3;
1129 switch (addr & 3) {
1130 case 0:
1131 packet.header = (type << 6) | 0x000f;
1132 ret = sisusb_send_packet(sisusb, 6, &packet);
1133 *data = packet.data;
1134 break;
1135 case 1:
1136 packet.header = (type << 6) | 0x000e;
1137 ret = sisusb_send_packet(sisusb, 6, &packet);
1138 *data = packet.data >> 8;
1139 packet.header = (type << 6) | 0x0001;
1140 packet.address = (addr & ~3) + 4;
1141 ret |= sisusb_send_packet(sisusb, 6, &packet);
1142 *data |= (packet.data << 24);
1143 break;
1144 case 2:
1145 packet.header = (type << 6) | 0x000c;
1146 ret = sisusb_send_packet(sisusb, 6, &packet);
1147 *data = packet.data >> 16;
1148 packet.header = (type << 6) | 0x0003;
1149 packet.address = (addr & ~3) + 4;
1150 ret |= sisusb_send_packet(sisusb, 6, &packet);
1151 *data |= (packet.data << 16);
1152 break;
1153 case 3:
1154 packet.header = (type << 6) | 0x0008;
1155 ret = sisusb_send_packet(sisusb, 6, &packet);
1156 *data = packet.data >> 24;
1157 packet.header = (type << 6) | 0x0007;
1158 packet.address = (addr & ~3) + 4;
1159 ret |= sisusb_send_packet(sisusb, 6, &packet);
1160 *data |= (packet.data << 8);
1163 return ret;
1166 static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1167 char *kernbuffer, int length,
1168 char __user *userbuffer, ssize_t *bytes_read)
1170 int ret = 0;
1171 char buf[4];
1172 u16 swap16;
1173 u32 swap32;
1175 (*bytes_read = 0);
1177 length &= 0x00ffffff;
1179 while (length) {
1181 switch (length) {
1183 case 1:
1185 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1186 addr, &buf[0]);
1187 if (!ret) {
1188 (*bytes_read)++;
1189 if (userbuffer) {
1190 if (put_user(buf[0],
1191 (u8 __user *)userbuffer)) {
1192 return -EFAULT;
1194 } else {
1195 kernbuffer[0] = buf[0];
1198 return ret;
1200 case 2:
1201 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1202 addr, &swap16);
1203 if (!ret) {
1204 (*bytes_read) += 2;
1205 if (userbuffer) {
1206 if (put_user(swap16,
1207 (u16 __user *)userbuffer))
1208 return -EFAULT;
1209 } else {
1210 *((u16 *)kernbuffer) = swap16;
1213 return ret;
1215 case 3:
1216 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1217 addr, &swap32);
1218 if (!ret) {
1219 (*bytes_read) += 3;
1220 #ifdef __BIG_ENDIAN
1221 buf[0] = (swap32 >> 16) & 0xff;
1222 buf[1] = (swap32 >> 8) & 0xff;
1223 buf[2] = swap32 & 0xff;
1224 #else
1225 buf[2] = (swap32 >> 16) & 0xff;
1226 buf[1] = (swap32 >> 8) & 0xff;
1227 buf[0] = swap32 & 0xff;
1228 #endif
1229 if (userbuffer) {
1230 if (copy_to_user(userbuffer, &buf[0], 3))
1231 return -EFAULT;
1232 } else {
1233 kernbuffer[0] = buf[0];
1234 kernbuffer[1] = buf[1];
1235 kernbuffer[2] = buf[2];
1238 return ret;
1240 default:
1241 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1242 addr, &swap32);
1243 if (!ret) {
1244 (*bytes_read) += 4;
1245 if (userbuffer) {
1246 if (put_user(swap32,
1247 (u32 __user *)userbuffer))
1248 return -EFAULT;
1250 userbuffer += 4;
1251 } else {
1252 *((u32 *)kernbuffer) = swap32;
1253 kernbuffer += 4;
1255 addr += 4;
1256 length -= 4;
1260 if (ret)
1261 break;
1264 return ret;
1267 /* High level: Gfx (indexed) register access */
1269 #ifdef INCL_SISUSB_CON
1271 sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
1273 return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1277 sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
1279 return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1281 #endif
1284 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1286 int ret;
1287 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1288 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1289 return ret;
1293 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1295 int ret;
1296 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1297 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1298 return ret;
1302 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1303 u8 myand, u8 myor)
1305 int ret;
1306 u8 tmp;
1308 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1309 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1310 tmp &= myand;
1311 tmp |= myor;
1312 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1313 return ret;
1316 static int
1317 sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1318 u8 data, u8 mask)
1320 int ret;
1321 u8 tmp;
1322 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1323 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1324 tmp &= ~(mask);
1325 tmp |= (data & mask);
1326 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1327 return ret;
1331 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1333 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1337 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1339 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1342 /* Write/read video ram */
1344 #ifdef INCL_SISUSB_CON
1346 sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
1348 return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1352 sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
1354 return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1358 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
1359 u32 dest, int length, size_t *bytes_written)
1361 return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
1364 #ifdef SISUSBENDIANTEST
1366 sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
1367 u32 src, int length, size_t *bytes_written)
1369 return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
1371 #endif
1372 #endif
1374 #ifdef SISUSBENDIANTEST
1375 static void
1376 sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
1378 static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
1379 char destbuffer[10];
1380 size_t dummy;
1381 int i,j;
1383 sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
1385 for(i = 1; i <= 7; i++) {
1386 dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
1387 sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
1388 for(j = 0; j < i; j++) {
1389 dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
1393 #endif
1395 /* access pci config registers (reg numbers 0, 4, 8, etc) */
1397 static int
1398 sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1400 struct sisusb_packet packet;
1401 int ret;
1403 packet.header = 0x008f;
1404 packet.address = regnum | 0x10000;
1405 packet.data = data;
1406 ret = sisusb_send_packet(sisusb, 10, &packet);
1407 return ret;
1410 static int
1411 sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1413 struct sisusb_packet packet;
1414 int ret;
1416 packet.header = 0x008f;
1417 packet.address = (u32)regnum | 0x10000;
1418 ret = sisusb_send_packet(sisusb, 6, &packet);
1419 *data = packet.data;
1420 return ret;
1423 /* Clear video RAM */
1425 static int
1426 sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1428 int ret, i;
1429 ssize_t j;
1431 if (address < sisusb->vrambase)
1432 return 1;
1434 if (address >= sisusb->vrambase + sisusb->vramsize)
1435 return 1;
1437 if (address + length > sisusb->vrambase + sisusb->vramsize)
1438 length = sisusb->vrambase + sisusb->vramsize - address;
1440 if (length <= 0)
1441 return 0;
1443 /* allocate free buffer/urb and clear the buffer */
1444 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1445 return -EBUSY;
1447 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1449 /* We can write a length > buffer size here. The buffer
1450 * data will simply be re-used (like a ring-buffer).
1452 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1454 /* Free the buffer/urb */
1455 sisusb_free_outbuf(sisusb, i);
1457 return ret;
1460 /* Initialize the graphics core (return 0 on success)
1461 * This resets the graphics hardware and puts it into
1462 * a defined mode (640x480@60Hz)
1465 #define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1466 #define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1467 #define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
1468 #define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
1469 #define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
1470 #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
1471 #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
1472 #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1473 #define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1474 #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1475 #define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1477 static int
1478 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1480 int ret;
1481 u8 tmp8;
1483 ret = GETIREG(SISSR, 0x16, &tmp8);
1484 if (ramtype <= 1) {
1485 tmp8 &= 0x3f;
1486 ret |= SETIREG(SISSR, 0x16, tmp8);
1487 tmp8 |= 0x80;
1488 ret |= SETIREG(SISSR, 0x16, tmp8);
1489 } else {
1490 tmp8 |= 0xc0;
1491 ret |= SETIREG(SISSR, 0x16, tmp8);
1492 tmp8 &= 0x0f;
1493 ret |= SETIREG(SISSR, 0x16, tmp8);
1494 tmp8 |= 0x80;
1495 ret |= SETIREG(SISSR, 0x16, tmp8);
1496 tmp8 &= 0x0f;
1497 ret |= SETIREG(SISSR, 0x16, tmp8);
1498 tmp8 |= 0xd0;
1499 ret |= SETIREG(SISSR, 0x16, tmp8);
1500 tmp8 &= 0x0f;
1501 ret |= SETIREG(SISSR, 0x16, tmp8);
1502 tmp8 |= 0xa0;
1503 ret |= SETIREG(SISSR, 0x16, tmp8);
1505 return ret;
1508 static int
1509 sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1511 int ret;
1512 u8 ramtype, done = 0;
1513 u32 t0, t1, t2, t3;
1514 u32 ramptr = SISUSB_PCI_MEMBASE;
1516 ret = GETIREG(SISSR, 0x3a, &ramtype);
1517 ramtype &= 3;
1519 ret |= SETIREG(SISSR, 0x13, 0x00);
1521 if (ramtype <= 1) {
1522 ret |= SETIREG(SISSR, 0x14, 0x12);
1523 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1524 } else {
1525 ret |= SETIREG(SISSR, 0x14, 0x02);
1528 ret |= sisusb_triggersr16(sisusb, ramtype);
1529 ret |= WRITEL(ramptr + 0, 0x01234567);
1530 ret |= WRITEL(ramptr + 4, 0x456789ab);
1531 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1532 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1533 ret |= WRITEL(ramptr + 16, 0x55555555);
1534 ret |= WRITEL(ramptr + 20, 0x55555555);
1535 ret |= WRITEL(ramptr + 24, 0xffffffff);
1536 ret |= WRITEL(ramptr + 28, 0xffffffff);
1537 ret |= READL(ramptr + 0, &t0);
1538 ret |= READL(ramptr + 4, &t1);
1539 ret |= READL(ramptr + 8, &t2);
1540 ret |= READL(ramptr + 12, &t3);
1542 if (ramtype <= 1) {
1544 *chab = 0; *bw = 64;
1546 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1547 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1548 *chab = 0; *bw = 64;
1549 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1552 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1553 *chab = 1; *bw = 64;
1554 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1556 ret |= sisusb_triggersr16(sisusb, ramtype);
1557 ret |= WRITEL(ramptr + 0, 0x89abcdef);
1558 ret |= WRITEL(ramptr + 4, 0xcdef0123);
1559 ret |= WRITEL(ramptr + 8, 0x55555555);
1560 ret |= WRITEL(ramptr + 12, 0x55555555);
1561 ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1562 ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1563 ret |= READL(ramptr + 4, &t1);
1565 if (t1 != 0xcdef0123) {
1566 *bw = 32;
1567 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1571 } else {
1573 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1575 done = 0;
1577 if (t1 == 0x456789ab) {
1578 if (t0 == 0x01234567) {
1579 *chab = 0; *bw = 64;
1580 done = 1;
1582 } else {
1583 if (t0 == 0x01234567) {
1584 *chab = 0; *bw = 32;
1585 ret |= SETIREG(SISSR, 0x14, 0x00);
1586 done = 1;
1590 if (!done) {
1591 ret |= SETIREG(SISSR, 0x14, 0x03);
1592 ret |= sisusb_triggersr16(sisusb, ramtype);
1594 ret |= WRITEL(ramptr + 0, 0x01234567);
1595 ret |= WRITEL(ramptr + 4, 0x456789ab);
1596 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1597 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1598 ret |= WRITEL(ramptr + 16, 0x55555555);
1599 ret |= WRITEL(ramptr + 20, 0x55555555);
1600 ret |= WRITEL(ramptr + 24, 0xffffffff);
1601 ret |= WRITEL(ramptr + 28, 0xffffffff);
1602 ret |= READL(ramptr + 0, &t0);
1603 ret |= READL(ramptr + 4, &t1);
1605 if (t1 == 0x456789ab) {
1606 if (t0 == 0x01234567) {
1607 *chab = 1; *bw = 64;
1608 return ret;
1609 } /* else error */
1610 } else {
1611 if (t0 == 0x01234567) {
1612 *chab = 1; *bw = 32;
1613 ret |= SETIREG(SISSR, 0x14, 0x01);
1614 } /* else error */
1618 return ret;
1621 static int
1622 sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1624 int ret = 0;
1625 u32 ramptr = SISUSB_PCI_MEMBASE;
1626 u8 tmp1, tmp2, i, j;
1628 ret |= WRITEB(ramptr, 0xaa);
1629 ret |= WRITEB(ramptr + 16, 0x55);
1630 ret |= READB(ramptr, &tmp1);
1631 ret |= READB(ramptr + 16, &tmp2);
1632 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1633 for (i = 0, j = 16; i < 2; i++, j += 16) {
1634 ret |= GETIREG(SISSR, 0x21, &tmp1);
1635 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1636 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1637 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1638 ret |= SETIREG(SISSR, 0x21, tmp1);
1639 ret |= WRITEB(ramptr + 16 + j, j);
1640 ret |= READB(ramptr + 16 + j, &tmp1);
1641 if (tmp1 == j) {
1642 ret |= WRITEB(ramptr + j, j);
1643 break;
1647 return ret;
1650 static int
1651 sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1652 u8 rankno, u8 chab, const u8 dramtype[][5],
1653 int bw)
1655 int ret = 0, ranksize;
1656 u8 tmp;
1658 *iret = 0;
1660 if ((rankno == 2) && (dramtype[index][0] == 2))
1661 return ret;
1663 ranksize = dramtype[index][3] / 2 * bw / 32;
1665 if ((ranksize * rankno) > 128)
1666 return ret;
1668 tmp = 0;
1669 while ((ranksize >>= 1) > 0) tmp += 0x10;
1670 tmp |= ((rankno - 1) << 2);
1671 tmp |= ((bw / 64) & 0x02);
1672 tmp |= (chab & 0x01);
1674 ret = SETIREG(SISSR, 0x14, tmp);
1675 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1677 *iret = 1;
1679 return ret;
1682 static int
1683 sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1685 int ret = 0, i;
1686 u32 j, tmp;
1688 *iret = 0;
1690 for (i = 0, j = 0; i < testn; i++) {
1691 ret |= WRITEL(sisusb->vrambase + j, j);
1692 j += inc;
1695 for (i = 0, j = 0; i < testn; i++) {
1696 ret |= READL(sisusb->vrambase + j, &tmp);
1697 if (tmp != j) return ret;
1698 j += inc;
1701 *iret = 1;
1702 return ret;
1705 static int
1706 sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1707 int idx, int bw, const u8 rtype[][5])
1709 int ret = 0, i, i2ret;
1710 u32 inc;
1712 *iret = 0;
1714 for (i = rankno; i >= 1; i--) {
1715 inc = 1 << (rtype[idx][2] +
1716 rtype[idx][1] +
1717 rtype[idx][0] +
1718 bw / 64 + i);
1719 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1720 if (!i2ret)
1721 return ret;
1724 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1725 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1726 if (!i2ret)
1727 return ret;
1729 inc = 1 << (10 + bw / 64);
1730 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1731 if (!i2ret)
1732 return ret;
1734 *iret = 1;
1735 return ret;
1738 static int
1739 sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1740 int chab)
1742 int ret = 0, i2ret = 0, i, j;
1743 static const u8 sdramtype[13][5] = {
1744 { 2, 12, 9, 64, 0x35 },
1745 { 1, 13, 9, 64, 0x44 },
1746 { 2, 12, 8, 32, 0x31 },
1747 { 2, 11, 9, 32, 0x25 },
1748 { 1, 12, 9, 32, 0x34 },
1749 { 1, 13, 8, 32, 0x40 },
1750 { 2, 11, 8, 16, 0x21 },
1751 { 1, 12, 8, 16, 0x30 },
1752 { 1, 11, 9, 16, 0x24 },
1753 { 1, 11, 8, 8, 0x20 },
1754 { 2, 9, 8, 4, 0x01 },
1755 { 1, 10, 8, 4, 0x10 },
1756 { 1, 9, 8, 2, 0x00 }
1759 *iret = 1; /* error */
1761 for (i = 0; i < 13; i++) {
1762 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1763 for (j = 2; j > 0; j--) {
1764 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1765 chab, sdramtype, bw);
1766 if (!i2ret)
1767 continue;
1769 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1770 bw, sdramtype);
1771 if (i2ret) {
1772 *iret = 0; /* ram size found */
1773 return ret;
1778 return ret;
1781 static int
1782 sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1784 int ret = 0;
1785 u32 address;
1786 int i, length, modex, modey, bpp;
1788 modex = 640; modey = 480; bpp = 2;
1790 address = sisusb->vrambase; /* Clear video ram */
1792 if (clrall)
1793 length = sisusb->vramsize;
1794 else
1795 length = modex * bpp * modey;
1797 ret = sisusb_clear_vram(sisusb, address, length);
1799 if (!ret && drwfr) {
1800 for (i = 0; i < modex; i++) {
1801 address = sisusb->vrambase + (i * bpp);
1802 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1803 address, 0xf100);
1804 address += (modex * (modey-1) * bpp);
1805 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1806 address, 0xf100);
1808 for (i = 0; i < modey; i++) {
1809 address = sisusb->vrambase + ((i * modex) * bpp);
1810 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1811 address, 0xf100);
1812 address += ((modex - 1) * bpp);
1813 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1814 address, 0xf100);
1818 return ret;
1821 static int
1822 sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1824 int ret = 0, i, j, modex, modey, bpp, du;
1825 u8 sr31, cr63, tmp8;
1826 static const char attrdata[] = {
1827 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1828 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1829 0x01,0x00,0x00,0x00
1831 static const char crtcrdata[] = {
1832 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1833 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1834 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1835 0xff
1837 static const char grcdata[] = {
1838 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1839 0xff
1841 static const char crtcdata[] = {
1842 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1843 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1844 0x00
1847 modex = 640; modey = 480; bpp = 2;
1849 GETIREG(SISSR, 0x31, &sr31);
1850 GETIREG(SISCR, 0x63, &cr63);
1851 SETIREGOR(SISSR, 0x01, 0x20);
1852 SETIREG(SISCR, 0x63, cr63 & 0xbf);
1853 SETIREGOR(SISCR, 0x17, 0x80);
1854 SETIREGOR(SISSR, 0x1f, 0x04);
1855 SETIREGAND(SISSR, 0x07, 0xfb);
1856 SETIREG(SISSR, 0x00, 0x03); /* seq */
1857 SETIREG(SISSR, 0x01, 0x21);
1858 SETIREG(SISSR, 0x02, 0x0f);
1859 SETIREG(SISSR, 0x03, 0x00);
1860 SETIREG(SISSR, 0x04, 0x0e);
1861 SETREG(SISMISCW, 0x23); /* misc */
1862 for (i = 0; i <= 0x18; i++) { /* crtc */
1863 SETIREG(SISCR, i, crtcrdata[i]);
1865 for (i = 0; i <= 0x13; i++) { /* att */
1866 GETREG(SISINPSTAT, &tmp8);
1867 SETREG(SISAR, i);
1868 SETREG(SISAR, attrdata[i]);
1870 GETREG(SISINPSTAT, &tmp8);
1871 SETREG(SISAR, 0x14);
1872 SETREG(SISAR, 0x00);
1873 GETREG(SISINPSTAT, &tmp8);
1874 SETREG(SISAR, 0x20);
1875 GETREG(SISINPSTAT, &tmp8);
1876 for (i = 0; i <= 0x08; i++) { /* grc */
1877 SETIREG(SISGR, i, grcdata[i]);
1879 SETIREGAND(SISGR, 0x05, 0xbf);
1880 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1881 SETIREG(SISSR, i, 0x00);
1883 SETIREGAND(SISSR, 0x37, 0xfe);
1884 SETREG(SISMISCW, 0xef); /* sync */
1885 SETIREG(SISCR, 0x11, 0x00); /* crtc */
1886 for (j = 0x00, i = 0; i <= 7; i++, j++) {
1887 SETIREG(SISCR, j, crtcdata[i]);
1889 for (j = 0x10; i <= 10; i++, j++) {
1890 SETIREG(SISCR, j, crtcdata[i]);
1892 for (j = 0x15; i <= 12; i++, j++) {
1893 SETIREG(SISCR, j, crtcdata[i]);
1895 for (j = 0x0A; i <= 15; i++, j++) {
1896 SETIREG(SISSR, j, crtcdata[i]);
1898 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
1899 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
1900 SETIREG(SISCR, 0x14, 0x4f);
1901 du = (modex / 16) * (bpp * 2); /* offset/pitch */
1902 if (modex % 16) du += bpp;
1903 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
1904 SETIREG(SISCR, 0x13, (du & 0xff));
1905 du <<= 5;
1906 tmp8 = du >> 8;
1907 if (du & 0xff) tmp8++;
1908 SETIREG(SISSR, 0x10, tmp8);
1909 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
1910 SETIREG(SISSR, 0x2b, 0x1b);
1911 SETIREG(SISSR, 0x2c, 0xe1);
1912 SETIREG(SISSR, 0x2d, 0x01);
1913 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
1914 SETIREG(SISSR, 0x08, 0xae);
1915 SETIREGAND(SISSR, 0x09, 0xf0);
1916 SETIREG(SISSR, 0x08, 0x34);
1917 SETIREGOR(SISSR, 0x3d, 0x01);
1918 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
1919 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
1920 SETIREG(SISCR, 0x19, 0x00);
1921 SETIREGAND(SISCR, 0x1a, 0xfc);
1922 SETIREGAND(SISSR, 0x0f, 0xb7);
1923 SETIREGAND(SISSR, 0x31, 0xfb);
1924 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
1925 SETIREGAND(SISSR, 0x32, 0xf3);
1926 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
1927 SETIREG(SISCR, 0x52, 0x6c);
1929 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
1930 SETIREG(SISCR, 0x0c, 0x00);
1931 SETIREG(SISSR, 0x0d, 0x00);
1932 SETIREGAND(SISSR, 0x37, 0xfe);
1934 SETIREG(SISCR, 0x32, 0x20);
1935 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
1936 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
1937 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
1939 if (touchengines) {
1940 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
1941 SETIREGOR(SISSR, 0x1e, 0x5a);
1943 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
1944 SETIREG(SISSR, 0x27, 0x1f);
1945 SETIREG(SISSR, 0x26, 0x00);
1948 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
1950 return ret;
1953 static int
1954 sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
1956 int ret = 0, i, j, bw, chab, iret, retry = 3;
1957 u8 tmp8, ramtype;
1958 u32 tmp32;
1959 static const char mclktable[] = {
1960 0x3b, 0x22, 0x01, 143,
1961 0x3b, 0x22, 0x01, 143,
1962 0x3b, 0x22, 0x01, 143,
1963 0x3b, 0x22, 0x01, 143
1965 static const char eclktable[] = {
1966 0x3b, 0x22, 0x01, 143,
1967 0x3b, 0x22, 0x01, 143,
1968 0x3b, 0x22, 0x01, 143,
1969 0x3b, 0x22, 0x01, 143
1971 static const char ramtypetable1[] = {
1972 0x00, 0x04, 0x60, 0x60,
1973 0x0f, 0x0f, 0x1f, 0x1f,
1974 0xba, 0xba, 0xba, 0xba,
1975 0xa9, 0xa9, 0xac, 0xac,
1976 0xa0, 0xa0, 0xa0, 0xa8,
1977 0x00, 0x00, 0x02, 0x02,
1978 0x30, 0x30, 0x40, 0x40
1980 static const char ramtypetable2[] = {
1981 0x77, 0x77, 0x44, 0x44,
1982 0x77, 0x77, 0x44, 0x44,
1983 0x00, 0x00, 0x00, 0x00,
1984 0x5b, 0x5b, 0xab, 0xab,
1985 0x00, 0x00, 0xf0, 0xf8
1988 while (retry--) {
1990 /* Enable VGA */
1991 ret = GETREG(SISVGAEN, &tmp8);
1992 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
1994 /* Enable GPU access to VRAM */
1995 ret |= GETREG(SISMISCR, &tmp8);
1996 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
1998 if (ret) continue;
2000 /* Reset registers */
2001 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
2002 ret |= SETIREG(SISSR, 0x05, 0x86);
2003 ret |= SETIREGOR(SISSR, 0x20, 0x01);
2005 ret |= SETREG(SISMISCW, 0x67);
2007 for (i = 0x06; i <= 0x1f; i++) {
2008 ret |= SETIREG(SISSR, i, 0x00);
2010 for (i = 0x21; i <= 0x27; i++) {
2011 ret |= SETIREG(SISSR, i, 0x00);
2013 for (i = 0x31; i <= 0x3d; i++) {
2014 ret |= SETIREG(SISSR, i, 0x00);
2016 for (i = 0x12; i <= 0x1b; i++) {
2017 ret |= SETIREG(SISSR, i, 0x00);
2019 for (i = 0x79; i <= 0x7c; i++) {
2020 ret |= SETIREG(SISCR, i, 0x00);
2023 if (ret) continue;
2025 ret |= SETIREG(SISCR, 0x63, 0x80);
2027 ret |= GETIREG(SISSR, 0x3a, &ramtype);
2028 ramtype &= 0x03;
2030 ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
2031 ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
2032 ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
2034 ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
2035 ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
2036 ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
2038 ret |= SETIREG(SISSR, 0x07, 0x18);
2039 ret |= SETIREG(SISSR, 0x11, 0x0f);
2041 if (ret) continue;
2043 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2044 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2046 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2047 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2050 ret |= SETIREG(SISCR, 0x49, 0xaa);
2052 ret |= SETIREG(SISSR, 0x1f, 0x00);
2053 ret |= SETIREG(SISSR, 0x20, 0xa0);
2054 ret |= SETIREG(SISSR, 0x23, 0xf6);
2055 ret |= SETIREG(SISSR, 0x24, 0x0d);
2056 ret |= SETIREG(SISSR, 0x25, 0x33);
2058 ret |= SETIREG(SISSR, 0x11, 0x0f);
2060 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2062 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2064 if (ret) continue;
2066 ret |= SETIREG(SISPART1, 0x00, 0x00);
2068 ret |= GETIREG(SISSR, 0x13, &tmp8);
2069 tmp8 >>= 4;
2071 ret |= SETIREG(SISPART1, 0x02, 0x00);
2072 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2074 ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
2075 tmp32 &= 0x00f00000;
2076 tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
2077 ret |= SETIREG(SISSR, 0x25, tmp8);
2078 tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
2079 ret |= SETIREG(SISCR, 0x49, tmp8);
2081 ret |= SETIREG(SISSR, 0x27, 0x1f);
2082 ret |= SETIREG(SISSR, 0x31, 0x00);
2083 ret |= SETIREG(SISSR, 0x32, 0x11);
2084 ret |= SETIREG(SISSR, 0x33, 0x00);
2086 if (ret) continue;
2088 ret |= SETIREG(SISCR, 0x83, 0x00);
2090 ret |= sisusb_set_default_mode(sisusb, 0);
2092 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2093 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2094 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2096 ret |= sisusb_triggersr16(sisusb, ramtype);
2098 /* Disable refresh */
2099 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2100 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2102 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2103 ret |= sisusb_verify_mclk(sisusb);
2105 if (ramtype <= 1) {
2106 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2107 if (iret) {
2108 dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
2109 ret |= SETIREG(SISSR,0x14,0x31);
2110 /* TODO */
2112 } else {
2113 dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
2114 ret |= SETIREG(SISSR,0x14,0x31);
2115 /* *** TODO *** */
2118 /* Enable refresh */
2119 ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
2120 ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
2121 ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
2123 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2125 ret |= SETIREG(SISSR, 0x22, 0xfb);
2126 ret |= SETIREG(SISSR, 0x21, 0xa5);
2128 if (ret == 0)
2129 break;
2132 return ret;
2135 #undef SETREG
2136 #undef GETREG
2137 #undef SETIREG
2138 #undef GETIREG
2139 #undef SETIREGOR
2140 #undef SETIREGAND
2141 #undef SETIREGANDOR
2142 #undef READL
2143 #undef WRITEL
2145 static void
2146 sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2148 u8 tmp8, tmp82, ramtype;
2149 int bw = 0;
2150 char *ramtypetext1 = NULL;
2151 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2152 "DDR SDRAM", "DDR SGRAM" };
2153 static const int busSDR[4] = {64, 64, 128, 128};
2154 static const int busDDR[4] = {32, 32, 64, 64};
2155 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2157 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2158 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2159 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2160 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2161 ramtype &= 0x03;
2162 switch ((tmp8 >> 2) & 0x03) {
2163 case 0: ramtypetext1 = "1 ch/1 r";
2164 if (tmp82 & 0x10) {
2165 bw = 32;
2166 } else {
2167 bw = busSDR[(tmp8 & 0x03)];
2169 break;
2170 case 1: ramtypetext1 = "1 ch/2 r";
2171 sisusb->vramsize <<= 1;
2172 bw = busSDR[(tmp8 & 0x03)];
2173 break;
2174 case 2: ramtypetext1 = "asymmeric";
2175 sisusb->vramsize += sisusb->vramsize/2;
2176 bw = busDDRA[(tmp8 & 0x03)];
2177 break;
2178 case 3: ramtypetext1 = "2 channel";
2179 sisusb->vramsize <<= 1;
2180 bw = busDDR[(tmp8 & 0x03)];
2181 break;
2184 dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1,
2185 ramtypetext2[ramtype], bw);
2188 static int
2189 sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2191 struct sisusb_packet packet;
2192 int ret;
2193 u32 tmp32;
2195 /* Do some magic */
2196 packet.header = 0x001f;
2197 packet.address = 0x00000324;
2198 packet.data = 0x00000004;
2199 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2201 packet.header = 0x001f;
2202 packet.address = 0x00000364;
2203 packet.data = 0x00000004;
2204 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2206 packet.header = 0x001f;
2207 packet.address = 0x00000384;
2208 packet.data = 0x00000004;
2209 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2211 packet.header = 0x001f;
2212 packet.address = 0x00000100;
2213 packet.data = 0x00000700;
2214 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2216 packet.header = 0x000f;
2217 packet.address = 0x00000004;
2218 ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2219 packet.data |= 0x17;
2220 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2222 /* Init BAR 0 (VRAM) */
2223 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2224 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2225 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2226 tmp32 &= 0x0f;
2227 tmp32 |= SISUSB_PCI_MEMBASE;
2228 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2230 /* Init BAR 1 (MMIO) */
2231 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2232 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2233 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2234 tmp32 &= 0x0f;
2235 tmp32 |= SISUSB_PCI_MMIOBASE;
2236 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2238 /* Init BAR 2 (i/o ports) */
2239 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2240 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2241 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2242 tmp32 &= 0x0f;
2243 tmp32 |= SISUSB_PCI_IOPORTBASE;
2244 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2246 /* Enable memory and i/o access */
2247 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2248 tmp32 |= 0x3;
2249 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2251 if (ret == 0) {
2252 /* Some further magic */
2253 packet.header = 0x001f;
2254 packet.address = 0x00000050;
2255 packet.data = 0x000000ff;
2256 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2259 return ret;
2262 /* Initialize the graphics device (return 0 on success)
2263 * This initializes the net2280 as well as the PCI registers
2264 * of the graphics board.
2267 static int
2268 sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2270 int ret = 0, test = 0;
2271 u32 tmp32;
2273 if (sisusb->devinit == 1) {
2274 /* Read PCI BARs and see if they have been set up */
2275 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2276 if (ret) return ret;
2277 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
2279 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2280 if (ret) return ret;
2281 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2283 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2284 if (ret) return ret;
2285 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2288 /* No? So reset the device */
2289 if ((sisusb->devinit == 0) || (test != 3)) {
2291 ret |= sisusb_do_init_gfxdevice(sisusb);
2293 if (ret == 0)
2294 sisusb->devinit = 1;
2298 if (sisusb->devinit) {
2299 /* Initialize the graphics core */
2300 if (sisusb_init_gfxcore(sisusb) == 0) {
2301 sisusb->gfxinit = 1;
2302 sisusb_get_ramconfig(sisusb);
2303 ret |= sisusb_set_default_mode(sisusb, 1);
2304 ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2308 return ret;
2312 #ifdef INCL_SISUSB_CON
2314 /* Set up default text mode:
2315 - Set text mode (0x03)
2316 - Upload default font
2317 - Upload user font (if available)
2321 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
2323 int ret = 0, slot = sisusb->font_slot, i;
2324 const struct font_desc *myfont;
2325 u8 *tempbuf;
2326 u16 *tempbufb;
2327 size_t written;
2328 static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
2329 static const char bootlogo[] = "(o_ //\\ V_/_";
2331 /* sisusb->lock is down */
2333 if (!sisusb->SiS_Pr)
2334 return 1;
2336 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2337 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2339 /* Set mode 0x03 */
2340 SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
2342 if (!(myfont = find_font("VGA8x16")))
2343 return 1;
2345 if (!(tempbuf = vmalloc(8192)))
2346 return 1;
2348 for (i = 0; i < 256; i++)
2349 memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
2351 /* Upload default font */
2352 ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
2354 vfree(tempbuf);
2356 /* Upload user font (and reset current slot) */
2357 if (sisusb->font_backup) {
2358 ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
2359 8192, sisusb->font_backup_512, 1, NULL,
2360 sisusb->font_backup_height, 0);
2361 if (slot != 2)
2362 sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
2363 NULL, 16, 0);
2366 if (init && !sisusb->scrbuf) {
2368 if ((tempbuf = vmalloc(8192))) {
2370 i = 4096;
2371 tempbufb = (u16 *)tempbuf;
2372 while (i--)
2373 *(tempbufb++) = 0x0720;
2375 i = 0;
2376 tempbufb = (u16 *)tempbuf;
2377 while (bootlogo[i]) {
2378 *(tempbufb++) = 0x0700 | bootlogo[i++];
2379 if (!(i % 4))
2380 tempbufb += 76;
2383 i = 0;
2384 tempbufb = (u16 *)tempbuf + 6;
2385 while (bootstring[i])
2386 *(tempbufb++) = 0x0700 | bootstring[i++];
2388 ret |= sisusb_copy_memory(sisusb, tempbuf,
2389 sisusb->vrambase, 8192, &written);
2391 vfree(tempbuf);
2395 } else if (sisusb->scrbuf) {
2397 ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
2398 sisusb->vrambase, sisusb->scrbuf_size, &written);
2402 if (sisusb->sisusb_cursor_size_from >= 0 &&
2403 sisusb->sisusb_cursor_size_to >= 0) {
2404 sisusb_setidxreg(sisusb, SISCR, 0x0a,
2405 sisusb->sisusb_cursor_size_from);
2406 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
2407 sisusb->sisusb_cursor_size_to);
2408 } else {
2409 sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
2410 sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
2411 sisusb->sisusb_cursor_size_to = -1;
2414 slot = sisusb->sisusb_cursor_loc;
2415 if(slot < 0) slot = 0;
2417 sisusb->sisusb_cursor_loc = -1;
2418 sisusb->bad_cursor_pos = 1;
2420 sisusb_set_cursor(sisusb, slot);
2422 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
2423 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
2425 sisusb->textmodedestroyed = 0;
2427 /* sisusb->lock is down */
2429 return ret;
2432 #endif
2434 /* fops */
2436 static int
2437 sisusb_open(struct inode *inode, struct file *file)
2439 struct sisusb_usb_data *sisusb;
2440 struct usb_interface *interface;
2441 int subminor = iminor(inode);
2443 if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
2444 return -ENODEV;
2446 if (!(sisusb = usb_get_intfdata(interface)))
2447 return -ENODEV;
2449 mutex_lock(&sisusb->lock);
2451 if (!sisusb->present || !sisusb->ready) {
2452 mutex_unlock(&sisusb->lock);
2453 return -ENODEV;
2456 if (sisusb->isopen) {
2457 mutex_unlock(&sisusb->lock);
2458 return -EBUSY;
2461 if (!sisusb->devinit) {
2462 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2463 if (sisusb_init_gfxdevice(sisusb, 0)) {
2464 mutex_unlock(&sisusb->lock);
2465 dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
2466 return -EIO;
2468 } else {
2469 mutex_unlock(&sisusb->lock);
2470 dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
2471 return -EIO;
2475 /* Increment usage count for our sisusb */
2476 kref_get(&sisusb->kref);
2478 sisusb->isopen = 1;
2480 file->private_data = sisusb;
2482 mutex_unlock(&sisusb->lock);
2484 return 0;
2487 void
2488 sisusb_delete(struct kref *kref)
2490 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2492 if (!sisusb)
2493 return;
2495 if (sisusb->sisusb_dev)
2496 usb_put_dev(sisusb->sisusb_dev);
2498 sisusb->sisusb_dev = NULL;
2499 sisusb_free_buffers(sisusb);
2500 sisusb_free_urbs(sisusb);
2501 #ifdef INCL_SISUSB_CON
2502 kfree(sisusb->SiS_Pr);
2503 #endif
2504 kfree(sisusb);
2507 static int
2508 sisusb_release(struct inode *inode, struct file *file)
2510 struct sisusb_usb_data *sisusb;
2512 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2513 return -ENODEV;
2515 mutex_lock(&sisusb->lock);
2517 if (sisusb->present) {
2518 /* Wait for all URBs to finish if device still present */
2519 if (!sisusb_wait_all_out_complete(sisusb))
2520 sisusb_kill_all_busy(sisusb);
2523 sisusb->isopen = 0;
2524 file->private_data = NULL;
2526 mutex_unlock(&sisusb->lock);
2528 /* decrement the usage count on our device */
2529 kref_put(&sisusb->kref, sisusb_delete);
2531 return 0;
2534 static ssize_t
2535 sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2537 struct sisusb_usb_data *sisusb;
2538 ssize_t bytes_read = 0;
2539 int errno = 0;
2540 u8 buf8;
2541 u16 buf16;
2542 u32 buf32, address;
2544 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2545 return -ENODEV;
2547 mutex_lock(&sisusb->lock);
2549 /* Sanity check */
2550 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2551 mutex_unlock(&sisusb->lock);
2552 return -ENODEV;
2555 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2556 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2558 address = (*ppos) -
2559 SISUSB_PCI_PSEUDO_IOPORTBASE +
2560 SISUSB_PCI_IOPORTBASE;
2562 /* Read i/o ports
2563 * Byte, word and long(32) can be read. As this
2564 * emulates inX instructions, the data returned is
2565 * in machine-endianness.
2567 switch (count) {
2569 case 1:
2570 if (sisusb_read_memio_byte(sisusb,
2571 SISUSB_TYPE_IO,
2572 address, &buf8))
2573 errno = -EIO;
2574 else if (put_user(buf8, (u8 __user *)buffer))
2575 errno = -EFAULT;
2576 else
2577 bytes_read = 1;
2579 break;
2581 case 2:
2582 if (sisusb_read_memio_word(sisusb,
2583 SISUSB_TYPE_IO,
2584 address, &buf16))
2585 errno = -EIO;
2586 else if (put_user(buf16, (u16 __user *)buffer))
2587 errno = -EFAULT;
2588 else
2589 bytes_read = 2;
2591 break;
2593 case 4:
2594 if (sisusb_read_memio_long(sisusb,
2595 SISUSB_TYPE_IO,
2596 address, &buf32))
2597 errno = -EIO;
2598 else if (put_user(buf32, (u32 __user *)buffer))
2599 errno = -EFAULT;
2600 else
2601 bytes_read = 4;
2603 break;
2605 default:
2606 errno = -EIO;
2610 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2611 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2613 address = (*ppos) -
2614 SISUSB_PCI_PSEUDO_MEMBASE +
2615 SISUSB_PCI_MEMBASE;
2617 /* Read video ram
2618 * Remember: Data delivered is never endian-corrected
2620 errno = sisusb_read_mem_bulk(sisusb, address,
2621 NULL, count, buffer, &bytes_read);
2623 if (bytes_read)
2624 errno = bytes_read;
2626 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2627 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2629 address = (*ppos) -
2630 SISUSB_PCI_PSEUDO_MMIOBASE +
2631 SISUSB_PCI_MMIOBASE;
2633 /* Read MMIO
2634 * Remember: Data delivered is never endian-corrected
2636 errno = sisusb_read_mem_bulk(sisusb, address,
2637 NULL, count, buffer, &bytes_read);
2639 if (bytes_read)
2640 errno = bytes_read;
2642 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2643 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2645 if (count != 4) {
2646 mutex_unlock(&sisusb->lock);
2647 return -EINVAL;
2650 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2652 /* Read PCI config register
2653 * Return value delivered in machine endianness.
2655 if (sisusb_read_pci_config(sisusb, address, &buf32))
2656 errno = -EIO;
2657 else if (put_user(buf32, (u32 __user *)buffer))
2658 errno = -EFAULT;
2659 else
2660 bytes_read = 4;
2662 } else {
2664 errno = -EBADFD;
2668 (*ppos) += bytes_read;
2670 mutex_unlock(&sisusb->lock);
2672 return errno ? errno : bytes_read;
2675 static ssize_t
2676 sisusb_write(struct file *file, const char __user *buffer, size_t count,
2677 loff_t *ppos)
2679 struct sisusb_usb_data *sisusb;
2680 int errno = 0;
2681 ssize_t bytes_written = 0;
2682 u8 buf8;
2683 u16 buf16;
2684 u32 buf32, address;
2686 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2687 return -ENODEV;
2689 mutex_lock(&sisusb->lock);
2691 /* Sanity check */
2692 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2693 mutex_unlock(&sisusb->lock);
2694 return -ENODEV;
2697 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2698 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2700 address = (*ppos) -
2701 SISUSB_PCI_PSEUDO_IOPORTBASE +
2702 SISUSB_PCI_IOPORTBASE;
2704 /* Write i/o ports
2705 * Byte, word and long(32) can be written. As this
2706 * emulates outX instructions, the data is expected
2707 * in machine-endianness.
2709 switch (count) {
2711 case 1:
2712 if (get_user(buf8, (u8 __user *)buffer))
2713 errno = -EFAULT;
2714 else if (sisusb_write_memio_byte(sisusb,
2715 SISUSB_TYPE_IO,
2716 address, buf8))
2717 errno = -EIO;
2718 else
2719 bytes_written = 1;
2721 break;
2723 case 2:
2724 if (get_user(buf16, (u16 __user *)buffer))
2725 errno = -EFAULT;
2726 else if (sisusb_write_memio_word(sisusb,
2727 SISUSB_TYPE_IO,
2728 address, buf16))
2729 errno = -EIO;
2730 else
2731 bytes_written = 2;
2733 break;
2735 case 4:
2736 if (get_user(buf32, (u32 __user *)buffer))
2737 errno = -EFAULT;
2738 else if (sisusb_write_memio_long(sisusb,
2739 SISUSB_TYPE_IO,
2740 address, buf32))
2741 errno = -EIO;
2742 else
2743 bytes_written = 4;
2745 break;
2747 default:
2748 errno = -EIO;
2751 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2752 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2754 address = (*ppos) -
2755 SISUSB_PCI_PSEUDO_MEMBASE +
2756 SISUSB_PCI_MEMBASE;
2758 /* Write video ram.
2759 * Buffer is copied 1:1, therefore, on big-endian
2760 * machines, the data must be swapped by userland
2761 * in advance (if applicable; no swapping in 8bpp
2762 * mode or if YUV data is being transferred).
2764 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2765 count, buffer, 0, &bytes_written);
2767 if (bytes_written)
2768 errno = bytes_written;
2770 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2771 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2773 address = (*ppos) -
2774 SISUSB_PCI_PSEUDO_MMIOBASE +
2775 SISUSB_PCI_MMIOBASE;
2777 /* Write MMIO.
2778 * Buffer is copied 1:1, therefore, on big-endian
2779 * machines, the data must be swapped by userland
2780 * in advance.
2782 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2783 count, buffer, 0, &bytes_written);
2785 if (bytes_written)
2786 errno = bytes_written;
2788 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2789 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2791 if (count != 4) {
2792 mutex_unlock(&sisusb->lock);
2793 return -EINVAL;
2796 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2798 /* Write PCI config register.
2799 * Given value expected in machine endianness.
2801 if (get_user(buf32, (u32 __user *)buffer))
2802 errno = -EFAULT;
2803 else if (sisusb_write_pci_config(sisusb, address, buf32))
2804 errno = -EIO;
2805 else
2806 bytes_written = 4;
2809 } else {
2811 /* Error */
2812 errno = -EBADFD;
2816 (*ppos) += bytes_written;
2818 mutex_unlock(&sisusb->lock);
2820 return errno ? errno : bytes_written;
2823 static loff_t
2824 sisusb_lseek(struct file *file, loff_t offset, int orig)
2826 struct sisusb_usb_data *sisusb;
2827 loff_t ret;
2829 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2830 return -ENODEV;
2832 mutex_lock(&sisusb->lock);
2834 /* Sanity check */
2835 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2836 mutex_unlock(&sisusb->lock);
2837 return -ENODEV;
2840 switch (orig) {
2841 case 0:
2842 file->f_pos = offset;
2843 ret = file->f_pos;
2844 /* never negative, no force_successful_syscall needed */
2845 break;
2846 case 1:
2847 file->f_pos += offset;
2848 ret = file->f_pos;
2849 /* never negative, no force_successful_syscall needed */
2850 break;
2851 default:
2852 /* seeking relative to "end of file" is not supported */
2853 ret = -EINVAL;
2856 mutex_unlock(&sisusb->lock);
2857 return ret;
2860 static int
2861 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2862 unsigned long arg)
2864 int retval, port, length;
2865 u32 address;
2867 /* All our commands require the device
2868 * to be initialized.
2870 if (!sisusb->devinit)
2871 return -ENODEV;
2873 port = y->data3 -
2874 SISUSB_PCI_PSEUDO_IOPORTBASE +
2875 SISUSB_PCI_IOPORTBASE;
2877 switch (y->operation) {
2878 case SUCMD_GET:
2879 retval = sisusb_getidxreg(sisusb, port,
2880 y->data0, &y->data1);
2881 if (!retval) {
2882 if (copy_to_user((void __user *)arg, y,
2883 sizeof(*y)))
2884 retval = -EFAULT;
2886 break;
2888 case SUCMD_SET:
2889 retval = sisusb_setidxreg(sisusb, port,
2890 y->data0, y->data1);
2891 break;
2893 case SUCMD_SETOR:
2894 retval = sisusb_setidxregor(sisusb, port,
2895 y->data0, y->data1);
2896 break;
2898 case SUCMD_SETAND:
2899 retval = sisusb_setidxregand(sisusb, port,
2900 y->data0, y->data1);
2901 break;
2903 case SUCMD_SETANDOR:
2904 retval = sisusb_setidxregandor(sisusb, port,
2905 y->data0, y->data1, y->data2);
2906 break;
2908 case SUCMD_SETMASK:
2909 retval = sisusb_setidxregmask(sisusb, port,
2910 y->data0, y->data1, y->data2);
2911 break;
2913 case SUCMD_CLRSCR:
2914 /* Gfx core must be initialized */
2915 if (!sisusb->gfxinit)
2916 return -ENODEV;
2918 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
2919 address = y->data3 -
2920 SISUSB_PCI_PSEUDO_MEMBASE +
2921 SISUSB_PCI_MEMBASE;
2922 retval = sisusb_clear_vram(sisusb, address, length);
2923 break;
2925 case SUCMD_HANDLETEXTMODE:
2926 retval = 0;
2927 #ifdef INCL_SISUSB_CON
2928 /* Gfx core must be initialized, SiS_Pr must exist */
2929 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
2930 return -ENODEV;
2932 switch (y->data0) {
2933 case 0:
2934 retval = sisusb_reset_text_mode(sisusb, 0);
2935 break;
2936 case 1:
2937 sisusb->textmodedestroyed = 1;
2938 break;
2940 #endif
2941 break;
2943 #ifdef INCL_SISUSB_CON
2944 case SUCMD_SETMODE:
2945 /* Gfx core must be initialized, SiS_Pr must exist */
2946 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
2947 return -ENODEV;
2949 retval = 0;
2951 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2952 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2954 if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
2955 retval = -EINVAL;
2957 break;
2959 case SUCMD_SETVESAMODE:
2960 /* Gfx core must be initialized, SiS_Pr must exist */
2961 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
2962 return -ENODEV;
2964 retval = 0;
2966 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2967 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2969 if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
2970 retval = -EINVAL;
2972 break;
2973 #endif
2975 default:
2976 retval = -EINVAL;
2979 if (retval > 0)
2980 retval = -EIO;
2982 return retval;
2985 static int
2986 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
2987 unsigned long arg)
2989 struct sisusb_usb_data *sisusb;
2990 struct sisusb_info x;
2991 struct sisusb_command y;
2992 int retval = 0;
2993 u32 __user *argp = (u32 __user *)arg;
2995 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2996 return -ENODEV;
2998 mutex_lock(&sisusb->lock);
3000 /* Sanity check */
3001 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
3002 retval = -ENODEV;
3003 goto err_out;
3006 switch (cmd) {
3008 case SISUSB_GET_CONFIG_SIZE:
3010 if (put_user(sizeof(x), argp))
3011 retval = -EFAULT;
3013 break;
3015 case SISUSB_GET_CONFIG:
3017 x.sisusb_id = SISUSB_ID;
3018 x.sisusb_version = SISUSB_VERSION;
3019 x.sisusb_revision = SISUSB_REVISION;
3020 x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
3021 x.sisusb_gfxinit = sisusb->gfxinit;
3022 x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
3023 x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
3024 x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
3025 x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
3026 x.sisusb_vramsize = sisusb->vramsize;
3027 x.sisusb_minor = sisusb->minor;
3028 x.sisusb_fbdevactive= 0;
3029 #ifdef INCL_SISUSB_CON
3030 x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
3031 #else
3032 x.sisusb_conactive = 0;
3033 #endif
3035 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
3036 retval = -EFAULT;
3038 break;
3040 case SISUSB_COMMAND:
3042 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
3043 retval = -EFAULT;
3044 else
3045 retval = sisusb_handle_command(sisusb, &y, arg);
3047 break;
3049 default:
3050 retval = -ENOTTY;
3051 break;
3054 err_out:
3055 mutex_unlock(&sisusb->lock);
3056 return retval;
3059 #ifdef SISUSB_NEW_CONFIG_COMPAT
3060 static long
3061 sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
3063 long retval;
3065 switch (cmd) {
3066 case SISUSB_GET_CONFIG_SIZE:
3067 case SISUSB_GET_CONFIG:
3068 case SISUSB_COMMAND:
3069 lock_kernel();
3070 retval = sisusb_ioctl(f->f_path.dentry->d_inode, f, cmd, arg);
3071 unlock_kernel();
3072 return retval;
3074 default:
3075 return -ENOIOCTLCMD;
3078 #endif
3080 static const struct file_operations usb_sisusb_fops = {
3081 .owner = THIS_MODULE,
3082 .open = sisusb_open,
3083 .release = sisusb_release,
3084 .read = sisusb_read,
3085 .write = sisusb_write,
3086 .llseek = sisusb_lseek,
3087 #ifdef SISUSB_NEW_CONFIG_COMPAT
3088 .compat_ioctl = sisusb_compat_ioctl,
3089 #endif
3090 .ioctl = sisusb_ioctl
3093 static struct usb_class_driver usb_sisusb_class = {
3094 .name = "sisusbvga%d",
3095 .fops = &usb_sisusb_fops,
3096 .minor_base = SISUSB_MINOR
3099 static int sisusb_probe(struct usb_interface *intf,
3100 const struct usb_device_id *id)
3102 struct usb_device *dev = interface_to_usbdev(intf);
3103 struct sisusb_usb_data *sisusb;
3104 int retval = 0, i;
3106 dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
3107 dev->devnum);
3109 /* Allocate memory for our private */
3110 if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
3111 dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
3112 return -ENOMEM;
3114 kref_init(&sisusb->kref);
3116 mutex_init(&(sisusb->lock));
3118 /* Register device */
3119 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
3120 dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
3121 dev->devnum);
3122 retval = -ENODEV;
3123 goto error_1;
3126 sisusb->sisusb_dev = dev;
3127 sisusb->minor = intf->minor;
3128 sisusb->vrambase = SISUSB_PCI_MEMBASE;
3129 sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
3130 sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
3131 sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
3132 /* Everything else is zero */
3134 /* Allocate buffers */
3135 sisusb->ibufsize = SISUSB_IBUF_SIZE;
3136 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
3137 GFP_KERNEL, &sisusb->transfer_dma_in))) {
3138 dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
3139 retval = -ENOMEM;
3140 goto error_2;
3143 sisusb->numobufs = 0;
3144 sisusb->obufsize = SISUSB_OBUF_SIZE;
3145 for (i = 0; i < NUMOBUFS; i++) {
3146 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
3147 GFP_KERNEL,
3148 &sisusb->transfer_dma_out[i]))) {
3149 if (i == 0) {
3150 dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
3151 retval = -ENOMEM;
3152 goto error_3;
3154 break;
3155 } else
3156 sisusb->numobufs++;
3160 /* Allocate URBs */
3161 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
3162 dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
3163 retval = -ENOMEM;
3164 goto error_3;
3166 sisusb->completein = 1;
3168 for (i = 0; i < sisusb->numobufs; i++) {
3169 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
3170 dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
3171 retval = -ENOMEM;
3172 goto error_4;
3174 sisusb->urbout_context[i].sisusb = (void *)sisusb;
3175 sisusb->urbout_context[i].urbindex = i;
3176 sisusb->urbstatus[i] = 0;
3179 dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
3181 #ifdef INCL_SISUSB_CON
3182 /* Allocate our SiS_Pr */
3183 if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
3184 dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
3186 #endif
3188 /* Do remaining init stuff */
3190 init_waitqueue_head(&sisusb->wait_q);
3192 usb_set_intfdata(intf, sisusb);
3194 usb_get_dev(sisusb->sisusb_dev);
3196 sisusb->present = 1;
3198 #ifdef SISUSB_OLD_CONFIG_COMPAT
3200 int ret;
3201 /* Our ioctls are all "32/64bit compatible" */
3202 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3203 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3204 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3205 if (ret)
3206 dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
3207 else
3208 sisusb->ioctl32registered = 1;
3210 #endif
3212 if (dev->speed == USB_SPEED_HIGH) {
3213 int initscreen = 1;
3214 #ifdef INCL_SISUSB_CON
3215 if (sisusb_first_vc > 0 &&
3216 sisusb_last_vc > 0 &&
3217 sisusb_first_vc <= sisusb_last_vc &&
3218 sisusb_last_vc <= MAX_NR_CONSOLES)
3219 initscreen = 0;
3220 #endif
3221 if (sisusb_init_gfxdevice(sisusb, initscreen))
3222 dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
3224 } else
3225 dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
3227 sisusb->ready = 1;
3229 #ifdef SISUSBENDIANTEST
3230 dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
3231 sisusb_testreadwrite(sisusb);
3232 dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
3233 #endif
3235 #ifdef INCL_SISUSB_CON
3236 sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
3237 #endif
3239 return 0;
3241 error_4:
3242 sisusb_free_urbs(sisusb);
3243 error_3:
3244 sisusb_free_buffers(sisusb);
3245 error_2:
3246 usb_deregister_dev(intf, &usb_sisusb_class);
3247 error_1:
3248 kfree(sisusb);
3249 return retval;
3252 static void sisusb_disconnect(struct usb_interface *intf)
3254 struct sisusb_usb_data *sisusb;
3256 /* This should *not* happen */
3257 if (!(sisusb = usb_get_intfdata(intf)))
3258 return;
3260 #ifdef INCL_SISUSB_CON
3261 sisusb_console_exit(sisusb);
3262 #endif
3264 usb_deregister_dev(intf, &usb_sisusb_class);
3266 mutex_lock(&sisusb->lock);
3268 /* Wait for all URBs to complete and kill them in case (MUST do) */
3269 if (!sisusb_wait_all_out_complete(sisusb))
3270 sisusb_kill_all_busy(sisusb);
3272 usb_set_intfdata(intf, NULL);
3274 #ifdef SISUSB_OLD_CONFIG_COMPAT
3275 if (sisusb->ioctl32registered) {
3276 int ret;
3277 sisusb->ioctl32registered = 0;
3278 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3279 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3280 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3281 if (ret) {
3282 dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
3285 #endif
3287 sisusb->present = 0;
3288 sisusb->ready = 0;
3290 mutex_unlock(&sisusb->lock);
3292 /* decrement our usage count */
3293 kref_put(&sisusb->kref, sisusb_delete);
3295 dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
3298 static struct usb_device_id sisusb_table [] = {
3299 { USB_DEVICE(0x0711, 0x0550) },
3300 { USB_DEVICE(0x0711, 0x0900) },
3301 { USB_DEVICE(0x0711, 0x0901) },
3302 { USB_DEVICE(0x0711, 0x0902) },
3303 { USB_DEVICE(0x182d, 0x021c) },
3304 { USB_DEVICE(0x182d, 0x0269) },
3308 MODULE_DEVICE_TABLE (usb, sisusb_table);
3310 static struct usb_driver sisusb_driver = {
3311 .name = "sisusb",
3312 .probe = sisusb_probe,
3313 .disconnect = sisusb_disconnect,
3314 .id_table = sisusb_table,
3317 static int __init usb_sisusb_init(void)
3320 #ifdef INCL_SISUSB_CON
3321 sisusb_init_concode();
3322 #endif
3324 return usb_register(&sisusb_driver);
3327 static void __exit usb_sisusb_exit(void)
3329 usb_deregister(&sisusb_driver);
3332 module_init(usb_sisusb_init);
3333 module_exit(usb_sisusb_exit);
3335 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3336 MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
3337 MODULE_LICENSE("GPL");