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
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
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.
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>
54 #define SISUSB_DONTSYNC
56 /* Forward declarations / clean-up routines */
58 static struct usb_driver sisusb_driver
;
60 static DECLARE_MUTEX(disconnect_sem
);
63 sisusb_free_buffers(struct sisusb_usb_data
*sisusb
)
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
;
75 usb_buffer_free(sisusb
->sisusb_dev
, sisusb
->ibufsize
,
76 sisusb
->ibuf
, sisusb
->transfer_dma_in
);
82 sisusb_free_urbs(struct sisusb_usb_data
*sisusb
)
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 */
98 /* out-urb management */
100 /* Return 1 if all free, 0 otherwise */
102 sisusb_all_free(struct sisusb_usb_data
*sisusb
)
106 for (i
= 0; i
< sisusb
->numobufs
; i
++) {
108 if (sisusb
->urbstatus
[i
] & SU_URB_BUSY
)
116 /* Kill all busy URBs */
118 sisusb_kill_all_busy(struct sisusb_usb_data
*sisusb
)
122 if (sisusb_all_free(sisusb
))
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) */
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
)),
147 sisusb_outurb_available(struct sisusb_usb_data
*sisusb
)
151 for (i
= 0; i
< sisusb
->numobufs
; i
++) {
153 if ((sisusb
->urbstatus
[i
] & (SU_URB_BUSY
|SU_URB_ALLOC
)) == 0)
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),
174 sisusb_alloc_outbuf(struct sisusb_usb_data
*sisusb
)
178 i
= sisusb_outurb_available(sisusb
);
181 sisusb
->urbstatus
[i
] |= SU_URB_ALLOC
;
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 */
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
;
204 sisusb
= context
->sisusb
;
206 if (!sisusb
|| !sisusb
->sisusb_dev
|| !sisusb
->present
)
209 #ifndef SISUSB_DONTSYNC
210 if (context
->actual_length
)
211 *(context
->actual_length
) += urb
->actual_length
;
214 sisusb
->urbstatus
[context
->urbindex
] &= ~SU_URB_BUSY
;
215 wake_up(&sisusb
->wait_q
);
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;
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
;
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
;
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
)),
253 if (sisusb
->urbstatus
[index
] & SU_URB_BUSY
) {
254 /* URB timed out... kill it and report error */
258 /* Otherwise, report urb status */
259 retval
= urb
->status
;
260 byteswritten
= urb
->actual_length
;
265 *actual_length
= byteswritten
;
272 /* completion callback */
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
)
282 sisusb
->completein
= 1;
283 wake_up(&sisusb
->wait_q
);
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
);
307 wait_event_timeout(sisusb
->wait_q
, sisusb
->completein
, timeout
);
308 if (!sisusb
->completein
) {
309 /* URB timed out... kill it and report error */
313 /* URB completed within timout */
314 retval
= urb
->status
;
315 readbytes
= urb
->actual_length
;
320 *actual_length
= readbytes
;
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;
352 (*bytes_written
) = 0;
355 if (!sisusb
|| !sisusb
->present
|| !sisusb
->sisusb_dev
)
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
)
368 else if (len
> sisusb
->obufsize
)
371 pipe
= usb_sndbulkpipe(sisusb
->sisusb_dev
, ep
);
374 passsize
= thispass
= (sisusb
->obufsize
< count
) ?
375 sisusb
->obufsize
: count
;
378 index
= sisusb_get_free_outbuf(sisusb
);
383 buffer
= sisusb
->obuf
[index
];
387 if (copy_from_user(buffer
, userbuffer
, passsize
))
390 userbuffer
+= passsize
;
392 } else if (fromkern
) {
394 memcpy(buffer
, kernbuffer
, passsize
);
395 kernbuffer
+= passsize
;
402 if (!sisusb
->sisusb_dev
)
405 result
= sisusb_bulkout_msg(sisusb
,
413 sisusb
->transfer_dma_out
[index
]);
415 if (result
== -ETIMEDOUT
) {
417 /* Will not happen if async */
423 } else if ((result
== 0) && !async
&& transferred_len
) {
425 thispass
-= transferred_len
;
427 if (sisusb
->transfer_dma_out
) {
428 /* If DMA, copy remaining
429 * to beginning of buffer
432 buffer
+ transferred_len
,
435 /* If not DMA, simply increase
438 buffer
+= transferred_len
;
449 (*bytes_written
) += passsize
;
452 /* Force new allocation in next iteration */
453 if (fromuser
|| fromkern
)
459 #ifdef SISUSB_DONTSYNC
460 (*bytes_written
) = len
;
461 /* Some URBs/buffers might be busy */
463 sisusb_wait_all_out_complete(sisusb
);
464 (*bytes_written
) = transferred_len
;
465 /* All URBs and all buffers are available */
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
,
485 int result
= 0, retry
, count
= len
;
486 int bufsize
, thispass
, transferred_len
;
493 if (!sisusb
|| !sisusb
->present
|| !sisusb
->sisusb_dev
)
496 pipe
= usb_rcvbulkpipe(sisusb
->sisusb_dev
, ep
);
497 buffer
= sisusb
->ibuf
;
498 bufsize
= sisusb
->ibufsize
;
502 #ifdef SISUSB_DONTSYNC
503 if (!(sisusb_wait_all_out_complete(sisusb
)))
509 if (!sisusb
->sisusb_dev
)
512 thispass
= (bufsize
< count
) ? bufsize
: count
;
514 result
= sisusb_bulkin_msg(sisusb
,
521 sisusb
->transfer_dma_in
);
524 thispass
= transferred_len
;
526 else if (result
== -ETIMEDOUT
) {
539 (*bytes_read
) += thispass
;
544 if (copy_to_user(userbuffer
, buffer
, thispass
))
547 userbuffer
+= thispass
;
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
)
567 ssize_t bytes_transferred
= 0;
573 #ifdef SISUSB_DONTSYNC
574 if (!(sisusb_wait_all_out_complete(sisusb
)))
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
);
599 static int sisusb_send_bridge_packet(struct sisusb_usb_data
*sisusb
, int len
,
600 struct sisusb_packet
*packet
,
604 ssize_t bytes_transferred
= 0;
610 #ifdef SISUSB_DONTSYNC
611 if (!(sisusb_wait_all_out_complete(sisusb
)))
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
);
636 /* access video memory and mmio (return 0 on success) */
640 /* The following routines assume being used to transfer byte, word,
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
,
648 struct sisusb_packet packet
;
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
);
658 static int sisusb_write_memio_word(struct sisusb_usb_data
*sisusb
, int type
,
661 struct sisusb_packet packet
;
664 packet
.address
= addr
& ~3;
668 packet
.header
= (type
<< 6) | 0x0003;
669 packet
.data
= (u32
)data
;
670 ret
= sisusb_send_packet(sisusb
, 10, &packet
);
673 packet
.header
= (type
<< 6) | 0x0006;
674 packet
.data
= (u32
)data
<< 8;
675 ret
= sisusb_send_packet(sisusb
, 10, &packet
);
678 packet
.header
= (type
<< 6) | 0x000c;
679 packet
.data
= (u32
)data
<< 16;
680 ret
= sisusb_send_packet(sisusb
, 10, &packet
);
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
);
695 static int sisusb_write_memio_24bit(struct sisusb_usb_data
*sisusb
, int type
,
698 struct sisusb_packet packet
;
701 packet
.address
= addr
& ~3;
705 packet
.header
= (type
<< 6) | 0x0007;
706 packet
.data
= data
& 0x00ffffff;
707 ret
= sisusb_send_packet(sisusb
, 10, &packet
);
710 packet
.header
= (type
<< 6) | 0x000e;
711 packet
.data
= data
<< 8;
712 ret
= sisusb_send_packet(sisusb
, 10, &packet
);
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
);
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
);
736 static int sisusb_write_memio_long(struct sisusb_usb_data
*sisusb
, int type
,
739 struct sisusb_packet packet
;
742 packet
.address
= addr
& ~3;
746 packet
.header
= (type
<< 6) | 0x000f;
748 ret
= sisusb_send_packet(sisusb
, 10, &packet
);
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
);
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
);
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
);
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
;
798 static int msgcount
= 0;
799 u8 swap8
, fromkern
= kernbuffer
? 1 : 0;
801 u32 swap32
, flag
= (length
>> 28) & 1;
804 /* if neither kernbuffer not userbuffer are given, assume
807 if (!fromkern
&& !userbuffer
)
808 kernbuffer
= sisusb
->obuf
[index
];
810 (*bytes_written
= 0);
812 length
&= 0x00ffffff;
823 if (get_user(swap8
, (u8 __user
*)userbuffer
))
826 swap8
= kernbuffer
[0];
828 ret
= sisusb_write_memio_byte(sisusb
,
839 if (get_user(swap16
, (u16 __user
*)userbuffer
))
842 swap16
= (kernbuffer
[0] << 8) | kernbuffer
[1];
844 ret
= sisusb_write_memio_word(sisusb
,
850 (*bytes_written
) += 2;
856 if (copy_from_user(&buf
, userbuffer
, 3))
859 swap32
= (buf
[0] << 16) |
863 swap32
= (kernbuffer
[0] << 16) |
864 (kernbuffer
[1] << 8) |
867 ret
= sisusb_write_memio_24bit(sisusb
,
873 (*bytes_written
) += 3;
879 if (get_user(swap32
, (u32 __user
*)userbuffer
))
882 swap32
= (kernbuffer
[0] << 24) |
883 (kernbuffer
[1] << 16) |
884 (kernbuffer
[2] << 8) |
887 ret
= sisusb_write_memio_long(sisusb
,
892 (*bytes_written
) += 4;
897 if ((length
& ~3) > 0x10000) {
899 packet
.header
= 0x001f;
900 packet
.address
= 0x000001d4;
902 ret
= sisusb_send_bridge_packet(sisusb
, 10,
904 packet
.header
= 0x001f;
905 packet
.address
= 0x000001d0;
906 packet
.data
= (length
& ~3);
907 ret
|= sisusb_send_bridge_packet(sisusb
, 10,
909 packet
.header
= 0x001f;
910 packet
.address
= 0x000001c0;
911 packet
.data
= flag
| 0x16;
912 ret
|= sisusb_send_bridge_packet(sisusb
, 10,
915 ret
|= sisusb_send_bulk_msg(sisusb
,
916 SISUSB_EP_GFX_LBULK_OUT
,
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
,
926 bytes_written
, 0, 1);
927 kernbuffer
+= (*bytes_written
);
929 ret
|= sisusb_send_bulk_msg(sisusb
,
930 SISUSB_EP_GFX_LBULK_OUT
,
933 bytes_written
, 0, 1);
934 kernbuffer
+= ((*bytes_written
) &
935 (sisusb
->obufsize
-1));
940 packet
.header
= 0x001f;
941 packet
.address
= 0x00000194;
943 ret
= sisusb_send_bridge_packet(sisusb
, 10,
945 packet
.header
= 0x001f;
946 packet
.address
= 0x00000190;
947 packet
.data
= (length
& ~3);
948 ret
|= sisusb_send_bridge_packet(sisusb
, 10,
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,
956 sisusb
->flagb0
= 0x16;
959 ret
|= sisusb_send_bulk_msg(sisusb
,
960 SISUSB_EP_GFX_BULK_OUT
,
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
,
970 bytes_written
, 0, 1);
971 kernbuffer
+= (*bytes_written
);
973 ret
|= sisusb_send_bulk_msg(sisusb
,
974 SISUSB_EP_GFX_BULK_OUT
,
977 bytes_written
, 0, 1);
978 kernbuffer
+= ((*bytes_written
) &
979 (sisusb
->obufsize
-1));
986 "sisusbvga[%d]: Wrote %Zd of "
987 "%d bytes, error %d\n",
988 sisusb
->minor
, *bytes_written
,
990 else if (msgcount
== 500)
992 "sisusbvga[%d]: Too many errors"
993 ", logging stopped\n",
996 addr
+= (*bytes_written
);
997 length
-= (*bytes_written
);
1005 return ret
? -EIO
: 0;
1008 static int sisusb_read_memio_byte(struct sisusb_usb_data
*sisusb
, int type
,
1011 struct sisusb_packet packet
;
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));
1022 static int sisusb_read_memio_word(struct sisusb_usb_data
*sisusb
, int type
,
1023 u32 addr
, u16
*data
)
1025 struct sisusb_packet packet
;
1028 CLEARPACKET(&packet
);
1030 packet
.address
= addr
& ~3;
1034 packet
.header
= (type
<< 6) | 0x0003;
1035 ret
= sisusb_send_packet(sisusb
, 6, &packet
);
1036 *data
= (u16
)(packet
.data
);
1039 packet
.header
= (type
<< 6) | 0x0006;
1040 ret
= sisusb_send_packet(sisusb
, 6, &packet
);
1041 *data
= (u16
)(packet
.data
>> 8);
1044 packet
.header
= (type
<< 6) | 0x000c;
1045 ret
= sisusb_send_packet(sisusb
, 6, &packet
);
1046 *data
= (u16
)(packet
.data
>> 16);
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);
1061 static int sisusb_read_memio_24bit(struct sisusb_usb_data
*sisusb
, int type
,
1062 u32 addr
, u32
*data
)
1064 struct sisusb_packet packet
;
1067 packet
.address
= addr
& ~3;
1071 packet
.header
= (type
<< 6) | 0x0007;
1072 ret
= sisusb_send_packet(sisusb
, 6, &packet
);
1073 *data
= packet
.data
& 0x00ffffff;
1076 packet
.header
= (type
<< 6) | 0x000e;
1077 ret
= sisusb_send_packet(sisusb
, 6, &packet
);
1078 *data
= packet
.data
>> 8;
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);
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);
1102 static int sisusb_read_memio_long(struct sisusb_usb_data
*sisusb
, int type
,
1103 u32 addr
, u32
*data
)
1105 struct sisusb_packet packet
;
1108 packet
.address
= addr
& ~3;
1112 packet
.header
= (type
<< 6) | 0x000f;
1113 ret
= sisusb_send_packet(sisusb
, 6, &packet
);
1114 *data
= packet
.data
;
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);
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);
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);
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
)
1158 length
&= 0x00ffffff;
1169 ret
|= sisusb_read_memio_byte(sisusb
, SISUSB_TYPE_MEM
,
1174 if (put_user(buf
[0],
1175 (u8 __user
*)userbuffer
)) {
1179 kernbuffer
[0] = buf
[0];
1185 ret
|= sisusb_read_memio_word(sisusb
, SISUSB_TYPE_MEM
,
1190 if (put_user(swap16
,
1191 (u16 __user
*)userbuffer
))
1194 kernbuffer
[0] = swap16
>> 8;
1195 kernbuffer
[1] = swap16
& 0xff;
1201 ret
|= sisusb_read_memio_24bit(sisusb
, SISUSB_TYPE_MEM
,
1205 buf
[0] = (swap32
>> 16) & 0xff;
1206 buf
[1] = (swap32
>> 8) & 0xff;
1207 buf
[2] = swap32
& 0xff;
1209 if (copy_to_user(userbuffer
, &buf
[0], 3))
1212 kernbuffer
[0] = buf
[0];
1213 kernbuffer
[1] = buf
[1];
1214 kernbuffer
[2] = buf
[2];
1220 ret
|= sisusb_read_memio_long(sisusb
, SISUSB_TYPE_MEM
,
1225 if (put_user(swap32
,
1226 (u32 __user
*)userbuffer
))
1231 kernbuffer
[0] = (swap32
>> 24) & 0xff;
1232 kernbuffer
[1] = (swap32
>> 16) & 0xff;
1233 kernbuffer
[2] = (swap32
>> 8) & 0xff;
1234 kernbuffer
[3] = swap32
& 0xff;
1240 #if 0 /* That does not work, as EP 2 is an OUT EP! */
1242 CLEARPACKET(&packet
);
1243 packet
.header
= 0x001f;
1244 packet
.address
= 0x000001a0;
1245 packet
.data
= 0x00000006;
1246 ret
|= sisusb_send_bridge_packet(sisusb
, 10,
1248 packet
.header
= 0x001f;
1249 packet
.address
= 0x000001b0;
1250 packet
.data
= (length
& ~3) | 0x40000000;
1251 ret
|= sisusb_send_bridge_packet(sisusb
, 10,
1253 packet
.header
= 0x001f;
1254 packet
.address
= 0x000001b4;
1256 ret
|= sisusb_send_bridge_packet(sisusb
, 10,
1258 packet
.header
= 0x001f;
1259 packet
.address
= 0x000001a4;
1260 packet
.data
= 0x00000001;
1261 ret
|= sisusb_send_bridge_packet(sisusb
, 10,
1264 ret
|= sisusb_recv_bulk_msg(sisusb
,
1265 SISUSB_EP_GFX_BULK_IN
,
1269 if (!ret
) userbuffer
+= (*bytes_read
);
1271 ret
|= sisusb_recv_bulk_msg(sisusb
,
1272 SISUSB_EP_GFX_BULK_IN
,
1276 if (!ret
) kernbuffer
+= (*bytes_read
);
1278 addr
+= (*bytes_read
);
1279 length
-= (*bytes_read
);
1290 /* High level: Gfx (indexed) register access */
1293 sisusb_setidxreg(struct sisusb_usb_data
*sisusb
, int port
, u8 index
, u8 data
)
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
);
1302 sisusb_getidxreg(struct sisusb_usb_data
*sisusb
, int port
, u8 index
, u8
*data
)
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
);
1311 sisusb_setidxregandor(struct sisusb_usb_data
*sisusb
, int port
, u8 idx
,
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
);
1321 ret
|= sisusb_write_memio_byte(sisusb
, SISUSB_TYPE_IO
, port
+ 1, tmp
);
1326 sisusb_setidxregmask(struct sisusb_usb_data
*sisusb
, int port
, u8 idx
,
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
);
1334 tmp
|= (data
& mask
);
1335 ret
|= sisusb_write_memio_byte(sisusb
, SISUSB_TYPE_IO
, port
+ 1, tmp
);
1340 sisusb_setidxregor(struct sisusb_usb_data
*sisusb
, int port
, u8 index
, u8 myor
)
1342 return(sisusb_setidxregandor(sisusb
, port
, index
, 0xff, myor
));
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) */
1354 sisusb_write_pci_config(struct sisusb_usb_data
*sisusb
, int regnum
, u32 data
)
1356 struct sisusb_packet packet
;
1359 packet
.header
= 0x008f;
1360 packet
.address
= regnum
| 0x10000;
1362 ret
= sisusb_send_packet(sisusb
, 10, &packet
);
1367 sisusb_read_pci_config(struct sisusb_usb_data
*sisusb
, int regnum
, u32
*data
)
1369 struct sisusb_packet packet
;
1372 packet
.header
= 0x008f;
1373 packet
.address
= (u32
)regnum
| 0x10000;
1374 ret
= sisusb_send_packet(sisusb
, 6, &packet
);
1375 *data
= packet
.data
;
1379 /* Clear video RAM */
1382 sisusb_clear_vram(struct sisusb_usb_data
*sisusb
, u32 address
, int length
)
1387 if (address
< sisusb
->vrambase
)
1390 if (address
>= sisusb
->vrambase
+ sisusb
->vramsize
)
1393 if (address
+ length
> sisusb
->vrambase
+ sisusb
->vramsize
)
1394 length
= sisusb
->vrambase
+ sisusb
->vramsize
- address
;
1399 /* allocate free buffer/urb and clear the buffer */
1400 if ((i
= sisusb_alloc_outbuf(sisusb
)) < 0)
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
);
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)
1434 sisusb_triggersr16(struct sisusb_usb_data
*sisusb
, u8 ramtype
)
1439 ret
= GETIREG(SISSR
, 0x16, &tmp8
);
1442 ret
|= SETIREG(SISSR
, 0x16, tmp8
);
1444 ret
|= SETIREG(SISSR
, 0x16, tmp8
);
1447 ret
|= SETIREG(SISSR
, 0x16, tmp8
);
1449 ret
|= SETIREG(SISSR
, 0x16, tmp8
);
1451 ret
|= SETIREG(SISSR
, 0x16, tmp8
);
1453 ret
|= SETIREG(SISSR
, 0x16, tmp8
);
1455 ret
|= SETIREG(SISSR
, 0x16, tmp8
);
1457 ret
|= SETIREG(SISSR
, 0x16, tmp8
);
1459 ret
|= SETIREG(SISSR
, 0x16, tmp8
);
1465 sisusb_getbuswidth(struct sisusb_usb_data
*sisusb
, int *bw
, int *chab
)
1468 u8 ramtype
, done
= 0;
1470 u32 ramptr
= SISUSB_PCI_MEMBASE
;
1472 ret
= GETIREG(SISSR
, 0x3a, &ramtype
);
1475 ret
|= SETIREG(SISSR
, 0x13, 0x00);
1478 ret
|= SETIREG(SISSR
, 0x14, 0x12);
1479 ret
|= SETIREGAND(SISSR
, 0x15, 0xef);
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
);
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) {
1523 ret
|= SETIREGOR(SISSR
, 0x15, 0x10);
1529 *chab
= 0; *bw
= 64; /* default: cha, bw = 64 */
1533 if (t1
== 0x456789ab) {
1534 if (t0
== 0x01234567) {
1535 *chab
= 0; *bw
= 64;
1539 if (t0
== 0x01234567) {
1540 *chab
= 0; *bw
= 32;
1541 ret
|= SETIREG(SISSR
, 0x14, 0x00);
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;
1567 if (t0
== 0x01234567) {
1568 *chab
= 1; *bw
= 32;
1569 ret
|= SETIREG(SISSR
, 0x14, 0x01);
1578 sisusb_verify_mclk(struct sisusb_usb_data
*sisusb
)
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
);
1598 ret
|= WRITEB(ramptr
+ j
, j
);
1607 sisusb_set_rank(struct sisusb_usb_data
*sisusb
, int *iret
, int index
,
1608 u8 rankno
, u8 chab
, const u8 dramtype
[][5],
1611 int ret
= 0, ranksize
;
1616 if ((rankno
== 2) && (dramtype
[index
][0] == 2))
1619 ranksize
= dramtype
[index
][3] / 2 * bw
/ 32;
1621 if ((ranksize
* rankno
) > 128)
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! */
1639 sisusb_check_rbc(struct sisusb_usb_data
*sisusb
, int *iret
, u32 inc
, int testn
)
1646 for (i
= 0, j
= 0; i
< testn
; i
++) {
1647 ret
|= WRITEL(sisusb
->vrambase
+ j
, j
);
1651 for (i
= 0, j
= 0; i
< testn
; i
++) {
1652 ret
|= READL(sisusb
->vrambase
+ j
, &tmp
);
1653 if (tmp
!= j
) return ret
;
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
;
1670 for (i
= rankno
; i
>= 1; i
--) {
1671 inc
= 1 << (rtype
[idx
][2] +
1675 ret
|= sisusb_check_rbc(sisusb
, &i2ret
, inc
, 2);
1680 inc
= 1 << (rtype
[idx
][2] + bw
/ 64 + 2);
1681 ret
|= sisusb_check_rbc(sisusb
, &i2ret
, inc
, 4);
1685 inc
= 1 << (10 + bw
/ 64);
1686 ret
|= sisusb_check_rbc(sisusb
, &i2ret
, inc
, 2);
1695 sisusb_get_sdram_size(struct sisusb_usb_data
*sisusb
, int *iret
, int bw
,
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
);
1725 ret
|= sisusb_check_ranks(sisusb
, &i2ret
, j
, i
,
1728 *iret
= 0; /* ram size found */
1738 sisusb_setup_screen(struct sisusb_usb_data
*sisusb
, int clrall
, int drwfr
)
1742 int i
, length
, modex
, modey
, bpp
;
1744 modex
= 640; modey
= 480; bpp
= 2;
1746 address
= sisusb
->vrambase
; /* Clear video ram */
1749 length
= sisusb
->vramsize
;
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
,
1760 address
+= (modex
* (modey
-1) * bpp
);
1761 ret
|= sisusb_write_memio_word(sisusb
, SISUSB_TYPE_MEM
,
1764 for (i
= 0; i
< modey
; i
++) {
1765 address
= sisusb
->vrambase
+ ((i
* modex
) * bpp
);
1766 ret
|= sisusb_write_memio_word(sisusb
, SISUSB_TYPE_MEM
,
1768 address
+= ((modex
- 1) * bpp
);
1769 ret
|= sisusb_write_memio_word(sisusb
, SISUSB_TYPE_MEM
,
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,
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,
1793 static const char grcdata
[] = {
1794 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1797 static const char crtcdata
[] = {
1798 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1799 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
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
);
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));
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));
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 */
1910 sisusb_init_gfxcore(struct sisusb_usb_data
*sisusb
)
1912 int ret
= 0, i
, j
, bw
, chab
, iret
, retry
= 3;
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
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));
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);
1981 ret
|= SETIREG(SISCR
, 0x63, 0x80);
1983 ret
|= GETIREG(SISSR
, 0x3a, &ramtype
);
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);
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);
2022 ret
|= SETIREG(SISPART1
, 0x00, 0x00);
2024 ret
|= GETIREG(SISSR
, 0x13, &tmp8
);
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);
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
);
2062 ret
|= sisusb_get_sdram_size(sisusb
, &iret
, bw
, chab
);
2064 printk(KERN_ERR
"sisusbvga[%d]: RAM size "
2065 "detection failed, "
2066 "assuming 8MB video RAM\n",
2068 ret
|= SETIREG(SISSR
,0x14,0x31);
2072 printk(KERN_ERR
"sisusbvga[%d]: DDR RAM device found, "
2073 "assuming 8MB video RAM\n",
2075 ret
|= SETIREG(SISSR
,0x14,0x31);
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);
2107 sisusb_get_ramconfig(struct sisusb_usb_data
*sisusb
)
2109 u8 tmp8
, tmp82
, ramtype
;
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;
2123 switch ((tmp8
>> 2) & 0x03) {
2124 case 0: ramtypetext1
= "1 ch/1 r";
2128 bw
= busSDR
[(tmp8
& 0x03)];
2131 case 1: ramtypetext1
= "1 ch/2 r";
2132 sisusb
->vramsize
<<= 1;
2133 bw
= busSDR
[(tmp8
& 0x03)];
2135 case 2: ramtypetext1
= "asymmeric";
2136 sisusb
->vramsize
+= sisusb
->vramsize
/2;
2137 bw
= busDDRA
[(tmp8
& 0x03)];
2139 case 3: ramtypetext1
= "2 channel";
2140 sisusb
->vramsize
<<= 1;
2141 bw
= busDDR
[(tmp8
& 0x03)];
2145 printk(KERN_INFO
"sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2146 sisusb
->minor
, (sisusb
->vramsize
>> 20), ramtypetext1
,
2147 ramtypetext2
[ramtype
], bw
);
2151 sisusb_do_init_gfxdevice(struct sisusb_usb_data
*sisusb
)
2153 struct sisusb_packet packet
;
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
);
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
);
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
);
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
);
2211 ret
|= sisusb_write_pci_config(sisusb
, 0x04, tmp32
);
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);
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.
2230 sisusb_init_gfxdevice(struct sisusb_usb_data
*sisusb
, int initscreen
)
2232 int ret
= 0, test
= 0;
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
);
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
);
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",
2287 up(&disconnect_sem
);
2291 if (!(sisusb
= usb_get_intfdata(interface
))) {
2292 up(&disconnect_sem
);
2296 down(&sisusb
->lock
);
2298 if (!sisusb
->present
|| !sisusb
->ready
) {
2300 up(&disconnect_sem
);
2304 if (sisusb
->isopen
) {
2306 up(&disconnect_sem
);
2310 if (!sisusb
->devinit
) {
2311 if (sisusb
->sisusb_dev
->speed
== USB_SPEED_HIGH
) {
2312 if (sisusb_init_gfxdevice(sisusb
, 0)) {
2314 up(&disconnect_sem
);
2316 "sisusbvga[%d]: Failed to initialize "
2323 up(&disconnect_sem
);
2325 "sisusbvga[%d]: Device not attached to "
2332 /* increment usage count for the device */
2333 kref_get(&sisusb
->kref
);
2337 file
->private_data
= sisusb
;
2341 up(&disconnect_sem
);
2343 printk(KERN_DEBUG
"sisusbvga[%d]: opened", sisusb
->minor
);
2349 sisusb_delete(struct kref
*kref
)
2351 struct sisusb_usb_data
*sisusb
= to_sisusb_dev(kref
);
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
);
2366 sisusb_release(struct inode
*inode
, struct file
*file
)
2368 struct sisusb_usb_data
*sisusb
;
2371 down(&disconnect_sem
);
2373 if (!(sisusb
= (struct sisusb_usb_data
*)file
->private_data
)) {
2374 up(&disconnect_sem
);
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
;
2389 file
->private_data
= NULL
;
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
);
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;
2413 if (!(sisusb
= (struct sisusb_usb_data
*)file
->private_data
))
2416 down(&sisusb
->lock
);
2419 if (!sisusb
->present
|| !sisusb
->ready
|| !sisusb
->sisusb_dev
) {
2424 if ((*ppos
) >= SISUSB_PCI_PSEUDO_IOPORTBASE
&&
2425 (*ppos
) < SISUSB_PCI_PSEUDO_IOPORTBASE
+ 128) {
2428 SISUSB_PCI_PSEUDO_IOPORTBASE
+
2429 SISUSB_PCI_IOPORTBASE
;
2432 * Byte, word and long(32) can be read. As this
2433 * emulates inX instructions, the data returned is
2434 * in machine-endianness.
2439 if (sisusb_read_memio_byte(sisusb
,
2443 else if (put_user(buf8
, (u8 __user
*)buffer
))
2451 if (sisusb_read_memio_word(sisusb
,
2455 else if (put_user(buf16
, (u16 __user
*)buffer
))
2463 if (sisusb_read_memio_long(sisusb
,
2467 else if (put_user(buf32
, (u32 __user
*)buffer
))
2479 } else if ((*ppos
) >= SISUSB_PCI_PSEUDO_MEMBASE
&&
2480 (*ppos
) < SISUSB_PCI_PSEUDO_MEMBASE
+ sisusb
->vramsize
) {
2483 SISUSB_PCI_PSEUDO_MEMBASE
+
2487 * Remember: Data delivered is never endian-corrected
2489 errno
= sisusb_read_mem_bulk(sisusb
, address
,
2490 NULL
, count
, buffer
, &bytes_read
);
2495 } else if ((*ppos
) >= SISUSB_PCI_PSEUDO_MMIOBASE
&&
2496 (*ppos
) < SISUSB_PCI_PSEUDO_MMIOBASE
+ SISUSB_PCI_MMIOSIZE
) {
2499 SISUSB_PCI_PSEUDO_MMIOBASE
+
2500 SISUSB_PCI_MMIOBASE
;
2503 * Remember: Data delivered is never endian-corrected
2505 errno
= sisusb_read_mem_bulk(sisusb
, address
,
2506 NULL
, count
, buffer
, &bytes_read
);
2511 } else if ((*ppos
) >= SISUSB_PCI_PSEUDO_PCIBASE
&&
2512 (*ppos
) <= SISUSB_PCI_PSEUDO_PCIBASE
+ 0x5c) {
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
))
2526 else if (put_user(buf32
, (u32 __user
*)buffer
))
2537 (*ppos
) += bytes_read
;
2541 return errno
? errno
: bytes_read
;
2545 sisusb_write(struct file
*file
, const char __user
*buffer
, size_t count
,
2548 struct sisusb_usb_data
*sisusb
;
2550 ssize_t bytes_written
= 0;
2555 if (!(sisusb
= (struct sisusb_usb_data
*)file
->private_data
))
2558 down(&sisusb
->lock
);
2561 if (!sisusb
->present
|| !sisusb
->ready
|| !sisusb
->sisusb_dev
) {
2566 if ((*ppos
) >= SISUSB_PCI_PSEUDO_IOPORTBASE
&&
2567 (*ppos
) < SISUSB_PCI_PSEUDO_IOPORTBASE
+ 128) {
2570 SISUSB_PCI_PSEUDO_IOPORTBASE
+
2571 SISUSB_PCI_IOPORTBASE
;
2574 * Byte, word and long(32) can be written. As this
2575 * emulates outX instructions, the data is expected
2576 * in machine-endianness.
2581 if (get_user(buf8
, (u8 __user
*)buffer
))
2583 else if (sisusb_write_memio_byte(sisusb
,
2593 if (get_user(buf16
, (u16 __user
*)buffer
))
2595 else if (sisusb_write_memio_word(sisusb
,
2605 if (get_user(buf32
, (u32 __user
*)buffer
))
2607 else if (sisusb_write_memio_long(sisusb
,
2620 } else if ((*ppos
) >= SISUSB_PCI_PSEUDO_MEMBASE
&&
2621 (*ppos
) < SISUSB_PCI_PSEUDO_MEMBASE
+ sisusb
->vramsize
) {
2624 SISUSB_PCI_PSEUDO_MEMBASE
+
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
);
2637 errno
= bytes_written
;
2639 } else if ((*ppos
) >= SISUSB_PCI_PSEUDO_MMIOBASE
&&
2640 (*ppos
) < SISUSB_PCI_PSEUDO_MMIOBASE
+ SISUSB_PCI_MMIOSIZE
) {
2643 SISUSB_PCI_PSEUDO_MMIOBASE
+
2644 SISUSB_PCI_MMIOBASE
;
2647 * Buffer is copied 1:1, therefore, on big-endian
2648 * machines, the data must be swapped by userland
2651 errno
= sisusb_write_mem_bulk(sisusb
, address
, NULL
,
2652 count
, buffer
, 0, &bytes_written
);
2655 errno
= bytes_written
;
2657 } else if ((*ppos
) >= SISUSB_PCI_PSEUDO_PCIBASE
&&
2658 (*ppos
) <= SISUSB_PCI_PSEUDO_PCIBASE
+ SISUSB_PCI_PCONFSIZE
) {
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
))
2672 else if (sisusb_write_pci_config(sisusb
, address
, buf32
))
2685 (*ppos
) += bytes_written
;
2689 return errno
? errno
: bytes_written
;
2693 sisusb_lseek(struct file
*file
, loff_t offset
, int orig
)
2695 struct sisusb_usb_data
*sisusb
;
2698 if (!(sisusb
= (struct sisusb_usb_data
*)file
->private_data
))
2701 down(&sisusb
->lock
);
2704 if (!sisusb
->present
|| !sisusb
->ready
|| !sisusb
->sisusb_dev
) {
2711 file
->f_pos
= offset
;
2713 /* never negative, no force_successful_syscall needed */
2716 file
->f_pos
+= offset
;
2718 /* never negative, no force_successful_syscall needed */
2721 /* seeking relative to "end of file" is not supported */
2730 sisusb_handle_command(struct sisusb_usb_data
*sisusb
, struct sisusb_command
*y
,
2733 int retval
, port
, length
;
2737 SISUSB_PCI_PSEUDO_IOPORTBASE
+
2738 SISUSB_PCI_IOPORTBASE
;
2740 switch (y
->operation
) {
2742 retval
= sisusb_getidxreg(sisusb
, port
,
2743 y
->data0
, &y
->data1
);
2745 if (copy_to_user((void __user
*)arg
, y
,
2752 retval
= sisusb_setidxreg(sisusb
, port
,
2753 y
->data0
, y
->data1
);
2757 retval
= sisusb_setidxregor(sisusb
, port
,
2758 y
->data0
, y
->data1
);
2762 retval
= sisusb_setidxregand(sisusb
, port
,
2763 y
->data0
, y
->data1
);
2766 case SUCMD_SETANDOR
:
2767 retval
= sisusb_setidxregandor(sisusb
, port
,
2768 y
->data0
, y
->data1
, y
->data2
);
2772 retval
= sisusb_setidxregmask(sisusb
, port
,
2773 y
->data0
, y
->data1
, y
->data2
);
2777 length
= (y
->data0
<< 16) | (y
->data1
<< 8) | y
->data2
;
2778 address
= y
->data3
-
2779 SISUSB_PCI_PSEUDO_MEMBASE
+
2781 retval
= sisusb_clear_vram(sisusb
, address
, length
);
2795 sisusb_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
2798 struct sisusb_usb_data
*sisusb
;
2799 struct sisusb_info x
;
2800 struct sisusb_command y
;
2802 u32 __user
*argp
= (u32 __user
*)arg
;
2804 if (!(sisusb
= (struct sisusb_usb_data
*)file
->private_data
))
2807 down(&sisusb
->lock
);
2810 if (!sisusb
->present
|| !sisusb
->ready
|| !sisusb
->sisusb_dev
) {
2817 case SISUSB_GET_CONFIG_SIZE
:
2819 if (put_user(sizeof(x
), argp
))
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
)))
2844 case SISUSB_COMMAND
:
2846 if (copy_from_user(&y
, (void __user
*)arg
, sizeof(y
)))
2849 retval
= sisusb_handle_command(sisusb
, &y
, arg
);
2863 #ifdef SISUSB_NEW_CONFIG_COMPAT
2865 sisusb_compat_ioctl(struct file
*f
, unsigned int cmd
, unsigned long arg
)
2870 case SISUSB_GET_CONFIG_SIZE
:
2871 case SISUSB_GET_CONFIG
:
2872 case SISUSB_COMMAND
:
2874 retval
= sisusb_ioctl(f
->f_dentry
->d_inode
, f
, cmd
, arg
);
2879 return -ENOIOCTLCMD
;
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
,
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
;
2910 const char *memfail
=
2912 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
2914 printk(KERN_INFO
"sisusb: USB2VGA dongle found at address %d\n",
2917 /* Allocate memory for our private */
2918 if (!(sisusb
= kmalloc(sizeof(*sisusb
), GFP_KERNEL
))) {
2920 "sisusb: Failed to allocate memory for private data\n");
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
))) {
2931 "sisusb: Failed to get a minor for device %d\n",
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
);
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
,
2959 &sisusb
->transfer_dma_out
[i
]))) {
2961 printk(memfail
, "output", sisusb
->minor
);
2972 if (!(sisusb
->sisurbin
= usb_alloc_urb(0, GFP_KERNEL
))) {
2974 "sisusbvga[%d]: Failed to allocate URBs\n",
2979 sisusb
->completein
= 1;
2981 for (i
= 0; i
< sisusb
->numobufs
; i
++) {
2982 if (!(sisusb
->sisurbout
[i
] = usb_alloc_urb(0, GFP_KERNEL
))) {
2984 "sisusbvga[%d]: Failed to allocate URBs\n",
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
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
);
3012 "sisusbvga[%d]: Error registering ioctl32 "
3016 sisusb
->ioctl32registered
= 1;
3021 sisusb
->present
= 1;
3023 if (dev
->speed
== USB_SPEED_HIGH
) {
3024 if (sisusb_init_gfxdevice(sisusb
, 1))
3026 "sisusbvga[%d]: Failed to early "
3027 "initialize device\n",
3032 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3041 sisusb_free_urbs(sisusb
);
3043 sisusb_free_buffers(sisusb
);
3045 usb_deregister_dev(intf
, &usb_sisusb_class
);
3051 static void sisusb_disconnect(struct usb_interface
*intf
)
3053 struct sisusb_usb_data
*sisusb
;
3056 down(&disconnect_sem
);
3058 /* This should *not* happen */
3059 if (!(sisusb
= usb_get_intfdata(intf
))) {
3060 up(&disconnect_sem
);
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
) {
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
);
3085 "sisusbvga[%d]: Error unregistering "
3086 "ioctl32 translations\n",
3092 sisusb
->present
= 0;
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
,
3115 .probe
= sisusb_probe
,
3116 .disconnect
= sisusb_disconnect
,
3117 .id_table
= sisusb_table
3120 static int __init
usb_sisusb_init(void)
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
);
3128 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
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");