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);
	}
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
0
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;
	}
}