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

source code of linux/drivers/usb/misc/sisusbvga/sisusbvga.c