void cdc_ncm_intr_complete(struct urb *urb) { struct if_usb_devdata *pipe_data = urb->context; struct usb_link_device *usb_ld = pipe_data->usb_ld; int ret; mif_debug("status = %d\n", urb->status); switch (urb->status) { /* success */ case -ENOENT: /* urb killed by L2 suspend */ case 0: usb_ld->rx_cnt++; if (urb->actual_length) { mif_info("ep=%d\n", usb_pipeendpoint(urb->pipe)); pr_urb(__func__, urb); } cdc_ncm_status(pipe_data, urb); break; case -ESHUTDOWN: /* hardware gone */ mif_err("intr shutdown, code %d\n", urb->status); return; /* NOTE: not throttling like RX/TX, since this endpoint * already polls infrequently */ default: mif_err("intr status %d\n", urb->status); break; } if (!urb->status) { /*skip -ENOENT L2 enter status */ memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); ret = usb_submit_urb(urb, GFP_ATOMIC); mif_debug("status: usb_submit_urb ret=%d\n", ret); if (ret != 0) mif_err("intr resubmit --> %d\n", ret); } }
static void usb_rx_retry_work(struct work_struct *work) { int ret = 0; struct usb_link_device *usb_ld = container_of(work, struct usb_link_device, rx_retry_work.work); struct urb *urb = usb_ld->retry_urb; struct if_usb_devdata *pipe_data = urb->context; struct io_device *iod; int iod_format; if (!usb_ld->if_usb_connected || !usb_ld->usbdev) return; if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); switch (pipe_data->format) { case IF_USB_FMT_EP: if (usb_ld->if_usb_is_main) { pr_urb("IPC-RX, retry", urb); iod_format = IPC_FMT; } else { iod_format = IPC_BOOT; } break; case IF_USB_RAW_EP: iod_format = IPC_MULTI_RAW; break; case IF_USB_RFS_EP: iod_format = IPC_RFS; pr_urb("RFS-RX, retry", urb); break; case IF_USB_CMD_EP: iod_format = IPC_CMD; break; default: iod_format = -1; break; } iod = link_get_iod_with_format(&usb_ld->ld, iod_format); if (iod) { ret = iod->recv(iod, &usb_ld->ld, (char *)urb->transfer_buffer, urb->actual_length); if (ret == -ENOMEM) { /* TODO: check the retry count */ /* retry the delay work after 20ms and resubit*/ mif_err("ENOMEM, +retry 20ms\n"); if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); usb_ld->retry_urb = urb; if (usb_ld->rx_retry_cnt++ < 10) queue_delayed_work(usb_ld->ld.tx_wq, &usb_ld->rx_retry_work, 10); return; } if (ret < 0) mif_err("io device recv error (%d)\n", ret); usb_ld->rx_retry_cnt = 0; } if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); usb_rx_submit(usb_ld, pipe_data, GFP_ATOMIC); }
static void usb_rx_complete(struct urb *urb) { struct if_usb_devdata *pipe_data = urb->context; struct usb_link_device *usb_ld = pipe_data->usb_ld; struct io_device *iod; int iod_format; int ret; if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); switch (urb->status) { case -ENOENT: /* case for 'link pm suspended but rx data had remained' */ mif_debug("urb->status = -ENOENT\n"); case 0: if (!urb->actual_length) { mif_debug("urb has zero length!\n"); goto rx_submit; } /* call iod recv */ /* how we can distinguish boot ch with fmt ch ?? */ switch (pipe_data->format) { case IF_USB_FMT_EP: if (usb_ld->if_usb_is_main) { pr_urb("IPC-RX", urb); iod_format = IPC_FMT; } else { iod_format = IPC_BOOT; /* usb_mark_last_busy(usb_ld->usbdev); usb_ld->retry_urb = urb; queue_delayed_work(usb_ld->ld.tx_wq, &usb_ld->rx_retry_work, msecs_to_jiffies(20)); return; */ } break; case IF_USB_RAW_EP: iod_format = IPC_MULTI_RAW; break; case IF_USB_RFS_EP: iod_format = IPC_RFS; break; case IF_USB_CMD_EP: iod_format = IPC_CMD; break; default: iod_format = -1; break; } /* flow control CMD by CP, not use io device */ if (unlikely(iod_format == IPC_CMD)) { ret = link_rx_flowctl_cmd(&usb_ld->ld, (char *)urb->transfer_buffer, urb->actual_length); if (ret < 0) mif_err("no multi raw device (%d)\n", ret); goto rx_submit; } iod = link_get_iod_with_format(&usb_ld->ld, iod_format); if (iod) { ret = iod->recv(iod, &usb_ld->ld, (char *)urb->transfer_buffer, urb->actual_length); if (ret == -ENOMEM) { /* retry the delay work and resubit*/ mif_err("ENOMEM, retry\n"); if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); usb_ld->retry_urb = urb; queue_delayed_work(usb_ld->ld.tx_wq, &usb_ld->rx_retry_work, 0); return; } if (ret < 0) mif_err("io device recv error (%d)\n", ret); } rx_submit: if (urb->status == 0) { if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); usb_rx_submit(usb_ld, pipe_data, GFP_ATOMIC); } break; case -ECONNRESET: case -ESHUTDOWN: pr_err("%s: RX complete Status(%d)\n", __func__, urb->status); break; case -EOVERFLOW: pr_err("%s: RX overflow\n", __func__); break; case -EILSEQ: break; default: mif_err("urb err status = %d\n", urb->status); break; } }