if (dir) {
mask = ENDPTCTRL_TXT; /* type */
- data = type << ffs_nr(mask);
+ data = type << __ffs(mask);
mask |= ENDPTCTRL_TXS; /* unstall */
mask |= ENDPTCTRL_TXR; /* reset data toggle */
data |= ENDPTCTRL_TXE;
} else {
mask = ENDPTCTRL_RXT; /* type */
- data = type << ffs_nr(mask);
+ data = type << __ffs(mask);
mask |= ENDPTCTRL_RXS; /* unstall */
mask |= ENDPTCTRL_RXR; /* reset data toggle */
return reg;
}
-static void hw_enable_vbus_intr(struct ci13xxx *ci)
-{
- hw_write(ci, OP_OTGSC, OTGSC_AVVIS, OTGSC_AVVIS);
- hw_write(ci, OP_OTGSC, OTGSC_AVVIE, OTGSC_AVVIE);
- queue_work(ci->wq, &ci->vbus_work);
-}
-
-static void hw_disable_vbus_intr(struct ci13xxx *ci)
-{
- hw_write(ci, OP_OTGSC, OTGSC_AVVIE, 0);
-}
-
/**
* hw_test_and_clear_setup_guard: test & clear setup guard (execute without
* interruption)
static void hw_usb_set_address(struct ci13xxx *ci, u8 value)
{
hw_write(ci, OP_DEVICEADDR, DEVICEADDR_USBADR,
- value << ffs_nr(DEVICEADDR_USBADR));
+ value << __ffs(DEVICEADDR_USBADR));
}
/**
return 0;
}
-static void vbus_work(struct work_struct *work)
-{
- struct ci13xxx *ci = container_of(work, struct ci13xxx, vbus_work);
-
- if (hw_read(ci, OP_OTGSC, OTGSC_AVV))
- usb_gadget_vbus_connect(&ci->gadget);
- else
- usb_gadget_vbus_disconnect(&ci->gadget);
-}
-
/******************************************************************************
* UTIL block
*****************************************************************************/
return -ENOMEM;
memset(mReq->zptr, 0, sizeof(*mReq->zptr));
- mReq->zptr->next = TD_TERMINATE;
- mReq->zptr->token = TD_STATUS_ACTIVE;
+ mReq->zptr->next = cpu_to_le32(TD_TERMINATE);
+ mReq->zptr->token = cpu_to_le32(TD_STATUS_ACTIVE);
if (!mReq->req.no_interrupt)
- mReq->zptr->token |= TD_IOC;
+ mReq->zptr->token |= cpu_to_le32(TD_IOC);
}
ret = usb_gadget_map_request(&ci->gadget, &mReq->req, mEp->dir);
if (ret)
* TODO - handle requests which spawns into several TDs
*/
memset(mReq->ptr, 0, sizeof(*mReq->ptr));
- mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES);
- mReq->ptr->token &= TD_TOTAL_BYTES;
- mReq->ptr->token |= TD_STATUS_ACTIVE;
+ mReq->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
+ mReq->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
+ mReq->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE);
if (mReq->zptr) {
- mReq->ptr->next = mReq->zdma;
+ mReq->ptr->next = cpu_to_le32(mReq->zdma);
} else {
- mReq->ptr->next = TD_TERMINATE;
+ mReq->ptr->next = cpu_to_le32(TD_TERMINATE);
if (!mReq->req.no_interrupt)
- mReq->ptr->token |= TD_IOC;
+ mReq->ptr->token |= cpu_to_le32(TD_IOC);
+ }
+ mReq->ptr->page[0] = cpu_to_le32(mReq->req.dma);
+ for (i = 1; i < TD_PAGE_COUNT; i++) {
+ u32 page = mReq->req.dma + i * CI13XXX_PAGE_SIZE;
+ page &= ~TD_RESERVED_MASK;
+ mReq->ptr->page[i] = cpu_to_le32(page);
}
- mReq->ptr->page[0] = mReq->req.dma;
- for (i = 1; i < 5; i++)
- mReq->ptr->page[i] =
- (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
+
+ wmb();
if (!list_empty(&mEp->qh.queue)) {
struct ci13xxx_req *mReqPrev;
int n = hw_ep_bit(mEp->num, mEp->dir);
int tmp_stat;
+ u32 next = mReq->dma & TD_ADDR_MASK;
mReqPrev = list_entry(mEp->qh.queue.prev,
struct ci13xxx_req, queue);
if (mReqPrev->zptr)
- mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
+ mReqPrev->zptr->next = cpu_to_le32(next);
else
- mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+ mReqPrev->ptr->next = cpu_to_le32(next);
wmb();
if (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
goto done;
}
/* QH configuration */
- mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
- mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */
- mEp->qh.ptr->cap |= QH_ZLT;
+ mEp->qh.ptr->td.next = cpu_to_le32(mReq->dma); /* TERMINATE = 0 */
+ mEp->qh.ptr->td.token &=
+ cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
wmb(); /* synchronize before ep prime */
*/
static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
{
+ u32 tmptoken = le32_to_cpu(mReq->ptr->token);
+
if (mReq->req.status != -EALREADY)
return -EINVAL;
- if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
+ if ((TD_STATUS_ACTIVE & tmptoken) != 0)
return -EBUSY;
if (mReq->zptr) {
- if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
+ if ((cpu_to_le32(TD_STATUS_ACTIVE) & mReq->zptr->token) != 0)
return -EBUSY;
dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
mReq->zptr = NULL;
usb_gadget_unmap_request(&mEp->ci->gadget, &mReq->req, mEp->dir);
- mReq->req.status = mReq->ptr->token & TD_STATUS;
+ mReq->req.status = tmptoken & TD_STATUS;
if ((TD_STATUS_HALTED & mReq->req.status) != 0)
mReq->req.status = -1;
else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
mReq->req.status = -1;
- mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES;
- mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
+ mReq->req.actual = tmptoken & TD_TOTAL_BYTES;
+ mReq->req.actual >>= __ffs(TD_TOTAL_BYTES);
mReq->req.actual = mReq->req.length - mReq->req.actual;
mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
{
int retval;
- dbg_event(0xFF, "BUS RST", 0);
-
spin_unlock(&ci->lock);
retval = _gadget_stop_activity(&ci->gadget);
if (retval)
usb_ep_free_request(ep, req);
}
+/**
+ * _ep_queue: queues (submits) an I/O request to an endpoint
+ *
+ * Caller must hold lock
+ */
+static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
+ gfp_t __maybe_unused gfp_flags)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ struct ci13xxx *ci = mEp->ci;
+ int retval = 0;
+
+ if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
+ return -EINVAL;
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (req->length)
+ mEp = (ci->ep0_dir == RX) ?
+ ci->ep0out : ci->ep0in;
+ if (!list_empty(&mEp->qh.queue)) {
+ _ep_nuke(mEp);
+ retval = -EOVERFLOW;
+ dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
+ _usb_addr(mEp));
+ }
+ }
+
+ /* first nuke then test link, e.g. previous status has not sent */
+ if (!list_empty(&mReq->queue)) {
+ dev_err(mEp->ci->dev, "request already in queue\n");
+ return -EBUSY;
+ }
+
+ if (req->length > (TD_PAGE_COUNT - 1) * CI13XXX_PAGE_SIZE) {
+ dev_err(mEp->ci->dev, "request bigger than one td\n");
+ return -EMSGSIZE;
+ }
+
+ /* push request */
+ mReq->req.status = -EINPROGRESS;
+ mReq->req.actual = 0;
+
+ retval = _hardware_enqueue(mEp, mReq);
+
+ if (retval == -EALREADY)
+ retval = 0;
+ if (!retval)
+ list_add_tail(&mReq->queue, &mEp->qh.queue);
+
+ return retval;
+}
+
/**
* isr_get_status_response: get_status request response
* @ci: ci struct
}
/* else do nothing; reserved for future use */
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
- spin_lock(mEp->lock);
+ retval = _ep_queue(&mEp->ep, req, gfp_flags);
if (retval)
goto err_free_buf;
* This function returns an error code
*/
static int isr_setup_status_phase(struct ci13xxx *ci)
-__releases(mEp->lock)
-__acquires(mEp->lock)
{
int retval;
struct ci13xxx_ep *mEp;
ci->status->context = ci;
ci->status->complete = isr_setup_status_complete;
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
- spin_lock(mEp->lock);
+ retval = _ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
return retval;
}
if (retval < 0)
break;
list_del_init(&mReq->queue);
- dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
if (retval == -EBUSY)
retval = 0;
- if (retval < 0)
- dbg_event(_usb_addr(mEp), "DONE", retval);
return retval;
}
if (err > 0) /* needs status phase */
err = isr_setup_status_phase(ci);
if (err < 0) {
- dbg_event(_usb_addr(mEp),
- "ERROR", err);
spin_unlock(&ci->lock);
if (usb_ep_set_halt(&mEp->ep))
dev_err(ci->dev,
ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
- dbg_setup(_usb_addr(mEp), &req);
-
switch (req.bRequest) {
case USB_REQ_CLEAR_FEATURE:
if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
}
if (err < 0) {
- dbg_event(_usb_addr(mEp), "ERROR", err);
-
spin_unlock(&ci->lock);
if (usb_ep_set_halt(&mEp->ep))
dev_err(ci->dev, "error: ep_set_halt\n");
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
int retval = 0;
unsigned long flags;
+ u32 cap = 0;
if (ep == NULL || desc == NULL)
return -EINVAL;
mEp->ep.maxpacket = usb_endpoint_maxp(desc);
- dbg_event(_usb_addr(mEp), "ENABLE", 0);
-
- mEp->qh.ptr->cap = 0;
-
if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mEp->qh.ptr->cap |= QH_IOS;
- else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
- mEp->qh.ptr->cap &= ~QH_MULT;
- else
- mEp->qh.ptr->cap &= ~QH_ZLT;
+ cap |= QH_IOS;
+ if (mEp->num)
+ cap |= QH_ZLT;
+ cap |= (mEp->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
- mEp->qh.ptr->cap |=
- (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
- mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
+ mEp->qh.ptr->cap = cpu_to_le32(cap);
+
+ mEp->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE); /* needed? */
/*
* Enable endpoints in the HW other than ep0 as ep0
direction = mEp->dir;
do {
- dbg_event(_usb_addr(mEp), "DISABLE", 0);
-
retval |= _ep_nuke(mEp);
retval |= hw_ep_disable(mEp->ci, mEp->num, mEp->dir);
}
}
- dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
-
return (mReq == NULL) ? NULL : &mReq->req;
}
dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
kfree(mReq);
- dbg_event(_usb_addr(mEp), "FREE", 0);
-
spin_unlock_irqrestore(mEp->lock, flags);
}
gfp_t __maybe_unused gfp_flags)
{
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
- struct ci13xxx *ci = mEp->ci;
int retval = 0;
unsigned long flags;
return -EINVAL;
spin_lock_irqsave(mEp->lock, flags);
-
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
- if (req->length)
- mEp = (ci->ep0_dir == RX) ?
- ci->ep0out : ci->ep0in;
- if (!list_empty(&mEp->qh.queue)) {
- _ep_nuke(mEp);
- retval = -EOVERFLOW;
- dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
- _usb_addr(mEp));
- }
- }
-
- /* first nuke then test link, e.g. previous status has not sent */
- if (!list_empty(&mReq->queue)) {
- retval = -EBUSY;
- dev_err(mEp->ci->dev, "request already in queue\n");
- goto done;
- }
-
- if (req->length > 4 * CI13XXX_PAGE_SIZE) {
- req->length = 4 * CI13XXX_PAGE_SIZE;
- retval = -EMSGSIZE;
- dev_warn(mEp->ci->dev, "request length truncated\n");
- }
-
- dbg_queue(_usb_addr(mEp), req, retval);
-
- /* push request */
- mReq->req.status = -EINPROGRESS;
- mReq->req.actual = 0;
-
- retval = _hardware_enqueue(mEp, mReq);
-
- if (retval == -EALREADY) {
- dbg_event(_usb_addr(mEp), "QUEUE", retval);
- retval = 0;
- }
- if (!retval)
- list_add_tail(&mReq->queue, &mEp->qh.queue);
-
- done:
+ retval = _ep_queue(ep, req, gfp_flags);
spin_unlock_irqrestore(mEp->lock, flags);
return retval;
}
spin_lock_irqsave(mEp->lock, flags);
- dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
-
hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
/* pop request */
direction = mEp->dir;
do {
- dbg_event(_usb_addr(mEp), "HALT", value);
retval |= hw_ep_set_halt(mEp->ci, mEp->num, mEp->dir, value);
if (!value)
return -EINVAL;
spin_lock_irqsave(mEp->lock, flags);
-
- dbg_event(_usb_addr(mEp), "WEDGE", 0);
mEp->wedge = 1;
-
spin_unlock_irqrestore(mEp->lock, flags);
return usb_ep_set_halt(ep);
spin_lock_irqsave(mEp->lock, flags);
- dbg_event(_usb_addr(mEp), "FFLUSH", 0);
hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
spin_unlock_irqrestore(mEp->lock, flags);
if (is_active) {
pm_runtime_get_sync(&_gadget->dev);
hw_device_reset(ci, USBMODE_CM_DC);
- hw_enable_vbus_intr(ci);
hw_device_state(ci, ci->ep0out->qh.dma);
} else {
hw_device_state(ci, 0);
pm_runtime_get_sync(&ci->gadget.dev);
if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {
if (ci->vbus_active) {
- if (ci->platdata->flags & CI13XXX_REGS_SHARED) {
+ if (ci->platdata->flags & CI13XXX_REGS_SHARED)
hw_device_reset(ci, USBMODE_CM_DC);
- hw_enable_vbus_intr(ci);
- }
} else {
pm_runtime_put_sync(&ci->gadget.dev);
goto done;
}
}
intr = hw_test_and_clear_intr_active(ci);
- dbg_interrupt(intr);
if (intr) {
/* order defines priority - do NOT change it */
} else {
retval = IRQ_NONE;
}
-
- intr = hw_read(ci, OP_OTGSC, ~0);
- hw_write(ci, OP_OTGSC, ~0, intr);
-
- if (intr & (OTGSC_AVVIE & OTGSC_AVVIS))
- queue_work(ci->wq, &ci->vbus_work);
-
spin_unlock(&ci->lock);
return retval;
retval = hw_device_reset(ci, USBMODE_CM_DC);
if (retval)
goto put_transceiver;
- hw_enable_vbus_intr(ci);
}
retval = device_register(&ci->gadget.dev);
goto put_transceiver;
}
- retval = dbg_create_files(ci->dev);
- if (retval)
- goto unreg_device;
-
if (!IS_ERR_OR_NULL(ci->transceiver)) {
retval = otg_set_peripheral(ci->transceiver->otg,
&ci->gadget);
if (retval)
- goto remove_dbg;
+ goto unreg_device;
}
retval = usb_add_gadget_udc(dev, &ci->gadget);
}
dev_err(dev, "error = %i\n", retval);
-remove_dbg:
- dbg_remove_files(ci->dev);
unreg_device:
device_unregister(&ci->gadget.dev);
put_transceiver:
if (ci == NULL)
return;
- hw_disable_vbus_intr(ci);
- cancel_work_sync(&ci->vbus_work);
-
usb_del_gadget_udc(&ci->gadget);
destroy_eps(ci);
if (ci->global_phy)
usb_put_phy(ci->transceiver);
}
- dbg_remove_files(ci->dev);
device_unregister(&ci->gadget.dev);
/* my kobject is dynamic, I swear! */
memset(&ci->gadget, 0, sizeof(ci->gadget));
rdrv->irq = udc_irq;
rdrv->name = "gadget";
ci->roles[CI_ROLE_GADGET] = rdrv;
- INIT_WORK(&ci->vbus_work, vbus_work);
return 0;
}