udc->udc_driver->notify_event(udc,
CI13XXX_CONTROLLER_RESET_EVENT);
- if (udc->udc_driver->flags && CI13XXX_DISABLE_STREAMING)
+ if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
/* USBMODE should be configured step by step */
stamp = stamp * 1000000 + tval.tv_usec;
scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
- "%04X\t» %02X %-7.7s %4i «\t%s\n",
+ "%04X\t? %02X %-7.7s %4i ?\t%s\n",
stamp, addr, name, status, extra);
dbg_inc(&dbg_data.idx);
write_unlock_irqrestore(&dbg_data.lck, flags);
if (dbg_data.tty != 0)
- pr_notice("%04X\t» %02X %-7.7s %4i «\t%s\n",
+ pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
stamp, addr, name, status, extra);
}
n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
isr_statistics.test);
- n += scnprintf(buf + n, PAGE_SIZE - n, "» ui = %d\n",
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n",
isr_statistics.ui);
- n += scnprintf(buf + n, PAGE_SIZE - n, "» uei = %d\n",
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
isr_statistics.uei);
- n += scnprintf(buf + n, PAGE_SIZE - n, "» pci = %d\n",
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
isr_statistics.pci);
- n += scnprintf(buf + n, PAGE_SIZE - n, "» uri = %d\n",
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
isr_statistics.uri);
- n += scnprintf(buf + n, PAGE_SIZE - n, "» sli = %d\n",
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
isr_statistics.sli);
n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
isr_statistics.none);
*
* Check "device.h" for details
*/
+#define DUMP_ENTRIES 512
static ssize_t show_registers(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
unsigned long flags;
- u32 dump[512];
+ u32 *dump;
unsigned i, k, n = 0;
dbg_trace("[%s] %p\n", __func__, buf);
return 0;
}
+ dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
+ if (!dump) {
+ dev_err(dev, "%s: out of memory\n", __func__);
+ return 0;
+ }
+
spin_lock_irqsave(udc->lock, flags);
- k = hw_register_read(dump, sizeof(dump)/sizeof(u32));
+ k = hw_register_read(dump, DUMP_ENTRIES);
spin_unlock_irqrestore(udc->lock, flags);
for (i = 0; i < k; i++) {
"reg[0x%04X] = 0x%08X\n",
i * (unsigned)sizeof(u32), dump[i]);
}
+ kfree(dump);
return n;
}
gadget_for_each_ep(ep, gadget) {
usb_ep_disable(ep);
}
- usb_ep_disable(&udc->ep0out.ep);
- usb_ep_disable(&udc->ep0in.ep);
if (udc->status != NULL) {
usb_ep_free_request(&udc->ep0in.ep, udc->status);
if (retval)
goto done;
- retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc);
- if (retval)
- goto done;
+ udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
+ if (udc->status == NULL)
+ retval = -ENOMEM;
- retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc);
- if (!retval) {
- udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
- if (udc->status == NULL) {
- usb_ep_disable(&udc->ep0out.ep);
- retval = -ENOMEM;
- }
- }
spin_lock(udc->lock);
done:
__acquires(mEp->lock)
{
struct ci13xxx_req *mReq, *mReqTemp;
- int retval;
+ struct ci13xxx_ep *mEpTemp = mEp;
+ int uninitialized_var(retval);
trace("%p", mEp);
dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
- mReq->req.complete(&mEp->ep, &mReq->req);
+ if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+ mReq->req.length)
+ mEpTemp = &_udc->ep0in;
+ mReq->req.complete(&mEpTemp->ep, &mReq->req);
spin_lock(mEp->lock);
}
}
- if (retval == EBUSY)
+ if (retval == -EBUSY)
retval = 0;
if (retval < 0)
dbg_event(_usb_addr(mEp), "DONE", retval);
for (i = 0; i < hw_ep_max; i++) {
struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
- int type, num, err = -EINVAL;
+ int type, num, dir, err = -EINVAL;
struct usb_ctrlrequest req;
if (mEp->desc == NULL)
if (req.wLength != 0)
break;
num = le16_to_cpu(req.wIndex);
+ dir = num & USB_ENDPOINT_DIR_MASK;
num &= USB_ENDPOINT_NUMBER_MASK;
+ if (dir) /* TX */
+ num += hw_ep_max/2;
if (!udc->ci13xxx_ep[num].wedge) {
spin_unlock(udc->lock);
err = usb_ep_clear_halt(
if (req.wLength != 0)
break;
num = le16_to_cpu(req.wIndex);
+ dir = num & USB_ENDPOINT_DIR_MASK;
num &= USB_ENDPOINT_NUMBER_MASK;
+ if (dir) /* TX */
+ num += hw_ep_max/2;
spin_unlock(udc->lock);
err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
(mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
- retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
+ /*
+ * Enable endpoints in the HW other than ep0 as ep0
+ * is always enabled
+ */
+ if (mEp->num)
+ retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
spin_unlock_irqrestore(mEp->lock, flags);
return retval;
spin_lock_irqsave(mEp->lock, flags);
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL &&
- !list_empty(&mEp->qh.queue)) {
- _ep_nuke(mEp);
- retval = -EOVERFLOW;
- warn("endpoint ctrl %X nuked", _usb_addr(mEp));
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (req->length)
+ mEp = (_udc->ep0_dir == RX) ?
+ &_udc->ep0out : &_udc->ep0in;
+ if (!list_empty(&mEp->qh.queue)) {
+ _ep_nuke(mEp);
+ retval = -EOVERFLOW;
+ warn("endpoint ctrl %X nuked", _usb_addr(mEp));
+ }
}
/* first nuke then test link, e.g. previous status has not sent */
return ret;
}
+static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
+{
+ struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+
+ if (udc->transceiver)
+ return otg_set_power(udc->transceiver, mA);
+ return -ENOTSUPP;
+}
+
+static int ci13xxx_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int ci13xxx_stop(struct usb_gadget_driver *driver);
/**
* Device operations part of the API to the USB controller hardware,
* which don't involve endpoints (or i/o)
static const struct usb_gadget_ops usb_gadget_ops = {
.vbus_session = ci13xxx_vbus_session,
.wakeup = ci13xxx_wakeup,
+ .vbus_draw = ci13xxx_vbus_draw,
+ .start = ci13xxx_start,
+ .stop = ci13xxx_stop,
};
/**
- * usb_gadget_probe_driver: register a gadget driver
+ * ci13xxx_start: register a gadget driver
* @driver: the driver being registered
* @bind: the driver's bind callback
*
- * Check usb_gadget_probe_driver() at <linux/usb/gadget.h> for details.
+ * Check ci13xxx_start() at <linux/usb/gadget.h> for details.
* Interrupts are enabled here.
*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int ci13xxx_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct ci13xxx *udc = _udc;
}
if (retval)
goto done;
+ spin_unlock_irqrestore(udc->lock, flags);
+ udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
+ retval = usb_ep_enable(&udc->ep0out.ep);
+ if (retval)
+ return retval;
+
+ udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
+ retval = usb_ep_enable(&udc->ep0in.ep);
+ if (retval)
+ return retval;
+ spin_lock_irqsave(udc->lock, flags);
udc->gadget.ep0 = &udc->ep0in.ep;
/* bind gadget */
spin_unlock_irqrestore(udc->lock, flags);
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
/**
- * usb_gadget_unregister_driver: unregister a gadget driver
+ * ci13xxx_stop: unregister a gadget driver
*
* Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
*/
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int ci13xxx_stop(struct usb_gadget_driver *driver)
{
struct ci13xxx *udc = _udc;
unsigned long i, flags;
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
/******************************************************************************
* BUS block
if (retval)
goto remove_dbg;
}
+
+ retval = usb_add_gadget_udc(dev, &udc->gadget);
+ if (retval)
+ goto remove_trans;
+
pm_runtime_no_callbacks(&udc->gadget.dev);
pm_runtime_enable(&udc->gadget.dev);
_udc = udc;
return retval;
+remove_trans:
+ if (udc->transceiver) {
+ otg_set_peripheral(udc->transceiver, &udc->gadget);
+ otg_put_transceiver(udc->transceiver);
+ }
+
err("error = %i", retval);
remove_dbg:
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
err("EINVAL");
return;
}
+ usb_del_gadget_udc(&udc->gadget);
if (udc->transceiver) {
otg_set_peripheral(udc->transceiver, &udc->gadget);