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