Linux 2.6.18.8
[linux-2.6/suspend2-2.6.18.git] / drivers / usb / misc / sisusbvga / sisusb.c
blobe16582f3733c16a093ad30b4dbcf417093098f4a
1 /*
2 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
4 * Main part
6 * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
8 * If distributed as part of the Linux kernel, this code is licensed under the
9 * terms of the GPL v2.
11 * Otherwise, the following license terms apply:
13 * * Redistribution and use in source and binary forms, with or without
14 * * modification, are permitted provided that the following conditions
15 * * are met:
16 * * 1) Redistributions of source code must retain the above copyright
17 * * notice, this list of conditions and the following disclaimer.
18 * * 2) Redistributions in binary form must reproduce the above copyright
19 * * notice, this list of conditions and the following disclaimer in the
20 * * documentation and/or other materials provided with the distribution.
21 * * 3) The name of the author may not be used to endorse or promote products
22 * * derived from this software without specific psisusbr written permission.
23 * *
24 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
25 * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * Author: Thomas Winischhofer <thomas@winischhofer.net>
39 #include <linux/config.h>
40 #include <linux/mutex.h>
41 #include <linux/module.h>
42 #include <linux/kernel.h>
43 #include <linux/signal.h>
44 #include <linux/sched.h>
45 #include <linux/errno.h>
46 #include <linux/poll.h>
47 #include <linux/init.h>
48 #include <linux/slab.h>
49 #include <linux/spinlock.h>
50 #include <linux/kref.h>
51 #include <linux/usb.h>
52 #include <linux/smp_lock.h>
53 #include <linux/vmalloc.h>
55 #include "sisusb.h"
56 #include "sisusb_init.h"
58 #ifdef INCL_SISUSB_CON
59 #include <linux/font.h>
60 #endif
62 #define SISUSB_DONTSYNC
64 /* Forward declarations / clean-up routines */
66 #ifdef INCL_SISUSB_CON
67 static int sisusb_first_vc = 0;
68 static int sisusb_last_vc = 0;
69 module_param_named(first, sisusb_first_vc, int, 0);
70 module_param_named(last, sisusb_last_vc, int, 0);
71 MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)");
72 MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)");
73 #endif
75 static struct usb_driver sisusb_driver;
77 DEFINE_MUTEX(disconnect_mutex);
79 static void
80 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
82 int i;
84 for (i = 0; i < NUMOBUFS; i++) {
85 if (sisusb->obuf[i]) {
86 usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize,
87 sisusb->obuf[i], sisusb->transfer_dma_out[i]);
88 sisusb->obuf[i] = NULL;
91 if (sisusb->ibuf) {
92 usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
93 sisusb->ibuf, sisusb->transfer_dma_in);
94 sisusb->ibuf = NULL;
98 static void
99 sisusb_free_urbs(struct sisusb_usb_data *sisusb)
101 int i;
103 for (i = 0; i < NUMOBUFS; i++) {
104 usb_free_urb(sisusb->sisurbout[i]);
105 sisusb->sisurbout[i] = NULL;
107 usb_free_urb(sisusb->sisurbin);
108 sisusb->sisurbin = NULL;
111 /* Level 0: USB transport layer */
113 /* 1. out-bulks */
115 /* out-urb management */
117 /* Return 1 if all free, 0 otherwise */
118 static int
119 sisusb_all_free(struct sisusb_usb_data *sisusb)
121 int i;
123 for (i = 0; i < sisusb->numobufs; i++) {
125 if (sisusb->urbstatus[i] & SU_URB_BUSY)
126 return 0;
130 return 1;
133 /* Kill all busy URBs */
134 static void
135 sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
137 int i;
139 if (sisusb_all_free(sisusb))
140 return;
142 for (i = 0; i < sisusb->numobufs; i++) {
144 if (sisusb->urbstatus[i] & SU_URB_BUSY)
145 usb_kill_urb(sisusb->sisurbout[i]);
150 /* Return 1 if ok, 0 if error (not all complete within timeout) */
151 static int
152 sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
154 int timeout = 5 * HZ, i = 1;
156 wait_event_timeout(sisusb->wait_q,
157 (i = sisusb_all_free(sisusb)),
158 timeout);
160 return i;
163 static int
164 sisusb_outurb_available(struct sisusb_usb_data *sisusb)
166 int i;
168 for (i = 0; i < sisusb->numobufs; i++) {
170 if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
171 return i;
175 return -1;
178 static int
179 sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
181 int i, timeout = 5 * HZ;
183 wait_event_timeout(sisusb->wait_q,
184 ((i = sisusb_outurb_available(sisusb)) >= 0),
185 timeout);
187 return i;
190 static int
191 sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
193 int i;
195 i = sisusb_outurb_available(sisusb);
197 if (i >= 0)
198 sisusb->urbstatus[i] |= SU_URB_ALLOC;
200 return i;
203 static void
204 sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
206 if ((index >= 0) && (index < sisusb->numobufs))
207 sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
210 /* completion callback */
212 static void
213 sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
215 struct sisusb_urb_context *context = urb->context;
216 struct sisusb_usb_data *sisusb;
218 if (!context)
219 return;
221 sisusb = context->sisusb;
223 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
224 return;
226 #ifndef SISUSB_DONTSYNC
227 if (context->actual_length)
228 *(context->actual_length) += urb->actual_length;
229 #endif
231 sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
232 wake_up(&sisusb->wait_q);
235 static int
236 sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
237 int len, int *actual_length, int timeout, unsigned int tflags,
238 dma_addr_t transfer_dma)
240 struct urb *urb = sisusb->sisurbout[index];
241 int retval, byteswritten = 0;
243 /* Set up URB */
244 urb->transfer_flags = 0;
246 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
247 sisusb_bulk_completeout, &sisusb->urbout_context[index]);
249 urb->transfer_flags |= tflags;
250 urb->actual_length = 0;
252 if ((urb->transfer_dma = transfer_dma))
253 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
255 /* Set up context */
256 sisusb->urbout_context[index].actual_length = (timeout) ?
257 NULL : actual_length;
259 /* Declare this urb/buffer in use */
260 sisusb->urbstatus[index] |= SU_URB_BUSY;
262 /* Submit URB */
263 retval = usb_submit_urb(urb, GFP_ATOMIC);
265 /* If OK, and if timeout > 0, wait for completion */
266 if ((retval == 0) && timeout) {
267 wait_event_timeout(sisusb->wait_q,
268 (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
269 timeout);
270 if (sisusb->urbstatus[index] & SU_URB_BUSY) {
271 /* URB timed out... kill it and report error */
272 usb_kill_urb(urb);
273 retval = -ETIMEDOUT;
274 } else {
275 /* Otherwise, report urb status */
276 retval = urb->status;
277 byteswritten = urb->actual_length;
281 if (actual_length)
282 *actual_length = byteswritten;
284 return retval;
287 /* 2. in-bulks */
289 /* completion callback */
291 static void
292 sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
294 struct sisusb_usb_data *sisusb = urb->context;
296 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
297 return;
299 sisusb->completein = 1;
300 wake_up(&sisusb->wait_q);
303 static int
304 sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len,
305 int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma)
307 struct urb *urb = sisusb->sisurbin;
308 int retval, readbytes = 0;
310 urb->transfer_flags = 0;
312 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
313 sisusb_bulk_completein, sisusb);
315 urb->transfer_flags |= tflags;
316 urb->actual_length = 0;
318 if ((urb->transfer_dma = transfer_dma))
319 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
321 sisusb->completein = 0;
322 retval = usb_submit_urb(urb, GFP_ATOMIC);
323 if (retval == 0) {
324 wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
325 if (!sisusb->completein) {
326 /* URB timed out... kill it and report error */
327 usb_kill_urb(urb);
328 retval = -ETIMEDOUT;
329 } else {
330 /* URB completed within timout */
331 retval = urb->status;
332 readbytes = urb->actual_length;
336 if (actual_length)
337 *actual_length = readbytes;
339 return retval;
343 /* Level 1: */
345 /* Send a bulk message of variable size
347 * To copy the data from userspace, give pointer to "userbuffer",
348 * to copy from (non-DMA) kernel memory, give "kernbuffer". If
349 * both of these are NULL, it is assumed, that the transfer
350 * buffer "sisusb->obuf[index]" is set up with the data to send.
351 * Index is ignored if either kernbuffer or userbuffer is set.
352 * If async is nonzero, URBs will be sent without waiting for
353 * completion of the previous URB.
355 * (return 0 on success)
358 static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
359 char *kernbuffer, const char __user *userbuffer, int index,
360 ssize_t *bytes_written, unsigned int tflags, int async)
362 int result = 0, retry, count = len;
363 int passsize, thispass, transferred_len = 0;
364 int fromuser = (userbuffer != NULL) ? 1 : 0;
365 int fromkern = (kernbuffer != NULL) ? 1 : 0;
366 unsigned int pipe;
367 char *buffer;
369 (*bytes_written) = 0;
371 /* Sanity check */
372 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
373 return -ENODEV;
375 /* If we copy data from kernel or userspace, force the
376 * allocation of a buffer/urb. If we have the data in
377 * the transfer buffer[index] already, reuse the buffer/URB
378 * if the length is > buffer size. (So, transmitting
379 * large data amounts directly from the transfer buffer
380 * treats the buffer as a ring buffer. However, we need
381 * to sync in this case.)
383 if (fromuser || fromkern)
384 index = -1;
385 else if (len > sisusb->obufsize)
386 async = 0;
388 pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
390 do {
391 passsize = thispass = (sisusb->obufsize < count) ?
392 sisusb->obufsize : count;
394 if (index < 0)
395 index = sisusb_get_free_outbuf(sisusb);
397 if (index < 0)
398 return -EIO;
400 buffer = sisusb->obuf[index];
402 if (fromuser) {
404 if (copy_from_user(buffer, userbuffer, passsize))
405 return -EFAULT;
407 userbuffer += passsize;
409 } else if (fromkern) {
411 memcpy(buffer, kernbuffer, passsize);
412 kernbuffer += passsize;
416 retry = 5;
417 while (thispass) {
419 if (!sisusb->sisusb_dev)
420 return -ENODEV;
422 result = sisusb_bulkout_msg(sisusb,
423 index,
424 pipe,
425 buffer,
426 thispass,
427 &transferred_len,
428 async ? 0 : 5 * HZ,
429 tflags,
430 sisusb->transfer_dma_out[index]);
432 if (result == -ETIMEDOUT) {
434 /* Will not happen if async */
435 if (!retry--)
436 return -ETIME;
438 continue;
440 } else if ((result == 0) && !async && transferred_len) {
442 thispass -= transferred_len;
443 if (thispass) {
444 if (sisusb->transfer_dma_out) {
445 /* If DMA, copy remaining
446 * to beginning of buffer
448 memcpy(buffer,
449 buffer + transferred_len,
450 thispass);
451 } else {
452 /* If not DMA, simply increase
453 * the pointer
455 buffer += transferred_len;
459 } else
460 break;
463 if (result)
464 return result;
466 (*bytes_written) += passsize;
467 count -= passsize;
469 /* Force new allocation in next iteration */
470 if (fromuser || fromkern)
471 index = -1;
473 } while (count > 0);
475 if (async) {
476 #ifdef SISUSB_DONTSYNC
477 (*bytes_written) = len;
478 /* Some URBs/buffers might be busy */
479 #else
480 sisusb_wait_all_out_complete(sisusb);
481 (*bytes_written) = transferred_len;
482 /* All URBs and all buffers are available */
483 #endif
486 return ((*bytes_written) == len) ? 0 : -EIO;
489 /* Receive a bulk message of variable size
491 * To copy the data to userspace, give pointer to "userbuffer",
492 * to copy to kernel memory, give "kernbuffer". One of them
493 * MUST be set. (There is no technique for letting the caller
494 * read directly from the ibuf.)
498 static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
499 void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
500 unsigned int tflags)
502 int result = 0, retry, count = len;
503 int bufsize, thispass, transferred_len;
504 unsigned int pipe;
505 char *buffer;
507 (*bytes_read) = 0;
509 /* Sanity check */
510 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
511 return -ENODEV;
513 pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
514 buffer = sisusb->ibuf;
515 bufsize = sisusb->ibufsize;
517 retry = 5;
519 #ifdef SISUSB_DONTSYNC
520 if (!(sisusb_wait_all_out_complete(sisusb)))
521 return -EIO;
522 #endif
524 while (count > 0) {
526 if (!sisusb->sisusb_dev)
527 return -ENODEV;
529 thispass = (bufsize < count) ? bufsize : count;
531 result = sisusb_bulkin_msg(sisusb,
532 pipe,
533 buffer,
534 thispass,
535 &transferred_len,
536 5 * HZ,
537 tflags,
538 sisusb->transfer_dma_in);
540 if (transferred_len)
541 thispass = transferred_len;
543 else if (result == -ETIMEDOUT) {
545 if (!retry--)
546 return -ETIME;
548 continue;
550 } else
551 return -EIO;
554 if (thispass) {
556 (*bytes_read) += thispass;
557 count -= thispass;
559 if (userbuffer) {
561 if (copy_to_user(userbuffer, buffer, thispass))
562 return -EFAULT;
564 userbuffer += thispass;
566 } else {
568 memcpy(kernbuffer, buffer, thispass);
569 kernbuffer += thispass;
577 return ((*bytes_read) == len) ? 0 : -EIO;
580 static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
581 struct sisusb_packet *packet)
583 int ret;
584 ssize_t bytes_transferred = 0;
585 __le32 tmp;
587 if (len == 6)
588 packet->data = 0;
590 #ifdef SISUSB_DONTSYNC
591 if (!(sisusb_wait_all_out_complete(sisusb)))
592 return 1;
593 #endif
595 /* Eventually correct endianness */
596 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
598 /* 1. send the packet */
599 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
600 (char *)packet, NULL, 0, &bytes_transferred, 0, 0);
602 if ((ret == 0) && (len == 6)) {
604 /* 2. if packet len == 6, it means we read, so wait for 32bit
605 * return value and write it to packet->data
607 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
608 (char *)&tmp, NULL, &bytes_transferred, 0);
610 packet->data = le32_to_cpu(tmp);
613 return ret;
616 static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
617 struct sisusb_packet *packet,
618 unsigned int tflags)
620 int ret;
621 ssize_t bytes_transferred = 0;
622 __le32 tmp;
624 if (len == 6)
625 packet->data = 0;
627 #ifdef SISUSB_DONTSYNC
628 if (!(sisusb_wait_all_out_complete(sisusb)))
629 return 1;
630 #endif
632 /* Eventually correct endianness */
633 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
635 /* 1. send the packet */
636 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
637 (char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
639 if ((ret == 0) && (len == 6)) {
641 /* 2. if packet len == 6, it means we read, so wait for 32bit
642 * return value and write it to packet->data
644 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
645 (char *)&tmp, NULL, &bytes_transferred, 0);
647 packet->data = le32_to_cpu(tmp);
650 return ret;
653 /* access video memory and mmio (return 0 on success) */
655 /* Low level */
657 /* The following routines assume being used to transfer byte, word,
658 * long etc.
659 * This means that
660 * - the write routines expect "data" in machine endianness format.
661 * The data will be converted to leXX in sisusb_xxx_packet.
662 * - the read routines can expect read data in machine-endianess.
665 static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
666 u32 addr, u8 data)
668 struct sisusb_packet packet;
669 int ret;
671 packet.header = (1 << (addr & 3)) | (type << 6);
672 packet.address = addr & ~3;
673 packet.data = data << ((addr & 3) << 3);
674 ret = sisusb_send_packet(sisusb, 10, &packet);
675 return ret;
678 static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
679 u32 addr, u16 data)
681 struct sisusb_packet packet;
682 int ret = 0;
684 packet.address = addr & ~3;
686 switch (addr & 3) {
687 case 0:
688 packet.header = (type << 6) | 0x0003;
689 packet.data = (u32)data;
690 ret = sisusb_send_packet(sisusb, 10, &packet);
691 break;
692 case 1:
693 packet.header = (type << 6) | 0x0006;
694 packet.data = (u32)data << 8;
695 ret = sisusb_send_packet(sisusb, 10, &packet);
696 break;
697 case 2:
698 packet.header = (type << 6) | 0x000c;
699 packet.data = (u32)data << 16;
700 ret = sisusb_send_packet(sisusb, 10, &packet);
701 break;
702 case 3:
703 packet.header = (type << 6) | 0x0008;
704 packet.data = (u32)data << 24;
705 ret = sisusb_send_packet(sisusb, 10, &packet);
706 packet.header = (type << 6) | 0x0001;
707 packet.address = (addr & ~3) + 4;
708 packet.data = (u32)data >> 8;
709 ret |= sisusb_send_packet(sisusb, 10, &packet);
712 return ret;
715 static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
716 u32 addr, u32 data)
718 struct sisusb_packet packet;
719 int ret = 0;
721 packet.address = addr & ~3;
723 switch (addr & 3) {
724 case 0:
725 packet.header = (type << 6) | 0x0007;
726 packet.data = data & 0x00ffffff;
727 ret = sisusb_send_packet(sisusb, 10, &packet);
728 break;
729 case 1:
730 packet.header = (type << 6) | 0x000e;
731 packet.data = data << 8;
732 ret = sisusb_send_packet(sisusb, 10, &packet);
733 break;
734 case 2:
735 packet.header = (type << 6) | 0x000c;
736 packet.data = data << 16;
737 ret = sisusb_send_packet(sisusb, 10, &packet);
738 packet.header = (type << 6) | 0x0001;
739 packet.address = (addr & ~3) + 4;
740 packet.data = (data >> 16) & 0x00ff;
741 ret |= sisusb_send_packet(sisusb, 10, &packet);
742 break;
743 case 3:
744 packet.header = (type << 6) | 0x0008;
745 packet.data = data << 24;
746 ret = sisusb_send_packet(sisusb, 10, &packet);
747 packet.header = (type << 6) | 0x0003;
748 packet.address = (addr & ~3) + 4;
749 packet.data = (data >> 8) & 0xffff;
750 ret |= sisusb_send_packet(sisusb, 10, &packet);
753 return ret;
756 static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
757 u32 addr, u32 data)
759 struct sisusb_packet packet;
760 int ret = 0;
762 packet.address = addr & ~3;
764 switch (addr & 3) {
765 case 0:
766 packet.header = (type << 6) | 0x000f;
767 packet.data = data;
768 ret = sisusb_send_packet(sisusb, 10, &packet);
769 break;
770 case 1:
771 packet.header = (type << 6) | 0x000e;
772 packet.data = data << 8;
773 ret = sisusb_send_packet(sisusb, 10, &packet);
774 packet.header = (type << 6) | 0x0001;
775 packet.address = (addr & ~3) + 4;
776 packet.data = data >> 24;
777 ret |= sisusb_send_packet(sisusb, 10, &packet);
778 break;
779 case 2:
780 packet.header = (type << 6) | 0x000c;
781 packet.data = data << 16;
782 ret = sisusb_send_packet(sisusb, 10, &packet);
783 packet.header = (type << 6) | 0x0003;
784 packet.address = (addr & ~3) + 4;
785 packet.data = data >> 16;
786 ret |= sisusb_send_packet(sisusb, 10, &packet);
787 break;
788 case 3:
789 packet.header = (type << 6) | 0x0008;
790 packet.data = data << 24;
791 ret = sisusb_send_packet(sisusb, 10, &packet);
792 packet.header = (type << 6) | 0x0007;
793 packet.address = (addr & ~3) + 4;
794 packet.data = data >> 8;
795 ret |= sisusb_send_packet(sisusb, 10, &packet);
798 return ret;
801 /* The xxx_bulk routines copy a buffer of variable size. They treat the
802 * buffer as chars, therefore lsb/msb has to be corrected if using the
803 * byte/word/long/etc routines for speed-up
805 * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
806 * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
807 * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
808 * that the data already is in the transfer buffer "sisusb->obuf[index]".
811 static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
812 char *kernbuffer, int length,
813 const char __user *userbuffer, int index,
814 ssize_t *bytes_written)
816 struct sisusb_packet packet;
817 int ret = 0;
818 static int msgcount = 0;
819 u8 swap8, fromkern = kernbuffer ? 1 : 0;
820 u16 swap16;
821 u32 swap32, flag = (length >> 28) & 1;
822 char buf[4];
824 /* if neither kernbuffer not userbuffer are given, assume
825 * data in obuf
827 if (!fromkern && !userbuffer)
828 kernbuffer = sisusb->obuf[index];
830 (*bytes_written = 0);
832 length &= 0x00ffffff;
834 while (length) {
836 switch (length) {
838 case 1:
839 if (userbuffer) {
840 if (get_user(swap8, (u8 __user *)userbuffer))
841 return -EFAULT;
842 } else
843 swap8 = kernbuffer[0];
845 ret = sisusb_write_memio_byte(sisusb,
846 SISUSB_TYPE_MEM,
847 addr, swap8);
849 if (!ret)
850 (*bytes_written)++;
852 return ret;
854 case 2:
855 if (userbuffer) {
856 if (get_user(swap16, (u16 __user *)userbuffer))
857 return -EFAULT;
858 } else
859 swap16 = *((u16 *)kernbuffer);
861 ret = sisusb_write_memio_word(sisusb,
862 SISUSB_TYPE_MEM,
863 addr,
864 swap16);
866 if (!ret)
867 (*bytes_written) += 2;
869 return ret;
871 case 3:
872 if (userbuffer) {
873 if (copy_from_user(&buf, userbuffer, 3))
874 return -EFAULT;
875 #ifdef __BIG_ENDIAN
876 swap32 = (buf[0] << 16) |
877 (buf[1] << 8) |
878 buf[2];
879 #else
880 swap32 = (buf[2] << 16) |
881 (buf[1] << 8) |
882 buf[0];
883 #endif
884 } else
885 #ifdef __BIG_ENDIAN
886 swap32 = (kernbuffer[0] << 16) |
887 (kernbuffer[1] << 8) |
888 kernbuffer[2];
889 #else
890 swap32 = (kernbuffer[2] << 16) |
891 (kernbuffer[1] << 8) |
892 kernbuffer[0];
893 #endif
895 ret = sisusb_write_memio_24bit(sisusb,
896 SISUSB_TYPE_MEM,
897 addr,
898 swap32);
900 if (!ret)
901 (*bytes_written) += 3;
903 return ret;
905 case 4:
906 if (userbuffer) {
907 if (get_user(swap32, (u32 __user *)userbuffer))
908 return -EFAULT;
909 } else
910 swap32 = *((u32 *)kernbuffer);
912 ret = sisusb_write_memio_long(sisusb,
913 SISUSB_TYPE_MEM,
914 addr,
915 swap32);
916 if (!ret)
917 (*bytes_written) += 4;
919 return ret;
921 default:
922 if ((length & ~3) > 0x10000) {
924 packet.header = 0x001f;
925 packet.address = 0x000001d4;
926 packet.data = addr;
927 ret = sisusb_send_bridge_packet(sisusb, 10,
928 &packet, 0);
929 packet.header = 0x001f;
930 packet.address = 0x000001d0;
931 packet.data = (length & ~3);
932 ret |= sisusb_send_bridge_packet(sisusb, 10,
933 &packet, 0);
934 packet.header = 0x001f;
935 packet.address = 0x000001c0;
936 packet.data = flag | 0x16;
937 ret |= sisusb_send_bridge_packet(sisusb, 10,
938 &packet, 0);
939 if (userbuffer) {
940 ret |= sisusb_send_bulk_msg(sisusb,
941 SISUSB_EP_GFX_LBULK_OUT,
942 (length & ~3),
943 NULL, userbuffer, 0,
944 bytes_written, 0, 1);
945 userbuffer += (*bytes_written);
946 } else if (fromkern) {
947 ret |= sisusb_send_bulk_msg(sisusb,
948 SISUSB_EP_GFX_LBULK_OUT,
949 (length & ~3),
950 kernbuffer, NULL, 0,
951 bytes_written, 0, 1);
952 kernbuffer += (*bytes_written);
953 } else {
954 ret |= sisusb_send_bulk_msg(sisusb,
955 SISUSB_EP_GFX_LBULK_OUT,
956 (length & ~3),
957 NULL, NULL, index,
958 bytes_written, 0, 1);
959 kernbuffer += ((*bytes_written) &
960 (sisusb->obufsize-1));
963 } else {
965 packet.header = 0x001f;
966 packet.address = 0x00000194;
967 packet.data = addr;
968 ret = sisusb_send_bridge_packet(sisusb, 10,
969 &packet, 0);
970 packet.header = 0x001f;
971 packet.address = 0x00000190;
972 packet.data = (length & ~3);
973 ret |= sisusb_send_bridge_packet(sisusb, 10,
974 &packet, 0);
975 if (sisusb->flagb0 != 0x16) {
976 packet.header = 0x001f;
977 packet.address = 0x00000180;
978 packet.data = flag | 0x16;
979 ret |= sisusb_send_bridge_packet(sisusb, 10,
980 &packet, 0);
981 sisusb->flagb0 = 0x16;
983 if (userbuffer) {
984 ret |= sisusb_send_bulk_msg(sisusb,
985 SISUSB_EP_GFX_BULK_OUT,
986 (length & ~3),
987 NULL, userbuffer, 0,
988 bytes_written, 0, 1);
989 userbuffer += (*bytes_written);
990 } else if (fromkern) {
991 ret |= sisusb_send_bulk_msg(sisusb,
992 SISUSB_EP_GFX_BULK_OUT,
993 (length & ~3),
994 kernbuffer, NULL, 0,
995 bytes_written, 0, 1);
996 kernbuffer += (*bytes_written);
997 } else {
998 ret |= sisusb_send_bulk_msg(sisusb,
999 SISUSB_EP_GFX_BULK_OUT,
1000 (length & ~3),
1001 NULL, NULL, index,
1002 bytes_written, 0, 1);
1003 kernbuffer += ((*bytes_written) &
1004 (sisusb->obufsize-1));
1007 if (ret) {
1008 msgcount++;
1009 if (msgcount < 500)
1010 printk(KERN_ERR
1011 "sisusbvga[%d]: Wrote %zd of "
1012 "%d bytes, error %d\n",
1013 sisusb->minor, *bytes_written,
1014 length, ret);
1015 else if (msgcount == 500)
1016 printk(KERN_ERR
1017 "sisusbvga[%d]: Too many errors"
1018 ", logging stopped\n",
1019 sisusb->minor);
1021 addr += (*bytes_written);
1022 length -= (*bytes_written);
1025 if (ret)
1026 break;
1030 return ret ? -EIO : 0;
1033 /* Remember: Read data in packet is in machine-endianess! So for
1034 * byte, word, 24bit, long no endian correction is necessary.
1037 static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1038 u32 addr, u8 *data)
1040 struct sisusb_packet packet;
1041 int ret;
1043 CLEARPACKET(&packet);
1044 packet.header = (1 << (addr & 3)) | (type << 6);
1045 packet.address = addr & ~3;
1046 ret = sisusb_send_packet(sisusb, 6, &packet);
1047 *data = (u8)(packet.data >> ((addr & 3) << 3));
1048 return ret;
1051 static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1052 u32 addr, u16 *data)
1054 struct sisusb_packet packet;
1055 int ret = 0;
1057 CLEARPACKET(&packet);
1059 packet.address = addr & ~3;
1061 switch (addr & 3) {
1062 case 0:
1063 packet.header = (type << 6) | 0x0003;
1064 ret = sisusb_send_packet(sisusb, 6, &packet);
1065 *data = (u16)(packet.data);
1066 break;
1067 case 1:
1068 packet.header = (type << 6) | 0x0006;
1069 ret = sisusb_send_packet(sisusb, 6, &packet);
1070 *data = (u16)(packet.data >> 8);
1071 break;
1072 case 2:
1073 packet.header = (type << 6) | 0x000c;
1074 ret = sisusb_send_packet(sisusb, 6, &packet);
1075 *data = (u16)(packet.data >> 16);
1076 break;
1077 case 3:
1078 packet.header = (type << 6) | 0x0008;
1079 ret = sisusb_send_packet(sisusb, 6, &packet);
1080 *data = (u16)(packet.data >> 24);
1081 packet.header = (type << 6) | 0x0001;
1082 packet.address = (addr & ~3) + 4;
1083 ret |= sisusb_send_packet(sisusb, 6, &packet);
1084 *data |= (u16)(packet.data << 8);
1087 return ret;
1090 static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1091 u32 addr, u32 *data)
1093 struct sisusb_packet packet;
1094 int ret = 0;
1096 packet.address = addr & ~3;
1098 switch (addr & 3) {
1099 case 0:
1100 packet.header = (type << 6) | 0x0007;
1101 ret = sisusb_send_packet(sisusb, 6, &packet);
1102 *data = packet.data & 0x00ffffff;
1103 break;
1104 case 1:
1105 packet.header = (type << 6) | 0x000e;
1106 ret = sisusb_send_packet(sisusb, 6, &packet);
1107 *data = packet.data >> 8;
1108 break;
1109 case 2:
1110 packet.header = (type << 6) | 0x000c;
1111 ret = sisusb_send_packet(sisusb, 6, &packet);
1112 *data = packet.data >> 16;
1113 packet.header = (type << 6) | 0x0001;
1114 packet.address = (addr & ~3) + 4;
1115 ret |= sisusb_send_packet(sisusb, 6, &packet);
1116 *data |= ((packet.data & 0xff) << 16);
1117 break;
1118 case 3:
1119 packet.header = (type << 6) | 0x0008;
1120 ret = sisusb_send_packet(sisusb, 6, &packet);
1121 *data = packet.data >> 24;
1122 packet.header = (type << 6) | 0x0003;
1123 packet.address = (addr & ~3) + 4;
1124 ret |= sisusb_send_packet(sisusb, 6, &packet);
1125 *data |= ((packet.data & 0xffff) << 8);
1128 return ret;
1131 static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1132 u32 addr, u32 *data)
1134 struct sisusb_packet packet;
1135 int ret = 0;
1137 packet.address = addr & ~3;
1139 switch (addr & 3) {
1140 case 0:
1141 packet.header = (type << 6) | 0x000f;
1142 ret = sisusb_send_packet(sisusb, 6, &packet);
1143 *data = packet.data;
1144 break;
1145 case 1:
1146 packet.header = (type << 6) | 0x000e;
1147 ret = sisusb_send_packet(sisusb, 6, &packet);
1148 *data = packet.data >> 8;
1149 packet.header = (type << 6) | 0x0001;
1150 packet.address = (addr & ~3) + 4;
1151 ret |= sisusb_send_packet(sisusb, 6, &packet);
1152 *data |= (packet.data << 24);
1153 break;
1154 case 2:
1155 packet.header = (type << 6) | 0x000c;
1156 ret = sisusb_send_packet(sisusb, 6, &packet);
1157 *data = packet.data >> 16;
1158 packet.header = (type << 6) | 0x0003;
1159 packet.address = (addr & ~3) + 4;
1160 ret |= sisusb_send_packet(sisusb, 6, &packet);
1161 *data |= (packet.data << 16);
1162 break;
1163 case 3:
1164 packet.header = (type << 6) | 0x0008;
1165 ret = sisusb_send_packet(sisusb, 6, &packet);
1166 *data = packet.data >> 24;
1167 packet.header = (type << 6) | 0x0007;
1168 packet.address = (addr & ~3) + 4;
1169 ret |= sisusb_send_packet(sisusb, 6, &packet);
1170 *data |= (packet.data << 8);
1173 return ret;
1176 static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1177 char *kernbuffer, int length,
1178 char __user *userbuffer, ssize_t *bytes_read)
1180 int ret = 0;
1181 char buf[4];
1182 u16 swap16;
1183 u32 swap32;
1185 (*bytes_read = 0);
1187 length &= 0x00ffffff;
1189 while (length) {
1191 switch (length) {
1193 case 1:
1195 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1196 addr, &buf[0]);
1197 if (!ret) {
1198 (*bytes_read)++;
1199 if (userbuffer) {
1200 if (put_user(buf[0],
1201 (u8 __user *)userbuffer)) {
1202 return -EFAULT;
1204 } else {
1205 kernbuffer[0] = buf[0];
1208 return ret;
1210 case 2:
1211 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1212 addr, &swap16);
1213 if (!ret) {
1214 (*bytes_read) += 2;
1215 if (userbuffer) {
1216 if (put_user(swap16,
1217 (u16 __user *)userbuffer))
1218 return -EFAULT;
1219 } else {
1220 *((u16 *)kernbuffer) = swap16;
1223 return ret;
1225 case 3:
1226 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1227 addr, &swap32);
1228 if (!ret) {
1229 (*bytes_read) += 3;
1230 #ifdef __BIG_ENDIAN
1231 buf[0] = (swap32 >> 16) & 0xff;
1232 buf[1] = (swap32 >> 8) & 0xff;
1233 buf[2] = swap32 & 0xff;
1234 #else
1235 buf[2] = (swap32 >> 16) & 0xff;
1236 buf[1] = (swap32 >> 8) & 0xff;
1237 buf[0] = swap32 & 0xff;
1238 #endif
1239 if (userbuffer) {
1240 if (copy_to_user(userbuffer, &buf[0], 3))
1241 return -EFAULT;
1242 } else {
1243 kernbuffer[0] = buf[0];
1244 kernbuffer[1] = buf[1];
1245 kernbuffer[2] = buf[2];
1248 return ret;
1250 default:
1251 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1252 addr, &swap32);
1253 if (!ret) {
1254 (*bytes_read) += 4;
1255 if (userbuffer) {
1256 if (put_user(swap32,
1257 (u32 __user *)userbuffer))
1258 return -EFAULT;
1260 userbuffer += 4;
1261 } else {
1262 *((u32 *)kernbuffer) = swap32;
1263 kernbuffer += 4;
1265 addr += 4;
1266 length -= 4;
1268 #if 0 /* That does not work, as EP 2 is an OUT EP! */
1269 default:
1270 CLEARPACKET(&packet);
1271 packet.header = 0x001f;
1272 packet.address = 0x000001a0;
1273 packet.data = 0x00000006;
1274 ret |= sisusb_send_bridge_packet(sisusb, 10,
1275 &packet, 0);
1276 packet.header = 0x001f;
1277 packet.address = 0x000001b0;
1278 packet.data = (length & ~3) | 0x40000000;
1279 ret |= sisusb_send_bridge_packet(sisusb, 10,
1280 &packet, 0);
1281 packet.header = 0x001f;
1282 packet.address = 0x000001b4;
1283 packet.data = addr;
1284 ret |= sisusb_send_bridge_packet(sisusb, 10,
1285 &packet, 0);
1286 packet.header = 0x001f;
1287 packet.address = 0x000001a4;
1288 packet.data = 0x00000001;
1289 ret |= sisusb_send_bridge_packet(sisusb, 10,
1290 &packet, 0);
1291 if (userbuffer) {
1292 ret |= sisusb_recv_bulk_msg(sisusb,
1293 SISUSB_EP_GFX_BULK_IN,
1294 (length & ~3),
1295 NULL, userbuffer,
1296 bytes_read, 0);
1297 if (!ret) userbuffer += (*bytes_read);
1298 } else {
1299 ret |= sisusb_recv_bulk_msg(sisusb,
1300 SISUSB_EP_GFX_BULK_IN,
1301 (length & ~3),
1302 kernbuffer, NULL,
1303 bytes_read, 0);
1304 if (!ret) kernbuffer += (*bytes_read);
1306 addr += (*bytes_read);
1307 length -= (*bytes_read);
1308 #endif
1311 if (ret)
1312 break;
1315 return ret;
1318 /* High level: Gfx (indexed) register access */
1320 #ifdef INCL_SISUSB_CON
1322 sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
1324 return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1328 sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
1330 return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1332 #endif
1335 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1337 int ret;
1338 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1339 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1340 return ret;
1344 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1346 int ret;
1347 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1348 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1349 return ret;
1353 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1354 u8 myand, u8 myor)
1356 int ret;
1357 u8 tmp;
1359 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1360 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1361 tmp &= myand;
1362 tmp |= myor;
1363 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1364 return ret;
1367 static int
1368 sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1369 u8 data, u8 mask)
1371 int ret;
1372 u8 tmp;
1373 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1374 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1375 tmp &= ~(mask);
1376 tmp |= (data & mask);
1377 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1378 return ret;
1382 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1384 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1388 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1390 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1393 /* Write/read video ram */
1395 #ifdef INCL_SISUSB_CON
1397 sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
1399 return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1403 sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
1405 return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1408 #if 0
1411 sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
1413 return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1417 sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
1419 return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1422 #endif /* 0 */
1425 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
1426 u32 dest, int length, size_t *bytes_written)
1428 return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
1431 #ifdef SISUSBENDIANTEST
1433 sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
1434 u32 src, int length, size_t *bytes_written)
1436 return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
1438 #endif
1439 #endif
1441 #ifdef SISUSBENDIANTEST
1442 static void
1443 sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
1445 static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
1446 char destbuffer[10];
1447 size_t dummy;
1448 int i,j;
1450 sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
1452 for(i = 1; i <= 7; i++) {
1453 printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
1454 sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
1455 for(j = 0; j < i; j++) {
1456 printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
1460 #endif
1462 /* access pci config registers (reg numbers 0, 4, 8, etc) */
1464 static int
1465 sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1467 struct sisusb_packet packet;
1468 int ret;
1470 packet.header = 0x008f;
1471 packet.address = regnum | 0x10000;
1472 packet.data = data;
1473 ret = sisusb_send_packet(sisusb, 10, &packet);
1474 return ret;
1477 static int
1478 sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1480 struct sisusb_packet packet;
1481 int ret;
1483 packet.header = 0x008f;
1484 packet.address = (u32)regnum | 0x10000;
1485 ret = sisusb_send_packet(sisusb, 6, &packet);
1486 *data = packet.data;
1487 return ret;
1490 /* Clear video RAM */
1492 static int
1493 sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1495 int ret, i;
1496 ssize_t j;
1498 if (address < sisusb->vrambase)
1499 return 1;
1501 if (address >= sisusb->vrambase + sisusb->vramsize)
1502 return 1;
1504 if (address + length > sisusb->vrambase + sisusb->vramsize)
1505 length = sisusb->vrambase + sisusb->vramsize - address;
1507 if (length <= 0)
1508 return 0;
1510 /* allocate free buffer/urb and clear the buffer */
1511 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1512 return -EBUSY;
1514 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1516 /* We can write a length > buffer size here. The buffer
1517 * data will simply be re-used (like a ring-buffer).
1519 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1521 /* Free the buffer/urb */
1522 sisusb_free_outbuf(sisusb, i);
1524 return ret;
1527 /* Initialize the graphics core (return 0 on success)
1528 * This resets the graphics hardware and puts it into
1529 * a defined mode (640x480@60Hz)
1532 #define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1533 #define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1534 #define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
1535 #define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
1536 #define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
1537 #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
1538 #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
1539 #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1540 #define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1541 #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1542 #define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1544 static int
1545 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1547 int ret;
1548 u8 tmp8;
1550 ret = GETIREG(SISSR, 0x16, &tmp8);
1551 if (ramtype <= 1) {
1552 tmp8 &= 0x3f;
1553 ret |= SETIREG(SISSR, 0x16, tmp8);
1554 tmp8 |= 0x80;
1555 ret |= SETIREG(SISSR, 0x16, tmp8);
1556 } else {
1557 tmp8 |= 0xc0;
1558 ret |= SETIREG(SISSR, 0x16, tmp8);
1559 tmp8 &= 0x0f;
1560 ret |= SETIREG(SISSR, 0x16, tmp8);
1561 tmp8 |= 0x80;
1562 ret |= SETIREG(SISSR, 0x16, tmp8);
1563 tmp8 &= 0x0f;
1564 ret |= SETIREG(SISSR, 0x16, tmp8);
1565 tmp8 |= 0xd0;
1566 ret |= SETIREG(SISSR, 0x16, tmp8);
1567 tmp8 &= 0x0f;
1568 ret |= SETIREG(SISSR, 0x16, tmp8);
1569 tmp8 |= 0xa0;
1570 ret |= SETIREG(SISSR, 0x16, tmp8);
1572 return ret;
1575 static int
1576 sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1578 int ret;
1579 u8 ramtype, done = 0;
1580 u32 t0, t1, t2, t3;
1581 u32 ramptr = SISUSB_PCI_MEMBASE;
1583 ret = GETIREG(SISSR, 0x3a, &ramtype);
1584 ramtype &= 3;
1586 ret |= SETIREG(SISSR, 0x13, 0x00);
1588 if (ramtype <= 1) {
1589 ret |= SETIREG(SISSR, 0x14, 0x12);
1590 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1591 } else {
1592 ret |= SETIREG(SISSR, 0x14, 0x02);
1595 ret |= sisusb_triggersr16(sisusb, ramtype);
1596 ret |= WRITEL(ramptr + 0, 0x01234567);
1597 ret |= WRITEL(ramptr + 4, 0x456789ab);
1598 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1599 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1600 ret |= WRITEL(ramptr + 16, 0x55555555);
1601 ret |= WRITEL(ramptr + 20, 0x55555555);
1602 ret |= WRITEL(ramptr + 24, 0xffffffff);
1603 ret |= WRITEL(ramptr + 28, 0xffffffff);
1604 ret |= READL(ramptr + 0, &t0);
1605 ret |= READL(ramptr + 4, &t1);
1606 ret |= READL(ramptr + 8, &t2);
1607 ret |= READL(ramptr + 12, &t3);
1609 if (ramtype <= 1) {
1611 *chab = 0; *bw = 64;
1613 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1614 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1615 *chab = 0; *bw = 64;
1616 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1619 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1620 *chab = 1; *bw = 64;
1621 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1623 ret |= sisusb_triggersr16(sisusb, ramtype);
1624 ret |= WRITEL(ramptr + 0, 0x89abcdef);
1625 ret |= WRITEL(ramptr + 4, 0xcdef0123);
1626 ret |= WRITEL(ramptr + 8, 0x55555555);
1627 ret |= WRITEL(ramptr + 12, 0x55555555);
1628 ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1629 ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1630 ret |= READL(ramptr + 4, &t1);
1632 if (t1 != 0xcdef0123) {
1633 *bw = 32;
1634 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1638 } else {
1640 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1642 done = 0;
1644 if (t1 == 0x456789ab) {
1645 if (t0 == 0x01234567) {
1646 *chab = 0; *bw = 64;
1647 done = 1;
1649 } else {
1650 if (t0 == 0x01234567) {
1651 *chab = 0; *bw = 32;
1652 ret |= SETIREG(SISSR, 0x14, 0x00);
1653 done = 1;
1657 if (!done) {
1658 ret |= SETIREG(SISSR, 0x14, 0x03);
1659 ret |= sisusb_triggersr16(sisusb, ramtype);
1661 ret |= WRITEL(ramptr + 0, 0x01234567);
1662 ret |= WRITEL(ramptr + 4, 0x456789ab);
1663 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1664 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1665 ret |= WRITEL(ramptr + 16, 0x55555555);
1666 ret |= WRITEL(ramptr + 20, 0x55555555);
1667 ret |= WRITEL(ramptr + 24, 0xffffffff);
1668 ret |= WRITEL(ramptr + 28, 0xffffffff);
1669 ret |= READL(ramptr + 0, &t0);
1670 ret |= READL(ramptr + 4, &t1);
1672 if (t1 == 0x456789ab) {
1673 if (t0 == 0x01234567) {
1674 *chab = 1; *bw = 64;
1675 return ret;
1676 } /* else error */
1677 } else {
1678 if (t0 == 0x01234567) {
1679 *chab = 1; *bw = 32;
1680 ret |= SETIREG(SISSR, 0x14, 0x01);
1681 } /* else error */
1685 return ret;
1688 static int
1689 sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1691 int ret = 0;
1692 u32 ramptr = SISUSB_PCI_MEMBASE;
1693 u8 tmp1, tmp2, i, j;
1695 ret |= WRITEB(ramptr, 0xaa);
1696 ret |= WRITEB(ramptr + 16, 0x55);
1697 ret |= READB(ramptr, &tmp1);
1698 ret |= READB(ramptr + 16, &tmp2);
1699 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1700 for (i = 0, j = 16; i < 2; i++, j += 16) {
1701 ret |= GETIREG(SISSR, 0x21, &tmp1);
1702 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1703 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1704 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1705 ret |= SETIREG(SISSR, 0x21, tmp1);
1706 ret |= WRITEB(ramptr + 16 + j, j);
1707 ret |= READB(ramptr + 16 + j, &tmp1);
1708 if (tmp1 == j) {
1709 ret |= WRITEB(ramptr + j, j);
1710 break;
1714 return ret;
1717 static int
1718 sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1719 u8 rankno, u8 chab, const u8 dramtype[][5],
1720 int bw)
1722 int ret = 0, ranksize;
1723 u8 tmp;
1725 *iret = 0;
1727 if ((rankno == 2) && (dramtype[index][0] == 2))
1728 return ret;
1730 ranksize = dramtype[index][3] / 2 * bw / 32;
1732 if ((ranksize * rankno) > 128)
1733 return ret;
1735 tmp = 0;
1736 while ((ranksize >>= 1) > 0) tmp += 0x10;
1737 tmp |= ((rankno - 1) << 2);
1738 tmp |= ((bw / 64) & 0x02);
1739 tmp |= (chab & 0x01);
1741 ret = SETIREG(SISSR, 0x14, tmp);
1742 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1744 *iret = 1;
1746 return ret;
1749 static int
1750 sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1752 int ret = 0, i;
1753 u32 j, tmp;
1755 *iret = 0;
1757 for (i = 0, j = 0; i < testn; i++) {
1758 ret |= WRITEL(sisusb->vrambase + j, j);
1759 j += inc;
1762 for (i = 0, j = 0; i < testn; i++) {
1763 ret |= READL(sisusb->vrambase + j, &tmp);
1764 if (tmp != j) return ret;
1765 j += inc;
1768 *iret = 1;
1769 return ret;
1772 static int
1773 sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1774 int idx, int bw, const u8 rtype[][5])
1776 int ret = 0, i, i2ret;
1777 u32 inc;
1779 *iret = 0;
1781 for (i = rankno; i >= 1; i--) {
1782 inc = 1 << (rtype[idx][2] +
1783 rtype[idx][1] +
1784 rtype[idx][0] +
1785 bw / 64 + i);
1786 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1787 if (!i2ret)
1788 return ret;
1791 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1792 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1793 if (!i2ret)
1794 return ret;
1796 inc = 1 << (10 + bw / 64);
1797 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1798 if (!i2ret)
1799 return ret;
1801 *iret = 1;
1802 return ret;
1805 static int
1806 sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1807 int chab)
1809 int ret = 0, i2ret = 0, i, j;
1810 static const u8 sdramtype[13][5] = {
1811 { 2, 12, 9, 64, 0x35 },
1812 { 1, 13, 9, 64, 0x44 },
1813 { 2, 12, 8, 32, 0x31 },
1814 { 2, 11, 9, 32, 0x25 },
1815 { 1, 12, 9, 32, 0x34 },
1816 { 1, 13, 8, 32, 0x40 },
1817 { 2, 11, 8, 16, 0x21 },
1818 { 1, 12, 8, 16, 0x30 },
1819 { 1, 11, 9, 16, 0x24 },
1820 { 1, 11, 8, 8, 0x20 },
1821 { 2, 9, 8, 4, 0x01 },
1822 { 1, 10, 8, 4, 0x10 },
1823 { 1, 9, 8, 2, 0x00 }
1826 *iret = 1; /* error */
1828 for (i = 0; i < 13; i++) {
1829 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1830 for (j = 2; j > 0; j--) {
1831 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1832 chab, sdramtype, bw);
1833 if (!i2ret)
1834 continue;
1836 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1837 bw, sdramtype);
1838 if (i2ret) {
1839 *iret = 0; /* ram size found */
1840 return ret;
1845 return ret;
1848 static int
1849 sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1851 int ret = 0;
1852 u32 address;
1853 int i, length, modex, modey, bpp;
1855 modex = 640; modey = 480; bpp = 2;
1857 address = sisusb->vrambase; /* Clear video ram */
1859 if (clrall)
1860 length = sisusb->vramsize;
1861 else
1862 length = modex * bpp * modey;
1864 ret = sisusb_clear_vram(sisusb, address, length);
1866 if (!ret && drwfr) {
1867 for (i = 0; i < modex; i++) {
1868 address = sisusb->vrambase + (i * bpp);
1869 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1870 address, 0xf100);
1871 address += (modex * (modey-1) * bpp);
1872 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1873 address, 0xf100);
1875 for (i = 0; i < modey; i++) {
1876 address = sisusb->vrambase + ((i * modex) * bpp);
1877 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1878 address, 0xf100);
1879 address += ((modex - 1) * bpp);
1880 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1881 address, 0xf100);
1885 return ret;
1888 static int
1889 sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1891 int ret = 0, i, j, modex, modey, bpp, du;
1892 u8 sr31, cr63, tmp8;
1893 static const char attrdata[] = {
1894 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1895 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1896 0x01,0x00,0x00,0x00
1898 static const char crtcrdata[] = {
1899 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1900 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1901 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1902 0xff
1904 static const char grcdata[] = {
1905 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1906 0xff
1908 static const char crtcdata[] = {
1909 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1910 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1911 0x00
1914 modex = 640; modey = 480; bpp = 2;
1916 GETIREG(SISSR, 0x31, &sr31);
1917 GETIREG(SISCR, 0x63, &cr63);
1918 SETIREGOR(SISSR, 0x01, 0x20);
1919 SETIREG(SISCR, 0x63, cr63 & 0xbf);
1920 SETIREGOR(SISCR, 0x17, 0x80);
1921 SETIREGOR(SISSR, 0x1f, 0x04);
1922 SETIREGAND(SISSR, 0x07, 0xfb);
1923 SETIREG(SISSR, 0x00, 0x03); /* seq */
1924 SETIREG(SISSR, 0x01, 0x21);
1925 SETIREG(SISSR, 0x02, 0x0f);
1926 SETIREG(SISSR, 0x03, 0x00);
1927 SETIREG(SISSR, 0x04, 0x0e);
1928 SETREG(SISMISCW, 0x23); /* misc */
1929 for (i = 0; i <= 0x18; i++) { /* crtc */
1930 SETIREG(SISCR, i, crtcrdata[i]);
1932 for (i = 0; i <= 0x13; i++) { /* att */
1933 GETREG(SISINPSTAT, &tmp8);
1934 SETREG(SISAR, i);
1935 SETREG(SISAR, attrdata[i]);
1937 GETREG(SISINPSTAT, &tmp8);
1938 SETREG(SISAR, 0x14);
1939 SETREG(SISAR, 0x00);
1940 GETREG(SISINPSTAT, &tmp8);
1941 SETREG(SISAR, 0x20);
1942 GETREG(SISINPSTAT, &tmp8);
1943 for (i = 0; i <= 0x08; i++) { /* grc */
1944 SETIREG(SISGR, i, grcdata[i]);
1946 SETIREGAND(SISGR, 0x05, 0xbf);
1947 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1948 SETIREG(SISSR, i, 0x00);
1950 SETIREGAND(SISSR, 0x37, 0xfe);
1951 SETREG(SISMISCW, 0xef); /* sync */
1952 SETIREG(SISCR, 0x11, 0x00); /* crtc */
1953 for (j = 0x00, i = 0; i <= 7; i++, j++) {
1954 SETIREG(SISCR, j, crtcdata[i]);
1956 for (j = 0x10; i <= 10; i++, j++) {
1957 SETIREG(SISCR, j, crtcdata[i]);
1959 for (j = 0x15; i <= 12; i++, j++) {
1960 SETIREG(SISCR, j, crtcdata[i]);
1962 for (j = 0x0A; i <= 15; i++, j++) {
1963 SETIREG(SISSR, j, crtcdata[i]);
1965 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
1966 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
1967 SETIREG(SISCR, 0x14, 0x4f);
1968 du = (modex / 16) * (bpp * 2); /* offset/pitch */
1969 if (modex % 16) du += bpp;
1970 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
1971 SETIREG(SISCR, 0x13, (du & 0xff));
1972 du <<= 5;
1973 tmp8 = du >> 8;
1974 if (du & 0xff) tmp8++;
1975 SETIREG(SISSR, 0x10, tmp8);
1976 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
1977 SETIREG(SISSR, 0x2b, 0x1b);
1978 SETIREG(SISSR, 0x2c, 0xe1);
1979 SETIREG(SISSR, 0x2d, 0x01);
1980 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
1981 SETIREG(SISSR, 0x08, 0xae);
1982 SETIREGAND(SISSR, 0x09, 0xf0);
1983 SETIREG(SISSR, 0x08, 0x34);
1984 SETIREGOR(SISSR, 0x3d, 0x01);
1985 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
1986 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
1987 SETIREG(SISCR, 0x19, 0x00);
1988 SETIREGAND(SISCR, 0x1a, 0xfc);
1989 SETIREGAND(SISSR, 0x0f, 0xb7);
1990 SETIREGAND(SISSR, 0x31, 0xfb);
1991 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
1992 SETIREGAND(SISSR, 0x32, 0xf3);
1993 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
1994 SETIREG(SISCR, 0x52, 0x6c);
1996 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
1997 SETIREG(SISCR, 0x0c, 0x00);
1998 SETIREG(SISSR, 0x0d, 0x00);
1999 SETIREGAND(SISSR, 0x37, 0xfe);
2001 SETIREG(SISCR, 0x32, 0x20);
2002 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
2003 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
2004 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
2006 if (touchengines) {
2007 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
2008 SETIREGOR(SISSR, 0x1e, 0x5a);
2010 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
2011 SETIREG(SISSR, 0x27, 0x1f);
2012 SETIREG(SISSR, 0x26, 0x00);
2015 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
2017 return ret;
2020 static int
2021 sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
2023 int ret = 0, i, j, bw, chab, iret, retry = 3;
2024 u8 tmp8, ramtype;
2025 u32 tmp32;
2026 static const char mclktable[] = {
2027 0x3b, 0x22, 0x01, 143,
2028 0x3b, 0x22, 0x01, 143,
2029 0x3b, 0x22, 0x01, 143,
2030 0x3b, 0x22, 0x01, 143
2032 static const char eclktable[] = {
2033 0x3b, 0x22, 0x01, 143,
2034 0x3b, 0x22, 0x01, 143,
2035 0x3b, 0x22, 0x01, 143,
2036 0x3b, 0x22, 0x01, 143
2038 static const char ramtypetable1[] = {
2039 0x00, 0x04, 0x60, 0x60,
2040 0x0f, 0x0f, 0x1f, 0x1f,
2041 0xba, 0xba, 0xba, 0xba,
2042 0xa9, 0xa9, 0xac, 0xac,
2043 0xa0, 0xa0, 0xa0, 0xa8,
2044 0x00, 0x00, 0x02, 0x02,
2045 0x30, 0x30, 0x40, 0x40
2047 static const char ramtypetable2[] = {
2048 0x77, 0x77, 0x44, 0x44,
2049 0x77, 0x77, 0x44, 0x44,
2050 0x00, 0x00, 0x00, 0x00,
2051 0x5b, 0x5b, 0xab, 0xab,
2052 0x00, 0x00, 0xf0, 0xf8
2055 while (retry--) {
2057 /* Enable VGA */
2058 ret = GETREG(SISVGAEN, &tmp8);
2059 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
2061 /* Enable GPU access to VRAM */
2062 ret |= GETREG(SISMISCR, &tmp8);
2063 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
2065 if (ret) continue;
2067 /* Reset registers */
2068 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
2069 ret |= SETIREG(SISSR, 0x05, 0x86);
2070 ret |= SETIREGOR(SISSR, 0x20, 0x01);
2072 ret |= SETREG(SISMISCW, 0x67);
2074 for (i = 0x06; i <= 0x1f; i++) {
2075 ret |= SETIREG(SISSR, i, 0x00);
2077 for (i = 0x21; i <= 0x27; i++) {
2078 ret |= SETIREG(SISSR, i, 0x00);
2080 for (i = 0x31; i <= 0x3d; i++) {
2081 ret |= SETIREG(SISSR, i, 0x00);
2083 for (i = 0x12; i <= 0x1b; i++) {
2084 ret |= SETIREG(SISSR, i, 0x00);
2086 for (i = 0x79; i <= 0x7c; i++) {
2087 ret |= SETIREG(SISCR, i, 0x00);
2090 if (ret) continue;
2092 ret |= SETIREG(SISCR, 0x63, 0x80);
2094 ret |= GETIREG(SISSR, 0x3a, &ramtype);
2095 ramtype &= 0x03;
2097 ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
2098 ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
2099 ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
2101 ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
2102 ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
2103 ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
2105 ret |= SETIREG(SISSR, 0x07, 0x18);
2106 ret |= SETIREG(SISSR, 0x11, 0x0f);
2108 if (ret) continue;
2110 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2111 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2113 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2114 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2117 ret |= SETIREG(SISCR, 0x49, 0xaa);
2119 ret |= SETIREG(SISSR, 0x1f, 0x00);
2120 ret |= SETIREG(SISSR, 0x20, 0xa0);
2121 ret |= SETIREG(SISSR, 0x23, 0xf6);
2122 ret |= SETIREG(SISSR, 0x24, 0x0d);
2123 ret |= SETIREG(SISSR, 0x25, 0x33);
2125 ret |= SETIREG(SISSR, 0x11, 0x0f);
2127 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2129 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2131 if (ret) continue;
2133 ret |= SETIREG(SISPART1, 0x00, 0x00);
2135 ret |= GETIREG(SISSR, 0x13, &tmp8);
2136 tmp8 >>= 4;
2138 ret |= SETIREG(SISPART1, 0x02, 0x00);
2139 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2141 ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
2142 tmp32 &= 0x00f00000;
2143 tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
2144 ret |= SETIREG(SISSR, 0x25, tmp8);
2145 tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
2146 ret |= SETIREG(SISCR, 0x49, tmp8);
2148 ret |= SETIREG(SISSR, 0x27, 0x1f);
2149 ret |= SETIREG(SISSR, 0x31, 0x00);
2150 ret |= SETIREG(SISSR, 0x32, 0x11);
2151 ret |= SETIREG(SISSR, 0x33, 0x00);
2153 if (ret) continue;
2155 ret |= SETIREG(SISCR, 0x83, 0x00);
2157 ret |= sisusb_set_default_mode(sisusb, 0);
2159 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2160 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2161 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2163 ret |= sisusb_triggersr16(sisusb, ramtype);
2165 /* Disable refresh */
2166 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2167 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2169 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2170 ret |= sisusb_verify_mclk(sisusb);
2172 if (ramtype <= 1) {
2173 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2174 if (iret) {
2175 printk(KERN_ERR "sisusbvga[%d]: RAM size "
2176 "detection failed, "
2177 "assuming 8MB video RAM\n",
2178 sisusb->minor);
2179 ret |= SETIREG(SISSR,0x14,0x31);
2180 /* TODO */
2182 } else {
2183 printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
2184 "assuming 8MB video RAM\n",
2185 sisusb->minor);
2186 ret |= SETIREG(SISSR,0x14,0x31);
2187 /* *** TODO *** */
2190 /* Enable refresh */
2191 ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
2192 ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
2193 ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
2195 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2197 ret |= SETIREG(SISSR, 0x22, 0xfb);
2198 ret |= SETIREG(SISSR, 0x21, 0xa5);
2200 if (ret == 0)
2201 break;
2204 return ret;
2207 #undef SETREG
2208 #undef GETREG
2209 #undef SETIREG
2210 #undef GETIREG
2211 #undef SETIREGOR
2212 #undef SETIREGAND
2213 #undef SETIREGANDOR
2214 #undef READL
2215 #undef WRITEL
2217 static void
2218 sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2220 u8 tmp8, tmp82, ramtype;
2221 int bw = 0;
2222 char *ramtypetext1 = NULL;
2223 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2224 "DDR SDRAM", "DDR SGRAM" };
2225 static const int busSDR[4] = {64, 64, 128, 128};
2226 static const int busDDR[4] = {32, 32, 64, 64};
2227 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2229 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2230 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2231 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2232 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2233 ramtype &= 0x03;
2234 switch ((tmp8 >> 2) & 0x03) {
2235 case 0: ramtypetext1 = "1 ch/1 r";
2236 if (tmp82 & 0x10) {
2237 bw = 32;
2238 } else {
2239 bw = busSDR[(tmp8 & 0x03)];
2241 break;
2242 case 1: ramtypetext1 = "1 ch/2 r";
2243 sisusb->vramsize <<= 1;
2244 bw = busSDR[(tmp8 & 0x03)];
2245 break;
2246 case 2: ramtypetext1 = "asymmeric";
2247 sisusb->vramsize += sisusb->vramsize/2;
2248 bw = busDDRA[(tmp8 & 0x03)];
2249 break;
2250 case 3: ramtypetext1 = "2 channel";
2251 sisusb->vramsize <<= 1;
2252 bw = busDDR[(tmp8 & 0x03)];
2253 break;
2256 printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2257 sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
2258 ramtypetext2[ramtype], bw);
2261 static int
2262 sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2264 struct sisusb_packet packet;
2265 int ret;
2266 u32 tmp32;
2268 /* Do some magic */
2269 packet.header = 0x001f;
2270 packet.address = 0x00000324;
2271 packet.data = 0x00000004;
2272 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2274 packet.header = 0x001f;
2275 packet.address = 0x00000364;
2276 packet.data = 0x00000004;
2277 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2279 packet.header = 0x001f;
2280 packet.address = 0x00000384;
2281 packet.data = 0x00000004;
2282 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2284 packet.header = 0x001f;
2285 packet.address = 0x00000100;
2286 packet.data = 0x00000700;
2287 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2289 packet.header = 0x000f;
2290 packet.address = 0x00000004;
2291 ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2292 packet.data |= 0x17;
2293 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2295 /* Init BAR 0 (VRAM) */
2296 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2297 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2298 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2299 tmp32 &= 0x0f;
2300 tmp32 |= SISUSB_PCI_MEMBASE;
2301 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2303 /* Init BAR 1 (MMIO) */
2304 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2305 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2306 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2307 tmp32 &= 0x0f;
2308 tmp32 |= SISUSB_PCI_MMIOBASE;
2309 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2311 /* Init BAR 2 (i/o ports) */
2312 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2313 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2314 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2315 tmp32 &= 0x0f;
2316 tmp32 |= SISUSB_PCI_IOPORTBASE;
2317 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2319 /* Enable memory and i/o access */
2320 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2321 tmp32 |= 0x3;
2322 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2324 if (ret == 0) {
2325 /* Some further magic */
2326 packet.header = 0x001f;
2327 packet.address = 0x00000050;
2328 packet.data = 0x000000ff;
2329 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2332 return ret;
2335 /* Initialize the graphics device (return 0 on success)
2336 * This initializes the net2280 as well as the PCI registers
2337 * of the graphics board.
2340 static int
2341 sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2343 int ret = 0, test = 0;
2344 u32 tmp32;
2346 if (sisusb->devinit == 1) {
2347 /* Read PCI BARs and see if they have been set up */
2348 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2349 if (ret) return ret;
2350 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
2352 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2353 if (ret) return ret;
2354 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2356 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2357 if (ret) return ret;
2358 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2361 /* No? So reset the device */
2362 if ((sisusb->devinit == 0) || (test != 3)) {
2364 ret |= sisusb_do_init_gfxdevice(sisusb);
2366 if (ret == 0)
2367 sisusb->devinit = 1;
2371 if (sisusb->devinit) {
2372 /* Initialize the graphics core */
2373 if (sisusb_init_gfxcore(sisusb) == 0) {
2374 sisusb->gfxinit = 1;
2375 sisusb_get_ramconfig(sisusb);
2376 ret |= sisusb_set_default_mode(sisusb, 1);
2377 ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2381 return ret;
2385 #ifdef INCL_SISUSB_CON
2387 /* Set up default text mode:
2388 - Set text mode (0x03)
2389 - Upload default font
2390 - Upload user font (if available)
2394 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
2396 int ret = 0, slot = sisusb->font_slot, i;
2397 const struct font_desc *myfont;
2398 u8 *tempbuf;
2399 u16 *tempbufb;
2400 size_t written;
2401 static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
2402 static const char bootlogo[] = "(o_ //\\ V_/_";
2404 /* sisusb->lock is down */
2406 if (!sisusb->SiS_Pr)
2407 return 1;
2409 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2410 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2412 /* Set mode 0x03 */
2413 SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
2415 if (!(myfont = find_font("VGA8x16")))
2416 return 1;
2418 if (!(tempbuf = vmalloc(8192)))
2419 return 1;
2421 for (i = 0; i < 256; i++)
2422 memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
2424 /* Upload default font */
2425 ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
2427 vfree(tempbuf);
2429 /* Upload user font (and reset current slot) */
2430 if (sisusb->font_backup) {
2431 ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
2432 8192, sisusb->font_backup_512, 1, NULL,
2433 sisusb->font_backup_height, 0);
2434 if (slot != 2)
2435 sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
2436 NULL, 16, 0);
2439 if (init && !sisusb->scrbuf) {
2441 if ((tempbuf = vmalloc(8192))) {
2443 i = 4096;
2444 tempbufb = (u16 *)tempbuf;
2445 while (i--)
2446 *(tempbufb++) = 0x0720;
2448 i = 0;
2449 tempbufb = (u16 *)tempbuf;
2450 while (bootlogo[i]) {
2451 *(tempbufb++) = 0x0700 | bootlogo[i++];
2452 if (!(i % 4))
2453 tempbufb += 76;
2456 i = 0;
2457 tempbufb = (u16 *)tempbuf + 6;
2458 while (bootstring[i])
2459 *(tempbufb++) = 0x0700 | bootstring[i++];
2461 ret |= sisusb_copy_memory(sisusb, tempbuf,
2462 sisusb->vrambase, 8192, &written);
2464 vfree(tempbuf);
2468 } else if (sisusb->scrbuf) {
2470 ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
2471 sisusb->vrambase, sisusb->scrbuf_size, &written);
2475 if (sisusb->sisusb_cursor_size_from >= 0 &&
2476 sisusb->sisusb_cursor_size_to >= 0) {
2477 sisusb_setidxreg(sisusb, SISCR, 0x0a,
2478 sisusb->sisusb_cursor_size_from);
2479 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
2480 sisusb->sisusb_cursor_size_to);
2481 } else {
2482 sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
2483 sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
2484 sisusb->sisusb_cursor_size_to = -1;
2487 slot = sisusb->sisusb_cursor_loc;
2488 if(slot < 0) slot = 0;
2490 sisusb->sisusb_cursor_loc = -1;
2491 sisusb->bad_cursor_pos = 1;
2493 sisusb_set_cursor(sisusb, slot);
2495 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
2496 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
2498 sisusb->textmodedestroyed = 0;
2500 /* sisusb->lock is down */
2502 return ret;
2505 #endif
2507 /* fops */
2509 static int
2510 sisusb_open(struct inode *inode, struct file *file)
2512 struct sisusb_usb_data *sisusb;
2513 struct usb_interface *interface;
2514 int subminor = iminor(inode);
2516 mutex_lock(&disconnect_mutex);
2518 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
2519 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
2520 subminor);
2521 mutex_unlock(&disconnect_mutex);
2522 return -ENODEV;
2525 if (!(sisusb = usb_get_intfdata(interface))) {
2526 mutex_unlock(&disconnect_mutex);
2527 return -ENODEV;
2530 mutex_lock(&sisusb->lock);
2532 if (!sisusb->present || !sisusb->ready) {
2533 mutex_unlock(&sisusb->lock);
2534 mutex_unlock(&disconnect_mutex);
2535 return -ENODEV;
2538 if (sisusb->isopen) {
2539 mutex_unlock(&sisusb->lock);
2540 mutex_unlock(&disconnect_mutex);
2541 return -EBUSY;
2544 if (!sisusb->devinit) {
2545 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2546 if (sisusb_init_gfxdevice(sisusb, 0)) {
2547 mutex_unlock(&sisusb->lock);
2548 mutex_unlock(&disconnect_mutex);
2549 printk(KERN_ERR
2550 "sisusbvga[%d]: Failed to initialize "
2551 "device\n",
2552 sisusb->minor);
2553 return -EIO;
2555 } else {
2556 mutex_unlock(&sisusb->lock);
2557 mutex_unlock(&disconnect_mutex);
2558 printk(KERN_ERR
2559 "sisusbvga[%d]: Device not attached to "
2560 "USB 2.0 hub\n",
2561 sisusb->minor);
2562 return -EIO;
2566 /* Increment usage count for our sisusb */
2567 kref_get(&sisusb->kref);
2569 sisusb->isopen = 1;
2571 file->private_data = sisusb;
2573 mutex_unlock(&sisusb->lock);
2575 mutex_unlock(&disconnect_mutex);
2577 return 0;
2580 void
2581 sisusb_delete(struct kref *kref)
2583 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2585 if (!sisusb)
2586 return;
2588 if (sisusb->sisusb_dev)
2589 usb_put_dev(sisusb->sisusb_dev);
2591 sisusb->sisusb_dev = NULL;
2592 sisusb_free_buffers(sisusb);
2593 sisusb_free_urbs(sisusb);
2594 #ifdef INCL_SISUSB_CON
2595 kfree(sisusb->SiS_Pr);
2596 #endif
2597 kfree(sisusb);
2600 static int
2601 sisusb_release(struct inode *inode, struct file *file)
2603 struct sisusb_usb_data *sisusb;
2604 int myminor;
2606 mutex_lock(&disconnect_mutex);
2608 if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
2609 mutex_unlock(&disconnect_mutex);
2610 return -ENODEV;
2613 mutex_lock(&sisusb->lock);
2615 if (sisusb->present) {
2616 /* Wait for all URBs to finish if device still present */
2617 if (!sisusb_wait_all_out_complete(sisusb))
2618 sisusb_kill_all_busy(sisusb);
2621 myminor = sisusb->minor;
2623 sisusb->isopen = 0;
2624 file->private_data = NULL;
2626 mutex_unlock(&sisusb->lock);
2628 /* decrement the usage count on our device */
2629 kref_put(&sisusb->kref, sisusb_delete);
2631 mutex_unlock(&disconnect_mutex);
2633 return 0;
2636 static ssize_t
2637 sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2639 struct sisusb_usb_data *sisusb;
2640 ssize_t bytes_read = 0;
2641 int errno = 0;
2642 u8 buf8;
2643 u16 buf16;
2644 u32 buf32, address;
2646 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2647 return -ENODEV;
2649 mutex_lock(&sisusb->lock);
2651 /* Sanity check */
2652 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2653 mutex_unlock(&sisusb->lock);
2654 return -ENODEV;
2657 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2658 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2660 address = (*ppos) -
2661 SISUSB_PCI_PSEUDO_IOPORTBASE +
2662 SISUSB_PCI_IOPORTBASE;
2664 /* Read i/o ports
2665 * Byte, word and long(32) can be read. As this
2666 * emulates inX instructions, the data returned is
2667 * in machine-endianness.
2669 switch (count) {
2671 case 1:
2672 if (sisusb_read_memio_byte(sisusb,
2673 SISUSB_TYPE_IO,
2674 address, &buf8))
2675 errno = -EIO;
2676 else if (put_user(buf8, (u8 __user *)buffer))
2677 errno = -EFAULT;
2678 else
2679 bytes_read = 1;
2681 break;
2683 case 2:
2684 if (sisusb_read_memio_word(sisusb,
2685 SISUSB_TYPE_IO,
2686 address, &buf16))
2687 errno = -EIO;
2688 else if (put_user(buf16, (u16 __user *)buffer))
2689 errno = -EFAULT;
2690 else
2691 bytes_read = 2;
2693 break;
2695 case 4:
2696 if (sisusb_read_memio_long(sisusb,
2697 SISUSB_TYPE_IO,
2698 address, &buf32))
2699 errno = -EIO;
2700 else if (put_user(buf32, (u32 __user *)buffer))
2701 errno = -EFAULT;
2702 else
2703 bytes_read = 4;
2705 break;
2707 default:
2708 errno = -EIO;
2712 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2713 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2715 address = (*ppos) -
2716 SISUSB_PCI_PSEUDO_MEMBASE +
2717 SISUSB_PCI_MEMBASE;
2719 /* Read video ram
2720 * Remember: Data delivered is never endian-corrected
2722 errno = sisusb_read_mem_bulk(sisusb, address,
2723 NULL, count, buffer, &bytes_read);
2725 if (bytes_read)
2726 errno = bytes_read;
2728 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2729 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2731 address = (*ppos) -
2732 SISUSB_PCI_PSEUDO_MMIOBASE +
2733 SISUSB_PCI_MMIOBASE;
2735 /* Read MMIO
2736 * Remember: Data delivered is never endian-corrected
2738 errno = sisusb_read_mem_bulk(sisusb, address,
2739 NULL, count, buffer, &bytes_read);
2741 if (bytes_read)
2742 errno = bytes_read;
2744 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2745 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2747 if (count != 4) {
2748 mutex_unlock(&sisusb->lock);
2749 return -EINVAL;
2752 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2754 /* Read PCI config register
2755 * Return value delivered in machine endianness.
2757 if (sisusb_read_pci_config(sisusb, address, &buf32))
2758 errno = -EIO;
2759 else if (put_user(buf32, (u32 __user *)buffer))
2760 errno = -EFAULT;
2761 else
2762 bytes_read = 4;
2764 } else {
2766 errno = -EBADFD;
2770 (*ppos) += bytes_read;
2772 mutex_unlock(&sisusb->lock);
2774 return errno ? errno : bytes_read;
2777 static ssize_t
2778 sisusb_write(struct file *file, const char __user *buffer, size_t count,
2779 loff_t *ppos)
2781 struct sisusb_usb_data *sisusb;
2782 int errno = 0;
2783 ssize_t bytes_written = 0;
2784 u8 buf8;
2785 u16 buf16;
2786 u32 buf32, address;
2788 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2789 return -ENODEV;
2791 mutex_lock(&sisusb->lock);
2793 /* Sanity check */
2794 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2795 mutex_unlock(&sisusb->lock);
2796 return -ENODEV;
2799 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2800 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2802 address = (*ppos) -
2803 SISUSB_PCI_PSEUDO_IOPORTBASE +
2804 SISUSB_PCI_IOPORTBASE;
2806 /* Write i/o ports
2807 * Byte, word and long(32) can be written. As this
2808 * emulates outX instructions, the data is expected
2809 * in machine-endianness.
2811 switch (count) {
2813 case 1:
2814 if (get_user(buf8, (u8 __user *)buffer))
2815 errno = -EFAULT;
2816 else if (sisusb_write_memio_byte(sisusb,
2817 SISUSB_TYPE_IO,
2818 address, buf8))
2819 errno = -EIO;
2820 else
2821 bytes_written = 1;
2823 break;
2825 case 2:
2826 if (get_user(buf16, (u16 __user *)buffer))
2827 errno = -EFAULT;
2828 else if (sisusb_write_memio_word(sisusb,
2829 SISUSB_TYPE_IO,
2830 address, buf16))
2831 errno = -EIO;
2832 else
2833 bytes_written = 2;
2835 break;
2837 case 4:
2838 if (get_user(buf32, (u32 __user *)buffer))
2839 errno = -EFAULT;
2840 else if (sisusb_write_memio_long(sisusb,
2841 SISUSB_TYPE_IO,
2842 address, buf32))
2843 errno = -EIO;
2844 else
2845 bytes_written = 4;
2847 break;
2849 default:
2850 errno = -EIO;
2853 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2854 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2856 address = (*ppos) -
2857 SISUSB_PCI_PSEUDO_MEMBASE +
2858 SISUSB_PCI_MEMBASE;
2860 /* Write video ram.
2861 * Buffer is copied 1:1, therefore, on big-endian
2862 * machines, the data must be swapped by userland
2863 * in advance (if applicable; no swapping in 8bpp
2864 * mode or if YUV data is being transferred).
2866 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2867 count, buffer, 0, &bytes_written);
2869 if (bytes_written)
2870 errno = bytes_written;
2872 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2873 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2875 address = (*ppos) -
2876 SISUSB_PCI_PSEUDO_MMIOBASE +
2877 SISUSB_PCI_MMIOBASE;
2879 /* Write MMIO.
2880 * Buffer is copied 1:1, therefore, on big-endian
2881 * machines, the data must be swapped by userland
2882 * in advance.
2884 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2885 count, buffer, 0, &bytes_written);
2887 if (bytes_written)
2888 errno = bytes_written;
2890 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2891 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2893 if (count != 4) {
2894 mutex_unlock(&sisusb->lock);
2895 return -EINVAL;
2898 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2900 /* Write PCI config register.
2901 * Given value expected in machine endianness.
2903 if (get_user(buf32, (u32 __user *)buffer))
2904 errno = -EFAULT;
2905 else if (sisusb_write_pci_config(sisusb, address, buf32))
2906 errno = -EIO;
2907 else
2908 bytes_written = 4;
2911 } else {
2913 /* Error */
2914 errno = -EBADFD;
2918 (*ppos) += bytes_written;
2920 mutex_unlock(&sisusb->lock);
2922 return errno ? errno : bytes_written;
2925 static loff_t
2926 sisusb_lseek(struct file *file, loff_t offset, int orig)
2928 struct sisusb_usb_data *sisusb;
2929 loff_t ret;
2931 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2932 return -ENODEV;
2934 mutex_lock(&sisusb->lock);
2936 /* Sanity check */
2937 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2938 mutex_unlock(&sisusb->lock);
2939 return -ENODEV;
2942 switch (orig) {
2943 case 0:
2944 file->f_pos = offset;
2945 ret = file->f_pos;
2946 /* never negative, no force_successful_syscall needed */
2947 break;
2948 case 1:
2949 file->f_pos += offset;
2950 ret = file->f_pos;
2951 /* never negative, no force_successful_syscall needed */
2952 break;
2953 default:
2954 /* seeking relative to "end of file" is not supported */
2955 ret = -EINVAL;
2958 mutex_unlock(&sisusb->lock);
2959 return ret;
2962 static int
2963 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2964 unsigned long arg)
2966 int retval, port, length;
2967 u32 address;
2969 /* All our commands require the device
2970 * to be initialized.
2972 if (!sisusb->devinit)
2973 return -ENODEV;
2975 port = y->data3 -
2976 SISUSB_PCI_PSEUDO_IOPORTBASE +
2977 SISUSB_PCI_IOPORTBASE;
2979 switch (y->operation) {
2980 case SUCMD_GET:
2981 retval = sisusb_getidxreg(sisusb, port,
2982 y->data0, &y->data1);
2983 if (!retval) {
2984 if (copy_to_user((void __user *)arg, y,
2985 sizeof(*y)))
2986 retval = -EFAULT;
2988 break;
2990 case SUCMD_SET:
2991 retval = sisusb_setidxreg(sisusb, port,
2992 y->data0, y->data1);
2993 break;
2995 case SUCMD_SETOR:
2996 retval = sisusb_setidxregor(sisusb, port,
2997 y->data0, y->data1);
2998 break;
3000 case SUCMD_SETAND:
3001 retval = sisusb_setidxregand(sisusb, port,
3002 y->data0, y->data1);
3003 break;
3005 case SUCMD_SETANDOR:
3006 retval = sisusb_setidxregandor(sisusb, port,
3007 y->data0, y->data1, y->data2);
3008 break;
3010 case SUCMD_SETMASK:
3011 retval = sisusb_setidxregmask(sisusb, port,
3012 y->data0, y->data1, y->data2);
3013 break;
3015 case SUCMD_CLRSCR:
3016 /* Gfx core must be initialized */
3017 if (!sisusb->gfxinit)
3018 return -ENODEV;
3020 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
3021 address = y->data3 -
3022 SISUSB_PCI_PSEUDO_MEMBASE +
3023 SISUSB_PCI_MEMBASE;
3024 retval = sisusb_clear_vram(sisusb, address, length);
3025 break;
3027 case SUCMD_HANDLETEXTMODE:
3028 retval = 0;
3029 #ifdef INCL_SISUSB_CON
3030 /* Gfx core must be initialized, SiS_Pr must exist */
3031 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3032 return -ENODEV;
3034 switch (y->data0) {
3035 case 0:
3036 retval = sisusb_reset_text_mode(sisusb, 0);
3037 break;
3038 case 1:
3039 sisusb->textmodedestroyed = 1;
3040 break;
3042 #endif
3043 break;
3045 #ifdef INCL_SISUSB_CON
3046 case SUCMD_SETMODE:
3047 /* Gfx core must be initialized, SiS_Pr must exist */
3048 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3049 return -ENODEV;
3051 retval = 0;
3053 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3054 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3056 if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
3057 retval = -EINVAL;
3059 break;
3061 case SUCMD_SETVESAMODE:
3062 /* Gfx core must be initialized, SiS_Pr must exist */
3063 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3064 return -ENODEV;
3066 retval = 0;
3068 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3069 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3071 if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
3072 retval = -EINVAL;
3074 break;
3075 #endif
3077 default:
3078 retval = -EINVAL;
3081 if (retval > 0)
3082 retval = -EIO;
3084 return retval;
3087 static int
3088 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
3089 unsigned long arg)
3091 struct sisusb_usb_data *sisusb;
3092 struct sisusb_info x;
3093 struct sisusb_command y;
3094 int retval = 0;
3095 u32 __user *argp = (u32 __user *)arg;
3097 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
3098 return -ENODEV;
3100 mutex_lock(&sisusb->lock);
3102 /* Sanity check */
3103 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
3104 retval = -ENODEV;
3105 goto err_out;
3108 switch (cmd) {
3110 case SISUSB_GET_CONFIG_SIZE:
3112 if (put_user(sizeof(x), argp))
3113 retval = -EFAULT;
3115 break;
3117 case SISUSB_GET_CONFIG:
3119 x.sisusb_id = SISUSB_ID;
3120 x.sisusb_version = SISUSB_VERSION;
3121 x.sisusb_revision = SISUSB_REVISION;
3122 x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
3123 x.sisusb_gfxinit = sisusb->gfxinit;
3124 x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
3125 x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
3126 x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
3127 x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
3128 x.sisusb_vramsize = sisusb->vramsize;
3129 x.sisusb_minor = sisusb->minor;
3130 x.sisusb_fbdevactive= 0;
3131 #ifdef INCL_SISUSB_CON
3132 x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
3133 #else
3134 x.sisusb_conactive = 0;
3135 #endif
3137 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
3138 retval = -EFAULT;
3140 break;
3142 case SISUSB_COMMAND:
3144 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
3145 retval = -EFAULT;
3146 else
3147 retval = sisusb_handle_command(sisusb, &y, arg);
3149 break;
3151 default:
3152 retval = -ENOTTY;
3153 break;
3156 err_out:
3157 mutex_unlock(&sisusb->lock);
3158 return retval;
3161 #ifdef SISUSB_NEW_CONFIG_COMPAT
3162 static long
3163 sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
3165 long retval;
3167 switch (cmd) {
3168 case SISUSB_GET_CONFIG_SIZE:
3169 case SISUSB_GET_CONFIG:
3170 case SISUSB_COMMAND:
3171 lock_kernel();
3172 retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
3173 unlock_kernel();
3174 return retval;
3176 default:
3177 return -ENOIOCTLCMD;
3180 #endif
3182 static struct file_operations usb_sisusb_fops = {
3183 .owner = THIS_MODULE,
3184 .open = sisusb_open,
3185 .release = sisusb_release,
3186 .read = sisusb_read,
3187 .write = sisusb_write,
3188 .llseek = sisusb_lseek,
3189 #ifdef SISUSB_NEW_CONFIG_COMPAT
3190 .compat_ioctl = sisusb_compat_ioctl,
3191 #endif
3192 .ioctl = sisusb_ioctl
3195 static struct usb_class_driver usb_sisusb_class = {
3196 .name = "sisusbvga%d",
3197 .fops = &usb_sisusb_fops,
3198 .minor_base = SISUSB_MINOR
3201 static int sisusb_probe(struct usb_interface *intf,
3202 const struct usb_device_id *id)
3204 struct usb_device *dev = interface_to_usbdev(intf);
3205 struct sisusb_usb_data *sisusb;
3206 int retval = 0, i;
3207 const char *memfail =
3208 KERN_ERR
3209 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
3211 printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
3212 dev->devnum);
3214 /* Allocate memory for our private */
3215 if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
3216 printk(KERN_ERR
3217 "sisusb: Failed to allocate memory for private data\n");
3218 return -ENOMEM;
3220 kref_init(&sisusb->kref);
3222 mutex_init(&(sisusb->lock));
3224 /* Register device */
3225 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
3226 printk(KERN_ERR
3227 "sisusb: Failed to get a minor for device %d\n",
3228 dev->devnum);
3229 retval = -ENODEV;
3230 goto error_1;
3233 sisusb->sisusb_dev = dev;
3234 sisusb->minor = intf->minor;
3235 sisusb->vrambase = SISUSB_PCI_MEMBASE;
3236 sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
3237 sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
3238 sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
3239 /* Everything else is zero */
3241 /* Allocate buffers */
3242 sisusb->ibufsize = SISUSB_IBUF_SIZE;
3243 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
3244 GFP_KERNEL, &sisusb->transfer_dma_in))) {
3245 printk(memfail, "input", sisusb->minor);
3246 retval = -ENOMEM;
3247 goto error_2;
3250 sisusb->numobufs = 0;
3251 sisusb->obufsize = SISUSB_OBUF_SIZE;
3252 for (i = 0; i < NUMOBUFS; i++) {
3253 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
3254 GFP_KERNEL,
3255 &sisusb->transfer_dma_out[i]))) {
3256 if (i == 0) {
3257 printk(memfail, "output", sisusb->minor);
3258 retval = -ENOMEM;
3259 goto error_3;
3261 break;
3262 } else
3263 sisusb->numobufs++;
3267 /* Allocate URBs */
3268 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
3269 printk(KERN_ERR
3270 "sisusbvga[%d]: Failed to allocate URBs\n",
3271 sisusb->minor);
3272 retval = -ENOMEM;
3273 goto error_3;
3275 sisusb->completein = 1;
3277 for (i = 0; i < sisusb->numobufs; i++) {
3278 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
3279 printk(KERN_ERR
3280 "sisusbvga[%d]: Failed to allocate URBs\n",
3281 sisusb->minor);
3282 retval = -ENOMEM;
3283 goto error_4;
3285 sisusb->urbout_context[i].sisusb = (void *)sisusb;
3286 sisusb->urbout_context[i].urbindex = i;
3287 sisusb->urbstatus[i] = 0;
3290 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
3291 sisusb->minor, sisusb->numobufs);
3293 #ifdef INCL_SISUSB_CON
3294 /* Allocate our SiS_Pr */
3295 if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
3296 printk(KERN_ERR
3297 "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
3298 sisusb->minor);
3300 #endif
3302 /* Do remaining init stuff */
3304 init_waitqueue_head(&sisusb->wait_q);
3306 usb_set_intfdata(intf, sisusb);
3308 usb_get_dev(sisusb->sisusb_dev);
3310 sisusb->present = 1;
3312 #ifdef SISUSB_OLD_CONFIG_COMPAT
3314 int ret;
3315 /* Our ioctls are all "32/64bit compatible" */
3316 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3317 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3318 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3319 if (ret)
3320 printk(KERN_ERR
3321 "sisusbvga[%d]: Error registering ioctl32 "
3322 "translations\n",
3323 sisusb->minor);
3324 else
3325 sisusb->ioctl32registered = 1;
3327 #endif
3329 if (dev->speed == USB_SPEED_HIGH) {
3330 int initscreen = 1;
3331 #ifdef INCL_SISUSB_CON
3332 if (sisusb_first_vc > 0 &&
3333 sisusb_last_vc > 0 &&
3334 sisusb_first_vc <= sisusb_last_vc &&
3335 sisusb_last_vc <= MAX_NR_CONSOLES)
3336 initscreen = 0;
3337 #endif
3338 if (sisusb_init_gfxdevice(sisusb, initscreen))
3339 printk(KERN_ERR
3340 "sisusbvga[%d]: Failed to early "
3341 "initialize device\n",
3342 sisusb->minor);
3344 } else
3345 printk(KERN_INFO
3346 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3347 "deferring init\n",
3348 sisusb->minor);
3350 sisusb->ready = 1;
3352 #ifdef SISUSBENDIANTEST
3353 printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
3354 sisusb_testreadwrite(sisusb);
3355 printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
3356 #endif
3358 #ifdef INCL_SISUSB_CON
3359 sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
3360 #endif
3362 return 0;
3364 error_4:
3365 sisusb_free_urbs(sisusb);
3366 error_3:
3367 sisusb_free_buffers(sisusb);
3368 error_2:
3369 usb_deregister_dev(intf, &usb_sisusb_class);
3370 error_1:
3371 kfree(sisusb);
3372 return retval;
3375 static void sisusb_disconnect(struct usb_interface *intf)
3377 struct sisusb_usb_data *sisusb;
3378 int minor;
3380 /* This should *not* happen */
3381 if (!(sisusb = usb_get_intfdata(intf)))
3382 return;
3384 #ifdef INCL_SISUSB_CON
3385 sisusb_console_exit(sisusb);
3386 #endif
3388 /* The above code doesn't need the disconnect
3389 * semaphore to be down; its meaning is to
3390 * protect all other routines from the disconnect
3391 * case, not the other way round.
3393 mutex_lock(&disconnect_mutex);
3395 mutex_lock(&sisusb->lock);
3397 /* Wait for all URBs to complete and kill them in case (MUST do) */
3398 if (!sisusb_wait_all_out_complete(sisusb))
3399 sisusb_kill_all_busy(sisusb);
3401 minor = sisusb->minor;
3403 usb_set_intfdata(intf, NULL);
3405 usb_deregister_dev(intf, &usb_sisusb_class);
3407 #ifdef SISUSB_OLD_CONFIG_COMPAT
3408 if (sisusb->ioctl32registered) {
3409 int ret;
3410 sisusb->ioctl32registered = 0;
3411 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3412 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3413 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3414 if (ret) {
3415 printk(KERN_ERR
3416 "sisusbvga[%d]: Error unregistering "
3417 "ioctl32 translations\n",
3418 minor);
3421 #endif
3423 sisusb->present = 0;
3424 sisusb->ready = 0;
3426 mutex_unlock(&sisusb->lock);
3428 /* decrement our usage count */
3429 kref_put(&sisusb->kref, sisusb_delete);
3431 mutex_unlock(&disconnect_mutex);
3433 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
3436 static struct usb_device_id sisusb_table [] = {
3437 { USB_DEVICE(0x0711, 0x0900) },
3438 { USB_DEVICE(0x0711, 0x0901) },
3439 { USB_DEVICE(0x0711, 0x0902) },
3440 { USB_DEVICE(0x182d, 0x021c) },
3441 { USB_DEVICE(0x182d, 0x0269) },
3445 MODULE_DEVICE_TABLE (usb, sisusb_table);
3447 static struct usb_driver sisusb_driver = {
3448 .name = "sisusb",
3449 .probe = sisusb_probe,
3450 .disconnect = sisusb_disconnect,
3451 .id_table = sisusb_table,
3454 static int __init usb_sisusb_init(void)
3456 int retval;
3458 #ifdef INCL_SISUSB_CON
3459 sisusb_init_concode();
3460 #endif
3462 if (!(retval = usb_register(&sisusb_driver))) {
3464 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3465 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3466 printk(KERN_INFO
3467 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3471 return retval;
3474 static void __exit usb_sisusb_exit(void)
3476 usb_deregister(&sisusb_driver);
3479 module_init(usb_sisusb_init);
3480 module_exit(usb_sisusb_exit);
3482 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3483 MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
3484 MODULE_LICENSE("GPL");