#define ADMHCD_REG_PORTSTATUS1 0x7c
#define ADMHCD_REG_HOSTHEAD 0x80
-
#define ADMHCD_NUMPORTS 2
struct admhcd_ed {
static int admhcd_td_err[16] = {
0, /* No */
- -EREMOTEIO, /* CRC */
+ -EREMOTEIO, /* CRC */
-EREMOTEIO, /* bit stuff */
- -EREMOTEIO, /* data toggle */
+ -EREMOTEIO, /* data toggle */
-EPIPE, /* stall */
-ETIMEDOUT, /* timeout */
-EPROTO, /* pid err */
{
spin_lock_irqsave(&ahcd->lock, ahcd->flags);
ahcd->dma_en = admhcd_reg_get(ahcd, ADMHCD_REG_HOSTCONTROL) &
- ADMHCD_DMA_EN;
+ ADMHCD_DMA_EN;
admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP);
}
static void admhcd_unlock(struct admhcd *ahcd)
{
admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL,
- ADMHCD_STATE_OP | ahcd->dma_en);
+ ADMHCD_STATE_OP | ahcd->dma_en);
spin_unlock_irqrestore(&ahcd->lock, ahcd->flags);
}
{
struct admhcd_td *tdn, *td;
- tdn = kmalloc(sizeof(struct admhcd_td), GFP_ATOMIC);
+ tdn = kzalloc(sizeof(*tdn), GFP_ATOMIC);
if (!tdn)
return NULL;
+
tdn->real = tdn;
tdn = (struct admhcd_td *)KSEG1ADDR(tdn);
- memset(tdn, 0, sizeof(struct admhcd_td));
if (ed->cur == NULL) {
ed->cur = tdn;
ed->head = tdn;
in the DMA chain
*/
static struct admhcd_ed *admhcd_get_ed(struct admhcd *ahcd,
- struct usb_host_endpoint *ep, struct urb *urb)
+ struct usb_host_endpoint *ep, struct urb *urb)
{
struct admhcd_ed *hosthead;
struct admhcd_ed *found = NULL, *ed = NULL;
}
}
if (!found) {
- found = kmalloc(sizeof(struct admhcd_ed), GFP_ATOMIC);
+ found = kzalloc(sizeof(*found), GFP_ATOMIC);
if (!found)
goto out;
- memset(found, 0, sizeof(struct admhcd_ed));
found->real = found;
found->ep = ep;
found = (struct admhcd_ed *)KSEG1ADDR(found);
}
static struct admhcd_td *admhcd_td_fill(u32 control, struct admhcd_td *td,
- dma_addr_t data, int len)
+ dma_addr_t data, int len)
{
td->buffer = data;
td->buflen = len;
ahcd->dma_en |= ADMHCD_DMA_EN;
}
-static irqreturn_t adm5120hcd_irq(struct usb_hcd *hcd)
+static irqreturn_t admhcd_irq(struct usb_hcd *hcd)
{
struct admhcd *ahcd = hcd_to_admhcd(hcd);
u32 intstatus;
intstatus = admhcd_reg_get(ahcd, ADMHCD_REG_INTSTATUS);
if (intstatus & ADMHCD_INT_FATAL) {
admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS, ADMHCD_INT_FATAL);
- //
+ /* FIXME: handle fatal interrupts */
}
+
if (intstatus & ADMHCD_INT_SW) {
admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS, ADMHCD_INT_SW);
- //
+ /* FIXME: handle software interrupts */
}
+
if (intstatus & ADMHCD_INT_TD) {
struct admhcd_ed *ed, *head;
}
static int admhcd_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep,
- struct urb *urb, gfp_t mem_flags)
+ struct urb *urb, gfp_t mem_flags)
{
struct admhcd *ahcd = hcd_to_admhcd(hcd);
struct admhcd_ed *ed;
return -ENOMEM;
switch(usb_pipetype(pipe)) {
- case PIPE_CONTROL:
- size = 2;
- case PIPE_INTERRUPT:
- case PIPE_BULK:
- default:
- size += urb->transfer_buffer_length / 4096;
- if (urb->transfer_buffer_length % 4096)
- size++;
- if (size == 0)
- size++;
- else if (urb->transfer_flags & URB_ZERO_PACKET &&
- !(urb->transfer_buffer_length %
- usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe)))) {
- size++;
- zero = 1;
- }
- break;
- case PIPE_ISOCHRONOUS:
- size = urb->number_of_packets;
- break;
+ case PIPE_CONTROL:
+ size = 2;
+ case PIPE_INTERRUPT:
+ case PIPE_BULK:
+ default:
+ size += urb->transfer_buffer_length / 4096;
+ if (urb->transfer_buffer_length % 4096)
+ size++;
+ if (size == 0)
+ size++;
+ else if (urb->transfer_flags & URB_ZERO_PACKET &&
+ !(urb->transfer_buffer_length %
+ usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe)))) {
+ size++;
+ zero = 1;
+ }
+ break;
+ case PIPE_ISOCHRONOUS:
+ size = urb->number_of_packets;
+ break;
}
admhcd_lock(ahcd);
}
switch(usb_pipetype(pipe)) {
- case PIPE_CONTROL:
- 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
- | ADMHCD_TD_R |
- (usb_pipeout(pipe) ?
- ADMHCD_TD_OUT : ADMHCD_TD_IN), td,
- data, data_len % 4097);
- data_len -= 4096;
- }
- admhcd_td_fill(ADMHCD_TD_DATA1 | (usb_pipeout(pipe) ?
- ADMHCD_TD_IN : ADMHCD_TD_OUT), td,
- data, 0);
- break;
- case PIPE_INTERRUPT:
- case PIPE_BULK:
- //info ok for interrupt?
- i = 0;
- while(data_len > 4096) {
- td = admhcd_td_fill((usb_pipeout(pipe) ?
- ADMHCD_TD_OUT :
- ADMHCD_TD_IN | ADMHCD_TD_R) |
- (i ? ADMHCD_TD_TOGGLE : toggle), td,
- data, 4096);
- data += 4096;
- data_len -= 4096;
- i++;
- }
+ case PIPE_CONTROL:
+ 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
+ | ADMHCD_TD_R |
+ (usb_pipeout(pipe) ?
+ ADMHCD_TD_OUT : ADMHCD_TD_IN), td,
+ data, data_len % 4097);
+ data_len -= 4096;
+ }
+ admhcd_td_fill(ADMHCD_TD_DATA1 | (usb_pipeout(pipe) ?
+ ADMHCD_TD_IN : ADMHCD_TD_OUT), td,
+ data, 0);
+ break;
+ case PIPE_INTERRUPT:
+ case PIPE_BULK:
+ //info ok for interrupt?
+ i = 0;
+ while(data_len > 4096) {
td = admhcd_td_fill((usb_pipeout(pipe) ?
- ADMHCD_TD_OUT : ADMHCD_TD_IN) |
- (i ? ADMHCD_TD_TOGGLE : toggle), td, data, data_len);
+ ADMHCD_TD_OUT :
+ ADMHCD_TD_IN | ADMHCD_TD_R) |
+ (i ? ADMHCD_TD_TOGGLE : toggle), td,
+ data, 4096);
+ data += 4096;
+ data_len -= 4096;
i++;
- if (zero)
- admhcd_td_fill((usb_pipeout(pipe) ?
- ADMHCD_TD_OUT : ADMHCD_TD_IN) |
- (i ? ADMHCD_TD_TOGGLE : toggle), td, 0, 0);
- break;
- case PIPE_ISOCHRONOUS:
- for (i = 0; i < urb->number_of_packets; i++) {
- td = admhcd_td_fill(ADMHCD_TD_ISO |
- ((urb->start_frame + i) & 0xffff), td,
- data + urb->iso_frame_desc[i].offset,
- urb->iso_frame_desc[i].length);
- }
- break;
+ }
+ td = admhcd_td_fill((usb_pipeout(pipe) ?
+ ADMHCD_TD_OUT : ADMHCD_TD_IN) |
+ (i ? ADMHCD_TD_TOGGLE : toggle), td, data, data_len);
+ i++;
+ if (zero)
+ admhcd_td_fill((usb_pipeout(pipe) ?
+ ADMHCD_TD_OUT : ADMHCD_TD_IN) |
+ (i ? ADMHCD_TD_TOGGLE : toggle), td, 0, 0);
+ break;
+ case PIPE_ISOCHRONOUS:
+ for (i = 0; i < urb->number_of_packets; i++) {
+ td = admhcd_td_fill(ADMHCD_TD_ISO |
+ ((urb->start_frame + i) & 0xffff), td,
+ data + urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].length);
+ }
+ break;
}
urb->hcpriv = ed;
admhcd_ed_start(ahcd, ed);
}
for (edt = head; edt->next != ed; edt = edt->next);
edt->next = ed->next;
+
out_free:
kfree(ed->real);
out:
};
static int admhcd_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
- u16 wIndex, char *buf, u16 wLength)
+ u16 wIndex, char *buf, u16 wLength)
{
struct admhcd *ahcd = hcd_to_admhcd(hcd);
int retval = 0, len;
spin_lock_irqsave(&ahcd->lock, flags);
- /* Initialise the HCD registers */
- admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
- mdelay(10);
+ /* Initialise the HCD registers */
+ admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
+ mdelay(10);
- admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_SW_RESET);
+ admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_SW_RESET);
- while (admhcd_reg_get(ahcd, ADMHCD_REG_CONTROL) & ADMHCD_SW_RESET) {
+ while (admhcd_reg_get(ahcd, ADMHCD_REG_CONTROL) & ADMHCD_SW_RESET) {
printk(KERN_WARNING PFX "waiting for reset to complete\n");
- mdelay(1);
+ mdelay(1);
}
hcd->uses_new_polling = 1;
/* Enable USB host mode */
- admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_HOST_EN);
+ admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_HOST_EN);
/* Set host specific settings */
- admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, 0x00000000);
- admhcd_reg_set(ahcd, ADMHCD_REG_FMINTERVAL, 0x20002edf);
- admhcd_reg_set(ahcd, ADMHCD_REG_LSTHRESH, 0x628);
+ admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, 0x00000000);
+ admhcd_reg_set(ahcd, ADMHCD_REG_FMINTERVAL, 0x20002edf);
+ admhcd_reg_set(ahcd, ADMHCD_REG_LSTHRESH, 0x628);
/* Set interrupts */
- admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE,
- ADMHCD_INT_ACT | ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
- admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS,
- ADMHCD_INT_ACT | ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
+ admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, ADMHCD_INT_ACT |
+ ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
+ admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS, ADMHCD_INT_ACT |
+ ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
/* Power on all ports */
- admhcd_reg_set(ahcd, ADMHCD_REG_RHDESCR, ADMHCD_NPS | ADMHCD_LPSC);
+ admhcd_reg_set(ahcd, ADMHCD_REG_RHDESCR, ADMHCD_NPS | ADMHCD_LPSC);
/* HCD is now operationnal */
- admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP);
+ admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP);
- hcd->state = HC_STATE_RUNNING;
+ hcd->state = HC_STATE_RUNNING;
spin_unlock_irqrestore(&ahcd->lock, flags);
printk(KERN_DEBUG PFX "returning 0 from admhcd_start\n");
- return 0;
+ return 0;
}
static int admhcd_sw_reset(struct admhcd *ahcd)
spin_lock_irqsave(&ahcd->lock, flags);
admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
- mdelay(10);
+ mdelay(10);
- admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_SW_RESET);
+ admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_SW_RESET);
- while (--retries) {
+ while (--retries) {
mdelay(1);
if (!(admhcd_reg_get(ahcd, ADMHCD_REG_CONTROL) & ADMHCD_SW_RESET))
break;
static int admhcd_reset(struct usb_hcd *hcd)
{
struct admhcd *ahcd = hcd_to_admhcd(hcd);
- u32 state = 0;
+ u32 state = 0;
int ret, timeout = 15; /* ms */
unsigned long t;
t = jiffies + msecs_to_jiffies(timeout);
do {
- spin_lock_irq(&ahcd->lock);
- state = admhcd_reg_get(ahcd, ADMHCD_REG_HOSTCONTROL);
- spin_unlock_irq(&ahcd->lock);
+ spin_lock_irq(&ahcd->lock);
+ state = admhcd_reg_get(ahcd, ADMHCD_REG_HOSTCONTROL);
+ spin_unlock_irq(&ahcd->lock);
state &= ADMHCD_STATE_MASK;
- if (state == ADMHCD_STATE_RST)
- break;
- msleep(4);
+ if (state == ADMHCD_STATE_RST)
+ break;
+ msleep(4);
} while (time_before_eq(jiffies, t));
- if (state != ADMHCD_STATE_RST) {
- printk(KERN_WARNING "%s: device not ready after %dms\n",
+ if (state != ADMHCD_STATE_RST) {
+ printk(KERN_WARNING "%s: device not ready after %dms\n",
hcd_name, timeout);
- ret = -ENODEV;
- }
+ ret = -ENODEV;
+ }
- return ret;
+ return ret;
}
static void admhcd_stop(struct usb_hcd *hcd)
{
struct admhcd *ahcd = hcd_to_admhcd(hcd);
- unsigned long flags;
+ unsigned long flags;
u32 val;
- spin_lock_irqsave(&ahcd->lock, flags);
- admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
+ spin_lock_irqsave(&ahcd->lock, flags);
+ admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
/* Set global control of power for ports */
val = admhcd_reg_get(ahcd, ADMHCD_REG_RHDESCR);
.description = hcd_name,
.product_desc = "ADM5120 HCD",
.hcd_priv_size = sizeof(struct admhcd),
- .irq = adm5120hcd_irq,
+ .irq = admhcd_irq,
.flags = HCD_USB11,
.urb_enqueue = admhcd_urb_enqueue,
.urb_dequeue = admhcd_urb_dequeue,
static int __init adm5120hcd_probe(struct platform_device *pdev)
{
- struct usb_hcd *hcd;
- struct admhcd *ahcd;
+ struct usb_hcd *hcd;
+ struct admhcd *ahcd;
struct resource *data;
void __iomem *data_reg;
- int err = 0, irq;
+ int err = 0, irq;
if (pdev->num_resources < 2) {
printk(KERN_WARNING PFX "not enough resources\n");
err = -ENODEV;
goto out;
- }
+ }
irq = platform_get_irq(pdev, 0);
data = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (pdev->dev.dma_mask) {
- printk(KERN_DEBUG PFX "no we won't dma\n");
- return -EINVAL;
- }
+ printk(KERN_DEBUG PFX "no we won't dma\n");
+ return -EINVAL;
+ }
if (!data || irq < 0) {
printk(KERN_DEBUG PFX "either IRQ or data resource is invalid\n");
- err = -ENODEV;
- goto out;
- }
+ err = -ENODEV;
+ goto out;
+ }
- if (!request_mem_region(data->start, resource_len(data), hcd_name)) {
+ if (!request_mem_region(data->start, resource_len(data), hcd_name)) {
printk(KERN_DEBUG PFX "cannot request memory regions for the data resource\n");
- err = -EBUSY;
- goto out;
- }
+ err = -EBUSY;
+ goto out;
+ }
- data_reg = ioremap(data->start, resource_len(data));
- if (data_reg == NULL) {
+ data_reg = ioremap(data->start, resource_len(data));
+ if (data_reg == NULL) {
printk(KERN_DEBUG PFX "unable to ioremap\n");
- err = -ENOMEM;
- goto out_mem;
+ err = -ENOMEM;
+ goto out_mem;
}
hcd = usb_create_hcd(&adm5120_hc_driver, &pdev->dev, pdev->dev.bus_id);
- if (!hcd) {
+ if (!hcd) {
printk(KERN_DEBUG PFX "unable to create the hcd\n");
err = -ENOMEM;
- goto out_unmap;
+ goto out_unmap;
}
hcd->rsrc_start = data->start;