blob: be163b33016742b95731b5b1e5e79b3167f0b1d5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
3 *
4 * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
5 *
6 * If distributed as part of the Linux kernel, this code is licensed under the
7 * terms of the GPL v2.
8 *
9 * Otherwise, the following license terms apply:
10 *
11 * * Redistribution and use in source and binary forms, with or without
12 * * modification, are permitted provided that the following conditions
13 * * are met:
14 * * 1) Redistributions of source code must retain the above copyright
15 * * notice, this list of conditions and the following disclaimer.
16 * * 2) Redistributions in binary form must reproduce the above copyright
17 * * notice, this list of conditions and the following disclaimer in the
18 * * documentation and/or other materials provided with the distribution.
19 * * 3) The name of the author may not be used to endorse or promote products
20 * * derived from this software without specific psisusbr written permission.
21 * *
22 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
23 * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Author: Thomas Winischhofer <thomas@winischhofer.net>
34 *
35 */
36
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>
51
52#include "sisusb.h"
53
54#define SISUSB_DONTSYNC
55
56/* Forward declarations / clean-up routines */
57
58static struct usb_driver sisusb_driver;
59
60static DECLARE_MUTEX(disconnect_sem);
61
62static void
63sisusb_free_buffers(struct sisusb_usb_data *sisusb)
64{
65 int i;
66
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;
72 }
73 }
74 if (sisusb->ibuf) {
75 usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize,
76 sisusb->ibuf, sisusb->transfer_dma_in);
77 sisusb->ibuf = NULL;
78 }
79}
80
81static void
82sisusb_free_urbs(struct sisusb_usb_data *sisusb)
83{
84 int i;
85
86 for (i = 0; i < NUMOBUFS; i++) {
87 usb_free_urb(sisusb->sisurbout[i]);
88 sisusb->sisurbout[i] = NULL;
89 }
90 usb_free_urb(sisusb->sisurbin);
91 sisusb->sisurbin = NULL;
92}
93
94/* Level 0: USB transport layer */
95
96/* 1. out-bulks */
97
98/* out-urb management */
99
100/* Return 1 if all free, 0 otherwise */
101static int
102sisusb_all_free(struct sisusb_usb_data *sisusb)
103{
104 int i;
105
106 for (i = 0; i < sisusb->numobufs; i++) {
107
108 if (sisusb->urbstatus[i] & SU_URB_BUSY)
109 return 0;
110
111 }
112
113 return 1;
114}
115
116/* Kill all busy URBs */
117static void
118sisusb_kill_all_busy(struct sisusb_usb_data *sisusb)
119{
120 int i;
121
122 if (sisusb_all_free(sisusb))
123 return;
124
125 for (i = 0; i < sisusb->numobufs; i++) {
126
127 if (sisusb->urbstatus[i] & SU_URB_BUSY)
128 usb_kill_urb(sisusb->sisurbout[i]);
129
130 }
131}
132
133/* Return 1 if ok, 0 if error (not all complete within timeout) */
134static int
135sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb)
136{
137 int timeout = 5 * HZ, i = 1;
138
139 wait_event_timeout(sisusb->wait_q,
140 (i = sisusb_all_free(sisusb)),
141 timeout);
142
143 return i;
144}
145
146static int
147sisusb_outurb_available(struct sisusb_usb_data *sisusb)
148{
149 int i;
150
151 for (i = 0; i < sisusb->numobufs; i++) {
152
153 if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0)
154 return i;
155
156 }
157
158 return -1;
159}
160
161static int
162sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb)
163{
164 int i, timeout = 5 * HZ;
165
166 wait_event_timeout(sisusb->wait_q,
167 ((i = sisusb_outurb_available(sisusb)) >= 0),
168 timeout);
169
170 return i;
171}
172
173static int
174sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb)
175{
176 int i;
177
178 i = sisusb_outurb_available(sisusb);
179
180 if (i >= 0)
181 sisusb->urbstatus[i] |= SU_URB_ALLOC;
182
183 return i;
184}
185
186static void
187sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
188{
189 if ((index >= 0) && (index < sisusb->numobufs))
190 sisusb->urbstatus[index] &= ~SU_URB_ALLOC;
191}
192
193/* completion callback */
194
195static void
196sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
197{
198 struct sisusb_urb_context *context = urb->context;
199 struct sisusb_usb_data *sisusb;
200
201 if (!context)
202 return;
203
204 sisusb = context->sisusb;
205
206 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
207 return;
208
209#ifndef SISUSB_DONTSYNC
210 if (context->actual_length)
211 *(context->actual_length) += urb->actual_length;
212#endif
213
214 sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY;
215 wake_up(&sisusb->wait_q);
216}
217
218static int
219sisusb_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)
222{
223 struct urb *urb = sisusb->sisurbout[index];
224 int retval, byteswritten = 0;
225
226 /* Set up URB */
227 urb->transfer_flags = 0;
228
229 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
230 sisusb_bulk_completeout, &sisusb->urbout_context[index]);
231
232 urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
233 urb->actual_length = 0;
234
235 if ((urb->transfer_dma = transfer_dma))
236 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
237
238 /* Set up context */
239 sisusb->urbout_context[index].actual_length = (timeout) ?
240 NULL : actual_length;
241
242 /* Declare this urb/buffer in use */
243 sisusb->urbstatus[index] |= SU_URB_BUSY;
244
245 /* Submit URB */
246 retval = usb_submit_urb(urb, GFP_ATOMIC);
247
248 /* If OK, and if timeout > 0, wait for completion */
249 if ((retval == 0) && timeout) {
250 wait_event_timeout(sisusb->wait_q,
251 (!(sisusb->urbstatus[index] & SU_URB_BUSY)),
252 timeout);
253 if (sisusb->urbstatus[index] & SU_URB_BUSY) {
254 /* URB timed out... kill it and report error */
255 usb_kill_urb(urb);
256 retval = -ETIMEDOUT;
257 } else {
258 /* Otherwise, report urb status */
259 retval = urb->status;
260 byteswritten = urb->actual_length;
261 }
262 }
263
264 if (actual_length)
265 *actual_length = byteswritten;
266
267 return retval;
268}
269
270/* 2. in-bulks */
271
272/* completion callback */
273
274static void
275sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
276{
277 struct sisusb_usb_data *sisusb = urb->context;
278
279 if (!sisusb || !sisusb->sisusb_dev || !sisusb->present)
280 return;
281
282 sisusb->completein = 1;
283 wake_up(&sisusb->wait_q);
284}
285
286static int
287sisusb_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)
289{
290 struct urb *urb = sisusb->sisurbin;
291 int retval, readbytes = 0;
292
293 urb->transfer_flags = 0;
294
295 usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
296 sisusb_bulk_completein, sisusb);
297
298 urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
299 urb->actual_length = 0;
300
301 if ((urb->transfer_dma = transfer_dma))
302 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
303
304 sisusb->completein = 0;
305 retval = usb_submit_urb(urb, GFP_ATOMIC);
306 if (retval == 0) {
307 wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
308 if (!sisusb->completein) {
309 /* URB timed out... kill it and report error */
310 usb_kill_urb(urb);
311 retval = -ETIMEDOUT;
312 } else {
313 /* URB completed within timout */
314 retval = urb->status;
315 readbytes = urb->actual_length;
316 }
317 }
318
319 if (actual_length)
320 *actual_length = readbytes;
321
322 return retval;
323}
324
325
326/* Level 1: */
327
328/* Send a bulk message of variable size
329 *
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.
337 *
338 * (return 0 on success)
339 */
340
341static 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)
344{
345 int result = 0, retry, count = len;
346 int passsize, thispass, transferred_len = 0;
347 int fromuser = (userbuffer != NULL) ? 1 : 0;
348 int fromkern = (kernbuffer != NULL) ? 1 : 0;
349 unsigned int pipe;
350 char *buffer;
351
352 (*bytes_written) = 0;
353
354 /* Sanity check */
355 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
356 return -ENODEV;
357
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.)
365 */
366 if (fromuser || fromkern)
367 index = -1;
368 else if (len > sisusb->obufsize)
369 async = 0;
370
371 pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep);
372
373 do {
374 passsize = thispass = (sisusb->obufsize < count) ?
375 sisusb->obufsize : count;
376
377 if (index < 0)
378 index = sisusb_get_free_outbuf(sisusb);
379
380 if (index < 0)
381 return -EIO;
382
383 buffer = sisusb->obuf[index];
384
385 if (fromuser) {
386
387 if (copy_from_user(buffer, userbuffer, passsize))
388 return -EFAULT;
389
390 userbuffer += passsize;
391
392 } else if (fromkern) {
393
394 memcpy(buffer, kernbuffer, passsize);
395 kernbuffer += passsize;
396
397 }
398
399 retry = 5;
400 while (thispass) {
401
402 if (!sisusb->sisusb_dev)
403 return -ENODEV;
404
405 result = sisusb_bulkout_msg(sisusb,
406 index,
407 pipe,
408 buffer,
409 thispass,
410 &transferred_len,
411 async ? 0 : 5 * HZ,
412 tflags,
413 sisusb->transfer_dma_out[index]);
414
415 if (result == -ETIMEDOUT) {
416
417 /* Will not happen if async */
418 if (!retry--)
419 return -ETIME;
420
421 continue;
422
423 } else if ((result == 0) && !async && transferred_len) {
424
425 thispass -= transferred_len;
426 if (thispass) {
427 if (sisusb->transfer_dma_out) {
428 /* If DMA, copy remaining
429 * to beginning of buffer
430 */
431 memcpy(buffer,
432 buffer + transferred_len,
433 thispass);
434 } else {
435 /* If not DMA, simply increase
436 * the pointer
437 */
438 buffer += transferred_len;
439 }
440 }
441
442 } else
443 break;
444 };
445
446 if (result)
447 return result;
448
449 (*bytes_written) += passsize;
450 count -= passsize;
451
452 /* Force new allocation in next iteration */
453 if (fromuser || fromkern)
454 index = -1;
455
456 } while (count > 0);
457
458 if (async) {
459#ifdef SISUSB_DONTSYNC
460 (*bytes_written) = len;
461 /* Some URBs/buffers might be busy */
462#else
463 sisusb_wait_all_out_complete(sisusb);
464 (*bytes_written) = transferred_len;
465 /* All URBs and all buffers are available */
466#endif
467 }
468
469 return ((*bytes_written) == len) ? 0 : -EIO;
470}
471
472/* Receive a bulk message of variable size
473 *
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.)
478 *
479 */
480
481static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
482 void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read,
483 unsigned int tflags)
484{
485 int result = 0, retry, count = len;
486 int bufsize, thispass, transferred_len;
487 unsigned int pipe;
488 char *buffer;
489
490 (*bytes_read) = 0;
491
492 /* Sanity check */
493 if (!sisusb || !sisusb->present || !sisusb->sisusb_dev)
494 return -ENODEV;
495
496 pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep);
497 buffer = sisusb->ibuf;
498 bufsize = sisusb->ibufsize;
499
500 retry = 5;
501
502#ifdef SISUSB_DONTSYNC
503 if (!(sisusb_wait_all_out_complete(sisusb)))
504 return -EIO;
505#endif
506
507 while (count > 0) {
508
509 if (!sisusb->sisusb_dev)
510 return -ENODEV;
511
512 thispass = (bufsize < count) ? bufsize : count;
513
514 result = sisusb_bulkin_msg(sisusb,
515 pipe,
516 buffer,
517 thispass,
518 &transferred_len,
519 5 * HZ,
520 tflags,
521 sisusb->transfer_dma_in);
522
523 if (transferred_len)
524 thispass = transferred_len;
525
526 else if (result == -ETIMEDOUT) {
527
528 if (!retry--)
529 return -ETIME;
530
531 continue;
532
533 } else
534 return -EIO;
535
536
537 if (thispass) {
538
539 (*bytes_read) += thispass;
540 count -= thispass;
541
542 if (userbuffer) {
543
544 if (copy_to_user(userbuffer, buffer, thispass))
545 return -EFAULT;
546
547 userbuffer += thispass;
548
549 } else {
550
551 memcpy(kernbuffer, buffer, thispass);
552 kernbuffer += thispass;
553
554 }
555
556 }
557
558 }
559
560 return ((*bytes_read) == len) ? 0 : -EIO;
561}
562
563static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len,
564 struct sisusb_packet *packet)
565{
566 int ret;
567 ssize_t bytes_transferred = 0;
568 __le32 tmp;
569
570 if (len == 6)
571 packet->data = 0;
572
573#ifdef SISUSB_DONTSYNC
574 if (!(sisusb_wait_all_out_complete(sisusb)))
575 return 1;
576#endif
577
578 /* Eventually correct endianness */
579 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
580
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);
584
585 if ((ret == 0) && (len == 6)) {
586
587 /* 2. if packet len == 6, it means we read, so wait for 32bit
588 * return value and write it to packet->data
589 */
590 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4,
591 (char *)&tmp, NULL, &bytes_transferred, 0);
592
593 packet->data = le32_to_cpu(tmp);
594 }
595
596 return ret;
597}
598
599static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
600 struct sisusb_packet *packet,
601 unsigned int tflags)
602{
603 int ret;
604 ssize_t bytes_transferred = 0;
605 __le32 tmp;
606
607 if (len == 6)
608 packet->data = 0;
609
610#ifdef SISUSB_DONTSYNC
611 if (!(sisusb_wait_all_out_complete(sisusb)))
612 return 1;
613#endif
614
615 /* Eventually correct endianness */
616 SISUSB_CORRECT_ENDIANNESS_PACKET(packet);
617
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);
621
622 if ((ret == 0) && (len == 6)) {
623
624 /* 2. if packet len == 6, it means we read, so wait for 32bit
625 * return value and write it to packet->data
626 */
627 ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4,
628 (char *)&tmp, NULL, &bytes_transferred, 0);
629
630 packet->data = le32_to_cpu(tmp);
631 }
632
633 return ret;
634}
635
636/* access video memory and mmio (return 0 on success) */
637
638/* Low level */
639
640/* The following routines assume being used to transfer byte, word,
641 * long etc.
642 * This means that they assume "data" in machine endianness format.
643 */
644
645static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
646 u32 addr, u8 data)
647{
648 struct sisusb_packet packet;
649 int ret;
650
651 packet.header = (1 << (addr & 3)) | (type << 6);
652 packet.address = addr & ~3;
653 packet.data = data << ((addr & 3) << 3);
654 ret = sisusb_send_packet(sisusb, 10, &packet);
655 return ret;
656}
657
658static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type,
659 u32 addr, u16 data)
660{
661 struct sisusb_packet packet;
662 int ret = 0;
663
664 packet.address = addr & ~3;
665
666 switch (addr & 3) {
667 case 0:
668 packet.header = (type << 6) | 0x0003;
669 packet.data = (u32)data;
670 ret = sisusb_send_packet(sisusb, 10, &packet);
671 break;
672 case 1:
673 packet.header = (type << 6) | 0x0006;
674 packet.data = (u32)data << 8;
675 ret = sisusb_send_packet(sisusb, 10, &packet);
676 break;
677 case 2:
678 packet.header = (type << 6) | 0x000c;
679 packet.data = (u32)data << 16;
680 ret = sisusb_send_packet(sisusb, 10, &packet);
681 break;
682 case 3:
683 packet.header = (type << 6) | 0x0008;
684 packet.data = (u32)data << 24;
685 ret = sisusb_send_packet(sisusb, 10, &packet);
686 packet.header = (type << 6) | 0x0001;
687 packet.address = (addr & ~3) + 4;
688 packet.data = (u32)data >> 8;
689 ret |= sisusb_send_packet(sisusb, 10, &packet);
690 }
691
692 return ret;
693}
694
695static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type,
696 u32 addr, u32 data)
697{
698 struct sisusb_packet packet;
699 int ret = 0;
700
701 packet.address = addr & ~3;
702
703 switch (addr & 3) {
704 case 0:
705 packet.header = (type << 6) | 0x0007;
706 packet.data = data & 0x00ffffff;
707 ret = sisusb_send_packet(sisusb, 10, &packet);
708 break;
709 case 1:
710 packet.header = (type << 6) | 0x000e;
711 packet.data = data << 8;
712 ret = sisusb_send_packet(sisusb, 10, &packet);
713 break;
714 case 2:
715 packet.header = (type << 6) | 0x000c;
716 packet.data = data << 16;
717 ret = sisusb_send_packet(sisusb, 10, &packet);
718 packet.header = (type << 6) | 0x0001;
719 packet.address = (addr & ~3) + 4;
720 packet.data = (data >> 16) & 0x00ff;
721 ret |= sisusb_send_packet(sisusb, 10, &packet);
722 break;
723 case 3:
724 packet.header = (type << 6) | 0x0008;
725 packet.data = data << 24;
726 ret = sisusb_send_packet(sisusb, 10, &packet);
727 packet.header = (type << 6) | 0x0003;
728 packet.address = (addr & ~3) + 4;
729 packet.data = (data >> 8) & 0xffff;
730 ret |= sisusb_send_packet(sisusb, 10, &packet);
731 }
732
733 return ret;
734}
735
736static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type,
737 u32 addr, u32 data)
738{
739 struct sisusb_packet packet;
740 int ret = 0;
741
742 packet.address = addr & ~3;
743
744 switch (addr & 3) {
745 case 0:
746 packet.header = (type << 6) | 0x000f;
747 packet.data = data;
748 ret = sisusb_send_packet(sisusb, 10, &packet);
749 break;
750 case 1:
751 packet.header = (type << 6) | 0x000e;
752 packet.data = data << 8;
753 ret = sisusb_send_packet(sisusb, 10, &packet);
754 packet.header = (type << 6) | 0x0001;
755 packet.address = (addr & ~3) + 4;
756 packet.data = data >> 24;
757 ret |= sisusb_send_packet(sisusb, 10, &packet);
758 break;
759 case 2:
760 packet.header = (type << 6) | 0x000c;
761 packet.data = data << 16;
762 ret = sisusb_send_packet(sisusb, 10, &packet);
763 packet.header = (type << 6) | 0x0003;
764 packet.address = (addr & ~3) + 4;
765 packet.data = data >> 16;
766 ret |= sisusb_send_packet(sisusb, 10, &packet);
767 break;
768 case 3:
769 packet.header = (type << 6) | 0x0008;
770 packet.data = data << 24;
771 ret = sisusb_send_packet(sisusb, 10, &packet);
772 packet.header = (type << 6) | 0x0007;
773 packet.address = (addr & ~3) + 4;
774 packet.data = data >> 8;
775 ret |= sisusb_send_packet(sisusb, 10, &packet);
776 }
777
778 return ret;
779}
780
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
784 *
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]".
789 */
790
791static 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)
795{
796 struct sisusb_packet packet;
797 int ret = 0;
798 static int msgcount = 0;
799 u8 swap8, fromkern = kernbuffer ? 1 : 0;
800 u16 swap16;
801 u32 swap32, flag = (length >> 28) & 1;
802 char buf[4];
803
804 /* if neither kernbuffer not userbuffer are given, assume
805 * data in obuf
806 */
807 if (!fromkern && !userbuffer)
808 kernbuffer = sisusb->obuf[index];
809
810 (*bytes_written = 0);
811
812 length &= 0x00ffffff;
813
814 while (length) {
815
816 switch (length) {
817
818 case 0:
819 return ret;
820
821 case 1:
822 if (userbuffer) {
823 if (get_user(swap8, (u8 __user *)userbuffer))
824 return -EFAULT;
825 } else
826 swap8 = kernbuffer[0];
827
828 ret = sisusb_write_memio_byte(sisusb,
829 SISUSB_TYPE_MEM,
830 addr, swap8);
831
832 if (!ret)
833 (*bytes_written)++;
834
835 return ret;
836
837 case 2:
838 if (userbuffer) {
839 if (get_user(swap16, (u16 __user *)userbuffer))
840 return -EFAULT;
841 } else
842 swap16 = (kernbuffer[0] << 8) | kernbuffer[1];
843
844 ret = sisusb_write_memio_word(sisusb,
845 SISUSB_TYPE_MEM,
846 addr,
847 swap16);
848
849 if (!ret)
850 (*bytes_written) += 2;
851
852 return ret;
853
854 case 3:
855 if (userbuffer) {
856 if (copy_from_user(&buf, userbuffer, 3))
857 return -EFAULT;
858
859 swap32 = (buf[0] << 16) |
860 (buf[1] << 8) |
861 buf[2];
862 } else
863 swap32 = (kernbuffer[0] << 16) |
864 (kernbuffer[1] << 8) |
865 kernbuffer[2];
866
867 ret = sisusb_write_memio_24bit(sisusb,
868 SISUSB_TYPE_MEM,
869 addr,
870 swap32);
871
872 if (!ret)
873 (*bytes_written) += 3;
874
875 return ret;
876
877 case 4:
878 if (userbuffer) {
879 if (get_user(swap32, (u32 __user *)userbuffer))
880 return -EFAULT;
881 } else
882 swap32 = (kernbuffer[0] << 24) |
883 (kernbuffer[1] << 16) |
884 (kernbuffer[2] << 8) |
885 kernbuffer[3];
886
887 ret = sisusb_write_memio_long(sisusb,
888 SISUSB_TYPE_MEM,
889 addr,
890 swap32);
891 if (!ret)
892 (*bytes_written) += 4;
893
894 return ret;
895
896 default:
897 if ((length & ~3) > 0x10000) {
898
899 packet.header = 0x001f;
900 packet.address = 0x000001d4;
901 packet.data = addr;
902 ret = sisusb_send_bridge_packet(sisusb, 10,
903 &packet, 0);
904 packet.header = 0x001f;
905 packet.address = 0x000001d0;
906 packet.data = (length & ~3);
907 ret |= sisusb_send_bridge_packet(sisusb, 10,
908 &packet, 0);
909 packet.header = 0x001f;
910 packet.address = 0x000001c0;
911 packet.data = flag | 0x16;
912 ret |= sisusb_send_bridge_packet(sisusb, 10,
913 &packet, 0);
914 if (userbuffer) {
915 ret |= sisusb_send_bulk_msg(sisusb,
916 SISUSB_EP_GFX_LBULK_OUT,
917 (length & ~3),
918 NULL, userbuffer, 0,
919 bytes_written, 0, 1);
920 userbuffer += (*bytes_written);
921 } else if (fromkern) {
922 ret |= sisusb_send_bulk_msg(sisusb,
923 SISUSB_EP_GFX_LBULK_OUT,
924 (length & ~3),
925 kernbuffer, NULL, 0,
926 bytes_written, 0, 1);
927 kernbuffer += (*bytes_written);
928 } else {
929 ret |= sisusb_send_bulk_msg(sisusb,
930 SISUSB_EP_GFX_LBULK_OUT,
931 (length & ~3),
932 NULL, NULL, index,
933 bytes_written, 0, 1);
934 kernbuffer += ((*bytes_written) &
935 (sisusb->obufsize-1));
936 }
937
938 } else {
939
940 packet.header = 0x001f;
941 packet.address = 0x00000194;
942 packet.data = addr;
943 ret = sisusb_send_bridge_packet(sisusb, 10,
944 &packet, 0);
945 packet.header = 0x001f;
946 packet.address = 0x00000190;
947 packet.data = (length & ~3);
948 ret |= sisusb_send_bridge_packet(sisusb, 10,
949 &packet, 0);
950 if (sisusb->flagb0 != 0x16) {
951 packet.header = 0x001f;
952 packet.address = 0x00000180;
953 packet.data = flag | 0x16;
954 ret |= sisusb_send_bridge_packet(sisusb, 10,
955 &packet, 0);
956 sisusb->flagb0 = 0x16;
957 }
958 if (userbuffer) {
959 ret |= sisusb_send_bulk_msg(sisusb,
960 SISUSB_EP_GFX_BULK_OUT,
961 (length & ~3),
962 NULL, userbuffer, 0,
963 bytes_written, 0, 1);
964 userbuffer += (*bytes_written);
965 } else if (fromkern) {
966 ret |= sisusb_send_bulk_msg(sisusb,
967 SISUSB_EP_GFX_BULK_OUT,
968 (length & ~3),
969 kernbuffer, NULL, 0,
970 bytes_written, 0, 1);
971 kernbuffer += (*bytes_written);
972 } else {
973 ret |= sisusb_send_bulk_msg(sisusb,
974 SISUSB_EP_GFX_BULK_OUT,
975 (length & ~3),
976 NULL, NULL, index,
977 bytes_written, 0, 1);
978 kernbuffer += ((*bytes_written) &
979 (sisusb->obufsize-1));
980 }
981 }
982 if (ret) {
983 msgcount++;
984 if (msgcount < 500)
985 printk(KERN_ERR
986 "sisusbvga[%d]: Wrote %Zd of "
987 "%d bytes, error %d\n",
988 sisusb->minor, *bytes_written,
989 length, ret);
990 else if (msgcount == 500)
991 printk(KERN_ERR
992 "sisusbvga[%d]: Too many errors"
993 ", logging stopped\n",
994 sisusb->minor);
995 }
996 addr += (*bytes_written);
997 length -= (*bytes_written);
998 }
999
1000 if (ret)
1001 break;
1002
1003 }
1004
1005 return ret ? -EIO : 0;
1006}
1007
1008static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1009 u32 addr, u8 *data)
1010{
1011 struct sisusb_packet packet;
1012 int ret;
1013
1014 CLEARPACKET(&packet);
1015 packet.header = (1 << (addr & 3)) | (type << 6);
1016 packet.address = addr & ~3;
1017 ret = sisusb_send_packet(sisusb, 6, &packet);
1018 *data = (u8)(packet.data >> ((addr & 3) << 3));
1019 return ret;
1020}
1021
1022static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type,
1023 u32 addr, u16 *data)
1024{
1025 struct sisusb_packet packet;
1026 int ret = 0;
1027
1028 CLEARPACKET(&packet);
1029
1030 packet.address = addr & ~3;
1031
1032 switch (addr & 3) {
1033 case 0:
1034 packet.header = (type << 6) | 0x0003;
1035 ret = sisusb_send_packet(sisusb, 6, &packet);
1036 *data = (u16)(packet.data);
1037 break;
1038 case 1:
1039 packet.header = (type << 6) | 0x0006;
1040 ret = sisusb_send_packet(sisusb, 6, &packet);
1041 *data = (u16)(packet.data >> 8);
1042 break;
1043 case 2:
1044 packet.header = (type << 6) | 0x000c;
1045 ret = sisusb_send_packet(sisusb, 6, &packet);
1046 *data = (u16)(packet.data >> 16);
1047 break;
1048 case 3:
1049 packet.header = (type << 6) | 0x0008;
1050 ret = sisusb_send_packet(sisusb, 6, &packet);
1051 *data = (u16)(packet.data >> 24);
1052 packet.header = (type << 6) | 0x0001;
1053 packet.address = (addr & ~3) + 4;
1054 ret |= sisusb_send_packet(sisusb, 6, &packet);
1055 *data |= (u16)(packet.data << 8);
1056 }
1057
1058 return ret;
1059}
1060
1061static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type,
1062 u32 addr, u32 *data)
1063{
1064 struct sisusb_packet packet;
1065 int ret = 0;
1066
1067 packet.address = addr & ~3;
1068
1069 switch (addr & 3) {
1070 case 0:
1071 packet.header = (type << 6) | 0x0007;
1072 ret = sisusb_send_packet(sisusb, 6, &packet);
1073 *data = packet.data & 0x00ffffff;
1074 break;
1075 case 1:
1076 packet.header = (type << 6) | 0x000e;
1077 ret = sisusb_send_packet(sisusb, 6, &packet);
1078 *data = packet.data >> 8;
1079 break;
1080 case 2:
1081 packet.header = (type << 6) | 0x000c;
1082 ret = sisusb_send_packet(sisusb, 6, &packet);
1083 *data = packet.data >> 16;
1084 packet.header = (type << 6) | 0x0001;
1085 packet.address = (addr & ~3) + 4;
1086 ret |= sisusb_send_packet(sisusb, 6, &packet);
1087 *data |= ((packet.data & 0xff) << 16);
1088 break;
1089 case 3:
1090 packet.header = (type << 6) | 0x0008;
1091 ret = sisusb_send_packet(sisusb, 6, &packet);
1092 *data = packet.data >> 24;
1093 packet.header = (type << 6) | 0x0003;
1094 packet.address = (addr & ~3) + 4;
1095 ret |= sisusb_send_packet(sisusb, 6, &packet);
1096 *data |= ((packet.data & 0xffff) << 8);
1097 }
1098
1099 return ret;
1100}
1101
1102static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type,
1103 u32 addr, u32 *data)
1104{
1105 struct sisusb_packet packet;
1106 int ret = 0;
1107
1108 packet.address = addr & ~3;
1109
1110 switch (addr & 3) {
1111 case 0:
1112 packet.header = (type << 6) | 0x000f;
1113 ret = sisusb_send_packet(sisusb, 6, &packet);
1114 *data = packet.data;
1115 break;
1116 case 1:
1117 packet.header = (type << 6) | 0x000e;
1118 ret = sisusb_send_packet(sisusb, 6, &packet);
1119 *data = packet.data >> 8;
1120 packet.header = (type << 6) | 0x0001;
1121 packet.address = (addr & ~3) + 4;
1122 ret |= sisusb_send_packet(sisusb, 6, &packet);
1123 *data |= (packet.data << 24);
1124 break;
1125 case 2:
1126 packet.header = (type << 6) | 0x000c;
1127 ret = sisusb_send_packet(sisusb, 6, &packet);
1128 *data = packet.data >> 16;
1129 packet.header = (type << 6) | 0x0003;
1130 packet.address = (addr & ~3) + 4;
1131 ret |= sisusb_send_packet(sisusb, 6, &packet);
1132 *data |= (packet.data << 16);
1133 break;
1134 case 3:
1135 packet.header = (type << 6) | 0x0008;
1136 ret = sisusb_send_packet(sisusb, 6, &packet);
1137 *data = packet.data >> 24;
1138 packet.header = (type << 6) | 0x0007;
1139 packet.address = (addr & ~3) + 4;
1140 ret |= sisusb_send_packet(sisusb, 6, &packet);
1141 *data |= (packet.data << 8);
1142 }
1143
1144 return ret;
1145}
1146
1147static 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)
1150{
1151 int ret = 0;
1152 char buf[4];
1153 u16 swap16;
1154 u32 swap32;
1155
1156 (*bytes_read = 0);
1157
1158 length &= 0x00ffffff;
1159
1160 while (length) {
1161
1162 switch (length) {
1163
1164 case 0:
1165 return ret;
1166
1167 case 1:
1168
1169 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM,
1170 addr, &buf[0]);
1171 if (!ret) {
1172 (*bytes_read)++;
1173 if (userbuffer) {
1174 if (put_user(buf[0],
1175 (u8 __user *)userbuffer)) {
1176 return -EFAULT;
1177 }
1178 } else {
1179 kernbuffer[0] = buf[0];
1180 }
1181 }
1182 return ret;
1183
1184 case 2:
1185 ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM,
1186 addr, &swap16);
1187 if (!ret) {
1188 (*bytes_read) += 2;
1189 if (userbuffer) {
1190 if (put_user(swap16,
1191 (u16 __user *)userbuffer))
1192 return -EFAULT;
1193 } else {
1194 kernbuffer[0] = swap16 >> 8;
1195 kernbuffer[1] = swap16 & 0xff;
1196 }
1197 }
1198 return ret;
1199
1200 case 3:
1201 ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM,
1202 addr, &swap32);
1203 if (!ret) {
1204 (*bytes_read) += 3;
1205 buf[0] = (swap32 >> 16) & 0xff;
1206 buf[1] = (swap32 >> 8) & 0xff;
1207 buf[2] = swap32 & 0xff;
1208 if (userbuffer) {
1209 if (copy_to_user(userbuffer, &buf[0], 3))
1210 return -EFAULT;
1211 } else {
1212 kernbuffer[0] = buf[0];
1213 kernbuffer[1] = buf[1];
1214 kernbuffer[2] = buf[2];
1215 }
1216 }
1217 return ret;
1218
1219 default:
1220 ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM,
1221 addr, &swap32);
1222 if (!ret) {
1223 (*bytes_read) += 4;
1224 if (userbuffer) {
1225 if (put_user(swap32,
1226 (u32 __user *)userbuffer))
1227 return -EFAULT;
1228
1229 userbuffer += 4;
1230 } else {
1231 kernbuffer[0] = (swap32 >> 24) & 0xff;
1232 kernbuffer[1] = (swap32 >> 16) & 0xff;
1233 kernbuffer[2] = (swap32 >> 8) & 0xff;
1234 kernbuffer[3] = swap32 & 0xff;
1235 kernbuffer += 4;
1236 }
1237 addr += 4;
1238 length -= 4;
1239 }
1240#if 0 /* That does not work, as EP 2 is an OUT EP! */
1241 default:
1242 CLEARPACKET(&packet);
1243 packet.header = 0x001f;
1244 packet.address = 0x000001a0;
1245 packet.data = 0x00000006;
1246 ret |= sisusb_send_bridge_packet(sisusb, 10,
1247 &packet, 0);
1248 packet.header = 0x001f;
1249 packet.address = 0x000001b0;
1250 packet.data = (length & ~3) | 0x40000000;
1251 ret |= sisusb_send_bridge_packet(sisusb, 10,
1252 &packet, 0);
1253 packet.header = 0x001f;
1254 packet.address = 0x000001b4;
1255 packet.data = addr;
1256 ret |= sisusb_send_bridge_packet(sisusb, 10,
1257 &packet, 0);
1258 packet.header = 0x001f;
1259 packet.address = 0x000001a4;
1260 packet.data = 0x00000001;
1261 ret |= sisusb_send_bridge_packet(sisusb, 10,
1262 &packet, 0);
1263 if (userbuffer) {
1264 ret |= sisusb_recv_bulk_msg(sisusb,
1265 SISUSB_EP_GFX_BULK_IN,
1266 (length & ~3),
1267 NULL, userbuffer,
1268 bytes_read, 0);
1269 if (!ret) userbuffer += (*bytes_read);
1270 } else {
1271 ret |= sisusb_recv_bulk_msg(sisusb,
1272 SISUSB_EP_GFX_BULK_IN,
1273 (length & ~3),
1274 kernbuffer, NULL,
1275 bytes_read, 0);
1276 if (!ret) kernbuffer += (*bytes_read);
1277 }
1278 addr += (*bytes_read);
1279 length -= (*bytes_read);
1280#endif
1281 }
1282
1283 if (ret)
1284 break;
1285 }
1286
1287 return ret;
1288}
1289
1290/* High level: Gfx (indexed) register access */
1291
1292static int
1293sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1294{
1295 int ret;
1296 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1297 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1298 return ret;
1299}
1300
1301static int
1302sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1303{
1304 int ret;
1305 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index);
1306 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data);
1307 return ret;
1308}
1309
1310static int
1311sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1312 u8 myand, u8 myor)
1313{
1314 int ret;
1315 u8 tmp;
1316
1317 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1318 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1319 tmp &= myand;
1320 tmp |= myor;
1321 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1322 return ret;
1323}
1324
1325static int
1326sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1327 u8 data, u8 mask)
1328{
1329 int ret;
1330 u8 tmp;
1331 ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx);
1332 ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp);
1333 tmp &= ~(mask);
1334 tmp |= (data & mask);
1335 ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp);
1336 return ret;
1337}
1338
1339static int
1340sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1341{
1342 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1343}
1344
1345static int
1346sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1347{
1348 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1349}
1350
1351/* access pci config registers (reg numbers 0, 4, 8, etc) */
1352
1353static int
1354sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data)
1355{
1356 struct sisusb_packet packet;
1357 int ret;
1358
1359 packet.header = 0x008f;
1360 packet.address = regnum | 0x10000;
1361 packet.data = data;
1362 ret = sisusb_send_packet(sisusb, 10, &packet);
1363 return ret;
1364}
1365
1366static int
1367sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data)
1368{
1369 struct sisusb_packet packet;
1370 int ret;
1371
1372 packet.header = 0x008f;
1373 packet.address = (u32)regnum | 0x10000;
1374 ret = sisusb_send_packet(sisusb, 6, &packet);
1375 *data = packet.data;
1376 return ret;
1377}
1378
1379/* Clear video RAM */
1380
1381static int
1382sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
1383{
1384 int ret, i;
1385 ssize_t j;
1386
1387 if (address < sisusb->vrambase)
1388 return 1;
1389
1390 if (address >= sisusb->vrambase + sisusb->vramsize)
1391 return 1;
1392
1393 if (address + length > sisusb->vrambase + sisusb->vramsize)
1394 length = sisusb->vrambase + sisusb->vramsize - address;
1395
1396 if (length <= 0)
1397 return 0;
1398
1399 /* allocate free buffer/urb and clear the buffer */
1400 if ((i = sisusb_alloc_outbuf(sisusb)) < 0)
1401 return -EBUSY;
1402
1403 memset(sisusb->obuf[i], 0, sisusb->obufsize);
1404
1405 /* We can write a length > buffer size here. The buffer
1406 * data will simply be re-used (like a ring-buffer).
1407 */
1408 ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j);
1409
1410 /* Free the buffer/urb */
1411 sisusb_free_outbuf(sisusb, i);
1412
1413 return ret;
1414}
1415
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)
1419 */
1420
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)
1432
1433static int
1434sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
1435{
1436 int ret;
1437 u8 tmp8;
1438
1439 ret = GETIREG(SISSR, 0x16, &tmp8);
1440 if (ramtype <= 1) {
1441 tmp8 &= 0x3f;
1442 ret |= SETIREG(SISSR, 0x16, tmp8);
1443 tmp8 |= 0x80;
1444 ret |= SETIREG(SISSR, 0x16, tmp8);
1445 } else {
1446 tmp8 |= 0xc0;
1447 ret |= SETIREG(SISSR, 0x16, tmp8);
1448 tmp8 &= 0x0f;
1449 ret |= SETIREG(SISSR, 0x16, tmp8);
1450 tmp8 |= 0x80;
1451 ret |= SETIREG(SISSR, 0x16, tmp8);
1452 tmp8 &= 0x0f;
1453 ret |= SETIREG(SISSR, 0x16, tmp8);
1454 tmp8 |= 0xd0;
1455 ret |= SETIREG(SISSR, 0x16, tmp8);
1456 tmp8 &= 0x0f;
1457 ret |= SETIREG(SISSR, 0x16, tmp8);
1458 tmp8 |= 0xa0;
1459 ret |= SETIREG(SISSR, 0x16, tmp8);
1460 }
1461 return ret;
1462}
1463
1464static int
1465sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab)
1466{
1467 int ret;
1468 u8 ramtype, done = 0;
1469 u32 t0, t1, t2, t3;
1470 u32 ramptr = SISUSB_PCI_MEMBASE;
1471
1472 ret = GETIREG(SISSR, 0x3a, &ramtype);
1473 ramtype &= 3;
1474
1475 ret |= SETIREG(SISSR, 0x13, 0x00);
1476
1477 if (ramtype <= 1) {
1478 ret |= SETIREG(SISSR, 0x14, 0x12);
1479 ret |= SETIREGAND(SISSR, 0x15, 0xef);
1480 } else {
1481 ret |= SETIREG(SISSR, 0x14, 0x02);
1482 }
1483
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);
1497
1498 if (ramtype <= 1) {
1499
1500 *chab = 0; *bw = 64;
1501
1502 if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) {
1503 if ((t1 == 0x456789ab) && (t0 == 0x01234567)) {
1504 *chab = 0; *bw = 64;
1505 ret |= SETIREGAND(SISSR, 0x14, 0xfd);
1506 }
1507 }
1508 if ((t1 != 0x456789ab) || (t0 != 0x01234567)) {
1509 *chab = 1; *bw = 64;
1510 ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01);
1511
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);
1520
1521 if (t1 != 0xcdef0123) {
1522 *bw = 32;
1523 ret |= SETIREGOR(SISSR, 0x15, 0x10);
1524 }
1525 }
1526
1527 } else {
1528
1529 *chab = 0; *bw = 64; /* default: cha, bw = 64 */
1530
1531 done = 0;
1532
1533 if (t1 == 0x456789ab) {
1534 if (t0 == 0x01234567) {
1535 *chab = 0; *bw = 64;
1536 done = 1;
1537 }
1538 } else {
1539 if (t0 == 0x01234567) {
1540 *chab = 0; *bw = 32;
1541 ret |= SETIREG(SISSR, 0x14, 0x00);
1542 done = 1;
1543 }
1544 }
1545
1546 if (!done) {
1547 ret |= SETIREG(SISSR, 0x14, 0x03);
1548 ret |= sisusb_triggersr16(sisusb, ramtype);
1549
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);
1560
1561 if (t1 == 0x456789ab) {
1562 if (t0 == 0x01234567) {
1563 *chab = 1; *bw = 64;
1564 return ret;
1565 } /* else error */
1566 } else {
1567 if (t0 == 0x01234567) {
1568 *chab = 1; *bw = 32;
1569 ret |= SETIREG(SISSR, 0x14, 0x01);
1570 } /* else error */
1571 }
1572 }
1573 }
1574 return ret;
1575}
1576
1577static int
1578sisusb_verify_mclk(struct sisusb_usb_data *sisusb)
1579{
1580 int ret = 0;
1581 u32 ramptr = SISUSB_PCI_MEMBASE;
1582 u8 tmp1, tmp2, i, j;
1583
1584 ret |= WRITEB(ramptr, 0xaa);
1585 ret |= WRITEB(ramptr + 16, 0x55);
1586 ret |= READB(ramptr, &tmp1);
1587 ret |= READB(ramptr + 16, &tmp2);
1588 if ((tmp1 != 0xaa) || (tmp2 != 0x55)) {
1589 for (i = 0, j = 16; i < 2; i++, j += 16) {
1590 ret |= GETIREG(SISSR, 0x21, &tmp1);
1591 ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb));
1592 ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */
1593 ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */
1594 ret |= SETIREG(SISSR, 0x21, tmp1);
1595 ret |= WRITEB(ramptr + 16 + j, j);
1596 ret |= READB(ramptr + 16 + j, &tmp1);
1597 if (tmp1 == j) {
1598 ret |= WRITEB(ramptr + j, j);
1599 break;
1600 }
1601 }
1602 }
1603 return ret;
1604}
1605
1606static int
1607sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index,
1608 u8 rankno, u8 chab, const u8 dramtype[][5],
1609 int bw)
1610{
1611 int ret = 0, ranksize;
1612 u8 tmp;
1613
1614 *iret = 0;
1615
1616 if ((rankno == 2) && (dramtype[index][0] == 2))
1617 return ret;
1618
1619 ranksize = dramtype[index][3] / 2 * bw / 32;
1620
1621 if ((ranksize * rankno) > 128)
1622 return ret;
1623
1624 tmp = 0;
1625 while ((ranksize >>= 1) > 0) tmp += 0x10;
1626 tmp |= ((rankno - 1) << 2);
1627 tmp |= ((bw / 64) & 0x02);
1628 tmp |= (chab & 0x01);
1629
1630 ret = SETIREG(SISSR, 0x14, tmp);
1631 ret |= sisusb_triggersr16(sisusb, 0); /* sic! */
1632
1633 *iret = 1;
1634
1635 return ret;
1636}
1637
1638static int
1639sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn)
1640{
1641 int ret = 0, i;
1642 u32 j, tmp;
1643
1644 *iret = 0;
1645
1646 for (i = 0, j = 0; i < testn; i++) {
1647 ret |= WRITEL(sisusb->vrambase + j, j);
1648 j += inc;
1649 }
1650
1651 for (i = 0, j = 0; i < testn; i++) {
1652 ret |= READL(sisusb->vrambase + j, &tmp);
1653 if (tmp != j) return ret;
1654 j += inc;
1655 }
1656
1657 *iret = 1;
1658 return ret;
1659}
1660
1661static int
1662sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno,
1663 int idx, int bw, const u8 rtype[][5])
1664{
1665 int ret = 0, i, i2ret;
1666 u32 inc;
1667
1668 *iret = 0;
1669
1670 for (i = rankno; i >= 1; i--) {
1671 inc = 1 << (rtype[idx][2] +
1672 rtype[idx][1] +
1673 rtype[idx][0] +
1674 bw / 64 + i);
1675 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1676 if (!i2ret)
1677 return ret;
1678 }
1679
1680 inc = 1 << (rtype[idx][2] + bw / 64 + 2);
1681 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4);
1682 if (!i2ret)
1683 return ret;
1684
1685 inc = 1 << (10 + bw / 64);
1686 ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2);
1687 if (!i2ret)
1688 return ret;
1689
1690 *iret = 1;
1691 return ret;
1692}
1693
1694static int
1695sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw,
1696 int chab)
1697{
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 }
1713 };
1714
1715 *iret = 1; /* error */
1716
1717 for (i = 0; i < 13; i++) {
1718 ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]);
1719 for (j = 2; j > 0; j--) {
1720 ret |= sisusb_set_rank(sisusb, &i2ret, i, j,
1721 chab, sdramtype, bw);
1722 if (!i2ret)
1723 continue;
1724
1725 ret |= sisusb_check_ranks(sisusb, &i2ret, j, i,
1726 bw, sdramtype);
1727 if (i2ret) {
1728 *iret = 0; /* ram size found */
1729 return ret;
1730 }
1731 }
1732 }
1733
1734 return ret;
1735}
1736
1737static int
1738sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr)
1739{
1740 int ret = 0;
1741 u32 address;
1742 int i, length, modex, modey, bpp;
1743
1744 modex = 640; modey = 480; bpp = 2;
1745
1746 address = sisusb->vrambase; /* Clear video ram */
1747
1748 if (clrall)
1749 length = sisusb->vramsize;
1750 else
1751 length = modex * bpp * modey;
1752
1753 ret = sisusb_clear_vram(sisusb, address, length);
1754
1755 if (!ret && drwfr) {
1756 for (i = 0; i < modex; i++) {
1757 address = sisusb->vrambase + (i * bpp);
1758 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1759 address, 0xf100);
1760 address += (modex * (modey-1) * bpp);
1761 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1762 address, 0xf100);
1763 }
1764 for (i = 0; i < modey; i++) {
1765 address = sisusb->vrambase + ((i * modex) * bpp);
1766 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1767 address, 0xf100);
1768 address += ((modex - 1) * bpp);
1769 ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM,
1770 address, 0xf100);
1771 }
1772 }
1773
1774 return ret;
1775}
1776
1777static int
1778sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
1779{
1780 int ret = 0, i, j, modex, modey, bpp, du;
1781 u8 sr31, cr63, tmp8;
1782 static const char attrdata[] = {
1783 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
1784 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
1785 0x01,0x00,0x00,0x00
1786 };
1787 static const char crtcrdata[] = {
1788 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
1789 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
1790 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
1791 0xff
1792 };
1793 static const char grcdata[] = {
1794 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
1795 0xff
1796 };
1797 static const char crtcdata[] = {
1798 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
1799 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
1800 0x00
1801 };
1802
1803 modex = 640; modey = 480; bpp = 2;
1804
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]);
1820 }
1821 for (i = 0; i <= 0x13; i++) { /* att */
1822 GETREG(SISINPSTAT, &tmp8);
1823 SETREG(SISAR, i);
1824 SETREG(SISAR, attrdata[i]);
1825 }
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]);
1834 }
1835 SETIREGAND(SISGR, 0x05, 0xbf);
1836 for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */
1837 SETIREG(SISSR, i, 0x00);
1838 }
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]);
1844 }
1845 for (j = 0x10; i <= 10; i++, j++) {
1846 SETIREG(SISCR, j, crtcdata[i]);
1847 }
1848 for (j = 0x15; i <= 12; i++, j++) {
1849 SETIREG(SISCR, j, crtcdata[i]);
1850 }
1851 for (j = 0x0A; i <= 15; i++, j++) {
1852 SETIREG(SISSR, j, crtcdata[i]);
1853 }
1854 SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0));
1855 SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5));
1856 SETIREG(SISCR, 0x14, 0x4f);
1857 du = (modex / 16) * (bpp * 2); /* offset/pitch */
1858 if (modex % 16) du += bpp;
1859 SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f));
1860 SETIREG(SISCR, 0x13, (du & 0xff));
1861 du <<= 5;
1862 tmp8 = du >> 8;
1863 if (du & 0xff) tmp8++;
1864 SETIREG(SISSR, 0x10, tmp8);
1865 SETIREG(SISSR, 0x31, 0x00); /* VCLK */
1866 SETIREG(SISSR, 0x2b, 0x1b);
1867 SETIREG(SISSR, 0x2c, 0xe1);
1868 SETIREG(SISSR, 0x2d, 0x01);
1869 SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */
1870 SETIREG(SISSR, 0x08, 0xae);
1871 SETIREGAND(SISSR, 0x09, 0xf0);
1872 SETIREG(SISSR, 0x08, 0x34);
1873 SETIREGOR(SISSR, 0x3d, 0x01);
1874 SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */
1875 SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a);
1876 SETIREG(SISCR, 0x19, 0x00);
1877 SETIREGAND(SISCR, 0x1a, 0xfc);
1878 SETIREGAND(SISSR, 0x0f, 0xb7);
1879 SETIREGAND(SISSR, 0x31, 0xfb);
1880 SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0);
1881 SETIREGAND(SISSR, 0x32, 0xf3);
1882 SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03);
1883 SETIREG(SISCR, 0x52, 0x6c);
1884
1885 SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */
1886 SETIREG(SISCR, 0x0c, 0x00);
1887 SETIREG(SISSR, 0x0d, 0x00);
1888 SETIREGAND(SISSR, 0x37, 0xfe);
1889
1890 SETIREG(SISCR, 0x32, 0x20);
1891 SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */
1892 SETIREG(SISCR, 0x63, (cr63 & 0xbf));
1893 SETIREG(SISSR, 0x31, (sr31 & 0xfb));
1894
1895 if (touchengines) {
1896 SETIREG(SISSR, 0x20, 0xa1); /* enable engines */
1897 SETIREGOR(SISSR, 0x1e, 0x5a);
1898
1899 SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */
1900 SETIREG(SISSR, 0x27, 0x1f);
1901 SETIREG(SISSR, 0x26, 0x00);
1902 }
1903
1904 SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
1905
1906 return ret;
1907}
1908
1909static int
1910sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
1911{
1912 int ret = 0, i, j, bw, chab, iret, retry = 3;
1913 u8 tmp8, ramtype;
1914 u32 tmp32;
1915 static const char mclktable[] = {
1916 0x3b, 0x22, 0x01, 143,
1917 0x3b, 0x22, 0x01, 143,
1918 0x3b, 0x22, 0x01, 143,
1919 0x3b, 0x22, 0x01, 143
1920 };
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
1926 };
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
1935 };
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
1942 };
1943
1944 while (retry--) {
1945
1946 /* Enable VGA */
1947 ret = GETREG(SISVGAEN, &tmp8);
1948 ret |= SETREG(SISVGAEN, (tmp8 | 0x01));
1949
1950 /* Enable GPU access to VRAM */
1951 ret |= GETREG(SISMISCR, &tmp8);
1952 ret |= SETREG(SISMISCW, (tmp8 | 0x01));
1953
1954 if (ret) continue;
1955
1956 /* Reset registers */
1957 ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
1958 ret |= SETIREG(SISSR, 0x05, 0x86);
1959 ret |= SETIREGOR(SISSR, 0x20, 0x01);
1960
1961 ret |= SETREG(SISMISCW, 0x67);
1962
1963 for (i = 0x06; i <= 0x1f; i++) {
1964 ret |= SETIREG(SISSR, i, 0x00);
1965 }
1966 for (i = 0x21; i <= 0x27; i++) {
1967 ret |= SETIREG(SISSR, i, 0x00);
1968 }
1969 for (i = 0x31; i <= 0x3d; i++) {
1970 ret |= SETIREG(SISSR, i, 0x00);
1971 }
1972 for (i = 0x12; i <= 0x1b; i++) {
1973 ret |= SETIREG(SISSR, i, 0x00);
1974 }
1975 for (i = 0x79; i <= 0x7c; i++) {
1976 ret |= SETIREG(SISCR, i, 0x00);
1977 }
1978
1979 if (ret) continue;
1980
1981 ret |= SETIREG(SISCR, 0x63, 0x80);
1982
1983 ret |= GETIREG(SISSR, 0x3a, &ramtype);
1984 ramtype &= 0x03;
1985
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]);
1989
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]);
1993
1994 ret |= SETIREG(SISSR, 0x07, 0x18);
1995 ret |= SETIREG(SISSR, 0x11, 0x0f);
1996
1997 if (ret) continue;
1998
1999 for (i = 0x15, j = 0; i <= 0x1b; i++, j++) {
2000 ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]);
2001 }
2002 for (i = 0x40, j = 0; i <= 0x44; i++, j++) {
2003 ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]);
2004 }
2005
2006 ret |= SETIREG(SISCR, 0x49, 0xaa);
2007
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);
2013
2014 ret |= SETIREG(SISSR, 0x11, 0x0f);
2015
2016 ret |= SETIREGOR(SISPART1, 0x2f, 0x01);
2017
2018 ret |= SETIREGAND(SISCAP, 0x3f, 0xef);
2019
2020 if (ret) continue;
2021
2022 ret |= SETIREG(SISPART1, 0x00, 0x00);
2023
2024 ret |= GETIREG(SISSR, 0x13, &tmp8);
2025 tmp8 >>= 4;
2026
2027 ret |= SETIREG(SISPART1, 0x02, 0x00);
2028 ret |= SETIREG(SISPART1, 0x2e, 0x08);
2029
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);
2036
2037 ret |= SETIREG(SISSR, 0x27, 0x1f);
2038 ret |= SETIREG(SISSR, 0x31, 0x00);
2039 ret |= SETIREG(SISSR, 0x32, 0x11);
2040 ret |= SETIREG(SISSR, 0x33, 0x00);
2041
2042 if (ret) continue;
2043
2044 ret |= SETIREG(SISCR, 0x83, 0x00);
2045
2046 ret |= sisusb_set_default_mode(sisusb, 0);
2047
2048 ret |= SETIREGAND(SISSR, 0x21, 0xdf);
2049 ret |= SETIREGOR(SISSR, 0x01, 0x20);
2050 ret |= SETIREGOR(SISSR, 0x16, 0x0f);
2051
2052 ret |= sisusb_triggersr16(sisusb, ramtype);
2053
2054 /* Disable refresh */
2055 ret |= SETIREGAND(SISSR, 0x17, 0xf8);
2056 ret |= SETIREGOR(SISSR, 0x19, 0x03);
2057
2058 ret |= sisusb_getbuswidth(sisusb, &bw, &chab);
2059 ret |= sisusb_verify_mclk(sisusb);
2060
2061 if (ramtype <= 1) {
2062 ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
2063 if (iret) {
2064 printk(KERN_ERR "sisusbvga[%d]: RAM size "
2065 "detection failed, "
2066 "assuming 8MB video RAM\n",
2067 sisusb->minor);
2068 ret |= SETIREG(SISSR,0x14,0x31);
2069 /* TODO */
2070 }
2071 } else {
2072 printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
2073 "assuming 8MB video RAM\n",
2074 sisusb->minor);
2075 ret |= SETIREG(SISSR,0x14,0x31);
2076 /* *** TODO *** */
2077 }
2078
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]);
2083
2084 ret |= SETIREGOR(SISSR, 0x21, 0x20);
2085
2086 ret |= SETIREG(SISSR, 0x22, 0xfb);
2087 ret |= SETIREG(SISSR, 0x21, 0xa5);
2088
2089 if (ret == 0)
2090 break;
2091 }
2092
2093 return ret;
2094}
2095
2096#undef SETREG
2097#undef GETREG
2098#undef SETIREG
2099#undef GETIREG
2100#undef SETIREGOR
2101#undef SETIREGAND
2102#undef SETIREGANDOR
2103#undef READL
2104#undef WRITEL
2105
2106static void
2107sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
2108{
2109 u8 tmp8, tmp82, ramtype;
2110 int bw = 0;
2111 char *ramtypetext1 = NULL;
2112 const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM",
2113 "DDR SDRAM", "DDR SGRAM" };
2114 static const int busSDR[4] = {64, 64, 128, 128};
2115 static const int busDDR[4] = {32, 32, 64, 64};
2116 static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2};
2117
2118 sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8);
2119 sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82);
2120 sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype);
2121 sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024;
2122 ramtype &= 0x03;
2123 switch ((tmp8 >> 2) & 0x03) {
2124 case 0: ramtypetext1 = "1 ch/1 r";
2125 if (tmp82 & 0x10) {
2126 bw = 32;
2127 } else {
2128 bw = busSDR[(tmp8 & 0x03)];
2129 }
2130 break;
2131 case 1: ramtypetext1 = "1 ch/2 r";
2132 sisusb->vramsize <<= 1;
2133 bw = busSDR[(tmp8 & 0x03)];
2134 break;
2135 case 2: ramtypetext1 = "asymmeric";
2136 sisusb->vramsize += sisusb->vramsize/2;
2137 bw = busDDRA[(tmp8 & 0x03)];
2138 break;
2139 case 3: ramtypetext1 = "2 channel";
2140 sisusb->vramsize <<= 1;
2141 bw = busDDR[(tmp8 & 0x03)];
2142 break;
2143 }
2144
2145 printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
2146 sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
2147 ramtypetext2[ramtype], bw);
2148}
2149
2150static int
2151sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb)
2152{
2153 struct sisusb_packet packet;
2154 int ret;
2155 u32 tmp32;
2156
2157 /* Do some magic */
2158 packet.header = 0x001f;
2159 packet.address = 0x00000324;
2160 packet.data = 0x00000004;
2161 ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2162
2163 packet.header = 0x001f;
2164 packet.address = 0x00000364;
2165 packet.data = 0x00000004;
2166 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2167
2168 packet.header = 0x001f;
2169 packet.address = 0x00000384;
2170 packet.data = 0x00000004;
2171 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2172
2173 packet.header = 0x001f;
2174 packet.address = 0x00000100;
2175 packet.data = 0x00000700;
2176 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2177
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);
2183
2184 /* Init BAR 0 (VRAM) */
2185 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2186 ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0);
2187 ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32);
2188 tmp32 &= 0x0f;
2189 tmp32 |= SISUSB_PCI_MEMBASE;
2190 ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32);
2191
2192 /* Init BAR 1 (MMIO) */
2193 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2194 ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0);
2195 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2196 tmp32 &= 0x0f;
2197 tmp32 |= SISUSB_PCI_MMIOBASE;
2198 ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32);
2199
2200 /* Init BAR 2 (i/o ports) */
2201 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2202 ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0);
2203 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2204 tmp32 &= 0x0f;
2205 tmp32 |= SISUSB_PCI_IOPORTBASE;
2206 ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32);
2207
2208 /* Enable memory and i/o access */
2209 ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32);
2210 tmp32 |= 0x3;
2211 ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32);
2212
2213 if (ret == 0) {
2214 /* Some further magic */
2215 packet.header = 0x001f;
2216 packet.address = 0x00000050;
2217 packet.data = 0x000000ff;
2218 ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0);
2219 }
2220
2221 return ret;
2222}
2223
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.
2227 */
2228
2229static int
2230sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2231{
2232 int ret = 0, test = 0;
2233 u32 tmp32;
2234
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++;
2240
2241 ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32);
2242 if (ret) return ret;
2243 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++;
2244
2245 ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32);
2246 if (ret) return ret;
2247 if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++;
2248 }
2249
2250 /* No? So reset the device */
2251 if ((sisusb->devinit == 0) || (test != 3)) {
2252
2253 ret |= sisusb_do_init_gfxdevice(sisusb);
2254
2255 if (ret == 0)
2256 sisusb->devinit = 1;
2257
2258 }
2259
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);
2267 }
2268 }
2269
2270 return ret;
2271}
2272
2273/* fops */
2274
2275static int
2276sisusb_open(struct inode *inode, struct file *file)
2277{
2278 struct sisusb_usb_data *sisusb;
2279 struct usb_interface *interface;
2280 int subminor = iminor(inode);
2281
2282 down(&disconnect_sem);
2283
2284 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
2285 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
2286 subminor);
2287 up(&disconnect_sem);
2288 return -ENODEV;
2289 }
2290
2291 if (!(sisusb = usb_get_intfdata(interface))) {
2292 up(&disconnect_sem);
2293 return -ENODEV;
2294 }
2295
2296 down(&sisusb->lock);
2297
2298 if (!sisusb->present || !sisusb->ready) {
2299 up(&sisusb->lock);
2300 up(&disconnect_sem);
2301 return -ENODEV;
2302 }
2303
2304 if (sisusb->isopen) {
2305 up(&sisusb->lock);
2306 up(&disconnect_sem);
2307 return -EBUSY;
2308 }
2309
2310 if (!sisusb->devinit) {
2311 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
2312 if (sisusb_init_gfxdevice(sisusb, 0)) {
2313 up(&sisusb->lock);
2314 up(&disconnect_sem);
2315 printk(KERN_ERR
2316 "sisusbvga[%d]: Failed to initialize "
2317 "device\n",
2318 sisusb->minor);
2319 return -EIO;
2320 }
2321 } else {
2322 up(&sisusb->lock);
2323 up(&disconnect_sem);
2324 printk(KERN_ERR
2325 "sisusbvga[%d]: Device not attached to "
2326 "USB 2.0 hub\n",
2327 sisusb->minor);
2328 return -EIO;
2329 }
2330 }
2331
2332 /* increment usage count for the device */
2333 kref_get(&sisusb->kref);
2334
2335 sisusb->isopen = 1;
2336
2337 file->private_data = sisusb;
2338
2339 up(&sisusb->lock);
2340
2341 up(&disconnect_sem);
2342
2343 printk(KERN_DEBUG "sisusbvga[%d]: opened", sisusb->minor);
2344
2345 return 0;
2346}
2347
2348static void
2349sisusb_delete(struct kref *kref)
2350{
2351 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
2352
2353 if (!sisusb)
2354 return;
2355
2356 if (sisusb->sisusb_dev)
2357 usb_put_dev(sisusb->sisusb_dev);
2358
2359 sisusb->sisusb_dev = NULL;
2360 sisusb_free_buffers(sisusb);
2361 sisusb_free_urbs(sisusb);
2362 kfree(sisusb);
2363}
2364
2365static int
2366sisusb_release(struct inode *inode, struct file *file)
2367{
2368 struct sisusb_usb_data *sisusb;
2369 int myminor;
2370
2371 down(&disconnect_sem);
2372
2373 if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
2374 up(&disconnect_sem);
2375 return -ENODEV;
2376 }
2377
2378 down(&sisusb->lock);
2379
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);
2384 }
2385
2386 myminor = sisusb->minor;
2387
2388 sisusb->isopen = 0;
2389 file->private_data = NULL;
2390
2391 up(&sisusb->lock);
2392
2393 /* decrement the usage count on our device */
2394 kref_put(&sisusb->kref, sisusb_delete);
2395
2396 up(&disconnect_sem);
2397
2398 printk(KERN_DEBUG "sisusbvga[%d]: released", myminor);
2399
2400 return 0;
2401}
2402
2403static ssize_t
2404sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2405{
2406 struct sisusb_usb_data *sisusb;
2407 ssize_t bytes_read = 0;
2408 int errno = 0;
2409 u8 buf8;
2410 u16 buf16;
2411 u32 buf32, address;
2412
2413 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2414 return -ENODEV;
2415
2416 down(&sisusb->lock);
2417
2418 /* Sanity check */
2419 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2420 up(&sisusb->lock);
2421 return -ENODEV;
2422 }
2423
2424 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2425 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2426
2427 address = (*ppos) -
2428 SISUSB_PCI_PSEUDO_IOPORTBASE +
2429 SISUSB_PCI_IOPORTBASE;
2430
2431 /* Read i/o ports
2432 * Byte, word and long(32) can be read. As this
2433 * emulates inX instructions, the data returned is
2434 * in machine-endianness.
2435 */
2436 switch (count) {
2437
2438 case 1:
2439 if (sisusb_read_memio_byte(sisusb,
2440 SISUSB_TYPE_IO,
2441 address, &buf8))
2442 errno = -EIO;
2443 else if (put_user(buf8, (u8 __user *)buffer))
2444 errno = -EFAULT;
2445 else
2446 bytes_read = 1;
2447
2448 break;
2449
2450 case 2:
2451 if (sisusb_read_memio_word(sisusb,
2452 SISUSB_TYPE_IO,
2453 address, &buf16))
2454 errno = -EIO;
2455 else if (put_user(buf16, (u16 __user *)buffer))
2456 errno = -EFAULT;
2457 else
2458 bytes_read = 2;
2459
2460 break;
2461
2462 case 4:
2463 if (sisusb_read_memio_long(sisusb,
2464 SISUSB_TYPE_IO,
2465 address, &buf32))
2466 errno = -EIO;
2467 else if (put_user(buf32, (u32 __user *)buffer))
2468 errno = -EFAULT;
2469 else
2470 bytes_read = 4;
2471
2472 break;
2473
2474 default:
2475 errno = -EIO;
2476
2477 }
2478
2479 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2480 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2481
2482 address = (*ppos) -
2483 SISUSB_PCI_PSEUDO_MEMBASE +
2484 SISUSB_PCI_MEMBASE;
2485
2486 /* Read video ram
2487 * Remember: Data delivered is never endian-corrected
2488 */
2489 errno = sisusb_read_mem_bulk(sisusb, address,
2490 NULL, count, buffer, &bytes_read);
2491
2492 if (bytes_read)
2493 errno = bytes_read;
2494
2495 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2496 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2497
2498 address = (*ppos) -
2499 SISUSB_PCI_PSEUDO_MMIOBASE +
2500 SISUSB_PCI_MMIOBASE;
2501
2502 /* Read MMIO
2503 * Remember: Data delivered is never endian-corrected
2504 */
2505 errno = sisusb_read_mem_bulk(sisusb, address,
2506 NULL, count, buffer, &bytes_read);
2507
2508 if (bytes_read)
2509 errno = bytes_read;
2510
2511 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2512 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) {
2513
2514 if (count != 4) {
2515 up(&sisusb->lock);
2516 return -EINVAL;
2517 }
2518
2519 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2520
2521 /* Read PCI config register
2522 * Return value delivered in machine endianness.
2523 */
2524 if (sisusb_read_pci_config(sisusb, address, &buf32))
2525 errno = -EIO;
2526 else if (put_user(buf32, (u32 __user *)buffer))
2527 errno = -EFAULT;
2528 else
2529 bytes_read = 4;
2530
2531 } else {
2532
2533 errno = -EBADFD;
2534
2535 }
2536
2537 (*ppos) += bytes_read;
2538
2539 up(&sisusb->lock);
2540
2541 return errno ? errno : bytes_read;
2542}
2543
2544static ssize_t
2545sisusb_write(struct file *file, const char __user *buffer, size_t count,
2546 loff_t *ppos)
2547{
2548 struct sisusb_usb_data *sisusb;
2549 int errno = 0;
2550 ssize_t bytes_written = 0;
2551 u8 buf8;
2552 u16 buf16;
2553 u32 buf32, address;
2554
2555 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2556 return -ENODEV;
2557
2558 down(&sisusb->lock);
2559
2560 /* Sanity check */
2561 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2562 up(&sisusb->lock);
2563 return -ENODEV;
2564 }
2565
2566 if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE &&
2567 (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) {
2568
2569 address = (*ppos) -
2570 SISUSB_PCI_PSEUDO_IOPORTBASE +
2571 SISUSB_PCI_IOPORTBASE;
2572
2573 /* Write i/o ports
2574 * Byte, word and long(32) can be written. As this
2575 * emulates outX instructions, the data is expected
2576 * in machine-endianness.
2577 */
2578 switch (count) {
2579
2580 case 1:
2581 if (get_user(buf8, (u8 __user *)buffer))
2582 errno = -EFAULT;
2583 else if (sisusb_write_memio_byte(sisusb,
2584 SISUSB_TYPE_IO,
2585 address, buf8))
2586 errno = -EIO;
2587 else
2588 bytes_written = 1;
2589
2590 break;
2591
2592 case 2:
2593 if (get_user(buf16, (u16 __user *)buffer))
2594 errno = -EFAULT;
2595 else if (sisusb_write_memio_word(sisusb,
2596 SISUSB_TYPE_IO,
2597 address, buf16))
2598 errno = -EIO;
2599 else
2600 bytes_written = 2;
2601
2602 break;
2603
2604 case 4:
2605 if (get_user(buf32, (u32 __user *)buffer))
2606 errno = -EFAULT;
2607 else if (sisusb_write_memio_long(sisusb,
2608 SISUSB_TYPE_IO,
2609 address, buf32))
2610 errno = -EIO;
2611 else
2612 bytes_written = 4;
2613
2614 break;
2615
2616 default:
2617 errno = -EIO;
2618 }
2619
2620 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE &&
2621 (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) {
2622
2623 address = (*ppos) -
2624 SISUSB_PCI_PSEUDO_MEMBASE +
2625 SISUSB_PCI_MEMBASE;
2626
2627 /* Write video ram.
2628 * Buffer is copied 1:1, therefore, on big-endian
2629 * machines, the data must be swapped by userland
2630 * in advance (if applicable; no swapping in 8bpp
2631 * mode or if YUV data is being transferred).
2632 */
2633 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2634 count, buffer, 0, &bytes_written);
2635
2636 if (bytes_written)
2637 errno = bytes_written;
2638
2639 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE &&
2640 (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) {
2641
2642 address = (*ppos) -
2643 SISUSB_PCI_PSEUDO_MMIOBASE +
2644 SISUSB_PCI_MMIOBASE;
2645
2646 /* Write MMIO.
2647 * Buffer is copied 1:1, therefore, on big-endian
2648 * machines, the data must be swapped by userland
2649 * in advance.
2650 */
2651 errno = sisusb_write_mem_bulk(sisusb, address, NULL,
2652 count, buffer, 0, &bytes_written);
2653
2654 if (bytes_written)
2655 errno = bytes_written;
2656
2657 } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE &&
2658 (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) {
2659
2660 if (count != 4) {
2661 up(&sisusb->lock);
2662 return -EINVAL;
2663 }
2664
2665 address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE;
2666
2667 /* Write PCI config register.
2668 * Given value expected in machine endianness.
2669 */
2670 if (get_user(buf32, (u32 __user *)buffer))
2671 errno = -EFAULT;
2672 else if (sisusb_write_pci_config(sisusb, address, buf32))
2673 errno = -EIO;
2674 else
2675 bytes_written = 4;
2676
2677
2678 } else {
2679
2680 /* Error */
2681 errno = -EBADFD;
2682
2683 }
2684
2685 (*ppos) += bytes_written;
2686
2687 up(&sisusb->lock);
2688
2689 return errno ? errno : bytes_written;
2690}
2691
2692static loff_t
2693sisusb_lseek(struct file *file, loff_t offset, int orig)
2694{
2695 struct sisusb_usb_data *sisusb;
2696 loff_t ret;
2697
2698 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2699 return -ENODEV;
2700
2701 down(&sisusb->lock);
2702
2703 /* Sanity check */
2704 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2705 up(&sisusb->lock);
2706 return -ENODEV;
2707 }
2708
2709 switch (orig) {
2710 case 0:
2711 file->f_pos = offset;
2712 ret = file->f_pos;
2713 /* never negative, no force_successful_syscall needed */
2714 break;
2715 case 1:
2716 file->f_pos += offset;
2717 ret = file->f_pos;
2718 /* never negative, no force_successful_syscall needed */
2719 break;
2720 default:
2721 /* seeking relative to "end of file" is not supported */
2722 ret = -EINVAL;
2723 }
2724
2725 up(&sisusb->lock);
2726 return ret;
2727}
2728
2729static int
2730sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2731 unsigned long arg)
2732{
2733 int retval, port, length;
2734 u32 address;
2735
2736 port = y->data3 -
2737 SISUSB_PCI_PSEUDO_IOPORTBASE +
2738 SISUSB_PCI_IOPORTBASE;
2739
2740 switch (y->operation) {
2741 case SUCMD_GET:
2742 retval = sisusb_getidxreg(sisusb, port,
2743 y->data0, &y->data1);
2744 if (!retval) {
2745 if (copy_to_user((void __user *)arg, y,
2746 sizeof(*y)))
2747 retval = -EFAULT;
2748 }
2749 break;
2750
2751 case SUCMD_SET:
2752 retval = sisusb_setidxreg(sisusb, port,
2753 y->data0, y->data1);
2754 break;
2755
2756 case SUCMD_SETOR:
2757 retval = sisusb_setidxregor(sisusb, port,
2758 y->data0, y->data1);
2759 break;
2760
2761 case SUCMD_SETAND:
2762 retval = sisusb_setidxregand(sisusb, port,
2763 y->data0, y->data1);
2764 break;
2765
2766 case SUCMD_SETANDOR:
2767 retval = sisusb_setidxregandor(sisusb, port,
2768 y->data0, y->data1, y->data2);
2769 break;
2770
2771 case SUCMD_SETMASK:
2772 retval = sisusb_setidxregmask(sisusb, port,
2773 y->data0, y->data1, y->data2);
2774 break;
2775
2776 case SUCMD_CLRSCR:
2777 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
2778 address = y->data3 -
2779 SISUSB_PCI_PSEUDO_MEMBASE +
2780 SISUSB_PCI_MEMBASE;
2781 retval = sisusb_clear_vram(sisusb, address, length);
2782 break;
2783
2784 default:
2785 retval = -EINVAL;
2786 }
2787
2788 if(retval > 0)
2789 retval = -EIO;
2790
2791 return retval;
2792}
2793
2794static int
2795sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
2796 unsigned long arg)
2797{
2798 struct sisusb_usb_data *sisusb;
2799 struct sisusb_info x;
2800 struct sisusb_command y;
2801 int retval = 0;
2802 u32 __user *argp = (u32 __user *)arg;
2803
2804 if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
2805 return -ENODEV;
2806
2807 down(&sisusb->lock);
2808
2809 /* Sanity check */
2810 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) {
2811 retval = -ENODEV;
2812 goto err_out;
2813 }
2814
2815 switch (cmd) {
2816
2817 case SISUSB_GET_CONFIG_SIZE:
2818
2819 if (put_user(sizeof(x), argp))
2820 retval = -EFAULT;
2821
2822 break;
2823
2824 case SISUSB_GET_CONFIG:
2825
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;
2838
2839 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
2840 retval = -EFAULT;
2841
2842 break;
2843
2844 case SISUSB_COMMAND:
2845
2846 if (copy_from_user(&y, (void __user *)arg, sizeof(y)))
2847 retval = -EFAULT;
2848 else
2849 retval = sisusb_handle_command(sisusb, &y, arg);
2850
2851 break;
2852
2853 default:
2854 retval = -EINVAL;
2855 break;
2856 }
2857
2858err_out:
2859 up(&sisusb->lock);
2860 return retval;
2861}
2862
2863#ifdef SISUSB_NEW_CONFIG_COMPAT
2864static long
2865sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
2866{
2867 long retval;
2868
2869 switch (cmd) {
2870 case SISUSB_GET_CONFIG_SIZE:
2871 case SISUSB_GET_CONFIG:
2872 case SISUSB_COMMAND:
2873 lock_kernel();
2874 retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg);
2875 unlock_kernel();
2876 return retval;
2877
2878 default:
2879 return -ENOIOCTLCMD;
2880 }
2881}
2882#endif
2883
2884static struct file_operations usb_sisusb_fops = {
2885 .owner = THIS_MODULE,
2886 .open = sisusb_open,
2887 .release = sisusb_release,
2888 .read = sisusb_read,
2889 .write = sisusb_write,
2890 .llseek = sisusb_lseek,
2891#ifdef SISUSB_NEW_CONFIG_COMPAT
2892 .compat_ioctl = sisusb_compat_ioctl,
2893#endif
2894 .ioctl = sisusb_ioctl
2895};
2896
2897static 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
2902};
2903
2904static int sisusb_probe(struct usb_interface *intf,
2905 const struct usb_device_id *id)
2906{
2907 struct usb_device *dev = interface_to_usbdev(intf);
2908 struct sisusb_usb_data *sisusb;
2909 int retval = 0, i;
2910 const char *memfail =
2911 KERN_ERR
2912 "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
2913
2914 printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
2915 dev->devnum);
2916
2917 /* Allocate memory for our private */
2918 if (!(sisusb = kmalloc(sizeof(*sisusb), GFP_KERNEL))) {
2919 printk(KERN_ERR
2920 "sisusb: Failed to allocate memory for private data\n");
2921 return -ENOMEM;
2922 }
2923 memset(sisusb, 0, sizeof(*sisusb));
2924 kref_init(&sisusb->kref);
2925
2926 init_MUTEX(&(sisusb->lock));
2927
2928 /* Register device */
2929 if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
2930 printk(KERN_ERR
2931 "sisusb: Failed to get a minor for device %d\n",
2932 dev->devnum);
2933 retval = -ENODEV;
2934 goto error_1;
2935 }
2936
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 */
2944
2945 /* Allocate buffers */
2946 sisusb->ibufsize = SISUSB_IBUF_SIZE;
2947 if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
2948 GFP_KERNEL, &sisusb->transfer_dma_in))) {
2949 printk(memfail, "input", sisusb->minor);
2950 retval = -ENOMEM;
2951 goto error_2;
2952 }
2953
2954 sisusb->numobufs = 0;
2955 sisusb->obufsize = SISUSB_OBUF_SIZE;
2956 for (i = 0; i < NUMOBUFS; i++) {
2957 if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE,
2958 GFP_KERNEL,
2959 &sisusb->transfer_dma_out[i]))) {
2960 if (i == 0) {
2961 printk(memfail, "output", sisusb->minor);
2962 retval = -ENOMEM;
2963 goto error_3;
2964 }
2965 break;
2966 } else
2967 sisusb->numobufs++;
2968
2969 }
2970
2971 /* Allocate URBs */
2972 if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
2973 printk(KERN_ERR
2974 "sisusbvga[%d]: Failed to allocate URBs\n",
2975 sisusb->minor);
2976 retval = -ENOMEM;
2977 goto error_3;
2978 }
2979 sisusb->completein = 1;
2980
2981 for (i = 0; i < sisusb->numobufs; i++) {
2982 if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
2983 printk(KERN_ERR
2984 "sisusbvga[%d]: Failed to allocate URBs\n",
2985 sisusb->minor);
2986 retval = -ENOMEM;
2987 goto error_4;
2988 }
2989 sisusb->urbout_context[i].sisusb = (void *)sisusb;
2990 sisusb->urbout_context[i].urbindex = i;
2991 sisusb->urbstatus[i] = 0;
2992 }
2993
2994 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
2995 sisusb->minor, sisusb->numobufs);
2996
2997 /* Do remaining init stuff */
2998
2999 init_waitqueue_head(&sisusb->wait_q);
3000
3001 usb_set_intfdata(intf, sisusb);
3002
3003#ifdef SISUSB_OLD_CONFIG_COMPAT
3004 {
3005 int ret;
3006 /* Our ioctls are all "32/64bit compatible" */
3007 ret = register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
3008 ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
3009 ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
3010 if (ret)
3011 printk(KERN_ERR
3012 "sisusbvga[%d]: Error registering ioctl32 "
3013 "translations\n",
3014 sisusb->minor);
3015 else
3016 sisusb->ioctl32registered = 1;
3017
3018 }
3019#endif
3020
3021 sisusb->present = 1;
3022
3023 if (dev->speed == USB_SPEED_HIGH) {
3024 if (sisusb_init_gfxdevice(sisusb, 1))
3025 printk(KERN_ERR
3026 "sisusbvga[%d]: Failed to early "
3027 "initialize device\n",
3028 sisusb->minor);
3029
3030 } else
3031 printk(KERN_INFO
3032 "sisusbvga[%d]: Not attached to USB 2.0 hub, "
3033 "deferring init\n",
3034 sisusb->minor);
3035
3036 sisusb->ready = 1;
3037
3038 return 0;
3039
3040error_4:
3041 sisusb_free_urbs(sisusb);
3042error_3:
3043 sisusb_free_buffers(sisusb);
3044error_2:
3045 usb_deregister_dev(intf, &usb_sisusb_class);
3046error_1:
3047 kfree(sisusb);
3048 return retval;
3049}
3050
3051static void sisusb_disconnect(struct usb_interface *intf)
3052{
3053 struct sisusb_usb_data *sisusb;
3054 int minor;
3055
3056 down(&disconnect_sem);
3057
3058 /* This should *not* happen */
3059 if (!(sisusb = usb_get_intfdata(intf))) {
3060 up(&disconnect_sem);
3061 return;
3062 }
3063
3064 down(&sisusb->lock);
3065
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);
3069
3070 minor = sisusb->minor;
3071
3072 usb_set_intfdata(intf, NULL);
3073
3074 usb_deregister_dev(intf, &usb_sisusb_class);
3075
3076#ifdef SISUSB_OLD_CONFIG_COMPAT
3077 if (sisusb->ioctl32registered) {
3078 int ret;
3079 sisusb->ioctl32registered = 0;
3080 ret = unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
3081 ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
3082 ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
3083 if (ret) {
3084 printk(KERN_ERR
3085 "sisusbvga[%d]: Error unregistering "
3086 "ioctl32 translations\n",
3087 minor);
3088 }
3089 }
3090#endif
3091
3092 sisusb->present = 0;
3093 sisusb->ready = 0;
3094
3095 up(&sisusb->lock);
3096
3097 /* decrement our usage count */
3098 kref_put(&sisusb->kref, sisusb_delete);
3099
3100 up(&disconnect_sem);
3101
3102 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
3103}
3104
3105static struct usb_device_id sisusb_table [] = {
3106 { USB_DEVICE(0x0711, 0x0900) },
3107 { }
3108};
3109
3110MODULE_DEVICE_TABLE (usb, sisusb_table);
3111
3112static struct usb_driver sisusb_driver = {
3113 .owner = THIS_MODULE,
3114 .name = "sisusb",
3115 .probe = sisusb_probe,
3116 .disconnect = sisusb_disconnect,
3117 .id_table = sisusb_table
3118};
3119
3120static int __init usb_sisusb_init(void)
3121{
3122 int retval;
3123
3124 if (!(retval = usb_register(&sisusb_driver))) {
3125 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3126 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3127 printk(KERN_INFO
3128 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3129 }
3130
3131 return retval;
3132}
3133
3134static void __exit usb_sisusb_exit(void)
3135{
3136 usb_deregister(&sisusb_driver);
3137}
3138
3139module_init(usb_sisusb_init);
3140module_exit(usb_sisusb_exit);
3141
3142MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3143MODULE_DESCRIPTION("sisusb - Driver for Net2280/SiS315-based USB2VGA dongles");
3144MODULE_LICENSE("GPL");
3145