diff options
Diffstat (limited to 'target/linux/adm5120/patches-3.3/a15-adm5120-usb-driver-cleanup.patch')
-rw-r--r-- | target/linux/adm5120/patches-3.3/a15-adm5120-usb-driver-cleanup.patch | 582 |
1 files changed, 582 insertions, 0 deletions
diff --git a/target/linux/adm5120/patches-3.3/a15-adm5120-usb-driver-cleanup.patch b/target/linux/adm5120/patches-3.3/a15-adm5120-usb-driver-cleanup.patch new file mode 100644 index 0000000000..5994d43c8a --- /dev/null +++ b/target/linux/adm5120/patches-3.3/a15-adm5120-usb-driver-cleanup.patch @@ -0,0 +1,582 @@ +--- a/drivers/usb/host/adm5120.h ++++ b/drivers/usb/host/adm5120.h +@@ -403,6 +403,7 @@ struct admhcd { + * other external transceivers should be software-transparent + */ + struct otg_transceiver *transceiver; ++ void (*start_hnp)(struct admhcd *ahcd); + #endif + + /* +@@ -537,15 +538,7 @@ static inline struct usb_hcd *admhcd_to_ + * Big-endian read/write functions are arch-specific. + * Other arches can be added if/when they're needed. + * +- * REVISIT: arch/powerpc now has readl/writel_be, so the +- * definition below can die once the STB04xxx support is +- * finally ported over. + */ +-#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE) +-#define readl_be(addr) in_be32((__force unsigned *)addr) +-#define writel_be(val, addr) out_be32((__force unsigned *)addr, val) +-#endif +- + static inline unsigned int admhc_readl(const struct admhcd *ahcd, + __hc32 __iomem *regs) + { +--- a/drivers/usb/host/adm5120-drv.c ++++ b/drivers/usb/host/adm5120-drv.c +@@ -9,7 +9,7 @@ + * (C) Copyright 2002 Hewlett-Packard Company + * + * Written by Christopher Hoover <ch@hpl.hp.com> +- * Based on fragments of previous driver by Rusell King et al. ++ * Based on fragments of previous driver by Russell King et al. + * + * Modified for LH7A404 from ahcd-sa1111.c + * by Durgesh Pattamatta <pattamattad@sharpsec.com> +@@ -81,7 +81,7 @@ static int admhc_adm5120_probe(const str + + admhc_hcd_init(hcd_to_admhcd(hcd)); + +- retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); ++ retval = usb_add_hcd(hcd, irq, 0); + if (retval) + goto err_io; + +@@ -109,10 +109,7 @@ static void admhc_adm5120_remove(struct + usb_put_hcd(hcd); + } + +-/*-------------------------------------------------------------------------*/ +- +-static int __devinit +-admhc_adm5120_start(struct usb_hcd *hcd) ++static int __devinit admhc_adm5120_start(struct usb_hcd *hcd) + { + struct admhcd *ahcd = hcd_to_admhcd(hcd); + int ret; +@@ -137,8 +134,6 @@ err: + return ret; + } + +-/*-------------------------------------------------------------------------*/ +- + static const struct hc_driver adm5120_hc_driver = { + .description = hcd_name, + .product_desc = "ADM5120 built-in USB 1.1 Host Controller", +@@ -181,8 +176,6 @@ static const struct hc_driver adm5120_hc + .start_port_reset = admhc_start_port_reset, + }; + +-/*-------------------------------------------------------------------------*/ +- + static int usb_hcd_adm5120_probe(struct platform_device *pdev) + { + int ret; +--- a/drivers/usb/host/adm5120-dbg.c ++++ b/drivers/usb/host/adm5120-dbg.c +@@ -401,25 +401,28 @@ static const struct file_operations debu + .open = debug_async_open, + .read = debug_output, + .release = debug_close, ++ .llseek = default_llseek, + }; + static const struct file_operations debug_periodic_fops = { + .owner = THIS_MODULE, + .open = debug_periodic_open, + .read = debug_output, + .release = debug_close, ++ .llseek = default_llseek, + }; + static const struct file_operations debug_registers_fops = { + .owner = THIS_MODULE, + .open = debug_registers_open, + .read = debug_output, + .release = debug_close, ++ .llseek = default_llseek, + }; + + static struct dentry *admhc_debug_root; + + struct debug_buffer { + ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ +- struct device *dev; ++ struct admhcd *ahcd; + struct mutex mutex; /* protect filling of buffer */ + size_t count; /* number of characters filled into buffer */ + char *page; +@@ -494,15 +497,11 @@ show_list(struct admhcd *ahcd, char *buf + + static ssize_t fill_async_buffer(struct debug_buffer *buf) + { +- struct usb_bus *bus; +- struct usb_hcd *hcd; + struct admhcd *ahcd; + size_t temp; + unsigned long flags; + +- bus = dev_get_drvdata(buf->dev); +- hcd = bus_to_hcd(bus); +- ahcd = hcd_to_admhcd(hcd); ++ ahcd = buf->ahcd; + + spin_lock_irqsave(&ahcd->lock, flags); + temp = show_list(ahcd, buf->page, PAGE_SIZE, ahcd->ed_head); +@@ -516,8 +515,6 @@ static ssize_t fill_async_buffer(struct + + static ssize_t fill_periodic_buffer(struct debug_buffer *buf) + { +- struct usb_bus *bus; +- struct usb_hcd *hcd; + struct admhcd *ahcd; + struct ed **seen, *ed; + unsigned long flags; +@@ -530,9 +527,7 @@ static ssize_t fill_periodic_buffer(stru + return 0; + seen_count = 0; + +- bus = dev_get_drvdata(buf->dev); +- hcd = bus_to_hcd(bus); +- ahcd = hcd_to_admhcd(hcd); ++ ahcd = buf->ahcd; + next = buf->page; + size = PAGE_SIZE; + +@@ -615,7 +610,6 @@ static ssize_t fill_periodic_buffer(stru + + static ssize_t fill_registers_buffer(struct debug_buffer *buf) + { +- struct usb_bus *bus; + struct usb_hcd *hcd; + struct admhcd *ahcd; + struct admhcd_regs __iomem *regs; +@@ -624,9 +618,8 @@ static ssize_t fill_registers_buffer(str + char *next; + u32 rdata; + +- bus = dev_get_drvdata(buf->dev); +- hcd = bus_to_hcd(bus); +- ahcd = hcd_to_admhcd(hcd); ++ ahcd = buf->ahcd; ++ hcd = admhc_to_hcd(ahcd); + regs = ahcd->regs; + next = buf->page; + size = PAGE_SIZE; +@@ -638,13 +631,13 @@ static ssize_t fill_registers_buffer(str + admhc_dbg_sw(ahcd, &next, &size, + "bus %s, device %s\n" + "%s\n" +- "%s version " DRIVER_VERSION "\n", ++ "%s\n", + hcd->self.controller->bus->name, + dev_name(hcd->self.controller), + hcd->product_desc, + hcd_name); + +- if (bus->controller->power.power_state.event) { ++ if (!HCD_HW_ACCESSIBLE(hcd)) { + size -= scnprintf(next, size, + "SUSPENDED (no register access)\n"); + goto done; +@@ -691,7 +684,7 @@ done: + } + + +-static struct debug_buffer *alloc_buffer(struct device *dev, ++static struct debug_buffer *alloc_buffer(struct admhcd *ahcd, + ssize_t (*fill_func)(struct debug_buffer *)) + { + struct debug_buffer *buf; +@@ -699,7 +692,7 @@ static struct debug_buffer *alloc_buffer + buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); + + if (buf) { +- buf->dev = dev; ++ buf->ahcd = ahcd; + buf->fill_func = fill_func; + mutex_init(&buf->mutex); + } +@@ -792,26 +785,25 @@ static int debug_registers_open(struct i + static inline void create_debug_files(struct admhcd *ahcd) + { + struct usb_bus *bus = &admhcd_to_hcd(ahcd)->self; +- struct device *dev = bus->dev; + + ahcd->debug_dir = debugfs_create_dir(bus->bus_name, admhc_debug_root); + if (!ahcd->debug_dir) + goto dir_error; + + ahcd->debug_async = debugfs_create_file("async", S_IRUGO, +- ahcd->debug_dir, dev, ++ ahcd->debug_dir, ahcd, + &debug_async_fops); + if (!ahcd->debug_async) + goto async_error; + + ahcd->debug_periodic = debugfs_create_file("periodic", S_IRUGO, +- ahcd->debug_dir, dev, ++ ahcd->debug_dir, ahcd, + &debug_periodic_fops); + if (!ahcd->debug_periodic) + goto periodic_error; + + ahcd->debug_registers = debugfs_create_file("registers", S_IRUGO, +- ahcd->debug_dir, dev, ++ ahcd->debug_dir, ahcd, + &debug_registers_fops); + if (!ahcd->debug_registers) + goto registers_error; +--- a/drivers/usb/host/adm5120-pm.c ++++ b/drivers/usb/host/adm5120-pm.c +@@ -257,7 +257,7 @@ static int admhc_bus_suspend(struct usb_ + + spin_lock_irq(&ahcd->lock); + +- if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) ++ if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) + rc = -ESHUTDOWN; + else + rc = admhc_rh_suspend(ahcd, 0); +@@ -275,7 +275,7 @@ static int admhc_bus_resume(struct usb_h + + spin_lock_irq(&ahcd->lock); + +- if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) ++ if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) + rc = -ESHUTDOWN; + else + rc = admhc_rh_resume(ahcd); +--- a/drivers/usb/host/adm5120-hcd.c ++++ b/drivers/usb/host/adm5120-hcd.c +@@ -32,9 +32,9 @@ + #include <linux/list.h> + #include <linux/usb.h> + #include <linux/usb/otg.h> ++#include <linux/usb/hcd.h> + #include <linux/dma-mapping.h> + #include <linux/dmapool.h> +-#include <linux/reboot.h> + #include <linux/debugfs.h> + #include <linux/io.h> + +@@ -43,9 +43,6 @@ + #include <asm/unaligned.h> + #include <asm/byteorder.h> + +-#include "../core/hcd.h" +-#include "../core/hub.h" +- + #define DRIVER_VERSION "0.27.0" + #define DRIVER_AUTHOR "Gabor Juhos <juhosg@openwrt.org>" + #define DRIVER_DESC "ADMtek USB 1.1 Host Controller Driver" +@@ -117,7 +114,7 @@ static int admhc_urb_enqueue(struct usb_ + td_cnt = 2; + /* FALLTHROUGH */ + case PIPE_BULK: +- /* one TD for every 4096 Bytes (can be upto 8K) */ ++ /* one TD for every 4096 Bytes (can be up to 8K) */ + td_cnt += urb->transfer_buffer_length / TD_DATALEN_MAX; + /* ... and for any remaining bytes ... */ + if ((urb->transfer_buffer_length % TD_DATALEN_MAX) != 0) +@@ -153,7 +150,7 @@ static int admhc_urb_enqueue(struct usb_ + + spin_lock_irqsave(&ahcd->lock, flags); + /* don't submit to a dead HC */ +- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { ++ if (!HCD_HW_ACCESSIBLE(hcd)) { + ret = -ENODEV; + goto fail; + } +@@ -321,7 +318,6 @@ sanitize: + ep->hcpriv = NULL; + + spin_unlock_irqrestore(&ahcd->lock, flags); +- return; + } + + static int admhc_get_frame_number(struct usb_hcd *hcd) +@@ -488,7 +484,7 @@ err: + */ + static int admhc_run(struct admhcd *ahcd) + { +- u32 temp; ++ u32 val; + int first = ahcd->fminterval == 0; + struct usb_hcd *hcd = admhcd_to_hcd(ahcd); + +@@ -496,8 +492,8 @@ static int admhc_run(struct admhcd *ahcd + + /* boot firmware should have set this up (5.1.1.3.1) */ + if (first) { +- temp = admhc_readl(ahcd, &ahcd->regs->fminterval); +- ahcd->fminterval = temp & ADMHC_SFI_FI_MASK; ++ val = admhc_readl(ahcd, &ahcd->regs->fminterval); ++ ahcd->fminterval = val & ADMHC_SFI_FI_MASK; + if (ahcd->fminterval != FI) + admhc_dbg(ahcd, "fminterval delta %d\n", + ahcd->fminterval - FI); +@@ -507,30 +503,30 @@ static int admhc_run(struct admhcd *ahcd + } + + #if 0 /* TODO: not applicable */ +- /* Reset USB nearly "by the book". RemoteWakeupConnected was +- * saved if boot firmware (BIOS/SMM/...) told us it's connected, +- * or if bus glue did the same (e.g. for PCI add-in cards with +- * PCI PM support). ++ /* Reset USB nearly "by the book". RemoteWakeupConnected has ++ * to be checked in case boot firmware (BIOS/SMM/...) has set up ++ * wakeup in a way the bus isn't aware of (e.g., legacy PCI PM). ++ * If the bus glue detected wakeup capability then it should ++ * already be enabled; if so we'll just enable it again. + */ +- if ((ahcd->hc_control & OHCI_CTRL_RWC) != 0 +- && !device_may_wakeup(hcd->self.controller)) +- device_init_wakeup(hcd->self.controller, 1); ++ if ((ahcd->hc_control & OHCI_CTRL_RWC) != 0) ++ device_set_wakeup_capable(hcd->self.controller, 1); + #endif + + switch (ahcd->host_control & ADMHC_HC_BUSS) { + case ADMHC_BUSS_OPER: +- temp = 0; ++ val = 0; + break; + case ADMHC_BUSS_SUSPEND: + /* FALLTHROUGH ? */ + case ADMHC_BUSS_RESUME: + ahcd->host_control = ADMHC_BUSS_RESUME; +- temp = 10 /* msec wait */; ++ val = 10 /* msec wait */; + break; + /* case ADMHC_BUSS_RESET: */ + default: + ahcd->host_control = ADMHC_BUSS_RESET; +- temp = 50 /* msec wait */; ++ val = 50 /* msec wait */; + break; + } + admhc_writel(ahcd, ahcd->host_control, &ahcd->regs->host_control); +@@ -538,12 +534,12 @@ static int admhc_run(struct admhcd *ahcd + /* flush the writes */ + admhc_writel_flush(ahcd); + +- msleep(temp); +- temp = admhc_read_rhdesc(ahcd); +- if (!(temp & ADMHC_RH_NPS)) { ++ msleep(val); ++ val = admhc_read_rhdesc(ahcd); ++ if (!(val & ADMHC_RH_NPS)) { + /* power down each port */ +- for (temp = 0; temp < ahcd->num_ports; temp++) +- admhc_write_portstatus(ahcd, temp, ADMHC_PS_CPP); ++ for (val = 0; val < ahcd->num_ports; val++) ++ admhc_write_portstatus(ahcd, val, ADMHC_PS_CPP); + } + /* flush those writes */ + admhc_writel_flush(ahcd); +@@ -552,9 +548,9 @@ static int admhc_run(struct admhcd *ahcd + spin_lock_irq(&ahcd->lock); + + admhc_writel(ahcd, ADMHC_CTRL_SR, &ahcd->regs->gencontrol); +- temp = 30; /* ... allow extra time */ ++ val = 30; /* ... allow extra time */ + while ((admhc_readl(ahcd, &ahcd->regs->gencontrol) & ADMHC_CTRL_SR) != 0) { +- if (--temp == 0) { ++ if (--val == 0) { + spin_unlock_irq(&ahcd->lock); + admhc_err(ahcd, "USB HC reset timed out!\n"); + return -1; +@@ -571,7 +567,7 @@ static int admhc_run(struct admhcd *ahcd + periodic_reinit(ahcd); + + /* use rhsc irqs after khubd is fully initialized */ +- hcd->poll_rh = 1; ++ set_bit(HCD_FLAG_POLL_RH, &hcd->flags); + hcd->uses_new_polling = 1; + + #if 0 +@@ -594,10 +590,10 @@ static int admhc_run(struct admhcd *ahcd + ahcd->host_control = ADMHC_BUSS_OPER; + admhc_writel(ahcd, ahcd->host_control, &ahcd->regs->host_control); + +- temp = 20; ++ val = 20; + while ((admhc_readl(ahcd, &ahcd->regs->host_control) + & ADMHC_HC_BUSS) != ADMHC_BUSS_OPER) { +- if (--temp == 0) { ++ if (--val == 0) { + spin_unlock_irq(&ahcd->lock); + admhc_err(ahcd, "unable to setup operational mode!\n"); + return -1; +@@ -613,10 +609,10 @@ static int admhc_run(struct admhcd *ahcd + /* FIXME: enabling DMA is always failed here for an unknown reason */ + admhc_dma_enable(ahcd); + +- temp = 200; ++ val = 200; + while ((admhc_readl(ahcd, &ahcd->regs->host_control) + & ADMHC_HC_DMAE) != ADMHC_HC_DMAE) { +- if (--temp == 0) { ++ if (--val == 0) { + spin_unlock_irq(&ahcd->lock); + admhc_err(ahcd, "unable to enable DMA!\n"); + admhc_dump(ahcd, 1); +@@ -688,7 +684,7 @@ static irqreturn_t admhc_irq(struct usb_ + */ + admhc_vdbg(ahcd, "Resume Detect\n"); + admhc_intr_ack(ahcd, ADMHC_INTR_RESI); +- hcd->poll_rh = 1; ++ set_bit(HCD_FLAG_POLL_RH, &hcd->flags); + if (ahcd->autostop) { + spin_lock(&ahcd->lock); + admhc_rh_resume(ahcd); +@@ -799,9 +795,10 @@ static int __init admhc_hcd_mod_init(voi + pr_info("%s: " DRIVER_INFO "\n", hcd_name); + pr_info("%s: block sizes: ed %Zd td %Zd\n", hcd_name, + sizeof(struct ed), sizeof(struct td)); ++ set_bit(USB_OHCI_LOADED, &usb_hcds_loaded); + + #ifdef DEBUG +- admhc_debug_root = debugfs_create_dir("admhc", NULL); ++ admhc_debug_root = debugfs_create_dir("admhc", usb_debug_root); + if (!admhc_debug_root) { + ret = -ENOENT; + goto error_debug; +@@ -826,6 +823,7 @@ error_platform: + admhc_debug_root = NULL; + error_debug: + #endif ++ clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded); + return ret; + } + module_init(admhc_hcd_mod_init); +@@ -836,6 +834,7 @@ static void __exit admhc_hcd_mod_exit(vo + #ifdef DEBUG + debugfs_remove(admhc_debug_root); + #endif ++ clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded); + } + module_exit(admhc_hcd_mod_exit); + +--- a/drivers/usb/host/adm5120-hub.c ++++ b/drivers/usb/host/adm5120-hub.c +@@ -75,7 +75,7 @@ admhc_hub_status_data(struct usb_hcd *hc + u32 status; + + spin_lock_irqsave(&ahcd->lock, flags); +- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) ++ if (!HCD_HW_ACCESSIBLE(hcd)) + goto done; + + /* init status */ +@@ -106,8 +106,11 @@ admhc_hub_status_data(struct usb_hcd *hc + } + } + +- hcd->poll_rh = admhc_root_hub_state_changes(ahcd, changed, +- any_connected); ++ if (admhc_root_hub_state_changes(ahcd, changed, ++ any_connected)) ++ set_bit(HCD_FLAG_POLL_RH, &hcd->flags); ++ else ++ clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); + + done: + spin_unlock_irqrestore(&ahcd->lock, flags); +@@ -143,9 +146,9 @@ static int admhc_get_hub_descriptor(stru + temp |= 0x0008; + desc->wHubCharacteristics = (__force __u16)cpu_to_hc16(ahcd, temp); + +- /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ +- desc->bitmap[0] = 0; +- desc->bitmap[0] = ~0; ++ /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */ ++ desc->u.hs.DeviceRemovable[0] = 0; ++ desc->u.hs.DeviceRemovable[0] = ~0; + + return 0; + } +@@ -310,10 +313,10 @@ static int admhc_hub_control(struct usb_ + u16 wIndex, char *buf, u16 wLength) + { + struct admhcd *ahcd = hcd_to_admhcd(hcd); +- int ports = hcd_to_bus(hcd)->root_hub->maxchild; ++ int ports = ahcd->num_ports; + int ret = 0; + +- if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) ++ if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) + return -ESHUTDOWN; + + switch (typeReq) { +--- a/drivers/usb/host/adm5120-q.c ++++ b/drivers/usb/host/adm5120-q.c +@@ -14,6 +14,7 @@ + */ + + #include <linux/irq.h> ++#include <linux/slab.h> + + /*-------------------------------------------------------------------------*/ + +@@ -300,7 +301,7 @@ static struct ed *ed_get(struct admhcd * + u32 info; + + /* FIXME: usbcore changes dev->devnum before SET_ADDRESS +- * suceeds ... otherwise we wouldn't need "pipe". ++ * succeeds ... otherwise we wouldn't need "pipe". + */ + info = usb_pipedevice(pipe); + info |= (ep->desc.bEndpointAddress & ~USB_DIR_IN) << ED_EN_SHIFT; +@@ -634,8 +635,7 @@ static int td_done(struct admhcd *ahcd, + + /*-------------------------------------------------------------------------*/ + +-static inline void +-ed_halted(struct admhcd *ahcd, struct td *td, int cc, struct td *rev) ++static void ed_halted(struct admhcd *ahcd, struct td *td, int cc) + { + struct urb *urb = td->urb; + struct urb_priv *urb_priv = urb->hcpriv; +@@ -764,6 +764,7 @@ rescan_this: + struct urb *urb; + struct urb_priv *urb_priv; + __hc32 savebits; ++ u32 tdINFO; + int status; + + td = list_entry(entry, struct td, td_list); +@@ -781,6 +782,16 @@ rescan_this: + /* patch pointer hc uses */ + savebits = *prev & ~cpu_to_hc32(ahcd, TD_MASK); + *prev = td->hwNextTD | savebits; ++ /* If this was unlinked, the TD may not have been ++ * retired ... so manually save dhe data toggle. ++ * The controller ignores the value we save for ++ * control and ISO endpoints. ++ */ ++ tdINFO = hc32_to_cpup(ahcd, &td->hwINFO); ++ if ((tdINFO & TD_T) == TD_T_DATA0) ++ ed->hwHeadP &= ~cpu_to_hc32(ahcd, ED_C); ++ else if ((tdINFO & TD_T) == TD_T_DATA1) ++ ed->hwHeadP |= cpu_to_hc32(ahcd, ED_C); + + /* HC may have partly processed this TD */ + #ifdef ADMHC_VERBOSE_DEBUG +@@ -816,13 +827,12 @@ rescan_this: + } + + /*-------------------------------------------------------------------------*/ +- + /* + * Process normal completions (error or success) and clean the schedules. + * + * This is the main path for handing urbs back to drivers. The only other +- * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of +- * scanning the (re-reversed) donelist as this does. ++ * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, ++ * instead of scanning the (re-reversed) donelist as this does. + */ + + static void ed_unhalt(struct admhcd *ahcd, struct ed *ed, struct urb *urb) |