X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=blobdiff_plain;f=drivers%2Fusb%2Frenesas_usbhs%2Fmod_gadget.c;h=50c7566369eb7756abe841acb51c418be45b5937;hp=206cfabc92863e0d409e8c76a32bf3129883eeda;hb=dad67397f2090b29cd1f169e6a4ac6f3532c6858;hpb=1f3a8e093f470ef193b0ca6011d90180331c8b53 diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 206cfabc9286..50c7566369eb 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -26,21 +26,19 @@ */ struct usbhsg_request { struct usb_request req; - struct list_head node; + struct usbhs_pkt pkt; }; #define EP_NAME_SIZE 8 struct usbhsg_gpriv; -struct usbhsg_pipe_handle; struct usbhsg_uep { struct usb_ep ep; struct usbhs_pipe *pipe; - struct list_head list; char ep_name[EP_NAME_SIZE]; struct usbhsg_gpriv *gpriv; - struct usbhsg_pipe_handle *handler; + struct usbhs_pkt_handle *handler; }; struct usbhsg_gpriv { @@ -58,12 +56,6 @@ struct usbhsg_gpriv { #define USBHSG_STATUS_WEDGE (1 << 2) }; -struct usbhsg_pipe_handle { - int (*prepare)(struct usbhsg_uep *uep, struct usbhsg_request *ureq); - int (*try_run)(struct usbhsg_uep *uep, struct usbhsg_request *ureq); - void (*irq_mask)(struct usbhsg_uep *uep, int enable); -}; - struct usbhsg_recip_handle { char *name; int (*device)(struct usbhs_priv *priv, struct usbhsg_uep *uep, @@ -110,6 +102,10 @@ struct usbhsg_recip_handle { #define usbhsg_pipe_to_uep(p) ((p)->mod_private) #define usbhsg_is_dcp(u) ((u) == usbhsg_gpriv_to_dcp((u)->gpriv)) +#define usbhsg_ureq_to_pkt(u) (&(u)->pkt) +#define usbhsg_pkt_to_ureq(i) \ + container_of(i, struct usbhsg_request, pkt) + #define usbhsg_is_not_connected(gp) ((gp)->gadget.speed == USB_SPEED_UNKNOWN) /* status */ @@ -156,47 +152,45 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep, struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct device *dev = usbhsg_gpriv_to_dev(gpriv); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + struct usbhs_pkt *pkt = usbhsg_ureq_to_pkt(ureq); + struct usb_request *req = &ureq->req; /* ********* assume under spin lock ********* */ - list_del_init(&ureq->node); - list_add_tail(&ureq->node, &uep->list); - ureq->req.actual = 0; - ureq->req.status = -EINPROGRESS; + usbhs_pkt_push(pipe, pkt, uep->handler, + req->buf, req->length, req->zero); + req->actual = 0; + req->status = -EINPROGRESS; dev_dbg(dev, "pipe %d : queue push (%d)\n", usbhs_pipe_number(pipe), - ureq->req.length); + req->length); } static struct usbhsg_request *usbhsg_queue_get(struct usbhsg_uep *uep) { + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + struct usbhs_pkt *pkt = usbhs_pkt_get(pipe); + /* ********* assume under spin lock ********* */ - if (list_empty(&uep->list)) - return NULL; + if (!pkt) + return 0; - return list_entry(uep->list.next, struct usbhsg_request, node); + return usbhsg_pkt_to_ureq(pkt); } -#define usbhsg_queue_prepare(uep) __usbhsg_queue_handler(uep, 1); -#define usbhsg_queue_handle(uep) __usbhsg_queue_handler(uep, 0); -static int __usbhsg_queue_handler(struct usbhsg_uep *uep, int prepare) +static int usbhsg_queue_start(struct usbhsg_uep *uep) { struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - struct usbhsg_request *ureq; + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + struct usbhs_pkt *pkt; spinlock_t *lock; unsigned long flags; int ret = 0; - if (!uep->handler) { - dev_err(dev, "no handler function\n"); - return -EIO; - } - /* * CAUTION [*queue handler*] * @@ -218,13 +212,10 @@ static int __usbhsg_queue_handler(struct usbhsg_uep *uep, int prepare) /****************** spin try lock *******************/ lock = usbhsg_trylock(gpriv, &flags); - ureq = usbhsg_queue_get(uep); - if (ureq) { - if (prepare) - ret = uep->handler->prepare(uep, ureq); - else - ret = uep->handler->try_run(uep, ureq); - } + pkt = usbhs_pkt_get(pipe); + if (pkt) + ret = usbhs_pkt_start(pkt); + usbhsg_unlock(lock, &flags); /******************** spin unlock ******************/ @@ -238,6 +229,7 @@ static void usbhsg_queue_pop(struct usbhsg_uep *uep, struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); struct device *dev = usbhsg_gpriv_to_dev(gpriv); + struct usbhs_pkt *pkt = usbhsg_ureq_to_pkt(ureq); /* ********* assume under spin lock ********* @@ -263,265 +255,27 @@ static void usbhsg_queue_pop(struct usbhsg_uep *uep, dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe)); - list_del_init(&ureq->node); + usbhs_pkt_pop(pkt); ureq->req.status = status; ureq->req.complete(&uep->ep, &ureq->req); /* more request ? */ if (0 == status) - usbhsg_queue_prepare(uep); -} - -/* - * irq enable/disable function - */ -#define usbhsg_irq_callback_ctrl(uep, status, enable) \ - ({ \ - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); \ - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); \ - struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); \ - struct usbhs_mod *mod = usbhs_mod_get_current(priv); \ - if (!mod) \ - return; \ - if (enable) \ - mod->irq_##status |= (1 << usbhs_pipe_number(pipe)); \ - else \ - mod->irq_##status &= ~(1 << usbhs_pipe_number(pipe)); \ - usbhs_irq_callback_update(priv, mod); \ - }) - -static void usbhsg_irq_empty_ctrl(struct usbhsg_uep *uep, int enable) -{ - usbhsg_irq_callback_ctrl(uep, bempsts, enable); + usbhsg_queue_start(uep); } -static void usbhsg_irq_ready_ctrl(struct usbhsg_uep *uep, int enable) +static void usbhsg_queue_done(struct usbhs_pkt *pkt) { - usbhsg_irq_callback_ctrl(uep, brdysts, enable); -} + struct usbhs_pipe *pipe = pkt->pipe; + struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe); + struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); -/* - * handler function - */ -static int usbhsg_try_run_ctrl_stage_end(struct usbhsg_uep *uep, - struct usbhsg_request *ureq) -{ - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + ureq->req.actual = pkt->actual; - /* - ********* assume under spin lock ********* - */ - - usbhs_dcp_control_transfer_done(pipe); usbhsg_queue_pop(uep, ureq, 0); - - return 0; } -static int usbhsg_try_run_send_packet(struct usbhsg_uep *uep, - struct usbhsg_request *ureq) -{ - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - struct usb_request *req = &ureq->req; - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - void *buf; - int remainder, send; - int is_done = 0; - int enable; - int maxp; - - /* - ********* assume under spin lock ********* - */ - - maxp = usbhs_pipe_get_maxpacket(pipe); - buf = req->buf + req->actual; - remainder = req->length - req->actual; - - send = usbhs_fifo_write(pipe, buf, remainder); - - /* - * send < 0 : pipe busy - * send = 0 : send zero packet - * send > 0 : send data - * - * send <= max_packet - */ - if (send > 0) - req->actual += send; - - /* send all packet ? */ - if (send < remainder) - is_done = 0; /* there are remainder data */ - else if (send < maxp) - is_done = 1; /* short packet */ - else - is_done = !req->zero; /* send zero packet ? */ - - dev_dbg(dev, " send %d (%d/ %d/ %d/ %d)\n", - usbhs_pipe_number(pipe), - remainder, send, is_done, req->zero); - - /* - * enable interrupt and send again in irq handler - * if it still have remainder data which should be sent. - */ - enable = !is_done; - uep->handler->irq_mask(uep, enable); - - /* - * usbhs_fifo_enable execute - * - after callback_update, - * - before queue_pop / stage_end - */ - usbhs_fifo_enable(pipe); - - /* - * all data were sent ? - */ - if (is_done) { - /* it care below call in - "function mode" */ - if (usbhsg_is_dcp(uep)) - usbhs_dcp_control_transfer_done(pipe); - - usbhsg_queue_pop(uep, ureq, 0); - } - - return 0; -} - -static int usbhsg_prepare_send_packet(struct usbhsg_uep *uep, - struct usbhsg_request *ureq) -{ - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - - /* - ********* assume under spin lock ********* - */ - - usbhs_fifo_prepare_write(pipe); - usbhsg_try_run_send_packet(uep, ureq); - - return 0; -} - -static int usbhsg_try_run_receive_packet(struct usbhsg_uep *uep, - struct usbhsg_request *ureq) -{ - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - struct usb_request *req = &ureq->req; - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - void *buf; - int maxp; - int remainder, recv; - int is_done = 0; - - /* - ********* assume under spin lock ********* - */ - - maxp = usbhs_pipe_get_maxpacket(pipe); - buf = req->buf + req->actual; - remainder = req->length - req->actual; - - recv = usbhs_fifo_read(pipe, buf, remainder); - /* - * recv < 0 : pipe busy - * recv >= 0 : receive data - * - * recv <= max_packet - */ - if (recv < 0) - return -EBUSY; - - /* update parameters */ - req->actual += recv; - - if ((recv == remainder) || /* receive all data */ - (recv < maxp)) /* short packet */ - is_done = 1; - - dev_dbg(dev, " recv %d (%d/ %d/ %d/ %d)\n", - usbhs_pipe_number(pipe), - remainder, recv, is_done, req->zero); - - /* read all data ? */ - if (is_done) { - int disable = 0; - - uep->handler->irq_mask(uep, disable); - usbhs_fifo_disable(pipe); - usbhsg_queue_pop(uep, ureq, 0); - } - - return 0; -} - -static int usbhsg_prepare_receive_packet(struct usbhsg_uep *uep, - struct usbhsg_request *ureq) -{ - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - int enable = 1; - int ret; - - /* - ********* assume under spin lock ********* - */ - - ret = usbhs_fifo_prepare_read(pipe); - if (ret < 0) - return ret; - - /* - * data will be read in interrupt handler - */ - uep->handler->irq_mask(uep, enable); - - return ret; -} - -static struct usbhsg_pipe_handle usbhsg_handler_send_by_empty = { - .prepare = usbhsg_prepare_send_packet, - .try_run = usbhsg_try_run_send_packet, - .irq_mask = usbhsg_irq_empty_ctrl, -}; - -static struct usbhsg_pipe_handle usbhsg_handler_send_by_ready = { - .prepare = usbhsg_prepare_send_packet, - .try_run = usbhsg_try_run_send_packet, - .irq_mask = usbhsg_irq_ready_ctrl, -}; - -static struct usbhsg_pipe_handle usbhsg_handler_recv_by_ready = { - .prepare = usbhsg_prepare_receive_packet, - .try_run = usbhsg_try_run_receive_packet, - .irq_mask = usbhsg_irq_ready_ctrl, -}; - -static struct usbhsg_pipe_handle usbhsg_handler_ctrl_stage_end = { - .prepare = usbhsg_try_run_ctrl_stage_end, - .try_run = usbhsg_try_run_ctrl_stage_end, -}; - -/* - * DCP pipe can NOT use "ready interrupt" for "send" - * it should use "empty" interrupt. - * see - * "Operation" - "Interrupt Function" - "BRDY Interrupt" - * - * on the other hand, normal pipe can use "ready interrupt" for "send" - * even though it is single/double buffer - */ -#define usbhsg_handler_send_ctrl usbhsg_handler_send_by_empty -#define usbhsg_handler_recv_ctrl usbhsg_handler_recv_by_ready - -#define usbhsg_handler_send_packet usbhsg_handler_send_by_ready -#define usbhsg_handler_recv_packet usbhsg_handler_recv_by_ready - /* * USB_TYPE_STANDARD / clear feature functions */ @@ -546,14 +300,14 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv, struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); if (!usbhsg_status_has(gpriv, USBHSG_STATUS_WEDGE)) { - usbhs_fifo_disable(pipe); + usbhs_pipe_disable(pipe); usbhs_pipe_clear_sequence(pipe); - usbhs_fifo_enable(pipe); + usbhs_pipe_enable(pipe); } usbhsg_recip_handler_std_control_done(priv, uep, ctrl); - usbhsg_queue_prepare(uep); + usbhsg_queue_start(uep); return 0; } @@ -660,13 +414,13 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv, switch (stage) { case READ_DATA_STAGE: - dcp->handler = &usbhsg_handler_send_ctrl; + dcp->handler = &usbhs_fifo_push_handler; break; case WRITE_DATA_STAGE: - dcp->handler = &usbhsg_handler_recv_ctrl; + dcp->handler = &usbhs_fifo_pop_handler; break; case NODATA_STATUS_STAGE: - dcp->handler = &usbhsg_handler_ctrl_stage_end; + dcp->handler = &usbhs_ctrl_stage_end_handler; break; default: return ret; @@ -695,77 +449,11 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv, ret = gpriv->driver->setup(&gpriv->gadget, &ctrl); if (ret < 0) - usbhs_fifo_stall(pipe); + usbhs_pipe_stall(pipe); return ret; } -static int usbhsg_irq_empty(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state) -{ - struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); - struct usbhsg_uep *uep; - struct usbhs_pipe *pipe; - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - int i, ret; - - if (!irq_state->bempsts) { - dev_err(dev, "debug %s !!\n", __func__); - return -EIO; - } - - dev_dbg(dev, "irq empty [0x%04x]\n", irq_state->bempsts); - - /* - * search interrupted "pipe" - * not "uep". - */ - usbhs_for_each_pipe_with_dcp(pipe, priv, i) { - if (!(irq_state->bempsts & (1 << i))) - continue; - - uep = usbhsg_pipe_to_uep(pipe); - ret = usbhsg_queue_handle(uep); - if (ret < 0) - dev_err(dev, "send error %d : %d\n", i, ret); - } - - return 0; -} - -static int usbhsg_irq_ready(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state) -{ - struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); - struct usbhsg_uep *uep; - struct usbhs_pipe *pipe; - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - int i, ret; - - if (!irq_state->brdysts) { - dev_err(dev, "debug %s !!\n", __func__); - return -EIO; - } - - dev_dbg(dev, "irq ready [0x%04x]\n", irq_state->brdysts); - - /* - * search interrupted "pipe" - * not "uep". - */ - usbhs_for_each_pipe_with_dcp(pipe, priv, i) { - if (!(irq_state->brdysts & (1 << i))) - continue; - - uep = usbhsg_pipe_to_uep(pipe); - ret = usbhsg_queue_handle(uep); - if (ret < 0) - dev_err(dev, "receive error %d : %d\n", i, ret); - } - - return 0; -} - /* * * usb_dcp_ops @@ -787,7 +475,6 @@ static int usbhsg_dcp_enable(struct usbhsg_uep *uep) uep->pipe = pipe; uep->pipe->mod_private = uep; - INIT_LIST_HEAD(&uep->list); return 0; } @@ -797,19 +484,12 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep) { struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); struct usbhsg_request *ureq; - int disable = 0; /* ********* assume under spin lock ********* */ - usbhs_fifo_disable(pipe); - - /* - * disable pipe irq - */ - usbhsg_irq_empty_ctrl(uep, disable); - usbhsg_irq_ready_ctrl(uep, disable); + usbhs_pipe_disable(pipe); while (1) { ureq = usbhsg_queue_get(uep); @@ -861,12 +541,11 @@ static int usbhsg_ep_enable(struct usb_ep *ep, if (pipe) { uep->pipe = pipe; pipe->mod_private = uep; - INIT_LIST_HEAD(&uep->list); if (usb_endpoint_dir_in(desc)) - uep->handler = &usbhsg_handler_send_packet; + uep->handler = &usbhs_fifo_push_handler; else - uep->handler = &usbhsg_handler_recv_packet; + uep->handler = &usbhs_fifo_pop_handler; ret = 0; } @@ -905,7 +584,8 @@ static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, if (!ureq) return NULL; - INIT_LIST_HEAD(&ureq->node); + usbhs_pkt_init(usbhsg_ureq_to_pkt(ureq)); + return &ureq->req; } @@ -914,7 +594,7 @@ static void usbhsg_ep_free_request(struct usb_ep *ep, { struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); - WARN_ON(!list_empty(&ureq->node)); + WARN_ON(!list_empty(&ureq->pkt.node)); kfree(ureq); } @@ -960,7 +640,7 @@ static int usbhsg_ep_queue(struct usb_ep *ep, struct usb_request *req, usbhsg_unlock(lock, &flags); /******************** spin unlock ******************/ - usbhsg_queue_prepare(uep); + usbhsg_queue_start(uep); return ret; } @@ -1016,9 +696,9 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) halt, usbhs_pipe_number(pipe)); if (halt) - usbhs_fifo_stall(pipe); + usbhs_pipe_stall(pipe); else - usbhs_fifo_disable(pipe); + usbhs_pipe_disable(pipe); if (halt && wedge) usbhsg_status_set(gpriv, USBHSG_STATUS_WEDGE); @@ -1086,7 +766,9 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) /* * pipe initialize and enable DCP */ - usbhs_pipe_init(priv); + usbhs_pipe_init(priv, + usbhsg_queue_done); + usbhs_fifo_init(priv); usbhsg_uep_init(gpriv); usbhsg_dcp_enable(dcp); @@ -1105,10 +787,6 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) */ mod->irq_dev_state = usbhsg_irq_dev_state; mod->irq_ctrl_stage = usbhsg_irq_ctrl_stage; - mod->irq_empty = usbhsg_irq_empty; - mod->irq_ready = usbhsg_irq_ready; - mod->irq_bempsts = 0; - mod->irq_brdysts = 0; usbhs_irq_callback_update(priv, mod); usbhsg_try_start_unlock: @@ -1138,13 +816,11 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) !usbhsg_status_has(gpriv, USBHSG_STATUS_REGISTERD)) goto usbhsg_try_stop_unlock; + usbhs_fifo_quit(priv); + /* disable all irq */ mod->irq_dev_state = NULL; mod->irq_ctrl_stage = NULL; - mod->irq_empty = NULL; - mod->irq_ready = NULL; - mod->irq_bempsts = 0; - mod->irq_brdysts = 0; usbhs_irq_callback_update(priv, mod); usbhsg_dcp_disable(dcp); @@ -1350,7 +1026,6 @@ int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv) uep->ep.name = uep->ep_name; uep->ep.ops = &usbhsg_ep_ops; INIT_LIST_HEAD(&uep->ep.ep_list); - INIT_LIST_HEAD(&uep->list); /* init DCP */ if (usbhsg_is_dcp(uep)) {