Linux 2.6.17.7
[linux/fpc-iii.git] / drivers / usb / misc / sisusbvga / sisusb.c
blob196c8794a73cf161d3262059d648fe397125d64d
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/module.h>
41 #include <linux/kernel.h>
42 #include <linux/signal.h>
43 #include <linux/sched.h>
44 #include <linux/errno.h>
45 #include <linux/poll.h>
46 #include <linux/init.h>
47 #include <linux/slab.h>
48 #include <linux/spinlock.h>
49 #include <linux/kref.h>
50 #include <linux/usb.h>
51 #include <linux/smp_lock.h>
52 #include <linux/vmalloc.h>
54 #include "sisusb.h"
56 #ifdef INCL_SISUSB_CON
57 #include <linux/font.h>
58 #endif
60 #define SISUSB_DONTSYNC
62 /* Forward declarations / clean-up routines */
64 #ifdef INCL_SISUSB_CON
65 int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
66 int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
67 int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data);
68 int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data);
69 int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand, u8 myor);
70 int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor);
71 int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand);
73 int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
74 int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
75 int sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data);
76 int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data);
77 int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
78 u32 dest, int length, size_t *bytes_written);
80 int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
82 extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
83 extern int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
85 extern void sisusb_init_concode(void);
86 extern int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
87 extern void sisusb_console_exit(struct sisusb_usb_data *sisusb);
89 extern void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
91 extern int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
92 u8 *arg, int cmapsz, int ch512, int dorecalc,
93 struct vc_data *c, int fh, int uplock);
95 static int sisusb_first_vc = 0;
96 static int sisusb_last_vc = 0;
97 module_param_named(first, sisusb_first_vc, int, 0);
98 module_param_named(last, sisusb_last_vc, int, 0);
99 MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)");
100 MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)");
101 #endif
103 static struct usb_driver sisusb_driver;
105 DECLARE_MUTEX(disconnect_sem);
107 static void
108 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
110 int i;
112 for (i = 0; i < NUMOBUFS; i++) {
113 if (sisusb->obuf[i]) {
114 usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize,
115 sisusb->obuf[i], sisusb->transfer_dma_out[i]);
116 sisusb->obuf[i] = NULL;
119 if (sisusb->ibuf) {
120 usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
121 sisusb->ibuf, sisusb->transfer_dma_in);
122 sisusb->ibuf = NULL;
126 static void
127 sisusb_free_urbs(struct sisusb_usb_data *sisusb)
129 int i;
131 for (i = 0; i < NUMOBUFS; i++) {
132 usb_free_urb(sisusb->sisurbout[i]);
133 sisusb->sisurbout[i] = NULL;
135 usb_free_urb(sisusb->sisurbin);
136 sisusb->sisurbin = NULL;
139 /* Level 0: USB transport layer */
141 /* 1. out-bulks */
143 /* out-urb management */
145 /* Return 1 if all free, 0 otherwise */
146 static int
147 sisusb_all_free(struct sisusb_usb_data *sisusb)
149 int i;
151 for (i = 0; i < sisusb->numobufs; i++) {
153 if (sisusb->urbstatus[i] & SU_URB_BUSY)
154 return 0;
158 return 1;
161 /* Kill all busy URBs */
162 static void
163 sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
165 int i;
167 if (sisusb_all_free(sisusb))
168 return;
170 for (i = 0; i < sisusb->numobufs; i++) {
172 if (sisusb->urbstatus[i] & SU_URB_BUSY)
173 usb_kill_urb(sisusb->sisurbout[i]);
178 /* Return 1 if ok, 0 if error (not all complete within timeout) */
179 static int
180 sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
182 int timeout = 5 * HZ, i = 1;
184 wait_event_timeout(sisusb->wait_q,
185 (i = sisusb_all_free(sisusb)),
186 timeout);
188 return i;
191 static int
192 sisusb_outurb_available(struct sisusb_usb_data *sisusb)
194 int i;
196 for (i = 0; i < sisusb->numobufs; i++) {
198 if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
199 return i;
203 return -1;
206 static int
207 sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
209 int i, timeout = 5 * HZ;
211 wait_event_timeout(sisusb->wait_q,
212 ((i = sisusb_outurb_available(sisusb)) >= 0),
213 timeout);
215 return i;
218 static int
219 sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
221 int i;
223 i = sisusb_outurb_available(sisusb);
225 if (i >= 0)
226 sisusb->urbstatus[i] |= SU_URB_ALLOC;
228 return i;
231 static void
232 sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
234 if ((index >= 0) && (index < sisusb->numobufs))
235 sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
238 /* completion callback */
240 static void
241 sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
243 struct sisusb_urb_context *context = urb->context;
244 struct sisusb_usb_data *sisusb;
246 if (!context)
247 return;
249 sisusb = context->sisusb;
251 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
252 return;
254 #ifndef SISUSB_DONTSYNC
255 if (context->actual_length)
256 *(context->actual_length) += urb->actual_length;
257 #endif
259 sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
260 wake_up(&sisusb->wait_q);
263 static int
264 sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
265 int len, int *actual_length, int timeout, unsigned int tflags,
266 dma_addr_t transfer_dma)
268 struct urb *urb = sisusb->sisurbout[index];
269 int retval, byteswritten = 0;
271 /* Set up URB */
272 urb->transfer_flags = 0;
274 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
275 sisusb_bulk_completeout, &sisusb->urbout_context[index]);
277 urb->transfer_flags |= tflags;
278 urb->actual_length = 0;
280 if ((urb->transfer_dma = transfer_dma))
281 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
283 /* Set up context */
284 sisusb->urbout_context[index].actual_length = (timeout) ?
285 NULL : actual_length;
287 /* Declare this urb/buffer in use */
288 sisusb->urbstatus[index] |= SU_URB_BUSY;
290 /* Submit URB */
291 retval = usb_submit_urb(urb, GFP_ATOMIC);
293 /* If OK, and if timeout > 0, wait for completion */
294 if ((retval == 0) && timeout) {
295 wait_event_timeout(sisusb->wait_q,
296 (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
297 timeout);
298 if (sisusb->urbstatus[index] & SU_URB_BUSY) {
299 /* URB timed out... kill it and report error */
300 usb_kill_urb(urb);
301 retval = -ETIMEDOUT;
302 } else {
303 /* Otherwise, report urb status */
304 retval = urb->status;
305 byteswritten = urb->actual_length;
309 if (actual_length)
310 *actual_length = byteswritten;
312 return retval;
315 /* 2. in-bulks */
317 /* completion callback */
319 static void
320 sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
322 struct sisusb_usb_data *sisusb = urb->context;
324 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
325 return;
327 sisusb->completein = 1;
328 wake_up(&sisusb->wait_q);
331 static int
332 sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len,
333 int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma)
335 struct urb *urb = sisusb->sisurbin;
336 int retval, readbytes = 0;
338 urb->transfer_flags = 0;
340 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
341 sisusb_bulk_completein, sisusb);
343 urb->transfer_flags |= tflags;
344 urb->actual_length = 0;
346 if ((urb->transfer_dma = transfer_dma))
347 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
349 sisusb->completein = 0;
350 retval = usb_submit_urb(urb, GFP_ATOMIC);
351 if (retval == 0) {
352 wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
353 if (!sisusb->completein) {
354 /* URB timed out... kill it and report error */
355 usb_kill_urb(urb);
356 retval = -ETIMEDOUT;
357 } else {
358 /* URB completed within timout */
359 retval = urb->status;
360 readbytes = urb->actual_length;
364 if (actual_length)
365 *actual_length = readbytes;
367 return retval;
371 /* Level 1: */
373 /* Send a bulk message of variable size
375 * To copy the data from userspace, give pointer to "userbuffer",
376 * to copy from (non-DMA) kernel memory, give "kernbuffer". If
377 * both of these are NULL, it is assumed, that the transfer
378 * buffer "sisusb->obuf[index]" is set up with the data to send.
379 * Index is ignored if either kernbuffer or userbuffer is set.
380 * If async is nonzero, URBs will be sent without waiting for
381 * completion of the previous URB.
383 * (return 0 on success)
386 static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
387 char *kernbuffer, const char __user *userbuffer, int index,
388 ssize_t *bytes_written, unsigned int tflags, int async)
390 int result = 0, retry, count = len;
391 int passsize, thispass, transferred_len = 0;
392 int fromuser = (userbuffer != NULL) ? 1 : 0;
393 int fromkern = (kernbuffer != NULL) ? 1 : 0;
394 unsigned int pipe;
395 char *buffer;
397 (*bytes_written) = 0;
399 /* Sanity check */
400 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
401 return -ENODEV;
403 /* If we copy data from kernel or userspace, force the
404 * allocation of a buffer/urb. If we have the data in
405 * the transfer buffer[index] already, reuse the buffer/URB
406 * if the length is > buffer size. (So, transmitting
407 * large data amounts directly from the transfer buffer
408 * treats the buffer as a ring buffer. However, we need
409 * to sync in this case.)
411 if (fromuser || fromkern)
412 index = -1;
413 else if (len > sisusb->obufsize)
414 async = 0;
416 pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
418 do {
419 passsize = thispass = (sisusb->obufsize < count) ?
420 sisusb->obufsize : count;
422 if (index < 0)
423 index = sisusb_get_free_outbuf(sisusb);
425 if (index < 0)
426 return -EIO;
428 buffer = sisusb->obuf[index];
430 if (fromuser) {
432 if (copy_from_user(buffer, userbuffer, passsize))
433 return -EFAULT;
435 userbuffer += passsize;
437 } else if (fromkern) {
439 memcpy(buffer, kernbuffer, passsize);
440 kernbuffer += passsize;
444 retry = 5;
445 while (thispass) {
447 if (!sisusb->sisusb_dev)
448 return -ENODEV;
450 result = sisusb_bulkout_msg(sisusb,
451 index,
452 pipe,
453 buffer,
454 thispass,
455 &transferred_len,
456 async ? 0 : 5 * HZ,
457 tflags,
458 sisusb->transfer_dma_out[index]);
460 if (result == -ETIMEDOUT) {
462 /* Will not happen if async */
463 if (!retry--)
464 return -ETIME;
466 continue;
468 } else if ((result == 0) && !async && transferred_len) {
470 thispass -= transferred_len;
471 if (thispass) {
472 if (sisusb->transfer_dma_out) {
473 /* If DMA, copy remaining
474 * to beginning of buffer
476 memcpy(buffer,
477 buffer + transferred_len,
478 thispass);
479 } else {
480 /* If not DMA, simply increase
481 * the pointer
483 buffer += transferred_len;
487 } else
488 break;
491 if (result)
492 return result;
494 (*bytes_written) += passsize;
495 count -= passsize;
497 /* Force new allocation in next iteration */
498 if (fromuser || fromkern)
499 index = -1;
501 } while (count > 0);
503 if (async) {
504 #ifdef SISUSB_DONTSYNC
505 (*bytes_written) = len;
506 /* Some URBs/buffers might be busy */
507 #else
508 sisusb_wait_all_out_complete(sisusb);
509 (*bytes_written) = transferred_len;
510 /* All URBs and all buffers are available */
511 #endif
514 return ((*bytes_written) == len) ? 0 : -EIO;
517 /* Receive a bulk message of variable size
519 * To copy the data to userspace, give pointer to "userbuffer",
520 * to copy to kernel memory, give "kernbuffer". One of them
521 * MUST be set. (There is no technique for letting the caller
522 * read directly from the ibuf.)
526 static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
527 void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
528 unsigned int tflags)
530 int result = 0, retry, count = len;
531 int bufsize, thispass, transferred_len;
532 unsigned int pipe;
533 char *buffer;
535 (*bytes_read) = 0;
537 /* Sanity check */
538 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
539 return -ENODEV;
541 pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
542 buffer = sisusb->ibuf;
543 bufsize = sisusb->ibufsize;
545 retry = 5;
547 #ifdef SISUSB_DONTSYNC
548 if (!(sisusb_wait_all_out_complete(sisusb)))
549 return -EIO;
550 #endif
552 while (count > 0) {
554 if (!sisusb->sisusb_dev)
555 return -ENODEV;
557 thispass = (bufsize < count) ? bufsize : count;
559 result = sisusb_bulkin_msg(sisusb,
560 pipe,
561 buffer,
562 thispass,
563 &transferred_len,
564 5 * HZ,
565 tflags,
566 sisusb->transfer_dma_in);
568 if (transferred_len)
569 thispass = transferred_len;
571 else if (result == -ETIMEDOUT) {
573 if (!retry--)
574 return -ETIME;
576 continue;
578 } else
579 return -EIO;
582 if (thispass) {
584 (*bytes_read) += thispass;
585 count -= thispass;
587 if (userbuffer) {
589 if (copy_to_user(userbuffer, buffer, thispass))
590 return -EFAULT;
592 userbuffer += thispass;
594 } else {
596 memcpy(kernbuffer, buffer, thispass);
597 kernbuffer += thispass;
605 return ((*bytes_read) == len) ? 0 : -EIO;
608 static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
609 struct sisusb_packet *packet)
611 int ret;
612 ssize_t bytes_transferred = 0;
613 __le32 tmp;
615 if (len == 6)
616 packet->data = 0;
618 #ifdef SISUSB_DONTSYNC
619 if (!(sisusb_wait_all_out_complete(sisusb)))
620 return 1;
621 #endif
623 /* Eventually correct endianness */
624 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
626 /* 1. send the packet */
627 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len,
628 (char *)packet, NULL, 0, &bytes_transferred, 0, 0);
630 if ((ret == 0) && (len == 6)) {
632 /* 2. if packet len == 6, it means we read, so wait for 32bit
633 * return value and write it to packet->data
635 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
636 (char *)&tmp, NULL, &bytes_transferred, 0);
638 packet->data = le32_to_cpu(tmp);
641 return ret;
644 static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
645 struct sisusb_packet *packet,
646 unsigned int tflags)
648 int ret;
649 ssize_t bytes_transferred = 0;
650 __le32 tmp;
652 if (len == 6)
653 packet->data = 0;
655 #ifdef SISUSB_DONTSYNC
656 if (!(sisusb_wait_all_out_complete(sisusb)))
657 return 1;
658 #endif
660 /* Eventually correct endianness */
661 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
663 /* 1. send the packet */
664 ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len,
665 (char *)packet, NULL, 0, &bytes_transferred, tflags, 0);
667 if ((ret == 0) && (len == 6)) {
669 /* 2. if packet len == 6, it means we read, so wait for 32bit
670 * return value and write it to packet->data
672 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
673 (char *)&tmp, NULL, &bytes_transferred, 0);
675 packet->data = le32_to_cpu(tmp);
678 return ret;
681 /* access video memory and mmio (return 0 on success) */
683 /* Low level */
685 /* The following routines assume being used to transfer byte, word,
686 * long etc.
687 * This means that
688 * - the write routines expect "data" in machine endianness format.
689 * The data will be converted to leXX in sisusb_xxx_packet.
690 * - the read routines can expect read data in machine-endianess.
693 static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
694 u32 addr, u8 data)
696 struct sisusb_packet packet;
697 int ret;
699 packet.header = (1 << (addr & 3)) | (type << 6);
700 packet.address = addr & ~3;
701 packet.data = data << ((addr & 3) << 3);
702 ret = sisusb_send_packet(sisusb, 10, &packet);
703 return ret;
706 static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
707 u32 addr, u16 data)
709 struct sisusb_packet packet;
710 int ret = 0;
712 packet.address = addr & ~3;
714 switch (addr & 3) {
715 case 0:
716 packet.header = (type << 6) | 0x0003;
717 packet.data = (u32)data;
718 ret = sisusb_send_packet(sisusb, 10, &packet);
719 break;
720 case 1:
721 packet.header = (type << 6) | 0x0006;
722 packet.data = (u32)data << 8;
723 ret = sisusb_send_packet(sisusb, 10, &packet);
724 break;
725 case 2:
726 packet.header = (type << 6) | 0x000c;
727 packet.data = (u32)data << 16;
728 ret = sisusb_send_packet(sisusb, 10, &packet);
729 break;
730 case 3:
731 packet.header = (type << 6) | 0x0008;
732 packet.data = (u32)data << 24;
733 ret = sisusb_send_packet(sisusb, 10, &packet);
734 packet.header = (type << 6) | 0x0001;
735 packet.address = (addr & ~3) + 4;
736 packet.data = (u32)data >> 8;
737 ret |= sisusb_send_packet(sisusb, 10, &packet);
740 return ret;
743 static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
744 u32 addr, u32 data)
746 struct sisusb_packet packet;
747 int ret = 0;
749 packet.address = addr & ~3;
751 switch (addr & 3) {
752 case 0:
753 packet.header = (type << 6) | 0x0007;
754 packet.data = data & 0x00ffffff;
755 ret = sisusb_send_packet(sisusb, 10, &packet);
756 break;
757 case 1:
758 packet.header = (type << 6) | 0x000e;
759 packet.data = data << 8;
760 ret = sisusb_send_packet(sisusb, 10, &packet);
761 break;
762 case 2:
763 packet.header = (type << 6) | 0x000c;
764 packet.data = data << 16;
765 ret = sisusb_send_packet(sisusb, 10, &packet);
766 packet.header = (type << 6) | 0x0001;
767 packet.address = (addr & ~3) + 4;
768 packet.data = (data >> 16) & 0x00ff;
769 ret |= sisusb_send_packet(sisusb, 10, &packet);
770 break;
771 case 3:
772 packet.header = (type << 6) | 0x0008;
773 packet.data = data << 24;
774 ret = sisusb_send_packet(sisusb, 10, &packet);
775 packet.header = (type << 6) | 0x0003;
776 packet.address = (addr & ~3) + 4;
777 packet.data = (data >> 8) & 0xffff;
778 ret |= sisusb_send_packet(sisusb, 10, &packet);
781 return ret;
784 static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
785 u32 addr, u32 data)
787 struct sisusb_packet packet;
788 int ret = 0;
790 packet.address = addr & ~3;
792 switch (addr & 3) {
793 case 0:
794 packet.header = (type << 6) | 0x000f;
795 packet.data = data;
796 ret = sisusb_send_packet(sisusb, 10, &packet);
797 break;
798 case 1:
799 packet.header = (type << 6) | 0x000e;
800 packet.data = data << 8;
801 ret = sisusb_send_packet(sisusb, 10, &packet);
802 packet.header = (type << 6) | 0x0001;
803 packet.address = (addr & ~3) + 4;
804 packet.data = data >> 24;
805 ret |= sisusb_send_packet(sisusb, 10, &packet);
806 break;
807 case 2:
808 packet.header = (type << 6) | 0x000c;
809 packet.data = data << 16;
810 ret = sisusb_send_packet(sisusb, 10, &packet);
811 packet.header = (type << 6) | 0x0003;
812 packet.address = (addr & ~3) + 4;
813 packet.data = data >> 16;
814 ret |= sisusb_send_packet(sisusb, 10, &packet);
815 break;
816 case 3:
817 packet.header = (type << 6) | 0x0008;
818 packet.data = data << 24;
819 ret = sisusb_send_packet(sisusb, 10, &packet);
820 packet.header = (type << 6) | 0x0007;
821 packet.address = (addr & ~3) + 4;
822 packet.data = data >> 8;
823 ret |= sisusb_send_packet(sisusb, 10, &packet);
826 return ret;
829 /* The xxx_bulk routines copy a buffer of variable size. They treat the
830 * buffer as chars, therefore lsb/msb has to be corrected if using the
831 * byte/word/long/etc routines for speed-up
833 * If data is from userland, set "userbuffer" (and clear "kernbuffer"),
834 * if data is in kernel space, set "kernbuffer" (and clear "userbuffer");
835 * if neither "kernbuffer" nor "userbuffer" are given, it is assumed
836 * that the data already is in the transfer buffer "sisusb->obuf[index]".
839 static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
840 char *kernbuffer, int length,
841 const char __user *userbuffer, int index,
842 ssize_t *bytes_written)
844 struct sisusb_packet packet;
845 int ret = 0;
846 static int msgcount = 0;
847 u8 swap8, fromkern = kernbuffer ? 1 : 0;
848 u16 swap16;
849 u32 swap32, flag = (length >> 28) & 1;
850 char buf[4];
852 /* if neither kernbuffer not userbuffer are given, assume
853 * data in obuf
855 if (!fromkern && !userbuffer)
856 kernbuffer = sisusb->obuf[index];
858 (*bytes_written = 0);
860 length &= 0x00ffffff;
862 while (length) {
864 switch (length) {
866 case 1:
867 if (userbuffer) {
868 if (get_user(swap8, (u8 __user *)userbuffer))
869 return -EFAULT;
870 } else
871 swap8 = kernbuffer[0];
873 ret = sisusb_write_memio_byte(sisusb,
874 SISUSB_TYPE_MEM,
875 addr, swap8);
877 if (!ret)
878 (*bytes_written)++;
880 return ret;
882 case 2:
883 if (userbuffer) {
884 if (get_user(swap16, (u16 __user *)userbuffer))
885 return -EFAULT;
886 } else
887 swap16 = *((u16 *)kernbuffer);
889 ret = sisusb_write_memio_word(sisusb,
890 SISUSB_TYPE_MEM,
891 addr,
892 swap16);
894 if (!ret)
895 (*bytes_written) += 2;
897 return ret;
899 case 3:
900 if (userbuffer) {
901 if (copy_from_user(&buf, userbuffer, 3))
902 return -EFAULT;
903 #ifdef __BIG_ENDIAN
904 swap32 = (buf[0] << 16) |
905 (buf[1] << 8) |
906 buf[2];
907 #else
908 swap32 = (buf[2] << 16) |
909 (buf[1] << 8) |
910 buf[0];
911 #endif
912 } else
913 #ifdef __BIG_ENDIAN
914 swap32 = (kernbuffer[0] << 16) |
915 (kernbuffer[1] << 8) |
916 kernbuffer[2];
917 #else
918 swap32 = (kernbuffer[2] << 16) |
919 (kernbuffer[1] << 8) |
920 kernbuffer[0];
921 #endif
923 ret = sisusb_write_memio_24bit(sisusb,
924 SISUSB_TYPE_MEM,
925 addr,
926 swap32);
928 if (!ret)
929 (*bytes_written) += 3;
931 return ret;
933 case 4:
934 if (userbuffer) {
935 if (get_user(swap32, (u32 __user *)userbuffer))
936 return -EFAULT;
937 } else
938 swap32 = *((u32 *)kernbuffer);
940 ret = sisusb_write_memio_long(sisusb,
941 SISUSB_TYPE_MEM,
942 addr,
943 swap32);
944 if (!ret)
945 (*bytes_written) += 4;
947 return ret;
949 default:
950 if ((length & ~3) > 0x10000) {
952 packet.header = 0x001f;
953 packet.address = 0x000001d4;
954 packet.data = addr;
955 ret = sisusb_send_bridge_packet(sisusb, 10,
956 &packet, 0);
957 packet.header = 0x001f;
958 packet.address = 0x000001d0;
959 packet.data = (length & ~3);
960 ret |= sisusb_send_bridge_packet(sisusb, 10,
961 &packet, 0);
962 packet.header = 0x001f;
963 packet.address = 0x000001c0;
964 packet.data = flag | 0x16;
965 ret |= sisusb_send_bridge_packet(sisusb, 10,
966 &packet, 0);
967 if (userbuffer) {
968 ret |= sisusb_send_bulk_msg(sisusb,
969 SISUSB_EP_GFX_LBULK_OUT,
970 (length & ~3),
971 NULL, userbuffer, 0,
972 bytes_written, 0, 1);
973 userbuffer += (*bytes_written);
974 } else if (fromkern) {
975 ret |= sisusb_send_bulk_msg(sisusb,
976 SISUSB_EP_GFX_LBULK_OUT,
977 (length & ~3),
978 kernbuffer, NULL, 0,
979 bytes_written, 0, 1);
980 kernbuffer += (*bytes_written);
981 } else {
982 ret |= sisusb_send_bulk_msg(sisusb,
983 SISUSB_EP_GFX_LBULK_OUT,
984 (length & ~3),
985 NULL, NULL, index,
986 bytes_written, 0, 1);
987 kernbuffer += ((*bytes_written) &
988 (sisusb->obufsize-1));
991 } else {
993 packet.header = 0x001f;
994 packet.address = 0x00000194;
995 packet.data = addr;
996 ret = sisusb_send_bridge_packet(sisusb, 10,
997 &packet, 0);
998 packet.header = 0x001f;
999 packet.address = 0x00000190;
1000 packet.data = (length & ~3);
1001 ret |= sisusb_send_bridge_packet(sisusb, 10,
1002 &packet, 0);
1003 if (sisusb->flagb0 != 0x16) {
1004 packet.header = 0x001f;
1005 packet.address = 0x00000180;
1006 packet.data = flag | 0x16;
1007 ret |= sisusb_send_bridge_packet(sisusb, 10,
1008 &packet, 0);
1009 sisusb->flagb0 = 0x16;
1011 if (userbuffer) {
1012 ret |= sisusb_send_bulk_msg(sisusb,
1013 SISUSB_EP_GFX_BULK_OUT,
1014 (length & ~3),
1015 NULL, userbuffer, 0,
1016 bytes_written, 0, 1);
1017 userbuffer += (*bytes_written);
1018 } else if (fromkern) {
1019 ret |= sisusb_send_bulk_msg(sisusb,
1020 SISUSB_EP_GFX_BULK_OUT,
1021 (length & ~3),
1022 kernbuffer, NULL, 0,
1023 bytes_written, 0, 1);
1024 kernbuffer += (*bytes_written);
1025 } else {
1026 ret |= sisusb_send_bulk_msg(sisusb,
1027 SISUSB_EP_GFX_BULK_OUT,
1028 (length & ~3),
1029 NULL, NULL, index,
1030 bytes_written, 0, 1);
1031 kernbuffer += ((*bytes_written) &
1032 (sisusb->obufsize-1));
1035 if (ret) {
1036 msgcount++;
1037 if (msgcount < 500)
1038 printk(KERN_ERR
1039 "sisusbvga[%d]: Wrote %zd of "
1040 "%d bytes, error %d\n",
1041 sisusb->minor, *bytes_written,
1042 length, ret);
1043 else if (msgcount == 500)
1044 printk(KERN_ERR
1045 "sisusbvga[%d]: Too many errors"
1046 ", logging stopped\n",
1047 sisusb->minor);
1049 addr += (*bytes_written);
1050 length -= (*bytes_written);
1053 if (ret)
1054 break;
1058 return ret ? -EIO : 0;
1061 /* Remember: Read data in packet is in machine-endianess! So for
1062 * byte, word, 24bit, long no endian correction is necessary.
1065 static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1066 u32 addr, u8 *data)
1068 struct sisusb_packet packet;
1069 int ret;
1071 CLEARPACKET(&packet);
1072 packet.header = (1 << (addr & 3)) | (type << 6);
1073 packet.address = addr & ~3;
1074 ret = sisusb_send_packet(sisusb, 6, &packet);
1075 *data = (u8)(packet.data >> ((addr & 3) << 3));
1076 return ret;
1079 static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1080 u32 addr, u16 *data)
1082 struct sisusb_packet packet;
1083 int ret = 0;
1085 CLEARPACKET(&packet);
1087 packet.address = addr & ~3;
1089 switch (addr & 3) {
1090 case 0:
1091 packet.header = (type << 6) | 0x0003;
1092 ret = sisusb_send_packet(sisusb, 6, &packet);
1093 *data = (u16)(packet.data);
1094 break;
1095 case 1:
1096 packet.header = (type << 6) | 0x0006;
1097 ret = sisusb_send_packet(sisusb, 6, &packet);
1098 *data = (u16)(packet.data >> 8);
1099 break;
1100 case 2:
1101 packet.header = (type << 6) | 0x000c;
1102 ret = sisusb_send_packet(sisusb, 6, &packet);
1103 *data = (u16)(packet.data >> 16);
1104 break;
1105 case 3:
1106 packet.header = (type << 6) | 0x0008;
1107 ret = sisusb_send_packet(sisusb, 6, &packet);
1108 *data = (u16)(packet.data >> 24);
1109 packet.header = (type << 6) | 0x0001;
1110 packet.address = (addr & ~3) + 4;
1111 ret |= sisusb_send_packet(sisusb, 6, &packet);
1112 *data |= (u16)(packet.data << 8);
1115 return ret;
1118 static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1119 u32 addr, u32 *data)
1121 struct sisusb_packet packet;
1122 int ret = 0;
1124 packet.address = addr & ~3;
1126 switch (addr & 3) {
1127 case 0:
1128 packet.header = (type << 6) | 0x0007;
1129 ret = sisusb_send_packet(sisusb, 6, &packet);
1130 *data = packet.data & 0x00ffffff;
1131 break;
1132 case 1:
1133 packet.header = (type << 6) | 0x000e;
1134 ret = sisusb_send_packet(sisusb, 6, &packet);
1135 *data = packet.data >> 8;
1136 break;
1137 case 2:
1138 packet.header = (type << 6) | 0x000c;
1139 ret = sisusb_send_packet(sisusb, 6, &packet);
1140 *data = packet.data >> 16;
1141 packet.header = (type << 6) | 0x0001;
1142 packet.address = (addr & ~3) + 4;
1143 ret |= sisusb_send_packet(sisusb, 6, &packet);
1144 *data |= ((packet.data & 0xff) << 16);
1145 break;
1146 case 3:
1147 packet.header = (type << 6) | 0x0008;
1148 ret = sisusb_send_packet(sisusb, 6, &packet);
1149 *data = packet.data >> 24;
1150 packet.header = (type << 6) | 0x0003;
1151 packet.address = (addr & ~3) + 4;
1152 ret |= sisusb_send_packet(sisusb, 6, &packet);
1153 *data |= ((packet.data & 0xffff) << 8);
1156 return ret;
1159 static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1160 u32 addr, u32 *data)
1162 struct sisusb_packet packet;
1163 int ret = 0;
1165 packet.address = addr & ~3;
1167 switch (addr & 3) {
1168 case 0:
1169 packet.header = (type << 6) | 0x000f;
1170 ret = sisusb_send_packet(sisusb, 6, &packet);
1171 *data = packet.data;
1172 break;
1173 case 1:
1174 packet.header = (type << 6) | 0x000e;
1175 ret = sisusb_send_packet(sisusb, 6, &packet);
1176 *data = packet.data >> 8;
1177 packet.header = (type << 6) | 0x0001;
1178 packet.address = (addr & ~3) + 4;
1179 ret |= sisusb_send_packet(sisusb, 6, &packet);
1180 *data |= (packet.data << 24);
1181 break;
1182 case 2:
1183 packet.header = (type << 6) | 0x000c;
1184 ret = sisusb_send_packet(sisusb, 6, &packet);
1185 *data = packet.data >> 16;
1186 packet.header = (type << 6) | 0x0003;
1187 packet.address = (addr & ~3) + 4;
1188 ret |= sisusb_send_packet(sisusb, 6, &packet);
1189 *data |= (packet.data << 16);
1190 break;
1191 case 3:
1192 packet.header = (type << 6) | 0x0008;
1193 ret = sisusb_send_packet(sisusb, 6, &packet);
1194 *data = packet.data >> 24;
1195 packet.header = (type << 6) | 0x0007;
1196 packet.address = (addr & ~3) + 4;
1197 ret |= sisusb_send_packet(sisusb, 6, &packet);
1198 *data |= (packet.data << 8);
1201 return ret;
1204 static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1205 char *kernbuffer, int length,
1206 char __user *userbuffer, ssize_t *bytes_read)
1208 int ret = 0;
1209 char buf[4];
1210 u16 swap16;
1211 u32 swap32;
1213 (*bytes_read = 0);
1215 length &= 0x00ffffff;
1217 while (length) {
1219 switch (length) {
1221 case 1:
1223 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1224 addr, &buf[0]);
1225 if (!ret) {
1226 (*bytes_read)++;
1227 if (userbuffer) {
1228 if (put_user(buf[0],
1229 (u8 __user *)userbuffer)) {
1230 return -EFAULT;
1232 } else {
1233 kernbuffer[0] = buf[0];
1236 return ret;
1238 case 2:
1239 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1240 addr, &swap16);
1241 if (!ret) {
1242 (*bytes_read) += 2;
1243 if (userbuffer) {
1244 if (put_user(swap16,
1245 (u16 __user *)userbuffer))
1246 return -EFAULT;
1247 } else {
1248 *((u16 *)kernbuffer) = swap16;
1251 return ret;
1253 case 3:
1254 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1255 addr, &swap32);
1256 if (!ret) {
1257 (*bytes_read) += 3;
1258 #ifdef __BIG_ENDIAN
1259 buf[0] = (swap32 >> 16) & 0xff;
1260 buf[1] = (swap32 >> 8) & 0xff;
1261 buf[2] = swap32 & 0xff;
1262 #else
1263 buf[2] = (swap32 >> 16) & 0xff;
1264 buf[1] = (swap32 >> 8) & 0xff;
1265 buf[0] = swap32 & 0xff;
1266 #endif
1267 if (userbuffer) {
1268 if (copy_to_user(userbuffer, &buf[0], 3))
1269 return -EFAULT;
1270 } else {
1271 kernbuffer[0] = buf[0];
1272 kernbuffer[1] = buf[1];
1273 kernbuffer[2] = buf[2];
1276 return ret;
1278 default:
1279 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1280 addr, &swap32);
1281 if (!ret) {
1282 (*bytes_read) += 4;
1283 if (userbuffer) {
1284 if (put_user(swap32,
1285 (u32 __user *)userbuffer))
1286 return -EFAULT;
1288 userbuffer += 4;
1289 } else {
1290 *((u32 *)kernbuffer) = swap32;
1291 kernbuffer += 4;
1293 addr += 4;
1294 length -= 4;
1296 #if 0 /* That does not work, as EP 2 is an OUT EP! */
1297 default:
1298 CLEARPACKET(&packet);
1299 packet.header = 0x001f;
1300 packet.address = 0x000001a0;
1301 packet.data = 0x00000006;
1302 ret |= sisusb_send_bridge_packet(sisusb, 10,
1303 &packet, 0);
1304 packet.header = 0x001f;
1305 packet.address = 0x000001b0;
1306 packet.data = (length & ~3) | 0x40000000;
1307 ret |= sisusb_send_bridge_packet(sisusb, 10,
1308 &packet, 0);
1309 packet.header = 0x001f;
1310 packet.address = 0x000001b4;
1311 packet.data = addr;
1312 ret |= sisusb_send_bridge_packet(sisusb, 10,
1313 &packet, 0);
1314 packet.header = 0x001f;
1315 packet.address = 0x000001a4;
1316 packet.data = 0x00000001;
1317 ret |= sisusb_send_bridge_packet(sisusb, 10,
1318 &packet, 0);
1319 if (userbuffer) {
1320 ret |= sisusb_recv_bulk_msg(sisusb,
1321 SISUSB_EP_GFX_BULK_IN,
1322 (length & ~3),
1323 NULL, userbuffer,
1324 bytes_read, 0);
1325 if (!ret) userbuffer += (*bytes_read);
1326 } else {
1327 ret |= sisusb_recv_bulk_msg(sisusb,
1328 SISUSB_EP_GFX_BULK_IN,
1329 (length & ~3),
1330 kernbuffer, NULL,
1331 bytes_read, 0);
1332 if (!ret) kernbuffer += (*bytes_read);
1334 addr += (*bytes_read);
1335 length -= (*bytes_read);
1336 #endif
1339 if (ret)
1340 break;
1343 return ret;
1346 /* High level: Gfx (indexed) register access */
1348 #ifdef INCL_SISUSB_CON
1350 sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data)
1352 return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1356 sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data)
1358 return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data);
1360 #endif
1362 #ifndef INCL_SISUSB_CON
1363 static
1364 #endif
1366 sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1368 int ret;
1369 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1370 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1371 return ret;
1374 #ifndef INCL_SISUSB_CON
1375 static
1376 #endif
1378 sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1380 int ret;
1381 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1382 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1383 return ret;
1386 #ifndef INCL_SISUSB_CON
1387 static
1388 #endif
1390 sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1391 u8 myand, u8 myor)
1393 int ret;
1394 u8 tmp;
1396 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1397 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1398 tmp &= myand;
1399 tmp |= myor;
1400 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1401 return ret;
1404 static int
1405 sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1406 u8 data, u8 mask)
1408 int ret;
1409 u8 tmp;
1410 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1411 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1412 tmp &= ~(mask);
1413 tmp |= (data & mask);
1414 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1415 return ret;
1418 #ifndef INCL_SISUSB_CON
1419 static
1420 #endif
1422 sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1424 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1427 #ifndef INCL_SISUSB_CON
1428 static
1429 #endif
1431 sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1433 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1436 /* Write/read video ram */
1438 #ifdef INCL_SISUSB_CON
1440 sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data)
1442 return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1446 sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
1448 return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
1452 sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
1454 return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1458 sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
1460 return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
1464 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
1465 u32 dest, int length, size_t *bytes_written)
1467 return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written));
1470 #ifdef SISUSBENDIANTEST
1472 sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
1473 u32 src, int length, size_t *bytes_written)
1475 return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written));
1477 #endif
1478 #endif
1480 #ifdef SISUSBENDIANTEST
1481 static void
1482 sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
1484 static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
1485 char destbuffer[10];
1486 size_t dummy;
1487 int i,j;
1489 sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
1491 for(i = 1; i <= 7; i++) {
1492 printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
1493 sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
1494 for(j = 0; j < i; j++) {
1495 printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
1499 #endif
1501 /* access pci config registers (reg numbers 0, 4, 8, etc) */
1503 static int
1504 sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1506 struct sisusb_packet packet;
1507 int ret;
1509 packet.header = 0x008f;
1510 packet.address = regnum | 0x10000;
1511 packet.data = data;
1512 ret = sisusb_send_packet(sisusb, 10, &packet);
1513 return ret;
1516 static int
1517 sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1519 struct sisusb_packet packet;
1520 int ret;
1522 packet.header = 0x008f;
1523 packet.address = (u32)regnum | 0x10000;
1524 ret = sisusb_send_packet(sisusb, 6, &packet);
1525 *data = packet.data;
1526 return ret;
1529 /* Clear video RAM */
1531 static int
1532 sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1534 int ret, i;
1535 ssize_t j;
1537 if (address < sisusb->vrambase)
1538 return 1;
1540 if (address >= sisusb->vrambase + sisusb->vramsize)
1541 return 1;
1543 if (address + length > sisusb->vrambase + sisusb->vramsize)
1544 length = sisusb->vrambase + sisusb->vramsize - address;
1546 if (length <= 0)
1547 return 0;
1549 /* allocate free buffer/urb and clear the buffer */
1550 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1551 return -EBUSY;
1553 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1555 /* We can write a length > buffer size here. The buffer
1556 * data will simply be re-used (like a ring-buffer).
1558 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1560 /* Free the buffer/urb */
1561 sisusb_free_outbuf(sisusb, i);
1563 return ret;
1566 /* Initialize the graphics core (return 0 on success)
1567 * This resets the graphics hardware and puts it into
1568 * a defined mode (640x480@60Hz)
1571 #define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1572 #define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d)
1573 #define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d)
1574 #define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d)
1575 #define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o)
1576 #define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
1577 #define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
1578 #define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1579 #define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
1580 #define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1581 #define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
1583 static int
1584 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1586 int ret;
1587 u8 tmp8;
1589 ret = GETIREG(SISSR, 0x16, &tmp8);
1590 if (ramtype <= 1) {
1591 tmp8 &= 0x3f;
1592 ret |= SETIREG(SISSR, 0x16, tmp8);
1593 tmp8 |= 0x80;
1594 ret |= SETIREG(SISSR, 0x16, tmp8);
1595 } else {
1596 tmp8 |= 0xc0;
1597 ret |= SETIREG(SISSR, 0x16, tmp8);
1598 tmp8 &= 0x0f;
1599 ret |= SETIREG(SISSR, 0x16, tmp8);
1600 tmp8 |= 0x80;
1601 ret |= SETIREG(SISSR, 0x16, tmp8);
1602 tmp8 &= 0x0f;
1603 ret |= SETIREG(SISSR, 0x16, tmp8);
1604 tmp8 |= 0xd0;
1605 ret |= SETIREG(SISSR, 0x16, tmp8);
1606 tmp8 &= 0x0f;
1607 ret |= SETIREG(SISSR, 0x16, tmp8);
1608 tmp8 |= 0xa0;
1609 ret |= SETIREG(SISSR, 0x16, tmp8);
1611 return ret;
1614 static int
1615 sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1617 int ret;
1618 u8 ramtype, done = 0;
1619 u32 t0, t1, t2, t3;
1620 u32 ramptr = SISUSB_PCI_MEMBASE;
1622 ret = GETIREG(SISSR, 0x3a, &ramtype);
1623 ramtype &= 3;
1625 ret |= SETIREG(SISSR, 0x13, 0x00);
1627 if (ramtype <= 1) {
1628 ret |= SETIREG(SISSR, 0x14, 0x12);
1629 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1630 } else {
1631 ret |= SETIREG(SISSR, 0x14, 0x02);
1634 ret |= sisusb_triggersr16(sisusb, ramtype);
1635 ret |= WRITEL(ramptr + 0, 0x01234567);
1636 ret |= WRITEL(ramptr + 4, 0x456789ab);
1637 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1638 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1639 ret |= WRITEL(ramptr + 16, 0x55555555);
1640 ret |= WRITEL(ramptr + 20, 0x55555555);
1641 ret |= WRITEL(ramptr + 24, 0xffffffff);
1642 ret |= WRITEL(ramptr + 28, 0xffffffff);
1643 ret |= READL(ramptr + 0, &t0);
1644 ret |= READL(ramptr + 4, &t1);
1645 ret |= READL(ramptr + 8, &t2);
1646 ret |= READL(ramptr + 12, &t3);
1648 if (ramtype <= 1) {
1650 *chab = 0; *bw = 64;
1652 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1653 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1654 *chab = 0; *bw = 64;
1655 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1658 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1659 *chab = 1; *bw = 64;
1660 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1662 ret |= sisusb_triggersr16(sisusb, ramtype);
1663 ret |= WRITEL(ramptr + 0, 0x89abcdef);
1664 ret |= WRITEL(ramptr + 4, 0xcdef0123);
1665 ret |= WRITEL(ramptr + 8, 0x55555555);
1666 ret |= WRITEL(ramptr + 12, 0x55555555);
1667 ret |= WRITEL(ramptr + 16, 0xaaaaaaaa);
1668 ret |= WRITEL(ramptr + 20, 0xaaaaaaaa);
1669 ret |= READL(ramptr + 4, &t1);
1671 if (t1 != 0xcdef0123) {
1672 *bw = 32;
1673 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1677 } else {
1679 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1681 done = 0;
1683 if (t1 == 0x456789ab) {
1684 if (t0 == 0x01234567) {
1685 *chab = 0; *bw = 64;
1686 done = 1;
1688 } else {
1689 if (t0 == 0x01234567) {
1690 *chab = 0; *bw = 32;
1691 ret |= SETIREG(SISSR, 0x14, 0x00);
1692 done = 1;
1696 if (!done) {
1697 ret |= SETIREG(SISSR, 0x14, 0x03);
1698 ret |= sisusb_triggersr16(sisusb, ramtype);
1700 ret |= WRITEL(ramptr + 0, 0x01234567);
1701 ret |= WRITEL(ramptr + 4, 0x456789ab);
1702 ret |= WRITEL(ramptr + 8, 0x89abcdef);
1703 ret |= WRITEL(ramptr + 12, 0xcdef0123);
1704 ret |= WRITEL(ramptr + 16, 0x55555555);
1705 ret |= WRITEL(ramptr + 20, 0x55555555);
1706 ret |= WRITEL(ramptr + 24, 0xffffffff);
1707 ret |= WRITEL(ramptr + 28, 0xffffffff);
1708 ret |= READL(ramptr + 0, &t0);
1709 ret |= READL(ramptr + 4, &t1);
1711 if (t1 == 0x456789ab) {
1712 if (t0 == 0x01234567) {
1713 *chab = 1; *bw = 64;
1714 return ret;
1715 } /* else error */
1716 } else {
1717 if (t0 == 0x01234567) {
1718 *chab = 1; *bw = 32;
1719 ret |= SETIREG(SISSR, 0x14, 0x01);
1720 } /* else error */
1724 return ret;
1727 static int
1728 sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1730 int ret = 0;
1731 u32 ramptr = SISUSB_PCI_MEMBASE;
1732 u8 tmp1, tmp2, i, j;
1734 ret |= WRITEB(ramptr, 0xaa);
1735 ret |= WRITEB(ramptr + 16, 0x55);
1736 ret |= READB(ramptr, &tmp1);
1737 ret |= READB(ramptr + 16, &tmp2);
1738 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1739 for (i = 0, j = 16; i < 2; i++, j += 16) {
1740 ret |= GETIREG(SISSR, 0x21, &tmp1);
1741 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1742 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1743 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1744 ret |= SETIREG(SISSR, 0x21, tmp1);
1745 ret |= WRITEB(ramptr + 16 + j, j);
1746 ret |= READB(ramptr + 16 + j, &tmp1);
1747 if (tmp1 == j) {
1748 ret |= WRITEB(ramptr + j, j);
1749 break;
1753 return ret;
1756 static int
1757 sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1758 u8 rankno, u8 chab, const u8 dramtype[][5],
1759 int bw)
1761 int ret = 0, ranksize;
1762 u8 tmp;
1764 *iret = 0;
1766 if ((rankno == 2) && (dramtype[index][0] == 2))
1767 return ret;
1769 ranksize = dramtype[index][3] / 2 * bw / 32;
1771 if ((ranksize * rankno) > 128)
1772 return ret;
1774 tmp = 0;
1775 while ((ranksize >>= 1) > 0) tmp += 0x10;
1776 tmp |= ((rankno - 1) << 2);
1777 tmp |= ((bw / 64) & 0x02);
1778 tmp |= (chab & 0x01);
1780 ret = SETIREG(SISSR, 0x14, tmp);
1781 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1783 *iret = 1;
1785 return ret;
1788 static int
1789 sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1791 int ret = 0, i;
1792 u32 j, tmp;
1794 *iret = 0;
1796 for (i = 0, j = 0; i < testn; i++) {
1797 ret |= WRITEL(sisusb->vrambase + j, j);
1798 j += inc;
1801 for (i = 0, j = 0; i < testn; i++) {
1802 ret |= READL(sisusb->vrambase + j, &tmp);
1803 if (tmp != j) return ret;
1804 j += inc;
1807 *iret = 1;
1808 return ret;
1811 static int
1812 sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1813 int idx, int bw, const u8 rtype[][5])
1815 int ret = 0, i, i2ret;
1816 u32 inc;
1818 *iret = 0;
1820 for (i = rankno; i >= 1; i--) {
1821 inc = 1 << (rtype[idx][2] +
1822 rtype[idx][1] +
1823 rtype[idx][0] +
1824 bw / 64 + i);
1825 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1826 if (!i2ret)
1827 return ret;
1830 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1831 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1832 if (!i2ret)
1833 return ret;
1835 inc = 1 << (10 + bw / 64);
1836 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1837 if (!i2ret)
1838 return ret;
1840 *iret = 1;
1841 return ret;
1844 static int
1845 sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1846 int chab)
1848 int ret = 0, i2ret = 0, i, j;
1849 static const u8 sdramtype[13][5] = {
1850 { 2, 12, 9, 64, 0x35 },
1851 { 1, 13, 9, 64, 0x44 },
1852 { 2, 12, 8, 32, 0x31 },
1853 { 2, 11, 9, 32, 0x25 },
1854 { 1, 12, 9, 32, 0x34 },
1855 { 1, 13, 8, 32, 0x40 },
1856 { 2, 11, 8, 16, 0x21 },
1857 { 1, 12, 8, 16, 0x30 },
1858 { 1, 11, 9, 16, 0x24 },
1859 { 1, 11, 8, 8, 0x20 },
1860 { 2, 9, 8, 4, 0x01 },
1861 { 1, 10, 8, 4, 0x10 },
1862 { 1, 9, 8, 2, 0x00 }
1865 *iret = 1; /* error */
1867 for (i = 0; i < 13; i++) {
1868 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1869 for (j = 2; j > 0; j--) {
1870 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1871 chab, sdramtype, bw);
1872 if (!i2ret)
1873 continue;
1875 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1876 bw, sdramtype);
1877 if (i2ret) {
1878 *iret = 0; /* ram size found */
1879 return ret;
1884 return ret;
1887 static int
1888 sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1890 int ret = 0;
1891 u32 address;
1892 int i, length, modex, modey, bpp;
1894 modex = 640; modey = 480; bpp = 2;
1896 address = sisusb->vrambase; /* Clear video ram */
1898 if (clrall)
1899 length = sisusb->vramsize;
1900 else
1901 length = modex * bpp * modey;
1903 ret = sisusb_clear_vram(sisusb, address, length);
1905 if (!ret && drwfr) {
1906 for (i = 0; i < modex; i++) {
1907 address = sisusb->vrambase + (i * bpp);
1908 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1909 address, 0xf100);
1910 address += (modex * (modey-1) * bpp);
1911 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1912 address, 0xf100);
1914 for (i = 0; i < modey; i++) {
1915 address = sisusb->vrambase + ((i * modex) * bpp);
1916 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1917 address, 0xf100);
1918 address += ((modex - 1) * bpp);
1919 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1920 address, 0xf100);
1924 return ret;
1927 static int
1928 sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1930 int ret = 0, i, j, modex, modey, bpp, du;
1931 u8 sr31, cr63, tmp8;
1932 static const char attrdata[] = {
1933 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1934 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1935 0x01,0x00,0x00,0x00
1937 static const char crtcrdata[] = {
1938 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1939 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1940 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1941 0xff
1943 static const char grcdata[] = {
1944 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1945 0xff
1947 static const char crtcdata[] = {
1948 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1949 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1950 0x00
1953 modex = 640; modey = 480; bpp = 2;
1955 GETIREG(SISSR, 0x31, &sr31);
1956 GETIREG(SISCR, 0x63, &cr63);
1957 SETIREGOR(SISSR, 0x01, 0x20);
1958 SETIREG(SISCR, 0x63, cr63 & 0xbf);
1959 SETIREGOR(SISCR, 0x17, 0x80);
1960 SETIREGOR(SISSR, 0x1f, 0x04);
1961 SETIREGAND(SISSR, 0x07, 0xfb);
1962 SETIREG(SISSR, 0x00, 0x03); /* seq */
1963 SETIREG(SISSR, 0x01, 0x21);
1964 SETIREG(SISSR, 0x02, 0x0f);
1965 SETIREG(SISSR, 0x03, 0x00);
1966 SETIREG(SISSR, 0x04, 0x0e);
1967 SETREG(SISMISCW, 0x23); /* misc */
1968 for (i = 0; i <= 0x18; i++) { /* crtc */
1969 SETIREG(SISCR, i, crtcrdata[i]);
1971 for (i = 0; i <= 0x13; i++) { /* att */
1972 GETREG(SISINPSTAT, &tmp8);
1973 SETREG(SISAR, i);
1974 SETREG(SISAR, attrdata[i]);
1976 GETREG(SISINPSTAT, &tmp8);
1977 SETREG(SISAR, 0x14);
1978 SETREG(SISAR, 0x00);
1979 GETREG(SISINPSTAT, &tmp8);
1980 SETREG(SISAR, 0x20);
1981 GETREG(SISINPSTAT, &tmp8);
1982 for (i = 0; i <= 0x08; i++) { /* grc */
1983 SETIREG(SISGR, i, grcdata[i]);
1985 SETIREGAND(SISGR, 0x05, 0xbf);
1986 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1987 SETIREG(SISSR, i, 0x00);
1989 SETIREGAND(SISSR, 0x37, 0xfe);
1990 SETREG(SISMISCW, 0xef); /* sync */
1991 SETIREG(SISCR, 0x11, 0x00); /* crtc */
1992 for (j = 0x00, i = 0; i <= 7; i++, j++) {
1993 SETIREG(SISCR, j, crtcdata[i]);
1995 for (j = 0x10; i <= 10; i++, j++) {
1996 SETIREG(SISCR, j, crtcdata[i]);
1998 for (j = 0x15; i <= 12; i++, j++) {
1999 SETIREG(SISCR, j, crtcdata[i]);
2001 for (j = 0x0A; i <= 15; i++, j++) {
2002 SETIREG(SISSR, j, crtcdata[i]);
2004 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
2005 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
2006 SETIREG(SISCR, 0x14, 0x4f);
2007 du = (modex / 16) * (bpp * 2); /* offset/pitch */
2008 if (modex % 16) du += bpp;
2009 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
2010 SETIREG(SISCR, 0x13, (du & 0xff));
2011 du <<= 5;
2012 tmp8 = du >> 8;
2013 if (du & 0xff) tmp8++;
2014 SETIREG(SISSR, 0x10, tmp8);
2015 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
2016 SETIREG(SISSR, 0x2b, 0x1b);
2017 SETIREG(SISSR, 0x2c, 0xe1);
2018 SETIREG(SISSR, 0x2d, 0x01);
2019 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
2020 SETIREG(SISSR, 0x08, 0xae);
2021 SETIREGAND(SISSR, 0x09, 0xf0);
2022 SETIREG(SISSR, 0x08, 0x34);
2023 SETIREGOR(SISSR, 0x3d, 0x01);
2024 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
2025 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
2026 SETIREG(SISCR, 0x19, 0x00);
2027 SETIREGAND(SISCR, 0x1a, 0xfc);
2028 SETIREGAND(SISSR, 0x0f, 0xb7);
2029 SETIREGAND(SISSR, 0x31, 0xfb);
2030 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
2031 SETIREGAND(SISSR, 0x32, 0xf3);
2032 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
2033 SETIREG(SISCR, 0x52, 0x6c);
2035 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
2036 SETIREG(SISCR, 0x0c, 0x00);
2037 SETIREG(SISSR, 0x0d, 0x00);
2038 SETIREGAND(SISSR, 0x37, 0xfe);
2040 SETIREG(SISCR, 0x32, 0x20);
2041 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
2042 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
2043 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
2045 if (touchengines) {
2046 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
2047 SETIREGOR(SISSR, 0x1e, 0x5a);
2049 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
2050 SETIREG(SISSR, 0x27, 0x1f);
2051 SETIREG(SISSR, 0x26, 0x00);
2054 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
2056 return ret;
2059 static int
2060 sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
2062 int ret = 0, i, j, bw, chab, iret, retry = 3;
2063 u8 tmp8, ramtype;
2064 u32 tmp32;
2065 static const char mclktable[] = {
2066 0x3b, 0x22, 0x01, 143,
2067 0x3b, 0x22, 0x01, 143,
2068 0x3b, 0x22, 0x01, 143,
2069 0x3b, 0x22, 0x01, 143
2071 static const char eclktable[] = {
2072 0x3b, 0x22, 0x01, 143,
2073 0x3b, 0x22, 0x01, 143,
2074 0x3b, 0x22, 0x01, 143,
2075 0x3b, 0x22, 0x01, 143
2077 static const char ramtypetable1[] = {
2078 0x00, 0x04, 0x60, 0x60,
2079 0x0f, 0x0f, 0x1f, 0x1f,
2080 0xba, 0xba, 0xba, 0xba,
2081 0xa9, 0xa9, 0xac, 0xac,
2082 0xa0, 0xa0, 0xa0, 0xa8,
2083 0x00, 0x00, 0x02, 0x02,
2084 0x30, 0x30, 0x40, 0x40
2086 static const char ramtypetable2[] = {
2087 0x77, 0x77, 0x44, 0x44,
2088 0x77, 0x77, 0x44, 0x44,
2089 0x00, 0x00, 0x00, 0x00,
2090 0x5b, 0x5b, 0xab, 0xab,
2091 0x00, 0x00, 0xf0, 0xf8
2094 while (retry--) {
2096 /* Enable VGA */
2097 ret = GETREG(SISVGAEN, &tmp8);
2098 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
2100 /* Enable GPU access to VRAM */
2101 ret |= GETREG(SISMISCR, &tmp8);
2102 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
2104 if (ret) continue;
2106 /* Reset registers */
2107 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
2108 ret |= SETIREG(SISSR, 0x05, 0x86);
2109 ret |= SETIREGOR(SISSR, 0x20, 0x01);
2111 ret |= SETREG(SISMISCW, 0x67);
2113 for (i = 0x06; i <= 0x1f; i++) {
2114 ret |= SETIREG(SISSR, i, 0x00);
2116 for (i = 0x21; i <= 0x27; i++) {
2117 ret |= SETIREG(SISSR, i, 0x00);
2119 for (i = 0x31; i <= 0x3d; i++) {
2120 ret |= SETIREG(SISSR, i, 0x00);
2122 for (i = 0x12; i <= 0x1b; i++) {
2123 ret |= SETIREG(SISSR, i, 0x00);
2125 for (i = 0x79; i <= 0x7c; i++) {
2126 ret |= SETIREG(SISCR, i, 0x00);
2129 if (ret) continue;
2131 ret |= SETIREG(SISCR, 0x63, 0x80);
2133 ret |= GETIREG(SISSR, 0x3a, &ramtype);
2134 ramtype &= 0x03;
2136 ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]);
2137 ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]);
2138 ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]);
2140 ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]);
2141 ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]);
2142 ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]);
2144 ret |= SETIREG(SISSR, 0x07, 0x18);
2145 ret |= SETIREG(SISSR, 0x11, 0x0f);
2147 if (ret) continue;
2149 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2150 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2152 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2153 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2156 ret |= SETIREG(SISCR, 0x49, 0xaa);
2158 ret |= SETIREG(SISSR, 0x1f, 0x00);
2159 ret |= SETIREG(SISSR, 0x20, 0xa0);
2160 ret |= SETIREG(SISSR, 0x23, 0xf6);
2161 ret |= SETIREG(SISSR, 0x24, 0x0d);
2162 ret |= SETIREG(SISSR, 0x25, 0x33);
2164 ret |= SETIREG(SISSR, 0x11, 0x0f);
2166 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2168 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2170 if (ret) continue;
2172 ret |= SETIREG(SISPART1, 0x00, 0x00);
2174 ret |= GETIREG(SISSR, 0x13, &tmp8);
2175 tmp8 >>= 4;
2177 ret |= SETIREG(SISPART1, 0x02, 0x00);
2178 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2180 ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32);
2181 tmp32 &= 0x00f00000;
2182 tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03;
2183 ret |= SETIREG(SISSR, 0x25, tmp8);
2184 tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88;
2185 ret |= SETIREG(SISCR, 0x49, tmp8);
2187 ret |= SETIREG(SISSR, 0x27, 0x1f);
2188 ret |= SETIREG(SISSR, 0x31, 0x00);
2189 ret |= SETIREG(SISSR, 0x32, 0x11);
2190 ret |= SETIREG(SISSR, 0x33, 0x00);
2192 if (ret) continue;
2194 ret |= SETIREG(SISCR, 0x83, 0x00);
2196 ret |= sisusb_set_default_mode(sisusb, 0);
2198 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2199 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2200 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2202 ret |= sisusb_triggersr16(sisusb, ramtype);
2204 /* Disable refresh */
2205 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2206 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2208 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2209 ret |= sisusb_verify_mclk(sisusb);
2211 if (ramtype <= 1) {
2212 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2213 if (iret) {
2214 printk(KERN_ERR "sisusbvga[%d]: RAM size "
2215 "detection failed, "
2216 "assuming 8MB video RAM\n",
2217 sisusb->minor);
2218 ret |= SETIREG(SISSR,0x14,0x31);
2219 /* TODO */
2221 } else {
2222 printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
2223 "assuming 8MB video RAM\n",
2224 sisusb->minor);
2225 ret |= SETIREG(SISSR,0x14,0x31);
2226 /* *** TODO *** */
2229 /* Enable refresh */
2230 ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]);
2231 ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]);
2232 ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]);
2234 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2236 ret |= SETIREG(SISSR, 0x22, 0xfb);
2237 ret |= SETIREG(SISSR, 0x21, 0xa5);
2239 if (ret == 0)
2240 break;
2243 return ret;
2246 #undef SETREG
2247 #undef GETREG
2248 #undef SETIREG
2249 #undef GETIREG
2250 #undef SETIREGOR
2251 #undef SETIREGAND
2252 #undef SETIREGANDOR
2253 #undef READL
2254 #undef WRITEL
2256 static void
2257 sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2259 u8 tmp8, tmp82, ramtype;
2260 int bw = 0;
2261 char *ramtypetext1 = NULL;
2262 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2263 "DDR SDRAM", "DDR SGRAM" };
2264 static const int busSDR[4] = {64, 64, 128, 128};
2265 static const int busDDR[4] = {32, 32, 64, 64};
2266 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2268 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2269 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2270 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2271 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2272 ramtype &= 0x03;
2273 switch ((tmp8 >> 2) & 0x03) {
2274 case 0: ramtypetext1 = "1 ch/1 r";
2275 if (tmp82 & 0x10) {
2276 bw = 32;
2277 } else {
2278 bw = busSDR[(tmp8 & 0x03)];
2280 break;
2281 case 1: ramtypetext1 = "1 ch/2 r";
2282 sisusb->vramsize <<= 1;
2283 bw = busSDR[(tmp8 & 0x03)];
2284 break;
2285 case 2: ramtypetext1 = "asymmeric";
2286 sisusb->vramsize += sisusb->vramsize/2;
2287 bw = busDDRA[(tmp8 & 0x03)];
2288 break;
2289 case 3: ramtypetext1 = "2 channel";
2290 sisusb->vramsize <<= 1;
2291 bw = busDDR[(tmp8 & 0x03)];
2292 break;
2295 printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2296 sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
2297 ramtypetext2[ramtype], bw);
2300 static int
2301 sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2303 struct sisusb_packet packet;
2304 int ret;
2305 u32 tmp32;
2307 /* Do some magic */
2308 packet.header = 0x001f;
2309 packet.address = 0x00000324;
2310 packet.data = 0x00000004;
2311 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2313 packet.header = 0x001f;
2314 packet.address = 0x00000364;
2315 packet.data = 0x00000004;
2316 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2318 packet.header = 0x001f;
2319 packet.address = 0x00000384;
2320 packet.data = 0x00000004;
2321 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2323 packet.header = 0x001f;
2324 packet.address = 0x00000100;
2325 packet.data = 0x00000700;
2326 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2328 packet.header = 0x000f;
2329 packet.address = 0x00000004;
2330 ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0);
2331 packet.data |= 0x17;
2332 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2334 /* Init BAR 0 (VRAM) */
2335 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2336 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2337 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2338 tmp32 &= 0x0f;
2339 tmp32 |= SISUSB_PCI_MEMBASE;
2340 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2342 /* Init BAR 1 (MMIO) */
2343 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2344 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2345 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2346 tmp32 &= 0x0f;
2347 tmp32 |= SISUSB_PCI_MMIOBASE;
2348 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2350 /* Init BAR 2 (i/o ports) */
2351 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2352 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2353 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2354 tmp32 &= 0x0f;
2355 tmp32 |= SISUSB_PCI_IOPORTBASE;
2356 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2358 /* Enable memory and i/o access */
2359 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2360 tmp32 |= 0x3;
2361 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2363 if (ret == 0) {
2364 /* Some further magic */
2365 packet.header = 0x001f;
2366 packet.address = 0x00000050;
2367 packet.data = 0x000000ff;
2368 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2371 return ret;
2374 /* Initialize the graphics device (return 0 on success)
2375 * This initializes the net2280 as well as the PCI registers
2376 * of the graphics board.
2379 static int
2380 sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2382 int ret = 0, test = 0;
2383 u32 tmp32;
2385 if (sisusb->devinit == 1) {
2386 /* Read PCI BARs and see if they have been set up */
2387 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2388 if (ret) return ret;
2389 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++;
2391 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2392 if (ret) return ret;
2393 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2395 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2396 if (ret) return ret;
2397 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2400 /* No? So reset the device */
2401 if ((sisusb->devinit == 0) || (test != 3)) {
2403 ret |= sisusb_do_init_gfxdevice(sisusb);
2405 if (ret == 0)
2406 sisusb->devinit = 1;
2410 if (sisusb->devinit) {
2411 /* Initialize the graphics core */
2412 if (sisusb_init_gfxcore(sisusb) == 0) {
2413 sisusb->gfxinit = 1;
2414 sisusb_get_ramconfig(sisusb);
2415 ret |= sisusb_set_default_mode(sisusb, 1);
2416 ret |= sisusb_setup_screen(sisusb, 1, initscreen);
2420 return ret;
2424 #ifdef INCL_SISUSB_CON
2426 /* Set up default text mode:
2427 - Set text mode (0x03)
2428 - Upload default font
2429 - Upload user font (if available)
2433 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
2435 int ret = 0, slot = sisusb->font_slot, i;
2436 const struct font_desc *myfont;
2437 u8 *tempbuf;
2438 u16 *tempbufb;
2439 size_t written;
2440 static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
2441 static const char bootlogo[] = "(o_ //\\ V_/_";
2443 /* sisusb->lock is down */
2445 if (!sisusb->SiS_Pr)
2446 return 1;
2448 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
2449 sisusb->SiS_Pr->sisusb = (void *)sisusb;
2451 /* Set mode 0x03 */
2452 SiSUSBSetMode(sisusb->SiS_Pr, 0x03);
2454 if (!(myfont = find_font("VGA8x16")))
2455 return 1;
2457 if (!(tempbuf = vmalloc(8192)))
2458 return 1;
2460 for (i = 0; i < 256; i++)
2461 memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16);
2463 /* Upload default font */
2464 ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0);
2466 vfree(tempbuf);
2468 /* Upload user font (and reset current slot) */
2469 if (sisusb->font_backup) {
2470 ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup,
2471 8192, sisusb->font_backup_512, 1, NULL,
2472 sisusb->font_backup_height, 0);
2473 if (slot != 2)
2474 sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1,
2475 NULL, 16, 0);
2478 if (init && !sisusb->scrbuf) {
2480 if ((tempbuf = vmalloc(8192))) {
2482 i = 4096;
2483 tempbufb = (u16 *)tempbuf;
2484 while (i--)
2485 *(tempbufb++) = 0x0720;
2487 i = 0;
2488 tempbufb = (u16 *)tempbuf;
2489 while (bootlogo[i]) {
2490 *(tempbufb++) = 0x0700 | bootlogo[i++];
2491 if (!(i % 4))
2492 tempbufb += 76;
2495 i = 0;
2496 tempbufb = (u16 *)tempbuf + 6;
2497 while (bootstring[i])
2498 *(tempbufb++) = 0x0700 | bootstring[i++];
2500 ret |= sisusb_copy_memory(sisusb, tempbuf,
2501 sisusb->vrambase, 8192, &written);
2503 vfree(tempbuf);
2507 } else if (sisusb->scrbuf) {
2509 ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
2510 sisusb->vrambase, sisusb->scrbuf_size, &written);
2514 if (sisusb->sisusb_cursor_size_from >= 0 &&
2515 sisusb->sisusb_cursor_size_to >= 0) {
2516 sisusb_setidxreg(sisusb, SISCR, 0x0a,
2517 sisusb->sisusb_cursor_size_from);
2518 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0,
2519 sisusb->sisusb_cursor_size_to);
2520 } else {
2521 sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d);
2522 sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e);
2523 sisusb->sisusb_cursor_size_to = -1;
2526 slot = sisusb->sisusb_cursor_loc;
2527 if(slot < 0) slot = 0;
2529 sisusb->sisusb_cursor_loc = -1;
2530 sisusb->bad_cursor_pos = 1;
2532 sisusb_set_cursor(sisusb, slot);
2534 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
2535 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
2537 sisusb->textmodedestroyed = 0;
2539 /* sisusb->lock is down */
2541 return ret;
2544 #endif
2546 /* fops */
2548 static int
2549 sisusb_open(struct inode *inode, struct file *file)
2551 struct sisusb_usb_data *sisusb;
2552 struct usb_interface *interface;
2553 int subminor = iminor(inode);
2555 down(&disconnect_sem);
2557 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
2558 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
2559 subminor);
2560 up(&disconnect_sem);
2561 return -ENODEV;
2564 if (!(sisusb = usb_get_intfdata(interface))) {
2565 up(&disconnect_sem);
2566 return -ENODEV;
2569 down(&sisusb->lock);
2571 if (!sisusb->present || !sisusb->ready) {
2572 up(&sisusb->lock);
2573 up(&disconnect_sem);
2574 return -ENODEV;
2577 if (sisusb->isopen) {
2578 up(&sisusb->lock);
2579 up(&disconnect_sem);
2580 return -EBUSY;
2583 if (!sisusb->devinit) {
2584 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2585 if (sisusb_init_gfxdevice(sisusb, 0)) {
2586 up(&sisusb->lock);
2587 up(&disconnect_sem);
2588 printk(KERN_ERR
2589 "sisusbvga[%d]: Failed to initialize "
2590 "device\n",
2591 sisusb->minor);
2592 return -EIO;
2594 } else {
2595 up(&sisusb->lock);
2596 up(&disconnect_sem);
2597 printk(KERN_ERR
2598 "sisusbvga[%d]: Device not attached to "
2599 "USB 2.0 hub\n",
2600 sisusb->minor);
2601 return -EIO;
2605 /* Increment usage count for our sisusb */
2606 kref_get(&sisusb->kref);
2608 sisusb->isopen = 1;
2610 file->private_data = sisusb;
2612 up(&sisusb->lock);
2614 up(&disconnect_sem);
2616 return 0;
2619 void
2620 sisusb_delete(struct kref *kref)
2622 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2624 if (!sisusb)
2625 return;
2627 if (sisusb->sisusb_dev)
2628 usb_put_dev(sisusb->sisusb_dev);
2630 sisusb->sisusb_dev = NULL;
2631 sisusb_free_buffers(sisusb);
2632 sisusb_free_urbs(sisusb);
2633 #ifdef INCL_SISUSB_CON
2634 kfree(sisusb->SiS_Pr);
2635 #endif
2636 kfree(sisusb);
2639 static int
2640 sisusb_release(struct inode *inode, struct file *file)
2642 struct sisusb_usb_data *sisusb;
2643 int myminor;
2645 down(&disconnect_sem);
2647 if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
2648 up(&disconnect_sem);
2649 return -ENODEV;
2652 down(&sisusb->lock);
2654 if (sisusb->present) {
2655 /* Wait for all URBs to finish if device still present */
2656 if (!sisusb_wait_all_out_complete(sisusb))
2657 sisusb_kill_all_busy(sisusb);
2660 myminor = sisusb->minor;
2662 sisusb->isopen = 0;
2663 file->private_data = NULL;
2665 up(&sisusb->lock);
2667 /* decrement the usage count on our device */
2668 kref_put(&sisusb->kref, sisusb_delete);
2670 up(&disconnect_sem);
2672 return 0;
2675 static ssize_t
2676 sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2678 struct sisusb_usb_data *sisusb;
2679 ssize_t bytes_read = 0;
2680 int errno = 0;
2681 u8 buf8;
2682 u16 buf16;
2683 u32 buf32, address;
2685 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2686 return -ENODEV;
2688 down(&sisusb->lock);
2690 /* Sanity check */
2691 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2692 up(&sisusb->lock);
2693 return -ENODEV;
2696 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2697 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2699 address = (*ppos) -
2700 SISUSB_PCI_PSEUDO_IOPORTBASE +
2701 SISUSB_PCI_IOPORTBASE;
2703 /* Read i/o ports
2704 * Byte, word and long(32) can be read. As this
2705 * emulates inX instructions, the data returned is
2706 * in machine-endianness.
2708 switch (count) {
2710 case 1:
2711 if (sisusb_read_memio_byte(sisusb,
2712 SISUSB_TYPE_IO,
2713 address, &buf8))
2714 errno = -EIO;
2715 else if (put_user(buf8, (u8 __user *)buffer))
2716 errno = -EFAULT;
2717 else
2718 bytes_read = 1;
2720 break;
2722 case 2:
2723 if (sisusb_read_memio_word(sisusb,
2724 SISUSB_TYPE_IO,
2725 address, &buf16))
2726 errno = -EIO;
2727 else if (put_user(buf16, (u16 __user *)buffer))
2728 errno = -EFAULT;
2729 else
2730 bytes_read = 2;
2732 break;
2734 case 4:
2735 if (sisusb_read_memio_long(sisusb,
2736 SISUSB_TYPE_IO,
2737 address, &buf32))
2738 errno = -EIO;
2739 else if (put_user(buf32, (u32 __user *)buffer))
2740 errno = -EFAULT;
2741 else
2742 bytes_read = 4;
2744 break;
2746 default:
2747 errno = -EIO;
2751 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2752 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2754 address = (*ppos) -
2755 SISUSB_PCI_PSEUDO_MEMBASE +
2756 SISUSB_PCI_MEMBASE;
2758 /* Read video ram
2759 * Remember: Data delivered is never endian-corrected
2761 errno = sisusb_read_mem_bulk(sisusb, address,
2762 NULL, count, buffer, &bytes_read);
2764 if (bytes_read)
2765 errno = bytes_read;
2767 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2768 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2770 address = (*ppos) -
2771 SISUSB_PCI_PSEUDO_MMIOBASE +
2772 SISUSB_PCI_MMIOBASE;
2774 /* Read MMIO
2775 * Remember: Data delivered is never endian-corrected
2777 errno = sisusb_read_mem_bulk(sisusb, address,
2778 NULL, count, buffer, &bytes_read);
2780 if (bytes_read)
2781 errno = bytes_read;
2783 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2784 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2786 if (count != 4) {
2787 up(&sisusb->lock);
2788 return -EINVAL;
2791 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2793 /* Read PCI config register
2794 * Return value delivered in machine endianness.
2796 if (sisusb_read_pci_config(sisusb, address, &buf32))
2797 errno = -EIO;
2798 else if (put_user(buf32, (u32 __user *)buffer))
2799 errno = -EFAULT;
2800 else
2801 bytes_read = 4;
2803 } else {
2805 errno = -EBADFD;
2809 (*ppos) += bytes_read;
2811 up(&sisusb->lock);
2813 return errno ? errno : bytes_read;
2816 static ssize_t
2817 sisusb_write(struct file *file, const char __user *buffer, size_t count,
2818 loff_t *ppos)
2820 struct sisusb_usb_data *sisusb;
2821 int errno = 0;
2822 ssize_t bytes_written = 0;
2823 u8 buf8;
2824 u16 buf16;
2825 u32 buf32, address;
2827 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2828 return -ENODEV;
2830 down(&sisusb->lock);
2832 /* Sanity check */
2833 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2834 up(&sisusb->lock);
2835 return -ENODEV;
2838 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2839 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2841 address = (*ppos) -
2842 SISUSB_PCI_PSEUDO_IOPORTBASE +
2843 SISUSB_PCI_IOPORTBASE;
2845 /* Write i/o ports
2846 * Byte, word and long(32) can be written. As this
2847 * emulates outX instructions, the data is expected
2848 * in machine-endianness.
2850 switch (count) {
2852 case 1:
2853 if (get_user(buf8, (u8 __user *)buffer))
2854 errno = -EFAULT;
2855 else if (sisusb_write_memio_byte(sisusb,
2856 SISUSB_TYPE_IO,
2857 address, buf8))
2858 errno = -EIO;
2859 else
2860 bytes_written = 1;
2862 break;
2864 case 2:
2865 if (get_user(buf16, (u16 __user *)buffer))
2866 errno = -EFAULT;
2867 else if (sisusb_write_memio_word(sisusb,
2868 SISUSB_TYPE_IO,
2869 address, buf16))
2870 errno = -EIO;
2871 else
2872 bytes_written = 2;
2874 break;
2876 case 4:
2877 if (get_user(buf32, (u32 __user *)buffer))
2878 errno = -EFAULT;
2879 else if (sisusb_write_memio_long(sisusb,
2880 SISUSB_TYPE_IO,
2881 address, buf32))
2882 errno = -EIO;
2883 else
2884 bytes_written = 4;
2886 break;
2888 default:
2889 errno = -EIO;
2892 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2893 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2895 address = (*ppos) -
2896 SISUSB_PCI_PSEUDO_MEMBASE +
2897 SISUSB_PCI_MEMBASE;
2899 /* Write video ram.
2900 * Buffer is copied 1:1, therefore, on big-endian
2901 * machines, the data must be swapped by userland
2902 * in advance (if applicable; no swapping in 8bpp
2903 * mode or if YUV data is being transferred).
2905 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2906 count, buffer, 0, &bytes_written);
2908 if (bytes_written)
2909 errno = bytes_written;
2911 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2912 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2914 address = (*ppos) -
2915 SISUSB_PCI_PSEUDO_MMIOBASE +
2916 SISUSB_PCI_MMIOBASE;
2918 /* Write MMIO.
2919 * Buffer is copied 1:1, therefore, on big-endian
2920 * machines, the data must be swapped by userland
2921 * in advance.
2923 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2924 count, buffer, 0, &bytes_written);
2926 if (bytes_written)
2927 errno = bytes_written;
2929 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2930 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2932 if (count != 4) {
2933 up(&sisusb->lock);
2934 return -EINVAL;
2937 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2939 /* Write PCI config register.
2940 * Given value expected in machine endianness.
2942 if (get_user(buf32, (u32 __user *)buffer))
2943 errno = -EFAULT;
2944 else if (sisusb_write_pci_config(sisusb, address, buf32))
2945 errno = -EIO;
2946 else
2947 bytes_written = 4;
2950 } else {
2952 /* Error */
2953 errno = -EBADFD;
2957 (*ppos) += bytes_written;
2959 up(&sisusb->lock);
2961 return errno ? errno : bytes_written;
2964 static loff_t
2965 sisusb_lseek(struct file *file, loff_t offset, int orig)
2967 struct sisusb_usb_data *sisusb;
2968 loff_t ret;
2970 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2971 return -ENODEV;
2973 down(&sisusb->lock);
2975 /* Sanity check */
2976 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2977 up(&sisusb->lock);
2978 return -ENODEV;
2981 switch (orig) {
2982 case 0:
2983 file->f_pos = offset;
2984 ret = file->f_pos;
2985 /* never negative, no force_successful_syscall needed */
2986 break;
2987 case 1:
2988 file->f_pos += offset;
2989 ret = file->f_pos;
2990 /* never negative, no force_successful_syscall needed */
2991 break;
2992 default:
2993 /* seeking relative to "end of file" is not supported */
2994 ret = -EINVAL;
2997 up(&sisusb->lock);
2998 return ret;
3001 static int
3002 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
3003 unsigned long arg)
3005 int retval, port, length;
3006 u32 address;
3008 /* All our commands require the device
3009 * to be initialized.
3011 if (!sisusb->devinit)
3012 return -ENODEV;
3014 port = y->data3 -
3015 SISUSB_PCI_PSEUDO_IOPORTBASE +
3016 SISUSB_PCI_IOPORTBASE;
3018 switch (y->operation) {
3019 case SUCMD_GET:
3020 retval = sisusb_getidxreg(sisusb, port,
3021 y->data0, &y->data1);
3022 if (!retval) {
3023 if (copy_to_user((void __user *)arg, y,
3024 sizeof(*y)))
3025 retval = -EFAULT;
3027 break;
3029 case SUCMD_SET:
3030 retval = sisusb_setidxreg(sisusb, port,
3031 y->data0, y->data1);
3032 break;
3034 case SUCMD_SETOR:
3035 retval = sisusb_setidxregor(sisusb, port,
3036 y->data0, y->data1);
3037 break;
3039 case SUCMD_SETAND:
3040 retval = sisusb_setidxregand(sisusb, port,
3041 y->data0, y->data1);
3042 break;
3044 case SUCMD_SETANDOR:
3045 retval = sisusb_setidxregandor(sisusb, port,
3046 y->data0, y->data1, y->data2);
3047 break;
3049 case SUCMD_SETMASK:
3050 retval = sisusb_setidxregmask(sisusb, port,
3051 y->data0, y->data1, y->data2);
3052 break;
3054 case SUCMD_CLRSCR:
3055 /* Gfx core must be initialized */
3056 if (!sisusb->gfxinit)
3057 return -ENODEV;
3059 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
3060 address = y->data3 -
3061 SISUSB_PCI_PSEUDO_MEMBASE +
3062 SISUSB_PCI_MEMBASE;
3063 retval = sisusb_clear_vram(sisusb, address, length);
3064 break;
3066 case SUCMD_HANDLETEXTMODE:
3067 retval = 0;
3068 #ifdef INCL_SISUSB_CON
3069 /* Gfx core must be initialized, SiS_Pr must exist */
3070 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3071 return -ENODEV;
3073 switch (y->data0) {
3074 case 0:
3075 retval = sisusb_reset_text_mode(sisusb, 0);
3076 break;
3077 case 1:
3078 sisusb->textmodedestroyed = 1;
3079 break;
3081 #endif
3082 break;
3084 #ifdef INCL_SISUSB_CON
3085 case SUCMD_SETMODE:
3086 /* Gfx core must be initialized, SiS_Pr must exist */
3087 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3088 return -ENODEV;
3090 retval = 0;
3092 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3093 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3095 if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3))
3096 retval = -EINVAL;
3098 break;
3100 case SUCMD_SETVESAMODE:
3101 /* Gfx core must be initialized, SiS_Pr must exist */
3102 if (!sisusb->gfxinit || !sisusb->SiS_Pr)
3103 return -ENODEV;
3105 retval = 0;
3107 sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30;
3108 sisusb->SiS_Pr->sisusb = (void *)sisusb;
3110 if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3))
3111 retval = -EINVAL;
3113 break;
3114 #endif
3116 default:
3117 retval = -EINVAL;
3120 if (retval > 0)
3121 retval = -EIO;
3123 return retval;
3126 static int
3127 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
3128 unsigned long arg)
3130 struct sisusb_usb_data *sisusb;
3131 struct sisusb_info x;
3132 struct sisusb_command y;
3133 int retval = 0;
3134 u32 __user *argp = (u32 __user *)arg;
3136 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
3137 return -ENODEV;
3139 down(&sisusb->lock);
3141 /* Sanity check */
3142 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
3143 retval = -ENODEV;
3144 goto err_out;
3147 switch (cmd) {
3149 case SISUSB_GET_CONFIG_SIZE:
3151 if (put_user(sizeof(x), argp))
3152 retval = -EFAULT;
3154 break;
3156 case SISUSB_GET_CONFIG:
3158 x.sisusb_id = SISUSB_ID;
3159 x.sisusb_version = SISUSB_VERSION;
3160 x.sisusb_revision = SISUSB_REVISION;
3161 x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
3162 x.sisusb_gfxinit = sisusb->gfxinit;
3163 x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE;
3164 x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE;
3165 x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE;
3166 x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE;
3167 x.sisusb_vramsize = sisusb->vramsize;
3168 x.sisusb_minor = sisusb->minor;
3169 x.sisusb_fbdevactive= 0;
3170 #ifdef INCL_SISUSB_CON
3171 x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
3172 #else
3173 x.sisusb_conactive = 0;
3174 #endif
3176 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
3177 retval = -EFAULT;
3179 break;
3181 case SISUSB_COMMAND:
3183 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
3184 retval = -EFAULT;
3185 else
3186 retval = sisusb_handle_command(sisusb, &y, arg);
3188 break;
3190 default:
3191 retval = -ENOTTY;
3192 break;
3195 err_out:
3196 up(&sisusb->lock);
3197 return retval;
3200 #ifdef SISUSB_NEW_CONFIG_COMPAT
3201 static long
3202 sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
3204 long retval;
3206 switch (cmd) {
3207 case SISUSB_GET_CONFIG_SIZE:
3208 case SISUSB_GET_CONFIG:
3209 case SISUSB_COMMAND:
3210 lock_kernel();
3211 retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
3212 unlock_kernel();
3213 return retval;
3215 default:
3216 return -ENOIOCTLCMD;
3219 #endif
3221 static struct file_operations usb_sisusb_fops = {
3222 .owner = THIS_MODULE,
3223 .open = sisusb_open,
3224 .release = sisusb_release,
3225 .read = sisusb_read,
3226 .write = sisusb_write,
3227 .llseek = sisusb_lseek,
3228 #ifdef SISUSB_NEW_CONFIG_COMPAT
3229 .compat_ioctl = sisusb_compat_ioctl,
3230 #endif
3231 .ioctl = sisusb_ioctl
3234 static struct usb_class_driver usb_sisusb_class = {
3235 .name = "sisusbvga%d",
3236 .fops = &usb_sisusb_fops,
3237 .minor_base = SISUSB_MINOR
3240 static int sisusb_probe(struct usb_interface *intf,
3241 const struct usb_device_id *id)
3243 struct usb_device *dev = interface_to_usbdev(intf);
3244 struct sisusb_usb_data *sisusb;
3245 int retval = 0, i;
3246 const char *memfail =
3247 KERN_ERR
3248 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
3250 printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
3251 dev->devnum);
3253 /* Allocate memory for our private */
3254 if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
3255 printk(KERN_ERR
3256 "sisusb: Failed to allocate memory for private data\n");
3257 return -ENOMEM;
3259 kref_init(&sisusb->kref);
3261 init_MUTEX(&(sisusb->lock));
3263 /* Register device */
3264 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
3265 printk(KERN_ERR
3266 "sisusb: Failed to get a minor for device %d\n",
3267 dev->devnum);
3268 retval = -ENODEV;
3269 goto error_1;
3272 sisusb->sisusb_dev = dev;
3273 sisusb->minor = intf->minor;
3274 sisusb->vrambase = SISUSB_PCI_MEMBASE;
3275 sisusb->mmiobase = SISUSB_PCI_MMIOBASE;
3276 sisusb->mmiosize = SISUSB_PCI_MMIOSIZE;
3277 sisusb->ioportbase = SISUSB_PCI_IOPORTBASE;
3278 /* Everything else is zero */
3280 /* Allocate buffers */
3281 sisusb->ibufsize = SISUSB_IBUF_SIZE;
3282 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
3283 GFP_KERNEL, &sisusb->transfer_dma_in))) {
3284 printk(memfail, "input", sisusb->minor);
3285 retval = -ENOMEM;
3286 goto error_2;
3289 sisusb->numobufs = 0;
3290 sisusb->obufsize = SISUSB_OBUF_SIZE;
3291 for (i = 0; i < NUMOBUFS; i++) {
3292 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
3293 GFP_KERNEL,
3294 &sisusb->transfer_dma_out[i]))) {
3295 if (i == 0) {
3296 printk(memfail, "output", sisusb->minor);
3297 retval = -ENOMEM;
3298 goto error_3;
3300 break;
3301 } else
3302 sisusb->numobufs++;
3306 /* Allocate URBs */
3307 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
3308 printk(KERN_ERR
3309 "sisusbvga[%d]: Failed to allocate URBs\n",
3310 sisusb->minor);
3311 retval = -ENOMEM;
3312 goto error_3;
3314 sisusb->completein = 1;
3316 for (i = 0; i < sisusb->numobufs; i++) {
3317 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
3318 printk(KERN_ERR
3319 "sisusbvga[%d]: Failed to allocate URBs\n",
3320 sisusb->minor);
3321 retval = -ENOMEM;
3322 goto error_4;
3324 sisusb->urbout_context[i].sisusb = (void *)sisusb;
3325 sisusb->urbout_context[i].urbindex = i;
3326 sisusb->urbstatus[i] = 0;
3329 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
3330 sisusb->minor, sisusb->numobufs);
3332 #ifdef INCL_SISUSB_CON
3333 /* Allocate our SiS_Pr */
3334 if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
3335 printk(KERN_ERR
3336 "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
3337 sisusb->minor);
3339 #endif
3341 /* Do remaining init stuff */
3343 init_waitqueue_head(&sisusb->wait_q);
3345 usb_set_intfdata(intf, sisusb);
3347 usb_get_dev(sisusb->sisusb_dev);
3349 sisusb->present = 1;
3351 #ifdef SISUSB_OLD_CONFIG_COMPAT
3353 int ret;
3354 /* Our ioctls are all "32/64bit compatible" */
3355 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3356 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3357 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3358 if (ret)
3359 printk(KERN_ERR
3360 "sisusbvga[%d]: Error registering ioctl32 "
3361 "translations\n",
3362 sisusb->minor);
3363 else
3364 sisusb->ioctl32registered = 1;
3366 #endif
3368 if (dev->speed == USB_SPEED_HIGH) {
3369 int initscreen = 1;
3370 #ifdef INCL_SISUSB_CON
3371 if (sisusb_first_vc > 0 &&
3372 sisusb_last_vc > 0 &&
3373 sisusb_first_vc <= sisusb_last_vc &&
3374 sisusb_last_vc <= MAX_NR_CONSOLES)
3375 initscreen = 0;
3376 #endif
3377 if (sisusb_init_gfxdevice(sisusb, initscreen))
3378 printk(KERN_ERR
3379 "sisusbvga[%d]: Failed to early "
3380 "initialize device\n",
3381 sisusb->minor);
3383 } else
3384 printk(KERN_INFO
3385 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3386 "deferring init\n",
3387 sisusb->minor);
3389 sisusb->ready = 1;
3391 #ifdef SISUSBENDIANTEST
3392 printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
3393 sisusb_testreadwrite(sisusb);
3394 printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
3395 #endif
3397 #ifdef INCL_SISUSB_CON
3398 sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc);
3399 #endif
3401 return 0;
3403 error_4:
3404 sisusb_free_urbs(sisusb);
3405 error_3:
3406 sisusb_free_buffers(sisusb);
3407 error_2:
3408 usb_deregister_dev(intf, &usb_sisusb_class);
3409 error_1:
3410 kfree(sisusb);
3411 return retval;
3414 static void sisusb_disconnect(struct usb_interface *intf)
3416 struct sisusb_usb_data *sisusb;
3417 int minor;
3419 /* This should *not* happen */
3420 if (!(sisusb = usb_get_intfdata(intf)))
3421 return;
3423 #ifdef INCL_SISUSB_CON
3424 sisusb_console_exit(sisusb);
3425 #endif
3427 /* The above code doesn't need the disconnect
3428 * semaphore to be down; its meaning is to
3429 * protect all other routines from the disconnect
3430 * case, not the other way round.
3432 down(&disconnect_sem);
3434 down(&sisusb->lock);
3436 /* Wait for all URBs to complete and kill them in case (MUST do) */
3437 if (!sisusb_wait_all_out_complete(sisusb))
3438 sisusb_kill_all_busy(sisusb);
3440 minor = sisusb->minor;
3442 usb_set_intfdata(intf, NULL);
3444 usb_deregister_dev(intf, &usb_sisusb_class);
3446 #ifdef SISUSB_OLD_CONFIG_COMPAT
3447 if (sisusb->ioctl32registered) {
3448 int ret;
3449 sisusb->ioctl32registered = 0;
3450 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3451 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3452 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3453 if (ret) {
3454 printk(KERN_ERR
3455 "sisusbvga[%d]: Error unregistering "
3456 "ioctl32 translations\n",
3457 minor);
3460 #endif
3462 sisusb->present = 0;
3463 sisusb->ready = 0;
3465 up(&sisusb->lock);
3467 /* decrement our usage count */
3468 kref_put(&sisusb->kref, sisusb_delete);
3470 up(&disconnect_sem);
3472 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
3475 static struct usb_device_id sisusb_table [] = {
3476 { USB_DEVICE(0x0711, 0x0900) },
3477 { USB_DEVICE(0x182d, 0x021c) },
3478 { USB_DEVICE(0x182d, 0x0269) },
3482 MODULE_DEVICE_TABLE (usb, sisusb_table);
3484 static struct usb_driver sisusb_driver = {
3485 .name = "sisusb",
3486 .probe = sisusb_probe,
3487 .disconnect = sisusb_disconnect,
3488 .id_table = sisusb_table,
3491 static int __init usb_sisusb_init(void)
3493 int retval;
3495 #ifdef INCL_SISUSB_CON
3496 sisusb_init_concode();
3497 #endif
3499 if (!(retval = usb_register(&sisusb_driver))) {
3501 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3502 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3503 printk(KERN_INFO
3504 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3508 return retval;
3511 static void __exit usb_sisusb_exit(void)
3513 usb_deregister(&sisusb_driver);
3516 module_init(usb_sisusb_init);
3517 module_exit(usb_sisusb_exit);
3519 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3520 MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
3521 MODULE_LICENSE("GPL");