X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/14f5c350584f1b0f282cfe7724965fb44494b3eb..23314df94957bf3c355b60b66ea7a6fee7ebaecf:/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c diff --git a/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c b/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c index b4a1899d1..87bfcc6c7 100644 --- a/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c +++ b/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c @@ -3,25 +3,35 @@ * * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) * - * Based on the ADMtek 2.4 driver + * Based on the ADMtek 2.4 driver * (C) Copyright 2003 Junius Chen * Which again was based on the ohci and uhci drivers. */ -#include -#include -#include +#include +#include +#include +#include #include -#include +#include +#include #include #include +#include +#include +#include +#include +#include + #include "../core/hcd.h" MODULE_DESCRIPTION("ADM5120 USB Host Controller Driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jeroen Vreeken (pe1rxq@amsat.org)"); +#define PFX "adm5120-hcd: " + #define ADMHCD_REG_CONTROL 0x00 #define ADMHCD_REG_INTSTATUS 0x04 #define ADMHCD_REG_INTENABLE 0x08 @@ -137,13 +147,33 @@ static int admhcd_td_err[16] = { #define ED(ed) ((struct admhcd_ed *)(((u32)(ed)) & ~0xf)) struct admhcd { + spinlock_t lock; + + void __iomem *addr_reg; + void __iomem *data_reg; + /* Root hub registers */ + u32 rhdesca; + u32 rhdescb; + u32 rhstatus; + u32 rhport[2]; + + /* async schedule: control, bulk */ + struct list_head async; u32 base; u32 dma_en; - spinlock_t lock; unsigned long flags; + }; -#define hcd_to_admhcd(hcd) ((struct admhcd *)(hcd)->hcd_priv) +static inline struct admhcd *hcd_to_admhcd(struct usb_hcd *hcd) +{ + return (struct admhcd *)(hcd->hcd_priv); +} + +static inline struct usb_hcd *admhcd_to_hcd(struct admhcd *admhcd) +{ + return container_of((void *)admhcd, struct usb_hcd, hcd_priv); +} static char hcd_name[] = "adm5120-hcd"; @@ -185,7 +215,7 @@ static struct admhcd_td *admhcd_td_alloc(struct admhcd_ed *ed, struct urb *urb) if (ed->cur == NULL) { ed->cur = tdn; ed->head = tdn; - ed->tail = tdn; + ed->tail = tdn; td = tdn; } else { /* Supply back the old tail and link in new td as tail */ @@ -300,9 +330,8 @@ static void admhcd_ed_start(struct admhcd *ahcd, struct admhcd_ed *ed) ahcd->dma_en |= ADMHCD_DMA_EN; } -static irqreturn_t adm5120hcd_irq(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t adm5120hcd_irq(struct usb_hcd *hcd) { - struct usb_hcd *hcd = (struct usb_hcd *)ptr; struct admhcd *ahcd = hcd_to_admhcd(hcd); u32 intstatus; @@ -317,7 +346,7 @@ static irqreturn_t adm5120hcd_irq(int irq, void *ptr, struct pt_regs *regs) } if (intstatus & ADMHCD_INT_TD) { struct admhcd_ed *ed, *head; - + admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS, ADMHCD_INT_TD); head = (struct admhcd_ed *)admhcd_reg_get(ahcd, ADMHCD_REG_HOSTHEAD); @@ -327,7 +356,7 @@ static irqreturn_t adm5120hcd_irq(int irq, void *ptr, struct pt_regs *regs) if (ed->urb && !(ed->cur->control & ADMHCD_TD_OWN)) { struct admhcd_td *td; int error; - + td = ed->cur; error = (td->control & ADMHCD_TD_ERRMASK) >> ADMHCD_TD_ERRSHIFT; @@ -348,7 +377,7 @@ static irqreturn_t adm5120hcd_irq(int irq, void *ptr, struct pt_regs *regs) } static int admhcd_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, - struct urb *urb, int mem_flags) + struct urb *urb, gfp_t mem_flags) { struct admhcd *ahcd = hcd_to_admhcd(hcd); struct admhcd_ed *ed; @@ -414,7 +443,7 @@ static int admhcd_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, td = admhcd_td_fill(ADMHCD_TD_SETUP | ADMHCD_TD_DATA0, td, (dma_addr_t)urb->setup_packet, 8); while (data_len > 0) { - td = admhcd_td_fill(ADMHCD_TD_DATA1 + td = admhcd_td_fill(ADMHCD_TD_DATA1 | ADMHCD_TD_R | (usb_pipeout(pipe) ? ADMHCD_TD_OUT : ADMHCD_TD_IN), td, @@ -431,7 +460,7 @@ static int admhcd_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, i = 0; while(data_len > 4096) { td = admhcd_td_fill((usb_pipeout(pipe) ? - ADMHCD_TD_OUT : + ADMHCD_TD_OUT : ADMHCD_TD_IN | ADMHCD_TD_R) | (i ? ADMHCD_TD_TOGGLE : toggle), td, data, 4096); @@ -439,7 +468,7 @@ static int admhcd_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, data_len -= 4096; i++; } - td = admhcd_td_fill((usb_pipeout(pipe) ? + td = admhcd_td_fill((usb_pipeout(pipe) ? ADMHCD_TD_OUT : ADMHCD_TD_IN) | (i ? ADMHCD_TD_TOGGLE : toggle), td, data, data_len); i++; @@ -588,7 +617,7 @@ static int admhcd_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_RESET: if (admhcd_reg_get(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4) & ADMHCD_CCS) { - admhcd_reg_set(ahcd, + admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4, ADMHCD_PRS | ADMHCD_CSC); mdelay(50); @@ -661,6 +690,7 @@ static struct hc_driver adm5120_hc_driver = { .description = hcd_name, .product_desc = "ADM5120 HCD", .hcd_priv_size = sizeof(struct admhcd), + .irq = adm5120hcd_irq, .flags = HCD_USB11, .urb_enqueue = admhcd_urb_enqueue, .urb_dequeue = admhcd_urb_dequeue, @@ -670,49 +700,79 @@ static struct hc_driver adm5120_hc_driver = { .hub_control = admhcd_hub_control, }; +#define resource_len(r) (((r)->end - (r)->start) + 1) + static int __init adm5120hcd_probe(struct platform_device *pdev) { - struct usb_hcd *hcd; - struct admhcd *ahcd; - struct usb_device *udev; - int err = 0; + struct usb_hcd *hcd; + struct admhcd *ahcd; + struct resource *addr, *data; + void __iomem *addr_reg; + void __iomem *data_reg; - if (!request_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start, hcd_name)) { - pr_debug("couldn't request mem\n"); - err = -EBUSY; - goto out; - } - - //hcd = usb_create_hcd(&adm5120_hc_driver, pdev, pdev->bus_id); - if (!hcd) - goto out_mem; + int err = 0, irq; + if (pdev->num_resources < 3) { + err = -ENODEV; + goto out; + } + + if (pdev->dev.dma_mask) { + printk(KERN_DEBUG "no we won't dma\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + data = platform_get_resource(pdev, IORESOURCE_MEM, 0); + addr = platform_get_resource(pdev, IORESOURCE_MEM, 1); + + if (!addr || !data || irq < 0) { + err = -ENODEV; + goto out; + } + + if (!request_mem_region(addr->start, 2, hcd_name)) { + err = -EBUSY; + goto out; + } + + addr_reg = ioremap(addr->start, resource_len(addr)); + if (addr_reg == NULL) { + err = -ENOMEM; + goto out_mem; + } + if (!request_mem_region(data->start, 2, hcd_name)) { + err = -EBUSY; + goto out_unmap; + } + + data_reg = ioremap(data->start, resource_len(data)); + if (data_reg == NULL) { + err = -ENOMEM; + goto out_mem; + } + + hcd = usb_create_hcd(&adm5120_hc_driver, &pdev->dev, pdev->dev.bus_id); + if (!hcd) + goto out_mem; + + hcd->rsrc_start = addr->start; ahcd = hcd_to_admhcd(hcd); - dev_set_drvdata(pdev, ahcd); - hcd->self.controller = pdev; - //hcd->self.bus_name = pdev->bus_id; - hcd->irq = pdev->resource[1].start; - hcd->regs = (void *)pdev->resource[0].start; - hcd->product_desc = hcd_name; - ahcd->base = pdev->resource[0].start; - - if (request_irq(pdev->resource[1].start, adm5120hcd_irq, 0, hcd_name, - hcd)) { - pr_debug("couldn't request irq\n"); - err = -EBUSY; - goto out_hcd; - } - - //err = usb_register_bus(&hcd->self); - //if (err < 0) - // goto out_irq; spin_lock_init(&ahcd->lock); + INIT_LIST_HEAD(&ahcd->async); + + ahcd->data_reg = data_reg; + ahcd->addr_reg = addr_reg; + hcd->product_desc = "ADM5120 HCD"; + + /* Initialise the HCD registers */ admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0); mdelay(10); + admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_SW_RESET); + while (admhcd_reg_get(ahcd, ADMHCD_REG_CONTROL) & ADMHCD_SW_RESET) mdelay(1); @@ -727,41 +787,34 @@ static int __init adm5120hcd_probe(struct platform_device *pdev) admhcd_reg_set(ahcd, ADMHCD_REG_RHDESCR, ADMHCD_NPS | ADMHCD_LPSC); admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP); - udev = usb_alloc_dev(NULL, &hcd->self, 0); - if (!udev) { - err = -ENOMEM; - goto out_bus; - } - - udev->speed = USB_SPEED_FULL; - hcd->state = HC_STATE_RUNNING; - - //err = hcd_register_root(udev, hcd); - //if (err != 0) { - // usb_put_dev(udev); - // goto out_dev; - //} + err = usb_add_hcd(hcd, irq, IRQF_DISABLED); + if (err) + goto out_dev; return 0; out_dev: - usb_put_dev(udev); -out_bus: - //usb_deregister_bus(&hcd->self); -out_irq: - free_irq(pdev->resource[1].start, hcd); -out_hcd: usb_put_hcd(hcd); +out_unmap: + iounmap(addr_reg); out_mem: - release_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start); + release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start); out: return err; } static int __init_or_module adm5120hcd_remove(struct platform_device *pdev) { - device_init_wakeup(&pdev->dev, 0); + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct admhcd *ahcd; + + if (!hcd) + return 0; + ahcd = hcd_to_admhcd(hcd); + usb_remove_hcd(hcd); + + usb_put_hcd(hcd); + return 0; } static struct platform_driver adm5120hcd_driver = { @@ -775,9 +828,14 @@ static struct platform_driver adm5120hcd_driver = { static int __init adm5120hcd_init(void) { - if (usb_disabled()) + if (usb_disabled()) return -ENODEV; + if (!adm5120_board.has_usb) { + printk(KERN_DEBUG PFX "this board does not have USB\n"); + return -ENODEV; + } + printk(KERN_INFO PFX "registered\n"); return platform_driver_register(&adm5120hcd_driver); }