|
@@ -1138,7 +1138,7 @@ static int qe_ep_tx(struct qe_ep *ep, struct qe_frame *frame)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/* when an bd was transmitted, the function can *
|
|
|
|
|
|
+/* when a bd was transmitted, the function can
|
|
* handle the tx_req, not include ep0 */
|
|
* handle the tx_req, not include ep0 */
|
|
static int txcomplete(struct qe_ep *ep, unsigned char restart)
|
|
static int txcomplete(struct qe_ep *ep, unsigned char restart)
|
|
{
|
|
{
|
|
@@ -1174,7 +1174,7 @@ static int txcomplete(struct qe_ep *ep, unsigned char restart)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-/* give a frame and a tx_req,send some data */
|
|
|
|
|
|
+/* give a frame and a tx_req, send some data */
|
|
static int qe_usb_senddata(struct qe_ep *ep, struct qe_frame *frame)
|
|
static int qe_usb_senddata(struct qe_ep *ep, struct qe_frame *frame)
|
|
{
|
|
{
|
|
unsigned int size;
|
|
unsigned int size;
|
|
@@ -1797,11 +1797,6 @@ static int qe_ep_set_halt(struct usb_ep *_ep, int value)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- if (ep->epnum != 0) {
|
|
|
|
- status = 0;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
udc = ep->udc;
|
|
udc = ep->udc;
|
|
/* Attempt to halt IN ep will fail if any transfer requests
|
|
/* Attempt to halt IN ep will fail if any transfer requests
|
|
* are still queue */
|
|
* are still queue */
|
|
@@ -1821,7 +1816,7 @@ static int qe_ep_set_halt(struct usb_ep *_ep, int value)
|
|
udc->ep0_dir = 0;
|
|
udc->ep0_dir = 0;
|
|
}
|
|
}
|
|
out:
|
|
out:
|
|
- dev_vdbg(udc->dev, " %s %s halt stat %d\n", ep->ep.name,
|
|
|
|
|
|
+ dev_vdbg(udc->dev, "%s %s halt stat %d\n", ep->ep.name,
|
|
value ? "set" : "clear", status);
|
|
value ? "set" : "clear", status);
|
|
|
|
|
|
return status;
|
|
return status;
|
|
@@ -1953,22 +1948,51 @@ static void ownercomplete(struct usb_ep *_ep, struct usb_request *_req)
|
|
kfree(req);
|
|
kfree(req);
|
|
}
|
|
}
|
|
|
|
|
|
-static void ch9getstatus(struct qe_udc *udc, u16 value, u16 index,
|
|
|
|
- u16 length)
|
|
|
|
|
|
+static void ch9getstatus(struct qe_udc *udc, u8 request_type, u16 value,
|
|
|
|
+ u16 index, u16 length)
|
|
{
|
|
{
|
|
- u16 usb_status = 0; /* fix me to give correct status */
|
|
|
|
-
|
|
|
|
|
|
+ u16 usb_status = 0;
|
|
struct qe_req *req;
|
|
struct qe_req *req;
|
|
struct qe_ep *ep;
|
|
struct qe_ep *ep;
|
|
int status = 0;
|
|
int status = 0;
|
|
|
|
|
|
ep = &udc->eps[0];
|
|
ep = &udc->eps[0];
|
|
|
|
+ if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
|
|
|
|
+ /* Get device status */
|
|
|
|
+ usb_status = 1 << USB_DEVICE_SELF_POWERED;
|
|
|
|
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
|
|
|
|
+ /* Get interface status */
|
|
|
|
+ /* We don't have interface information in udc driver */
|
|
|
|
+ usb_status = 0;
|
|
|
|
+ } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
|
|
|
|
+ /* Get endpoint status */
|
|
|
|
+ int pipe = index & USB_ENDPOINT_NUMBER_MASK;
|
|
|
|
+ struct qe_ep *target_ep = &udc->eps[pipe];
|
|
|
|
+ u16 usep;
|
|
|
|
+
|
|
|
|
+ /* stall if endpoint doesn't exist */
|
|
|
|
+ if (!target_ep->desc)
|
|
|
|
+ goto stall;
|
|
|
|
+
|
|
|
|
+ usep = in_be16(&udc->usb_regs->usb_usep[pipe]);
|
|
|
|
+ if (index & USB_DIR_IN) {
|
|
|
|
+ if (target_ep->dir != USB_DIR_IN)
|
|
|
|
+ goto stall;
|
|
|
|
+ if ((usep & USB_THS_MASK) == USB_THS_STALL)
|
|
|
|
+ usb_status = 1 << USB_ENDPOINT_HALT;
|
|
|
|
+ } else {
|
|
|
|
+ if (target_ep->dir != USB_DIR_OUT)
|
|
|
|
+ goto stall;
|
|
|
|
+ if ((usep & USB_RHS_MASK) == USB_RHS_STALL)
|
|
|
|
+ usb_status = 1 << USB_ENDPOINT_HALT;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
req = container_of(qe_alloc_request(&ep->ep, GFP_KERNEL),
|
|
req = container_of(qe_alloc_request(&ep->ep, GFP_KERNEL),
|
|
struct qe_req, req);
|
|
struct qe_req, req);
|
|
req->req.length = 2;
|
|
req->req.length = 2;
|
|
- req->req.buf = udc->nullbuf;
|
|
|
|
- memcpy(req->req.buf, (u8 *)&usb_status, 2);
|
|
|
|
|
|
+ req->req.buf = udc->statusbuf;
|
|
|
|
+ *(u16 *)req->req.buf = cpu_to_le16(usb_status);
|
|
req->req.status = -EINPROGRESS;
|
|
req->req.status = -EINPROGRESS;
|
|
req->req.actual = 0;
|
|
req->req.actual = 0;
|
|
req->req.complete = ownercomplete;
|
|
req->req.complete = ownercomplete;
|
|
@@ -1978,10 +2002,11 @@ static void ch9getstatus(struct qe_udc *udc, u16 value, u16 index,
|
|
/* data phase */
|
|
/* data phase */
|
|
status = qe_ep_queue(&ep->ep, &req->req, GFP_ATOMIC);
|
|
status = qe_ep_queue(&ep->ep, &req->req, GFP_ATOMIC);
|
|
|
|
|
|
- if (status) {
|
|
|
|
- dev_err(udc->dev, "Can't respond to getstatus request \n");
|
|
|
|
- qe_ep0_stall(udc);
|
|
|
|
- }
|
|
|
|
|
|
+ if (status == 0)
|
|
|
|
+ return;
|
|
|
|
+stall:
|
|
|
|
+ dev_err(udc->dev, "Can't respond to getstatus request \n");
|
|
|
|
+ qe_ep0_stall(udc);
|
|
}
|
|
}
|
|
|
|
|
|
/* only handle the setup request, suppose the device in normal status */
|
|
/* only handle the setup request, suppose the device in normal status */
|
|
@@ -2007,7 +2032,8 @@ static void setup_received_handle(struct qe_udc *udc,
|
|
if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
|
|
if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
|
|
!= (USB_DIR_IN | USB_TYPE_STANDARD))
|
|
!= (USB_DIR_IN | USB_TYPE_STANDARD))
|
|
break;
|
|
break;
|
|
- ch9getstatus(udc, wValue, wIndex, wLength);
|
|
|
|
|
|
+ ch9getstatus(udc, setup->bRequestType, wValue, wIndex,
|
|
|
|
+ wLength);
|
|
return;
|
|
return;
|
|
|
|
|
|
case USB_REQ_SET_ADDRESS:
|
|
case USB_REQ_SET_ADDRESS:
|
|
@@ -2021,7 +2047,7 @@ static void setup_received_handle(struct qe_udc *udc,
|
|
case USB_REQ_CLEAR_FEATURE:
|
|
case USB_REQ_CLEAR_FEATURE:
|
|
case USB_REQ_SET_FEATURE:
|
|
case USB_REQ_SET_FEATURE:
|
|
/* Requests with no data phase, status phase from udc */
|
|
/* Requests with no data phase, status phase from udc */
|
|
- if ((setup->bRequestType & USB_TYPE_MASK)
|
|
|
|
|
|
+ if ((setup->bRequestType & USB_TYPE_MASK)
|
|
!= USB_TYPE_STANDARD)
|
|
!= USB_TYPE_STANDARD)
|
|
break;
|
|
break;
|
|
|
|
|
|
@@ -2055,7 +2081,7 @@ static void setup_received_handle(struct qe_udc *udc,
|
|
if (setup->bRequestType & USB_DIR_IN) {
|
|
if (setup->bRequestType & USB_DIR_IN) {
|
|
udc->ep0_state = DATA_STATE_XMIT;
|
|
udc->ep0_state = DATA_STATE_XMIT;
|
|
udc->ep0_dir = USB_DIR_IN;
|
|
udc->ep0_dir = USB_DIR_IN;
|
|
- } else{
|
|
|
|
|
|
+ } else {
|
|
udc->ep0_state = DATA_STATE_RECV;
|
|
udc->ep0_state = DATA_STATE_RECV;
|
|
udc->ep0_dir = USB_DIR_OUT;
|
|
udc->ep0_dir = USB_DIR_OUT;
|
|
}
|
|
}
|
|
@@ -2160,13 +2186,11 @@ static int tx_irq(struct qe_udc *udc)
|
|
bd = ep->c_txbd;
|
|
bd = ep->c_txbd;
|
|
if (!(in_be32((u32 __iomem *)bd) & T_R)
|
|
if (!(in_be32((u32 __iomem *)bd) & T_R)
|
|
&& (in_be32(&bd->buf))) {
|
|
&& (in_be32(&bd->buf))) {
|
|
- /* Disable the TX Interrupt */
|
|
|
|
- /*confirm the transmitted bd*/
|
|
|
|
|
|
+ /* confirm the transmitted bd */
|
|
if (ep->epnum == 0)
|
|
if (ep->epnum == 0)
|
|
res = qe_ep0_txconf(ep);
|
|
res = qe_ep0_txconf(ep);
|
|
else
|
|
else
|
|
res = qe_ep_txconf(ep);
|
|
res = qe_ep_txconf(ep);
|
|
- /* Enable the TX Interrupt */
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -2205,7 +2229,6 @@ static irqreturn_t qe_udc_irq(int irq, void *_udc)
|
|
irqreturn_t status = IRQ_NONE;
|
|
irqreturn_t status = IRQ_NONE;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
-
|
|
|
|
spin_lock_irqsave(&udc->lock, flags);
|
|
spin_lock_irqsave(&udc->lock, flags);
|
|
|
|
|
|
irq_src = in_be16(&udc->usb_regs->usb_usber) &
|
|
irq_src = in_be16(&udc->usb_regs->usb_usber) &
|
|
@@ -2520,10 +2543,9 @@ static int __devinit qe_udc_probe(struct of_device *ofdev,
|
|
udc_controller->gadget.dev.release = qe_udc_release;
|
|
udc_controller->gadget.dev.release = qe_udc_release;
|
|
udc_controller->gadget.dev.parent = &ofdev->dev;
|
|
udc_controller->gadget.dev.parent = &ofdev->dev;
|
|
|
|
|
|
-
|
|
|
|
- /* EP:intialization qe_ep struct */
|
|
|
|
|
|
+ /* initialize qe_ep struct */
|
|
for (i = 0; i < USB_MAX_ENDPOINTS ; i++) {
|
|
for (i = 0; i < USB_MAX_ENDPOINTS ; i++) {
|
|
- /*because the ep type isn't decide here so
|
|
|
|
|
|
+ /* because the ep type isn't decide here so
|
|
* qe_ep_init() should be called in ep_enable() */
|
|
* qe_ep_init() should be called in ep_enable() */
|
|
|
|
|
|
/* setup the qe_ep struct and link ep.ep.list
|
|
/* setup the qe_ep struct and link ep.ep.list
|
|
@@ -2536,7 +2558,7 @@ static int __devinit qe_udc_probe(struct of_device *ofdev,
|
|
if (ret)
|
|
if (ret)
|
|
goto err2;
|
|
goto err2;
|
|
|
|
|
|
- /* create a buf for ZLP send */
|
|
|
|
|
|
+ /* create a buf for ZLP send, need to remain zeroed */
|
|
udc_controller->nullbuf = kzalloc(256, GFP_KERNEL);
|
|
udc_controller->nullbuf = kzalloc(256, GFP_KERNEL);
|
|
if (udc_controller->nullbuf == NULL) {
|
|
if (udc_controller->nullbuf == NULL) {
|
|
dev_dbg(udc_controller->dev, "cannot alloc nullbuf\n");
|
|
dev_dbg(udc_controller->dev, "cannot alloc nullbuf\n");
|
|
@@ -2544,6 +2566,13 @@ static int __devinit qe_udc_probe(struct of_device *ofdev,
|
|
goto err3;
|
|
goto err3;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* buffer for data of get_status request */
|
|
|
|
+ udc_controller->statusbuf = kzalloc(2, GFP_KERNEL);
|
|
|
|
+ if (udc_controller->statusbuf == NULL) {
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto err4;
|
|
|
|
+ }
|
|
|
|
+
|
|
udc_controller->nullp = virt_to_phys((void *)udc_controller->nullbuf);
|
|
udc_controller->nullp = virt_to_phys((void *)udc_controller->nullbuf);
|
|
if (udc_controller->nullp == DMA_ADDR_INVALID) {
|
|
if (udc_controller->nullp == DMA_ADDR_INVALID) {
|
|
udc_controller->nullp = dma_map_single(
|
|
udc_controller->nullp = dma_map_single(
|
|
@@ -2568,20 +2597,21 @@ static int __devinit qe_udc_probe(struct of_device *ofdev,
|
|
if (ret) {
|
|
if (ret) {
|
|
dev_err(udc_controller->dev, "cannot request irq %d err %d \n",
|
|
dev_err(udc_controller->dev, "cannot request irq %d err %d \n",
|
|
udc_controller->usb_irq, ret);
|
|
udc_controller->usb_irq, ret);
|
|
- goto err4;
|
|
|
|
|
|
+ goto err5;
|
|
}
|
|
}
|
|
|
|
|
|
ret = device_add(&udc_controller->gadget.dev);
|
|
ret = device_add(&udc_controller->gadget.dev);
|
|
if (ret)
|
|
if (ret)
|
|
- goto err5;
|
|
|
|
|
|
+ goto err6;
|
|
|
|
|
|
dev_info(udc_controller->dev,
|
|
dev_info(udc_controller->dev,
|
|
- "QE/CPM USB controller initialized as device\n");
|
|
|
|
|
|
+ "%s USB controller initialized as device\n",
|
|
|
|
+ (udc_controller->soc_type == PORT_QE) ? "QE" : "CPM");
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
-err5:
|
|
|
|
|
|
+err6:
|
|
free_irq(udc_controller->usb_irq, udc_controller);
|
|
free_irq(udc_controller->usb_irq, udc_controller);
|
|
-err4:
|
|
|
|
|
|
+err5:
|
|
if (udc_controller->nullmap) {
|
|
if (udc_controller->nullmap) {
|
|
dma_unmap_single(udc_controller->gadget.dev.parent,
|
|
dma_unmap_single(udc_controller->gadget.dev.parent,
|
|
udc_controller->nullp, 256,
|
|
udc_controller->nullp, 256,
|
|
@@ -2592,6 +2622,8 @@ err4:
|
|
udc_controller->nullp, 256,
|
|
udc_controller->nullp, 256,
|
|
DMA_TO_DEVICE);
|
|
DMA_TO_DEVICE);
|
|
}
|
|
}
|
|
|
|
+ kfree(udc_controller->statusbuf);
|
|
|
|
+err4:
|
|
kfree(udc_controller->nullbuf);
|
|
kfree(udc_controller->nullbuf);
|
|
err3:
|
|
err3:
|
|
ep = &udc_controller->eps[0];
|
|
ep = &udc_controller->eps[0];
|
|
@@ -2642,6 +2674,7 @@ static int __devexit qe_udc_remove(struct of_device *ofdev)
|
|
udc_controller->nullp, 256,
|
|
udc_controller->nullp, 256,
|
|
DMA_TO_DEVICE);
|
|
DMA_TO_DEVICE);
|
|
}
|
|
}
|
|
|
|
+ kfree(udc_controller->statusbuf);
|
|
kfree(udc_controller->nullbuf);
|
|
kfree(udc_controller->nullbuf);
|
|
|
|
|
|
ep = &udc_controller->eps[0];
|
|
ep = &udc_controller->eps[0];
|