Linux-2.6.12-rc2
[linux-2.6/next.git] / drivers / usb / misc / sisusbvga / sisusb.c
blobbe163b33016742b95731b5b1e5e79b3167f0b1d5
1 /*
2 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
4 * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
6 * If distributed as part of the Linux kernel, this code is licensed under the
7 * terms of the GPL v2.
9 * Otherwise, the following license terms apply:
11 * * Redistribution and use in source and binary forms, with or without
12 * * modification, are permitted provided that the following conditions
13 * * are met:
14 * * 1) Redistributions of source code must retain the above copyright
15 * * notice, this list of conditions and the following disclaimer.
16 * * 2) Redistributions in binary form must reproduce the above copyright
17 * * notice, this list of conditions and the following disclaimer in the
18 * * documentation and/or other materials provided with the distribution.
19 * * 3) The name of the author may not be used to endorse or promote products
20 * * derived from this software without specific psisusbr written permission.
21 * *
22 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
23 * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * Author: Thomas Winischhofer <thomas@winischhofer.net>
37 #include <linux/config.h>
38 #include <linux/version.h>
39 #include <linux/module.h>
40 #include <linux/kernel.h>
41 #include <linux/signal.h>
42 #include <linux/sched.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>
52 #include "sisusb.h"
54 #define SISUSB_DONTSYNC
56 /* Forward declarations / clean-up routines */
58 static struct usb_driver sisusb_driver;
60 static DECLARE_MUTEX(disconnect_sem);
62 static void
63 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
65 int i;
67 for (i = 0; i < NUMOBUFS; i++) {
68 if (sisusb->obuf[i]) {
69 usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize,
70 sisusb->obuf[i], sisusb->transfer_dma_out[i]);
71 sisusb->obuf[i] = NULL;
74 if (sisusb->ibuf) {
75 usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
76 sisusb->ibuf, sisusb->transfer_dma_in);
77 sisusb->ibuf = NULL;
81 static void
82 sisusb_free_urbs(struct sisusb_usb_data *sisusb)
84 int i;
86 for (i = 0; i < NUMOBUFS; i++) {
87 usb_free_urb(sisusb->sisurbout[i]);
88 sisusb->sisurbout[i] = NULL;
90 usb_free_urb(sisusb->sisurbin);
91 sisusb->sisurbin = NULL;
94 /* Level 0: USB transport layer */
96 /* 1. out-bulks */
98 /* out-urb management */
100 /* Return 1 if all free, 0 otherwise */
101 static int
102 sisusb_all_free(struct sisusb_usb_data *sisusb)
104 int i;
106 for (i = 0; i < sisusb->numobufs; i++) {
108 if (sisusb->urbstatus[i] & SU_URB_BUSY)
109 return 0;
113 return 1;
116 /* Kill all busy URBs */
117 static void
118 sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
120 int i;
122 if (sisusb_all_free(sisusb))
123 return;
125 for (i = 0; i < sisusb->numobufs; i++) {
127 if (sisusb->urbstatus[i] & SU_URB_BUSY)
128 usb_kill_urb(sisusb->sisurbout[i]);
133 /* Return 1 if ok, 0 if error (not all complete within timeout) */
134 static int
135 sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
137 int timeout = 5 * HZ, i = 1;
139 wait_event_timeout(sisusb->wait_q,
140 (i = sisusb_all_free(sisusb)),
141 timeout);
143 return i;
146 static int
147 sisusb_outurb_available(struct sisusb_usb_data *sisusb)
149 int i;
151 for (i = 0; i < sisusb->numobufs; i++) {
153 if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
154 return i;
158 return -1;
161 static int
162 sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
164 int i, timeout = 5 * HZ;
166 wait_event_timeout(sisusb->wait_q,
167 ((i = sisusb_outurb_available(sisusb)) >= 0),
168 timeout);
170 return i;
173 static int
174 sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
176 int i;
178 i = sisusb_outurb_available(sisusb);
180 if (i >= 0)
181 sisusb->urbstatus[i] |= SU_URB_ALLOC;
183 return i;
186 static void
187 sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
189 if ((index >= 0) && (index < sisusb->numobufs))
190 sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
193 /* completion callback */
195 static void
196 sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
198 struct sisusb_urb_context *context = urb->context;
199 struct sisusb_usb_data *sisusb;
201 if (!context)
202 return;
204 sisusb = context->sisusb;
206 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
207 return;
209 #ifndef SISUSB_DONTSYNC
210 if (context->actual_length)
211 *(context->actual_length) += urb->actual_length;
212 #endif
214 sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
215 wake_up(&sisusb->wait_q);
218 static int
219 sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
220 int len, int *actual_length, int timeout, unsigned int tflags,
221 dma_addr_t transfer_dma)
223 struct urb *urb = sisusb->sisurbout[index];
224 int retval, byteswritten = 0;
226 /* Set up URB */
227 urb->transfer_flags = 0;
229 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
230 sisusb_bulk_completeout, &sisusb->urbout_context[index]);
232 urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
233 urb->actual_length = 0;
235 if ((urb->transfer_dma = transfer_dma))
236 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
238 /* Set up context */
239 sisusb->urbout_context[index].actual_length = (timeout) ?
240 NULL : actual_length;
242 /* Declare this urb/buffer in use */
243 sisusb->urbstatus[index] |= SU_URB_BUSY;
245 /* Submit URB */
246 retval = usb_submit_urb(urb, GFP_ATOMIC);
248 /* If OK, and if timeout > 0, wait for completion */
249 if ((retval == 0) && timeout) {
250 wait_event_timeout(sisusb->wait_q,
251 (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
252 timeout);
253 if (sisusb->urbstatus[index] & SU_URB_BUSY) {
254 /* URB timed out... kill it and report error */
255 usb_kill_urb(urb);
256 retval = -ETIMEDOUT;
257 } else {
258 /* Otherwise, report urb status */
259 retval = urb->status;
260 byteswritten = urb->actual_length;
264 if (actual_length)
265 *actual_length = byteswritten;
267 return retval;
270 /* 2. in-bulks */
272 /* completion callback */
274 static void
275 sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
277 struct sisusb_usb_data *sisusb = urb->context;
279 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
280 return;
282 sisusb->completein = 1;
283 wake_up(&sisusb->wait_q);
286 static int
287 sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len,
288 int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma)
290 struct urb *urb = sisusb->sisurbin;
291 int retval, readbytes = 0;
293 urb->transfer_flags = 0;
295 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
296 sisusb_bulk_completein, sisusb);
298 urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
299 urb->actual_length = 0;
301 if ((urb->transfer_dma = transfer_dma))
302 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
304 sisusb->completein = 0;
305 retval = usb_submit_urb(urb, GFP_ATOMIC);
306 if (retval == 0) {
307 wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
308 if (!sisusb->completein) {
309 /* URB timed out... kill it and report error */
310 usb_kill_urb(urb);
311 retval = -ETIMEDOUT;
312 } else {
313 /* URB completed within timout */
314 retval = urb->status;
315 readbytes = urb->actual_length;
319 if (actual_length)
320 *actual_length = readbytes;
322 return retval;
326 /* Level 1: */
328 /* Send a bulk message of variable size
330 * To copy the data from userspace, give pointer to "userbuffer",
331 * to copy from (non-DMA) kernel memory, give "kernbuffer". If
332 * both of these are NULL, it is assumed, that the transfer
333 * buffer "sisusb->obuf[index]" is set up with the data to send.
334 * Index is ignored if either kernbuffer or userbuffer is set.
335 * If async is nonzero, URBs will be sent without waiting for
336 * completion of the previous URB.
338 * (return 0 on success)
341 static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
342 char *kernbuffer, const char __user *userbuffer, int index,
343 ssize_t *bytes_written, unsigned int tflags, int async)
345 int result = 0, retry, count = len;
346 int passsize, thispass, transferred_len = 0;
347 int fromuser = (userbuffer != NULL) ? 1 : 0;
348 int fromkern = (kernbuffer != NULL) ? 1 : 0;
349 unsigned int pipe;
350 char *buffer;
352 (*bytes_written) = 0;
354 /* Sanity check */
355 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
356 return -ENODEV;
358 /* If we copy data from kernel or userspace, force the
359 * allocation of a buffer/urb. If we have the data in
360 * the transfer buffer[index] already, reuse the buffer/URB
361 * if the length is > buffer size. (So, transmitting
362 * large data amounts directly from the transfer buffer
363 * treats the buffer as a ring buffer. However, we need
364 * to sync in this case.)
366 if (fromuser || fromkern)
367 index = -1;
368 else if (len > sisusb->obufsize)
369 async = 0;
371 pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
373 do {
374 passsize = thispass = (sisusb->obufsize < count) ?
375 sisusb->obufsize : count;
377 if (index < 0)
378 index = sisusb_get_free_outbuf(sisusb);
380 if (index < 0)
381 return -EIO;
383 buffer = sisusb->obuf[index];
385 if (fromuser) {
387 if (copy_from_user(buffer, userbuffer, passsize))
388 return -EFAULT;
390 userbuffer += passsize;
392 } else if (fromkern) {
394 memcpy(buffer, kernbuffer, passsize);
395 kernbuffer += passsize;
399 retry = 5;
400 while (thispass) {
402 if (!sisusb->sisusb_dev)
403 return -ENODEV;
405 result = sisusb_bulkout_msg(sisusb,
406 index,
407 pipe,
408 buffer,
409 thispass,
410 &transferred_len,
411 async ? 0 : 5 * HZ,
412 tflags,
413 sisusb->transfer_dma_out[index]);
415 if (result == -ETIMEDOUT) {
417 /* Will not happen if async */
418 if (!retry--)
419 return -ETIME;
421 continue;
423 } else if ((result == 0) && !async && transferred_len) {
425 thispass -= transferred_len;
426 if (thispass) {
427 if (sisusb->transfer_dma_out) {
428 /* If DMA, copy remaining
429 * to beginning of buffer
431 memcpy(buffer,
432 buffer + transferred_len,
433 thispass);
434 } else {
435 /* If not DMA, simply increase
436 * the pointer
438 buffer += transferred_len;
442 } else
443 break;
446 if (result)
447 return result;
449 (*bytes_written) += passsize;
450 count -= passsize;
452 /* Force new allocation in next iteration */
453 if (fromuser || fromkern)
454 index = -1;
456 } while (count > 0);
458 if (async) {
459 #ifdef SISUSB_DONTSYNC
460 (*bytes_written) = len;
461 /* Some URBs/buffers might be busy */
462 #else
463 sisusb_wait_all_out_complete(sisusb);
464 (*bytes_written) = transferred_len;
465 /* All URBs and all buffers are available */
466 #endif
469 return ((*bytes_written) == len) ? 0 : -EIO;
472 /* Receive a bulk message of variable size
474 * To copy the data to userspace, give pointer to "userbuffer",
475 * to copy to kernel memory, give "kernbuffer". One of them
476 * MUST be set. (There is no technique for letting the caller
477 * read directly from the ibuf.)
481 static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
482 void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
483 unsigned int tflags)
485 int result = 0, retry, count = len;
486 int bufsize, thispass, transferred_len;
487 unsigned int pipe;
488 char *buffer;
490 (*bytes_read) = 0;
492 /* Sanity check */
493 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
494 return -ENODEV;
496 pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
497 buffer = sisusb->ibuf;
498 bufsize = sisusb->ibufsize;
500 retry = 5;
502 #ifdef SISUSB_DONTSYNC
503 if (!(sisusb_wait_all_out_complete(sisusb)))
504 return -EIO;
505 #endif
507 while (count > 0) {
509 if (!sisusb->sisusb_dev)
510 return -ENODEV;
512 thispass = (bufsize < count) ? bufsize : count;
514 result = sisusb_bulkin_msg(sisusb,
515 pipe,
516 buffer,
517 thispass,
518 &transferred_len,
519 5 * HZ,
520 tflags,
521 sisusb->transfer_dma_in);
523 if (transferred_len)
524 thispass = transferred_len;
526 else if (result == -ETIMEDOUT) {
528 if (!retry--)
529 return -ETIME;
531 continue;
533 } else
534 return -EIO;
537 if (thispass) {
539 (*bytes_read) += thispass;
540 count -= thispass;
542 if (userbuffer) {
544 if (copy_to_user(userbuffer, buffer, thispass))
545 return -EFAULT;
547 userbuffer += thispass;
549 } else {
551 memcpy(kernbuffer, buffer, thispass);
552 kernbuffer += thispass;
560 return ((*bytes_read) == len) ? 0 : -EIO;
563 static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
564 struct sisusb_packet *packet)
566 int ret;
567 ssize_t bytes_transferred = 0;
568 __le32 tmp;
570 if (len == 6)
571 packet->data = 0;
573 #ifdef SISUSB_DONTSYNC
574 if (!(sisusb_wait_all_out_complete(sisusb)))
575 return 1;
576 #endif
578 /* Eventually correct endianness */
579 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
581 /* 1. send the packet */
582 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
583 (char *)packet, NULL, 0, &bytes_transferred, 0, 0);
585 if ((ret == 0) && (len == 6)) {
587 /* 2. if packet len == 6, it means we read, so wait for 32bit
588 * return value and write it to packet->data
590 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
591 (char *)&tmp, NULL, &bytes_transferred, 0);
593 packet->data = le32_to_cpu(tmp);
596 return ret;
599 static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
600 struct sisusb_packet *packet,
601 unsigned int tflags)
603 int ret;
604 ssize_t bytes_transferred = 0;
605 __le32 tmp;
607 if (len == 6)
608 packet->data = 0;
610 #ifdef SISUSB_DONTSYNC
611 if (!(sisusb_wait_all_out_complete(sisusb)))
612 return 1;
613 #endif
615 /* Eventually correct endianness */
616 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
618 /* 1. send the packet */
619 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
620 (char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
622 if ((ret == 0) && (len == 6)) {
624 /* 2. if packet len == 6, it means we read, so wait for 32bit
625 * return value and write it to packet->data
627 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
628 (char *)&tmp, NULL, &bytes_transferred, 0);
630 packet->data = le32_to_cpu(tmp);
633 return ret;
636 /* access video memory and mmio (return 0 on success) */
638 /* Low level */
640 /* The following routines assume being used to transfer byte, word,
641 * long etc.
642 * This means that they assume "data" in machine endianness format.
645 static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
646 u32 addr, u8 data)
648 struct sisusb_packet packet;
649 int ret;
651 packet.header = (1 << (addr & 3)) | (type << 6);
652 packet.address = addr & ~3;
653 packet.data = data << ((addr & 3) << 3);
654 ret = sisusb_send_packet(sisusb, 10, &packet);
655 return ret;
658 static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
659 u32 addr, u16 data)
661 struct sisusb_packet packet;
662 int ret = 0;
664 packet.address = addr & ~3;
666 switch (addr & 3) {
667 case 0:
668 packet.header = (type << 6) | 0x0003;
669 packet.data = (u32)data;
670 ret = sisusb_send_packet(sisusb, 10, &packet);
671 break;
672 case 1:
673 packet.header = (type << 6) | 0x0006;
674 packet.data = (u32)data << 8;
675 ret = sisusb_send_packet(sisusb, 10, &packet);
676 break;
677 case 2:
678 packet.header = (type << 6) | 0x000c;
679 packet.data = (u32)data << 16;
680 ret = sisusb_send_packet(sisusb, 10, &packet);
681 break;
682 case 3:
683 packet.header = (type << 6) | 0x0008;
684 packet.data = (u32)data << 24;
685 ret = sisusb_send_packet(sisusb, 10, &packet);
686 packet.header = (type << 6) | 0x0001;
687 packet.address = (addr & ~3) + 4;
688 packet.data = (u32)data >> 8;
689 ret |= sisusb_send_packet(sisusb, 10, &packet);
692 return ret;
695 static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
696 u32 addr, u32 data)
698 struct sisusb_packet packet;
699 int ret = 0;
701 packet.address = addr & ~3;
703 switch (addr & 3) {
704 case 0:
705 packet.header = (type << 6) | 0x0007;
706 packet.data = data & 0x00ffffff;
707 ret = sisusb_send_packet(sisusb, 10, &packet);
708 break;
709 case 1:
710 packet.header = (type << 6) | 0x000e;
711 packet.data = data << 8;
712 ret = sisusb_send_packet(sisusb, 10, &packet);
713 break;
714 case 2:
715 packet.header = (type << 6) | 0x000c;
716 packet.data = data << 16;
717 ret = sisusb_send_packet(sisusb, 10, &packet);
718 packet.header = (type << 6) | 0x0001;
719 packet.address = (addr & ~3) + 4;
720 packet.data = (data >> 16) & 0x00ff;
721 ret |= sisusb_send_packet(sisusb, 10, &packet);
722 break;
723 case 3:
724 packet.header = (type << 6) | 0x0008;
725 packet.data = data << 24;
726 ret = sisusb_send_packet(sisusb, 10, &packet);
727 packet.header = (type << 6) | 0x0003;
728 packet.address = (addr & ~3) + 4;
729 packet.data = (data >> 8) & 0xffff;
730 ret |= sisusb_send_packet(sisusb, 10, &packet);
733 return ret;
736 static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
737 u32 addr, u32 data)
739 struct sisusb_packet packet;
740 int ret = 0;
742 packet.address = addr & ~3;
744 switch (addr & 3) {
745 case 0:
746 packet.header = (type << 6) | 0x000f;
747 packet.data = data;
748 ret = sisusb_send_packet(sisusb, 10, &packet);
749 break;
750 case 1:
751 packet.header = (type << 6) | 0x000e;
752 packet.data = data << 8;
753 ret = sisusb_send_packet(sisusb, 10, &packet);
754 packet.header = (type << 6) | 0x0001;
755 packet.address = (addr & ~3) + 4;
756 packet.data = data >> 24;
757 ret |= sisusb_send_packet(sisusb, 10, &packet);
758 break;
759 case 2:
760 packet.header = (type << 6) | 0x000c;
761 packet.data = data << 16;
762 ret = sisusb_send_packet(sisusb, 10, &packet);
763 packet.header = (type << 6) | 0x0003;
764 packet.address = (addr & ~3) + 4;
765 packet.data = data >> 16;
766 ret |= sisusb_send_packet(sisusb, 10, &packet);
767 break;
768 case 3:
769 packet.header = (type << 6) | 0x0008;
770 packet.data = data << 24;
771 ret = sisusb_send_packet(sisusb, 10, &packet);
772 packet.header = (type << 6) | 0x0007;
773 packet.address = (addr & ~3) + 4;
774 packet.data = data >> 8;
775 ret |= sisusb_send_packet(sisusb, 10, &packet);
778 return ret;
781 /* The xxx_bulk routines copy a buffer of variable size. They treat the
782 * buffer as chars, therefore lsb/msb has to be corrected if using the
783 * byte/word/long/etc routines for speed-up
785 * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
786 * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
787 * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
788 * that the data already is in the transfer buffer "sisusb->obuf[index]".
791 static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
792 char *kernbuffer, int length,
793 const char __user *userbuffer, int index,
794 ssize_t *bytes_written)
796 struct sisusb_packet packet;
797 int ret = 0;
798 static int msgcount = 0;
799 u8 swap8, fromkern = kernbuffer ? 1 : 0;
800 u16 swap16;
801 u32 swap32, flag = (length >> 28) & 1;
802 char buf[4];
804 /* if neither kernbuffer not userbuffer are given, assume
805 * data in obuf
807 if (!fromkern && !userbuffer)
808 kernbuffer = sisusb->obuf[index];
810 (*bytes_written = 0);
812 length &= 0x00ffffff;
814 while (length) {
816 switch (length) {
818 case 0:
819 return ret;
821 case 1:
822 if (userbuffer) {
823 if (get_user(swap8, (u8 __user *)userbuffer))
824 return -EFAULT;
825 } else
826 swap8 = kernbuffer[0];
828 ret = sisusb_write_memio_byte(sisusb,
829 SISUSB_TYPE_MEM,
830 addr, swap8);
832 if (!ret)
833 (*bytes_written)++;
835 return ret;
837 case 2:
838 if (userbuffer) {
839 if (get_user(swap16, (u16 __user *)userbuffer))
840 return -EFAULT;
841 } else
842 swap16 = (kernbuffer[0] << 8) | kernbuffer[1];
844 ret = sisusb_write_memio_word(sisusb,
845 SISUSB_TYPE_MEM,
846 addr,
847 swap16);
849 if (!ret)
850 (*bytes_written) += 2;
852 return ret;
854 case 3:
855 if (userbuffer) {
856 if (copy_from_user(&buf, userbuffer, 3))
857 return -EFAULT;
859 swap32 = (buf[0] << 16) |
860 (buf[1] << 8) |
861 buf[2];
862 } else
863 swap32 = (kernbuffer[0] << 16) |
864 (kernbuffer[1] << 8) |
865 kernbuffer[2];
867 ret = sisusb_write_memio_24bit(sisusb,
868 SISUSB_TYPE_MEM,
869 addr,
870 swap32);
872 if (!ret)
873 (*bytes_written) += 3;
875 return ret;
877 case 4:
878 if (userbuffer) {
879 if (get_user(swap32, (u32 __user *)userbuffer))
880 return -EFAULT;
881 } else
882 swap32 = (kernbuffer[0] << 24) |
883 (kernbuffer[1] << 16) |
884 (kernbuffer[2] << 8) |
885 kernbuffer[3];
887 ret = sisusb_write_memio_long(sisusb,
888 SISUSB_TYPE_MEM,
889 addr,
890 swap32);
891 if (!ret)
892 (*bytes_written) += 4;
894 return ret;
896 default:
897 if ((length & ~3) > 0x10000) {
899 packet.header = 0x001f;
900 packet.address = 0x000001d4;
901 packet.data = addr;
902 ret = sisusb_send_bridge_packet(sisusb, 10,
903 &packet, 0);
904 packet.header = 0x001f;
905 packet.address = 0x000001d0;
906 packet.data = (length & ~3);
907 ret |= sisusb_send_bridge_packet(sisusb, 10,
908 &packet, 0);
909 packet.header = 0x001f;
910 packet.address = 0x000001c0;
911 packet.data = flag | 0x16;
912 ret |= sisusb_send_bridge_packet(sisusb, 10,
913 &packet, 0);
914 if (userbuffer) {
915 ret |= sisusb_send_bulk_msg(sisusb,
916 SISUSB_EP_GFX_LBULK_OUT,
917 (length & ~3),
918 NULL, userbuffer, 0,
919 bytes_written, 0, 1);
920 userbuffer += (*bytes_written);
921 } else if (fromkern) {
922 ret |= sisusb_send_bulk_msg(sisusb,
923 SISUSB_EP_GFX_LBULK_OUT,
924 (length & ~3),
925 kernbuffer, NULL, 0,
926 bytes_written, 0, 1);
927 kernbuffer += (*bytes_written);
928 } else {
929 ret |= sisusb_send_bulk_msg(sisusb,
930 SISUSB_EP_GFX_LBULK_OUT,
931 (length & ~3),
932 NULL, NULL, index,
933 bytes_written, 0, 1);
934 kernbuffer += ((*bytes_written) &
935 (sisusb->obufsize-1));
938 } else {
940 packet.header = 0x001f;
941 packet.address = 0x00000194;
942 packet.data = addr;
943 ret = sisusb_send_bridge_packet(sisusb, 10,
944 &packet, 0);
945 packet.header = 0x001f;
946 packet.address = 0x00000190;
947 packet.data = (length & ~3);
948 ret |= sisusb_send_bridge_packet(sisusb, 10,
949 &packet, 0);
950 if (sisusb->flagb0 != 0x16) {
951 packet.header = 0x001f;
952 packet.address = 0x00000180;
953 packet.data = flag | 0x16;
954 ret |= sisusb_send_bridge_packet(sisusb, 10,
955 &packet, 0);
956 sisusb->flagb0 = 0x16;
958 if (userbuffer) {
959 ret |= sisusb_send_bulk_msg(sisusb,
960 SISUSB_EP_GFX_BULK_OUT,
961 (length & ~3),
962 NULL, userbuffer, 0,
963 bytes_written, 0, 1);
964 userbuffer += (*bytes_written);
965 } else if (fromkern) {
966 ret |= sisusb_send_bulk_msg(sisusb,
967 SISUSB_EP_GFX_BULK_OUT,
968 (length & ~3),
969 kernbuffer, NULL, 0,
970 bytes_written, 0, 1);
971 kernbuffer += (*bytes_written);
972 } else {
973 ret |= sisusb_send_bulk_msg(sisusb,
974 SISUSB_EP_GFX_BULK_OUT,
975 (length & ~3),
976 NULL, NULL, index,
977 bytes_written, 0, 1);
978 kernbuffer += ((*bytes_written) &
979 (sisusb->obufsize-1));
982 if (ret) {
983 msgcount++;
984 if (msgcount < 500)
985 printk(KERN_ERR
986 "sisusbvga[%d]: Wrote %Zd of "
987 "%d bytes, error %d\n",
988 sisusb->minor, *bytes_written,
989 length, ret);
990 else if (msgcount == 500)
991 printk(KERN_ERR
992 "sisusbvga[%d]: Too many errors"
993 ", logging stopped\n",
994 sisusb->minor);
996 addr += (*bytes_written);
997 length -= (*bytes_written);
1000 if (ret)
1001 break;
1005 return ret ? -EIO : 0;
1008 static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1009 u32 addr, u8 *data)
1011 struct sisusb_packet packet;
1012 int ret;
1014 CLEARPACKET(&packet);
1015 packet.header = (1 << (addr & 3)) | (type << 6);
1016 packet.address = addr & ~3;
1017 ret = sisusb_send_packet(sisusb, 6, &packet);
1018 *data = (u8)(packet.data >> ((addr & 3) << 3));
1019 return ret;
1022 static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1023 u32 addr, u16 *data)
1025 struct sisusb_packet packet;
1026 int ret = 0;
1028 CLEARPACKET(&packet);
1030 packet.address = addr & ~3;
1032 switch (addr & 3) {
1033 case 0:
1034 packet.header = (type << 6) | 0x0003;
1035 ret = sisusb_send_packet(sisusb, 6, &packet);
1036 *data = (u16)(packet.data);
1037 break;
1038 case 1:
1039 packet.header = (type << 6) | 0x0006;
1040 ret = sisusb_send_packet(sisusb, 6, &packet);
1041 *data = (u16)(packet.data >> 8);
1042 break;
1043 case 2:
1044 packet.header = (type << 6) | 0x000c;
1045 ret = sisusb_send_packet(sisusb, 6, &packet);
1046 *data = (u16)(packet.data >> 16);
1047 break;
1048 case 3:
1049 packet.header = (type << 6) | 0x0008;
1050 ret = sisusb_send_packet(sisusb, 6, &packet);
1051 *data = (u16)(packet.data >> 24);
1052 packet.header = (type << 6) | 0x0001;
1053 packet.address = (addr & ~3) + 4;
1054 ret |= sisusb_send_packet(sisusb, 6, &packet);
1055 *data |= (u16)(packet.data << 8);
1058 return ret;
1061 static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1062 u32 addr, u32 *data)
1064 struct sisusb_packet packet;
1065 int ret = 0;
1067 packet.address = addr & ~3;
1069 switch (addr & 3) {
1070 case 0:
1071 packet.header = (type << 6) | 0x0007;
1072 ret = sisusb_send_packet(sisusb, 6, &packet);
1073 *data = packet.data & 0x00ffffff;
1074 break;
1075 case 1:
1076 packet.header = (type << 6) | 0x000e;
1077 ret = sisusb_send_packet(sisusb, 6, &packet);
1078 *data = packet.data >> 8;
1079 break;
1080 case 2:
1081 packet.header = (type << 6) | 0x000c;
1082 ret = sisusb_send_packet(sisusb, 6, &packet);
1083 *data = packet.data >> 16;
1084 packet.header = (type << 6) | 0x0001;
1085 packet.address = (addr & ~3) + 4;
1086 ret |= sisusb_send_packet(sisusb, 6, &packet);
1087 *data |= ((packet.data & 0xff) << 16);
1088 break;
1089 case 3:
1090 packet.header = (type << 6) | 0x0008;
1091 ret = sisusb_send_packet(sisusb, 6, &packet);
1092 *data = packet.data >> 24;
1093 packet.header = (type << 6) | 0x0003;
1094 packet.address = (addr & ~3) + 4;
1095 ret |= sisusb_send_packet(sisusb, 6, &packet);
1096 *data |= ((packet.data & 0xffff) << 8);
1099 return ret;
1102 static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1103 u32 addr, u32 *data)
1105 struct sisusb_packet packet;
1106 int ret = 0;
1108 packet.address = addr & ~3;
1110 switch (addr & 3) {
1111 case 0:
1112 packet.header = (type << 6) | 0x000f;
1113 ret = sisusb_send_packet(sisusb, 6, &packet);
1114 *data = packet.data;
1115 break;
1116 case 1:
1117 packet.header = (type << 6) | 0x000e;
1118 ret = sisusb_send_packet(sisusb, 6, &packet);
1119 *data = packet.data >> 8;
1120 packet.header = (type << 6) | 0x0001;
1121 packet.address = (addr & ~3) + 4;
1122 ret |= sisusb_send_packet(sisusb, 6, &packet);
1123 *data |= (packet.data << 24);
1124 break;
1125 case 2:
1126 packet.header = (type << 6) | 0x000c;
1127 ret = sisusb_send_packet(sisusb, 6, &packet);
1128 *data = packet.data >> 16;
1129 packet.header = (type << 6) | 0x0003;
1130 packet.address = (addr & ~3) + 4;
1131 ret |= sisusb_send_packet(sisusb, 6, &packet);
1132 *data |= (packet.data << 16);
1133 break;
1134 case 3:
1135 packet.header = (type << 6) | 0x0008;
1136 ret = sisusb_send_packet(sisusb, 6, &packet);
1137 *data = packet.data >> 24;
1138 packet.header = (type << 6) | 0x0007;
1139 packet.address = (addr & ~3) + 4;
1140 ret |= sisusb_send_packet(sisusb, 6, &packet);
1141 *data |= (packet.data << 8);
1144 return ret;
1147 static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1148 char *kernbuffer, int length,
1149 char __user *userbuffer, ssize_t *bytes_read)
1151 int ret = 0;
1152 char buf[4];
1153 u16 swap16;
1154 u32 swap32;
1156 (*bytes_read = 0);
1158 length &= 0x00ffffff;
1160 while (length) {
1162 switch (length) {
1164 case 0:
1165 return ret;
1167 case 1:
1169 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1170 addr, &buf[0]);
1171 if (!ret) {
1172 (*bytes_read)++;
1173 if (userbuffer) {
1174 if (put_user(buf[0],
1175 (u8 __user *)userbuffer)) {
1176 return -EFAULT;
1178 } else {
1179 kernbuffer[0] = buf[0];
1182 return ret;
1184 case 2:
1185 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1186 addr, &swap16);
1187 if (!ret) {
1188 (*bytes_read) += 2;
1189 if (userbuffer) {
1190 if (put_user(swap16,
1191 (u16 __user *)userbuffer))
1192 return -EFAULT;
1193 } else {
1194 kernbuffer[0] = swap16 >> 8;
1195 kernbuffer[1] = swap16 & 0xff;
1198 return ret;
1200 case 3:
1201 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1202 addr, &swap32);
1203 if (!ret) {
1204 (*bytes_read) += 3;
1205 buf[0] = (swap32 >> 16) & 0xff;
1206 buf[1] = (swap32 >> 8) & 0xff;
1207 buf[2] = swap32 & 0xff;
1208 if (userbuffer) {
1209 if (copy_to_user(userbuffer, &buf[0], 3))
1210 return -EFAULT;
1211 } else {
1212 kernbuffer[0] = buf[0];
1213 kernbuffer[1] = buf[1];
1214 kernbuffer[2] = buf[2];
1217 return ret;
1219 default:
1220 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1221 addr, &swap32);
1222 if (!ret) {
1223 (*bytes_read) += 4;
1224 if (userbuffer) {
1225 if (put_user(swap32,
1226 (u32 __user *)userbuffer))
1227 return -EFAULT;
1229 userbuffer += 4;
1230 } else {
1231 kernbuffer[0] = (swap32 >> 24) & 0xff;
1232 kernbuffer[1] = (swap32 >> 16) & 0xff;
1233 kernbuffer[2] = (swap32 >> 8) & 0xff;
1234 kernbuffer[3] = swap32 & 0xff;
1235 kernbuffer += 4;
1237 addr += 4;
1238 length -= 4;
1240 #if 0 /* That does not work, as EP 2 is an OUT EP! */
1241 default:
1242 CLEARPACKET(&packet);
1243 packet.header = 0x001f;
1244 packet.address = 0x000001a0;
1245 packet.data = 0x00000006;
1246 ret |= sisusb_send_bridge_packet(sisusb, 10,
1247 &packet, 0);
1248 packet.header = 0x001f;
1249 packet.address = 0x000001b0;
1250 packet.data = (length & ~3) | 0x40000000;
1251 ret |= sisusb_send_bridge_packet(sisusb, 10,
1252 &packet, 0);
1253 packet.header = 0x001f;
1254 packet.address = 0x000001b4;
1255 packet.data = addr;
1256 ret |= sisusb_send_bridge_packet(sisusb, 10,
1257 &packet, 0);
1258 packet.header = 0x001f;
1259 packet.address = 0x000001a4;
1260 packet.data = 0x00000001;
1261 ret |= sisusb_send_bridge_packet(sisusb, 10,
1262 &packet, 0);
1263 if (userbuffer) {
1264 ret |= sisusb_recv_bulk_msg(sisusb,
1265 SISUSB_EP_GFX_BULK_IN,
1266 (length & ~3),
1267 NULL, userbuffer,
1268 bytes_read, 0);
1269 if (!ret) userbuffer += (*bytes_read);
1270 } else {
1271 ret |= sisusb_recv_bulk_msg(sisusb,
1272 SISUSB_EP_GFX_BULK_IN,
1273 (length & ~3),
1274 kernbuffer, NULL,
1275 bytes_read, 0);
1276 if (!ret) kernbuffer += (*bytes_read);
1278 addr += (*bytes_read);
1279 length -= (*bytes_read);
1280 #endif
1283 if (ret)
1284 break;
1287 return ret;
1290 /* High level: Gfx (indexed) register access */
1292 static int
1293 sisusb_setidxreg(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_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1298 return ret;
1301 static int
1302 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1304 int ret;
1305 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1306 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1307 return ret;
1310 static int
1311 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1312 u8 myand, u8 myor)
1314 int ret;
1315 u8 tmp;
1317 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1318 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1319 tmp &= myand;
1320 tmp |= myor;
1321 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1322 return ret;
1325 static int
1326 sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1327 u8 data, u8 mask)
1329 int ret;
1330 u8 tmp;
1331 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1332 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1333 tmp &= ~(mask);
1334 tmp |= (data & mask);
1335 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1336 return ret;
1339 static int
1340 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1342 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1345 static int
1346 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1348 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1351 /* access pci config registers (reg numbers 0, 4, 8, etc) */
1353 static int
1354 sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1356 struct sisusb_packet packet;
1357 int ret;
1359 packet.header = 0x008f;
1360 packet.address = regnum | 0x10000;
1361 packet.data = data;
1362 ret = sisusb_send_packet(sisusb, 10, &packet);
1363 return ret;
1366 static int
1367 sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1369 struct sisusb_packet packet;
1370 int ret;
1372 packet.header = 0x008f;
1373 packet.address = (u32)regnum | 0x10000;
1374 ret = sisusb_send_packet(sisusb, 6, &packet);
1375 *data = packet.data;
1376 return ret;
1379 /* Clear video RAM */
1381 static int
1382 sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1384 int ret, i;
1385 ssize_t j;
1387 if (address < sisusb->vrambase)
1388 return 1;
1390 if (address >= sisusb->vrambase + sisusb->vramsize)
1391 return 1;
1393 if (address + length > sisusb->vrambase + sisusb->vramsize)
1394 length = sisusb->vrambase + sisusb->vramsize - address;
1396 if (length <= 0)
1397 return 0;
1399 /* allocate free buffer/urb and clear the buffer */
1400 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1401 return -EBUSY;
1403 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1405 /* We can write a length > buffer size here. The buffer
1406 * data will simply be re-used (like a ring-buffer).
1408 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1410 /* Free the buffer/urb */
1411 sisusb_free_outbuf(sisusb, i);
1413 return ret;
1416 /* Initialize the graphics core (return 0 on success)
1417 * This resets the graphics hardware and puts it into
1418 * a defined mode (640x480@60Hz)
1421 #define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1422 #define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1423 #define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
1424 #define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
1425 #define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
1426 #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
1427 #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
1428 #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1429 #define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1430 #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1431 #define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1433 static int
1434 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1436 int ret;
1437 u8 tmp8;
1439 ret = GETIREG(SISSR, 0x16, &tmp8);
1440 if (ramtype <= 1) {
1441 tmp8 &= 0x3f;
1442 ret |= SETIREG(SISSR, 0x16, tmp8);
1443 tmp8 |= 0x80;
1444 ret |= SETIREG(SISSR, 0x16, tmp8);
1445 } else {
1446 tmp8 |= 0xc0;
1447 ret |= SETIREG(SISSR, 0x16, tmp8);
1448 tmp8 &= 0x0f;
1449 ret |= SETIREG(SISSR, 0x16, tmp8);
1450 tmp8 |= 0x80;
1451 ret |= SETIREG(SISSR, 0x16, tmp8);
1452 tmp8 &= 0x0f;
1453 ret |= SETIREG(SISSR, 0x16, tmp8);
1454 tmp8 |= 0xd0;
1455 ret |= SETIREG(SISSR, 0x16, tmp8);
1456 tmp8 &= 0x0f;
1457 ret |= SETIREG(SISSR, 0x16, tmp8);
1458 tmp8 |= 0xa0;
1459 ret |= SETIREG(SISSR, 0x16, tmp8);
1461 return ret;
1464 static int
1465 sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1467 int ret;
1468 u8 ramtype, done = 0;
1469 u32 t0, t1, t2, t3;
1470 u32 ramptr = SISUSB_PCI_MEMBASE;
1472 ret = GETIREG(SISSR, 0x3a, &ramtype);
1473 ramtype &= 3;
1475 ret |= SETIREG(SISSR, 0x13, 0x00);
1477 if (ramtype <= 1) {
1478 ret |= SETIREG(SISSR, 0x14, 0x12);
1479 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1480 } else {
1481 ret |= SETIREG(SISSR, 0x14, 0x02);
1484 ret |= sisusb_triggersr16(sisusb, ramtype);
1485 ret |= WRITEL(ramptr + 0, 0x01234567);
1486 ret |= WRITEL(ramptr + 4, 0x456789ab);
1487 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1488 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1489 ret |= WRITEL(ramptr + 16, 0x55555555);
1490 ret |= WRITEL(ramptr + 20, 0x55555555);
1491 ret |= WRITEL(ramptr + 24, 0xffffffff);
1492 ret |= WRITEL(ramptr + 28, 0xffffffff);
1493 ret |= READL(ramptr + 0, &t0);
1494 ret |= READL(ramptr + 4, &t1);
1495 ret |= READL(ramptr + 8, &t2);
1496 ret |= READL(ramptr + 12, &t3);
1498 if (ramtype <= 1) {
1500 *chab = 0; *bw = 64;
1502 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1503 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1504 *chab = 0; *bw = 64;
1505 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1508 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1509 *chab = 1; *bw = 64;
1510 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1512 ret |= sisusb_triggersr16(sisusb, ramtype);
1513 ret |= WRITEL(ramptr + 0, 0x89abcdef);
1514 ret |= WRITEL(ramptr + 4, 0xcdef0123);
1515 ret |= WRITEL(ramptr + 8, 0x55555555);
1516 ret |= WRITEL(ramptr + 12, 0x55555555);
1517 ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1518 ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1519 ret |= READL(ramptr + 4, &t1);
1521 if (t1 != 0xcdef0123) {
1522 *bw = 32;
1523 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1527 } else {
1529 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1531 done = 0;
1533 if (t1 == 0x456789ab) {
1534 if (t0 == 0x01234567) {
1535 *chab = 0; *bw = 64;
1536 done = 1;
1538 } else {
1539 if (t0 == 0x01234567) {
1540 *chab = 0; *bw = 32;
1541 ret |= SETIREG(SISSR, 0x14, 0x00);
1542 done = 1;
1546 if (!done) {
1547 ret |= SETIREG(SISSR, 0x14, 0x03);
1548 ret |= sisusb_triggersr16(sisusb, ramtype);
1550 ret |= WRITEL(ramptr + 0, 0x01234567);
1551 ret |= WRITEL(ramptr + 4, 0x456789ab);
1552 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1553 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1554 ret |= WRITEL(ramptr + 16, 0x55555555);
1555 ret |= WRITEL(ramptr + 20, 0x55555555);
1556 ret |= WRITEL(ramptr + 24, 0xffffffff);
1557 ret |= WRITEL(ramptr + 28, 0xffffffff);
1558 ret |= READL(ramptr + 0, &t0);
1559 ret |= READL(ramptr + 4, &t1);
1561 if (t1 == 0x456789ab) {
1562 if (t0 == 0x01234567) {
1563 *chab = 1; *bw = 64;
1564 return ret;
1565 } /* else error */
1566 } else {
1567 if (t0 == 0x01234567) {
1568 *chab = 1; *bw = 32;
1569 ret |= SETIREG(SISSR, 0x14, 0x01);
1570 } /* else error */
1574 return ret;
1577 static int
1578 sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1580 int ret = 0;
1581 u32 ramptr = SISUSB_PCI_MEMBASE;
1582 u8 tmp1, tmp2, i, j;
1584 ret |= WRITEB(ramptr, 0xaa);
1585 ret |= WRITEB(ramptr + 16, 0x55);
1586 ret |= READB(ramptr, &tmp1);
1587 ret |= READB(ramptr + 16, &tmp2);
1588 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1589 for (i = 0, j = 16; i < 2; i++, j += 16) {
1590 ret |= GETIREG(SISSR, 0x21, &tmp1);
1591 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1592 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1593 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1594 ret |= SETIREG(SISSR, 0x21, tmp1);
1595 ret |= WRITEB(ramptr + 16 + j, j);
1596 ret |= READB(ramptr + 16 + j, &tmp1);
1597 if (tmp1 == j) {
1598 ret |= WRITEB(ramptr + j, j);
1599 break;
1603 return ret;
1606 static int
1607 sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1608 u8 rankno, u8 chab, const u8 dramtype[][5],
1609 int bw)
1611 int ret = 0, ranksize;
1612 u8 tmp;
1614 *iret = 0;
1616 if ((rankno == 2) && (dramtype[index][0] == 2))
1617 return ret;
1619 ranksize = dramtype[index][3] / 2 * bw / 32;
1621 if ((ranksize * rankno) > 128)
1622 return ret;
1624 tmp = 0;
1625 while ((ranksize >>= 1) > 0) tmp += 0x10;
1626 tmp |= ((rankno - 1) << 2);
1627 tmp |= ((bw / 64) & 0x02);
1628 tmp |= (chab & 0x01);
1630 ret = SETIREG(SISSR, 0x14, tmp);
1631 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1633 *iret = 1;
1635 return ret;
1638 static int
1639 sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1641 int ret = 0, i;
1642 u32 j, tmp;
1644 *iret = 0;
1646 for (i = 0, j = 0; i < testn; i++) {
1647 ret |= WRITEL(sisusb->vrambase + j, j);
1648 j += inc;
1651 for (i = 0, j = 0; i < testn; i++) {
1652 ret |= READL(sisusb->vrambase + j, &tmp);
1653 if (tmp != j) return ret;
1654 j += inc;
1657 *iret = 1;
1658 return ret;
1661 static int
1662 sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1663 int idx, int bw, const u8 rtype[][5])
1665 int ret = 0, i, i2ret;
1666 u32 inc;
1668 *iret = 0;
1670 for (i = rankno; i >= 1; i--) {
1671 inc = 1 << (rtype[idx][2] +
1672 rtype[idx][1] +
1673 rtype[idx][0] +
1674 bw / 64 + i);
1675 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1676 if (!i2ret)
1677 return ret;
1680 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1681 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1682 if (!i2ret)
1683 return ret;
1685 inc = 1 << (10 + bw / 64);
1686 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1687 if (!i2ret)
1688 return ret;
1690 *iret = 1;
1691 return ret;
1694 static int
1695 sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1696 int chab)
1698 int ret = 0, i2ret = 0, i, j;
1699 static const u8 sdramtype[13][5] = {
1700 { 2, 12, 9, 64, 0x35 },
1701 { 1, 13, 9, 64, 0x44 },
1702 { 2, 12, 8, 32, 0x31 },
1703 { 2, 11, 9, 32, 0x25 },
1704 { 1, 12, 9, 32, 0x34 },
1705 { 1, 13, 8, 32, 0x40 },
1706 { 2, 11, 8, 16, 0x21 },
1707 { 1, 12, 8, 16, 0x30 },
1708 { 1, 11, 9, 16, 0x24 },
1709 { 1, 11, 8, 8, 0x20 },
1710 { 2, 9, 8, 4, 0x01 },
1711 { 1, 10, 8, 4, 0x10 },
1712 { 1, 9, 8, 2, 0x00 }
1715 *iret = 1; /* error */
1717 for (i = 0; i < 13; i++) {
1718 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1719 for (j = 2; j > 0; j--) {
1720 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1721 chab, sdramtype, bw);
1722 if (!i2ret)
1723 continue;
1725 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1726 bw, sdramtype);
1727 if (i2ret) {
1728 *iret = 0; /* ram size found */
1729 return ret;
1734 return ret;
1737 static int
1738 sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1740 int ret = 0;
1741 u32 address;
1742 int i, length, modex, modey, bpp;
1744 modex = 640; modey = 480; bpp = 2;
1746 address = sisusb->vrambase; /* Clear video ram */
1748 if (clrall)
1749 length = sisusb->vramsize;
1750 else
1751 length = modex * bpp * modey;
1753 ret = sisusb_clear_vram(sisusb, address, length);
1755 if (!ret && drwfr) {
1756 for (i = 0; i < modex; i++) {
1757 address = sisusb->vrambase + (i * bpp);
1758 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1759 address, 0xf100);
1760 address += (modex * (modey-1) * bpp);
1761 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1762 address, 0xf100);
1764 for (i = 0; i < modey; i++) {
1765 address = sisusb->vrambase + ((i * modex) * bpp);
1766 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1767 address, 0xf100);
1768 address += ((modex - 1) * bpp);
1769 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1770 address, 0xf100);
1774 return ret;
1777 static int
1778 sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1780 int ret = 0, i, j, modex, modey, bpp, du;
1781 u8 sr31, cr63, tmp8;
1782 static const char attrdata[] = {
1783 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1784 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1785 0x01,0x00,0x00,0x00
1787 static const char crtcrdata[] = {
1788 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1789 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1790 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1791 0xff
1793 static const char grcdata[] = {
1794 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1795 0xff
1797 static const char crtcdata[] = {
1798 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1799 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1800 0x00
1803 modex = 640; modey = 480; bpp = 2;
1805 GETIREG(SISSR, 0x31, &sr31);
1806 GETIREG(SISCR, 0x63, &cr63);
1807 SETIREGOR(SISSR, 0x01, 0x20);
1808 SETIREG(SISCR, 0x63, cr63 & 0xbf);
1809 SETIREGOR(SISCR, 0x17, 0x80);
1810 SETIREGOR(SISSR, 0x1f, 0x04);
1811 SETIREGAND(SISSR, 0x07, 0xfb);
1812 SETIREG(SISSR, 0x00, 0x03); /* seq */
1813 SETIREG(SISSR, 0x01, 0x21);
1814 SETIREG(SISSR, 0x02, 0x0f);
1815 SETIREG(SISSR, 0x03, 0x00);
1816 SETIREG(SISSR, 0x04, 0x0e);
1817 SETREG(SISMISCW, 0x23); /* misc */
1818 for (i = 0; i <= 0x18; i++) { /* crtc */
1819 SETIREG(SISCR, i, crtcrdata[i]);
1821 for (i = 0; i <= 0x13; i++) { /* att */
1822 GETREG(SISINPSTAT, &tmp8);
1823 SETREG(SISAR, i);
1824 SETREG(SISAR, attrdata[i]);
1826 GETREG(SISINPSTAT, &tmp8);
1827 SETREG(SISAR, 0x14);
1828 SETREG(SISAR, 0x00);
1829 GETREG(SISINPSTAT, &tmp8);
1830 SETREG(SISAR, 0x20);
1831 GETREG(SISINPSTAT, &tmp8);
1832 for (i = 0; i <= 0x08; i++) { /* grc */
1833 SETIREG(SISGR, i, grcdata[i]);
1835 SETIREGAND(SISGR, 0x05, 0xbf);
1836 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1837 SETIREG(SISSR, i, 0x00);
1839 SETIREGAND(SISSR, 0x37, 0xfe);
1840 SETREG(SISMISCW, 0xef); /* sync */
1841 SETIREG(SISCR, 0x11, 0x00); /* crtc */
1842 for (j = 0x00, i = 0; i <= 7; i++, j++) {
1843 SETIREG(SISCR, j, crtcdata[i]);
1845 for (j = 0x10; i <= 10; i++, j++) {
1846 SETIREG(SISCR, j, crtcdata[i]);
1848 for (j = 0x15; i <= 12; i++, j++) {
1849 SETIREG(SISCR, j, crtcdata[i]);
1851 for (j = 0x0A; i <= 15; i++, j++) {
1852 SETIREG(SISSR, j, crtcdata[i]);
1854 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
1855 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
1856 SETIREG(SISCR, 0x14, 0x4f);
1857 du = (modex / 16) * (bpp * 2); /* offset/pitch */
1858 if (modex % 16) du += bpp;
1859 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
1860 SETIREG(SISCR, 0x13, (du & 0xff));
1861 du <<= 5;
1862 tmp8 = du >> 8;
1863 if (du & 0xff) tmp8++;
1864 SETIREG(SISSR, 0x10, tmp8);
1865 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
1866 SETIREG(SISSR, 0x2b, 0x1b);
1867 SETIREG(SISSR, 0x2c, 0xe1);
1868 SETIREG(SISSR, 0x2d, 0x01);
1869 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
1870 SETIREG(SISSR, 0x08, 0xae);
1871 SETIREGAND(SISSR, 0x09, 0xf0);
1872 SETIREG(SISSR, 0x08, 0x34);
1873 SETIREGOR(SISSR, 0x3d, 0x01);
1874 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
1875 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
1876 SETIREG(SISCR, 0x19, 0x00);
1877 SETIREGAND(SISCR, 0x1a, 0xfc);
1878 SETIREGAND(SISSR, 0x0f, 0xb7);
1879 SETIREGAND(SISSR, 0x31, 0xfb);
1880 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
1881 SETIREGAND(SISSR, 0x32, 0xf3);
1882 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
1883 SETIREG(SISCR, 0x52, 0x6c);
1885 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
1886 SETIREG(SISCR, 0x0c, 0x00);
1887 SETIREG(SISSR, 0x0d, 0x00);
1888 SETIREGAND(SISSR, 0x37, 0xfe);
1890 SETIREG(SISCR, 0x32, 0x20);
1891 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
1892 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
1893 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
1895 if (touchengines) {
1896 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
1897 SETIREGOR(SISSR, 0x1e, 0x5a);
1899 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
1900 SETIREG(SISSR, 0x27, 0x1f);
1901 SETIREG(SISSR, 0x26, 0x00);
1904 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
1906 return ret;
1909 static int
1910 sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
1912 int ret = 0, i, j, bw, chab, iret, retry = 3;
1913 u8 tmp8, ramtype;
1914 u32 tmp32;
1915 static const char mclktable[] = {
1916 0x3b, 0x22, 0x01, 143,
1917 0x3b, 0x22, 0x01, 143,
1918 0x3b, 0x22, 0x01, 143,
1919 0x3b, 0x22, 0x01, 143
1921 static const char eclktable[] = {
1922 0x3b, 0x22, 0x01, 143,
1923 0x3b, 0x22, 0x01, 143,
1924 0x3b, 0x22, 0x01, 143,
1925 0x3b, 0x22, 0x01, 143
1927 static const char ramtypetable1[] = {
1928 0x00, 0x04, 0x60, 0x60,
1929 0x0f, 0x0f, 0x1f, 0x1f,
1930 0xba, 0xba, 0xba, 0xba,
1931 0xa9, 0xa9, 0xac, 0xac,
1932 0xa0, 0xa0, 0xa0, 0xa8,
1933 0x00, 0x00, 0x02, 0x02,
1934 0x30, 0x30, 0x40, 0x40
1936 static const char ramtypetable2[] = {
1937 0x77, 0x77, 0x44, 0x44,
1938 0x77, 0x77, 0x44, 0x44,
1939 0x00, 0x00, 0x00, 0x00,
1940 0x5b, 0x5b, 0xab, 0xab,
1941 0x00, 0x00, 0xf0, 0xf8
1944 while (retry--) {
1946 /* Enable VGA */
1947 ret = GETREG(SISVGAEN, &tmp8);
1948 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
1950 /* Enable GPU access to VRAM */
1951 ret |= GETREG(SISMISCR, &tmp8);
1952 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
1954 if (ret) continue;
1956 /* Reset registers */
1957 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
1958 ret |= SETIREG(SISSR, 0x05, 0x86);
1959 ret |= SETIREGOR(SISSR, 0x20, 0x01);
1961 ret |= SETREG(SISMISCW, 0x67);
1963 for (i = 0x06; i <= 0x1f; i++) {
1964 ret |= SETIREG(SISSR, i, 0x00);
1966 for (i = 0x21; i <= 0x27; i++) {
1967 ret |= SETIREG(SISSR, i, 0x00);
1969 for (i = 0x31; i <= 0x3d; i++) {
1970 ret |= SETIREG(SISSR, i, 0x00);
1972 for (i = 0x12; i <= 0x1b; i++) {
1973 ret |= SETIREG(SISSR, i, 0x00);
1975 for (i = 0x79; i <= 0x7c; i++) {
1976 ret |= SETIREG(SISCR, i, 0x00);
1979 if (ret) continue;
1981 ret |= SETIREG(SISCR, 0x63, 0x80);
1983 ret |= GETIREG(SISSR, 0x3a, &ramtype);
1984 ramtype &= 0x03;
1986 ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
1987 ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
1988 ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
1990 ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
1991 ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
1992 ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
1994 ret |= SETIREG(SISSR, 0x07, 0x18);
1995 ret |= SETIREG(SISSR, 0x11, 0x0f);
1997 if (ret) continue;
1999 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2000 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2002 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2003 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2006 ret |= SETIREG(SISCR, 0x49, 0xaa);
2008 ret |= SETIREG(SISSR, 0x1f, 0x00);
2009 ret |= SETIREG(SISSR, 0x20, 0xa0);
2010 ret |= SETIREG(SISSR, 0x23, 0xf6);
2011 ret |= SETIREG(SISSR, 0x24, 0x0d);
2012 ret |= SETIREG(SISSR, 0x25, 0x33);
2014 ret |= SETIREG(SISSR, 0x11, 0x0f);
2016 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2018 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2020 if (ret) continue;
2022 ret |= SETIREG(SISPART1, 0x00, 0x00);
2024 ret |= GETIREG(SISSR, 0x13, &tmp8);
2025 tmp8 >>= 4;
2027 ret |= SETIREG(SISPART1, 0x02, 0x00);
2028 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2030 ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
2031 tmp32 &= 0x00f00000;
2032 tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
2033 ret |= SETIREG(SISSR, 0x25, tmp8);
2034 tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
2035 ret |= SETIREG(SISCR, 0x49, tmp8);
2037 ret |= SETIREG(SISSR, 0x27, 0x1f);
2038 ret |= SETIREG(SISSR, 0x31, 0x00);
2039 ret |= SETIREG(SISSR, 0x32, 0x11);
2040 ret |= SETIREG(SISSR, 0x33, 0x00);
2042 if (ret) continue;
2044 ret |= SETIREG(SISCR, 0x83, 0x00);
2046 ret |= sisusb_set_default_mode(sisusb, 0);
2048 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2049 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2050 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2052 ret |= sisusb_triggersr16(sisusb, ramtype);
2054 /* Disable refresh */
2055 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2056 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2058 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2059 ret |= sisusb_verify_mclk(sisusb);
2061 if (ramtype <= 1) {
2062 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2063 if (iret) {
2064 printk(KERN_ERR "sisusbvga[%d]: RAM size "
2065 "detection failed, "
2066 "assuming 8MB video RAM\n",
2067 sisusb->minor);
2068 ret |= SETIREG(SISSR,0x14,0x31);
2069 /* TODO */
2071 } else {
2072 printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
2073 "assuming 8MB video RAM\n",
2074 sisusb->minor);
2075 ret |= SETIREG(SISSR,0x14,0x31);
2076 /* *** TODO *** */
2079 /* Enable refresh */
2080 ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
2081 ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
2082 ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
2084 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2086 ret |= SETIREG(SISSR, 0x22, 0xfb);
2087 ret |= SETIREG(SISSR, 0x21, 0xa5);
2089 if (ret == 0)
2090 break;
2093 return ret;
2096 #undef SETREG
2097 #undef GETREG
2098 #undef SETIREG
2099 #undef GETIREG
2100 #undef SETIREGOR
2101 #undef SETIREGAND
2102 #undef SETIREGANDOR
2103 #undef READL
2104 #undef WRITEL
2106 static void
2107 sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2109 u8 tmp8, tmp82, ramtype;
2110 int bw = 0;
2111 char *ramtypetext1 = NULL;
2112 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2113 "DDR SDRAM", "DDR SGRAM" };
2114 static const int busSDR[4] = {64, 64, 128, 128};
2115 static const int busDDR[4] = {32, 32, 64, 64};
2116 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2118 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2119 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2120 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2121 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2122 ramtype &= 0x03;
2123 switch ((tmp8 >> 2) & 0x03) {
2124 case 0: ramtypetext1 = "1 ch/1 r";
2125 if (tmp82 & 0x10) {
2126 bw = 32;
2127 } else {
2128 bw = busSDR[(tmp8 & 0x03)];
2130 break;
2131 case 1: ramtypetext1 = "1 ch/2 r";
2132 sisusb->vramsize <<= 1;
2133 bw = busSDR[(tmp8 & 0x03)];
2134 break;
2135 case 2: ramtypetext1 = "asymmeric";
2136 sisusb->vramsize += sisusb->vramsize/2;
2137 bw = busDDRA[(tmp8 & 0x03)];
2138 break;
2139 case 3: ramtypetext1 = "2 channel";
2140 sisusb->vramsize <<= 1;
2141 bw = busDDR[(tmp8 & 0x03)];
2142 break;
2145 printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2146 sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
2147 ramtypetext2[ramtype], bw);
2150 static int
2151 sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2153 struct sisusb_packet packet;
2154 int ret;
2155 u32 tmp32;
2157 /* Do some magic */
2158 packet.header = 0x001f;
2159 packet.address = 0x00000324;
2160 packet.data = 0x00000004;
2161 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2163 packet.header = 0x001f;
2164 packet.address = 0x00000364;
2165 packet.data = 0x00000004;
2166 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2168 packet.header = 0x001f;
2169 packet.address = 0x00000384;
2170 packet.data = 0x00000004;
2171 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2173 packet.header = 0x001f;
2174 packet.address = 0x00000100;
2175 packet.data = 0x00000700;
2176 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2178 packet.header = 0x000f;
2179 packet.address = 0x00000004;
2180 ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2181 packet.data |= 0x17;
2182 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2184 /* Init BAR 0 (VRAM) */
2185 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2186 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2187 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2188 tmp32 &= 0x0f;
2189 tmp32 |= SISUSB_PCI_MEMBASE;
2190 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2192 /* Init BAR 1 (MMIO) */
2193 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2194 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2195 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2196 tmp32 &= 0x0f;
2197 tmp32 |= SISUSB_PCI_MMIOBASE;
2198 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2200 /* Init BAR 2 (i/o ports) */
2201 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2202 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2203 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2204 tmp32 &= 0x0f;
2205 tmp32 |= SISUSB_PCI_IOPORTBASE;
2206 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2208 /* Enable memory and i/o access */
2209 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2210 tmp32 |= 0x3;
2211 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2213 if (ret == 0) {
2214 /* Some further magic */
2215 packet.header = 0x001f;
2216 packet.address = 0x00000050;
2217 packet.data = 0x000000ff;
2218 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2221 return ret;
2224 /* Initialize the graphics device (return 0 on success)
2225 * This initializes the net2280 as well as the PCI registers
2226 * of the graphics board.
2229 static int
2230 sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2232 int ret = 0, test = 0;
2233 u32 tmp32;
2235 if (sisusb->devinit == 1) {
2236 /* Read PCI BARs and see if they have been set up */
2237 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2238 if (ret) return ret;
2239 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
2241 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2242 if (ret) return ret;
2243 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2245 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2246 if (ret) return ret;
2247 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2250 /* No? So reset the device */
2251 if ((sisusb->devinit == 0) || (test != 3)) {
2253 ret |= sisusb_do_init_gfxdevice(sisusb);
2255 if (ret == 0)
2256 sisusb->devinit = 1;
2260 if (sisusb->devinit) {
2261 /* Initialize the graphics core */
2262 if (sisusb_init_gfxcore(sisusb) == 0) {
2263 sisusb->gfxinit = 1;
2264 sisusb_get_ramconfig(sisusb);
2265 ret |= sisusb_set_default_mode(sisusb, 1);
2266 ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2270 return ret;
2273 /* fops */
2275 static int
2276 sisusb_open(struct inode *inode, struct file *file)
2278 struct sisusb_usb_data *sisusb;
2279 struct usb_interface *interface;
2280 int subminor = iminor(inode);
2282 down(&disconnect_sem);
2284 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
2285 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
2286 subminor);
2287 up(&disconnect_sem);
2288 return -ENODEV;
2291 if (!(sisusb = usb_get_intfdata(interface))) {
2292 up(&disconnect_sem);
2293 return -ENODEV;
2296 down(&sisusb->lock);
2298 if (!sisusb->present || !sisusb->ready) {
2299 up(&sisusb->lock);
2300 up(&disconnect_sem);
2301 return -ENODEV;
2304 if (sisusb->isopen) {
2305 up(&sisusb->lock);
2306 up(&disconnect_sem);
2307 return -EBUSY;
2310 if (!sisusb->devinit) {
2311 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2312 if (sisusb_init_gfxdevice(sisusb, 0)) {
2313 up(&sisusb->lock);
2314 up(&disconnect_sem);
2315 printk(KERN_ERR
2316 "sisusbvga[%d]: Failed to initialize "
2317 "device\n",
2318 sisusb->minor);
2319 return -EIO;
2321 } else {
2322 up(&sisusb->lock);
2323 up(&disconnect_sem);
2324 printk(KERN_ERR
2325 "sisusbvga[%d]: Device not attached to "
2326 "USB 2.0 hub\n",
2327 sisusb->minor);
2328 return -EIO;
2332 /* increment usage count for the device */
2333 kref_get(&sisusb->kref);
2335 sisusb->isopen = 1;
2337 file->private_data = sisusb;
2339 up(&sisusb->lock);
2341 up(&disconnect_sem);
2343 printk(KERN_DEBUG "sisusbvga[%d]: opened", sisusb->minor);
2345 return 0;
2348 static void
2349 sisusb_delete(struct kref *kref)
2351 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2353 if (!sisusb)
2354 return;
2356 if (sisusb->sisusb_dev)
2357 usb_put_dev(sisusb->sisusb_dev);
2359 sisusb->sisusb_dev = NULL;
2360 sisusb_free_buffers(sisusb);
2361 sisusb_free_urbs(sisusb);
2362 kfree(sisusb);
2365 static int
2366 sisusb_release(struct inode *inode, struct file *file)
2368 struct sisusb_usb_data *sisusb;
2369 int myminor;
2371 down(&disconnect_sem);
2373 if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
2374 up(&disconnect_sem);
2375 return -ENODEV;
2378 down(&sisusb->lock);
2380 if (sisusb->present) {
2381 /* Wait for all URBs to finish if device still present */
2382 if (!sisusb_wait_all_out_complete(sisusb))
2383 sisusb_kill_all_busy(sisusb);
2386 myminor = sisusb->minor;
2388 sisusb->isopen = 0;
2389 file->private_data = NULL;
2391 up(&sisusb->lock);
2393 /* decrement the usage count on our device */
2394 kref_put(&sisusb->kref, sisusb_delete);
2396 up(&disconnect_sem);
2398 printk(KERN_DEBUG "sisusbvga[%d]: released", myminor);
2400 return 0;
2403 static ssize_t
2404 sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2406 struct sisusb_usb_data *sisusb;
2407 ssize_t bytes_read = 0;
2408 int errno = 0;
2409 u8 buf8;
2410 u16 buf16;
2411 u32 buf32, address;
2413 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2414 return -ENODEV;
2416 down(&sisusb->lock);
2418 /* Sanity check */
2419 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2420 up(&sisusb->lock);
2421 return -ENODEV;
2424 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2425 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2427 address = (*ppos) -
2428 SISUSB_PCI_PSEUDO_IOPORTBASE +
2429 SISUSB_PCI_IOPORTBASE;
2431 /* Read i/o ports
2432 * Byte, word and long(32) can be read. As this
2433 * emulates inX instructions, the data returned is
2434 * in machine-endianness.
2436 switch (count) {
2438 case 1:
2439 if (sisusb_read_memio_byte(sisusb,
2440 SISUSB_TYPE_IO,
2441 address, &buf8))
2442 errno = -EIO;
2443 else if (put_user(buf8, (u8 __user *)buffer))
2444 errno = -EFAULT;
2445 else
2446 bytes_read = 1;
2448 break;
2450 case 2:
2451 if (sisusb_read_memio_word(sisusb,
2452 SISUSB_TYPE_IO,
2453 address, &buf16))
2454 errno = -EIO;
2455 else if (put_user(buf16, (u16 __user *)buffer))
2456 errno = -EFAULT;
2457 else
2458 bytes_read = 2;
2460 break;
2462 case 4:
2463 if (sisusb_read_memio_long(sisusb,
2464 SISUSB_TYPE_IO,
2465 address, &buf32))
2466 errno = -EIO;
2467 else if (put_user(buf32, (u32 __user *)buffer))
2468 errno = -EFAULT;
2469 else
2470 bytes_read = 4;
2472 break;
2474 default:
2475 errno = -EIO;
2479 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2480 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2482 address = (*ppos) -
2483 SISUSB_PCI_PSEUDO_MEMBASE +
2484 SISUSB_PCI_MEMBASE;
2486 /* Read video ram
2487 * Remember: Data delivered is never endian-corrected
2489 errno = sisusb_read_mem_bulk(sisusb, address,
2490 NULL, count, buffer, &bytes_read);
2492 if (bytes_read)
2493 errno = bytes_read;
2495 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2496 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2498 address = (*ppos) -
2499 SISUSB_PCI_PSEUDO_MMIOBASE +
2500 SISUSB_PCI_MMIOBASE;
2502 /* Read MMIO
2503 * Remember: Data delivered is never endian-corrected
2505 errno = sisusb_read_mem_bulk(sisusb, address,
2506 NULL, count, buffer, &bytes_read);
2508 if (bytes_read)
2509 errno = bytes_read;
2511 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2512 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2514 if (count != 4) {
2515 up(&sisusb->lock);
2516 return -EINVAL;
2519 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2521 /* Read PCI config register
2522 * Return value delivered in machine endianness.
2524 if (sisusb_read_pci_config(sisusb, address, &buf32))
2525 errno = -EIO;
2526 else if (put_user(buf32, (u32 __user *)buffer))
2527 errno = -EFAULT;
2528 else
2529 bytes_read = 4;
2531 } else {
2533 errno = -EBADFD;
2537 (*ppos) += bytes_read;
2539 up(&sisusb->lock);
2541 return errno ? errno : bytes_read;
2544 static ssize_t
2545 sisusb_write(struct file *file, const char __user *buffer, size_t count,
2546 loff_t *ppos)
2548 struct sisusb_usb_data *sisusb;
2549 int errno = 0;
2550 ssize_t bytes_written = 0;
2551 u8 buf8;
2552 u16 buf16;
2553 u32 buf32, address;
2555 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2556 return -ENODEV;
2558 down(&sisusb->lock);
2560 /* Sanity check */
2561 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2562 up(&sisusb->lock);
2563 return -ENODEV;
2566 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2567 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2569 address = (*ppos) -
2570 SISUSB_PCI_PSEUDO_IOPORTBASE +
2571 SISUSB_PCI_IOPORTBASE;
2573 /* Write i/o ports
2574 * Byte, word and long(32) can be written. As this
2575 * emulates outX instructions, the data is expected
2576 * in machine-endianness.
2578 switch (count) {
2580 case 1:
2581 if (get_user(buf8, (u8 __user *)buffer))
2582 errno = -EFAULT;
2583 else if (sisusb_write_memio_byte(sisusb,
2584 SISUSB_TYPE_IO,
2585 address, buf8))
2586 errno = -EIO;
2587 else
2588 bytes_written = 1;
2590 break;
2592 case 2:
2593 if (get_user(buf16, (u16 __user *)buffer))
2594 errno = -EFAULT;
2595 else if (sisusb_write_memio_word(sisusb,
2596 SISUSB_TYPE_IO,
2597 address, buf16))
2598 errno = -EIO;
2599 else
2600 bytes_written = 2;
2602 break;
2604 case 4:
2605 if (get_user(buf32, (u32 __user *)buffer))
2606 errno = -EFAULT;
2607 else if (sisusb_write_memio_long(sisusb,
2608 SISUSB_TYPE_IO,
2609 address, buf32))
2610 errno = -EIO;
2611 else
2612 bytes_written = 4;
2614 break;
2616 default:
2617 errno = -EIO;
2620 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2621 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2623 address = (*ppos) -
2624 SISUSB_PCI_PSEUDO_MEMBASE +
2625 SISUSB_PCI_MEMBASE;
2627 /* Write video ram.
2628 * Buffer is copied 1:1, therefore, on big-endian
2629 * machines, the data must be swapped by userland
2630 * in advance (if applicable; no swapping in 8bpp
2631 * mode or if YUV data is being transferred).
2633 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2634 count, buffer, 0, &bytes_written);
2636 if (bytes_written)
2637 errno = bytes_written;
2639 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2640 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2642 address = (*ppos) -
2643 SISUSB_PCI_PSEUDO_MMIOBASE +
2644 SISUSB_PCI_MMIOBASE;
2646 /* Write MMIO.
2647 * Buffer is copied 1:1, therefore, on big-endian
2648 * machines, the data must be swapped by userland
2649 * in advance.
2651 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2652 count, buffer, 0, &bytes_written);
2654 if (bytes_written)
2655 errno = bytes_written;
2657 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2658 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2660 if (count != 4) {
2661 up(&sisusb->lock);
2662 return -EINVAL;
2665 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2667 /* Write PCI config register.
2668 * Given value expected in machine endianness.
2670 if (get_user(buf32, (u32 __user *)buffer))
2671 errno = -EFAULT;
2672 else if (sisusb_write_pci_config(sisusb, address, buf32))
2673 errno = -EIO;
2674 else
2675 bytes_written = 4;
2678 } else {
2680 /* Error */
2681 errno = -EBADFD;
2685 (*ppos) += bytes_written;
2687 up(&sisusb->lock);
2689 return errno ? errno : bytes_written;
2692 static loff_t
2693 sisusb_lseek(struct file *file, loff_t offset, int orig)
2695 struct sisusb_usb_data *sisusb;
2696 loff_t ret;
2698 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2699 return -ENODEV;
2701 down(&sisusb->lock);
2703 /* Sanity check */
2704 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2705 up(&sisusb->lock);
2706 return -ENODEV;
2709 switch (orig) {
2710 case 0:
2711 file->f_pos = offset;
2712 ret = file->f_pos;
2713 /* never negative, no force_successful_syscall needed */
2714 break;
2715 case 1:
2716 file->f_pos += offset;
2717 ret = file->f_pos;
2718 /* never negative, no force_successful_syscall needed */
2719 break;
2720 default:
2721 /* seeking relative to "end of file" is not supported */
2722 ret = -EINVAL;
2725 up(&sisusb->lock);
2726 return ret;
2729 static int
2730 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2731 unsigned long arg)
2733 int retval, port, length;
2734 u32 address;
2736 port = y->data3 -
2737 SISUSB_PCI_PSEUDO_IOPORTBASE +
2738 SISUSB_PCI_IOPORTBASE;
2740 switch (y->operation) {
2741 case SUCMD_GET:
2742 retval = sisusb_getidxreg(sisusb, port,
2743 y->data0, &y->data1);
2744 if (!retval) {
2745 if (copy_to_user((void __user *)arg, y,
2746 sizeof(*y)))
2747 retval = -EFAULT;
2749 break;
2751 case SUCMD_SET:
2752 retval = sisusb_setidxreg(sisusb, port,
2753 y->data0, y->data1);
2754 break;
2756 case SUCMD_SETOR:
2757 retval = sisusb_setidxregor(sisusb, port,
2758 y->data0, y->data1);
2759 break;
2761 case SUCMD_SETAND:
2762 retval = sisusb_setidxregand(sisusb, port,
2763 y->data0, y->data1);
2764 break;
2766 case SUCMD_SETANDOR:
2767 retval = sisusb_setidxregandor(sisusb, port,
2768 y->data0, y->data1, y->data2);
2769 break;
2771 case SUCMD_SETMASK:
2772 retval = sisusb_setidxregmask(sisusb, port,
2773 y->data0, y->data1, y->data2);
2774 break;
2776 case SUCMD_CLRSCR:
2777 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
2778 address = y->data3 -
2779 SISUSB_PCI_PSEUDO_MEMBASE +
2780 SISUSB_PCI_MEMBASE;
2781 retval = sisusb_clear_vram(sisusb, address, length);
2782 break;
2784 default:
2785 retval = -EINVAL;
2788 if(retval > 0)
2789 retval = -EIO;
2791 return retval;
2794 static int
2795 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
2796 unsigned long arg)
2798 struct sisusb_usb_data *sisusb;
2799 struct sisusb_info x;
2800 struct sisusb_command y;
2801 int retval = 0;
2802 u32 __user *argp = (u32 __user *)arg;
2804 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2805 return -ENODEV;
2807 down(&sisusb->lock);
2809 /* Sanity check */
2810 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2811 retval = -ENODEV;
2812 goto err_out;
2815 switch (cmd) {
2817 case SISUSB_GET_CONFIG_SIZE:
2819 if (put_user(sizeof(x), argp))
2820 retval = -EFAULT;
2822 break;
2824 case SISUSB_GET_CONFIG:
2826 x.sisusb_id = SISUSB_ID;
2827 x.sisusb_version = SISUSB_VERSION;
2828 x.sisusb_revision = SISUSB_REVISION;
2829 x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
2830 x.sisusb_gfxinit = sisusb->gfxinit;
2831 x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
2832 x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
2833 x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
2834 x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
2835 x.sisusb_vramsize = sisusb->vramsize;
2836 x.sisusb_minor = sisusb->minor;
2837 x.sisusb_fbdevactive= 0;
2839 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
2840 retval = -EFAULT;
2842 break;
2844 case SISUSB_COMMAND:
2846 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
2847 retval = -EFAULT;
2848 else
2849 retval = sisusb_handle_command(sisusb, &y, arg);
2851 break;
2853 default:
2854 retval = -EINVAL;
2855 break;
2858 err_out:
2859 up(&sisusb->lock);
2860 return retval;
2863 #ifdef SISUSB_NEW_CONFIG_COMPAT
2864 static long
2865 sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
2867 long retval;
2869 switch (cmd) {
2870 case SISUSB_GET_CONFIG_SIZE:
2871 case SISUSB_GET_CONFIG:
2872 case SISUSB_COMMAND:
2873 lock_kernel();
2874 retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
2875 unlock_kernel();
2876 return retval;
2878 default:
2879 return -ENOIOCTLCMD;
2882 #endif
2884 static struct file_operations usb_sisusb_fops = {
2885 .owner = THIS_MODULE,
2886 .open = sisusb_open,
2887 .release = sisusb_release,
2888 .read = sisusb_read,
2889 .write = sisusb_write,
2890 .llseek = sisusb_lseek,
2891 #ifdef SISUSB_NEW_CONFIG_COMPAT
2892 .compat_ioctl = sisusb_compat_ioctl,
2893 #endif
2894 .ioctl = sisusb_ioctl
2897 static struct usb_class_driver usb_sisusb_class = {
2898 .name = "usb/sisusbvga%d",
2899 .fops = &usb_sisusb_fops,
2900 .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
2901 .minor_base = SISUSB_MINOR
2904 static int sisusb_probe(struct usb_interface *intf,
2905 const struct usb_device_id *id)
2907 struct usb_device *dev = interface_to_usbdev(intf);
2908 struct sisusb_usb_data *sisusb;
2909 int retval = 0, i;
2910 const char *memfail =
2911 KERN_ERR
2912 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
2914 printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
2915 dev->devnum);
2917 /* Allocate memory for our private */
2918 if (!(sisusb = kmalloc(sizeof(*sisusb), GFP_KERNEL))) {
2919 printk(KERN_ERR
2920 "sisusb: Failed to allocate memory for private data\n");
2921 return -ENOMEM;
2923 memset(sisusb, 0, sizeof(*sisusb));
2924 kref_init(&sisusb->kref);
2926 init_MUTEX(&(sisusb->lock));
2928 /* Register device */
2929 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
2930 printk(KERN_ERR
2931 "sisusb: Failed to get a minor for device %d\n",
2932 dev->devnum);
2933 retval = -ENODEV;
2934 goto error_1;
2937 sisusb->sisusb_dev = dev;
2938 sisusb->minor = intf->minor;
2939 sisusb->vrambase = SISUSB_PCI_MEMBASE;
2940 sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
2941 sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
2942 sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
2943 /* Everything else is zero */
2945 /* Allocate buffers */
2946 sisusb->ibufsize = SISUSB_IBUF_SIZE;
2947 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
2948 GFP_KERNEL, &sisusb->transfer_dma_in))) {
2949 printk(memfail, "input", sisusb->minor);
2950 retval = -ENOMEM;
2951 goto error_2;
2954 sisusb->numobufs = 0;
2955 sisusb->obufsize = SISUSB_OBUF_SIZE;
2956 for (i = 0; i < NUMOBUFS; i++) {
2957 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
2958 GFP_KERNEL,
2959 &sisusb->transfer_dma_out[i]))) {
2960 if (i == 0) {
2961 printk(memfail, "output", sisusb->minor);
2962 retval = -ENOMEM;
2963 goto error_3;
2965 break;
2966 } else
2967 sisusb->numobufs++;
2971 /* Allocate URBs */
2972 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
2973 printk(KERN_ERR
2974 "sisusbvga[%d]: Failed to allocate URBs\n",
2975 sisusb->minor);
2976 retval = -ENOMEM;
2977 goto error_3;
2979 sisusb->completein = 1;
2981 for (i = 0; i < sisusb->numobufs; i++) {
2982 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
2983 printk(KERN_ERR
2984 "sisusbvga[%d]: Failed to allocate URBs\n",
2985 sisusb->minor);
2986 retval = -ENOMEM;
2987 goto error_4;
2989 sisusb->urbout_context[i].sisusb = (void *)sisusb;
2990 sisusb->urbout_context[i].urbindex = i;
2991 sisusb->urbstatus[i] = 0;
2994 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
2995 sisusb->minor, sisusb->numobufs);
2997 /* Do remaining init stuff */
2999 init_waitqueue_head(&sisusb->wait_q);
3001 usb_set_intfdata(intf, sisusb);
3003 #ifdef SISUSB_OLD_CONFIG_COMPAT
3005 int ret;
3006 /* Our ioctls are all "32/64bit compatible" */
3007 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3008 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3009 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3010 if (ret)
3011 printk(KERN_ERR
3012 "sisusbvga[%d]: Error registering ioctl32 "
3013 "translations\n",
3014 sisusb->minor);
3015 else
3016 sisusb->ioctl32registered = 1;
3019 #endif
3021 sisusb->present = 1;
3023 if (dev->speed == USB_SPEED_HIGH) {
3024 if (sisusb_init_gfxdevice(sisusb, 1))
3025 printk(KERN_ERR
3026 "sisusbvga[%d]: Failed to early "
3027 "initialize device\n",
3028 sisusb->minor);
3030 } else
3031 printk(KERN_INFO
3032 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3033 "deferring init\n",
3034 sisusb->minor);
3036 sisusb->ready = 1;
3038 return 0;
3040 error_4:
3041 sisusb_free_urbs(sisusb);
3042 error_3:
3043 sisusb_free_buffers(sisusb);
3044 error_2:
3045 usb_deregister_dev(intf, &usb_sisusb_class);
3046 error_1:
3047 kfree(sisusb);
3048 return retval;
3051 static void sisusb_disconnect(struct usb_interface *intf)
3053 struct sisusb_usb_data *sisusb;
3054 int minor;
3056 down(&disconnect_sem);
3058 /* This should *not* happen */
3059 if (!(sisusb = usb_get_intfdata(intf))) {
3060 up(&disconnect_sem);
3061 return;
3064 down(&sisusb->lock);
3066 /* Wait for all URBs to complete and kill them in case (MUST do) */
3067 if (!sisusb_wait_all_out_complete(sisusb))
3068 sisusb_kill_all_busy(sisusb);
3070 minor = sisusb->minor;
3072 usb_set_intfdata(intf, NULL);
3074 usb_deregister_dev(intf, &usb_sisusb_class);
3076 #ifdef SISUSB_OLD_CONFIG_COMPAT
3077 if (sisusb->ioctl32registered) {
3078 int ret;
3079 sisusb->ioctl32registered = 0;
3080 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3081 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3082 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3083 if (ret) {
3084 printk(KERN_ERR
3085 "sisusbvga[%d]: Error unregistering "
3086 "ioctl32 translations\n",
3087 minor);
3090 #endif
3092 sisusb->present = 0;
3093 sisusb->ready = 0;
3095 up(&sisusb->lock);
3097 /* decrement our usage count */
3098 kref_put(&sisusb->kref, sisusb_delete);
3100 up(&disconnect_sem);
3102 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
3105 static struct usb_device_id sisusb_table [] = {
3106 { USB_DEVICE(0x0711, 0x0900) },
3110 MODULE_DEVICE_TABLE (usb, sisusb_table);
3112 static struct usb_driver sisusb_driver = {
3113 .owner = THIS_MODULE,
3114 .name = "sisusb",
3115 .probe = sisusb_probe,
3116 .disconnect = sisusb_disconnect,
3117 .id_table = sisusb_table
3120 static int __init usb_sisusb_init(void)
3122 int retval;
3124 if (!(retval = usb_register(&sisusb_driver))) {
3125 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3126 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3127 printk(KERN_INFO
3128 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3131 return retval;
3134 static void __exit usb_sisusb_exit(void)
3136 usb_deregister(&sisusb_driver);
3139 module_init(usb_sisusb_init);
3140 module_exit(usb_sisusb_exit);
3142 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3143 MODULE_DESCRIPTION("sisusb - Driver for Net2280/SiS315-based USB2VGA dongles");
3144 MODULE_LICENSE("GPL");