diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/host/uhci-debug.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.c | 40 | ||||
-rw-r--r-- | drivers/usb/host/uhci-hcd.h | 3 |
3 files changed, 28 insertions, 19 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 081c592fe8b1..ecef5880cfd9 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c | |||
@@ -289,7 +289,7 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) | |||
289 | unsigned short portsc1, portsc2; | 289 | unsigned short portsc1, portsc2; |
290 | 290 | ||
291 | /* Try to make sure there's enough memory */ | 291 | /* Try to make sure there's enough memory */ |
292 | if (len < 80 * 6) | 292 | if (len < 80 * 9) |
293 | return 0; | 293 | return 0; |
294 | 294 | ||
295 | usbcmd = inw(io_addr + 0); | 295 | usbcmd = inw(io_addr + 0); |
@@ -328,6 +328,8 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) | |||
328 | out += sprintf(out, " sof = %02x\n", sof); | 328 | out += sprintf(out, " sof = %02x\n", sof); |
329 | out += uhci_show_sc(1, portsc1, out, len - (out - buf)); | 329 | out += uhci_show_sc(1, portsc1, out, len - (out - buf)); |
330 | out += uhci_show_sc(2, portsc2, out, len - (out - buf)); | 330 | out += uhci_show_sc(2, portsc2, out, len - (out - buf)); |
331 | out += sprintf(out, "Most recent frame: %x\n", | ||
332 | uhci->frame_number); | ||
331 | 333 | ||
332 | return out - buf; | 334 | return out - buf; |
333 | } | 335 | } |
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 395402eec5ef..5e75ad6dc29f 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
@@ -13,7 +13,7 @@ | |||
13 | * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface | 13 | * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface |
14 | * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). | 14 | * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). |
15 | * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) | 15 | * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) |
16 | * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu | 16 | * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu |
17 | * | 17 | * |
18 | * Intel documents this fairly well, and as far as I know there | 18 | * Intel documents this fairly well, and as far as I know there |
19 | * are no royalties or anything like that, but even so there are | 19 | * are no royalties or anything like that, but even so there are |
@@ -31,7 +31,6 @@ | |||
31 | #include <linux/ioport.h> | 31 | #include <linux/ioport.h> |
32 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/smp_lock.h> | ||
35 | #include <linux/errno.h> | 34 | #include <linux/errno.h> |
36 | #include <linux/unistd.h> | 35 | #include <linux/unistd.h> |
37 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
@@ -146,7 +145,8 @@ static void configure_hc(struct uhci_hcd *uhci) | |||
146 | outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD); | 145 | outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD); |
147 | 146 | ||
148 | /* Set the current frame number */ | 147 | /* Set the current frame number */ |
149 | outw(uhci->frame_number, uhci->io_addr + USBFRNUM); | 148 | outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER, |
149 | uhci->io_addr + USBFRNUM); | ||
150 | 150 | ||
151 | /* Mark controller as not halted before we enable interrupts */ | 151 | /* Mark controller as not halted before we enable interrupts */ |
152 | uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED; | 152 | uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED; |
@@ -239,7 +239,6 @@ __acquires(uhci->lock) | |||
239 | dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); | 239 | dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); |
240 | 240 | ||
241 | uhci_get_current_frame_number(uhci); | 241 | uhci_get_current_frame_number(uhci); |
242 | smp_wmb(); | ||
243 | 242 | ||
244 | uhci->rh_state = new_state; | 243 | uhci->rh_state = new_state; |
245 | uhci->is_stopped = UHCI_IS_STOPPED; | 244 | uhci->is_stopped = UHCI_IS_STOPPED; |
@@ -253,7 +252,6 @@ static void start_rh(struct uhci_hcd *uhci) | |||
253 | { | 252 | { |
254 | uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; | 253 | uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; |
255 | uhci->is_stopped = 0; | 254 | uhci->is_stopped = 0; |
256 | smp_wmb(); | ||
257 | 255 | ||
258 | /* Mark it configured and running with a 64-byte max packet. | 256 | /* Mark it configured and running with a 64-byte max packet. |
259 | * All interrupts are enabled, even though RESUME won't do anything. | 257 | * All interrupts are enabled, even though RESUME won't do anything. |
@@ -360,12 +358,21 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) | |||
360 | 358 | ||
361 | /* | 359 | /* |
362 | * Store the current frame number in uhci->frame_number if the controller | 360 | * Store the current frame number in uhci->frame_number if the controller |
363 | * is runnning | 361 | * is runnning. Expand from 11 bits (of which we use only 10) to a |
362 | * full-sized integer. | ||
363 | * | ||
364 | * Like many other parts of the driver, this code relies on being polled | ||
365 | * more than once per second as long as the controller is running. | ||
364 | */ | 366 | */ |
365 | static void uhci_get_current_frame_number(struct uhci_hcd *uhci) | 367 | static void uhci_get_current_frame_number(struct uhci_hcd *uhci) |
366 | { | 368 | { |
367 | if (!uhci->is_stopped) | 369 | if (!uhci->is_stopped) { |
368 | uhci->frame_number = inw(uhci->io_addr + USBFRNUM); | 370 | unsigned delta; |
371 | |||
372 | delta = (inw(uhci->io_addr + USBFRNUM) - uhci->frame_number) & | ||
373 | (UHCI_NUMFRAMES - 1); | ||
374 | uhci->frame_number += delta; | ||
375 | } | ||
369 | } | 376 | } |
370 | 377 | ||
371 | /* | 378 | /* |
@@ -798,18 +805,15 @@ done: | |||
798 | static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) | 805 | static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) |
799 | { | 806 | { |
800 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 807 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
801 | unsigned long flags; | 808 | unsigned frame_number; |
802 | int is_stopped; | 809 | unsigned delta; |
803 | int frame_number; | ||
804 | 810 | ||
805 | /* Minimize latency by avoiding the spinlock */ | 811 | /* Minimize latency by avoiding the spinlock */ |
806 | local_irq_save(flags); | 812 | frame_number = uhci->frame_number; |
807 | is_stopped = uhci->is_stopped; | 813 | barrier(); |
808 | smp_rmb(); | 814 | delta = (inw(uhci->io_addr + USBFRNUM) - frame_number) & |
809 | frame_number = (is_stopped ? uhci->frame_number : | 815 | (UHCI_NUMFRAMES - 1); |
810 | inw(uhci->io_addr + USBFRNUM)); | 816 | return frame_number + delta; |
811 | local_irq_restore(flags); | ||
812 | return frame_number; | ||
813 | } | 817 | } |
814 | 818 | ||
815 | static const char hcd_name[] = "uhci_hcd"; | 819 | static const char hcd_name[] = "uhci_hcd"; |
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 04938e64799f..c87ceaa178b6 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h | |||
@@ -448,6 +448,9 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci) | |||
448 | 448 | ||
449 | #define uhci_dev(u) (uhci_to_hcd(u)->self.controller) | 449 | #define uhci_dev(u) (uhci_to_hcd(u)->self.controller) |
450 | 450 | ||
451 | /* Utility macro for comparing frame numbers */ | ||
452 | #define uhci_frame_before_eq(f1, f2) (0 <= (int) ((f2) - (f1))) | ||
453 | |||
451 | 454 | ||
452 | /* | 455 | /* |
453 | * Private per-URB data | 456 | * Private per-URB data |