Commit cc6120c6 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6

parents 7b799bc8 f5e09b7c
Apple Touchpad Driver (appletouch)
----------------------------------
Copyright (C) 2005 Stelian Pop <stelian@popies.net>
appletouch is a Linux kernel driver for the USB touchpad found on post
February 2005 Apple Alu Powerbooks.
This driver is derived from Johannes Berg's appletrackpad driver[1], but it has
been improved in some areas:
* appletouch is a full kernel driver, no userspace program is necessary
* appletouch can be interfaced with the synaptics X11 driver, in order
to have touchpad acceleration, scrolling, etc.
Credits go to Johannes Berg for reverse-engineering the touchpad protocol,
Frank Arnold for further improvements, and Alex Harper for some additional
information about the inner workings of the touchpad sensors.
Usage:
------
In order to use the touchpad in the basic mode, compile the driver and load
the module. A new input device will be detected and you will be able to read
the mouse data from /dev/input/mice (using gpm, or X11).
In X11, you can configure the touchpad to use the synaptics X11 driver, which
will give additional functionalities, like acceleration, scrolling, 2 finger
tap for middle button mouse emulation, 3 finger tap for right button mouse
emulation, etc. In order to do this, make sure you're using a recent version of
the synaptics driver (tested with 0.14.2, available from [2]), and configure a
new input device in your X11 configuration file (take a look below for an
example). For additional configuration, see the synaptics driver documentation.
Section "InputDevice"
Identifier "Synaptics Touchpad"
Driver "synaptics"
Option "SendCoreEvents" "true"
Option "Device" "/dev/input/mice"
Option "Protocol" "auto-dev"
Option "LeftEdge" "0"
Option "RightEdge" "850"
Option "TopEdge" "0"
Option "BottomEdge" "645"
Option "MinSpeed" "0.4"
Option "MaxSpeed" "1"
Option "AccelFactor" "0.02"
Option "FingerLow" "0"
Option "FingerHigh" "30"
Option "MaxTapMove" "20"
Option "MaxTapTime" "100"
Option "HorizScrollDelta" "0"
Option "VertScrollDelta" "30"
Option "SHMConfig" "on"
EndSection
Section "ServerLayout"
...
InputDevice "Mouse"
InputDevice "Synaptics Touchpad"
...
EndSection
Fuzz problems:
--------------
The touchpad sensors are very sensitive to heat, and will generate a lot of
noise when the temperature changes. This is especially true when you power-on
the laptop for the first time.
The appletouch driver tries to handle this noise and auto adapt itself, but it
is not perfect. If finger movements are not recognized anymore, try reloading
the driver.
You can activate debugging using the 'debug' module parameter. A value of 0
deactivates any debugging, 1 activates tracing of invalid samples, 2 activates
full tracing (each sample is being traced):
modprobe appletouch debug=1
or
echo "1" > /sys/module/appletouch/parameters/debug
Links:
------
[1]: http://johannes.sipsolutions.net/PowerBook/touchpad/
[2]: http://web.telia.com/~u89404340/touchpad/index.html
...@@ -297,18 +297,21 @@ S: SerialNumber=dce0 ...@@ -297,18 +297,21 @@ S: SerialNumber=dce0
C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms
T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4 T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4
D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0451 ProdID=1446 Rev= 1.00 P: Vendor=0451 ProdID=1446 Rev= 1.00
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms
T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0 T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0
D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=04b4 ProdID=0001 Rev= 0.00 P: Vendor=04b4 ProdID=0001 Rev= 0.00
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse
E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms
T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0 T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0565 ProdID=0001 Rev= 1.08 P: Vendor=0565 ProdID=0001 Rev= 1.08
......
...@@ -631,8 +631,10 @@ static void usbin_stop(struct usb_audiodev *as) ...@@ -631,8 +631,10 @@ static void usbin_stop(struct usb_audiodev *as)
i = u->flags; i = u->flags;
spin_unlock_irqrestore(&as->lock, flags); spin_unlock_irqrestore(&as->lock, flags);
while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); if (notkilled)
schedule_timeout(1); schedule_timeout_interruptible(1);
else
schedule_timeout_uninterruptible(1);
spin_lock_irqsave(&as->lock, flags); spin_lock_irqsave(&as->lock, flags);
i = u->flags; i = u->flags;
spin_unlock_irqrestore(&as->lock, flags); spin_unlock_irqrestore(&as->lock, flags);
...@@ -1102,8 +1104,10 @@ static void usbout_stop(struct usb_audiodev *as) ...@@ -1102,8 +1104,10 @@ static void usbout_stop(struct usb_audiodev *as)
i = u->flags; i = u->flags;
spin_unlock_irqrestore(&as->lock, flags); spin_unlock_irqrestore(&as->lock, flags);
while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); if (notkilled)
schedule_timeout(1); schedule_timeout_interruptible(1);
else
schedule_timeout_uninterruptible(1);
spin_lock_irqsave(&as->lock, flags); spin_lock_irqsave(&as->lock, flags);
i = u->flags; i = u->flags;
spin_unlock_irqrestore(&as->lock, flags); spin_unlock_irqrestore(&as->lock, flags);
......
...@@ -1606,7 +1606,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) ...@@ -1606,7 +1606,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
return IRQ_NONE; return IRQ_NONE;
hcd->saw_irq = 1; hcd->saw_irq = 1;
if (hcd->state != start && hcd->state == HC_STATE_HALT) if (hcd->state == HC_STATE_HALT)
usb_hc_died (hcd); usb_hc_died (hcd);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1630,7 +1630,6 @@ void usb_hc_died (struct usb_hcd *hcd) ...@@ -1630,7 +1630,6 @@ void usb_hc_died (struct usb_hcd *hcd)
spin_lock_irqsave (&hcd_root_hub_lock, flags); spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (hcd->rh_registered) { if (hcd->rh_registered) {
hcd->poll_rh = 0; hcd->poll_rh = 0;
del_timer(&hcd->rh_timer);
/* make khubd clean up old urbs and devices */ /* make khubd clean up old urbs and devices */
usb_set_device_state (hcd->self.root_hub, usb_set_device_state (hcd->self.root_hub,
......
...@@ -435,6 +435,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) ...@@ -435,6 +435,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
static void hub_power_on(struct usb_hub *hub) static void hub_power_on(struct usb_hub *hub)
{ {
int port1; int port1;
unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
/* if hub supports power switching, enable power on each port */ /* if hub supports power switching, enable power on each port */
if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) { if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
...@@ -444,8 +445,8 @@ static void hub_power_on(struct usb_hub *hub) ...@@ -444,8 +445,8 @@ static void hub_power_on(struct usb_hub *hub)
USB_PORT_FEAT_POWER); USB_PORT_FEAT_POWER);
} }
/* Wait for power to be enabled */ /* Wait at least 100 msec for power to become stable */
msleep(hub->descriptor->bPwrOn2PwrGood * 2); msleep(max(pgood_delay, (unsigned) 100));
} }
static void hub_quiesce(struct usb_hub *hub) static void hub_quiesce(struct usb_hub *hub)
...@@ -1460,7 +1461,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, ...@@ -1460,7 +1461,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
port1, status); port1, status);
else { else {
status = hub_port_wait_reset(hub, port1, udev, delay); status = hub_port_wait_reset(hub, port1, udev, delay);
if (status) if (status && status != -ENOTCONN)
dev_dbg(hub->intfdev, dev_dbg(hub->intfdev,
"port_wait_reset: err = %d\n", "port_wait_reset: err = %d\n",
status); status);
...@@ -1469,8 +1470,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1, ...@@ -1469,8 +1470,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
/* return on disconnect or reset */ /* return on disconnect or reset */
switch (status) { switch (status) {
case 0: case 0:
/* TRSTRCY = 10 ms */ /* TRSTRCY = 10 ms; plus some extra */
msleep(10); msleep(10 + 40);
/* FALL THROUGH */ /* FALL THROUGH */
case -ENOTCONN: case -ENOTCONN:
case -ENODEV: case -ENODEV:
......
...@@ -483,6 +483,7 @@ ep_release (struct inode *inode, struct file *fd) ...@@ -483,6 +483,7 @@ ep_release (struct inode *inode, struct file *fd)
data->state = STATE_EP_DISABLED; data->state = STATE_EP_DISABLED;
data->desc.bDescriptorType = 0; data->desc.bDescriptorType = 0;
data->hs_desc.bDescriptorType = 0; data->hs_desc.bDescriptorType = 0;
usb_ep_disable(data->ep);
} }
put_ep (data); put_ep (data);
return 0; return 0;
......
...@@ -400,6 +400,23 @@ static int ehci_hc_reset (struct usb_hcd *hcd) ...@@ -400,6 +400,23 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
return -EIO; return -EIO;
} }
break; break;
case PCI_VENDOR_ID_NVIDIA:
/* NVidia reports that certain chips don't handle
* QH, ITD, or SITD addresses above 2GB. (But TD,
* data buffer, and periodic schedule are normal.)
*/
switch (pdev->device) {
case 0x003c: /* MCP04 */
case 0x005b: /* CK804 */
case 0x00d8: /* CK8 */
case 0x00e8: /* CK8S */
if (pci_set_consistent_dma_mask(pdev,
DMA_31BIT_MASK) < 0)
ehci_warn (ehci, "can't enable NVidia "
"workaround for >2GB RAM\n");
break;
}
break;
} }
/* optional debug port, normally in the first BAR */ /* optional debug port, normally in the first BAR */
...@@ -759,12 +776,16 @@ static int ehci_resume (struct usb_hcd *hcd) ...@@ -759,12 +776,16 @@ static int ehci_resume (struct usb_hcd *hcd)
if (time_before (jiffies, ehci->next_statechange)) if (time_before (jiffies, ehci->next_statechange))
msleep (100); msleep (100);
/* If any port is suspended, we know we can/must resume the HC. */ /* If any port is suspended (or owned by the companion),
* we know we can/must resume the HC (and mustn't reset it).
*/
for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) { for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
u32 status; u32 status;
port--; port--;
status = readl (&ehci->regs->port_status [port]); status = readl (&ehci->regs->port_status [port]);
if (status & PORT_SUSPEND) { if (!(status & PORT_POWER))
continue;
if (status & (PORT_SUSPEND | PORT_OWNER)) {
down (&hcd->self.root_hub->serialize); down (&hcd->self.root_hub->serialize);
retval = ehci_hub_resume (hcd); retval = ehci_hub_resume (hcd);
up (&hcd->self.root_hub->serialize); up (&hcd->self.root_hub->serialize);
...@@ -1126,8 +1147,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) ...@@ -1126,8 +1147,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
case QH_STATE_UNLINK: /* wait for hw to finish? */ case QH_STATE_UNLINK: /* wait for hw to finish? */
idle_timeout: idle_timeout:
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
set_current_state (TASK_UNINTERRUPTIBLE); schedule_timeout_uninterruptible(1);
schedule_timeout (1);
goto rescan; goto rescan;
case QH_STATE_IDLE: /* fully unlinked */ case QH_STATE_IDLE: /* fully unlinked */
if (list_empty (&qh->qtd_list)) { if (list_empty (&qh->qtd_list)) {
......
...@@ -54,7 +54,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd) ...@@ -54,7 +54,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
/* suspend any active/unsuspended ports, maybe allow wakeup */ /* suspend any active/unsuspended ports, maybe allow wakeup */
while (port--) { while (port--) {
u32 __iomem *reg = &ehci->regs->port_status [port]; u32 __iomem *reg = &ehci->regs->port_status [port];
u32 t1 = readl (reg); u32 t1 = readl (reg) & ~PORT_RWC_BITS;
u32 t2 = t1; u32 t2 = t1;
if ((t1 & PORT_PE) && !(t1 & PORT_OWNER)) if ((t1 & PORT_PE) && !(t1 & PORT_OWNER))
...@@ -115,7 +115,8 @@ static int ehci_hub_resume (struct usb_hcd *hcd) ...@@ -115,7 +115,8 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
i = HCS_N_PORTS (ehci->hcs_params); i = HCS_N_PORTS (ehci->hcs_params);
while (i--) { while (i--) {
temp = readl (&ehci->regs->port_status [i]); temp = readl (&ehci->regs->port_status [i]);
temp &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E); temp &= ~(PORT_RWC_BITS
| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
if (temp & PORT_SUSPEND) { if (temp & PORT_SUSPEND) {
ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
temp |= PORT_RESUME; temp |= PORT_RESUME;
...@@ -128,7 +129,7 @@ static int ehci_hub_resume (struct usb_hcd *hcd) ...@@ -128,7 +129,7 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
temp = readl (&ehci->regs->port_status [i]); temp = readl (&ehci->regs->port_status [i]);
if ((temp & PORT_SUSPEND) == 0) if ((temp & PORT_SUSPEND) == 0)
continue; continue;
temp &= ~PORT_RESUME; temp &= ~(PORT_RWC_BITS | PORT_RESUME);
writel (temp, &ehci->regs->port_status [i]); writel (temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1); ehci_vdbg (ehci, "resumed port %d\n", i + 1);
} }
...@@ -191,6 +192,7 @@ static int check_reset_complete ( ...@@ -191,6 +192,7 @@ static int check_reset_complete (
// what happens if HCS_N_CC(params) == 0 ? // what happens if HCS_N_CC(params) == 0 ?
port_status |= PORT_OWNER; port_status |= PORT_OWNER;
port_status &= ~PORT_RWC_BITS;
writel (port_status, &ehci->regs->port_status [index]); writel (port_status, &ehci->regs->port_status [index]);
} else } else
...@@ -233,7 +235,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -233,7 +235,8 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
if (temp & PORT_OWNER) { if (temp & PORT_OWNER) {
/* don't report this in GetPortStatus */ /* don't report this in GetPortStatus */
if (temp & PORT_CSC) { if (temp & PORT_CSC) {
temp &= ~PORT_CSC; temp &= ~PORT_RWC_BITS;
temp |= PORT_CSC;
writel (temp, &ehci->regs->port_status [i]); writel (temp, &ehci->regs->port_status [i]);
} }
continue; continue;
...@@ -343,7 +346,7 @@ static int ehci_hub_control ( ...@@ -343,7 +346,7 @@ static int ehci_hub_control (
&ehci->regs->port_status [wIndex]); &ehci->regs->port_status [wIndex]);
break; break;
case USB_PORT_FEAT_C_ENABLE: case USB_PORT_FEAT_C_ENABLE:
writel (temp | PORT_PEC, writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
&ehci->regs->port_status [wIndex]); &ehci->regs->port_status [wIndex]);
break; break;
case USB_PORT_FEAT_SUSPEND: case USB_PORT_FEAT_SUSPEND:
...@@ -353,7 +356,8 @@ static int ehci_hub_control ( ...@@ -353,7 +356,8 @@ static int ehci_hub_control (
if ((temp & PORT_PE) == 0) if ((temp & PORT_PE) == 0)
goto error; goto error;
/* resume signaling for 20 msec */ /* resume signaling for 20 msec */
writel ((temp & ~PORT_WAKE_BITS) | PORT_RESUME, temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
writel (temp | PORT_RESUME,
&ehci->regs->port_status [wIndex]); &ehci->regs->port_status [wIndex]);
ehci->reset_done [wIndex] = jiffies ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (20); + msecs_to_jiffies (20);
...@@ -364,15 +368,15 @@ static int ehci_hub_control ( ...@@ -364,15 +368,15 @@ static int ehci_hub_control (
break; break;
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params)) if (HCS_PPC (ehci->hcs_params))
writel (temp & ~PORT_POWER, writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
&ehci->regs->port_status [wIndex]); &ehci->regs->port_status [wIndex]);
break; break;
case USB_PORT_FEAT_C_CONNECTION: case USB_PORT_FEAT_C_CONNECTION:
writel (temp | PORT_CSC, writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
&ehci->regs->port_status [wIndex]); &ehci->regs->port_status [wIndex]);
break; break;
case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_OVER_CURRENT:
writel (temp | PORT_OCC, writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
&ehci->regs->port_status [wIndex]); &ehci->regs->port_status [wIndex]);
break; break;
case USB_PORT_FEAT_C_RESET: case USB_PORT_FEAT_C_RESET:
...@@ -416,7 +420,7 @@ static int ehci_hub_control ( ...@@ -416,7 +420,7 @@ static int ehci_hub_control (
/* stop resume signaling */ /* stop resume signaling */
temp = readl (&ehci->regs->port_status [wIndex]); temp = readl (&ehci->regs->port_status [wIndex]);
writel (temp & ~PORT_RESUME, writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
&ehci->regs->port_status [wIndex]); &ehci->regs->port_status [wIndex]);
retval = handshake ( retval = handshake (
&ehci->regs->port_status [wIndex], &ehci->regs->port_status [wIndex],
...@@ -437,7 +441,7 @@ static int ehci_hub_control ( ...@@ -437,7 +441,7 @@ static int ehci_hub_control (
ehci->reset_done [wIndex] = 0; ehci->reset_done [wIndex] = 0;
/* force reset to complete */ /* force reset to complete */
writel (temp & ~PORT_RESET, writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
&ehci->regs->port_status [wIndex]); &ehci->regs->port_status [wIndex]);
/* REVISIT: some hardware needs 550+ usec to clear /* REVISIT: some hardware needs 550+ usec to clear
* this bit; seems too long to spin routinely... * this bit; seems too long to spin routinely...
...@@ -500,6 +504,7 @@ static int ehci_hub_control ( ...@@ -500,6 +504,7 @@ static int ehci_hub_control (
if (temp & PORT_OWNER) if (temp & PORT_OWNER)
break; break;
temp &= ~PORT_RWC_BITS;
switch (wValue) { switch (wValue) {
case USB_PORT_FEAT_SUSPEND: case USB_PORT_FEAT_SUSPEND:
if ((temp & PORT_PE) == 0 if ((temp & PORT_PE) == 0
......
...@@ -263,6 +263,7 @@ struct ehci_regs { ...@@ -263,6 +263,7 @@ struct ehci_regs {
#define PORT_PE (1<<2) /* port enable */ #define PORT_PE (1<<2) /* port enable */
#define PORT_CSC (1<<1) /* connect status change */ #define PORT_CSC (1<<1) /* connect status change */
#define PORT_CONNECT (1<<0) /* device connected */ #define PORT_CONNECT (1<<0) /* device connected */
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Appendix C, Debug port ... intended for use with special "debug devices" /* Appendix C, Debug port ... intended for use with special "debug devices"
......
...@@ -228,23 +228,22 @@ ohci_dump_roothub ( ...@@ -228,23 +228,22 @@ ohci_dump_roothub (
char **next, char **next,
unsigned *size) unsigned *size)
{ {
u32 temp, ndp, i; u32 temp, i;
temp = roothub_a (controller); temp = roothub_a (controller);
if (temp == ~(u32)0) if (temp == ~(u32)0)
return; return;
ndp = (temp & RH_A_NDP);
if (verbose) { if (verbose) {
ohci_dbg_sw (controller, next, size, ohci_dbg_sw (controller, next, size,
"roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d\n", temp, "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d(%d)\n", temp,
((temp & RH_A_POTPGT) >> 24) & 0xff, ((temp & RH_A_POTPGT) >> 24) & 0xff,
(temp & RH_A_NOCP) ? " NOCP" : "", (temp & RH_A_NOCP) ? " NOCP" : "",
(temp & RH_A_OCPM) ? " OCPM" : "", (temp & RH_A_OCPM) ? " OCPM" : "",
(temp & RH_A_DT) ? " DT" : "", (temp & RH_A_DT) ? " DT" : "",
(temp & RH_A_NPS) ? " NPS" : "", (temp & RH_A_NPS) ? " NPS" : "",
(temp & RH_A_PSM) ? " PSM" : "", (temp & RH_A_PSM) ? " PSM" : "",
ndp (temp & RH_A_NDP), controller->num_ports
); );
temp = roothub_b (controller); temp = roothub_b (controller);
ohci_dbg_sw (controller, next, size, ohci_dbg_sw (controller, next, size,
...@@ -266,7 +265,7 @@ ohci_dump_roothub ( ...@@ -266,7 +265,7 @@ ohci_dump_roothub (
); );
} }
for (i = 0; i < ndp; i++) { for (i = 0; i < controller->num_ports; i++) {
temp = roothub_portstatus (controller, i); temp = roothub_portstatus (controller, i);
dbg_port_sw (controller, i, temp, next, size); dbg_port_sw (controller, i, temp, next, size);
} }
......
...@@ -382,8 +382,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) ...@@ -382,8 +382,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
goto sanitize; goto sanitize;
} }
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock_irqrestore (&ohci->lock, flags);
set_current_state (TASK_UNINTERRUPTIBLE); schedule_timeout_uninterruptible(1);
schedule_timeout (1);
goto rescan; goto rescan;
case ED_IDLE: /* fully unlinked */ case ED_IDLE: /* fully unlinked */
if (list_empty (&ed->td_list)) { if (list_empty (&ed->td_list)) {
...@@ -485,6 +484,10 @@ static int ohci_init (struct ohci_hcd *ohci) ...@@ -485,6 +484,10 @@ static int ohci_init (struct ohci_hcd *ohci)
// flush the writes // flush the writes
(void) ohci_readl (ohci, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control);
/* Read the number of ports unless overridden */
if (ohci->num_ports == 0)
ohci->num_ports = roothub_a(ohci) & RH_A_NDP;
if (ohci->hcca) if (ohci->hcca)
return 0; return 0;
...@@ -561,10 +564,8 @@ static int ohci_run (struct ohci_hcd *ohci) ...@@ -561,10 +564,8 @@ static int ohci_run (struct ohci_hcd *ohci)
msleep(temp); msleep(temp);
temp = roothub_a (ohci); temp = roothub_a (ohci);
if (!(temp & RH_A_NPS)) { if (!(temp & RH_A_NPS)) {
unsigned ports = temp & RH_A_NDP;
/* power down each port */ /* power down each port */
for (temp = 0; temp < ports; temp++) for (temp = 0; temp < ohci->num_ports; temp++)
ohci_writel (ohci, RH_PS_LSDA, ohci_writel (ohci, RH_PS_LSDA,
&ohci->regs->roothub.portstatus [temp]); &ohci->regs->roothub.portstatus [temp]);
} }
...@@ -720,6 +721,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) ...@@ -720,6 +721,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
if (ints & OHCI_INTR_RD) { if (ints & OHCI_INTR_RD) {
ohci_vdbg (ohci, "resume detect\n"); ohci_vdbg (ohci, "resume detect\n");
ohci_writel (ohci, OHCI_INTR_RD, &regs->intrstatus);
if (hcd->state != HC_STATE_QUIESCING) if (hcd->state != HC_STATE_QUIESCING)
schedule_work(&ohci->rh_resume); schedule_work(&ohci->rh_resume);
} }
...@@ -861,7 +863,7 @@ static int ohci_restart (struct ohci_hcd *ohci) ...@@ -861,7 +863,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
* and that if we try to turn them back on the root hub * and that if we try to turn them back on the root hub
* will respond to CSC processing. * will respond to CSC processing.
*/ */
i = roothub_a (ohci) & RH_A_NDP; i = ohci->num_ports;
while (i--) while (i--)
ohci_writel (ohci, RH_PS_PSS, ohci_writel (ohci, RH_PS_PSS,
&ohci->regs->roothub.portstatus [temp]); &ohci->regs->roothub.portstatus [temp]);
......
...@@ -184,7 +184,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd) ...@@ -184,7 +184,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
if (status != -EINPROGRESS) if (status != -EINPROGRESS)
return status; return status;
temp = roothub_a (ohci) & RH_A_NDP; temp = ohci->num_ports;
enables = 0; enables = 0;
while (temp--) { while (temp--) {
u32 stat = ohci_readl (ohci, u32 stat = ohci_readl (ohci,
...@@ -304,7 +304,7 @@ static int ...@@ -304,7 +304,7 @@ static int
ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ports, i, changed = 0, length = 1; int i, changed = 0, length = 1;
int can_suspend = hcd->can_wakeup; int can_suspend = hcd->can_wakeup;
unsigned long flags; unsigned long flags;
...@@ -319,9 +319,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -319,9 +319,10 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
goto done; goto done;
} }
ports = roothub_a (ohci) & RH_A_NDP; /* undocumented erratum seen on at least rev D */
if (ports > MAX_ROOT_PORTS) { if ((ohci->flags & OHCI_QUIRK_AMD756)
ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports, && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) {
ohci_warn (ohci, "bogus NDP, rereads as NDP=%d\n",
ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP); ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP);
/* retry later; "should not happen" */ /* retry later; "should not happen" */
goto done; goto done;
...@@ -332,13 +333,13 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -332,13 +333,13 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
buf [0] = changed = 1; buf [0] = changed = 1;
else else
buf [0] = 0; buf [0] = 0;
if (ports > 7) { if (ohci->num_ports > 7) {
buf [1] = 0; buf [1] = 0;
length++; length++;
} }
/* look at each port */ /* look at each port */
for (i = 0; i < ports; i++) { for (i = 0; i < ohci->num_ports; i++) {
u32 status = roothub_portstatus (ohci, i); u32 status = roothub_portstatus (ohci, i);
if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
...@@ -395,15 +396,14 @@ ohci_hub_descriptor ( ...@@ -395,15 +396,14 @@ ohci_hub_descriptor (
struct usb_hub_descriptor *desc struct usb_hub_descriptor *desc
) { ) {
u32 rh = roothub_a (ohci); u32 rh = roothub_a (ohci);
int ports = rh & RH_A_NDP;
u16 temp; u16 temp;
desc->bDescriptorType = 0x29; desc->bDescriptorType = 0x29;
desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24; desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24;
desc->bHubContrCurrent = 0; desc->bHubContrCurrent = 0;
desc->bNbrPorts = ports; desc->bNbrPorts = ohci->num_ports;
temp = 1 + (ports / 8); temp = 1 + (ohci->num_ports / 8);
desc->bDescLength = 7 + 2 * temp; desc->bDescLength = 7 + 2 * temp;
temp = 0; temp = 0;
...@@ -421,7 +421,7 @@ ohci_hub_descriptor ( ...@@ -421,7 +421,7 @@ ohci_hub_descriptor (
rh = roothub_b (ohci); rh = roothub_b (ohci);
memset(desc->bitmap, 0xff, sizeof(desc->bitmap)); memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
desc->bitmap [0] = rh & RH_B_DR; desc->bitmap [0] = rh & RH_B_DR;
if (ports > 7) { if (ohci->num_ports > 7) {
desc->bitmap [1] = (rh & RH_B_DR) >> 8; desc->bitmap [1] = (rh & RH_B_DR) >> 8;
desc->bitmap [2] = 0xff; desc->bitmap [2] = 0xff;
} else } else
......
...@@ -75,33 +75,6 @@ static int pxa27x_ohci_select_pmm( int mode ) ...@@ -75,33 +75,6 @@ static int pxa27x_ohci_select_pmm( int mode )
return 0; return 0;
} }
/*
If you select PMM_PERPORT_MODE, you should set the port power
*/
static int pxa27x_ohci_set_port_power( int port )
{
if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE)
&& (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) {
UHCRHPS(port) |= 0x100;
return 0;
}
return -1;
}
/*
If you select PMM_PERPORT_MODE, you should set the port power
*/
static int pxa27x_ohci_clear_port_power( int port )
{
if ( (pxa27x_ohci_pmm_state==PMM_PERPORT_MODE)
&& (port>0) && (port<PXA_UHC_MAX_PORTNUM) ) {
UHCRHPS(port) |= 0x200;
return 0;
}
return -1;
}
extern int usb_disabled(void); extern int usb_disabled(void);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -130,11 +103,17 @@ static void pxa27x_start_hc(struct platform_device *dev) ...@@ -130,11 +103,17 @@ static void pxa27x_start_hc(struct platform_device *dev)
Polarity Low to active low. Supply power to USB ports. */ Polarity Low to active low. Supply power to USB ports. */
UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) & UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
pxa27x_ohci_pmm_state = PMM_PERPORT_MODE;
} }
UHCHR &= ~UHCHR_SSE; UHCHR &= ~UHCHR_SSE;
UHCHIE = (UHCHIE_UPRIE | UHCHIE_RWIE); UHCHIE = (UHCHIE_UPRIE | UHCHIE_RWIE);
/* Clear any OTG Pin Hold */
if (PSSR & PSSR_OTGPH)
PSSR |= PSSR_OTGPH;
} }
static void pxa27x_stop_hc(struct platform_device *dev) static void pxa27x_stop_hc(struct platform_device *dev)
...@@ -198,17 +177,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, ...@@ -198,17 +177,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
pxa27x_start_hc(dev); pxa27x_start_hc(dev);
/* Select Power Management Mode */ /* Select Power Management Mode */
pxa27x_ohci_select_pmm( PMM_PERPORT_MODE ); pxa27x_ohci_select_pmm(pxa27x_ohci_pmm_state);
/* If choosing PMM_PERPORT_MODE, we should set the port power before we use it. */
if (pxa27x_ohci_set_port_power(1) < 0)
printk(KERN_ERR "Setting port 1 power failed.\n");
if (pxa27x_ohci_clear_port_power(2) < 0)
printk(KERN_ERR "Setting port 2 power failed.\n");
if (pxa27x_ohci_clear_port_power(3) < 0)
printk(KERN_ERR "Setting port 3 power failed.\n");
ohci_hcd_init(hcd_to_ohci(hcd)); ohci_hcd_init(hcd_to_ohci(hcd));
...@@ -258,6 +227,9 @@ ohci_pxa27x_start (struct usb_hcd *hcd) ...@@ -258,6 +227,9 @@ ohci_pxa27x_start (struct usb_hcd *hcd)
ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci); ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci);
/* The value of NDP in roothub_a is incorrect on this hardware */
ohci->num_ports = 3;
if ((ret = ohci_init(ohci)) < 0) if ((ret = ohci_init(ohci)) < 0)
return ret; return ret;
......
...@@ -383,6 +383,7 @@ struct ohci_hcd { ...@@ -383,6 +383,7 @@ struct ohci_hcd {
/* /*
* driver state * driver state
*/ */
int num_ports;
int load [NUM_INTS]; int load [NUM_INTS];
u32 hc_control; /* copy of hc control reg */ u32 hc_control; /* copy of hc control reg */
unsigned long next_statechange; /* suspend/resume */ unsigned long next_statechange; /* suspend/resume */
......
...@@ -97,14 +97,9 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci); ...@@ -97,14 +97,9 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
/* to make sure it doesn't hog all of the bandwidth */ /* to make sure it doesn't hog all of the bandwidth */
#define DEPTH_INTERVAL 5 #define DEPTH_INTERVAL 5
static inline void restart_timer(struct uhci_hcd *uhci)
{
mod_timer(&uhci->stall_timer, jiffies + msecs_to_jiffies(100));
}
#include "uhci-hub.c"
#include "uhci-debug.c" #include "uhci-debug.c"
#include "uhci-q.c" #include "uhci-q.c"
#include "uhci-hub.c"
/* /*
* Make sure the controller is completely inactive, unable to * Make sure the controller is completely inactive, unable to
...@@ -160,7 +155,6 @@ static void hc_died(struct uhci_hcd *uhci) ...@@ -160,7 +155,6 @@ static void hc_died(struct uhci_hcd *uhci)
{ {
reset_hc(uhci); reset_hc(uhci);
uhci->hc_inaccessible = 1; uhci->hc_inaccessible = 1;
del_timer(&uhci->stall_timer);
} }
/* /*
...@@ -287,8 +281,11 @@ __acquires(uhci->lock) ...@@ -287,8 +281,11 @@ __acquires(uhci->lock)
/* Enable resume-detect interrupts if they work. /* Enable resume-detect interrupts if they work.
* Then enter Global Suspend mode, still configured. * Then enter Global Suspend mode, still configured.
*/ */
int_enable = (resume_detect_interrupts_are_broken(uhci) ? uhci->working_RD = 1;
0 : USBINTR_RESUME); int_enable = USBINTR_RESUME;
if (resume_detect_interrupts_are_broken(uhci)) {
uhci->working_RD = int_enable = 0;
}
outw(int_enable, uhci->io_addr + USBINTR); outw(int_enable, uhci->io_addr + USBINTR);
outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD); outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
mb(); mb();
...@@ -315,7 +312,6 @@ __acquires(uhci->lock) ...@@ -315,7 +312,6 @@ __acquires(uhci->lock)
uhci->rh_state = new_state; uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED; uhci->is_stopped = UHCI_IS_STOPPED;
del_timer(&uhci->stall_timer);
uhci_to_hcd(uhci)->poll_rh = !int_enable; uhci_to_hcd(uhci)->poll_rh = !int_enable;
uhci_scan_schedule(uhci, NULL); uhci_scan_schedule(uhci, NULL);
...@@ -335,7 +331,6 @@ static void start_rh(struct uhci_hcd *uhci) ...@@ -335,7 +331,6 @@ static void start_rh(struct uhci_hcd *uhci)
mb(); mb();
uhci->rh_state = UHCI_RH_RUNNING; uhci->rh_state = UHCI_RH_RUNNING;
uhci_to_hcd(uhci)->poll_rh = 1; uhci_to_hcd(uhci)->poll_rh = 1;
restart_timer(uhci);
} }
static void wakeup_rh(struct uhci_hcd *uhci) static void wakeup_rh(struct uhci_hcd *uhci)
...@@ -374,20 +369,6 @@ __acquires(uhci->lock) ...@@ -374,20 +369,6 @@ __acquires(uhci->lock)
mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
} }
static void stall_callback(unsigned long _uhci)
{
struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci;
unsigned long flags;
spin_lock_irqsave(&uhci->lock, flags);
uhci_scan_schedule(uhci, NULL);
check_fsbr(uhci);
if (!uhci->is_stopped)
restart_timer(uhci);
spin_unlock_irqrestore(&uhci->lock, flags);
}
static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
{ {
struct uhci_hcd *uhci = hcd_to_uhci(hcd); 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,8 +399,10 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
"host controller halted, " "host controller halted, "
"very bad!\n"); "very bad!\n");
hc_died(uhci); hc_died(uhci);
spin_unlock_irqrestore(&uhci->lock, flags);
return IRQ_HANDLED; /* Force a callback in case there are
* pending unlinks */
mod_timer(&hcd->rh_timer, jiffies);
} }
spin_unlock_irqrestore(&uhci->lock, flags); spin_unlock_irqrestore(&uhci->lock, flags);
} }
...@@ -427,10 +410,11 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -427,10 +410,11 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
if (status & USBSTS_RD) if (status & USBSTS_RD)
usb_hcd_poll_rh_status(hcd); usb_hcd_poll_rh_status(hcd);
else {
spin_lock_irqsave(&uhci->lock, flags); spin_lock_irqsave(&uhci->lock, flags);
uhci_scan_schedule(uhci, regs); uhci_scan_schedule(uhci, regs);
spin_unlock_irqrestore(&uhci->lock, flags); spin_unlock_irqrestore(&uhci->lock, flags);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -595,10 +579,6 @@ static int uhci_start(struct usb_hcd *hcd) ...@@ -595,10 +579,6 @@ static int uhci_start(struct usb_hcd *hcd)
init_waitqueue_head(&uhci->waitqh); init_waitqueue_head(&uhci->waitqh);
init_timer(&uhci->stall_timer);
uhci->stall_timer.function = stall_callback;
uhci->stall_timer.data = (unsigned long) uhci;
uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl), uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
&dma_handle, 0); &dma_handle, 0);
if (!uhci->fl) { if (!uhci->fl) {
...@@ -745,11 +725,11 @@ static void uhci_stop(struct usb_hcd *hcd) ...@@ -745,11 +725,11 @@ static void uhci_stop(struct usb_hcd *hcd)
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
spin_lock_irq(&uhci->lock); spin_lock_irq(&uhci->lock);
if (!uhci->hc_inaccessible)
reset_hc(uhci); reset_hc(uhci);
uhci_scan_schedule(uhci, NULL); uhci_scan_schedule(uhci, NULL);
spin_unlock_irq(&uhci->lock); spin_unlock_irq(&uhci->lock);
del_timer_sync(&uhci->stall_timer);
release_uhci(uhci); release_uhci(uhci);
} }
...@@ -811,13 +791,12 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) ...@@ -811,13 +791,12 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
*/ */
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
uhci->hc_inaccessible = 1; uhci->hc_inaccessible = 1;
hcd->poll_rh = 0;
/* FIXME: Enable non-PME# remote wakeup? */ /* FIXME: Enable non-PME# remote wakeup? */
done: done:
spin_unlock_irq(&uhci->lock); spin_unlock_irq(&uhci->lock);
if (rc == 0)
del_timer_sync(&hcd->rh_timer);
return rc; return rc;
} }
...@@ -850,8 +829,11 @@ static int uhci_resume(struct usb_hcd *hcd) ...@@ -850,8 +829,11 @@ static int uhci_resume(struct usb_hcd *hcd)
spin_unlock_irq(&uhci->lock); spin_unlock_irq(&uhci->lock);
if (hcd->poll_rh) if (!uhci->working_RD) {
/* Suspended root hub needs to be polled */
hcd->poll_rh = 1;
usb_hcd_poll_rh_status(hcd); usb_hcd_poll_rh_status(hcd);
}
return 0; return 0;
} }
#endif #endif
......
...@@ -345,9 +345,6 @@ enum uhci_rh_state { ...@@ -345,9 +345,6 @@ enum uhci_rh_state {
/* /*
* This describes the full uhci information. * This describes the full uhci information.
*
* Note how the "proper" USB information is just
* a subset of what the full implementation needs.
*/ */
struct uhci_hcd { struct uhci_hcd {
...@@ -360,8 +357,6 @@ struct uhci_hcd { ...@@ -360,8 +357,6 @@ struct uhci_hcd {
struct dma_pool *qh_pool; struct dma_pool *qh_pool;
struct dma_pool *td_pool; struct dma_pool *td_pool;
struct usb_bus *bus;
struct uhci_td *term_td; /* Terminating TD, see UHCI bug */ struct uhci_td *term_td; /* Terminating TD, see UHCI bug */
struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
...@@ -380,6 +375,8 @@ struct uhci_hcd { ...@@ -380,6 +375,8 @@ struct uhci_hcd {
unsigned int scan_in_progress:1; /* Schedule scan is running */ unsigned int scan_in_progress:1; /* Schedule scan is running */
unsigned int need_rescan:1; /* Redo the schedule scan */ unsigned int need_rescan:1; /* Redo the schedule scan */
unsigned int hc_inaccessible:1; /* HC is suspended or dead */ unsigned int hc_inaccessible:1; /* HC is suspended or dead */
unsigned int working_RD:1; /* Suspended root hub doesn't
need to be polled */
/* Support for port suspend/resume/reset */ /* Support for port suspend/resume/reset */
unsigned long port_c_suspend; /* Bit-arrays of ports */ unsigned long port_c_suspend; /* Bit-arrays of ports */
...@@ -405,9 +402,7 @@ struct uhci_hcd { ...@@ -405,9 +402,7 @@ struct uhci_hcd {
/* List of URB's awaiting completion callback */ /* List of URB's awaiting completion callback */
struct list_head complete_list; /* P: uhci->lock */ struct list_head complete_list; /* P: uhci->lock */
int rh_numports; int rh_numports; /* Number of root-hub ports */
struct timer_list stall_timer;
wait_queue_head_t waitqh; /* endpoint_disable waiters */ wait_queue_head_t waitqh; /* endpoint_disable waiters */
}; };
......
...@@ -145,15 +145,16 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) ...@@ -145,15 +145,16 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
{ {
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags; unsigned long flags;
int status; int status = 0;
spin_lock_irqsave(&uhci->lock, flags); spin_lock_irqsave(&uhci->lock, flags);
if (uhci->hc_inaccessible) {
status = 0;
goto done;
}
uhci_scan_schedule(uhci, NULL);
if (uhci->hc_inaccessible)
goto done;
check_fsbr(uhci);
uhci_check_ports(uhci); uhci_check_ports(uhci);
status = get_hub_status_data(uhci, buf); status = get_hub_status_data(uhci, buf);
switch (uhci->rh_state) { switch (uhci->rh_state) {
......
...@@ -33,7 +33,7 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci); ...@@ -33,7 +33,7 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
{ {
if (uhci->is_stopped) if (uhci->is_stopped)
mod_timer(&uhci->stall_timer, jiffies); mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
} }
......
...@@ -286,3 +286,23 @@ config USB_KEYSPAN_REMOTE ...@@ -286,3 +286,23 @@ config USB_KEYSPAN_REMOTE
To compile this driver as a module, choose M here: the module will To compile this driver as a module, choose M here: the module will
be called keyspan_remote. be called keyspan_remote.
config USB_APPLETOUCH
tristate "Apple USB Touchpad support"
depends on USB && INPUT
---help---
Say Y here if you want to use an Apple USB Touchpad.
These are the touchpads that can be found on post-February 2005
Apple Powerbooks (prior models have a Synaptics touchpad connected
to the ADB bus).
This driver provides a basic mouse driver but can be interfaced
with the synaptics X11 driver to provide acceleration and
scrolling in X11.
For further information, see
<file:Documentation/input/appletouch.txt>.
To compile this driver as a module, choose M here: the
module will be called appletouch.
...@@ -41,3 +41,4 @@ obj-$(CONFIG_USB_WACOM) += wacom.o ...@@ -41,3 +41,4 @@ obj-$(CONFIG_USB_WACOM) += wacom.o
obj-$(CONFIG_USB_ACECAD) += acecad.o obj-$(CONFIG_USB_ACECAD) += acecad.o
obj-$(CONFIG_USB_YEALINK) += yealink.o obj-$(CONFIG_USB_YEALINK) += yealink.o
obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_XPAD) += xpad.o
obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o
This diff is collapsed.
...@@ -1446,7 +1446,6 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1446,7 +1446,6 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_APPLE 0x05ac #define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304 #define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_BLUETOOTH 0x1000
/* /*
* Alphabetically sorted blacklist by quirk type. * Alphabetically sorted blacklist by quirk type.
...@@ -1465,7 +1464,6 @@ static struct hid_blacklist { ...@@ -1465,7 +1464,6 @@ static struct hid_blacklist {
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_BLUETOOTH, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
......
...@@ -9,6 +9,38 @@ config USB_SISUSBVGA ...@@ -9,6 +9,38 @@ config USB_SISUSBVGA
Note that this device requires a USB 2.0 host controller. It will not Note that this device requires a USB 2.0 host controller. It will not
work with USB 1.x controllers. work with USB 1.x controllers.
To compile this driver as a module, choose M here: the module will be To compile this driver as a module, choose M here; the module will be
called sisusb. If unsure, say N. called sisusbvga. If unsure, say N.
config USB_SISUSBVGA_CON
bool "Text console and mode switching support" if USB_SISUSBVGA
depends on VT
select FONT_8x16
---help---
Say Y here if you want a VGA text console via the USB dongle or
want to support userland applications that utilize the driver's
display mode switching capabilities.
Note that this console supports VGA/EGA text mode only.
By default, the console part of the driver will not kick in when
the driver is initialized. If you want the driver to take over
one or more of the consoles, you need to specify the number of
the first and last consoles (starting at 1) as driver parameters.
For example, if the driver is compiled as a module:
modprobe sisusbvga first=1 last=5
If you use hotplug, add this to your modutils config files with
the "options" keyword, such as eg.
options sisusbvga first=1 last=5
If the driver is compiled into the kernel image, the parameters
must be given in the kernel command like, such as
sisusbvga.first=1 sisusbvga.last=5
...@@ -2,5 +2,7 @@ ...@@ -2,5 +2,7 @@
# Makefile for the sisusb driver (if driver is inside kernel tree). # Makefile for the sisusb driver (if driver is inside kernel tree).
# #
obj-$(CONFIG_USB_SISUSBVGA) += sisusb.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o
sisusbvga-objs := sisusb.o sisusb_init.o sisusb_con.o
This diff is collapsed.
...@@ -46,15 +46,36 @@ ...@@ -46,15 +46,36 @@
#endif #endif
#endif #endif
/* For older kernels, support for text consoles is by default
* off. To ensable text console support, change the following:
*/
#if 0
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
#define CONFIG_USB_SISUSBVGA_CON
#endif
#endif
/* Version Information */ /* Version Information */
#define SISUSB_VERSION 0 #define SISUSB_VERSION 0
#define SISUSB_REVISION 0 #define SISUSB_REVISION 0
#define SISUSB_PATCHLEVEL 7 #define SISUSB_PATCHLEVEL 8
/* Include console and mode switching code? */
#ifdef CONFIG_USB_SISUSBVGA_CON
#define INCL_SISUSB_CON 1
#endif
#ifdef INCL_SISUSB_CON
#include <linux/console.h>
#include <linux/vt_kern.h>
#include "sisusb_struct.h"
#endif
/* USB related */ /* USB related */
#define SISUSB_MINOR 133 /* FIXME */ #define SISUSB_MINOR 133 /* official */
/* Size of the sisusb input/output buffers */ /* Size of the sisusb input/output buffers */
#define SISUSB_IBUF_SIZE 0x01000 #define SISUSB_IBUF_SIZE 0x01000
...@@ -131,6 +152,26 @@ struct sisusb_usb_data { ...@@ -131,6 +152,26 @@ struct sisusb_usb_data {
unsigned char gfxinit; /* graphics core initialized? */ unsigned char gfxinit; /* graphics core initialized? */
unsigned short chipid, chipvendor; unsigned short chipid, chipvendor;
unsigned short chiprevision; unsigned short chiprevision;
#ifdef INCL_SISUSB_CON
struct SiS_Private *SiS_Pr;
unsigned long scrbuf;
unsigned int scrbuf_size;
int haveconsole, con_first, con_last;
int havethisconsole[MAX_NR_CONSOLES];
int textmodedestroyed;
unsigned int sisusb_num_columns; /* real number, not vt's idea */
int cur_start_addr, con_rolled_over;
int sisusb_cursor_loc, bad_cursor_pos;
int sisusb_cursor_size_from;
int sisusb_cursor_size_to;
int current_font_height, current_font_512;
int font_backup_size, font_backup_height, font_backup_512;
char *font_backup;
int font_slot;
struct vc_data *sisusb_display_fg;
int is_gfx;
int con_blanked;
#endif
}; };
#define to_sisusb_dev(d) container_of(d, struct sisusb_usb_data, kref) #define to_sisusb_dev(d) container_of(d, struct sisusb_usb_data, kref)
...@@ -249,7 +290,9 @@ struct sisusb_info { ...@@ -249,7 +290,9 @@ struct sisusb_info {
__u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
__u8 sisusb_reserved[32]; /* for future use */ __u32 sisusb_conactive; /* != 0 if console driver active */
__u8 sisusb_reserved[28]; /* for future use */
}; };
struct sisusb_command { struct sisusb_command {
...@@ -270,9 +313,15 @@ struct sisusb_command { ...@@ -270,9 +313,15 @@ struct sisusb_command {
#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */ #define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */
#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
#define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */
#define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */
#define SISUSB_COMMAND _IOWR(0xF3,0x3D,struct sisusb_command) #define SISUSB_COMMAND _IOWR(0xF3,0x3D,struct sisusb_command)
#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32) #define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32)
#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info) #define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info)
#endif /* SISUSB_H */ #endif /* SISUSB_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* General structure definitions for universal mode switching modules
*
* Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria
*
* If distributed as part of the Linux kernel, the following license terms
* apply:
*
* * This program is free software; you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation; either version 2 of the named License,
* * or any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program; if not, write to the Free Software
* * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*
* Otherwise, the following license terms apply:
*
* * Redistribution and use in source and binary forms, with or without
* * modification, are permitted provided that the following conditions
* * are met:
* * 1) Redistributions of source code must retain the above copyright
* * notice, this list of conditions and the following disclaimer.
* * 2) Redistributions in binary form must reproduce the above copyright
* * notice, this list of conditions and the following disclaimer in the
* * documentation and/or other materials provided with the distribution.
* * 3) The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission.
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
#ifndef _SISUSB_STRUCT_H_
#define _SISUSB_STRUCT_H_
struct SiS_St {
unsigned char St_ModeID;
unsigned short St_ModeFlag;
unsigned char St_StTableIndex;
unsigned char St_CRT2CRTC;
unsigned char St_ResInfo;
unsigned char VB_StTVFlickerIndex;
unsigned char VB_StTVEdgeIndex;
unsigned char VB_StTVYFilterIndex;
unsigned char St_PDC;
};
struct SiS_StandTable
{
unsigned char CRT_COLS;
unsigned char ROWS;
unsigned char CHAR_HEIGHT;
unsigned short CRT_LEN;
unsigned char SR[4];
unsigned char MISC;
unsigned char CRTC[0x19];
unsigned char ATTR[0x14];
unsigned char GRC[9];
};
struct SiS_StResInfo_S {
unsigned short HTotal;
unsigned short VTotal;
};
struct SiS_Ext
{
unsigned char Ext_ModeID;
unsigned short Ext_ModeFlag;
unsigned short Ext_VESAID;
unsigned char Ext_RESINFO;
unsigned char VB_ExtTVFlickerIndex;
unsigned char VB_ExtTVEdgeIndex;
unsigned char VB_ExtTVYFilterIndex;
unsigned char VB_ExtTVYFilterIndexROM661;
unsigned char REFindex;
char ROMMODEIDX661;
};
struct SiS_Ext2
{
unsigned short Ext_InfoFlag;
unsigned char Ext_CRT1CRTC;
unsigned char Ext_CRTVCLK;
unsigned char Ext_CRT2CRTC;
unsigned char Ext_CRT2CRTC_NS;
unsigned char ModeID;
unsigned short XRes;
unsigned short YRes;
unsigned char Ext_PDC;
unsigned char Ext_FakeCRT2CRTC;
unsigned char Ext_FakeCRT2Clk;
};
struct SiS_CRT1Table
{
unsigned char CR[17];
};
struct SiS_VCLKData
{
unsigned char SR2B,SR2C;
unsigned short CLOCK;
};
struct SiS_ModeResInfo
{
unsigned short HTotal;
unsigned short VTotal;
unsigned char XChar;
unsigned char YChar;
};
struct SiS_Private
{
void *sisusb;
unsigned long IOAddress;
unsigned long SiS_P3c4;
unsigned long SiS_P3d4;
unsigned long SiS_P3c0;
unsigned long SiS_P3ce;
unsigned long SiS_P3c2;
unsigned long SiS_P3ca;
unsigned long SiS_P3c6;
unsigned long SiS_P3c7;
unsigned long SiS_P3c8;
unsigned long SiS_P3c9;
unsigned long SiS_P3cb;
unsigned long SiS_P3cc;
unsigned long SiS_P3cd;
unsigned long SiS_P3da;
unsigned long SiS_Part1Port;
unsigned char SiS_MyCR63;
unsigned short SiS_CRT1Mode;
unsigned short SiS_ModeType;
unsigned short SiS_SetFlag;
const struct SiS_StandTable *SiS_StandTable;
const struct SiS_St *SiS_SModeIDTable;
const struct SiS_Ext *SiS_EModeIDTable;
const struct SiS_Ext2 *SiS_RefIndex;
const struct SiS_CRT1Table *SiS_CRT1Table;
struct SiS_VCLKData *SiS_VCLKData;
const struct SiS_ModeResInfo *SiS_ModeResInfo;
};
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment