int ctrl_bridge_resume(unsigned int id) { struct ctrl_bridge *dev; struct urb *urb; if (id >= MAX_BRIDGE_DEVICES) return -EINVAL; dev = __dev[id]; if (!dev) return -ENODEV; if (!test_and_clear_bit(SUSPENDED, &dev->flags)) return 0; /* submit pending write requests */ while ((urb = usb_get_from_anchor(&dev->tx_deferred))) { int ret; usb_anchor_urb(urb, &dev->tx_submitted); ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { usb_unanchor_urb(urb); kfree(urb->setup_packet); kfree(urb->transfer_buffer); usb_free_urb(urb); usb_autopm_put_interface_async(dev->intf); } } return ctrl_bridge_start_read(dev); }
int ctrl_bridge_resume(unsigned int id) { struct ctrl_bridge *dev; struct urb *urb; if (id >= MAX_BRIDGE_DEVICES) return -EINVAL; dev = __dev[id]; if (!dev) return -ENODEV; if (!test_and_clear_bit(SUSPENDED, &dev->flags)) return 0; /* submit pending write requests */ while ((urb = usb_get_from_anchor(&dev->tx_deferred))) { int ret; usb_anchor_urb(urb, &dev->tx_submitted); ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { usb_unanchor_urb(urb); kfree(urb->setup_packet); kfree(urb->transfer_buffer); usb_free_urb(urb); usb_autopm_put_interface_async(dev->intf); } } /* if the bridge is open, resume reading */ #ifndef CONFIG_MDM_HSIC_PM if (dev->brdg) return ctrl_bridge_start_read(dev); #else /* if the bridge is open or not, resume to consume mdm request * because this link is not dead, it's alive */ return ctrl_bridge_start_read(dev); #endif return 0; }
static void resp_avail_cb(struct urb *urb) { struct ctrl_bridge *dev = urb->context; int resubmit_urb = 1; struct bridge *brdg = dev->brdg; unsigned long flags; /*usb device disconnect*/ if (urb->dev->state == USB_STATE_NOTATTACHED) return; switch (urb->status) { case 0: /*success*/ dev->get_encap_res++; if (brdg && brdg->ops.send_pkt) brdg->ops.send_pkt(brdg->ctx, urb->transfer_buffer, urb->actual_length); break; /*do not resubmit*/ case -ESHUTDOWN: case -ENOENT: case -ECONNRESET: /* unplug */ case -EPROTO: /*babble error*/ resubmit_urb = 0; /*resubmit*/ case -EOVERFLOW: default: dev_dbg(&dev->intf->dev, "%s: non zero urb status = %d\n", __func__, urb->status); } if (resubmit_urb) { /*re- submit int urb to check response available*/ ctrl_bridge_start_read(dev, GFP_ATOMIC); } else { spin_lock_irqsave(&dev->lock, flags); dev->rx_state = RX_IDLE; spin_unlock_irqrestore(&dev->lock, flags); } usb_autopm_put_interface_async(dev->intf); }
int ctrl_bridge_resume(unsigned int id) { struct ctrl_bridge *dev; struct urb *urb; unsigned long flags; int ret; if (id >= MAX_BRIDGE_DEVICES) return -EINVAL; dev = __dev[id]; if (!dev) return -ENODEV; if (!dev->int_pipe) return 0; if (!test_bit(SUSPENDED, &dev->flags)) return 0; spin_lock_irqsave(&dev->lock, flags); /* submit pending write requests */ while ((urb = usb_get_from_anchor(&dev->tx_deferred))) { spin_unlock_irqrestore(&dev->lock, flags); /* * usb_get_from_anchor() does not drop the * ref count incremented by the usb_anchro_urb() * called in Tx submission path. Let us do it. */ usb_put_urb(urb); usb_anchor_urb(urb, &dev->tx_submitted); ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { usb_unanchor_urb(urb); kfree(urb->setup_packet); kfree(urb->transfer_buffer); usb_free_urb(urb); usb_autopm_put_interface_async(dev->intf); } spin_lock_irqsave(&dev->lock, flags); } clear_bit(SUSPENDED, &dev->flags); spin_unlock_irqrestore(&dev->lock, flags); return ctrl_bridge_start_read(dev, GFP_KERNEL); }
int ctrl_bridge_suspend(unsigned int id) { struct ctrl_bridge *dev; unsigned long flags; if (id >= MAX_BRIDGE_DEVICES) return -EINVAL; dev = __dev[id]; if (!dev) return -ENODEV; if (!dev->int_pipe) return 0; spin_lock_irqsave(&dev->lock, flags); if (!usb_anchor_empty(&dev->tx_submitted) || dev->rx_state == RX_BUSY) { spin_unlock_irqrestore(&dev->lock, flags); return -EBUSY; } spin_unlock_irqrestore(&dev->lock, flags); usb_kill_urb(dev->inturb); spin_lock_irqsave(&dev->lock, flags); if (dev->rx_state != RX_IDLE) { spin_unlock_irqrestore(&dev->lock, flags); return -EBUSY; } if (!usb_anchor_empty(&dev->tx_submitted)) { spin_unlock_irqrestore(&dev->lock, flags); ctrl_bridge_start_read(dev, GFP_KERNEL); return -EBUSY; } set_bit(SUSPENDED, &dev->flags); spin_unlock_irqrestore(&dev->lock, flags); return 0; }
int ctrl_bridge_open(struct bridge *brdg) { struct ctrl_bridge *dev; int ret; if (!brdg) { err("bridge is null\n"); return -EINVAL; } if (brdg->ch_id >= MAX_BRIDGE_DEVICES) return -EINVAL; dev = __dev[brdg->ch_id]; if (!dev) { err("dev is null\n"); return -ENODEV; } dev->brdg = brdg; dev->snd_encap_cmd = 0; dev->get_encap_res = 0; dev->resp_avail = 0; dev->set_ctrl_line_sts = 0; dev->notify_ser_state = 0; ret = usb_autopm_get_interface(dev->intf); if (ret < 0) { dev_err(&dev->udev->dev, "%s autopm_get fail: %d\n", __func__, ret); return ret; } ret = ctrl_bridge_start_read(dev); usb_autopm_put_interface(dev->intf); return ret; }
int ctrl_bridge_probe(struct usb_interface *ifc, struct usb_host_endpoint *int_in, int id) { struct ctrl_bridge *dev; struct usb_device *udev; struct usb_endpoint_descriptor *ep; u16 wMaxPacketSize; int retval = 0; int interval; udev = interface_to_usbdev(ifc); dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { dev_err(&ifc->dev, "%s: unable to allocate dev\n", __func__); return -ENOMEM; } dev->pdev = platform_device_alloc(ctrl_bridge_names[id], id); if (!dev->pdev) { dev_err(&ifc->dev, "%s: unable to allocate platform device\n", __func__); retval = -ENOMEM; goto nomem; } dev->udev = udev; dev->int_pipe = usb_rcvintpipe(udev, int_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->intf = ifc; init_usb_anchor(&dev->tx_submitted); init_usb_anchor(&dev->tx_deferred); /*use max pkt size from ep desc*/ ep = &dev->intf->cur_altsetting->endpoint[0].desc; dev->inturb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->inturb) { dev_err(&ifc->dev, "%s: error allocating int urb\n", __func__); retval = -ENOMEM; goto pdev_del; } wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); dev->intbuf = kmalloc(wMaxPacketSize, GFP_KERNEL); if (!dev->intbuf) { dev_err(&ifc->dev, "%s: error allocating int buffer\n", __func__); retval = -ENOMEM; goto free_inturb; } interval = (udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL : FS_LS_INTERVAL; usb_fill_int_urb(dev->inturb, udev, dev->int_pipe, dev->intbuf, wMaxPacketSize, notification_available_cb, dev, interval); dev->readurb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->readurb) { dev_err(&ifc->dev, "%s: error allocating read urb\n", __func__); retval = -ENOMEM; goto free_intbuf; } dev->readbuf = kmalloc(DEFAULT_READ_URB_LENGTH, GFP_KERNEL); if (!dev->readbuf) { dev_err(&ifc->dev, "%s: error allocating read buffer\n", __func__); retval = -ENOMEM; goto free_rurb; } dev->in_ctlreq = kmalloc(sizeof(*dev->in_ctlreq), GFP_KERNEL); if (!dev->in_ctlreq) { dev_err(&ifc->dev, "%s:error allocating setup packet buffer\n", __func__); retval = -ENOMEM; goto free_rbuf; } dev->in_ctlreq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); dev->in_ctlreq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; dev->in_ctlreq->wValue = 0; dev->in_ctlreq->wIndex = dev->intf->cur_altsetting->desc.bInterfaceNumber; dev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH); __dev[id] = dev; platform_device_add(dev->pdev); ch_id++; return ctrl_bridge_start_read(dev); free_rbuf: kfree(dev->readbuf); free_rurb: usb_free_urb(dev->readurb); free_intbuf: kfree(dev->intbuf); free_inturb: usb_free_urb(dev->inturb); pdev_del: platform_device_unregister(dev->pdev); nomem: kfree(dev); return retval; }
static void notification_available_cb(struct urb *urb) { int status; struct usb_cdc_notification *ctrl; struct ctrl_bridge *dev = urb->context; struct bridge *brdg = dev->brdg; unsigned int ctrl_bits; unsigned char *data; unsigned long flags; /*usb device disconnect*/ if (urb->dev->state == USB_STATE_NOTATTACHED) return; spin_lock_irqsave(&dev->lock, flags); dev->rx_state = RX_IDLE; spin_unlock_irqrestore(&dev->lock, flags); switch (urb->status) { case 0: /*success*/ break; case -ESHUTDOWN: case -ENOENT: case -ECONNRESET: case -EPROTO: /* unplug */ return; case -EPIPE: dev_err(&dev->intf->dev, "%s: stall on int endpoint\n", __func__); /* TBD : halt to be cleared in work */ case -EOVERFLOW: default: pr_debug_ratelimited("%s: non zero urb status = %d\n", __func__, urb->status); goto resubmit_int_urb; } ctrl = (struct usb_cdc_notification *)urb->transfer_buffer; data = (unsigned char *)(ctrl + 1); switch (ctrl->bNotificationType) { case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: spin_lock_irqsave(&dev->lock, flags); dev->rx_state = RX_BUSY; spin_unlock_irqrestore(&dev->lock, flags); dev->resp_avail++; usb_autopm_get_interface_no_resume(dev->intf); usb_fill_control_urb(dev->readurb, dev->udev, usb_rcvctrlpipe(dev->udev, 0), (unsigned char *)dev->in_ctlreq, dev->readbuf, DEFAULT_READ_URB_LENGTH, resp_avail_cb, dev); status = usb_submit_urb(dev->readurb, GFP_ATOMIC); if (status) { dev_err(&dev->intf->dev, "%s: Error submitting Read URB %d\n", __func__, status); usb_autopm_put_interface_async(dev->intf); goto resubmit_int_urb; } return; case USB_CDC_NOTIFY_NETWORK_CONNECTION: dev_dbg(&dev->intf->dev, "%s network\n", ctrl->wValue ? "connected to" : "disconnected from"); break; case USB_CDC_NOTIFY_SERIAL_STATE: dev->notify_ser_state++; ctrl_bits = get_unaligned_le16(data); dev_dbg(&dev->intf->dev, "serial state: %d\n", ctrl_bits); dev->cbits_tohost = ctrl_bits; if (brdg && brdg->ops.send_cbits) brdg->ops.send_cbits(brdg->ctx, ctrl_bits); break; default: dev_err(&dev->intf->dev, "%s: unknown notification %d received:" "index %d len %d data0 %d data1 %d", __func__, ctrl->bNotificationType, ctrl->wIndex, ctrl->wLength, data[0], data[1]); } resubmit_int_urb: ctrl_bridge_start_read(dev, GFP_ATOMIC); }
int ctrl_bridge_probe(struct usb_interface *ifc, struct usb_host_endpoint *int_in, char *name, int id) { struct ctrl_bridge *dev; struct usb_device *udev; struct usb_endpoint_descriptor *ep; u16 wMaxPacketSize; int retval = 0; int interval; udev = interface_to_usbdev(ifc); dev = __dev[id]; if (!dev) { pr_err("%s:device not found\n", __func__); return -ENODEV; } if (!int_in) return 0; dev->name = name; dev->pdev = platform_device_alloc(name, -1); if (!dev->pdev) { retval = -ENOMEM; dev_err(&ifc->dev, "%s: unable to allocate platform device\n", __func__); goto free_name; } dev->flags = 0; dev->udev = udev; dev->int_pipe = usb_rcvintpipe(udev, int_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); dev->intf = ifc; /*use max pkt size from ep desc*/ ep = &dev->intf->cur_altsetting->endpoint[0].desc; dev->inturb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->inturb) { dev_err(&ifc->dev, "%s: error allocating int urb\n", __func__); retval = -ENOMEM; goto pdev_put; } wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); dev->intbuf = kmalloc(wMaxPacketSize, GFP_KERNEL); if (!dev->intbuf) { dev_err(&ifc->dev, "%s: error allocating int buffer\n", __func__); retval = -ENOMEM; goto free_inturb; } interval = int_in->desc.bInterval; usb_fill_int_urb(dev->inturb, udev, dev->int_pipe, dev->intbuf, wMaxPacketSize, notification_available_cb, dev, interval); dev->readurb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->readurb) { dev_err(&ifc->dev, "%s: error allocating read urb\n", __func__); retval = -ENOMEM; goto free_intbuf; } dev->readbuf = kmalloc(DEFAULT_READ_URB_LENGTH, GFP_KERNEL); if (!dev->readbuf) { dev_err(&ifc->dev, "%s: error allocating read buffer\n", __func__); retval = -ENOMEM; goto free_rurb; } dev->in_ctlreq = kmalloc(sizeof(*dev->in_ctlreq), GFP_KERNEL); if (!dev->in_ctlreq) { dev_err(&ifc->dev, "%s:error allocating setup packet buffer\n", __func__); retval = -ENOMEM; goto free_rbuf; } dev->in_ctlreq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); dev->in_ctlreq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; dev->in_ctlreq->wValue = 0; dev->in_ctlreq->wIndex = dev->intf->cur_altsetting->desc.bInterfaceNumber; dev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH); retval = platform_device_add(dev->pdev); if (retval) { dev_err(&ifc->dev, "%s:fail to add pdev\n", __func__); goto free_ctrlreq; } retval = ctrl_bridge_start_read(dev, GFP_KERNEL); if (retval) { dev_err(&ifc->dev, "%s:fail to start reading\n", __func__); goto pdev_del; } return 0; pdev_del: platform_device_del(dev->pdev); free_ctrlreq: kfree(dev->in_ctlreq); free_rbuf: kfree(dev->readbuf); free_rurb: usb_free_urb(dev->readurb); free_intbuf: kfree(dev->intbuf); free_inturb: usb_free_urb(dev->inturb); pdev_put: platform_device_put(dev->pdev); free_name: dev->name = "none"; return retval; }