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