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