aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2005-09-12 16:32:20 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-12 16:32:20 -0400
commitcc6120c6687c34501c0b1d49b4d7e46c63911fed (patch)
treea43eeb2ed68ba9ef544fe1f1dc108c8848ba0df9 /drivers
parent7b799bc82b5eebb8937ff773e4c4be7260698627 (diff)
parentf5e09b7cac4a2705f55830db64d448c062e84e8e (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/class/audio.c12
-rw-r--r--drivers/usb/core/hcd.c3
-rw-r--r--drivers/usb/core/hub.c11
-rw-r--r--drivers/usb/gadget/inode.c1
-rw-r--r--drivers/usb/host/ehci-hcd.c28
-rw-r--r--drivers/usb/host/ehci-hub.c27
-rw-r--r--drivers/usb/host/ehci.h1
-rw-r--r--drivers/usb/host/ohci-dbg.c9
-rw-r--r--drivers/usb/host/ohci-hcd.c14
-rw-r--r--drivers/usb/host/ohci-hub.c22
-rw-r--r--drivers/usb/host/ohci-pxa27x.c48
-rw-r--r--drivers/usb/host/ohci.h1
-rw-r--r--drivers/usb/host/uhci-hcd.c62
-rw-r--r--drivers/usb/host/uhci-hcd.h11
-rw-r--r--drivers/usb/host/uhci-hub.c11
-rw-r--r--drivers/usb/host/uhci-q.c2
-rw-r--r--drivers/usb/input/Kconfig20
-rw-r--r--drivers/usb/input/Makefile1
-rw-r--r--drivers/usb/input/appletouch.c469
-rw-r--r--drivers/usb/input/hid-core.c2
-rw-r--r--drivers/usb/misc/sisusbvga/Kconfig42
-rw-r--r--drivers/usb/misc/sisusbvga/Makefile4
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c463
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.h73
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c1658
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.c1047
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.h830
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_struct.h169
-rw-r--r--drivers/usb/misc/uss720.c393
-rw-r--r--drivers/usb/mon/mon_text.c2
-rw-r--r--drivers/usb/serial/cp2101.c5
-rw-r--r--drivers/usb/serial/cypress_m8.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.c2
-rw-r--r--drivers/usb/serial/pl2303.c4
-rw-r--r--drivers/usb/serial/pl2303.h4
-rw-r--r--drivers/usb/storage/scsiglue.c20
-rw-r--r--drivers/usb/storage/unusual_devs.h35
-rw-r--r--drivers/usb/storage/usb.c11
-rw-r--r--drivers/video/console/Kconfig2
-rw-r--r--drivers/video/console/Makefile4
40 files changed, 5184 insertions, 342 deletions
diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c
index f8f21567cc22..50858273f8d3 100644
--- a/drivers/usb/class/audio.c
+++ b/drivers/usb/class/audio.c
@@ -631,8 +631,10 @@ static void usbin_stop(struct usb_audiodev *as)
631 i = u->flags; 631 i = u->flags;
632 spin_unlock_irqrestore(&as->lock, flags); 632 spin_unlock_irqrestore(&as->lock, flags);
633 while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { 633 while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
634 set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); 634 if (notkilled)
635 schedule_timeout(1); 635 schedule_timeout_interruptible(1);
636 else
637 schedule_timeout_uninterruptible(1);
636 spin_lock_irqsave(&as->lock, flags); 638 spin_lock_irqsave(&as->lock, flags);
637 i = u->flags; 639 i = u->flags;
638 spin_unlock_irqrestore(&as->lock, flags); 640 spin_unlock_irqrestore(&as->lock, flags);
@@ -1102,8 +1104,10 @@ static void usbout_stop(struct usb_audiodev *as)
1102 i = u->flags; 1104 i = u->flags;
1103 spin_unlock_irqrestore(&as->lock, flags); 1105 spin_unlock_irqrestore(&as->lock, flags);
1104 while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { 1106 while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
1105 set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); 1107 if (notkilled)
1106 schedule_timeout(1); 1108 schedule_timeout_interruptible(1);
1109 else
1110 schedule_timeout_uninterruptible(1);
1107 spin_lock_irqsave(&as->lock, flags); 1111 spin_lock_irqsave(&as->lock, flags);
1108 i = u->flags; 1112 i = u->flags;
1109 spin_unlock_irqrestore(&as->lock, flags); 1113 spin_unlock_irqrestore(&as->lock, flags);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 12ecdb03ee5f..1017a97a418b 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1606,7 +1606,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
1606 return IRQ_NONE; 1606 return IRQ_NONE;
1607 1607
1608 hcd->saw_irq = 1; 1608 hcd->saw_irq = 1;
1609 if (hcd->state != start && hcd->state == HC_STATE_HALT) 1609 if (hcd->state == HC_STATE_HALT)
1610 usb_hc_died (hcd); 1610 usb_hc_died (hcd);
1611 return IRQ_HANDLED; 1611 return IRQ_HANDLED;
1612} 1612}
@@ -1630,7 +1630,6 @@ void usb_hc_died (struct usb_hcd *hcd)
1630 spin_lock_irqsave (&hcd_root_hub_lock, flags); 1630 spin_lock_irqsave (&hcd_root_hub_lock, flags);
1631 if (hcd->rh_registered) { 1631 if (hcd->rh_registered) {
1632 hcd->poll_rh = 0; 1632 hcd->poll_rh = 0;
1633 del_timer(&hcd->rh_timer);
1634 1633
1635 /* make khubd clean up old urbs and devices */ 1634 /* make khubd clean up old urbs and devices */
1636 usb_set_device_state (hcd->self.root_hub, 1635 usb_set_device_state (hcd->self.root_hub,
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 758c7f0ed159..a12cab5314e9 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -435,6 +435,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
435static void hub_power_on(struct usb_hub *hub) 435static void hub_power_on(struct usb_hub *hub)
436{ 436{
437 int port1; 437 int port1;
438 unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
438 439
439 /* if hub supports power switching, enable power on each port */ 440 /* if hub supports power switching, enable power on each port */
440 if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) { 441 if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
@@ -444,8 +445,8 @@ static void hub_power_on(struct usb_hub *hub)
444 USB_PORT_FEAT_POWER); 445 USB_PORT_FEAT_POWER);
445 } 446 }
446 447
447 /* Wait for power to be enabled */ 448 /* Wait at least 100 msec for power to become stable */
448 msleep(hub->descriptor->bPwrOn2PwrGood * 2); 449 msleep(max(pgood_delay, (unsigned) 100));
449} 450}
450 451
451static void hub_quiesce(struct usb_hub *hub) 452static void hub_quiesce(struct usb_hub *hub)
@@ -1460,7 +1461,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
1460 port1, status); 1461 port1, status);
1461 else { 1462 else {
1462 status = hub_port_wait_reset(hub, port1, udev, delay); 1463 status = hub_port_wait_reset(hub, port1, udev, delay);
1463 if (status) 1464 if (status && status != -ENOTCONN)
1464 dev_dbg(hub->intfdev, 1465 dev_dbg(hub->intfdev,
1465 "port_wait_reset: err = %d\n", 1466 "port_wait_reset: err = %d\n",
1466 status); 1467 status);
@@ -1469,8 +1470,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
1469 /* return on disconnect or reset */ 1470 /* return on disconnect or reset */
1470 switch (status) { 1471 switch (status) {
1471 case 0: 1472 case 0:
1472 /* TRSTRCY = 10 ms */ 1473 /* TRSTRCY = 10 ms; plus some extra */
1473 msleep(10); 1474 msleep(10 + 40);
1474 /* FALL THROUGH */ 1475 /* FALL THROUGH */
1475 case -ENOTCONN: 1476 case -ENOTCONN:
1476 case -ENODEV: 1477 case -ENODEV:
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 020815397a49..5c40980a5bd9 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -483,6 +483,7 @@ ep_release (struct inode *inode, struct file *fd)
483 data->state = STATE_EP_DISABLED; 483 data->state = STATE_EP_DISABLED;
484 data->desc.bDescriptorType = 0; 484 data->desc.bDescriptorType = 0;
485 data->hs_desc.bDescriptorType = 0; 485 data->hs_desc.bDescriptorType = 0;
486 usb_ep_disable(data->ep);
486 } 487 }
487 put_ep (data); 488 put_ep (data);
488 return 0; 489 return 0;
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 2507e898af09..b948ffd94f45 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -400,6 +400,23 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
400 return -EIO; 400 return -EIO;
401 } 401 }
402 break; 402 break;
403 case PCI_VENDOR_ID_NVIDIA:
404 /* NVidia reports that certain chips don't handle
405 * QH, ITD, or SITD addresses above 2GB. (But TD,
406 * data buffer, and periodic schedule are normal.)
407 */
408 switch (pdev->device) {
409 case 0x003c: /* MCP04 */
410 case 0x005b: /* CK804 */
411 case 0x00d8: /* CK8 */
412 case 0x00e8: /* CK8S */
413 if (pci_set_consistent_dma_mask(pdev,
414 DMA_31BIT_MASK) < 0)
415 ehci_warn (ehci, "can't enable NVidia "
416 "workaround for >2GB RAM\n");
417 break;
418 }
419 break;
403 } 420 }
404 421
405 /* optional debug port, normally in the first BAR */ 422 /* optional debug port, normally in the first BAR */
@@ -759,12 +776,16 @@ static int ehci_resume (struct usb_hcd *hcd)
759 if (time_before (jiffies, ehci->next_statechange)) 776 if (time_before (jiffies, ehci->next_statechange))
760 msleep (100); 777 msleep (100);
761 778
762 /* If any port is suspended, we know we can/must resume the HC. */ 779 /* If any port is suspended (or owned by the companion),
780 * we know we can/must resume the HC (and mustn't reset it).
781 */
763 for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) { 782 for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
764 u32 status; 783 u32 status;
765 port--; 784 port--;
766 status = readl (&ehci->regs->port_status [port]); 785 status = readl (&ehci->regs->port_status [port]);
767 if (status & PORT_SUSPEND) { 786 if (!(status & PORT_POWER))
787 continue;
788 if (status & (PORT_SUSPEND | PORT_OWNER)) {
768 down (&hcd->self.root_hub->serialize); 789 down (&hcd->self.root_hub->serialize);
769 retval = ehci_hub_resume (hcd); 790 retval = ehci_hub_resume (hcd);
770 up (&hcd->self.root_hub->serialize); 791 up (&hcd->self.root_hub->serialize);
@@ -1126,8 +1147,7 @@ rescan:
1126 case QH_STATE_UNLINK: /* wait for hw to finish? */ 1147 case QH_STATE_UNLINK: /* wait for hw to finish? */
1127idle_timeout: 1148idle_timeout:
1128 spin_unlock_irqrestore (&ehci->lock, flags); 1149 spin_unlock_irqrestore (&ehci->lock, flags);
1129 set_current_state (TASK_UNINTERRUPTIBLE); 1150 schedule_timeout_uninterruptible(1);
1130 schedule_timeout (1);
1131 goto rescan; 1151 goto rescan;
1132 case QH_STATE_IDLE: /* fully unlinked */ 1152 case QH_STATE_IDLE: /* fully unlinked */
1133 if (list_empty (&qh->qtd_list)) { 1153 if (list_empty (&qh->qtd_list)) {
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 36cc1f2218d5..18d3f2270316 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -54,7 +54,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
54 /* suspend any active/unsuspended ports, maybe allow wakeup */ 54 /* suspend any active/unsuspended ports, maybe allow wakeup */
55 while (port--) { 55 while (port--) {
56 u32 __iomem *reg = &ehci->regs->port_status [port]; 56 u32 __iomem *reg = &ehci->regs->port_status [port];
57 u32 t1 = readl (reg); 57 u32 t1 = readl (reg) & ~PORT_RWC_BITS;
58 u32 t2 = t1; 58 u32 t2 = t1;
59 59
60 if ((t1 & PORT_PE) && !(t1 & PORT_OWNER)) 60 if ((t1 & PORT_PE) && !(t1 & PORT_OWNER))
@@ -115,7 +115,8 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
115 i = HCS_N_PORTS (ehci->hcs_params); 115 i = HCS_N_PORTS (ehci->hcs_params);
116 while (i--) { 116 while (i--) {
117 temp = readl (&ehci->regs->port_status [i]); 117 temp = readl (&ehci->regs->port_status [i]);
118 temp &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E); 118 temp &= ~(PORT_RWC_BITS
119 | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
119 if (temp & PORT_SUSPEND) { 120 if (temp & PORT_SUSPEND) {
120 ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); 121 ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
121 temp |= PORT_RESUME; 122 temp |= PORT_RESUME;
@@ -128,7 +129,7 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
128 temp = readl (&ehci->regs->port_status [i]); 129 temp = readl (&ehci->regs->port_status [i]);
129 if ((temp & PORT_SUSPEND) == 0) 130 if ((temp & PORT_SUSPEND) == 0)
130 continue; 131 continue;
131 temp &= ~PORT_RESUME; 132 temp &= ~(PORT_RWC_BITS | PORT_RESUME);
132 writel (temp, &ehci->regs->port_status [i]); 133 writel (temp, &ehci->regs->port_status [i]);
133 ehci_vdbg (ehci, "resumed port %d\n", i + 1); 134 ehci_vdbg (ehci, "resumed port %d\n", i + 1);
134 } 135 }
@@ -191,6 +192,7 @@ static int check_reset_complete (
191 192
192 // what happens if HCS_N_CC(params) == 0 ? 193 // what happens if HCS_N_CC(params) == 0 ?
193 port_status |= PORT_OWNER; 194 port_status |= PORT_OWNER;
195 port_status &= ~PORT_RWC_BITS;
194 writel (port_status, &ehci->regs->port_status [index]); 196 writel (port_status, &ehci->regs->port_status [index]);
195 197
196 } else 198 } else
@@ -233,7 +235,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
233 if (temp & PORT_OWNER) { 235 if (temp & PORT_OWNER) {
234 /* don't report this in GetPortStatus */ 236 /* don't report this in GetPortStatus */
235 if (temp & PORT_CSC) { 237 if (temp & PORT_CSC) {
236 temp &= ~PORT_CSC; 238 temp &= ~PORT_RWC_BITS;
239 temp |= PORT_CSC;
237 writel (temp, &ehci->regs->port_status [i]); 240 writel (temp, &ehci->regs->port_status [i]);
238 } 241 }
239 continue; 242 continue;
@@ -343,7 +346,7 @@ static int ehci_hub_control (
343 &ehci->regs->port_status [wIndex]); 346 &ehci->regs->port_status [wIndex]);
344 break; 347 break;
345 case USB_PORT_FEAT_C_ENABLE: 348 case USB_PORT_FEAT_C_ENABLE:
346 writel (temp | PORT_PEC, 349 writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
347 &ehci->regs->port_status [wIndex]); 350 &ehci->regs->port_status [wIndex]);
348 break; 351 break;
349 case USB_PORT_FEAT_SUSPEND: 352 case USB_PORT_FEAT_SUSPEND:
@@ -353,7 +356,8 @@ static int ehci_hub_control (
353 if ((temp & PORT_PE) == 0) 356 if ((temp & PORT_PE) == 0)
354 goto error; 357 goto error;
355 /* resume signaling for 20 msec */ 358 /* resume signaling for 20 msec */
356 writel ((temp & ~PORT_WAKE_BITS) | PORT_RESUME, 359 temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
360 writel (temp | PORT_RESUME,
357 &ehci->regs->port_status [wIndex]); 361 &ehci->regs->port_status [wIndex]);
358 ehci->reset_done [wIndex] = jiffies 362 ehci->reset_done [wIndex] = jiffies
359 + msecs_to_jiffies (20); 363 + msecs_to_jiffies (20);
@@ -364,15 +368,15 @@ static int ehci_hub_control (
364 break; 368 break;
365 case USB_PORT_FEAT_POWER: 369 case USB_PORT_FEAT_POWER:
366 if (HCS_PPC (ehci->hcs_params)) 370 if (HCS_PPC (ehci->hcs_params))
367 writel (temp & ~PORT_POWER, 371 writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
368 &ehci->regs->port_status [wIndex]); 372 &ehci->regs->port_status [wIndex]);
369 break; 373 break;
370 case USB_PORT_FEAT_C_CONNECTION: 374 case USB_PORT_FEAT_C_CONNECTION:
371 writel (temp | PORT_CSC, 375 writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
372 &ehci->regs->port_status [wIndex]); 376 &ehci->regs->port_status [wIndex]);
373 break; 377 break;
374 case USB_PORT_FEAT_C_OVER_CURRENT: 378 case USB_PORT_FEAT_C_OVER_CURRENT:
375 writel (temp | PORT_OCC, 379 writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
376 &ehci->regs->port_status [wIndex]); 380 &ehci->regs->port_status [wIndex]);
377 break; 381 break;
378 case USB_PORT_FEAT_C_RESET: 382 case USB_PORT_FEAT_C_RESET:
@@ -416,7 +420,7 @@ static int ehci_hub_control (
416 420
417 /* stop resume signaling */ 421 /* stop resume signaling */
418 temp = readl (&ehci->regs->port_status [wIndex]); 422 temp = readl (&ehci->regs->port_status [wIndex]);
419 writel (temp & ~PORT_RESUME, 423 writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
420 &ehci->regs->port_status [wIndex]); 424 &ehci->regs->port_status [wIndex]);
421 retval = handshake ( 425 retval = handshake (
422 &ehci->regs->port_status [wIndex], 426 &ehci->regs->port_status [wIndex],
@@ -437,7 +441,7 @@ static int ehci_hub_control (
437 ehci->reset_done [wIndex] = 0; 441 ehci->reset_done [wIndex] = 0;
438 442
439 /* force reset to complete */ 443 /* force reset to complete */
440 writel (temp & ~PORT_RESET, 444 writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
441 &ehci->regs->port_status [wIndex]); 445 &ehci->regs->port_status [wIndex]);
442 /* REVISIT: some hardware needs 550+ usec to clear 446 /* REVISIT: some hardware needs 550+ usec to clear
443 * this bit; seems too long to spin routinely... 447 * this bit; seems too long to spin routinely...
@@ -500,6 +504,7 @@ static int ehci_hub_control (
500 if (temp & PORT_OWNER) 504 if (temp & PORT_OWNER)
501 break; 505 break;
502 506
507 temp &= ~PORT_RWC_BITS;
503 switch (wValue) { 508 switch (wValue) {
504 case USB_PORT_FEAT_SUSPEND: 509 case USB_PORT_FEAT_SUSPEND:
505 if ((temp & PORT_PE) == 0 510 if ((temp & PORT_PE) == 0
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 20c9b550097d..f34a0516d35f 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -263,6 +263,7 @@ struct ehci_regs {
263#define PORT_PE (1<<2) /* port enable */ 263#define PORT_PE (1<<2) /* port enable */
264#define PORT_CSC (1<<1) /* connect status change */ 264#define PORT_CSC (1<<1) /* connect status change */
265#define PORT_CONNECT (1<<0) /* device connected */ 265#define PORT_CONNECT (1<<0) /* device connected */
266#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
266} __attribute__ ((packed)); 267} __attribute__ ((packed));
267 268
268/* Appendix C, Debug port ... intended for use with special "debug devices" 269/* Appendix C, Debug port ... intended for use with special "debug devices"
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 447f488f5d93..7924c74f958e 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -228,23 +228,22 @@ ohci_dump_roothub (
228 char **next, 228 char **next,
229 unsigned *size) 229 unsigned *size)
230{ 230{
231 u32 temp, ndp, i; 231 u32 temp, i;
232 232
233 temp = roothub_a (controller); 233 temp = roothub_a (controller);
234 if (temp == ~(u32)0) 234 if (temp == ~(u32)0)
235 return; 235 return;
236 ndp = (temp & RH_A_NDP);
237 236
238 if (verbose) { 237 if (verbose) {
239 ohci_dbg_sw (controller, next, size, 238 ohci_dbg_sw (controller, next, size,
240 "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp, 239 "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d(%d)\n", temp,
241 ((temp & RH_A_POTPGT) >> 24) & 0xff, 240 ((temp & RH_A_POTPGT) >> 24) & 0xff,
242 (temp & RH_A_NOCP) ? " NOCP" : "", 241 (temp & RH_A_NOCP) ? " NOCP" : "",
243 (temp & RH_A_OCPM) ? " OCPM" : "", 242 (temp & RH_A_OCPM) ? " OCPM" : "",
244 (temp & RH_A_DT) ? " DT" : "", 243 (temp & RH_A_DT) ? " DT" : "",
245 (temp & RH_A_NPS) ? " NPS" : "", 244 (temp & RH_A_NPS) ? " NPS" : "",
246 (temp & RH_A_PSM) ? " PSM" : "", 245 (temp & RH_A_PSM) ? " PSM" : "",
247 ndp 246 (temp & RH_A_NDP), controller->num_ports
248 ); 247 );
249 temp = roothub_b (controller); 248 temp = roothub_b (controller);
250 ohci_dbg_sw (controller, next, size, 249 ohci_dbg_sw (controller, next, size,
@@ -266,7 +265,7 @@ ohci_dump_roothub (
266 ); 265 );
267 } 266 }
268 267
269 for (i = 0; i < ndp; i++) { 268 for (i = 0; i < controller->num_ports; i++) {
270 temp = roothub_portstatus (controller, i); 269 temp = roothub_portstatus (controller, i);
271 dbg_port_sw (controller, i, temp, next, size); 270 dbg_port_sw (controller, i, temp, next, size);
272 } 271 }
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 56b43f2a0e52..67c1aa5eb1c1 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -382,8 +382,7 @@ sanitize:
382 goto sanitize; 382 goto sanitize;
383 } 383 }
384 spin_unlock_irqrestore (&ohci->lock, flags); 384 spin_unlock_irqrestore (&ohci->lock, flags);
385 set_current_state (TASK_UNINTERRUPTIBLE); 385 schedule_timeout_uninterruptible(1);
386 schedule_timeout (1);
387 goto rescan; 386 goto rescan;
388 case ED_IDLE: /* fully unlinked */ 387 case ED_IDLE: /* fully unlinked */
389 if (list_empty (&ed->td_list)) { 388 if (list_empty (&ed->td_list)) {
@@ -485,6 +484,10 @@ static int ohci_init (struct ohci_hcd *ohci)
485 // flush the writes 484 // flush the writes
486 (void) ohci_readl (ohci, &ohci->regs->control); 485 (void) ohci_readl (ohci, &ohci->regs->control);
487 486
487 /* Read the number of ports unless overridden */
488 if (ohci->num_ports == 0)
489 ohci->num_ports = roothub_a(ohci) & RH_A_NDP;
490
488 if (ohci->hcca) 491 if (ohci->hcca)
489 return 0; 492 return 0;
490 493
@@ -561,10 +564,8 @@ static int ohci_run (struct ohci_hcd *ohci)
561 msleep(temp); 564 msleep(temp);
562 temp = roothub_a (ohci); 565 temp = roothub_a (ohci);
563 if (!(temp & RH_A_NPS)) { 566 if (!(temp & RH_A_NPS)) {
564 unsigned ports = temp & RH_A_NDP;
565
566 /* power down each port */ 567 /* power down each port */
567 for (temp = 0; temp < ports; temp++) 568 for (temp = 0; temp < ohci->num_ports; temp++)
568 ohci_writel (ohci, RH_PS_LSDA, 569 ohci_writel (ohci, RH_PS_LSDA,
569 &ohci->regs->roothub.portstatus [temp]); 570 &ohci->regs->roothub.portstatus [temp]);
570 } 571 }
@@ -720,6 +721,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
720 721
721 if (ints & OHCI_INTR_RD) { 722 if (ints & OHCI_INTR_RD) {
722 ohci_vdbg (ohci, "resume detect\n"); 723 ohci_vdbg (ohci, "resume detect\n");
724 ohci_writel (ohci, OHCI_INTR_RD, &regs->intrstatus);
723 if (hcd->state != HC_STATE_QUIESCING) 725 if (hcd->state != HC_STATE_QUIESCING)
724 schedule_work(&ohci->rh_resume); 726 schedule_work(&ohci->rh_resume);
725 } 727 }
@@ -861,7 +863,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
861 * and that if we try to turn them back on the root hub 863 * and that if we try to turn them back on the root hub
862 * will respond to CSC processing. 864 * will respond to CSC processing.
863 */ 865 */
864 i = roothub_a (ohci) & RH_A_NDP; 866 i = ohci->num_ports;
865 while (i--) 867 while (i--)
866 ohci_writel (ohci, RH_PS_PSS, 868 ohci_writel (ohci, RH_PS_PSS,
867 &ohci->regs->roothub.portstatus [temp]); 869 &ohci->regs->roothub.portstatus [temp]);
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 83ca4549a50e..ce7b28da7a15 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -184,7 +184,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
184 if (status != -EINPROGRESS) 184 if (status != -EINPROGRESS)
185 return status; 185 return status;
186 186
187 temp = roothub_a (ohci) & RH_A_NDP; 187 temp = ohci->num_ports;
188 enables = 0; 188 enables = 0;
189 while (temp--) { 189 while (temp--) {
190 u32 stat = ohci_readl (ohci, 190 u32 stat = ohci_readl (ohci,
@@ -304,7 +304,7 @@ static int
304ohci_hub_status_data (struct usb_hcd *hcd, char *buf) 304ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
305{ 305{
306 struct ohci_hcd *ohci = hcd_to_ohci (hcd); 306 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
307 int ports, i, changed = 0, length = 1; 307 int i, changed = 0, length = 1;
308 int can_suspend = hcd->can_wakeup; 308 int can_suspend = hcd->can_wakeup;
309 unsigned long flags; 309 unsigned long flags;
310 310
@@ -319,9 +319,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
319 goto done; 319 goto done;
320 } 320 }
321 321
322 ports = roothub_a (ohci) & RH_A_NDP; 322 /* undocumented erratum seen on at least rev D */
323 if (ports > MAX_ROOT_PORTS) { 323 if ((ohci->flags & OHCI_QUIRK_AMD756)
324 ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports, 324 && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) {
325 ohci_warn (ohci, "bogus NDP, rereads as NDP=%d\n",
325 ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP); 326 ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP);
326 /* retry later; "should not happen" */ 327 /* retry later; "should not happen" */
327 goto done; 328 goto done;
@@ -332,13 +333,13 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
332 buf [0] = changed = 1; 333 buf [0] = changed = 1;
333 else 334 else
334 buf [0] = 0; 335 buf [0] = 0;
335 if (ports > 7) { 336 if (ohci->num_ports > 7) {
336 buf [1] = 0; 337 buf [1] = 0;
337 length++; 338 length++;
338 } 339 }
339 340
340 /* look at each port */ 341 /* look at each port */
341 for (i = 0; i < ports; i++) { 342 for (i = 0; i < ohci->num_ports; i++) {
342 u32 status = roothub_portstatus (ohci, i); 343 u32 status = roothub_portstatus (ohci, i);
343 344
344 if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC 345 if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
@@ -395,15 +396,14 @@ ohci_hub_descriptor (
395 struct usb_hub_descriptor *desc 396 struct usb_hub_descriptor *desc
396) { 397) {
397 u32 rh = roothub_a (ohci); 398 u32 rh = roothub_a (ohci);
398 int ports = rh & RH_A_NDP;
399 u16 temp; 399 u16 temp;
400 400
401 desc->bDescriptorType = 0x29; 401 desc->bDescriptorType = 0x29;
402 desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24; 402 desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;
403 desc->bHubContrCurrent = 0; 403 desc->bHubContrCurrent = 0;
404 404
405 desc->bNbrPorts = ports; 405 desc->bNbrPorts = ohci->num_ports;
406 temp = 1 + (ports / 8); 406 temp = 1 + (ohci->num_ports / 8);
407 desc->bDescLength = 7 + 2 * temp; 407 desc->bDescLength = 7 + 2 * temp;
408 408
409 temp = 0; 409 temp = 0;
@@ -421,7 +421,7 @@ ohci_hub_descriptor (
421 rh = roothub_b (ohci); 421 rh = roothub_b (ohci);
422 memset(desc->bitmap, 0xff, sizeof(desc->bitmap)); 422 memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
423 desc->bitmap [0] = rh & RH_B_DR; 423 desc->bitmap [0] = rh & RH_B_DR;
424 if (ports > 7) { 424 if (ohci->num_ports > 7) {
425 desc->bitmap [1] = (rh & RH_B_DR) >> 8; 425 desc->bitmap [1] = (rh & RH_B_DR) >> 8;
426 desc->bitmap [2] = 0xff; 426 desc->bitmap [2] = 0xff;
427 } else 427 } else
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index e5bc1789d18a..2fdb262d4726 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -75,33 +75,6 @@ static int pxa27x_ohci_select_pmm( int mode )
75 return 0; 75 return 0;
76} 76}
77 77
78/*
79 If you select PMM_PERPORT_MODE, you should set the port power
80 */
81static int pxa27x_ohci_set_port_power( int port )
82{
83 if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE)
84 && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) {
85 UHCRHPS(port) |= 0x100;
86 return 0;
87 }
88 return -1;
89}
90
91/*
92 If you select PMM_PERPORT_MODE, you should set the port power
93 */
94static int pxa27x_ohci_clear_port_power( int port )
95{
96 if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE)
97 && (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) {
98 UHCRHPS(port) |= 0x200;
99 return 0;
100 }
101
102 return -1;
103}
104
105extern int usb_disabled(void); 78extern int usb_disabled(void);
106 79
107/*-------------------------------------------------------------------------*/ 80/*-------------------------------------------------------------------------*/
@@ -130,11 +103,17 @@ static void pxa27x_start_hc(struct platform_device *dev)
130 Polarity Low to active low. Supply power to USB ports. */ 103 Polarity Low to active low. Supply power to USB ports. */
131 UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) & 104 UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
132 ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); 105 ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
106
107 pxa27x_ohci_pmm_state = PMM_PERPORT_MODE;
133 } 108 }
134 109
135 UHCHR &= ~UHCHR_SSE; 110 UHCHR &= ~UHCHR_SSE;
136 111
137 UHCHIE = (UHCHIE_UPRIE | UHCHIE_RWIE); 112 UHCHIE = (UHCHIE_UPRIE | UHCHIE_RWIE);
113
114 /* Clear any OTG Pin Hold */
115 if (PSSR & PSSR_OTGPH)
116 PSSR |= PSSR_OTGPH;
138} 117}
139 118
140static void pxa27x_stop_hc(struct platform_device *dev) 119static void pxa27x_stop_hc(struct platform_device *dev)
@@ -198,17 +177,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
198 pxa27x_start_hc(dev); 177 pxa27x_start_hc(dev);
199 178
200 /* Select Power Management Mode */ 179 /* Select Power Management Mode */
201 pxa27x_ohci_select_pmm( PMM_PERPORT_MODE ); 180 pxa27x_ohci_select_pmm(pxa27x_ohci_pmm_state);
202
203 /* If choosing PMM_PERPORT_MODE, we should set the port power before we use it. */
204 if (pxa27x_ohci_set_port_power(1) < 0)
205 printk(KERN_ERR "Setting port 1 power failed.\n");
206
207 if (pxa27x_ohci_clear_port_power(2) < 0)
208 printk(KERN_ERR "Setting port 2 power failed.\n");
209
210 if (pxa27x_ohci_clear_port_power(3) < 0)
211 printk(KERN_ERR "Setting port 3 power failed.\n");
212 181
213 ohci_hcd_init(hcd_to_ohci(hcd)); 182 ohci_hcd_init(hcd_to_ohci(hcd));
214 183
@@ -258,6 +227,9 @@ ohci_pxa27x_start (struct usb_hcd *hcd)
258 227
259 ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci); 228 ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci);
260 229
230 /* The value of NDP in roothub_a is incorrect on this hardware */
231 ohci->num_ports = 3;
232
261 if ((ret = ohci_init(ohci)) < 0) 233 if ((ret = ohci_init(ohci)) < 0)
262 return ret; 234 return ret;
263 235
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 71cdd2262860..8a9b9d9209e9 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -383,6 +383,7 @@ struct ohci_hcd {
383 /* 383 /*
384 * driver state 384 * driver state
385 */ 385 */
386 int num_ports;
386 int load [NUM_INTS]; 387 int load [NUM_INTS];
387 u32 hc_control; /* copy of hc control reg */ 388 u32 hc_control; /* copy of hc control reg */
388 unsigned long next_statechange; /* suspend/resume */ 389 unsigned long next_statechange; /* suspend/resume */
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 0d5d2545bf07..0c024898cbea 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -97,14 +97,9 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
97/* to make sure it doesn't hog all of the bandwidth */ 97/* to make sure it doesn't hog all of the bandwidth */
98#define DEPTH_INTERVAL 5 98#define DEPTH_INTERVAL 5
99 99
100static inline void restart_timer(struct uhci_hcd *uhci)
101{
102 mod_timer(&uhci->stall_timer, jiffies + msecs_to_jiffies(100));
103}
104
105#include "uhci-hub.c"
106#include "uhci-debug.c" 100#include "uhci-debug.c"
107#include "uhci-q.c" 101#include "uhci-q.c"
102#include "uhci-hub.c"
108 103
109/* 104/*
110 * Make sure the controller is completely inactive, unable to 105 * Make sure the controller is completely inactive, unable to
@@ -160,7 +155,6 @@ static void hc_died(struct uhci_hcd *uhci)
160{ 155{
161 reset_hc(uhci); 156 reset_hc(uhci);
162 uhci->hc_inaccessible = 1; 157 uhci->hc_inaccessible = 1;
163 del_timer(&uhci->stall_timer);
164} 158}
165 159
166/* 160/*
@@ -287,8 +281,11 @@ __acquires(uhci->lock)
287 /* Enable resume-detect interrupts if they work. 281 /* Enable resume-detect interrupts if they work.
288 * Then enter Global Suspend mode, still configured. 282 * Then enter Global Suspend mode, still configured.
289 */ 283 */
290 int_enable = (resume_detect_interrupts_are_broken(uhci) ? 284 uhci->working_RD = 1;
291 0 : USBINTR_RESUME); 285 int_enable = USBINTR_RESUME;
286 if (resume_detect_interrupts_are_broken(uhci)) {
287 uhci->working_RD = int_enable = 0;
288 }
292 outw(int_enable, uhci->io_addr + USBINTR); 289 outw(int_enable, uhci->io_addr + USBINTR);
293 outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD); 290 outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
294 mb(); 291 mb();
@@ -315,7 +312,6 @@ __acquires(uhci->lock)
315 312
316 uhci->rh_state = new_state; 313 uhci->rh_state = new_state;
317 uhci->is_stopped = UHCI_IS_STOPPED; 314 uhci->is_stopped = UHCI_IS_STOPPED;
318 del_timer(&uhci->stall_timer);
319 uhci_to_hcd(uhci)->poll_rh = !int_enable; 315 uhci_to_hcd(uhci)->poll_rh = !int_enable;
320 316
321 uhci_scan_schedule(uhci, NULL); 317 uhci_scan_schedule(uhci, NULL);
@@ -335,7 +331,6 @@ static void start_rh(struct uhci_hcd *uhci)
335 mb(); 331 mb();
336 uhci->rh_state = UHCI_RH_RUNNING; 332 uhci->rh_state = UHCI_RH_RUNNING;
337 uhci_to_hcd(uhci)->poll_rh = 1; 333 uhci_to_hcd(uhci)->poll_rh = 1;
338 restart_timer(uhci);
339} 334}
340 335
341static void wakeup_rh(struct uhci_hcd *uhci) 336static void wakeup_rh(struct uhci_hcd *uhci)
@@ -374,20 +369,6 @@ __acquires(uhci->lock)
374 mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); 369 mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
375} 370}
376 371
377static void stall_callback(unsigned long _uhci)
378{
379 struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci;
380 unsigned long flags;
381
382 spin_lock_irqsave(&uhci->lock, flags);
383 uhci_scan_schedule(uhci, NULL);
384 check_fsbr(uhci);
385
386 if (!uhci->is_stopped)
387 restart_timer(uhci);
388 spin_unlock_irqrestore(&uhci->lock, flags);
389}
390
391static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) 372static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
392{ 373{
393 struct uhci_hcd *uhci = hcd_to_uhci(hcd); 374 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
@@ -418,8 +399,10 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
418 "host controller halted, " 399 "host controller halted, "
419 "very bad!\n"); 400 "very bad!\n");
420 hc_died(uhci); 401 hc_died(uhci);
421 spin_unlock_irqrestore(&uhci->lock, flags); 402
422 return IRQ_HANDLED; 403 /* Force a callback in case there are
404 * pending unlinks */
405 mod_timer(&hcd->rh_timer, jiffies);
423 } 406 }
424 spin_unlock_irqrestore(&uhci->lock, flags); 407 spin_unlock_irqrestore(&uhci->lock, flags);
425 } 408 }
@@ -427,10 +410,11 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
427 410
428 if (status & USBSTS_RD) 411 if (status & USBSTS_RD)
429 usb_hcd_poll_rh_status(hcd); 412 usb_hcd_poll_rh_status(hcd);
430 413 else {
431 spin_lock_irqsave(&uhci->lock, flags); 414 spin_lock_irqsave(&uhci->lock, flags);
432 uhci_scan_schedule(uhci, regs); 415 uhci_scan_schedule(uhci, regs);
433 spin_unlock_irqrestore(&uhci->lock, flags); 416 spin_unlock_irqrestore(&uhci->lock, flags);
417 }
434 418
435 return IRQ_HANDLED; 419 return IRQ_HANDLED;
436} 420}
@@ -595,10 +579,6 @@ static int uhci_start(struct usb_hcd *hcd)
595 579
596 init_waitqueue_head(&uhci->waitqh); 580 init_waitqueue_head(&uhci->waitqh);
597 581
598 init_timer(&uhci->stall_timer);
599 uhci->stall_timer.function = stall_callback;
600 uhci->stall_timer.data = (unsigned long) uhci;
601
602 uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl), 582 uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
603 &dma_handle, 0); 583 &dma_handle, 0);
604 if (!uhci->fl) { 584 if (!uhci->fl) {
@@ -745,11 +725,11 @@ static void uhci_stop(struct usb_hcd *hcd)
745 struct uhci_hcd *uhci = hcd_to_uhci(hcd); 725 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
746 726
747 spin_lock_irq(&uhci->lock); 727 spin_lock_irq(&uhci->lock);
748 reset_hc(uhci); 728 if (!uhci->hc_inaccessible)
729 reset_hc(uhci);
749 uhci_scan_schedule(uhci, NULL); 730 uhci_scan_schedule(uhci, NULL);
750 spin_unlock_irq(&uhci->lock); 731 spin_unlock_irq(&uhci->lock);
751 732
752 del_timer_sync(&uhci->stall_timer);
753 release_uhci(uhci); 733 release_uhci(uhci);
754} 734}
755 735
@@ -811,13 +791,12 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
811 */ 791 */
812 pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); 792 pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
813 uhci->hc_inaccessible = 1; 793 uhci->hc_inaccessible = 1;
794 hcd->poll_rh = 0;
814 795
815 /* FIXME: Enable non-PME# remote wakeup? */ 796 /* FIXME: Enable non-PME# remote wakeup? */
816 797
817done: 798done:
818 spin_unlock_irq(&uhci->lock); 799 spin_unlock_irq(&uhci->lock);
819 if (rc == 0)
820 del_timer_sync(&hcd->rh_timer);
821 return rc; 800 return rc;
822} 801}
823 802
@@ -850,8 +829,11 @@ static int uhci_resume(struct usb_hcd *hcd)
850 829
851 spin_unlock_irq(&uhci->lock); 830 spin_unlock_irq(&uhci->lock);
852 831
853 if (hcd->poll_rh) 832 if (!uhci->working_RD) {
833 /* Suspended root hub needs to be polled */
834 hcd->poll_rh = 1;
854 usb_hcd_poll_rh_status(hcd); 835 usb_hcd_poll_rh_status(hcd);
836 }
855 return 0; 837 return 0;
856} 838}
857#endif 839#endif
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index bf9c5f9b508b..282f40b75881 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -345,9 +345,6 @@ enum uhci_rh_state {
345 345
346/* 346/*
347 * This describes the full uhci information. 347 * This describes the full uhci information.
348 *
349 * Note how the "proper" USB information is just
350 * a subset of what the full implementation needs.
351 */ 348 */
352struct uhci_hcd { 349struct uhci_hcd {
353 350
@@ -360,8 +357,6 @@ struct uhci_hcd {
360 struct dma_pool *qh_pool; 357 struct dma_pool *qh_pool;
361 struct dma_pool *td_pool; 358 struct dma_pool *td_pool;
362 359
363 struct usb_bus *bus;
364
365 struct uhci_td *term_td; /* Terminating TD, see UHCI bug */ 360 struct uhci_td *term_td; /* Terminating TD, see UHCI bug */
366 struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ 361 struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
367 362
@@ -380,6 +375,8 @@ struct uhci_hcd {
380 unsigned int scan_in_progress:1; /* Schedule scan is running */ 375 unsigned int scan_in_progress:1; /* Schedule scan is running */
381 unsigned int need_rescan:1; /* Redo the schedule scan */ 376 unsigned int need_rescan:1; /* Redo the schedule scan */
382 unsigned int hc_inaccessible:1; /* HC is suspended or dead */ 377 unsigned int hc_inaccessible:1; /* HC is suspended or dead */
378 unsigned int working_RD:1; /* Suspended root hub doesn't
379 need to be polled */
383 380
384 /* Support for port suspend/resume/reset */ 381 /* Support for port suspend/resume/reset */
385 unsigned long port_c_suspend; /* Bit-arrays of ports */ 382 unsigned long port_c_suspend; /* Bit-arrays of ports */
@@ -405,9 +402,7 @@ struct uhci_hcd {
405 /* List of URB's awaiting completion callback */ 402 /* List of URB's awaiting completion callback */
406 struct list_head complete_list; /* P: uhci->lock */ 403 struct list_head complete_list; /* P: uhci->lock */
407 404
408 int rh_numports; 405 int rh_numports; /* Number of root-hub ports */
409
410 struct timer_list stall_timer;
411 406
412 wait_queue_head_t waitqh; /* endpoint_disable waiters */ 407 wait_queue_head_t waitqh; /* endpoint_disable waiters */
413}; 408};
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 4eace2b19ddb..a71e48a66805 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -145,15 +145,16 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
145{ 145{
146 struct uhci_hcd *uhci = hcd_to_uhci(hcd); 146 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
147 unsigned long flags; 147 unsigned long flags;
148 int status; 148 int status = 0;
149 149
150 spin_lock_irqsave(&uhci->lock, flags); 150 spin_lock_irqsave(&uhci->lock, flags);
151 if (uhci->hc_inaccessible) {
152 status = 0;
153 goto done;
154 }
155 151
152 uhci_scan_schedule(uhci, NULL);
153 if (uhci->hc_inaccessible)
154 goto done;
155 check_fsbr(uhci);
156 uhci_check_ports(uhci); 156 uhci_check_ports(uhci);
157
157 status = get_hub_status_data(uhci, buf); 158 status = get_hub_status_data(uhci, buf);
158 159
159 switch (uhci->rh_state) { 160 switch (uhci->rh_state) {
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index bbb36cd6ed61..ea0d168a8c67 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -33,7 +33,7 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
33static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) 33static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
34{ 34{
35 if (uhci->is_stopped) 35 if (uhci->is_stopped)
36 mod_timer(&uhci->stall_timer, jiffies); 36 mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
37 uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); 37 uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
38} 38}
39 39
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index 482c4be521f5..1e53934907c0 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -286,3 +286,23 @@ config USB_KEYSPAN_REMOTE
286 286
287 To compile this driver as a module, choose M here: the module will 287 To compile this driver as a module, choose M here: the module will
288 be called keyspan_remote. 288 be called keyspan_remote.
289
290config USB_APPLETOUCH
291 tristate "Apple USB Touchpad support"
292 depends on USB && INPUT
293 ---help---
294 Say Y here if you want to use an Apple USB Touchpad.
295
296 These are the touchpads that can be found on post-February 2005
297 Apple Powerbooks (prior models have a Synaptics touchpad connected
298 to the ADB bus).
299
300 This driver provides a basic mouse driver but can be interfaced
301 with the synaptics X11 driver to provide acceleration and
302 scrolling in X11.
303
304 For further information, see
305 <file:Documentation/input/appletouch.txt>.
306
307 To compile this driver as a module, choose M here: the
308 module will be called appletouch.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
index 43b2f999edfe..5e03b93f29f6 100644
--- a/drivers/usb/input/Makefile
+++ b/drivers/usb/input/Makefile
@@ -41,3 +41,4 @@ obj-$(CONFIG_USB_WACOM) += wacom.o
41obj-$(CONFIG_USB_ACECAD) += acecad.o 41obj-$(CONFIG_USB_ACECAD) += acecad.o
42obj-$(CONFIG_USB_YEALINK) += yealink.o 42obj-$(CONFIG_USB_YEALINK) += yealink.o
43obj-$(CONFIG_USB_XPAD) += xpad.o 43obj-$(CONFIG_USB_XPAD) += xpad.o
44obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o
diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c
new file mode 100644
index 000000000000..e03c1c567a14
--- /dev/null
+++ b/drivers/usb/input/appletouch.c
@@ -0,0 +1,469 @@
1/*
2 * Apple USB Touchpad (for post-February 2005 PowerBooks) driver
3 *
4 * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
5 * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net)
6 * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
7 * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de)
8 * Copyright (C) 2005 Peter Osterlund (petero2@telia.com)
9 *
10 * Thanks to Alex Harper <basilisk@foobox.net> for his inputs.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28#include <linux/config.h>
29#include <linux/kernel.h>
30#include <linux/errno.h>
31#include <linux/init.h>
32#include <linux/slab.h>
33#include <linux/module.h>
34#include <linux/usb.h>
35#include <linux/input.h>
36#include <linux/usb_input.h>
37
38/* Apple has powerbooks which have the keyboard with different Product IDs */
39#define APPLE_VENDOR_ID 0x05AC
40
41#define ATP_DEVICE(prod) \
42 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
43 USB_DEVICE_ID_MATCH_INT_CLASS | \
44 USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
45 .idVendor = APPLE_VENDOR_ID, \
46 .idProduct = (prod), \
47 .bInterfaceClass = 0x03, \
48 .bInterfaceProtocol = 0x02
49
50/* table of devices that work with this driver */
51static struct usb_device_id atp_table [] = {
52 { ATP_DEVICE(0x020E) },
53 { ATP_DEVICE(0x020F) },
54 { ATP_DEVICE(0x030A) },
55 { ATP_DEVICE(0x030B) },
56 { } /* Terminating entry */
57};
58MODULE_DEVICE_TABLE (usb, atp_table);
59
60/* size of a USB urb transfer */
61#define ATP_DATASIZE 81
62
63/*
64 * number of sensors. Note that only 16 instead of 26 X (horizontal)
65 * sensors exist on 12" and 15" PowerBooks. All models have 16 Y
66 * (vertical) sensors.
67 */
68#define ATP_XSENSORS 26
69#define ATP_YSENSORS 16
70
71/* amount of fuzz this touchpad generates */
72#define ATP_FUZZ 16
73
74/* maximum pressure this driver will report */
75#define ATP_PRESSURE 300
76/*
77 * multiplication factor for the X and Y coordinates.
78 * We try to keep the touchpad aspect ratio while still doing only simple
79 * arithmetics.
80 * The factors below give coordinates like:
81 * 0 <= x < 960 on 12" and 15" Powerbooks
82 * 0 <= x < 1600 on 17" Powerbooks
83 * 0 <= y < 646
84 */
85#define ATP_XFACT 64
86#define ATP_YFACT 43
87
88/*
89 * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
90 * ignored.
91 */
92#define ATP_THRESHOLD 5
93
94/* Structure to hold all of our device specific stuff */
95struct atp {
96 struct usb_device * udev; /* usb device */
97 struct urb * urb; /* usb request block */
98 signed char * data; /* transferred data */
99 int open; /* non-zero if opened */
100 struct input_dev input; /* input dev */
101 int valid; /* are the sensors valid ? */
102 int x_old; /* last reported x/y, */
103 int y_old; /* used for smoothing */
104 /* current value of the sensors */
105 signed char xy_cur[ATP_XSENSORS + ATP_YSENSORS];
106 /* last value of the sensors */
107 signed char xy_old[ATP_XSENSORS + ATP_YSENSORS];
108 /* accumulated sensors */
109 int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
110};
111
112#define dbg_dump(msg, tab) \
113 if (debug > 1) { \
114 int i; \
115 printk("appletouch: %s %lld", msg, (long long)jiffies); \
116 for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) \
117 printk(" %02x", tab[i]); \
118 printk("\n"); \
119 }
120
121#define dprintk(format, a...) \
122 do { \
123 if (debug) printk(format, ##a); \
124 } while (0)
125
126MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold");
127MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver");
128MODULE_LICENSE("GPL");
129
130static int debug = 1;
131module_param(debug, int, 0644);
132MODULE_PARM_DESC(debug, "Activate debugging output");
133
134static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
135 int *z, int *fingers)
136{
137 int i;
138 /* values to calculate mean */
139 int pcum = 0, psum = 0;
140
141 *fingers = 0;
142
143 for (i = 0; i < nb_sensors; i++) {
144 if (xy_sensors[i] < ATP_THRESHOLD)
145 continue;
146 if ((i - 1 < 0) || (xy_sensors[i - 1] < ATP_THRESHOLD))
147 (*fingers)++;
148 pcum += xy_sensors[i] * i;
149 psum += xy_sensors[i];
150 }
151
152 if (psum > 0) {
153 *z = psum;
154 return pcum * fact / psum;
155 }
156
157 return 0;
158}
159
160static inline void atp_report_fingers(struct input_dev *input, int fingers)
161{
162 input_report_key(input, BTN_TOOL_FINGER, fingers == 1);
163 input_report_key(input, BTN_TOOL_DOUBLETAP, fingers == 2);
164 input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2);
165}
166
167static void atp_complete(struct urb* urb, struct pt_regs* regs)
168{
169 int x, y, x_z, y_z, x_f, y_f;
170 int retval, i;
171 struct atp *dev = urb->context;
172
173 switch (urb->status) {
174 case 0:
175 /* success */
176 break;
177 case -ECONNRESET:
178 case -ENOENT:
179 case -ESHUTDOWN:
180 /* This urb is terminated, clean up */
181 dbg("%s - urb shutting down with status: %d",
182 __FUNCTION__, urb->status);
183 return;
184 default:
185 dbg("%s - nonzero urb status received: %d",
186 __FUNCTION__, urb->status);
187 goto exit;
188 }
189
190 /* drop incomplete datasets */
191 if (dev->urb->actual_length != ATP_DATASIZE) {
192 dprintk("appletouch: incomplete data package.\n");
193 goto exit;
194 }
195
196 /* reorder the sensors values */
197 for (i = 0; i < 8; i++) {
198 /* X values */
199 dev->xy_cur[i ] = dev->data[5 * i + 2];
200 dev->xy_cur[i + 8] = dev->data[5 * i + 4];
201 dev->xy_cur[i + 16] = dev->data[5 * i + 42];
202 if (i < 2)
203 dev->xy_cur[i + 24] = dev->data[5 * i + 44];
204
205 /* Y values */
206 dev->xy_cur[i + 26] = dev->data[5 * i + 1];
207 dev->xy_cur[i + 34] = dev->data[5 * i + 3];
208 }
209
210 dbg_dump("sample", dev->xy_cur);
211
212 if (!dev->valid) {
213 /* first sample */
214 dev->valid = 1;
215 dev->x_old = dev->y_old = -1;
216 memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
217
218 /* 17" Powerbooks have 10 extra X sensors */
219 for (i = 16; i < ATP_XSENSORS; i++)
220 if (dev->xy_cur[i]) {
221 printk("appletouch: 17\" model detected.\n");
222 input_set_abs_params(&dev->input, ABS_X, 0,
223 (ATP_XSENSORS - 1) *
224 ATP_XFACT - 1,
225 ATP_FUZZ, 0);
226 break;
227 }
228
229 goto exit;
230 }
231
232 for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
233 /* accumulate the change */
234 signed char change = dev->xy_old[i] - dev->xy_cur[i];
235 dev->xy_acc[i] -= change;
236
237 /* prevent down drifting */
238 if (dev->xy_acc[i] < 0)
239 dev->xy_acc[i] = 0;
240 }
241
242 memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
243
244 dbg_dump("accumulator", dev->xy_acc);
245
246 x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
247 ATP_XFACT, &x_z, &x_f);
248 y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
249 ATP_YFACT, &y_z, &y_f);
250
251 if (x && y) {
252 if (dev->x_old != -1) {
253 x = (dev->x_old * 3 + x) >> 2;
254 y = (dev->y_old * 3 + y) >> 2;
255 dev->x_old = x;
256 dev->y_old = y;
257
258 if (debug > 1)
259 printk("appletouch: X: %3d Y: %3d "
260 "Xz: %3d Yz: %3d\n",
261 x, y, x_z, y_z);
262
263 input_report_key(&dev->input, BTN_TOUCH, 1);
264 input_report_abs(&dev->input, ABS_X, x);
265 input_report_abs(&dev->input, ABS_Y, y);
266 input_report_abs(&dev->input, ABS_PRESSURE,
267 min(ATP_PRESSURE, x_z + y_z));
268 atp_report_fingers(&dev->input, max(x_f, y_f));
269 }
270 dev->x_old = x;
271 dev->y_old = y;
272 }
273 else if (!x && !y) {
274
275 dev->x_old = dev->y_old = -1;
276 input_report_key(&dev->input, BTN_TOUCH, 0);
277 input_report_abs(&dev->input, ABS_PRESSURE, 0);
278 atp_report_fingers(&dev->input, 0);
279
280 /* reset the accumulator on release */
281 memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
282 }
283
284 input_report_key(&dev->input, BTN_LEFT, !!dev->data[80]);
285
286 input_sync(&dev->input);
287
288exit:
289 retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
290 if (retval) {
291 err("%s - usb_submit_urb failed with result %d",
292 __FUNCTION__, retval);
293 }
294}
295
296static int atp_open(struct input_dev *input)
297{
298 struct atp *dev = input->private;
299
300 if (usb_submit_urb(dev->urb, GFP_ATOMIC))
301 return -EIO;
302
303 dev->open = 1;
304 return 0;
305}
306
307static void atp_close(struct input_dev *input)
308{
309 struct atp *dev = input->private;
310
311 usb_kill_urb(dev->urb);
312 dev->open = 0;
313}
314
315static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id)
316{
317 struct atp *dev = NULL;
318 struct usb_host_interface *iface_desc;
319 struct usb_endpoint_descriptor *endpoint;
320 int int_in_endpointAddr = 0;
321 int i, retval = -ENOMEM;
322
323 /* allocate memory for our device state and initialize it */
324 dev = kmalloc(sizeof(struct atp), GFP_KERNEL);
325 if (dev == NULL) {
326 err("Out of memory");
327 goto err_kmalloc;
328 }
329 memset(dev, 0, sizeof(struct atp));
330
331 dev->udev = interface_to_usbdev(iface);
332
333 /* set up the endpoint information */
334 /* use only the first interrupt-in endpoint */
335 iface_desc = iface->cur_altsetting;
336 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
337 endpoint = &iface_desc->endpoint[i].desc;
338 if (!int_in_endpointAddr &&
339 (endpoint->bEndpointAddress & USB_DIR_IN) &&
340 ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
341 == USB_ENDPOINT_XFER_INT)) {
342 /* we found an interrupt in endpoint */
343 int_in_endpointAddr = endpoint->bEndpointAddress;
344 break;
345 }
346 }
347 if (!int_in_endpointAddr) {
348 retval = -EIO;
349 err("Could not find int-in endpoint");
350 goto err_endpoint;
351 }
352
353 /* save our data pointer in this interface device */
354 usb_set_intfdata(iface, dev);
355
356 dev->urb = usb_alloc_urb(0, GFP_KERNEL);
357 if (!dev->urb) {
358 retval = -ENOMEM;
359 goto err_usballoc;
360 }
361 dev->data = usb_buffer_alloc(dev->udev, ATP_DATASIZE, GFP_KERNEL,
362 &dev->urb->transfer_dma);
363 if (!dev->data) {
364 retval = -ENOMEM;
365 goto err_usbbufalloc;
366 }
367 usb_fill_int_urb(dev->urb, dev->udev,
368 usb_rcvintpipe(dev->udev, int_in_endpointAddr),
369 dev->data, ATP_DATASIZE, atp_complete, dev, 1);
370
371 init_input_dev(&dev->input);
372 dev->input.name = "appletouch";
373 dev->input.dev = &iface->dev;
374 dev->input.private = dev;
375 dev->input.open = atp_open;
376 dev->input.close = atp_close;
377
378 usb_to_input_id(dev->udev, &dev->input.id);
379
380 set_bit(EV_ABS, dev->input.evbit);
381
382 /*
383 * 12" and 15" Powerbooks only have 16 x sensors,
384 * 17" models are detected later.
385 */
386 input_set_abs_params(&dev->input, ABS_X, 0,
387 (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0);
388 input_set_abs_params(&dev->input, ABS_Y, 0,
389 (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0);
390 input_set_abs_params(&dev->input, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
391
392 set_bit(EV_KEY, dev->input.evbit);
393 set_bit(BTN_TOUCH, dev->input.keybit);
394 set_bit(BTN_TOOL_FINGER, dev->input.keybit);
395 set_bit(BTN_TOOL_DOUBLETAP, dev->input.keybit);
396 set_bit(BTN_TOOL_TRIPLETAP, dev->input.keybit);
397 set_bit(BTN_LEFT, dev->input.keybit);
398
399 input_register_device(&dev->input);
400
401 printk(KERN_INFO "input: appletouch connected\n");
402
403 return 0;
404
405err_usbbufalloc:
406 usb_free_urb(dev->urb);
407err_usballoc:
408 usb_set_intfdata(iface, NULL);
409err_endpoint:
410 kfree(dev);
411err_kmalloc:
412 return retval;
413}
414
415static void atp_disconnect(struct usb_interface *iface)
416{
417 struct atp *dev = usb_get_intfdata(iface);
418
419 usb_set_intfdata(iface, NULL);
420 if (dev) {
421 usb_kill_urb(dev->urb);
422 input_unregister_device(&dev->input);
423 usb_free_urb(dev->urb);
424 usb_buffer_free(dev->udev, ATP_DATASIZE,
425 dev->data, dev->urb->transfer_dma);
426 kfree(dev);
427 }
428 printk(KERN_INFO "input: appletouch disconnected\n");
429}
430
431static int atp_suspend(struct usb_interface *iface, pm_message_t message)
432{
433 struct atp *dev = usb_get_intfdata(iface);
434 usb_kill_urb(dev->urb);
435 dev->valid = 0;
436 return 0;
437}
438
439static int atp_resume(struct usb_interface *iface)
440{
441 struct atp *dev = usb_get_intfdata(iface);
442 if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
443 return -EIO;
444
445 return 0;
446}
447
448static struct usb_driver atp_driver = {
449 .owner = THIS_MODULE,
450 .name = "appletouch",
451 .probe = atp_probe,
452 .disconnect = atp_disconnect,
453 .suspend = atp_suspend,
454 .resume = atp_resume,
455 .id_table = atp_table,
456};
457
458static int __init atp_init(void)
459{
460 return usb_register(&atp_driver);
461}
462
463static void __exit atp_exit(void)
464{
465 usb_deregister(&atp_driver);
466}
467
468module_init(atp_init);
469module_exit(atp_exit);
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index e108e0a36b74..a99865c689c5 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1446,7 +1446,6 @@ void hid_init_reports(struct hid_device *hid)
1446 1446
1447#define USB_VENDOR_ID_APPLE 0x05ac 1447#define USB_VENDOR_ID_APPLE 0x05ac
1448#define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304 1448#define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304
1449#define USB_DEVICE_ID_APPLE_BLUETOOTH 0x1000
1450 1449
1451/* 1450/*
1452 * Alphabetically sorted blacklist by quirk type. 1451 * Alphabetically sorted blacklist by quirk type.
@@ -1465,7 +1464,6 @@ static struct hid_blacklist {
1465 { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE }, 1464 { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
1466 { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, 1465 { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
1467 { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, 1466 { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
1468 { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_BLUETOOTH, HID_QUIRK_IGNORE },
1469 { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, 1467 { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
1470 { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, 1468 { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
1471 { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE }, 1469 { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig
index 3957e144caf7..7603cbe0865d 100644
--- a/drivers/usb/misc/sisusbvga/Kconfig
+++ b/drivers/usb/misc/sisusbvga/Kconfig
@@ -4,11 +4,43 @@ config USB_SISUSBVGA
4 depends on USB && USB_EHCI_HCD 4 depends on USB && USB_EHCI_HCD
5 ---help--- 5 ---help---
6 Say Y here if you intend to attach a USB2VGA dongle based on a 6 Say Y here if you intend to attach a USB2VGA dongle based on a
7 Net2280 and a SiS315 chip. 7 Net2280 and a SiS315 chip.
8 8
9 Note that this device requires a USB 2.0 host controller. It will not 9 Note that this device requires a USB 2.0 host controller. It will not
10 work with USB 1.x controllers. 10 work with USB 1.x controllers.
11 11
12 To compile this driver as a module, choose M here: the module will be 12 To compile this driver as a module, choose M here; the module will be
13 called sisusb. If unsure, say N. 13 called sisusbvga. If unsure, say N.
14
15config USB_SISUSBVGA_CON
16 bool "Text console and mode switching support" if USB_SISUSBVGA
17 depends on VT
18 select FONT_8x16
19 ---help---
20 Say Y here if you want a VGA text console via the USB dongle or
21 want to support userland applications that utilize the driver's
22 display mode switching capabilities.
23
24 Note that this console supports VGA/EGA text mode only.
25
26 By default, the console part of the driver will not kick in when
27 the driver is initialized. If you want the driver to take over
28 one or more of the consoles, you need to specify the number of
29 the first and last consoles (starting at 1) as driver parameters.
30
31 For example, if the driver is compiled as a module:
32
33 modprobe sisusbvga first=1 last=5
34
35 If you use hotplug, add this to your modutils config files with
36 the "options" keyword, such as eg.
37
38 options sisusbvga first=1 last=5
39
40 If the driver is compiled into the kernel image, the parameters
41 must be given in the kernel command like, such as
42
43 sisusbvga.first=1 sisusbvga.last=5
44
45
14 46
diff --git a/drivers/usb/misc/sisusbvga/Makefile b/drivers/usb/misc/sisusbvga/Makefile
index 76f1643ceaf8..7f934cfc906c 100644
--- a/drivers/usb/misc/sisusbvga/Makefile
+++ b/drivers/usb/misc/sisusbvga/Makefile
@@ -2,5 +2,7 @@
2# Makefile for the sisusb driver (if driver is inside kernel tree). 2# Makefile for the sisusb driver (if driver is inside kernel tree).
3# 3#
4 4
5obj-$(CONFIG_USB_SISUSBVGA) += sisusb.o 5obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o
6
7sisusbvga-objs := sisusb.o sisusb_init.o sisusb_con.o
6 8
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index d63ce6c030f3..39db3155723a 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -1,6 +1,8 @@
1/* 1/*
2 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles 2 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
3 * 3 *
4 * Main part
5 *
4 * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria 6 * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
5 * 7 *
6 * If distributed as part of the Linux kernel, this code is licensed under the 8 * If distributed as part of the Linux kernel, this code is licensed under the
@@ -48,16 +50,60 @@
48#include <linux/kref.h> 50#include <linux/kref.h>
49#include <linux/usb.h> 51#include <linux/usb.h>
50#include <linux/smp_lock.h> 52#include <linux/smp_lock.h>
53#include <linux/vmalloc.h>
51 54
52#include "sisusb.h" 55#include "sisusb.h"
53 56
57#ifdef INCL_SISUSB_CON
58#include <linux/font.h>
59#endif
60
54#define SISUSB_DONTSYNC 61#define SISUSB_DONTSYNC
55 62
56/* Forward declarations / clean-up routines */ 63/* Forward declarations / clean-up routines */
57 64
65#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
58static struct usb_driver sisusb_driver; 104static struct usb_driver sisusb_driver;
59 105
60static DECLARE_MUTEX(disconnect_sem); 106DECLARE_MUTEX(disconnect_sem);
61 107
62static void 108static void
63sisusb_free_buffers(struct sisusb_usb_data *sisusb) 109sisusb_free_buffers(struct sisusb_usb_data *sisusb)
@@ -639,7 +685,10 @@ static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len,
639 685
640/* The following routines assume being used to transfer byte, word, 686/* The following routines assume being used to transfer byte, word,
641 * long etc. 687 * long etc.
642 * This means that they assume "data" in machine endianness format. 688 * 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.
643 */ 692 */
644 693
645static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type, 694static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,
@@ -839,7 +888,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
839 if (get_user(swap16, (u16 __user *)userbuffer)) 888 if (get_user(swap16, (u16 __user *)userbuffer))
840 return -EFAULT; 889 return -EFAULT;
841 } else 890 } else
842 swap16 = (kernbuffer[0] << 8) | kernbuffer[1]; 891 swap16 = *((u16 *)kernbuffer);
843 892
844 ret = sisusb_write_memio_word(sisusb, 893 ret = sisusb_write_memio_word(sisusb,
845 SISUSB_TYPE_MEM, 894 SISUSB_TYPE_MEM,
@@ -855,14 +904,25 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
855 if (userbuffer) { 904 if (userbuffer) {
856 if (copy_from_user(&buf, userbuffer, 3)) 905 if (copy_from_user(&buf, userbuffer, 3))
857 return -EFAULT; 906 return -EFAULT;
858 907#ifdef __BIG_ENDIAN
859 swap32 = (buf[0] << 16) | 908 swap32 = (buf[0] << 16) |
860 (buf[1] << 8) | 909 (buf[1] << 8) |
861 buf[2]; 910 buf[2];
911#else
912 swap32 = (buf[2] << 16) |
913 (buf[1] << 8) |
914 buf[0];
915#endif
862 } else 916 } else
917#ifdef __BIG_ENDIAN
863 swap32 = (kernbuffer[0] << 16) | 918 swap32 = (kernbuffer[0] << 16) |
864 (kernbuffer[1] << 8) | 919 (kernbuffer[1] << 8) |
865 kernbuffer[2]; 920 kernbuffer[2];
921#else
922 swap32 = (kernbuffer[2] << 16) |
923 (kernbuffer[1] << 8) |
924 kernbuffer[0];
925#endif
866 926
867 ret = sisusb_write_memio_24bit(sisusb, 927 ret = sisusb_write_memio_24bit(sisusb,
868 SISUSB_TYPE_MEM, 928 SISUSB_TYPE_MEM,
@@ -879,10 +939,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
879 if (get_user(swap32, (u32 __user *)userbuffer)) 939 if (get_user(swap32, (u32 __user *)userbuffer))
880 return -EFAULT; 940 return -EFAULT;
881 } else 941 } else
882 swap32 = (kernbuffer[0] << 24) | 942 swap32 = *((u32 *)kernbuffer);
883 (kernbuffer[1] << 16) |
884 (kernbuffer[2] << 8) |
885 kernbuffer[3];
886 943
887 ret = sisusb_write_memio_long(sisusb, 944 ret = sisusb_write_memio_long(sisusb,
888 SISUSB_TYPE_MEM, 945 SISUSB_TYPE_MEM,
@@ -1005,6 +1062,10 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1005 return ret ? -EIO : 0; 1062 return ret ? -EIO : 0;
1006} 1063}
1007 1064
1065/* Remember: Read data in packet is in machine-endianess! So for
1066 * byte, word, 24bit, long no endian correction is necessary.
1067 */
1068
1008static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type, 1069static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type,
1009 u32 addr, u8 *data) 1070 u32 addr, u8 *data)
1010{ 1071{
@@ -1191,8 +1252,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1191 (u16 __user *)userbuffer)) 1252 (u16 __user *)userbuffer))
1192 return -EFAULT; 1253 return -EFAULT;
1193 } else { 1254 } else {
1194 kernbuffer[0] = swap16 >> 8; 1255 *((u16 *)kernbuffer) = swap16;
1195 kernbuffer[1] = swap16 & 0xff;
1196 } 1256 }
1197 } 1257 }
1198 return ret; 1258 return ret;
@@ -1202,9 +1262,15 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1202 addr, &swap32); 1262 addr, &swap32);
1203 if (!ret) { 1263 if (!ret) {
1204 (*bytes_read) += 3; 1264 (*bytes_read) += 3;
1265#ifdef __BIG_ENDIAN
1205 buf[0] = (swap32 >> 16) & 0xff; 1266 buf[0] = (swap32 >> 16) & 0xff;
1206 buf[1] = (swap32 >> 8) & 0xff; 1267 buf[1] = (swap32 >> 8) & 0xff;
1207 buf[2] = swap32 & 0xff; 1268 buf[2] = swap32 & 0xff;
1269#else
1270 buf[2] = (swap32 >> 16) & 0xff;
1271 buf[1] = (swap32 >> 8) & 0xff;
1272 buf[0] = swap32 & 0xff;
1273#endif
1208 if (userbuffer) { 1274 if (userbuffer) {
1209 if (copy_to_user(userbuffer, &buf[0], 3)) 1275 if (copy_to_user(userbuffer, &buf[0], 3))
1210 return -EFAULT; 1276 return -EFAULT;
@@ -1228,10 +1294,7 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1228 1294
1229 userbuffer += 4; 1295 userbuffer += 4;
1230 } else { 1296 } else {
1231 kernbuffer[0] = (swap32 >> 24) & 0xff; 1297 *((u32 *)kernbuffer) = swap32;
1232 kernbuffer[1] = (swap32 >> 16) & 0xff;
1233 kernbuffer[2] = (swap32 >> 8) & 0xff;
1234 kernbuffer[3] = swap32 & 0xff;
1235 kernbuffer += 4; 1298 kernbuffer += 4;
1236 } 1299 }
1237 addr += 4; 1300 addr += 4;
@@ -1289,7 +1352,24 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
1289 1352
1290/* High level: Gfx (indexed) register access */ 1353/* High level: Gfx (indexed) register access */
1291 1354
1292static int 1355#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
1293sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data) 1373sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1294{ 1374{
1295 int ret; 1375 int ret;
@@ -1298,7 +1378,10 @@ sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data)
1298 return ret; 1378 return ret;
1299} 1379}
1300 1380
1301static int 1381#ifndef INCL_SISUSB_CON
1382static
1383#endif
1384int
1302sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data) 1385sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1303{ 1386{
1304 int ret; 1387 int ret;
@@ -1307,7 +1390,10 @@ sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data)
1307 return ret; 1390 return ret;
1308} 1391}
1309 1392
1310static int 1393#ifndef INCL_SISUSB_CON
1394static
1395#endif
1396int
1311sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, 1397sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx,
1312 u8 myand, u8 myor) 1398 u8 myand, u8 myor)
1313{ 1399{
@@ -1336,18 +1422,89 @@ sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx,
1336 return ret; 1422 return ret;
1337} 1423}
1338 1424
1339static int 1425#ifndef INCL_SISUSB_CON
1426static
1427#endif
1428int
1340sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor) 1429sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor)
1341{ 1430{
1342 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor)); 1431 return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor));
1343} 1432}
1344 1433
1345static int 1434#ifndef INCL_SISUSB_CON
1435static
1436#endif
1437int
1346sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand) 1438sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand)
1347{ 1439{
1348 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00)); 1440 return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00));
1349} 1441}
1350 1442
1443/* 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
1351/* access pci config registers (reg numbers 0, 4, 8, etc) */ 1508/* access pci config registers (reg numbers 0, 4, 8, etc) */
1352 1509
1353static int 1510static int
@@ -2270,6 +2427,129 @@ sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen)
2270 return ret; 2427 return ret;
2271} 2428}
2272 2429
2430
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
2273/* fops */ 2553/* fops */
2274 2554
2275static int 2555static int
@@ -2329,7 +2609,7 @@ sisusb_open(struct inode *inode, struct file *file)
2329 } 2609 }
2330 } 2610 }
2331 2611
2332 /* increment usage count for the device */ 2612 /* Increment usage count for our sisusb */
2333 kref_get(&sisusb->kref); 2613 kref_get(&sisusb->kref);
2334 2614
2335 sisusb->isopen = 1; 2615 sisusb->isopen = 1;
@@ -2340,12 +2620,10 @@ sisusb_open(struct inode *inode, struct file *file)
2340 2620
2341 up(&disconnect_sem); 2621 up(&disconnect_sem);
2342 2622
2343 printk(KERN_DEBUG "sisusbvga[%d]: opened", sisusb->minor);
2344
2345 return 0; 2623 return 0;
2346} 2624}
2347 2625
2348static void 2626void
2349sisusb_delete(struct kref *kref) 2627sisusb_delete(struct kref *kref)
2350{ 2628{
2351 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref); 2629 struct sisusb_usb_data *sisusb = to_sisusb_dev(kref);
@@ -2359,6 +2637,9 @@ sisusb_delete(struct kref *kref)
2359 sisusb->sisusb_dev = NULL; 2637 sisusb->sisusb_dev = NULL;
2360 sisusb_free_buffers(sisusb); 2638 sisusb_free_buffers(sisusb);
2361 sisusb_free_urbs(sisusb); 2639 sisusb_free_urbs(sisusb);
2640#ifdef INCL_SISUSB_CON
2641 kfree(sisusb->SiS_Pr);
2642#endif
2362 kfree(sisusb); 2643 kfree(sisusb);
2363} 2644}
2364 2645
@@ -2395,8 +2676,6 @@ sisusb_release(struct inode *inode, struct file *file)
2395 2676
2396 up(&disconnect_sem); 2677 up(&disconnect_sem);
2397 2678
2398 printk(KERN_DEBUG "sisusbvga[%d]: released", myminor);
2399
2400 return 0; 2679 return 0;
2401} 2680}
2402 2681
@@ -2733,6 +3012,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2733 int retval, port, length; 3012 int retval, port, length;
2734 u32 address; 3013 u32 address;
2735 3014
3015 /* All our commands require the device
3016 * to be initialized.
3017 */
3018 if (!sisusb->devinit)
3019 return -ENODEV;
3020
2736 port = y->data3 - 3021 port = y->data3 -
2737 SISUSB_PCI_PSEUDO_IOPORTBASE + 3022 SISUSB_PCI_PSEUDO_IOPORTBASE +
2738 SISUSB_PCI_IOPORTBASE; 3023 SISUSB_PCI_IOPORTBASE;
@@ -2774,6 +3059,10 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2774 break; 3059 break;
2775 3060
2776 case SUCMD_CLRSCR: 3061 case SUCMD_CLRSCR:
3062 /* Gfx core must be initialized */
3063 if (!sisusb->gfxinit)
3064 return -ENODEV;
3065
2777 length = (y->data0 << 16) | (y->data1 << 8) | y->data2; 3066 length = (y->data0 << 16) | (y->data1 << 8) | y->data2;
2778 address = y->data3 - 3067 address = y->data3 -
2779 SISUSB_PCI_PSEUDO_MEMBASE + 3068 SISUSB_PCI_PSEUDO_MEMBASE +
@@ -2781,11 +3070,61 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
2781 retval = sisusb_clear_vram(sisusb, address, length); 3070 retval = sisusb_clear_vram(sisusb, address, length);
2782 break; 3071 break;
2783 3072
3073 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
2784 default: 3123 default:
2785 retval = -EINVAL; 3124 retval = -EINVAL;
2786 } 3125 }
2787 3126
2788 if(retval > 0) 3127 if (retval > 0)
2789 retval = -EIO; 3128 retval = -EIO;
2790 3129
2791 return retval; 3130 return retval;
@@ -2835,6 +3174,11 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
2835 x.sisusb_vramsize = sisusb->vramsize; 3174 x.sisusb_vramsize = sisusb->vramsize;
2836 x.sisusb_minor = sisusb->minor; 3175 x.sisusb_minor = sisusb->minor;
2837 x.sisusb_fbdevactive= 0; 3176 x.sisusb_fbdevactive= 0;
3177#ifdef INCL_SISUSB_CON
3178 x.sisusb_conactive = sisusb->haveconsole ? 1 : 0;
3179#else
3180 x.sisusb_conactive = 0;
3181#endif
2838 3182
2839 if (copy_to_user((void __user *)arg, &x, sizeof(x))) 3183 if (copy_to_user((void __user *)arg, &x, sizeof(x)))
2840 retval = -EFAULT; 3184 retval = -EFAULT;
@@ -2895,9 +3239,13 @@ static struct file_operations usb_sisusb_fops = {
2895}; 3239};
2896 3240
2897static struct usb_class_driver usb_sisusb_class = { 3241static struct usb_class_driver usb_sisusb_class = {
3242#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
2898 .name = "usb/sisusbvga%d", 3243 .name = "usb/sisusbvga%d",
2899 .fops = &usb_sisusb_fops,
2900 .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 3244 .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
3245#else
3246 .name = "sisusbvga%d",
3247#endif
3248 .fops = &usb_sisusb_fops,
2901 .minor_base = SISUSB_MINOR 3249 .minor_base = SISUSB_MINOR
2902}; 3250};
2903 3251
@@ -2994,12 +3342,25 @@ static int sisusb_probe(struct usb_interface *intf,
2994 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n", 3342 printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
2995 sisusb->minor, sisusb->numobufs); 3343 sisusb->minor, sisusb->numobufs);
2996 3344
3345#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
2997 /* Do remaining init stuff */ 3354 /* Do remaining init stuff */
2998 3355
2999 init_waitqueue_head(&sisusb->wait_q); 3356 init_waitqueue_head(&sisusb->wait_q);
3000 3357
3001 usb_set_intfdata(intf, sisusb); 3358 usb_set_intfdata(intf, sisusb);
3002 3359
3360 usb_get_dev(sisusb->sisusb_dev);
3361
3362 sisusb->present = 1;
3363
3003#ifdef SISUSB_OLD_CONFIG_COMPAT 3364#ifdef SISUSB_OLD_CONFIG_COMPAT
3004 { 3365 {
3005 int ret; 3366 int ret;
@@ -3014,14 +3375,19 @@ static int sisusb_probe(struct usb_interface *intf,
3014 sisusb->minor); 3375 sisusb->minor);
3015 else 3376 else
3016 sisusb->ioctl32registered = 1; 3377 sisusb->ioctl32registered = 1;
3017
3018 } 3378 }
3019#endif 3379#endif
3020 3380
3021 sisusb->present = 1;
3022
3023 if (dev->speed == USB_SPEED_HIGH) { 3381 if (dev->speed == USB_SPEED_HIGH) {
3024 if (sisusb_init_gfxdevice(sisusb, 1)) 3382 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))
3025 printk(KERN_ERR 3391 printk(KERN_ERR
3026 "sisusbvga[%d]: Failed to early " 3392 "sisusbvga[%d]: Failed to early "
3027 "initialize device\n", 3393 "initialize device\n",
@@ -3035,6 +3401,16 @@ static int sisusb_probe(struct usb_interface *intf,
3035 3401
3036 sisusb->ready = 1; 3402 sisusb->ready = 1;
3037 3403
3404#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
3038 return 0; 3414 return 0;
3039 3415
3040error_4: 3416error_4:
@@ -3053,13 +3429,20 @@ static void sisusb_disconnect(struct usb_interface *intf)
3053 struct sisusb_usb_data *sisusb; 3429 struct sisusb_usb_data *sisusb;
3054 int minor; 3430 int minor;
3055 3431
3056 down(&disconnect_sem);
3057
3058 /* This should *not* happen */ 3432 /* This should *not* happen */
3059 if (!(sisusb = usb_get_intfdata(intf))) { 3433 if (!(sisusb = usb_get_intfdata(intf)))
3060 up(&disconnect_sem);
3061 return; 3434 return;
3062 } 3435
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);
3063 3446
3064 down(&sisusb->lock); 3447 down(&sisusb->lock);
3065 3448
@@ -3123,11 +3506,17 @@ static int __init usb_sisusb_init(void)
3123{ 3506{
3124 int retval; 3507 int retval;
3125 3508
3509#ifdef INCL_SISUSB_CON
3510 sisusb_init_concode();
3511#endif
3512
3126 if (!(retval = usb_register(&sisusb_driver))) { 3513 if (!(retval = usb_register(&sisusb_driver))) {
3514
3127 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n", 3515 printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
3128 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL); 3516 SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
3129 printk(KERN_INFO 3517 printk(KERN_INFO
3130 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n"); 3518 "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
3519
3131 } 3520 }
3132 3521
3133 return retval; 3522 return retval;
@@ -3142,6 +3531,6 @@ module_init(usb_sisusb_init);
3142module_exit(usb_sisusb_exit); 3531module_exit(usb_sisusb_exit);
3143 3532
3144MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>"); 3533MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>");
3145MODULE_DESCRIPTION("sisusb - Driver for Net2280/SiS315-based USB2VGA dongles"); 3534MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles");
3146MODULE_LICENSE("GPL"); 3535MODULE_LICENSE("GPL");
3147 3536
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
index 1306d006a25a..401ff21d7881 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.h
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -46,15 +46,36 @@
46#endif 46#endif
47#endif 47#endif
48 48
49/* For older kernels, support for text consoles is by default
50 * off. To ensable text console support, change the following:
51 */
52#if 0
53#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
54#define CONFIG_USB_SISUSBVGA_CON
55#endif
56#endif
57
49/* Version Information */ 58/* Version Information */
50 59
51#define SISUSB_VERSION 0 60#define SISUSB_VERSION 0
52#define SISUSB_REVISION 0 61#define SISUSB_REVISION 0
53#define SISUSB_PATCHLEVEL 7 62#define SISUSB_PATCHLEVEL 8
63
64/* Include console and mode switching code? */
65
66#ifdef CONFIG_USB_SISUSBVGA_CON
67#define INCL_SISUSB_CON 1
68#endif
69
70#ifdef INCL_SISUSB_CON
71#include <linux/console.h>
72#include <linux/vt_kern.h>
73#include "sisusb_struct.h"
74#endif
54 75
55/* USB related */ 76/* USB related */
56 77
57#define SISUSB_MINOR 133 /* FIXME */ 78#define SISUSB_MINOR 133 /* official */
58 79
59/* Size of the sisusb input/output buffers */ 80/* Size of the sisusb input/output buffers */
60#define SISUSB_IBUF_SIZE 0x01000 81#define SISUSB_IBUF_SIZE 0x01000
@@ -131,6 +152,26 @@ struct sisusb_usb_data {
131 unsigned char gfxinit; /* graphics core initialized? */ 152 unsigned char gfxinit; /* graphics core initialized? */
132 unsigned short chipid, chipvendor; 153 unsigned short chipid, chipvendor;
133 unsigned short chiprevision; 154 unsigned short chiprevision;
155#ifdef INCL_SISUSB_CON
156 struct SiS_Private *SiS_Pr;
157 unsigned long scrbuf;
158 unsigned int scrbuf_size;
159 int haveconsole, con_first, con_last;
160 int havethisconsole[MAX_NR_CONSOLES];
161 int textmodedestroyed;
162 unsigned int sisusb_num_columns; /* real number, not vt's idea */
163 int cur_start_addr, con_rolled_over;
164 int sisusb_cursor_loc, bad_cursor_pos;
165 int sisusb_cursor_size_from;
166 int sisusb_cursor_size_to;
167 int current_font_height, current_font_512;
168 int font_backup_size, font_backup_height, font_backup_512;
169 char *font_backup;
170 int font_slot;
171 struct vc_data *sisusb_display_fg;
172 int is_gfx;
173 int con_blanked;
174#endif
134}; 175};
135 176
136#define to_sisusb_dev(d) container_of(d, struct sisusb_usb_data, kref) 177#define to_sisusb_dev(d) container_of(d, struct sisusb_usb_data, kref)
@@ -249,7 +290,9 @@ struct sisusb_info {
249 290
250 __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ 291 __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
251 292
252 __u8 sisusb_reserved[32]; /* for future use */ 293 __u32 sisusb_conactive; /* != 0 if console driver active */
294
295 __u8 sisusb_reserved[28]; /* for future use */
253}; 296};
254 297
255struct sisusb_command { 298struct sisusb_command {
@@ -261,18 +304,24 @@ struct sisusb_command {
261 __u32 data4; /* for future use */ 304 __u32 data4; /* for future use */
262}; 305};
263 306
264#define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */ 307#define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */
265#define SUCMD_SET 0x02 /* data1 = value */ 308#define SUCMD_SET 0x02 /* data1 = value */
266#define SUCMD_SETOR 0x03 /* data1 = or */ 309#define SUCMD_SETOR 0x03 /* data1 = or */
267#define SUCMD_SETAND 0x04 /* data1 = and */ 310#define SUCMD_SETAND 0x04 /* data1 = and */
268#define SUCMD_SETANDOR 0x05 /* data1 = and, data2 = or */ 311#define SUCMD_SETANDOR 0x05 /* data1 = and, data2 = or */
269#define SUCMD_SETMASK 0x06 /* data1 = data, data2 = mask */ 312#define SUCMD_SETMASK 0x06 /* data1 = data, data2 = mask */
270 313
271#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */ 314#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */
315
316#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
317
318#define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */
319#define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */
272 320
273#define SISUSB_COMMAND _IOWR(0xF3,0x3D,struct sisusb_command) 321#define SISUSB_COMMAND _IOWR(0xF3,0x3D,struct sisusb_command)
274#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32) 322#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32)
275#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info) 323#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info)
324
276 325
277#endif /* SISUSB_H */ 326#endif /* SISUSB_H */
278 327
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
new file mode 100644
index 000000000000..24584463553d
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -0,0 +1,1658 @@
1/*
2 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
3 *
4 * VGA text mode console part
5 *
6 * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria
7 *
8 * If distributed as part of the Linux kernel, this code is licensed under the
9 * terms of the GPL v2.
10 *
11 * Otherwise, the following license terms apply:
12 *
13 * * Redistribution and use in source and binary forms, with or without
14 * * modification, are permitted provided that the following conditions
15 * * are met:
16 * * 1) Redistributions of source code must retain the above copyright
17 * * notice, this list of conditions and the following disclaimer.
18 * * 2) Redistributions in binary form must reproduce the above copyright
19 * * notice, this list of conditions and the following disclaimer in the
20 * * documentation and/or other materials provided with the distribution.
21 * * 3) The name of the author may not be used to endorse or promote products
22 * * derived from this software without specific psisusbr written permission.
23 * *
24 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
25 * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 * Author: Thomas Winischhofer <thomas@winischhofer.net>
36 *
37 * Portions based on vgacon.c which are
38 * Created 28 Sep 1997 by Geert Uytterhoeven
39 * Rewritten by Martin Mares <mj@ucw.cz>, July 1998
40 * based on code Copyright (C) 1991, 1992 Linus Torvalds
41 * 1995 Jay Estabrook
42 *
43 * A note on using in_atomic() in here: We can't handle console
44 * calls from non-schedulable context due to our USB-dependend
45 * nature. For now, this driver just ignores any calls if it
46 * detects this state.
47 *
48 */
49
50#include <linux/config.h>
51#include <linux/version.h>
52#include <linux/module.h>
53#include <linux/kernel.h>
54#include <linux/signal.h>
55#include <linux/sched.h>
56#include <linux/fs.h>
57#include <linux/tty.h>
58#include <linux/console.h>
59#include <linux/string.h>
60#include <linux/kd.h>
61#include <linux/init.h>
62#include <linux/slab.h>
63#include <linux/vt_kern.h>
64#include <linux/selection.h>
65#include <linux/spinlock.h>
66#include <linux/kref.h>
67#include <linux/smp_lock.h>
68#include <linux/ioport.h>
69#include <linux/interrupt.h>
70#include <linux/vmalloc.h>
71
72#include "sisusb.h"
73
74#ifdef INCL_SISUSB_CON
75extern int sisusb_setreg(struct sisusb_usb_data *, int, u8);
76extern int sisusb_getreg(struct sisusb_usb_data *, int, u8 *);
77extern int sisusb_setidxreg(struct sisusb_usb_data *, int, u8, u8);
78extern int sisusb_getidxreg(struct sisusb_usb_data *, int, u8, u8 *);
79extern int sisusb_setidxregor(struct sisusb_usb_data *, int, u8, u8);
80extern int sisusb_setidxregand(struct sisusb_usb_data *, int, u8, u8);
81extern int sisusb_setidxregandor(struct sisusb_usb_data *, int, u8, u8, u8);
82
83extern int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
84extern int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
85extern int sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data);
86extern int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data);
87extern int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
88 u32 dest, int length, size_t *bytes_written);
89
90extern void sisusb_delete(struct kref *kref);
91extern int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
92
93extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
94
95#define sisusbcon_writew(val, addr) (*(addr) = (val))
96#define sisusbcon_readw(addr) (*(addr))
97#define sisusbcon_memmovew(d, s, c) memmove(d, s, c)
98#define sisusbcon_memcpyw(d, s, c) memcpy(d, s, c)
99
100/* vc_data -> sisusb conversion table */
101static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES];
102
103/* Forward declaration */
104static const struct consw sisusb_con;
105
106extern struct semaphore disconnect_sem;
107
108static inline void
109sisusbcon_memsetw(u16 *s, u16 c, unsigned int count)
110{
111 count /= 2;
112 while (count--)
113 sisusbcon_writew(c, s++);
114}
115
116static inline void
117sisusb_initialize(struct sisusb_usb_data *sisusb)
118{
119 /* Reset cursor and start address */
120 if (sisusb_setidxreg(sisusb, SISCR, 0x0c, 0x00))
121 return;
122 if (sisusb_setidxreg(sisusb, SISCR, 0x0d, 0x00))
123 return;
124 if (sisusb_setidxreg(sisusb, SISCR, 0x0e, 0x00))
125 return;
126 sisusb_setidxreg(sisusb, SISCR, 0x0f, 0x00);
127}
128
129static inline void
130sisusbcon_set_start_address(struct sisusb_usb_data *sisusb, struct vc_data *c)
131{
132 sisusb->cur_start_addr = (c->vc_visible_origin - sisusb->scrbuf) / 2;
133
134 sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8));
135 sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff));
136}
137
138void
139sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location)
140{
141 if (sisusb->sisusb_cursor_loc == location)
142 return;
143
144 sisusb->sisusb_cursor_loc = location;
145
146 /* Hardware bug: Text cursor appears twice or not at all
147 * at some positions. Work around it with the cursor skew
148 * bits.
149 */
150
151 if ((location & 0x0007) == 0x0007) {
152 sisusb->bad_cursor_pos = 1;
153 location--;
154 if (sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0x1f, 0x20))
155 return;
156 } else if (sisusb->bad_cursor_pos) {
157 if (sisusb_setidxregand(sisusb, SISCR, 0x0b, 0x1f))
158 return;
159 sisusb->bad_cursor_pos = 0;
160 }
161
162 if (sisusb_setidxreg(sisusb, SISCR, 0x0e, (location >> 8)))
163 return;
164 sisusb_setidxreg(sisusb, SISCR, 0x0f, (location & 0xff));
165}
166
167static inline struct sisusb_usb_data *
168sisusb_get_sisusb(unsigned short console)
169{
170 return mysisusbs[console];
171}
172
173static inline int
174sisusb_sisusb_valid(struct sisusb_usb_data *sisusb)
175{
176 if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev)
177 return 0;
178
179 return 1;
180}
181
182static struct sisusb_usb_data *
183sisusb_get_sisusb_lock_and_check(unsigned short console)
184{
185 struct sisusb_usb_data *sisusb;
186
187 /* We can't handle console calls in non-schedulable
188 * context due to our locks and the USB transport.
189 * So we simply ignore them. This should only affect
190 * some calls to printk.
191 */
192 if (in_atomic())
193 return NULL;
194
195 if (!(sisusb = sisusb_get_sisusb(console)))
196 return NULL;
197
198 down(&sisusb->lock);
199
200 if (!sisusb_sisusb_valid(sisusb) ||
201 !sisusb->havethisconsole[console]) {
202 up(&sisusb->lock);
203 return NULL;
204 }
205
206 return sisusb;
207}
208
209static int
210sisusb_is_inactive(struct vc_data *c, struct sisusb_usb_data *sisusb)
211{
212 if (sisusb->is_gfx ||
213 sisusb->textmodedestroyed ||
214 c->vc_mode != KD_TEXT)
215 return 1;
216
217 return 0;
218}
219
220/* con_startup console interface routine */
221static const char *
222sisusbcon_startup(void)
223{
224 return "SISUSBCON";
225}
226
227/* con_init console interface routine */
228static void
229sisusbcon_init(struct vc_data *c, int init)
230{
231 struct sisusb_usb_data *sisusb;
232 int cols, rows;
233
234 /* This is called by take_over_console(),
235 * ie by us/under our control. It is
236 * only called after text mode and fonts
237 * are set up/restored.
238 */
239
240 down(&disconnect_sem);
241
242 if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
243 up(&disconnect_sem);
244 return;
245 }
246
247 down(&sisusb->lock);
248
249 if (!sisusb_sisusb_valid(sisusb)) {
250 up(&sisusb->lock);
251 up(&disconnect_sem);
252 return;
253 }
254
255 c->vc_can_do_color = 1;
256
257 c->vc_complement_mask = 0x7700;
258
259 c->vc_hi_font_mask = sisusb->current_font_512 ? 0x0800 : 0;
260
261 sisusb->haveconsole = 1;
262
263 sisusb->havethisconsole[c->vc_num] = 1;
264
265 /* We only support 640x400 */
266 c->vc_scan_lines = 400;
267
268 c->vc_font.height = sisusb->current_font_height;
269
270 /* We only support width = 8 */
271 cols = 80;
272 rows = c->vc_scan_lines / c->vc_font.height;
273
274 /* Increment usage count for our sisusb.
275 * Doing so saves us from upping/downing
276 * the disconnect semaphore; we can't
277 * lose our sisusb until this is undone
278 * in con_deinit. For all other console
279 * interface functions, it suffices to
280 * use sisusb->lock and do a quick check
281 * of sisusb for device disconnection.
282 */
283 kref_get(&sisusb->kref);
284
285 if (!*c->vc_uni_pagedir_loc)
286 con_set_default_unimap(c);
287
288 up(&sisusb->lock);
289
290 up(&disconnect_sem);
291
292 if (init) {
293 c->vc_cols = cols;
294 c->vc_rows = rows;
295 } else
296 vc_resize(c, cols, rows);
297}
298
299/* con_deinit console interface routine */
300static void
301sisusbcon_deinit(struct vc_data *c)
302{
303 struct sisusb_usb_data *sisusb;
304 int i;
305
306 /* This is called by take_over_console()
307 * and others, ie not under our control.
308 */
309
310 down(&disconnect_sem);
311
312 if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
313 up(&disconnect_sem);
314 return;
315 }
316
317 down(&sisusb->lock);
318
319 /* Clear ourselves in mysisusbs */
320 mysisusbs[c->vc_num] = NULL;
321
322 sisusb->havethisconsole[c->vc_num] = 0;
323
324 /* Free our font buffer if all consoles are gone */
325 if (sisusb->font_backup) {
326 for(i = 0; i < MAX_NR_CONSOLES; i++) {
327 if (sisusb->havethisconsole[c->vc_num])
328 break;
329 }
330 if (i == MAX_NR_CONSOLES) {
331 vfree(sisusb->font_backup);
332 sisusb->font_backup = NULL;
333 }
334 }
335
336 up(&sisusb->lock);
337
338 /* decrement the usage count on our sisusb */
339 kref_put(&sisusb->kref, sisusb_delete);
340
341 up(&disconnect_sem);
342}
343
344/* interface routine */
345static u8
346sisusbcon_build_attr(struct vc_data *c, u8 color, u8 intensity,
347 u8 blink, u8 underline, u8 reverse)
348{
349 u8 attr = color;
350
351 if (underline)
352 attr = (attr & 0xf0) | c->vc_ulcolor;
353 else if (intensity == 0)
354 attr = (attr & 0xf0) | c->vc_halfcolor;
355
356 if (reverse)
357 attr = ((attr) & 0x88) |
358 ((((attr) >> 4) |
359 ((attr) << 4)) & 0x77);
360
361 if (blink)
362 attr ^= 0x80;
363
364 if (intensity == 2)
365 attr ^= 0x08;
366
367 return attr;
368}
369
370/* Interface routine */
371static void
372sisusbcon_invert_region(struct vc_data *vc, u16 *p, int count)
373{
374 /* Invert a region. This is called with a pointer
375 * to the console's internal screen buffer. So we
376 * simply do the inversion there and rely on
377 * a call to putc(s) to update the real screen.
378 */
379
380 while (count--) {
381 u16 a = sisusbcon_readw(p);
382
383 a = ((a) & 0x88ff) |
384 (((a) & 0x7000) >> 4) |
385 (((a) & 0x0700) << 4);
386
387 sisusbcon_writew(a, p++);
388 }
389}
390
391#define SISUSB_VADDR(x,y) \
392 ((u16 *)c->vc_origin + \
393 (y) * sisusb->sisusb_num_columns + \
394 (x))
395
396#define SISUSB_HADDR(x,y) \
397 ((u16 *)(sisusb->vrambase + (c->vc_origin - sisusb->scrbuf)) + \
398 (y) * sisusb->sisusb_num_columns + \
399 (x))
400
401/* Interface routine */
402static void
403sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
404{
405 struct sisusb_usb_data *sisusb;
406 ssize_t written;
407
408 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
409 return;
410
411 /* sisusb->lock is down */
412
413 /* Don't need to put the character into buffer ourselves,
414 * because the vt does this BEFORE calling us.
415 */
416#if 0
417 sisusbcon_writew(ch, SISUSB_VADDR(x, y));
418#endif
419
420 if (sisusb_is_inactive(c, sisusb)) {
421 up(&sisusb->lock);
422 return;
423 }
424
425
426 sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
427 (u32)SISUSB_HADDR(x, y), 2, &written);
428
429 up(&sisusb->lock);
430}
431
432/* Interface routine */
433static void
434sisusbcon_putcs(struct vc_data *c, const unsigned short *s,
435 int count, int y, int x)
436{
437 struct sisusb_usb_data *sisusb;
438 ssize_t written;
439 u16 *dest;
440 int i;
441
442 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
443 return;
444
445 /* sisusb->lock is down */
446
447 /* Need to put the characters into the buffer ourselves,
448 * because the vt does this AFTER calling us.
449 */
450
451 dest = SISUSB_VADDR(x, y);
452
453 for (i = count; i > 0; i--)
454 sisusbcon_writew(sisusbcon_readw(s++), dest++);
455
456 if (sisusb_is_inactive(c, sisusb)) {
457 up(&sisusb->lock);
458 return;
459 }
460
461 sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
462 (u32)SISUSB_HADDR(x, y), count * 2, &written);
463
464 up(&sisusb->lock);
465}
466
467/* Interface routine */
468static void
469sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width)
470{
471 struct sisusb_usb_data *sisusb;
472 u16 eattr = c->vc_video_erase_char;
473 ssize_t written;
474 int i, length, cols;
475 u16 *dest;
476
477 if (width <= 0 || height <= 0)
478 return;
479
480 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
481 return;
482
483 /* sisusb->lock is down */
484
485 /* Need to clear buffer ourselves, because the vt does
486 * this AFTER calling us.
487 */
488
489 dest = SISUSB_VADDR(x, y);
490
491 cols = sisusb->sisusb_num_columns;
492
493 if (width > cols)
494 width = cols;
495
496 if (x == 0 && width >= c->vc_cols) {
497
498 sisusbcon_memsetw(dest, eattr, height * cols * 2);
499
500 } else {
501
502 for (i = height; i > 0; i--, dest += cols)
503 sisusbcon_memsetw(dest, eattr, width * 2);
504
505 }
506
507 if (sisusb_is_inactive(c, sisusb)) {
508 up(&sisusb->lock);
509 return;
510 }
511
512 length = ((height * cols) - x - (cols - width - x)) * 2;
513
514
515 sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y),
516 (u32)SISUSB_HADDR(x, y), length, &written);
517
518 up(&sisusb->lock);
519}
520
521/* Interface routine */
522static void
523sisusbcon_bmove(struct vc_data *c, int sy, int sx,
524 int dy, int dx, int height, int width)
525{
526 struct sisusb_usb_data *sisusb;
527 ssize_t written;
528 int cols, length;
529#if 0
530 u16 *src, *dest;
531 int i;
532#endif
533
534 if (width <= 0 || height <= 0)
535 return;
536
537 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
538 return;
539
540 /* sisusb->lock is down */
541
542 cols = sisusb->sisusb_num_columns;
543
544 /* Don't need to move data outselves, because
545 * vt does this BEFORE calling us.
546 * This is only used by vt's insert/deletechar.
547 */
548#if 0
549 if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
550
551 sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
552 height * width * 2);
553
554 } else if (dy < sy || (dy == sy && dx < sx)) {
555
556 src = SISUSB_VADDR(sx, sy);
557 dest = SISUSB_VADDR(dx, dy);
558
559 for (i = height; i > 0; i--) {
560 sisusbcon_memmovew(dest, src, width * 2);
561 src += cols;
562 dest += cols;
563 }
564
565 } else {
566
567 src = SISUSB_VADDR(sx, sy + height - 1);
568 dest = SISUSB_VADDR(dx, dy + height - 1);
569
570 for (i = height; i > 0; i--) {
571 sisusbcon_memmovew(dest, src, width * 2);
572 src -= cols;
573 dest -= cols;
574 }
575
576 }
577#endif
578
579 if (sisusb_is_inactive(c, sisusb)) {
580 up(&sisusb->lock);
581 return;
582 }
583
584 length = ((height * cols) - dx - (cols - width - dx)) * 2;
585
586
587 sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy),
588 (u32)SISUSB_HADDR(dx, dy), length, &written);
589
590 up(&sisusb->lock);
591}
592
593/* interface routine */
594static int
595sisusbcon_switch(struct vc_data *c)
596{
597 struct sisusb_usb_data *sisusb;
598 ssize_t written;
599 int length;
600
601 /* Returnvalue 0 means we have fully restored screen,
602 * and vt doesn't need to call do_update_region().
603 * Returnvalue != 0 naturally means the opposite.
604 */
605
606 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
607 return 0;
608
609 /* sisusb->lock is down */
610
611 /* Don't write to screen if in gfx mode */
612 if (sisusb_is_inactive(c, sisusb)) {
613 up(&sisusb->lock);
614 return 0;
615 }
616
617 /* That really should not happen. It would mean we are
618 * being called while the vc is using its private buffer
619 * as origin.
620 */
621 if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
622 up(&sisusb->lock);
623 printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
624 return 0;
625 }
626
627 /* Check that we don't copy too much */
628 length = min((int)c->vc_screenbuf_size,
629 (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin));
630
631 /* Restore the screen contents */
632 sisusbcon_memcpyw((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf,
633 length);
634
635 sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin,
636 (u32)SISUSB_HADDR(0, 0),
637 length, &written);
638
639 up(&sisusb->lock);
640
641 return 0;
642}
643
644/* interface routine */
645static void
646sisusbcon_save_screen(struct vc_data *c)
647{
648 struct sisusb_usb_data *sisusb;
649 int length;
650
651 /* Save the current screen contents to vc's private
652 * buffer.
653 */
654
655 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
656 return;
657
658 /* sisusb->lock is down */
659
660 if (sisusb_is_inactive(c, sisusb)) {
661 up(&sisusb->lock);
662 return;
663 }
664
665 /* Check that we don't copy too much */
666 length = min((int)c->vc_screenbuf_size,
667 (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin));
668
669 /* Save the screen contents to vc's private buffer */
670 sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin,
671 length);
672
673 up(&sisusb->lock);
674}
675
676/* interface routine */
677static int
678sisusbcon_set_palette(struct vc_data *c, unsigned char *table)
679{
680 struct sisusb_usb_data *sisusb;
681 int i, j;
682
683 /* Return value not used by vt */
684
685 if (!CON_IS_VISIBLE(c))
686 return -EINVAL;
687
688 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
689 return -EINVAL;
690
691 /* sisusb->lock is down */
692
693 if (sisusb_is_inactive(c, sisusb)) {
694 up(&sisusb->lock);
695 return -EINVAL;
696 }
697
698 for (i = j = 0; i < 16; i++) {
699 if (sisusb_setreg(sisusb, SISCOLIDX, table[i]))
700 break;
701 if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
702 break;
703 if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
704 break;
705 if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2))
706 break;
707 }
708
709 up(&sisusb->lock);
710
711 return 0;
712}
713
714/* interface routine */
715static int
716sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
717{
718 struct sisusb_usb_data *sisusb;
719 u8 sr1, cr17, pmreg, cr63;
720 ssize_t written;
721 int ret = 0;
722
723 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
724 return 0;
725
726 /* sisusb->lock is down */
727
728 if (mode_switch)
729 sisusb->is_gfx = blank ? 1 : 0;
730
731 if (sisusb_is_inactive(c, sisusb)) {
732 up(&sisusb->lock);
733 return 0;
734 }
735
736 switch (blank) {
737
738 case 1: /* Normal blanking: Clear screen */
739 case -1:
740 sisusbcon_memsetw((u16 *)c->vc_origin,
741 c->vc_video_erase_char,
742 c->vc_screenbuf_size);
743 sisusb_copy_memory(sisusb,
744 (unsigned char *)c->vc_origin,
745 (u32)(sisusb->vrambase +
746 (c->vc_origin - sisusb->scrbuf)),
747 c->vc_screenbuf_size, &written);
748 sisusb->con_blanked = 1;
749 ret = 1;
750 break;
751
752 default: /* VESA blanking */
753 switch (blank) {
754 case 0: /* Unblank */
755 sr1 = 0x00;
756 cr17 = 0x80;
757 pmreg = 0x00;
758 cr63 = 0x00;
759 ret = 1;
760 sisusb->con_blanked = 0;
761 break;
762 case VESA_VSYNC_SUSPEND + 1:
763 sr1 = 0x20;
764 cr17 = 0x80;
765 pmreg = 0x80;
766 cr63 = 0x40;
767 break;
768 case VESA_HSYNC_SUSPEND + 1:
769 sr1 = 0x20;
770 cr17 = 0x80;
771 pmreg = 0x40;
772 cr63 = 0x40;
773 break;
774 case VESA_POWERDOWN + 1:
775 sr1 = 0x20;
776 cr17 = 0x00;
777 pmreg = 0xc0;
778 cr63 = 0x40;
779 break;
780 default:
781 up(&sisusb->lock);
782 return -EINVAL;
783 }
784
785 sisusb_setidxregandor(sisusb, SISSR, 0x01, ~0x20, sr1);
786 sisusb_setidxregandor(sisusb, SISCR, 0x17, 0x7f, cr17);
787 sisusb_setidxregandor(sisusb, SISSR, 0x1f, 0x3f, pmreg);
788 sisusb_setidxregandor(sisusb, SISCR, 0x63, 0xbf, cr63);
789
790 }
791
792 up(&sisusb->lock);
793
794 return ret;
795}
796
797/* interface routine */
798static int
799sisusbcon_scrolldelta(struct vc_data *c, int lines)
800{
801 struct sisusb_usb_data *sisusb;
802 int margin = c->vc_size_row * 4;
803 int ul, we, p, st;
804
805 /* The return value does not seem to be used */
806
807 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
808 return 0;
809
810 /* sisusb->lock is down */
811
812 if (sisusb_is_inactive(c, sisusb)) {
813 up(&sisusb->lock);
814 return 0;
815 }
816
817 if (!lines) /* Turn scrollback off */
818 c->vc_visible_origin = c->vc_origin;
819 else {
820
821 if (sisusb->con_rolled_over >
822 (c->vc_scr_end - sisusb->scrbuf) + margin) {
823
824 ul = c->vc_scr_end - sisusb->scrbuf;
825 we = sisusb->con_rolled_over + c->vc_size_row;
826
827 } else {
828
829 ul = 0;
830 we = sisusb->scrbuf_size;
831
832 }
833
834 p = (c->vc_visible_origin - sisusb->scrbuf - ul + we) % we +
835 lines * c->vc_size_row;
836
837 st = (c->vc_origin - sisusb->scrbuf - ul + we) % we;
838
839 if (st < 2 * margin)
840 margin = 0;
841
842 if (p < margin)
843 p = 0;
844
845 if (p > st - margin)
846 p = st;
847
848 c->vc_visible_origin = sisusb->scrbuf + (p + ul) % we;
849 }
850
851 sisusbcon_set_start_address(sisusb, c);
852
853 up(&sisusb->lock);
854
855 return 1;
856}
857
858/* Interface routine */
859static void
860sisusbcon_cursor(struct vc_data *c, int mode)
861{
862 struct sisusb_usb_data *sisusb;
863 int from, to, baseline;
864
865 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
866 return;
867
868 /* sisusb->lock is down */
869
870 if (sisusb_is_inactive(c, sisusb)) {
871 up(&sisusb->lock);
872 return;
873 }
874
875 if (c->vc_origin != c->vc_visible_origin) {
876 c->vc_visible_origin = c->vc_origin;
877 sisusbcon_set_start_address(sisusb, c);
878 }
879
880 if (mode == CM_ERASE) {
881 sisusb_setidxregor(sisusb, SISCR, 0x0a, 0x20);
882 sisusb->sisusb_cursor_size_to = -1;
883 up(&sisusb->lock);
884 return;
885 }
886
887 sisusb_set_cursor(sisusb, (c->vc_pos - sisusb->scrbuf) / 2);
888
889 baseline = c->vc_font.height - (c->vc_font.height < 10 ? 1 : 2);
890
891 switch (c->vc_cursor_type & 0x0f) {
892 case CUR_BLOCK: from = 1;
893 to = c->vc_font.height;
894 break;
895 case CUR_TWO_THIRDS: from = c->vc_font.height / 3;
896 to = baseline;
897 break;
898 case CUR_LOWER_HALF: from = c->vc_font.height / 2;
899 to = baseline;
900 break;
901 case CUR_LOWER_THIRD: from = (c->vc_font.height * 2) / 3;
902 to = baseline;
903 break;
904 case CUR_NONE: from = 31;
905 to = 30;
906 break;
907 default:
908 case CUR_UNDERLINE: from = baseline - 1;
909 to = baseline;
910 break;
911 }
912
913 if (sisusb->sisusb_cursor_size_from != from ||
914 sisusb->sisusb_cursor_size_to != to) {
915
916 sisusb_setidxreg(sisusb, SISCR, 0x0a, from);
917 sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0, to);
918
919 sisusb->sisusb_cursor_size_from = from;
920 sisusb->sisusb_cursor_size_to = to;
921 }
922
923 up(&sisusb->lock);
924}
925
926static int
927sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb,
928 int t, int b, int dir, int lines)
929{
930 int cols = sisusb->sisusb_num_columns;
931 int length = ((b - t) * cols) * 2;
932 u16 eattr = c->vc_video_erase_char;
933 ssize_t written;
934
935 /* sisusb->lock is down */
936
937 /* Scroll an area which does not match the
938 * visible screen's dimensions. This needs
939 * to be done separately, as it does not
940 * use hardware panning.
941 */
942
943 switch (dir) {
944
945 case SM_UP:
946 sisusbcon_memmovew(SISUSB_VADDR(0, t),
947 SISUSB_VADDR(0, t + lines),
948 (b - t - lines) * cols * 2);
949 sisusbcon_memsetw(SISUSB_VADDR(0, b - lines), eattr,
950 lines * cols * 2);
951 break;
952
953 case SM_DOWN:
954 sisusbcon_memmovew(SISUSB_VADDR(0, t + lines),
955 SISUSB_VADDR(0, t),
956 (b - t - lines) * cols * 2);
957 sisusbcon_memsetw(SISUSB_VADDR(0, t), eattr,
958 lines * cols * 2);
959 break;
960 }
961
962 sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t),
963 (u32)SISUSB_HADDR(0, t), length, &written);
964
965 up(&sisusb->lock);
966
967 return 1;
968}
969
970/* Interface routine */
971static int
972sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
973{
974 struct sisusb_usb_data *sisusb;
975 u16 eattr = c->vc_video_erase_char;
976 ssize_t written;
977 int copyall = 0;
978 unsigned long oldorigin;
979 unsigned int delta = lines * c->vc_size_row;
980 u32 originoffset;
981
982 /* Returning != 0 means we have done the scrolling successfully.
983 * Returning 0 makes vt do the scrolling on its own.
984 * Note that con_scroll is only called if the console is
985 * visible. In that case, the origin should be our buffer,
986 * not the vt's private one.
987 */
988
989 if (!lines)
990 return 1;
991
992 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
993 return 0;
994
995 /* sisusb->lock is down */
996
997 if (sisusb_is_inactive(c, sisusb)) {
998 up(&sisusb->lock);
999 return 0;
1000 }
1001
1002 /* Special case */
1003 if (t || b != c->vc_rows)
1004 return sisusbcon_scroll_area(c, sisusb, t, b, dir, lines);
1005
1006 if (c->vc_origin != c->vc_visible_origin) {
1007 c->vc_visible_origin = c->vc_origin;
1008 sisusbcon_set_start_address(sisusb, c);
1009 }
1010
1011 /* limit amount to maximum realistic size */
1012 if (lines > c->vc_rows)
1013 lines = c->vc_rows;
1014
1015 oldorigin = c->vc_origin;
1016
1017 switch (dir) {
1018
1019 case SM_UP:
1020
1021 if (c->vc_scr_end + delta >=
1022 sisusb->scrbuf + sisusb->scrbuf_size) {
1023 sisusbcon_memcpyw((u16 *)sisusb->scrbuf,
1024 (u16 *)(oldorigin + delta),
1025 c->vc_screenbuf_size - delta);
1026 c->vc_origin = sisusb->scrbuf;
1027 sisusb->con_rolled_over = oldorigin - sisusb->scrbuf;
1028 copyall = 1;
1029 } else
1030 c->vc_origin += delta;
1031
1032 sisusbcon_memsetw(
1033 (u16 *)(c->vc_origin + c->vc_screenbuf_size - delta),
1034 eattr, delta);
1035
1036 break;
1037
1038 case SM_DOWN:
1039
1040 if (oldorigin - delta < sisusb->scrbuf) {
1041 sisusbcon_memmovew((u16 *)(sisusb->scrbuf +
1042 sisusb->scrbuf_size -
1043 c->vc_screenbuf_size +
1044 delta),
1045 (u16 *)oldorigin,
1046 c->vc_screenbuf_size - delta);
1047 c->vc_origin = sisusb->scrbuf +
1048 sisusb->scrbuf_size -
1049 c->vc_screenbuf_size;
1050 sisusb->con_rolled_over = 0;
1051 copyall = 1;
1052 } else
1053 c->vc_origin -= delta;
1054
1055 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1056
1057 scr_memsetw((u16 *)(c->vc_origin), eattr, delta);
1058
1059 break;
1060 }
1061
1062 originoffset = (u32)(c->vc_origin - sisusb->scrbuf);
1063
1064 if (copyall)
1065 sisusb_copy_memory(sisusb,
1066 (char *)c->vc_origin,
1067 (u32)(sisusb->vrambase + originoffset),
1068 c->vc_screenbuf_size, &written);
1069 else if (dir == SM_UP)
1070 sisusb_copy_memory(sisusb,
1071 (char *)c->vc_origin + c->vc_screenbuf_size - delta,
1072 (u32)sisusb->vrambase + originoffset +
1073 c->vc_screenbuf_size - delta,
1074 delta, &written);
1075 else
1076 sisusb_copy_memory(sisusb,
1077 (char *)c->vc_origin,
1078 (u32)(sisusb->vrambase + originoffset),
1079 delta, &written);
1080
1081 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1082 c->vc_visible_origin = c->vc_origin;
1083
1084 sisusbcon_set_start_address(sisusb, c);
1085
1086 c->vc_pos = c->vc_pos - oldorigin + c->vc_origin;
1087
1088 up(&sisusb->lock);
1089
1090 return 1;
1091}
1092
1093/* Interface routine */
1094static int
1095sisusbcon_set_origin(struct vc_data *c)
1096{
1097 struct sisusb_usb_data *sisusb;
1098
1099 /* Returning != 0 means we were successful.
1100 * Returning 0 will vt make to use its own
1101 * screenbuffer as the origin.
1102 */
1103
1104 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
1105 return 0;
1106
1107 /* sisusb->lock is down */
1108
1109 if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) {
1110 up(&sisusb->lock);
1111 return 0;
1112 }
1113
1114 c->vc_origin = c->vc_visible_origin = sisusb->scrbuf;
1115
1116 sisusbcon_set_start_address(sisusb, c);
1117
1118 sisusb->con_rolled_over = 0;
1119
1120 up(&sisusb->lock);
1121
1122 return 1;
1123}
1124
1125/* Interface routine */
1126static int
1127sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows)
1128{
1129 struct sisusb_usb_data *sisusb;
1130 int fh;
1131
1132 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
1133 return -ENODEV;
1134
1135 fh = sisusb->current_font_height;
1136
1137 up(&sisusb->lock);
1138
1139 /* We are quite unflexible as regards resizing. The vt code
1140 * handles sizes where the line length isn't equal the pitch
1141 * quite badly. As regards the rows, our panning tricks only
1142 * work well if the number of rows equals the visible number
1143 * of rows.
1144 */
1145
1146 if (newcols != 80 || c->vc_scan_lines / fh != newrows)
1147 return -EINVAL;
1148
1149 return 0;
1150}
1151
1152int
1153sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
1154 u8 *arg, int cmapsz, int ch512, int dorecalc,
1155 struct vc_data *c, int fh, int uplock)
1156{
1157 int font_select = 0x00, i, err = 0;
1158 u32 offset = 0;
1159 u8 dummy;
1160
1161 /* sisusb->lock is down */
1162
1163 /*
1164 * The default font is kept in slot 0.
1165 * A user font is loaded in slot 2 (256 ch)
1166 * or 2+3 (512 ch).
1167 */
1168
1169 if ((slot != 0 && slot != 2) || !fh) {
1170 if (uplock)
1171 up(&sisusb->lock);
1172 return -EINVAL;
1173 }
1174
1175 if (set)
1176 sisusb->font_slot = slot;
1177
1178 /* Default font is always 256 */
1179 if (slot == 0)
1180 ch512 = 0;
1181 else
1182 offset = 4 * cmapsz;
1183
1184 font_select = (slot == 0) ? 0x00 : (ch512 ? 0x0e : 0x0a);
1185
1186 err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */
1187 err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x04); /* Write to plane 2 */
1188 err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x07); /* Memory mode a0-bf */
1189 err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset */
1190
1191 if (err)
1192 goto font_op_error;
1193
1194 err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x03); /* Select plane read 2 */
1195 err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x00); /* Disable odd/even */
1196 err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x00); /* Address range a0-bf */
1197
1198 if (err)
1199 goto font_op_error;
1200
1201 if (arg) {
1202 if (set)
1203 for (i = 0; i < cmapsz; i++) {
1204 err |= sisusb_writeb(sisusb,
1205 sisusb->vrambase + offset + i,
1206 arg[i]);
1207 if (err)
1208 break;
1209 }
1210 else
1211 for (i = 0; i < cmapsz; i++) {
1212 err |= sisusb_readb(sisusb,
1213 sisusb->vrambase + offset + i,
1214 &arg[i]);
1215 if (err)
1216 break;
1217 }
1218
1219 /*
1220 * In 512-character mode, the character map is not contiguous if
1221 * we want to remain EGA compatible -- which we do
1222 */
1223
1224 if (ch512) {
1225 if (set)
1226 for (i = 0; i < cmapsz; i++) {
1227 err |= sisusb_writeb(sisusb,
1228 sisusb->vrambase + offset +
1229 (2 * cmapsz) + i,
1230 arg[cmapsz + i]);
1231 if (err)
1232 break;
1233 }
1234 else
1235 for (i = 0; i < cmapsz; i++) {
1236 err |= sisusb_readb(sisusb,
1237 sisusb->vrambase + offset +
1238 (2 * cmapsz) + i,
1239 &arg[cmapsz + i]);
1240 if (err)
1241 break;
1242 }
1243 }
1244 }
1245
1246 if (err)
1247 goto font_op_error;
1248
1249 err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */
1250 err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x03); /* Write to planes 0+1 */
1251 err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x03); /* Memory mode a0-bf */
1252 if (set)
1253 sisusb_setidxreg(sisusb, SISSR, 0x03, font_select);
1254 err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset end */
1255
1256 if (err)
1257 goto font_op_error;
1258
1259 err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x00); /* Select plane read 0 */
1260 err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x10); /* Enable odd/even */
1261 err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x06); /* Address range b8-bf */
1262
1263 if (err)
1264 goto font_op_error;
1265
1266 if ((set) && (ch512 != sisusb->current_font_512)) {
1267
1268 /* Font is shared among all our consoles.
1269 * And so is the hi_font_mask.
1270 */
1271 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1272 struct vc_data *c = vc_cons[i].d;
1273 if (c && c->vc_sw == &sisusb_con)
1274 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1275 }
1276
1277 sisusb->current_font_512 = ch512;
1278
1279 /* color plane enable register:
1280 256-char: enable intensity bit
1281 512-char: disable intensity bit */
1282 sisusb_getreg(sisusb, SISINPSTAT, &dummy);
1283 sisusb_setreg(sisusb, SISAR, 0x12);
1284 sisusb_setreg(sisusb, SISAR, ch512 ? 0x07 : 0x0f);
1285
1286 sisusb_getreg(sisusb, SISINPSTAT, &dummy);
1287 sisusb_setreg(sisusb, SISAR, 0x20);
1288 sisusb_getreg(sisusb, SISINPSTAT, &dummy);
1289 }
1290
1291 if (dorecalc) {
1292
1293 /*
1294 * Adjust the screen to fit a font of a certain height
1295 */
1296
1297 unsigned char ovr, vde, fsr;
1298 int rows = 0, maxscan = 0;
1299
1300 if (c) {
1301
1302 /* Number of video rows */
1303 rows = c->vc_scan_lines / fh;
1304 /* Scan lines to actually display-1 */
1305 maxscan = rows * fh - 1;
1306
1307 /*printk(KERN_DEBUG "sisusb recalc rows %d maxscan %d fh %d sl %d\n",
1308 rows, maxscan, fh, c->vc_scan_lines);*/
1309
1310 sisusb_getidxreg(sisusb, SISCR, 0x07, &ovr);
1311 vde = maxscan & 0xff;
1312 ovr = (ovr & 0xbd) |
1313 ((maxscan & 0x100) >> 7) |
1314 ((maxscan & 0x200) >> 3);
1315 sisusb_setidxreg(sisusb, SISCR, 0x07, ovr);
1316 sisusb_setidxreg(sisusb, SISCR, 0x12, vde);
1317
1318 }
1319
1320 sisusb_getidxreg(sisusb, SISCR, 0x09, &fsr);
1321 fsr = (fsr & 0xe0) | (fh - 1);
1322 sisusb_setidxreg(sisusb, SISCR, 0x09, fsr);
1323 sisusb->current_font_height = fh;
1324
1325 sisusb->sisusb_cursor_size_from = -1;
1326 sisusb->sisusb_cursor_size_to = -1;
1327
1328 }
1329
1330 if (uplock)
1331 up(&sisusb->lock);
1332
1333 if (dorecalc && c) {
1334 int i, rows = c->vc_scan_lines / fh;
1335
1336 /* Now adjust our consoles' size */
1337
1338 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1339 struct vc_data *vc = vc_cons[i].d;
1340
1341 if (vc && vc->vc_sw == &sisusb_con) {
1342 if (CON_IS_VISIBLE(vc)) {
1343 vc->vc_sw->con_cursor(vc, CM_DRAW);
1344 }
1345 vc->vc_font.height = fh;
1346 vc_resize(vc, 0, rows);
1347 }
1348 }
1349 }
1350
1351 return 0;
1352
1353font_op_error:
1354 if (uplock)
1355 up(&sisusb->lock);
1356
1357 return -EIO;
1358}
1359
1360/* Interface routine */
1361static int
1362sisusbcon_font_set(struct vc_data *c, struct console_font *font,
1363 unsigned flags)
1364{
1365 struct sisusb_usb_data *sisusb;
1366 unsigned charcount = font->charcount;
1367
1368 if (font->width != 8 || (charcount != 256 && charcount != 512))
1369 return -EINVAL;
1370
1371 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
1372 return -ENODEV;
1373
1374 /* sisusb->lock is down */
1375
1376 /* Save the user-provided font into a buffer. This
1377 * is used for restoring text mode after quitting
1378 * from X and for the con_getfont routine.
1379 */
1380 if (sisusb->font_backup) {
1381 if (sisusb->font_backup_size < charcount) {
1382 vfree(sisusb->font_backup);
1383 sisusb->font_backup = NULL;
1384 }
1385 }
1386
1387 if (!sisusb->font_backup)
1388 sisusb->font_backup = vmalloc(charcount * 32);
1389
1390 if (sisusb->font_backup) {
1391 memcpy(sisusb->font_backup, font->data, charcount * 32);
1392 sisusb->font_backup_size = charcount;
1393 sisusb->font_backup_height = font->height;
1394 sisusb->font_backup_512 = (charcount == 512) ? 1 : 0;
1395 }
1396
1397 /* do_font_op ups sisusb->lock */
1398
1399 return sisusbcon_do_font_op(sisusb, 1, 2, font->data,
1400 8192, (charcount == 512),
1401 (!(flags & KD_FONT_FLAG_DONT_RECALC)) ? 1 : 0,
1402 c, font->height, 1);
1403}
1404
1405/* Interface routine */
1406static int
1407sisusbcon_font_get(struct vc_data *c, struct console_font *font)
1408{
1409 struct sisusb_usb_data *sisusb;
1410
1411 if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num)))
1412 return -ENODEV;
1413
1414 /* sisusb->lock is down */
1415
1416 font->width = 8;
1417 font->height = c->vc_font.height;
1418 font->charcount = 256;
1419
1420 if (!font->data) {
1421 up(&sisusb->lock);
1422 return 0;
1423 }
1424
1425 if (!sisusb->font_backup) {
1426 up(&sisusb->lock);
1427 return -ENODEV;
1428 }
1429
1430 /* Copy 256 chars only, like vgacon */
1431 memcpy(font->data, sisusb->font_backup, 256 * 32);
1432
1433 up(&sisusb->lock);
1434
1435 return 0;
1436}
1437
1438/*
1439 * The console `switch' structure for the sisusb console
1440 */
1441
1442static const struct consw sisusb_con = {
1443 .owner = THIS_MODULE,
1444 .con_startup = sisusbcon_startup,
1445 .con_init = sisusbcon_init,
1446 .con_deinit = sisusbcon_deinit,
1447 .con_clear = sisusbcon_clear,
1448 .con_putc = sisusbcon_putc,
1449 .con_putcs = sisusbcon_putcs,
1450 .con_cursor = sisusbcon_cursor,
1451 .con_scroll = sisusbcon_scroll,
1452 .con_bmove = sisusbcon_bmove,
1453 .con_switch = sisusbcon_switch,
1454 .con_blank = sisusbcon_blank,
1455 .con_font_set = sisusbcon_font_set,
1456 .con_font_get = sisusbcon_font_get,
1457 .con_set_palette = sisusbcon_set_palette,
1458 .con_scrolldelta = sisusbcon_scrolldelta,
1459 .con_build_attr = sisusbcon_build_attr,
1460 .con_invert_region = sisusbcon_invert_region,
1461 .con_set_origin = sisusbcon_set_origin,
1462 .con_save_screen = sisusbcon_save_screen,
1463 .con_resize = sisusbcon_resize,
1464};
1465
1466/* Our very own dummy console driver */
1467
1468static const char *sisusbdummycon_startup(void)
1469{
1470 return "SISUSBVGADUMMY";
1471}
1472
1473static void sisusbdummycon_init(struct vc_data *vc, int init)
1474{
1475 vc->vc_can_do_color = 1;
1476 if (init) {
1477 vc->vc_cols = 80;
1478 vc->vc_rows = 25;
1479 } else
1480 vc_resize(vc, 80, 25);
1481}
1482
1483static int sisusbdummycon_dummy(void)
1484{
1485 return 0;
1486}
1487
1488#define SISUSBCONDUMMY (void *)sisusbdummycon_dummy
1489
1490const struct consw sisusb_dummy_con = {
1491 .owner = THIS_MODULE,
1492 .con_startup = sisusbdummycon_startup,
1493 .con_init = sisusbdummycon_init,
1494 .con_deinit = SISUSBCONDUMMY,
1495 .con_clear = SISUSBCONDUMMY,
1496 .con_putc = SISUSBCONDUMMY,
1497 .con_putcs = SISUSBCONDUMMY,
1498 .con_cursor = SISUSBCONDUMMY,
1499 .con_scroll = SISUSBCONDUMMY,
1500 .con_bmove = SISUSBCONDUMMY,
1501 .con_switch = SISUSBCONDUMMY,
1502 .con_blank = SISUSBCONDUMMY,
1503 .con_font_set = SISUSBCONDUMMY,
1504 .con_font_get = SISUSBCONDUMMY,
1505 .con_font_default = SISUSBCONDUMMY,
1506 .con_font_copy = SISUSBCONDUMMY,
1507 .con_set_palette = SISUSBCONDUMMY,
1508 .con_scrolldelta = SISUSBCONDUMMY,
1509};
1510
1511int
1512sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
1513{
1514 int i, ret, minor = sisusb->minor;
1515
1516 down(&disconnect_sem);
1517
1518 down(&sisusb->lock);
1519
1520 /* Erm.. that should not happen */
1521 if (sisusb->haveconsole || !sisusb->SiS_Pr) {
1522 up(&sisusb->lock);
1523 up(&disconnect_sem);
1524 return 1;
1525 }
1526
1527 sisusb->con_first = first;
1528 sisusb->con_last = last;
1529
1530 if (first > last ||
1531 first > MAX_NR_CONSOLES ||
1532 last > MAX_NR_CONSOLES) {
1533 up(&sisusb->lock);
1534 up(&disconnect_sem);
1535 return 1;
1536 }
1537
1538 /* If gfxcore not initialized or no consoles given, quit graciously */
1539 if (!sisusb->gfxinit || first < 1 || last < 1) {
1540 up(&sisusb->lock);
1541 up(&disconnect_sem);
1542 return 0;
1543 }
1544
1545 sisusb->sisusb_cursor_loc = -1;
1546 sisusb->sisusb_cursor_size_from = -1;
1547 sisusb->sisusb_cursor_size_to = -1;
1548
1549 /* Set up text mode (and upload default font) */
1550 if (sisusb_reset_text_mode(sisusb, 1)) {
1551 up(&sisusb->lock);
1552 up(&disconnect_sem);
1553 printk(KERN_ERR
1554 "sisusbvga[%d]: Failed to set up text mode\n",
1555 minor);
1556 return 1;
1557 }
1558
1559 /* Initialize some gfx registers */
1560 sisusb_initialize(sisusb);
1561
1562 for (i = first - 1; i <= last - 1; i++) {
1563 /* Save sisusb for our interface routines */
1564 mysisusbs[i] = sisusb;
1565 }
1566
1567 /* Initial console setup */
1568 sisusb->sisusb_num_columns = 80;
1569
1570 /* Use a 32K buffer (matches b8000-bffff area) */
1571 sisusb->scrbuf_size = 32 * 1024;
1572
1573 /* Allocate screen buffer */
1574 if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
1575 up(&sisusb->lock);
1576 up(&disconnect_sem);
1577 printk(KERN_ERR
1578 "sisusbvga[%d]: Failed to allocate screen buffer\n",
1579 minor);
1580 return 1;
1581 }
1582
1583 up(&sisusb->lock);
1584 up(&disconnect_sem);
1585
1586 /* Now grab the desired console(s) */
1587 ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);
1588
1589 if (!ret)
1590 sisusb->haveconsole = 1;
1591 else {
1592 for (i = first - 1; i <= last - 1; i++)
1593 mysisusbs[i] = NULL;
1594 }
1595
1596 return ret;
1597}
1598
1599void
1600sisusb_console_exit(struct sisusb_usb_data *sisusb)
1601{
1602 int i;
1603
1604 /* This is called if the device is disconnected
1605 * and while disconnect and lock semaphores
1606 * are up. This should be save because we
1607 * can't lose our sisusb any other way but by
1608 * disconnection (and hence, the disconnect
1609 * sema is for protecting all other access
1610 * functions from disconnection, not the
1611 * other way round).
1612 */
1613
1614 /* Now what do we do in case of disconnection:
1615 * One alternative would be to simply call
1616 * give_up_console(). Nah, not a good idea.
1617 * give_up_console() is obviously buggy as it
1618 * only discards the consw pointer from the
1619 * driver_map, but doesn't adapt vc->vc_sw
1620 * of the affected consoles. Hence, the next
1621 * call to any of the console functions will
1622 * eventually take a trip to oops county.
1623 * Also, give_up_console for some reason
1624 * doesn't decrement our module refcount.
1625 * Instead, we switch our consoles to a private
1626 * dummy console. This, of course, keeps our
1627 * refcount up as well, but it works perfectly.
1628 */
1629
1630 if (sisusb->haveconsole) {
1631 for (i = 0; i < MAX_NR_CONSOLES; i++)
1632 if (sisusb->havethisconsole[i])
1633 take_over_console(&sisusb_dummy_con, i, i, 0);
1634 /* At this point, con_deinit for all our
1635 * consoles is executed by take_over_console().
1636 */
1637 sisusb->haveconsole = 0;
1638 }
1639
1640 vfree((void *)sisusb->scrbuf);
1641 sisusb->scrbuf = 0;
1642
1643 vfree(sisusb->font_backup);
1644 sisusb->font_backup = NULL;
1645}
1646
1647void __init sisusb_init_concode(void)
1648{
1649 int i;
1650
1651 for (i = 0; i < MAX_NR_CONSOLES; i++)
1652 mysisusbs[i] = NULL;
1653}
1654
1655#endif /* INCL_CON */
1656
1657
1658
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c
new file mode 100644
index 000000000000..f28bc240f9b6
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.c
@@ -0,0 +1,1047 @@
1/*
2 * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles
3 *
4 * Display mode initializing code
5 *
6 * Copyright (C) 2001-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 prior written permission.
23 * *
24 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 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/errno.h>
44#include <linux/poll.h>
45#include <linux/init.h>
46#include <linux/slab.h>
47#include <linux/spinlock.h>
48#include <linux/kref.h>
49
50#include "sisusb.h"
51
52#ifdef INCL_SISUSB_CON
53
54#include "sisusb_init.h"
55
56/*********************************************/
57/* POINTER INITIALIZATION */
58/*********************************************/
59
60static void
61SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
62{
63 SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
64 SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
65
66 SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
67 SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
68 SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
69 SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
70
71 SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
72}
73
74/*********************************************/
75/* HELPER: Get ModeID */
76/*********************************************/
77
78unsigned short
79SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
80{
81 unsigned short ModeIndex = 0;
82
83 switch (HDisplay)
84 {
85 case 320:
86 if (VDisplay == 200)
87 ModeIndex = ModeIndex_320x200[Depth];
88 else if (VDisplay == 240)
89 ModeIndex = ModeIndex_320x240[Depth];
90 break;
91 case 400:
92 if (VDisplay == 300)
93 ModeIndex = ModeIndex_400x300[Depth];
94 break;
95 case 512:
96 if (VDisplay == 384)
97 ModeIndex = ModeIndex_512x384[Depth];
98 break;
99 case 640:
100 if (VDisplay == 480)
101 ModeIndex = ModeIndex_640x480[Depth];
102 else if (VDisplay == 400)
103 ModeIndex = ModeIndex_640x400[Depth];
104 break;
105 case 720:
106 if (VDisplay == 480)
107 ModeIndex = ModeIndex_720x480[Depth];
108 else if (VDisplay == 576)
109 ModeIndex = ModeIndex_720x576[Depth];
110 break;
111 case 768:
112 if (VDisplay == 576)
113 ModeIndex = ModeIndex_768x576[Depth];
114 break;
115 case 800:
116 if (VDisplay == 600)
117 ModeIndex = ModeIndex_800x600[Depth];
118 else if (VDisplay == 480)
119 ModeIndex = ModeIndex_800x480[Depth];
120 break;
121 case 848:
122 if (VDisplay == 480)
123 ModeIndex = ModeIndex_848x480[Depth];
124 break;
125 case 856:
126 if (VDisplay == 480)
127 ModeIndex = ModeIndex_856x480[Depth];
128 break;
129 case 960:
130 if (VDisplay == 540)
131 ModeIndex = ModeIndex_960x540[Depth];
132 else if (VDisplay == 600)
133 ModeIndex = ModeIndex_960x600[Depth];
134 break;
135 case 1024:
136 if (VDisplay == 576)
137 ModeIndex = ModeIndex_1024x576[Depth];
138 else if (VDisplay == 768)
139 ModeIndex = ModeIndex_1024x768[Depth];
140 break;
141 case 1152:
142 if (VDisplay == 864)
143 ModeIndex = ModeIndex_1152x864[Depth];
144 break;
145 case 1280:
146 switch (VDisplay) {
147 case 720:
148 ModeIndex = ModeIndex_1280x720[Depth];
149 break;
150 case 768:
151 ModeIndex = ModeIndex_1280x768[Depth];
152 break;
153 case 1024:
154 ModeIndex = ModeIndex_1280x1024[Depth];
155 break;
156 }
157 }
158
159 return ModeIndex;
160}
161
162/*********************************************/
163/* HELPER: SetReg, GetReg */
164/*********************************************/
165
166static void
167SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
168 unsigned short index, unsigned short data)
169{
170 sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
171}
172
173static void
174SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
175 unsigned short data)
176{
177 sisusb_setreg(SiS_Pr->sisusb, port, data);
178}
179
180static unsigned char
181SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port,
182 unsigned short index)
183{
184 u8 data;
185
186 sisusb_getidxreg(SiS_Pr->sisusb, port, index, &data);
187
188 return data;
189}
190
191static unsigned char
192SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
193{
194 u8 data;
195
196 sisusb_getreg(SiS_Pr->sisusb, port, &data);
197
198 return data;
199}
200
201static void
202SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
203 unsigned short index, unsigned short DataAND,
204 unsigned short DataOR)
205{
206 sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
207}
208
209static void
210SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
211 unsigned short index, unsigned short DataAND)
212{
213 sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
214}
215
216static void
217SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
218 unsigned short index, unsigned short DataOR)
219{
220 sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
221}
222
223/*********************************************/
224/* HELPER: DisplayOn, DisplayOff */
225/*********************************************/
226
227static void
228SiS_DisplayOn(struct SiS_Private *SiS_Pr)
229{
230 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
231}
232
233/*********************************************/
234/* HELPER: Init Port Addresses */
235/*********************************************/
236
237void
238SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
239{
240 SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
241 SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
242 SiS_Pr->SiS_P3c0 = BaseAddr + 0x10;
243 SiS_Pr->SiS_P3ce = BaseAddr + 0x1e;
244 SiS_Pr->SiS_P3c2 = BaseAddr + 0x12;
245 SiS_Pr->SiS_P3ca = BaseAddr + 0x1a;
246 SiS_Pr->SiS_P3c6 = BaseAddr + 0x16;
247 SiS_Pr->SiS_P3c7 = BaseAddr + 0x17;
248 SiS_Pr->SiS_P3c8 = BaseAddr + 0x18;
249 SiS_Pr->SiS_P3c9 = BaseAddr + 0x19;
250 SiS_Pr->SiS_P3cb = BaseAddr + 0x1b;
251 SiS_Pr->SiS_P3cc = BaseAddr + 0x1c;
252 SiS_Pr->SiS_P3cd = BaseAddr + 0x1d;
253 SiS_Pr->SiS_P3da = BaseAddr + 0x2a;
254 SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04;
255}
256
257/*********************************************/
258/* HELPER: GetSysFlags */
259/*********************************************/
260
261static void
262SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
263{
264 SiS_Pr->SiS_MyCR63 = 0x63;
265}
266
267/*********************************************/
268/* HELPER: Init PCI & Engines */
269/*********************************************/
270
271static void
272SiSInitPCIetc(struct SiS_Private *SiS_Pr)
273{
274 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
275 /* - Enable 2D (0x40)
276 * - Enable 3D (0x02)
277 * - Enable 3D vertex command fetch (0x10)
278 * - Enable 3D command parser (0x08)
279 * - Enable 3D G/L transformation engine (0x80)
280 */
281 SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1E, 0xDA);
282}
283
284/*********************************************/
285/* HELPER: SET SEGMENT REGISTERS */
286/*********************************************/
287
288static void
289SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
290{
291 unsigned short temp;
292
293 value &= 0x00ff;
294 temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0xf0;
295 temp |= (value >> 4);
296 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp);
297 temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0xf0;
298 temp |= (value & 0x0f);
299 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
300}
301
302static void
303SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
304{
305 unsigned short temp;
306
307 value &= 0x00ff;
308 temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0x0f;
309 temp |= (value & 0xf0);
310 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp);
311 temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0x0f;
312 temp |= (value << 4);
313 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
314}
315
316static void
317SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
318{
319 SiS_SetSegRegLower(SiS_Pr, value);
320 SiS_SetSegRegUpper(SiS_Pr, value);
321}
322
323static void
324SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
325{
326 SiS_SetSegmentReg(SiS_Pr, 0);
327}
328
329static void
330SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
331{
332 unsigned short temp = value >> 8;
333
334 temp &= 0x07;
335 temp |= (temp << 4);
336 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1d, temp);
337 SiS_SetSegmentReg(SiS_Pr, value);
338}
339
340static void
341SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
342{
343 SiS_SetSegmentRegOver(SiS_Pr, 0);
344}
345
346static void
347SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
348{
349 SiS_ResetSegmentReg(SiS_Pr);
350 SiS_ResetSegmentRegOver(SiS_Pr);
351}
352
353/*********************************************/
354/* HELPER: SearchModeID */
355/*********************************************/
356
357static int
358SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
359 unsigned short *ModeIdIndex)
360{
361 if ((*ModeNo) <= 0x13) {
362
363 if ((*ModeNo) != 0x03)
364 return 0;
365
366 (*ModeIdIndex) = 0;
367
368 } else {
369
370 for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
371
372 if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
373 break;
374
375 if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
376 return 0;
377 }
378
379 }
380
381 return 1;
382}
383
384/*********************************************/
385/* HELPER: ENABLE CRT1 */
386/*********************************************/
387
388static void
389SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
390{
391 /* Enable CRT1 gating */
392 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
393}
394
395/*********************************************/
396/* HELPER: GetColorDepth */
397/*********************************************/
398
399static unsigned short
400SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
401 unsigned short ModeIdIndex)
402{
403 static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
404 unsigned short modeflag;
405 short index;
406
407 if (ModeNo <= 0x13) {
408 modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
409 } else {
410 modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
411 }
412
413 index = (modeflag & ModeTypeMask) - ModeEGA;
414 if (index < 0) index = 0;
415 return ColorDepth[index];
416}
417
418/*********************************************/
419/* HELPER: GetOffset */
420/*********************************************/
421
422static unsigned short
423SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
424 unsigned short ModeIdIndex, unsigned short rrti)
425{
426 unsigned short xres, temp, colordepth, infoflag;
427
428 infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
429 xres = SiS_Pr->SiS_RefIndex[rrti].XRes;
430
431 colordepth = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex);
432
433 temp = xres / 16;
434
435 if (infoflag & InterlaceMode)
436 temp <<= 1;
437
438 temp *= colordepth;
439
440 if (xres % 16)
441 temp += (colordepth >> 1);
442
443 return temp;
444}
445
446/*********************************************/
447/* SEQ */
448/*********************************************/
449
450static void
451SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
452{
453 unsigned char SRdata;
454 int i;
455
456 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x00, 0x03);
457
458 SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
459 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
460
461 for(i = 2; i <= 4; i++) {
462 SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
463 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
464 }
465}
466
467/*********************************************/
468/* MISC */
469/*********************************************/
470
471static void
472SiS_SetMiscRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
473{
474 unsigned char Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC;
475
476 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, Miscdata);
477}
478
479/*********************************************/
480/* CRTC */
481/*********************************************/
482
483static void
484SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
485{
486 unsigned char CRTCdata;
487 unsigned short i;
488
489 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
490
491 for(i = 0; i <= 0x18; i++) {
492 CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
493 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
494 }
495}
496
497/*********************************************/
498/* ATT */
499/*********************************************/
500
501static void
502SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
503{
504 unsigned char ARdata;
505 unsigned short i;
506
507 for(i = 0; i <= 0x13; i++) {
508 ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
509 SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
510 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
511 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, ARdata);
512 }
513 SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
514 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x14);
515 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x00);
516
517 SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
518 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x20);
519 SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
520}
521
522/*********************************************/
523/* GRC */
524/*********************************************/
525
526static void
527SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
528{
529 unsigned char GRdata;
530 unsigned short i;
531
532 for(i = 0; i <= 0x08; i++) {
533 GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
534 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
535 }
536
537 if (SiS_Pr->SiS_ModeType > ModeVGA) {
538 /* 256 color disable */
539 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3ce, 0x05, 0xBF);
540 }
541}
542
543/*********************************************/
544/* CLEAR EXTENDED REGISTERS */
545/*********************************************/
546
547static void
548SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
549{
550 int i;
551
552 for(i = 0x0A; i <= 0x0E; i++) {
553 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
554 }
555
556 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x37, 0xFE);
557}
558
559/*********************************************/
560/* Get rate index */
561/*********************************************/
562
563static unsigned short
564SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
565 unsigned short ModeIdIndex)
566{
567 unsigned short rrti, i, index, temp;
568
569 if (ModeNo <= 0x13)
570 return 0xFFFF;
571
572 index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
573 if (index > 0) index--;
574
575 rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
576 ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
577
578 i = 0;
579 do {
580 if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
581 break;
582
583 temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
584 if (temp < SiS_Pr->SiS_ModeType)
585 break;
586
587 i++;
588 index--;
589 } while(index != 0xFFFF);
590
591 i--;
592
593 return (rrti + i);
594}
595
596/*********************************************/
597/* SYNC */
598/*********************************************/
599
600static void
601SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
602{
603 unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
604 sync &= 0xC0;
605 sync |= 0x2f;
606 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, sync);
607}
608
609/*********************************************/
610/* CRTC/2 */
611/*********************************************/
612
613static void
614SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
615 unsigned short ModeIdIndex, unsigned short rrti)
616{
617 unsigned char index;
618 unsigned short temp, i, j, modeflag;
619
620 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f);
621
622 modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
623
624 index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
625
626 for(i = 0,j = 0; i <= 7; i++, j++) {
627 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
628 SiS_Pr->SiS_CRT1Table[index].CR[i]);
629 }
630 for(j = 0x10; i <= 10; i++, j++) {
631 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
632 SiS_Pr->SiS_CRT1Table[index].CR[i]);
633 }
634 for(j = 0x15; i <= 12; i++, j++) {
635 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
636 SiS_Pr->SiS_CRT1Table[index].CR[i]);
637 }
638 for(j = 0x0A; i <= 15; i++, j++) {
639 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
640 SiS_Pr->SiS_CRT1Table[index].CR[i]);
641 }
642
643 temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
644 SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp);
645
646 temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
647 if (modeflag & DoubleScanMode) temp |= 0x80;
648 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
649
650 if (SiS_Pr->SiS_ModeType > ModeVGA)
651 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x14, 0x4F);
652}
653
654/*********************************************/
655/* OFFSET & PITCH */
656/*********************************************/
657/* (partly overruled by SetPitch() in XF86) */
658/*********************************************/
659
660static void
661SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
662 unsigned short ModeIdIndex, unsigned short rrti)
663{
664 unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
665 unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
666 unsigned short temp;
667
668 temp = (du >> 8) & 0x0f;
669 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, 0xF0, temp);
670
671 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
672
673 if (infoflag & InterlaceMode) du >>= 1;
674
675 du <<= 5;
676 temp = (du >> 8) & 0xff;
677 if (du & 0xff) temp++;
678 temp++;
679 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
680}
681
682/*********************************************/
683/* VCLK */
684/*********************************************/
685
686static void
687SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
688 unsigned short rrti)
689{
690 unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
691 unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
692 unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
693
694 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF);
695
696 SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka);
697 SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb);
698 SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01);
699}
700
701/*********************************************/
702/* FIFO */
703/*********************************************/
704
705static void
706SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
707 unsigned short mi)
708{
709 unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
710
711 /* disable auto-threshold */
712 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0xFE);
713
714 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0xAE);
715 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x09, 0xF0);
716
717 if (ModeNo <= 0x13)
718 return;
719
720 if ((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
721 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0x34);
722 SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0x01);
723 }
724}
725
726/*********************************************/
727/* MODE REGISTERS */
728/*********************************************/
729
730static void
731SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
732 unsigned short rrti)
733{
734 unsigned short data = 0, VCLK = 0, index = 0;
735
736 if (ModeNo > 0x13) {
737 index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
738 VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
739 }
740
741 if (VCLK >= 166) data |= 0x0c;
742 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
743
744 if (VCLK >= 166)
745 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1f, 0xe7);
746
747 /* DAC speed */
748 data = 0x03;
749 if (VCLK >= 260)
750 data = 0x00;
751 else if (VCLK >= 160)
752 data = 0x01;
753 else if (VCLK >= 135)
754 data = 0x02;
755
756 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x07, 0xF8, data);
757}
758
759static void
760SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
761 unsigned short ModeIdIndex, unsigned short rrti)
762{
763 unsigned short data, infoflag = 0, modeflag;
764
765 if (ModeNo <= 0x13)
766 modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
767 else {
768 modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
769 infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
770 }
771
772 /* Disable DPMS */
773 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1F, 0x3F);
774
775 data = 0;
776 if (ModeNo > 0x13) {
777 if (SiS_Pr->SiS_ModeType > ModeEGA) {
778 data |= 0x02;
779 data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
780 }
781 if (infoflag & InterlaceMode) data |= 0x20;
782 }
783 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
784
785 data = 0;
786 if (infoflag & InterlaceMode) {
787 /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
788 unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
789 ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3;
790 unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
791 ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5;
792 data = hrs - (hto >> 1) + 3;
793 }
794 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
795 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x1a, 0xFC, (data >> 8));
796
797 if (modeflag & HalfDCLK)
798 SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0x08);
799
800 data = 0;
801 if (modeflag & LineCompareOff)
802 data = 0x08;
803 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0xB7, data);
804
805 if ((SiS_Pr->SiS_ModeType == ModeEGA) && (ModeNo > 0x13))
806 SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0x40);
807
808 SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xfb);
809
810 data = 0x60;
811 if (SiS_Pr->SiS_ModeType != ModeText) {
812 data ^= 0x60;
813 if (SiS_Pr->SiS_ModeType != ModeEGA)
814 data ^= 0xA0;
815 }
816 SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x21, 0x1F, data);
817
818 SiS_SetVCLKState(SiS_Pr, ModeNo, rrti);
819
820 if (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x31) & 0x40)
821 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x2c);
822 else
823 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x6c);
824}
825
826/*********************************************/
827/* LOAD DAC */
828/*********************************************/
829
830static void
831SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
832 unsigned short shiftflag, unsigned short dl, unsigned short ah,
833 unsigned short al, unsigned short dh)
834{
835 unsigned short d1, d2, d3;
836
837 switch (dl) {
838 case 0:
839 d1 = dh; d2 = ah; d3 = al;
840 break;
841 case 1:
842 d1 = ah; d2 = al; d3 = dh;
843 break;
844 default:
845 d1 = al; d2 = dh; d3 = ah;
846 }
847 SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
848 SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
849 SiS_SetRegByte(SiS_Pr, DACData, (d3 << shiftflag));
850}
851
852static void
853SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi)
854{
855 unsigned short data, data2, time, i, j, k, m, n, o;
856 unsigned short si, di, bx, sf;
857 unsigned long DACAddr, DACData;
858 const unsigned char *table = NULL;
859
860 if (ModeNo < 0x13)
861 data = SiS_Pr->SiS_SModeIDTable[mi].St_ModeFlag;
862 else
863 data = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
864
865 data &= DACInfoFlag;
866
867 j = time = 64;
868 if (data == 0x00)
869 table = SiS_MDA_DAC;
870 else if (data == 0x08)
871 table = SiS_CGA_DAC;
872 else if (data == 0x10)
873 table = SiS_EGA_DAC;
874 else {
875 j = 16;
876 time = 256;
877 table = SiS_VGA_DAC;
878 }
879
880 DACAddr = SiS_Pr->SiS_P3c8;
881 DACData = SiS_Pr->SiS_P3c9;
882 sf = 0;
883 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF);
884
885 SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
886
887 for(i = 0; i < j; i++) {
888 data = table[i];
889 for(k = 0; k < 3; k++) {
890 data2 = 0;
891 if (data & 0x01) data2 += 0x2A;
892 if (data & 0x02) data2 += 0x15;
893 SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
894 data >>= 2;
895 }
896 }
897
898 if (time == 256) {
899 for(i = 16; i < 32; i++) {
900 data = table[i] << sf;
901 for(k = 0; k < 3; k++)
902 SiS_SetRegByte(SiS_Pr, DACData, data);
903 }
904 si = 32;
905 for(m = 0; m < 9; m++) {
906 di = si;
907 bx = si + 4;
908 for(n = 0; n < 3; n++) {
909 for(o = 0; o < 5; o++) {
910 SiS_WriteDAC(SiS_Pr, DACData, sf, n,
911 table[di], table[bx], table[si]);
912 si++;
913 }
914 si -= 2;
915 for(o = 0; o < 3; o++) {
916 SiS_WriteDAC(SiS_Pr, DACData, sf, n,
917 table[di], table[si], table[bx]);
918 si--;
919 }
920 }
921 si += 5;
922 }
923 }
924}
925
926/*********************************************/
927/* SET CRT1 REGISTER GROUP */
928/*********************************************/
929
930static void
931SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
932 unsigned short ModeIdIndex)
933{
934 unsigned short StandTableIndex, rrti;
935
936 SiS_Pr->SiS_CRT1Mode = ModeNo;
937
938 if (ModeNo <= 0x13)
939 StandTableIndex = 0;
940 else
941 StandTableIndex = 1;
942
943 SiS_ResetSegmentRegisters(SiS_Pr);
944 SiS_SetSeqRegs(SiS_Pr, StandTableIndex);
945 SiS_SetMiscRegs(SiS_Pr, StandTableIndex);
946 SiS_SetCRTCRegs(SiS_Pr, StandTableIndex);
947 SiS_SetATTRegs(SiS_Pr, StandTableIndex);
948 SiS_SetGRCRegs(SiS_Pr, StandTableIndex);
949 SiS_ClearExt1Regs(SiS_Pr, ModeNo);
950
951 rrti = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex);
952
953 if (rrti != 0xFFFF) {
954 SiS_SetCRT1Sync(SiS_Pr, rrti);
955 SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, rrti);
956 SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
957 SiS_SetCRT1VCLK(SiS_Pr, ModeNo, rrti);
958 }
959
960 SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex);
961
962 SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, rrti);
963
964 SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex);
965
966 SiS_DisplayOn(SiS_Pr);
967}
968
969/*********************************************/
970/* SiSSetMode() */
971/*********************************************/
972
973int
974SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
975{
976 unsigned short ModeIdIndex;
977 unsigned long BaseAddr = SiS_Pr->IOAddress;
978
979 SiSUSB_InitPtr(SiS_Pr);
980 SiSUSBRegInit(SiS_Pr, BaseAddr);
981 SiS_GetSysFlags(SiS_Pr);
982
983 if (!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex)))
984 return 0;
985
986 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x05, 0x86);
987
988 SiSInitPCIetc(SiS_Pr);
989
990 ModeNo &= 0x7f;
991
992 SiS_Pr->SiS_ModeType =
993 SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
994
995 SiS_Pr->SiS_SetFlag = LowModeTests;
996
997 /* Set mode on CRT1 */
998 SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex);
999
1000 SiS_HandleCRT1(SiS_Pr);
1001
1002 SiS_DisplayOn(SiS_Pr);
1003 SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF);
1004
1005 /* Store mode number */
1006 SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x34, ModeNo);
1007
1008 return 1;
1009}
1010
1011int
1012SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
1013{
1014 unsigned short ModeNo = 0;
1015 int i;
1016
1017 SiSUSB_InitPtr(SiS_Pr);
1018
1019 if (VModeNo == 0x03) {
1020
1021 ModeNo = 0x03;
1022
1023 } else {
1024
1025 i = 0;
1026 do {
1027
1028 if (SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID == VModeNo) {
1029 ModeNo = SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID;
1030 break;
1031 }
1032
1033 } while (SiS_Pr->SiS_EModeIDTable[i++].Ext_ModeID != 0xff);
1034
1035 }
1036
1037 if (!ModeNo)
1038 return 0;
1039
1040 return SiSUSBSetMode(SiS_Pr, ModeNo);
1041}
1042
1043#endif /* INCL_SISUSB_CON */
1044
1045
1046
1047
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h
new file mode 100644
index 000000000000..5b11577835c8
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.h
@@ -0,0 +1,830 @@
1/* $XFree86$ */
2/* $XdotOrg$ */
3/*
4 * Data and prototypes for init.c
5 *
6 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
7 *
8 * If distributed as part of the Linux kernel, the following license terms
9 * apply:
10 *
11 * * This program is free software; you can redistribute it and/or modify
12 * * it under the terms of the GNU General Public License as published by
13 * * the Free Software Foundation; either version 2 of the named License,
14 * * or any later version.
15 * *
16 * * This program is distributed in the hope that it will be useful,
17 * * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * * GNU General Public License for more details.
20 * *
21 * * You should have received a copy of the GNU General Public License
22 * * along with this program; if not, write to the Free Software
23 * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
24 *
25 * Otherwise, the following license terms apply:
26 *
27 * * Redistribution and use in source and binary forms, with or without
28 * * modification, are permitted provided that the following conditions
29 * * are met:
30 * * 1) Redistributions of source code must retain the above copyright
31 * * notice, this list of conditions and the following disclaimer.
32 * * 2) Redistributions in binary form must reproduce the above copyright
33 * * notice, this list of conditions and the following disclaimer in the
34 * * documentation and/or other materials provided with the distribution.
35 * * 3) The name of the author may not be used to endorse or promote products
36 * * derived from this software without specific prior written permission.
37 * *
38 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
39 * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40 * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
41 * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
42 * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43 * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45 * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
47 * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 *
49 * Author: Thomas Winischhofer <thomas@winischhofer.net>
50 *
51 */
52
53#ifndef _SISUSB_INIT_H_
54#define _SISUSB_INIT_H_
55
56/* SiS_ModeType */
57#define ModeText 0x00
58#define ModeCGA 0x01
59#define ModeEGA 0x02
60#define ModeVGA 0x03
61#define Mode15Bpp 0x04
62#define Mode16Bpp 0x05
63#define Mode24Bpp 0x06
64#define Mode32Bpp 0x07
65
66#define ModeTypeMask 0x07
67#define IsTextMode 0x07
68
69#define DACInfoFlag 0x0018
70#define MemoryInfoFlag 0x01E0
71#define MemorySizeShift 5
72
73/* modeflag */
74#define Charx8Dot 0x0200
75#define LineCompareOff 0x0400
76#define CRT2Mode 0x0800
77#define HalfDCLK 0x1000
78#define NoSupportSimuTV 0x2000
79#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
80#define DoubleScanMode 0x8000
81
82/* Infoflag */
83#define SupportTV 0x0008
84#define SupportTV1024 0x0800
85#define SupportCHTV 0x0800
86#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */
87#define SupportHiVision 0x0010
88#define SupportYPbPr750p 0x1000
89#define SupportLCD 0x0020
90#define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */
91#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */
92#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */
93#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */
94#define InterlaceMode 0x0080
95#define SyncPP 0x0000
96#define SyncPN 0x4000
97#define SyncNP 0x8000
98#define SyncNN 0xc000
99
100/* SetFlag */
101#define ProgrammingCRT2 0x0001
102#define LowModeTests 0x0002
103#define LCDVESATiming 0x0008
104#define EnableLVDSDDA 0x0010
105#define SetDispDevSwitchFlag 0x0020
106#define CheckWinDos 0x0040
107#define SetDOSMode 0x0080
108
109/* Index in ModeResInfo table */
110#define SIS_RI_320x200 0
111#define SIS_RI_320x240 1
112#define SIS_RI_320x400 2
113#define SIS_RI_400x300 3
114#define SIS_RI_512x384 4
115#define SIS_RI_640x400 5
116#define SIS_RI_640x480 6
117#define SIS_RI_800x600 7
118#define SIS_RI_1024x768 8
119#define SIS_RI_1280x1024 9
120#define SIS_RI_1600x1200 10
121#define SIS_RI_1920x1440 11
122#define SIS_RI_2048x1536 12
123#define SIS_RI_720x480 13
124#define SIS_RI_720x576 14
125#define SIS_RI_1280x960 15
126#define SIS_RI_800x480 16
127#define SIS_RI_1024x576 17
128#define SIS_RI_1280x720 18
129#define SIS_RI_856x480 19
130#define SIS_RI_1280x768 20
131#define SIS_RI_1400x1050 21
132#define SIS_RI_1152x864 22 /* Up to here SiS conforming */
133#define SIS_RI_848x480 23
134#define SIS_RI_1360x768 24
135#define SIS_RI_1024x600 25
136#define SIS_RI_1152x768 26
137#define SIS_RI_768x576 27
138#define SIS_RI_1360x1024 28
139#define SIS_RI_1680x1050 29
140#define SIS_RI_1280x800 30
141#define SIS_RI_1920x1080 31
142#define SIS_RI_960x540 32
143#define SIS_RI_960x600 33
144
145#define SIS_VIDEO_CAPTURE 0x00 - 0x30
146#define SIS_VIDEO_PLAYBACK 0x02 - 0x30
147#define SIS_CRT2_PORT_04 0x04 - 0x30
148
149/* Mode numbers */
150static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f};
151static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53};
152static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54};
153static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c};
154static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e};
155static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62};
156static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35};
157static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36};
158static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61};
159static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76};
160static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63};
161static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e};
162static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45};
163static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f};
164static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22};
165static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64};
166static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77};
167static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b};
168static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78};
169static const unsigned short ModeIndex_1280x768[] = {0x23, 0x24, 0x00, 0x25};
170static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65};
171
172static const unsigned char SiS_MDA_DAC[] =
173{
174 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
175 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
176 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
177 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
178 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
179 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
180 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
181 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
182};
183
184static const unsigned char SiS_CGA_DAC[] =
185{
186 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
187 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
188 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
189 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
190 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
191 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
192 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
193 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
194};
195
196static const unsigned char SiS_EGA_DAC[] =
197{
198 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
199 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
200 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
201 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
202 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
203 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
204 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
205 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
206};
207
208static const unsigned char SiS_VGA_DAC[] =
209{
210 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
211 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
212 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
213 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
214 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
215 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
216 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
217 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
218 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
219 0x0B,0x0C,0x0D,0x0F,0x10
220};
221
222static const struct SiS_St SiSUSB_SModeIDTable[] =
223{
224 {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40},
225 {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
226};
227
228static const struct SiS_StResInfo_S SiSUSB_StResInfo[] =
229{
230 { 640,400},
231 { 640,350},
232 { 720,400},
233 { 720,350},
234 { 640,480}
235};
236
237static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] =
238{
239 { 320, 200, 8, 8}, /* 0x00 */
240 { 320, 240, 8, 8}, /* 0x01 */
241 { 320, 400, 8, 8}, /* 0x02 */
242 { 400, 300, 8, 8}, /* 0x03 */
243 { 512, 384, 8, 8}, /* 0x04 */
244 { 640, 400, 8,16}, /* 0x05 */
245 { 640, 480, 8,16}, /* 0x06 */
246 { 800, 600, 8,16}, /* 0x07 */
247 { 1024, 768, 8,16}, /* 0x08 */
248 { 1280,1024, 8,16}, /* 0x09 */
249 { 1600,1200, 8,16}, /* 0x0a */
250 { 1920,1440, 8,16}, /* 0x0b */
251 { 2048,1536, 8,16}, /* 0x0c */
252 { 720, 480, 8,16}, /* 0x0d */
253 { 720, 576, 8,16}, /* 0x0e */
254 { 1280, 960, 8,16}, /* 0x0f */
255 { 800, 480, 8,16}, /* 0x10 */
256 { 1024, 576, 8,16}, /* 0x11 */
257 { 1280, 720, 8,16}, /* 0x12 */
258 { 856, 480, 8,16}, /* 0x13 */
259 { 1280, 768, 8,16}, /* 0x14 */
260 { 1400,1050, 8,16}, /* 0x15 */
261 { 1152, 864, 8,16}, /* 0x16 */
262 { 848, 480, 8,16}, /* 0x17 */
263 { 1360, 768, 8,16}, /* 0x18 */
264 { 1024, 600, 8,16}, /* 0x19 */
265 { 1152, 768, 8,16}, /* 0x1a */
266 { 768, 576, 8,16}, /* 0x1b */
267 { 1360,1024, 8,16}, /* 0x1c */
268 { 1680,1050, 8,16}, /* 0x1d */
269 { 1280, 800, 8,16}, /* 0x1e */
270 { 1920,1080, 8,16}, /* 0x1f */
271 { 960, 540, 8,16}, /* 0x20 */
272 { 960, 600, 8,16} /* 0x21 */
273};
274
275static const struct SiS_StandTable SiSUSB_StandTable[] =
276{
277 /* MD_3_400 - mode 0x03 - 400 */
278 {
279 0x50,0x18,0x10,0x1000,
280 { 0x00,0x03,0x00,0x02 },
281 0x67,
282 { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
283 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
284 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
285 0xff },
286 { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
287 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
288 0x0c,0x00,0x0f,0x08 },
289 { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff }
290 },
291 /* Generic for VGA and higher */
292 {
293 0x00,0x00,0x00,0x0000,
294 { 0x01,0x0f,0x00,0x0e },
295 0x23,
296 { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
297 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
298 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
299 0xff },
300 { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
301 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
302 0x01,0x00,0x00,0x00 },
303 { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff }
304 }
305};
306
307static const struct SiS_Ext SiSUSB_EModeIDTable[] =
308{
309 {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */
310 {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */
311 {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */
312 {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */
313 {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */
314 {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */
315 {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */
316 {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */
317 {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */
318 {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */
319 {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */
320 {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */
321 {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */
322 {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */
323 {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */
324 {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */
325 {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8 */
326 {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8 */
327 {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8 */
328 {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */
329 {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */
330 {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */
331 {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8 */
332 {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */
333 {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */
334 {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */
335 {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */
336 {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */
337 {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */
338 {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */
339 {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */
340 {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */
341 {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */
342 {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */
343 {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */
344 {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */
345 {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */
346 {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */
347 {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */
348 {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */
349 {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */
350 {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */
351 {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */
352 {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1},
353 {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1},
354 {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */
355 {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1},
356 {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1},
357 {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */
358 {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */
359 {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */
360 {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */
361 {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1},
362 {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1},
363 {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */
364 {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1},
365 {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1},
366 {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */
367 {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1},
368 {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1},
369 {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */
370 {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
371 {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
372 {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1}
373};
374
375static const struct SiS_Ext2 SiSUSB_RefIndex[] =
376{
377 {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
378 {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
379 {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
380 {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
381 {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
382 {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
383 {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
384 {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
385 {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
386 {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
387 {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
388 {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
389 {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
390 {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
391 {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
392 {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
393 {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
394 {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
395 {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
396 {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
397 {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
398 {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
399 {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
400 {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
401 {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
402 {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
403 {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
404 {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
405 {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
406 {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
407 {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
408 {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
409 {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
410 {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
411 {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
412 {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
413 {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
414 {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
415 {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
416 {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
417 {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */
418 {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */
419 {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */
420 {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */
421 {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */
422 {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
423 {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
424 {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */
425 {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */
426 {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */
427 {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */
428 {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */
429 {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */
430 {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */
431 {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00}
432};
433
434static const struct SiS_CRT1Table SiSUSB_CRT1Table[] =
435{
436 {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
437 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
438 0x00}}, /* 0x0 */
439 {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
440 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
441 0x00}}, /* 0x1 */
442 {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
443 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
444 0x01}}, /* 0x2 */
445 {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
446 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
447 0x01}}, /* 0x3 */
448 {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
449 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
450 0x00}}, /* 0x4 */
451 {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
452 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
453 0x00}}, /* 0x5 */
454 {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e,
455 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01,
456 0x00}}, /* 0x6 */
457 {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
458 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
459 0x00}}, /* 0x7 */
460 {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
461 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
462 0x00}}, /* 0x8 */
463 {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
464 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
465 0x61}}, /* 0x9 */
466 {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
467 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
468 0x61}}, /* 0xa */
469 {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
470 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,
471 0x61}}, /* 0xb */
472 {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
473 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,
474 0x00}}, /* 0xc */
475 {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
476 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
477 0x01}}, /* 0xd */
478 {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
479 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
480 0x01}}, /* 0xe */
481 {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
482 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
483 0x01}}, /* 0xf */
484 {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
485 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
486 0x01}}, /* 0x10 */
487 {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
488 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
489 0x01}}, /* 0x11 */
490 {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
491 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
492 0x61}}, /* 0x12 */
493 {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
494 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
495 0x61}}, /* 0x13 */
496 {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
497 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
498 0x61}}, /* 0x14 */
499 {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
500 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
501 0x00}}, /* 0x15 */
502 {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
503 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
504 0x01}}, /* 0x16 */
505 {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
506 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
507 0x01}}, /* 0x17 */
508 {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
509 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
510 0x01}}, /* 0x18 */
511 {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
512 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
513 0x01}}, /* 0x19 */
514 {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
515 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
516 0x62}}, /* 0x1a */
517 {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
518 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
519 0x62}}, /* 0x1b */
520 {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
521 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
522 0x00}}, /* 0x1c */
523 {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
524 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
525 0x01}}, /* 0x1d */
526 {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
527 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
528 0x01}}, /* 0x1e */
529 {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
530 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
531 0x01}}, /* 0x1f */
532 {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
533 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
534 0x00}}, /* 0x20 */
535 {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
536 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
537 0x00}}, /* 0x21 */
538 {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
539 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
540 0x00}}, /* 0x22 */
541 {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
542 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
543 0x00}}, /* 0x23 */
544 {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
545 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
546 0x00}}, /* 0x24 */
547 {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
548 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
549 0x00}}, /* 0x25 */
550 {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
551 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
552 0x00}}, /* 0x26 */
553 {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
554 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
555 0x00}}, /* 0x27 */
556 {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
557 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
558 0x63}}, /* 0x28 */
559 {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
560 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
561 0x63}}, /* 0x29 */
562 {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
563 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
564 0x00}}, /* 0x2a */
565 {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
566 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
567 0x00}}, /* 0x2b */
568 {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
569 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
570 0x00}}, /* 0x2c */
571 {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
572 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
573 0x44}}, /* 0x2d */
574 {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
575 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
576 0x44}}, /* 0x2e */
577 {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
578 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
579 0x44}}, /* 0x2f */
580 {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
581 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
582 0x44}}, /* 0x30 */
583 {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
584 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
585 0x00}}, /* 0x31 */
586 {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
587 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
588 0x01}}, /* 0x32 */
589 {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
590 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
591 0x01}}, /* 0x33 */
592 {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
593 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
594 0x01}}, /* 0x34 */
595 {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
596 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
597 0x01}}, /* 0x35 */
598 {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
599 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
600 0x01}}, /* 0x36 */
601 {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,
602 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
603 0x01}}, /* 0x37 */
604 {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
605 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
606 0x01}}, /* 0x38 */
607 {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
608 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
609 0x01}}, /* 0x39 */
610 {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
611 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
612 0x01}}, /* 0x3a */
613 {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff,
614 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07,
615 0x01}}, /* 0x3b */
616 {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
617 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
618 0x00}}, /* 0x3c */
619 {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0,
620 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
621 0x41}}, /* 0x3d */
622 {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
623 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
624 0x00}}, /* 0x3e */
625 {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
626 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
627 0x00}}, /* 0x3f */
628 {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
629 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
630 0x01}}, /* 0x40 */
631 {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
632 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
633 0x01}}, /* 0x41 */
634 {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
635 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
636 0x01}}, /* 0x42 */
637 {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
638 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
639 0x00}}, /* 0x43 */
640 {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,
641 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
642 0x01}}, /* 0x44 */
643 {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,
644 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
645 0x00}}, /* 0x45 */
646 {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,
647 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
648 0x00}}, /* 0x46 */
649 {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,
650 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
651 0x00}}, /* 0x47 */
652 {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,
653 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
654 0x00}}, /* 0x48 */
655 {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,
656 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
657 0x01}}, /* 0x49 */
658 {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,
659 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
660 0x01}}, /* 0x4a */
661 {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10,
662 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03,
663 0x00}}, /* 0x4b */
664 {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,
665 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
666 0x01}}, /* 0x4c */
667 {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0,
668 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
669 0x41}},
670 {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
671 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
672 0x00}}, /* 0x4e */
673 {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff,
674 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07,
675 0x21}}, /* 0x4f */
676 {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10,
677 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c,
678 0x20}}, /* 0x50 */
679 {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0,
680 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00,
681 0x61}}, /* 0x51 */
682 {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0,
683 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02,
684 0x41}}, /* 0x52 */
685 {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0,
686 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02,
687 0x01}}, /* 0x53 */
688 {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff,
689 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07,
690 0x41}} /* 0x54 */
691};
692
693static struct SiS_VCLKData SiSUSB_VCLKData[] =
694{
695 { 0x1b,0xe1, 25}, /* 0x00 */
696 { 0x4e,0xe4, 28}, /* 0x01 */
697 { 0x57,0xe4, 31}, /* 0x02 */
698 { 0xc3,0xc8, 36}, /* 0x03 */
699 { 0x42,0xe2, 40}, /* 0x04 */
700 { 0xfe,0xcd, 43}, /* 0x05 */
701 { 0x5d,0xc4, 44}, /* 0x06 */
702 { 0x52,0xe2, 49}, /* 0x07 */
703 { 0x53,0xe2, 50}, /* 0x08 */
704 { 0x74,0x67, 52}, /* 0x09 */
705 { 0x6d,0x66, 56}, /* 0x0a */
706 { 0x5a,0x64, 65}, /* 0x0b */
707 { 0x46,0x44, 67}, /* 0x0c */
708 { 0xb1,0x46, 68}, /* 0x0d */
709 { 0xd3,0x4a, 72}, /* 0x0e */
710 { 0x29,0x61, 75}, /* 0x0f */
711 { 0x6e,0x46, 76}, /* 0x10 */
712 { 0x2b,0x61, 78}, /* 0x11 */
713 { 0x31,0x42, 79}, /* 0x12 */
714 { 0xab,0x44, 83}, /* 0x13 */
715 { 0x46,0x25, 84}, /* 0x14 */
716 { 0x78,0x29, 86}, /* 0x15 */
717 { 0x62,0x44, 94}, /* 0x16 */
718 { 0x2b,0x41,104}, /* 0x17 */
719 { 0x3a,0x23,105}, /* 0x18 */
720 { 0x70,0x44,108}, /* 0x19 */
721 { 0x3c,0x23,109}, /* 0x1a */
722 { 0x5e,0x43,113}, /* 0x1b */
723 { 0xbc,0x44,116}, /* 0x1c */
724 { 0xe0,0x46,132}, /* 0x1d */
725 { 0x54,0x42,135}, /* 0x1e */
726 { 0xea,0x2a,139}, /* 0x1f */
727 { 0x41,0x22,157}, /* 0x20 */
728 { 0x70,0x24,162}, /* 0x21 */
729 { 0x30,0x21,175}, /* 0x22 */
730 { 0x4e,0x22,189}, /* 0x23 */
731 { 0xde,0x26,194}, /* 0x24 */
732 { 0x62,0x06,202}, /* 0x25 */
733 { 0x3f,0x03,229}, /* 0x26 */
734 { 0xb8,0x06,234}, /* 0x27 */
735 { 0x34,0x02,253}, /* 0x28 */
736 { 0x58,0x04,255}, /* 0x29 */
737 { 0x24,0x01,265}, /* 0x2a */
738 { 0x9b,0x02,267}, /* 0x2b */
739 { 0x70,0x05,270}, /* 0x2c */
740 { 0x25,0x01,272}, /* 0x2d */
741 { 0x9c,0x02,277}, /* 0x2e */
742 { 0x27,0x01,286}, /* 0x2f */
743 { 0x3c,0x02,291}, /* 0x30 */
744 { 0xef,0x0a,292}, /* 0x31 */
745 { 0xf6,0x0a,310}, /* 0x32 */
746 { 0x95,0x01,315}, /* 0x33 */
747 { 0xf0,0x09,324}, /* 0x34 */
748 { 0xfe,0x0a,331}, /* 0x35 */
749 { 0xf3,0x09,332}, /* 0x36 */
750 { 0xea,0x08,340}, /* 0x37 */
751 { 0xe8,0x07,376}, /* 0x38 */
752 { 0xde,0x06,389}, /* 0x39 */
753 { 0x52,0x2a, 54}, /* 0x3a 301 TV */
754 { 0x52,0x6a, 27}, /* 0x3b 301 TV */
755 { 0x62,0x24, 70}, /* 0x3c 301 TV */
756 { 0x62,0x64, 70}, /* 0x3d 301 TV */
757 { 0xa8,0x4c, 30}, /* 0x3e 301 TV */
758 { 0x20,0x26, 33}, /* 0x3f 301 TV */
759 { 0x31,0xc2, 39}, /* 0x40 */
760 { 0x60,0x36, 30}, /* 0x41 Chrontel */
761 { 0x40,0x4a, 28}, /* 0x42 Chrontel */
762 { 0x9f,0x46, 44}, /* 0x43 Chrontel */
763 { 0x97,0x2c, 26}, /* 0x44 */
764 { 0x44,0xe4, 25}, /* 0x45 Chrontel */
765 { 0x7e,0x32, 47}, /* 0x46 Chrontel */
766 { 0x8a,0x24, 31}, /* 0x47 Chrontel */
767 { 0x97,0x2c, 26}, /* 0x48 Chrontel */
768 { 0xce,0x3c, 39}, /* 0x49 */
769 { 0x52,0x4a, 36}, /* 0x4a Chrontel */
770 { 0x34,0x61, 95}, /* 0x4b */
771 { 0x78,0x27,108}, /* 0x4c - was 102 */
772 { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
773 { 0x41,0x4e, 21}, /* 0x4e */
774 { 0xa1,0x4a, 29}, /* 0x4f Chrontel */
775 { 0x19,0x42, 42}, /* 0x50 */
776 { 0x54,0x46, 58}, /* 0x51 Chrontel */
777 { 0x25,0x42, 61}, /* 0x52 */
778 { 0x44,0x44, 66}, /* 0x53 Chrontel */
779 { 0x3a,0x62, 70}, /* 0x54 Chrontel */
780 { 0x62,0xc6, 34}, /* 0x55 848x480-60 */
781 { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */
782 { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */
783 { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
784 { 0x52,0x07,149}, /* 0x59 1280x960-85 */
785 { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
786 { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
787 { 0x45,0x25, 83}, /* 0x5c 1280x800 */
788 { 0x70,0x0a,147}, /* 0x5d 1680x1050 */
789 { 0x70,0x24,162}, /* 0x5e 1600x1200 */
790 { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */
791 { 0x63,0x46, 68}, /* 0x60 1280x768_2 */
792 { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
793 { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */
794 { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
795 { 0x70,0x28, 90}, /* 0x64 1152x864@60 */
796 { 0x41,0xc4, 32}, /* 0x65 848x480@60 */
797 { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
798 { 0x76,0xe7, 27}, /* 0x67 720x480@60 */
799 { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
800 { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
801 { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */
802 { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */
803 { 0x45,0x25, 83}, /* 0x6c 1280x800 */
804 { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */
805 { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
806 { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */
807 { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
808 { 0x2b,0xc2, 35} /* 0x71 768@576@60 */
809};
810
811void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr);
812unsigned short SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth);
813int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
814int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
815
816extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
817extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
818extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
819 u8 index, u8 data);
820extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
821 u8 index, u8 *data);
822extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
823 u8 idx, u8 myand, u8 myor);
824extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
825 u8 index, u8 myor);
826extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
827 u8 idx, u8 myand);
828
829#endif
830
diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h
new file mode 100644
index 000000000000..94edd4726c42
--- /dev/null
+++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h
@@ -0,0 +1,169 @@
1/*
2 * General structure definitions for universal mode switching modules
3 *
4 * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
5 *
6 * If distributed as part of the Linux kernel, the following license terms
7 * apply:
8 *
9 * * This program is free software; you can redistribute it and/or modify
10 * * it under the terms of the GNU General Public License as published by
11 * * the Free Software Foundation; either version 2 of the named License,
12 * * or any later version.
13 * *
14 * * This program is distributed in the hope that it will be useful,
15 * * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * * GNU General Public License for more details.
18 * *
19 * * You should have received a copy of the GNU General Public License
20 * * along with this program; if not, write to the Free Software
21 * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
22 *
23 * Otherwise, the following license terms apply:
24 *
25 * * Redistribution and use in source and binary forms, with or without
26 * * modification, are permitted provided that the following conditions
27 * * are met:
28 * * 1) Redistributions of source code must retain the above copyright
29 * * notice, this list of conditions and the following disclaimer.
30 * * 2) Redistributions in binary form must reproduce the above copyright
31 * * notice, this list of conditions and the following disclaimer in the
32 * * documentation and/or other materials provided with the distribution.
33 * * 3) The name of the author may not be used to endorse or promote products
34 * * derived from this software without specific prior written permission.
35 * *
36 * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
37 * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
39 * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
40 * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41 * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
45 * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 *
47 * Author: Thomas Winischhofer <thomas@winischhofer.net>
48 *
49 */
50
51#ifndef _SISUSB_STRUCT_H_
52#define _SISUSB_STRUCT_H_
53
54struct SiS_St {
55 unsigned char St_ModeID;
56 unsigned short St_ModeFlag;
57 unsigned char St_StTableIndex;
58 unsigned char St_CRT2CRTC;
59 unsigned char St_ResInfo;
60 unsigned char VB_StTVFlickerIndex;
61 unsigned char VB_StTVEdgeIndex;
62 unsigned char VB_StTVYFilterIndex;
63 unsigned char St_PDC;
64};
65
66struct SiS_StandTable
67{
68 unsigned char CRT_COLS;
69 unsigned char ROWS;
70 unsigned char CHAR_HEIGHT;
71 unsigned short CRT_LEN;
72 unsigned char SR[4];
73 unsigned char MISC;
74 unsigned char CRTC[0x19];
75 unsigned char ATTR[0x14];
76 unsigned char GRC[9];
77};
78
79struct SiS_StResInfo_S {
80 unsigned short HTotal;
81 unsigned short VTotal;
82};
83
84struct SiS_Ext
85{
86 unsigned char Ext_ModeID;
87 unsigned short Ext_ModeFlag;
88 unsigned short Ext_VESAID;
89 unsigned char Ext_RESINFO;
90 unsigned char VB_ExtTVFlickerIndex;
91 unsigned char VB_ExtTVEdgeIndex;
92 unsigned char VB_ExtTVYFilterIndex;
93 unsigned char VB_ExtTVYFilterIndexROM661;
94 unsigned char REFindex;
95 char ROMMODEIDX661;
96};
97
98struct SiS_Ext2
99{
100 unsigned short Ext_InfoFlag;
101 unsigned char Ext_CRT1CRTC;
102 unsigned char Ext_CRTVCLK;
103 unsigned char Ext_CRT2CRTC;
104 unsigned char Ext_CRT2CRTC_NS;
105 unsigned char ModeID;
106 unsigned short XRes;
107 unsigned short YRes;
108 unsigned char Ext_PDC;
109 unsigned char Ext_FakeCRT2CRTC;
110 unsigned char Ext_FakeCRT2Clk;
111};
112
113struct SiS_CRT1Table
114{
115 unsigned char CR[17];
116};
117
118struct SiS_VCLKData
119{
120 unsigned char SR2B,SR2C;
121 unsigned short CLOCK;
122};
123
124struct SiS_ModeResInfo
125{
126 unsigned short HTotal;
127 unsigned short VTotal;
128 unsigned char XChar;
129 unsigned char YChar;
130};
131
132struct SiS_Private
133{
134 void *sisusb;
135
136 unsigned long IOAddress;
137
138 unsigned long SiS_P3c4;
139 unsigned long SiS_P3d4;
140 unsigned long SiS_P3c0;
141 unsigned long SiS_P3ce;
142 unsigned long SiS_P3c2;
143 unsigned long SiS_P3ca;
144 unsigned long SiS_P3c6;
145 unsigned long SiS_P3c7;
146 unsigned long SiS_P3c8;
147 unsigned long SiS_P3c9;
148 unsigned long SiS_P3cb;
149 unsigned long SiS_P3cc;
150 unsigned long SiS_P3cd;
151 unsigned long SiS_P3da;
152 unsigned long SiS_Part1Port;
153
154 unsigned char SiS_MyCR63;
155 unsigned short SiS_CRT1Mode;
156 unsigned short SiS_ModeType;
157 unsigned short SiS_SetFlag;
158
159 const struct SiS_StandTable *SiS_StandTable;
160 const struct SiS_St *SiS_SModeIDTable;
161 const struct SiS_Ext *SiS_EModeIDTable;
162 const struct SiS_Ext2 *SiS_RefIndex;
163 const struct SiS_CRT1Table *SiS_CRT1Table;
164 struct SiS_VCLKData *SiS_VCLKData;
165 const struct SiS_ModeResInfo *SiS_ModeResInfo;
166};
167
168#endif
169
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index faa74436de52..03fb70ef2eb3 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -3,8 +3,8 @@
3/* 3/*
4 * uss720.c -- USS720 USB Parport Cable. 4 * uss720.c -- USS720 USB Parport Cable.
5 * 5 *
6 * Copyright (C) 1999 6 * Copyright (C) 1999, 2005
7 * Thomas Sailer (sailer@ife.ee.ethz.ch) 7 * Thomas Sailer (t.sailer@alumni.ethz.ch)
8 * 8 *
9 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
@@ -23,103 +23,240 @@
23 * Based on parport_pc.c 23 * Based on parport_pc.c
24 * 24 *
25 * History: 25 * History:
26 * 0.1 04.08.99 Created 26 * 0.1 04.08.1999 Created
27 * 0.2 07.08.99 Some fixes mainly suggested by Tim Waugh 27 * 0.2 07.08.1999 Some fixes mainly suggested by Tim Waugh
28 * Interrupt handling currently disabled because 28 * Interrupt handling currently disabled because
29 * usb_request_irq crashes somewhere within ohci.c 29 * usb_request_irq crashes somewhere within ohci.c
30 * for no apparent reason (that is for me, anyway) 30 * for no apparent reason (that is for me, anyway)
31 * ECP currently untested 31 * ECP currently untested
32 * 0.3 10.08.99 fixing merge errors 32 * 0.3 10.08.1999 fixing merge errors
33 * 0.4 13.08.99 Added Vendor/Product ID of Brad Hard's cable 33 * 0.4 13.08.1999 Added Vendor/Product ID of Brad Hard's cable
34 * 0.5 20.09.99 usb_control_msg wrapper used 34 * 0.5 20.09.1999 usb_control_msg wrapper used
35 * Nov01.00 usb_device_table support by Adam J. Richter 35 * Nov01.2000 usb_device_table support by Adam J. Richter
36 * 08.04.01 Identify version on module load. gb 36 * 08.04.2001 Identify version on module load. gb
37 * 0.6 02.09.2005 Fix "scheduling in interrupt" problem by making save/restore
38 * context asynchronous
37 * 39 *
38 */ 40 */
39 41
40/*****************************************************************************/ 42/*****************************************************************************/
41 43
44#define DEBUG
45
42#include <linux/module.h> 46#include <linux/module.h>
43#include <linux/socket.h> 47#include <linux/socket.h>
44#include <linux/parport.h> 48#include <linux/parport.h>
45#include <linux/init.h> 49#include <linux/init.h>
46#include <linux/usb.h> 50#include <linux/usb.h>
47#include <linux/delay.h> 51#include <linux/delay.h>
52#include <linux/completion.h>
53#include <linux/kref.h>
48 54
49/* 55/*
50 * Version Information 56 * Version Information
51 */ 57 */
52#define DRIVER_VERSION "v0.5" 58#define DRIVER_VERSION "v0.6"
53#define DRIVER_AUTHOR "Thomas M. Sailer, sailer@ife.ee.ethz.ch" 59#define DRIVER_AUTHOR "Thomas M. Sailer, t.sailer@alumni.ethz.ch"
54#define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip" 60#define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip"
55 61
56/* --------------------------------------------------------------------- */ 62/* --------------------------------------------------------------------- */
57 63
58struct parport_uss720_private { 64struct parport_uss720_private {
59 struct usb_device *usbdev; 65 struct usb_device *usbdev;
60 void *irqhandle; 66 struct parport *pp;
61 unsigned int irqpipe; 67 struct kref ref_count;
62 unsigned char reg[7]; /* USB registers */ 68 __u8 reg[7]; /* USB registers */
69 struct list_head asynclist;
70 spinlock_t asynclock;
71};
72
73struct uss720_async_request {
74 struct parport_uss720_private *priv;
75 struct kref ref_count;
76 struct list_head asynclist;
77 struct completion compl;
78 struct urb *urb;
79 struct usb_ctrlrequest dr;
80 __u8 reg[7];
63}; 81};
64 82
65/* --------------------------------------------------------------------- */ 83/* --------------------------------------------------------------------- */
66 84
67static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val) 85static void destroy_priv(struct kref *kref)
68{ 86{
69 struct parport_uss720_private *priv = pp->private_data; 87 struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count);
70 struct usb_device *usbdev = priv->usbdev;
71 static const unsigned char regindex[9] = {
72 4, 0, 1, 5, 5, 0, 2, 3, 6
73 };
74 int ret;
75 88
76 if (!usbdev) 89 usb_put_dev(priv->usbdev);
77 return -1; 90 kfree(priv);
78 ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, 1000); 91 dbg("destroying priv datastructure");
79 if (ret != 7) { 92}
80 printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x expected 7\n", 93
81 (unsigned int)reg, ret); 94static void destroy_async(struct kref *kref)
82 ret = -1; 95{
83 } else { 96 struct uss720_async_request *rq = container_of(kref, struct uss720_async_request, ref_count);
97 struct parport_uss720_private *priv = rq->priv;
98 unsigned long flags;
99
100 if (likely(rq->urb))
101 usb_free_urb(rq->urb);
102 spin_lock_irqsave(&priv->asynclock, flags);
103 list_del_init(&rq->asynclist);
104 spin_unlock_irqrestore(&priv->asynclock, flags);
105 kfree(rq);
106 kref_put(&priv->ref_count, destroy_priv);
107}
108
109/* --------------------------------------------------------------------- */
110
111static void async_complete(struct urb *urb, struct pt_regs *ptregs)
112{
113 struct uss720_async_request *rq;
114 struct parport *pp;
115 struct parport_uss720_private *priv;
116
117 rq = urb->context;
118 priv = rq->priv;
119 pp = priv->pp;
120 if (urb->status) {
121 err("async_complete: urb error %d", urb->status);
122 } else if (rq->dr.bRequest == 3) {
123 memcpy(priv->reg, rq->reg, sizeof(priv->reg));
84#if 0 124#if 0
85 printk(KERN_DEBUG "uss720: get_1284_register(%d) return %02x %02x %02x %02x %02x %02x %02x\n", 125 dbg("async_complete regs %02x %02x %02x %02x %02x %02x %02x",
86 (unsigned int)reg, (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], 126 (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], (unsigned int)priv->reg[2],
87 (unsigned int)priv->reg[2], (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], 127 (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], (unsigned int)priv->reg[5],
88 (unsigned int)priv->reg[5], (unsigned int)priv->reg[6]); 128 (unsigned int)priv->reg[6]);
89#endif 129#endif
90 /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */ 130 /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
91 if (priv->reg[2] & priv->reg[1] & 0x10) 131 if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
92 parport_generic_irq(0, pp, NULL); 132 parport_generic_irq(0, pp, NULL);
93 ret = 0;
94 } 133 }
95 if (val) 134 complete(&rq->compl);
96 *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]]; 135 kref_put(&rq->ref_count, destroy_async);
97 return ret;
98} 136}
99 137
100static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val) 138static struct uss720_async_request *submit_async_request(struct parport_uss720_private *priv,
139 __u8 request, __u8 requesttype, __u16 value, __u16 index,
140 unsigned int mem_flags)
101{ 141{
102 struct parport_uss720_private *priv = pp->private_data; 142 struct usb_device *usbdev;
103 struct usb_device *usbdev = priv->usbdev; 143 struct uss720_async_request *rq;
144 unsigned long flags;
104 int ret; 145 int ret;
105 146
147 if (!priv)
148 return NULL;
149 usbdev = priv->usbdev;
106 if (!usbdev) 150 if (!usbdev)
107 return -1; 151 return NULL;
108 ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, 1000); 152 rq = kmalloc(sizeof(struct uss720_async_request), mem_flags);
109 if (ret) { 153 if (!rq) {
110 printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n", 154 err("submit_async_request out of memory");
111 (unsigned int)reg, (unsigned int)val, ret); 155 return NULL;
112 } else { 156 }
113#if 0 157 kref_init(&rq->ref_count);
114 printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x)\n", 158 INIT_LIST_HEAD(&rq->asynclist);
115 (unsigned int)reg, (unsigned int)val); 159 init_completion(&rq->compl);
116#endif 160 kref_get(&priv->ref_count);
161 rq->priv = priv;
162 rq->urb = usb_alloc_urb(0, mem_flags);
163 if (!rq->urb) {
164 kref_put(&rq->ref_count, destroy_async);
165 err("submit_async_request out of memory");
166 return NULL;
167 }
168 rq->dr.bRequestType = requesttype;
169 rq->dr.bRequest = request;
170 rq->dr.wValue = cpu_to_le16(value);
171 rq->dr.wIndex = cpu_to_le16(index);
172 rq->dr.wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0);
173 usb_fill_control_urb(rq->urb, usbdev, (requesttype & 0x80) ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0),
174 (unsigned char *)&rq->dr,
175 (request == 3) ? rq->reg : NULL, (request == 3) ? sizeof(rq->reg) : 0, async_complete, rq);
176 /* rq->urb->transfer_flags |= URB_ASYNC_UNLINK; */
177 spin_lock_irqsave(&priv->asynclock, flags);
178 list_add_tail(&rq->asynclist, &priv->asynclist);
179 spin_unlock_irqrestore(&priv->asynclock, flags);
180 ret = usb_submit_urb(rq->urb, mem_flags);
181 if (!ret) {
182 kref_get(&rq->ref_count);
183 return rq;
117 } 184 }
185 kref_put(&rq->ref_count, destroy_async);
186 err("submit_async_request submit_urb failed with %d", ret);
187 return NULL;
188}
189
190static unsigned int kill_all_async_requests_priv(struct parport_uss720_private *priv)
191{
192 struct uss720_async_request *rq;
193 unsigned long flags;
194 unsigned int ret = 0;
195
196 spin_lock_irqsave(&priv->asynclock, flags);
197 list_for_each_entry(rq, &priv->asynclist, asynclist) {
198 usb_unlink_urb(rq->urb);
199 ret++;
200 }
201 spin_unlock_irqrestore(&priv->asynclock, flags);
118 return ret; 202 return ret;
119} 203}
120 204
121/* --------------------------------------------------------------------- */ 205/* --------------------------------------------------------------------- */
122 206
207static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, unsigned int mem_flags)
208{
209 struct parport_uss720_private *priv;
210 struct uss720_async_request *rq;
211 static const unsigned char regindex[9] = {
212 4, 0, 1, 5, 5, 0, 2, 3, 6
213 };
214 int ret;
215
216 if (!pp)
217 return -EIO;
218 priv = pp->private_data;
219 rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags);
220 if (!rq) {
221 err("get_1284_register(%u) failed", (unsigned int)reg);
222 return -EIO;
223 }
224 if (!val) {
225 kref_put(&rq->ref_count, destroy_async);
226 return 0;
227 }
228 if (wait_for_completion_timeout(&rq->compl, HZ)) {
229 ret = rq->urb->status;
230 *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];
231 if (ret)
232 warn("get_1284_register: usb error %d", ret);
233 kref_put(&rq->ref_count, destroy_async);
234 return ret;
235 }
236 warn("get_1284_register timeout");
237 kill_all_async_requests_priv(priv);
238 return -EIO;
239}
240
241static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, unsigned int mem_flags)
242{
243 struct parport_uss720_private *priv;
244 struct uss720_async_request *rq;
245
246 if (!pp)
247 return -EIO;
248 priv = pp->private_data;
249 rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags);
250 if (!rq) {
251 err("set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val);
252 return -EIO;
253 }
254 kref_put(&rq->ref_count, destroy_async);
255 return 0;
256}
257
258/* --------------------------------------------------------------------- */
259
123/* ECR modes */ 260/* ECR modes */
124#define ECR_SPP 00 261#define ECR_SPP 00
125#define ECR_PS2 01 262#define ECR_PS2 01
@@ -132,8 +269,9 @@ static int change_mode(struct parport *pp, int m)
132{ 269{
133 struct parport_uss720_private *priv = pp->private_data; 270 struct parport_uss720_private *priv = pp->private_data;
134 int mode; 271 int mode;
272 __u8 reg;
135 273
136 if (get_1284_register(pp, 6, NULL)) 274 if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
137 return -EIO; 275 return -EIO;
138 /* Bits <7:5> contain the mode. */ 276 /* Bits <7:5> contain the mode. */
139 mode = (priv->reg[2] >> 5) & 0x7; 277 mode = (priv->reg[2] >> 5) & 0x7;
@@ -153,7 +291,7 @@ static int change_mode(struct parport *pp, int m)
153 case ECR_ECP: /* ECP Parallel Port mode */ 291 case ECR_ECP: /* ECP Parallel Port mode */
154 /* Poll slowly. */ 292 /* Poll slowly. */
155 for (;;) { 293 for (;;) {
156 if (get_1284_register(pp, 6, NULL)) 294 if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
157 return -EIO; 295 return -EIO;
158 if (priv->reg[2] & 0x01) 296 if (priv->reg[2] & 0x01)
159 break; 297 break;
@@ -167,7 +305,9 @@ static int change_mode(struct parport *pp, int m)
167 } 305 }
168 } 306 }
169 /* Set the mode. */ 307 /* Set the mode. */
170 if (set_1284_register(pp, 6, m << 5)) 308 if (set_1284_register(pp, 6, m << 5, GFP_KERNEL))
309 return -EIO;
310 if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
171 return -EIO; 311 return -EIO;
172 return 0; 312 return 0;
173} 313}
@@ -179,7 +319,7 @@ static int clear_epp_timeout(struct parport *pp)
179{ 319{
180 unsigned char stat; 320 unsigned char stat;
181 321
182 if (get_1284_register(pp, 1, &stat)) 322 if (get_1284_register(pp, 1, &stat, GFP_KERNEL))
183 return 1; 323 return 1;
184 return stat & 1; 324 return stat & 1;
185} 325}
@@ -205,14 +345,14 @@ static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id)
205 345
206static void parport_uss720_write_data(struct parport *pp, unsigned char d) 346static void parport_uss720_write_data(struct parport *pp, unsigned char d)
207{ 347{
208 set_1284_register(pp, 0, d); 348 set_1284_register(pp, 0, d, GFP_KERNEL);
209} 349}
210 350
211static unsigned char parport_uss720_read_data(struct parport *pp) 351static unsigned char parport_uss720_read_data(struct parport *pp)
212{ 352{
213 unsigned char ret; 353 unsigned char ret;
214 354
215 if (get_1284_register(pp, 0, &ret)) 355 if (get_1284_register(pp, 0, &ret, GFP_KERNEL))
216 return 0; 356 return 0;
217 return ret; 357 return ret;
218} 358}
@@ -222,7 +362,7 @@ static void parport_uss720_write_control(struct parport *pp, unsigned char d)
222 struct parport_uss720_private *priv = pp->private_data; 362 struct parport_uss720_private *priv = pp->private_data;
223 363
224 d = (d & 0xf) | (priv->reg[1] & 0xf0); 364 d = (d & 0xf) | (priv->reg[1] & 0xf0);
225 if (set_1284_register(pp, 2, d)) 365 if (set_1284_register(pp, 2, d, GFP_KERNEL))
226 return; 366 return;
227 priv->reg[1] = d; 367 priv->reg[1] = d;
228} 368}
@@ -241,7 +381,7 @@ static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned ch
241 mask &= 0x0f; 381 mask &= 0x0f;
242 val &= 0x0f; 382 val &= 0x0f;
243 d = (priv->reg[1] & (~mask)) ^ val; 383 d = (priv->reg[1] & (~mask)) ^ val;
244 if (set_1284_register(pp, 2, d)) 384 if (set_1284_register(pp, 2, d, GFP_KERNEL))
245 return 0; 385 return 0;
246 priv->reg[1] = d; 386 priv->reg[1] = d;
247 return d & 0xf; 387 return d & 0xf;
@@ -251,7 +391,7 @@ static unsigned char parport_uss720_read_status(struct parport *pp)
251{ 391{
252 unsigned char ret; 392 unsigned char ret;
253 393
254 if (get_1284_register(pp, 1, &ret)) 394 if (get_1284_register(pp, 1, &ret, GFP_KERNEL))
255 return 0; 395 return 0;
256 return ret & 0xf8; 396 return ret & 0xf8;
257} 397}
@@ -262,7 +402,7 @@ static void parport_uss720_disable_irq(struct parport *pp)
262 unsigned char d; 402 unsigned char d;
263 403
264 d = priv->reg[1] & ~0x10; 404 d = priv->reg[1] & ~0x10;
265 if (set_1284_register(pp, 2, d)) 405 if (set_1284_register(pp, 2, d, GFP_KERNEL))
266 return; 406 return;
267 priv->reg[1] = d; 407 priv->reg[1] = d;
268} 408}
@@ -273,7 +413,7 @@ static void parport_uss720_enable_irq(struct parport *pp)
273 unsigned char d; 413 unsigned char d;
274 414
275 d = priv->reg[1] | 0x10; 415 d = priv->reg[1] | 0x10;
276 if (set_1284_register(pp, 2, d)) 416 if (set_1284_register(pp, 2, d, GFP_KERNEL))
277 return; 417 return;
278 priv->reg[1] = d; 418 priv->reg[1] = d;
279} 419}
@@ -284,7 +424,7 @@ static void parport_uss720_data_forward (struct parport *pp)
284 unsigned char d; 424 unsigned char d;
285 425
286 d = priv->reg[1] & ~0x20; 426 d = priv->reg[1] & ~0x20;
287 if (set_1284_register(pp, 2, d)) 427 if (set_1284_register(pp, 2, d, GFP_KERNEL))
288 return; 428 return;
289 priv->reg[1] = d; 429 priv->reg[1] = d;
290} 430}
@@ -295,7 +435,7 @@ static void parport_uss720_data_reverse (struct parport *pp)
295 unsigned char d; 435 unsigned char d;
296 436
297 d = priv->reg[1] | 0x20; 437 d = priv->reg[1] | 0x20;
298 if (set_1284_register(pp, 2, d)) 438 if (set_1284_register(pp, 2, d, GFP_KERNEL))
299 return; 439 return;
300 priv->reg[1] = d; 440 priv->reg[1] = d;
301} 441}
@@ -310,17 +450,23 @@ static void parport_uss720_save_state(struct parport *pp, struct parport_state *
310{ 450{
311 struct parport_uss720_private *priv = pp->private_data; 451 struct parport_uss720_private *priv = pp->private_data;
312 452
313 if (get_1284_register(pp, 2, NULL)) 453#if 0
454 if (get_1284_register(pp, 2, NULL, GFP_ATOMIC))
314 return; 455 return;
456#endif
315 s->u.pc.ctr = priv->reg[1]; 457 s->u.pc.ctr = priv->reg[1];
316 s->u.pc.ecr = priv->reg[2]; 458 s->u.pc.ecr = priv->reg[2];
317} 459}
318 460
319static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s) 461static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s)
320{ 462{
321 set_1284_register(pp, 2, s->u.pc.ctr); 463 struct parport_uss720_private *priv = pp->private_data;
322 set_1284_register(pp, 6, s->u.pc.ecr); 464
323 get_1284_register(pp, 2, NULL); 465 set_1284_register(pp, 2, s->u.pc.ctr, GFP_ATOMIC);
466 set_1284_register(pp, 6, s->u.pc.ecr, GFP_ATOMIC);
467 get_1284_register(pp, 2, NULL, GFP_ATOMIC);
468 priv->reg[1] = s->u.pc.ctr;
469 priv->reg[2] = s->u.pc.ecr;
324} 470}
325 471
326static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags) 472static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags)
@@ -331,7 +477,7 @@ static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t
331 if (change_mode(pp, ECR_EPP)) 477 if (change_mode(pp, ECR_EPP))
332 return 0; 478 return 0;
333 for (; got < length; got++) { 479 for (; got < length; got++) {
334 if (get_1284_register(pp, 4, (char *)buf)) 480 if (get_1284_register(pp, 4, (char *)buf, GFP_KERNEL))
335 break; 481 break;
336 buf++; 482 buf++;
337 if (priv->reg[0] & 0x01) { 483 if (priv->reg[0] & 0x01) {
@@ -352,10 +498,10 @@ static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf,
352 if (change_mode(pp, ECR_EPP)) 498 if (change_mode(pp, ECR_EPP))
353 return 0; 499 return 0;
354 for (; written < length; written++) { 500 for (; written < length; written++) {
355 if (set_1284_register(pp, 4, (char *)buf)) 501 if (set_1284_register(pp, 4, (char *)buf, GFP_KERNEL))
356 break; 502 break;
357 ((char*)buf)++; 503 ((char*)buf)++;
358 if (get_1284_register(pp, 1, NULL)) 504 if (get_1284_register(pp, 1, NULL, GFP_KERNEL))
359 break; 505 break;
360 if (priv->reg[0] & 0x01) { 506 if (priv->reg[0] & 0x01) {
361 clear_epp_timeout(pp); 507 clear_epp_timeout(pp);
@@ -390,7 +536,7 @@ static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t
390 if (change_mode(pp, ECR_EPP)) 536 if (change_mode(pp, ECR_EPP))
391 return 0; 537 return 0;
392 for (; got < length; got++) { 538 for (; got < length; got++) {
393 if (get_1284_register(pp, 3, (char *)buf)) 539 if (get_1284_register(pp, 3, (char *)buf, GFP_KERNEL))
394 break; 540 break;
395 buf++; 541 buf++;
396 if (priv->reg[0] & 0x01) { 542 if (priv->reg[0] & 0x01) {
@@ -410,10 +556,10 @@ static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf,
410 if (change_mode(pp, ECR_EPP)) 556 if (change_mode(pp, ECR_EPP))
411 return 0; 557 return 0;
412 for (; written < length; written++) { 558 for (; written < length; written++) {
413 if (set_1284_register(pp, 3, *(char *)buf)) 559 if (set_1284_register(pp, 3, *(char *)buf, GFP_KERNEL))
414 break; 560 break;
415 buf++; 561 buf++;
416 if (get_1284_register(pp, 1, NULL)) 562 if (get_1284_register(pp, 1, NULL, GFP_KERNEL))
417 break; 563 break;
418 if (priv->reg[0] & 0x01) { 564 if (priv->reg[0] & 0x01) {
419 clear_epp_timeout(pp); 565 clear_epp_timeout(pp);
@@ -467,7 +613,7 @@ static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buff
467 if (change_mode(pp, ECR_ECP)) 613 if (change_mode(pp, ECR_ECP))
468 return 0; 614 return 0;
469 for (; written < len; written++) { 615 for (; written < len; written++) {
470 if (set_1284_register(pp, 5, *(char *)buffer)) 616 if (set_1284_register(pp, 5, *(char *)buffer, GFP_KERNEL))
471 break; 617 break;
472 buffer++; 618 buffer++;
473 } 619 }
@@ -536,93 +682,91 @@ static struct parport_operations parport_uss720_ops =
536static int uss720_probe(struct usb_interface *intf, 682static int uss720_probe(struct usb_interface *intf,
537 const struct usb_device_id *id) 683 const struct usb_device_id *id)
538{ 684{
539 struct usb_device *usbdev = interface_to_usbdev(intf); 685 struct usb_device *usbdev = usb_get_dev(interface_to_usbdev(intf));
540 struct usb_host_interface *interface; 686 struct usb_host_interface *interface;
541 struct usb_host_endpoint *endpoint; 687 struct usb_host_endpoint *endpoint;
542 struct parport_uss720_private *priv; 688 struct parport_uss720_private *priv;
543 struct parport *pp; 689 struct parport *pp;
690 unsigned char reg;
544 int i; 691 int i;
545 692
546 printk(KERN_DEBUG "uss720: probe: vendor id 0x%x, device id 0x%x\n", 693 dbg("probe: vendor id 0x%x, device id 0x%x\n",
547 le16_to_cpu(usbdev->descriptor.idVendor), 694 le16_to_cpu(usbdev->descriptor.idVendor),
548 le16_to_cpu(usbdev->descriptor.idProduct)); 695 le16_to_cpu(usbdev->descriptor.idProduct));
549 696
550 /* our known interfaces have 3 alternate settings */ 697 /* our known interfaces have 3 alternate settings */
551 if (intf->num_altsetting != 3) 698 if (intf->num_altsetting != 3) {
699 usb_put_dev(usbdev);
552 return -ENODEV; 700 return -ENODEV;
553 701 }
554 i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2); 702 i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
555 printk(KERN_DEBUG "uss720: set inteface result %d\n", i); 703 dbg("set inteface result %d", i);
556 704
557 interface = intf->cur_altsetting; 705 interface = intf->cur_altsetting;
558 706
559 /* 707 /*
560 * Allocate parport interface 708 * Allocate parport interface
561 */ 709 */
562 printk(KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n"); 710 if (!(priv = kcalloc(sizeof(struct parport_uss720_private), 1, GFP_KERNEL))) {
563 711 usb_put_dev(usbdev);
564 if (!(priv = kmalloc(sizeof(struct parport_uss720_private), GFP_KERNEL)))
565 return -ENOMEM; 712 return -ENOMEM;
713 }
714 priv->pp = NULL;
715 priv->usbdev = usbdev;
716 kref_init(&priv->ref_count);
717 spin_lock_init(&priv->asynclock);
718 INIT_LIST_HEAD(&priv->asynclist);
566 if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) { 719 if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) {
567 printk(KERN_WARNING "usb-uss720: could not register parport\n"); 720 warn("could not register parport");
568 goto probe_abort; 721 goto probe_abort;
569 } 722 }
570 723
724 priv->pp = pp;
571 pp->private_data = priv; 725 pp->private_data = priv;
572 priv->usbdev = usbdev;
573 pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT; 726 pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
574 727
575 /* set the USS720 control register to manual mode, no ECP compression, enable all ints */ 728 /* set the USS720 control register to manual mode, no ECP compression, enable all ints */
576 set_1284_register(pp, 7, 0x00); 729 set_1284_register(pp, 7, 0x00, GFP_KERNEL);
577 set_1284_register(pp, 6, 0x30); /* PS/2 mode */ 730 set_1284_register(pp, 6, 0x30, GFP_KERNEL); /* PS/2 mode */
578 set_1284_register(pp, 2, 0x0c); 731 set_1284_register(pp, 2, 0x0c, GFP_KERNEL);
579 /* debugging */ 732 /* debugging */
580 get_1284_register(pp, 0, NULL); 733 get_1284_register(pp, 0, &reg, GFP_KERNEL);
581 printk("uss720: reg: %02x %02x %02x %02x %02x %02x %02x\n", 734 dbg("reg: %02x %02x %02x %02x %02x %02x %02x",
582 priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]); 735 priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
583 736
584 endpoint = &interface->endpoint[2]; 737 endpoint = &interface->endpoint[2];
585 printk(KERN_DEBUG "uss720: epaddr %d interval %d\n", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval); 738 dbg("epaddr %d interval %d", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
586#if 0
587 priv->irqpipe = usb_rcvctrlpipe(usbdev, endpoint->bEndpointAddress);
588 i = usb_request_irq(usbdev, priv->irqpipe,
589 uss720_irq, endpoint->bInterval,
590 pp, &priv->irqhandle);
591 if (i) {
592 printk (KERN_WARNING "usb-uss720: usb_request_irq failed (0x%x)\n", i);
593 goto probe_abort_port;
594 }
595#endif
596 parport_announce_port(pp); 739 parport_announce_port(pp);
597 740
598 usb_set_intfdata (intf, pp); 741 usb_set_intfdata(intf, pp);
599 return 0; 742 return 0;
600 743
601#if 0
602probe_abort_port:
603 parport_put_port(pp);
604#endif
605probe_abort: 744probe_abort:
606 kfree(priv); 745 kill_all_async_requests_priv(priv);
746 kref_put(&priv->ref_count, destroy_priv);
607 return -ENODEV; 747 return -ENODEV;
608} 748}
609 749
610static void uss720_disconnect(struct usb_interface *intf) 750static void uss720_disconnect(struct usb_interface *intf)
611{ 751{
612 struct parport *pp = usb_get_intfdata (intf); 752 struct parport *pp = usb_get_intfdata(intf);
613 struct parport_uss720_private *priv; 753 struct parport_uss720_private *priv;
754 struct usb_device *usbdev;
614 755
615 usb_set_intfdata (intf, NULL); 756 dbg("disconnect");
757 usb_set_intfdata(intf, NULL);
616 if (pp) { 758 if (pp) {
617 priv = pp->private_data; 759 priv = pp->private_data;
618 parport_remove_port(pp); 760 usbdev = priv->usbdev;
619#if 0
620 usb_release_irq(usbdev, priv->irqhandle, priv->irqpipe);
621#endif
622 priv->usbdev = NULL; 761 priv->usbdev = NULL;
762 priv->pp = NULL;
763 dbg("parport_remove_port");
764 parport_remove_port(pp);
623 parport_put_port(pp); 765 parport_put_port(pp);
624 kfree(priv); 766 kill_all_async_requests_priv(priv);
767 kref_put(&priv->ref_count, destroy_priv);
625 } 768 }
769 dbg("disconnect done");
626} 770}
627 771
628/* table of cables that work through this driver */ 772/* table of cables that work through this driver */
@@ -647,8 +791,8 @@ static struct usb_driver uss720_driver = {
647 791
648/* --------------------------------------------------------------------- */ 792/* --------------------------------------------------------------------- */
649 793
650MODULE_AUTHOR( DRIVER_AUTHOR ); 794MODULE_AUTHOR(DRIVER_AUTHOR);
651MODULE_DESCRIPTION( DRIVER_DESC ); 795MODULE_DESCRIPTION(DRIVER_DESC);
652MODULE_LICENSE("GPL"); 796MODULE_LICENSE("GPL");
653 797
654static int __init uss720_init(void) 798static int __init uss720_init(void)
@@ -659,6 +803,9 @@ static int __init uss720_init(void)
659 goto out; 803 goto out;
660 804
661 info(DRIVER_VERSION ":" DRIVER_DESC); 805 info(DRIVER_VERSION ":" DRIVER_DESC);
806 info("NOTE: this is a special purpose driver to allow nonstandard");
807 info("protocols (eg. bitbang) over USS720 usb to parallel cables");
808 info("If you just want to connect to a printer, use usblp instead");
662out: 809out:
663 return retval; 810 return retval;
664} 811}
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 417464dea9f6..17d0190ef64e 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -79,7 +79,7 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
79 return '-'; 79 return '-';
80 80
81 if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP) 81 if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
82 return 'D'; 82 return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
83 if (urb->setup_packet == NULL) 83 if (urb->setup_packet == NULL)
84 return 'Z'; /* '0' would be not as pretty. */ 84 return 'Z'; /* '0' would be not as pretty. */
85 85
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 4ace9964fc6b..97c78c21e8d1 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -32,7 +32,7 @@
32/* 32/*
33 * Version Information 33 * Version Information
34 */ 34 */
35#define DRIVER_VERSION "v0.04" 35#define DRIVER_VERSION "v0.05"
36#define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver" 36#define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
37 37
38/* 38/*
@@ -54,8 +54,11 @@ static void cp2101_shutdown(struct usb_serial*);
54static int debug; 54static int debug;
55 55
56static struct usb_device_id id_table [] = { 56static struct usb_device_id id_table [] = {
57 { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
57 { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ 58 { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
58 { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ 59 { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
60 { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
61 { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
59 { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ 62 { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
60 { } /* Terminating Entry */ 63 { } /* Terminating Entry */
61}; 64};
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 05c44ae3ed32..9ee1aaff2fcd 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -610,8 +610,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
610 timeout = max((HZ*2560)/bps,HZ/10); 610 timeout = max((HZ*2560)/bps,HZ/10);
611 else 611 else
612 timeout = 2*HZ; 612 timeout = 2*HZ;
613 set_current_state(TASK_INTERRUPTIBLE); 613 schedule_timeout_interruptible(timeout);
614 schedule_timeout(timeout);
615 614
616 dbg("%s - stopping urbs", __FUNCTION__); 615 dbg("%s - stopping urbs", __FUNCTION__);
617 usb_kill_urb (port->interrupt_in_urb); 616 usb_kill_urb (port->interrupt_in_urb);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 0a6e8b474b1f..4e434cb10bb1 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -914,7 +914,7 @@ static void ftdi_determine_type(struct usb_serial_port *port)
914 unsigned interfaces; 914 unsigned interfaces;
915 915
916 /* Assume it is not the original SIO device for now. */ 916 /* Assume it is not the original SIO device for now. */
917 priv->baud_base = 48000000 / 16; 917 priv->baud_base = 48000000 / 2;
918 priv->write_offset = 0; 918 priv->write_offset = 0;
919 919
920 version = le16_to_cpu(udev->descriptor.bcdDevice); 920 version = le16_to_cpu(udev->descriptor.bcdDevice);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 461474176cfb..3cf245bdda54 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -95,6 +95,7 @@ static struct usb_device_id id_table [] = {
95 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, 95 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
96 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, 96 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
97 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, 97 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
98 { USB_DEVICE( NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID ) },
98 { } /* Terminating entry */ 99 { } /* Terminating entry */
99}; 100};
100 101
@@ -652,8 +653,7 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp)
652 timeout = max((HZ*2560)/bps,HZ/10); 653 timeout = max((HZ*2560)/bps,HZ/10);
653 else 654 else
654 timeout = 2*HZ; 655 timeout = 2*HZ;
655 set_current_state(TASK_INTERRUPTIBLE); 656 schedule_timeout_interruptible(timeout);
656 schedule_timeout(timeout);
657 657
658 /* shutdown our urbs */ 658 /* shutdown our urbs */
659 dbg("%s - shutting down urbs", __FUNCTION__); 659 dbg("%s - shutting down urbs", __FUNCTION__);
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index b734c4003c5a..7be9644f5a03 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -58,3 +58,7 @@
58 58
59#define SYNTECH_VENDOR_ID 0x0745 59#define SYNTECH_VENDOR_ID 0x0745
60#define SYNTECH_PRODUCT_ID 0x0001 60#define SYNTECH_PRODUCT_ID 0x0001
61
62/* Nokia CA-42 Cable */
63#define NOKIA_CA42_VENDOR_ID 0x078b
64#define NOKIA_CA42_PRODUCT_ID 0x1234
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index d34dc9f417f0..4837524eada7 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -227,42 +227,42 @@ static int queuecommand(struct scsi_cmnd *srb,
227 ***********************************************************************/ 227 ***********************************************************************/
228 228
229/* Command timeout and abort */ 229/* Command timeout and abort */
230/* This is always called with scsi_lock(host) held */
231static int command_abort(struct scsi_cmnd *srb) 230static int command_abort(struct scsi_cmnd *srb)
232{ 231{
233 struct us_data *us = host_to_us(srb->device->host); 232 struct us_data *us = host_to_us(srb->device->host);
234 233
235 US_DEBUGP("%s called\n", __FUNCTION__); 234 US_DEBUGP("%s called\n", __FUNCTION__);
236 235
236 /* us->srb together with the TIMED_OUT, RESETTING, and ABORTING
237 * bits are protected by the host lock. */
238 scsi_lock(us_to_host(us));
239
237 /* Is this command still active? */ 240 /* Is this command still active? */
238 if (us->srb != srb) { 241 if (us->srb != srb) {
242 scsi_unlock(us_to_host(us));
239 US_DEBUGP ("-- nothing to abort\n"); 243 US_DEBUGP ("-- nothing to abort\n");
240 return FAILED; 244 return FAILED;
241 } 245 }
242 246
243 /* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if 247 /* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if
244 * a device reset isn't already in progress (to avoid interfering 248 * a device reset isn't already in progress (to avoid interfering
245 * with the reset). To prevent races with auto-reset, we must 249 * with the reset). Note that we must retain the host lock while
246 * stop any ongoing USB transfers while still holding the host 250 * calling usb_stor_stop_transport(); otherwise it might interfere
247 * lock. */ 251 * with an auto-reset that begins as soon as we release the lock. */
248 set_bit(US_FLIDX_TIMED_OUT, &us->flags); 252 set_bit(US_FLIDX_TIMED_OUT, &us->flags);
249 if (!test_bit(US_FLIDX_RESETTING, &us->flags)) { 253 if (!test_bit(US_FLIDX_RESETTING, &us->flags)) {
250 set_bit(US_FLIDX_ABORTING, &us->flags); 254 set_bit(US_FLIDX_ABORTING, &us->flags);
251 usb_stor_stop_transport(us); 255 usb_stor_stop_transport(us);
252 } 256 }
257 scsi_unlock(us_to_host(us));
253 258
254 /* Wait for the aborted command to finish */ 259 /* Wait for the aborted command to finish */
255 wait_for_completion(&us->notify); 260 wait_for_completion(&us->notify);
256
257 /* Reacquire the lock and allow USB transfers to resume */
258 clear_bit(US_FLIDX_ABORTING, &us->flags);
259 clear_bit(US_FLIDX_TIMED_OUT, &us->flags);
260 return SUCCESS; 261 return SUCCESS;
261} 262}
262 263
263/* This invokes the transport reset mechanism to reset the state of the 264/* This invokes the transport reset mechanism to reset the state of the
264 * device */ 265 * device */
265/* This is always called with scsi_lock(host) held */
266static int device_reset(struct scsi_cmnd *srb) 266static int device_reset(struct scsi_cmnd *srb)
267{ 267{
268 struct us_data *us = host_to_us(srb->device->host); 268 struct us_data *us = host_to_us(srb->device->host);
@@ -279,7 +279,6 @@ static int device_reset(struct scsi_cmnd *srb)
279} 279}
280 280
281/* Simulate a SCSI bus reset by resetting the device's USB port. */ 281/* Simulate a SCSI bus reset by resetting the device's USB port. */
282/* This is always called with scsi_lock(host) held */
283static int bus_reset(struct scsi_cmnd *srb) 282static int bus_reset(struct scsi_cmnd *srb)
284{ 283{
285 struct us_data *us = host_to_us(srb->device->host); 284 struct us_data *us = host_to_us(srb->device->host);
@@ -291,7 +290,6 @@ static int bus_reset(struct scsi_cmnd *srb)
291 result = usb_stor_port_reset(us); 290 result = usb_stor_port_reset(us);
292 up(&(us->dev_semaphore)); 291 up(&(us->dev_semaphore));
293 292
294 /* lock the host for the return */
295 return result < 0 ? FAILED : SUCCESS; 293 return result < 0 ? FAILED : SUCCESS;
296} 294}
297 295
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index ad0cfd7a782f..b79dad1b598c 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -86,6 +86,16 @@ UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003,
86 US_SC_DEVICE, US_PR_DEVICE, NULL, 86 US_SC_DEVICE, US_PR_DEVICE, NULL,
87 US_FL_IGNORE_RESIDUE ), 87 US_FL_IGNORE_RESIDUE ),
88 88
89/* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net>
90 * and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product)
91 * for USB floppies that need the SINGLE_LUN enforcement.
92 */
93UNUSUAL_DEV( 0x0409, 0x0040, 0x0000, 0x9999,
94 "NEC",
95 "NEC USB UF000x",
96 US_SC_DEVICE, US_PR_DEVICE, NULL,
97 US_FL_SINGLE_LUN ),
98
89/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au> 99/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
90 * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message 100 * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
91 * always fails and confuses drive. 101 * always fails and confuses drive.
@@ -96,6 +106,13 @@ UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113,
96 US_SC_DEVICE, US_PR_DEVICE, NULL, 106 US_SC_DEVICE, US_PR_DEVICE, NULL,
97 US_FL_FIX_INQUIRY ), 107 US_FL_FIX_INQUIRY ),
98 108
109/* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
110UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210,
111 "SMSC",
112 "FDC GOLD-2.30",
113 US_SC_DEVICE, US_PR_DEVICE, NULL,
114 US_FL_SINGLE_LUN ),
115
99#ifdef CONFIG_USB_STORAGE_DPCM 116#ifdef CONFIG_USB_STORAGE_DPCM
100UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, 117UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
101 "Microtech", 118 "Microtech",
@@ -103,6 +120,24 @@ UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
103 US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ), 120 US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
104#endif 121#endif
105 122
123/*
124 * Pete Zaitcev <zaitcev@yahoo.com>, from Patrick C. F. Ernzer, bz#162559.
125 * The key does not actually break, but it returns zero sense which
126 * makes our SCSI stack to print confusing messages.
127 */
128UNUSUAL_DEV( 0x0457, 0x0150, 0x0100, 0x0100,
129 "USBest Technology", /* sold by Transcend */
130 "USB Mass Storage Device",
131 US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
132
133/* Patch submitted by Daniel Drake <dsd@gentoo.org>
134 * Device reports nonsense bInterfaceProtocol 6 when connected over USB2 */
135UNUSUAL_DEV( 0x0451, 0x5416, 0x0100, 0x0100,
136 "Neuros Audio",
137 "USB 2.0 HD 2.5",
138 US_SC_DEVICE, US_PR_BULK, NULL,
139 US_FL_NEED_OVERRIDE ),
140
106/* Patch submitted by Philipp Friedrich <philipp@void.at> */ 141/* Patch submitted by Philipp Friedrich <philipp@void.at> */
107UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100, 142UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100,
108 "Kyocera", 143 "Kyocera",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index cb4c770baf32..f9a9bfa1aef5 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -392,11 +392,16 @@ SkipForAbort:
392 /* If an abort request was received we need to signal that 392 /* If an abort request was received we need to signal that
393 * the abort has finished. The proper test for this is 393 * the abort has finished. The proper test for this is
394 * the TIMED_OUT flag, not srb->result == DID_ABORT, because 394 * the TIMED_OUT flag, not srb->result == DID_ABORT, because
395 * a timeout/abort request might be received after all the 395 * the timeout might have occurred after the command had
396 * USB processing was complete. */ 396 * already completed with a different result code. */
397 if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) 397 if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
398 complete(&(us->notify)); 398 complete(&(us->notify));
399 399
400 /* Allow USB transfers to resume */
401 clear_bit(US_FLIDX_ABORTING, &us->flags);
402 clear_bit(US_FLIDX_TIMED_OUT, &us->flags);
403 }
404
400 /* finished working on this command */ 405 /* finished working on this command */
401 us->srb = NULL; 406 us->srb = NULL;
402 scsi_unlock(host); 407 scsi_unlock(host);
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 5fe182d6e4ab..eb83a7874c71 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -137,7 +137,7 @@ config FONT_8x8
137 137
138config FONT_8x16 138config FONT_8x16
139 bool "VGA 8x16 font" if FONTS 139 bool "VGA 8x16 font" if FONTS
140 depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y 140 depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || USB_SISUSBVGA_CON
141 default y if !SPARC32 && !SPARC64 && !FONTS 141 default y if !SPARC32 && !SPARC64 && !FONTS
142 help 142 help
143 This is the "high resolution" font for the VGA frame buffer (the one 143 This is the "high resolution" font for the VGA frame buffer (the one
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
index b562f6bb9d31..42c7b8dcd220 100644
--- a/drivers/video/console/Makefile
+++ b/drivers/video/console/Makefile
@@ -33,6 +33,10 @@ endif
33 33
34obj-$(CONFIG_FB_STI) += sticore.o font.o 34obj-$(CONFIG_FB_STI) += sticore.o font.o
35 35
36ifeq ($(CONFIG_USB_SISUSBVGA_CON),y)
37obj-$(CONFIG_USB_SISUSBVGA) += font.o
38endif
39
36# Targets that kbuild needs to know about 40# Targets that kbuild needs to know about
37targets := promcon_tbl.c 41targets := promcon_tbl.c
38 42