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