static int smdhsic_probe(struct usb_interface *intf, const struct usb_device_id *id) { int devid = -1; int err; const struct usb_cdc_union_desc *union_header = NULL; const struct usb_host_interface *data_desc; struct usb_interface *data_intf; struct usb_device *usbdev; struct str_intf_priv *intfpriv = NULL; struct usb_driver *driver; struct str_smdipc *smdipc; struct str_hsic *hsic; u8 *data; int len; pr_info("%s: Enter\n", __func__); usbdev = interface_to_usbdev(intf); g_usbdev.usbdev = usbdev; driver = get_usb_driver(intf); data = intf->altsetting->extra; len = intf->altsetting->extralen; if (!len) { if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { pr_debug( "%s: Seeking extra descriptors on endpoint\n", __func__); len = intf->cur_altsetting->endpoint->extralen; data = intf->cur_altsetting->endpoint->extra; } else { pr_err( "%s: Zero length descriptor reference\n", __func__); return -EINVAL; } } if (!len) { pr_err("%s: Zero length descriptor reference\n", __func__); return -EINVAL; } while (len > 0) { if (data[1] == USB_DT_CS_INTERFACE) { switch (data[2]) { case USB_CDC_UNION_TYPE: if (union_header) break; union_header = (struct usb_cdc_union_desc *)data; break; default: break; } } data += data[0]; len -= data[0]; } if (!union_header) { pr_err("%s:USB CDC is not union type\n", __func__); return -EINVAL; } data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0); if (!data_intf) { pr_err("%s:data_inferface is NULL\n", __func__); return -ENODEV; } data_desc = data_intf->altsetting; if (!data_desc) { pr_err("%s:data_desc is NULL\n", __func__); return -ENODEV; } switch (id->driver_info) { case XMM6260_PSI_DOWN: pr_warn("%s:XMM6260_PSI_DOWN\n", __func__); intfpriv = smd_create_dev(data_intf, usbdev, data_desc, DOWN_DEV_ID); break; case XMM6260_BIN_DOWN: intfpriv = smd_create_dev(data_intf, usbdev, data_desc, DOWN_DEV_ID); break; case XMM6260_CHANNEL: devid = intf->altsetting->desc.bInterfaceNumber / 2; intfpriv = smd_create_dev(data_intf, usbdev, data_desc, devid); break; default: pr_err("%s: Undefined driver_info: %lu\n", __func__, id->driver_info); break; } if (!intfpriv) { pr_err("%s:smd_create_dev() failed\n", __func__); return -EINVAL; } err = usb_driver_claim_interface(driver, data_intf, intfpriv); if (err < 0) { pr_err("%s:usb_driver_claim() failed\n", __func__); return err; } /* to start runtime pm with AP initiated L2 */ if (usb_runtime_pm_ap_initiated_L2) { usbdev->autosuspend_delay = msecs_to_jiffies(200); if (devid == FMT_DEV_ID) { smdipc = (struct str_smdipc *)intfpriv->data; hsic = &smdipc->hsic; g_usbdev.hsic = hsic; g_usbdev.hsic->dpm_suspending = false; g_usbdev.suspended = 0; INIT_DELAYED_WORK(&hsic->pm_runtime_work, smdhsic_pm_runtime_start); schedule_delayed_work(&hsic->pm_runtime_work, msecs_to_jiffies(10000)); } } else usbdev->autosuspend_delay = 0; intfpriv->devid |= ID_BIND; usb_set_intfdata(intf, intfpriv); pm_suspend_ignore_children(&usbdev->dev, true); return 0; }
static void smdhsic_disconnect(struct usb_interface *intf) { int devid; struct usb_interface *smd_intf; struct str_intf_priv *intfpriv; struct usb_device *device = NULL; pr_info("%s: Called\n", __func__); intfpriv = usb_get_intfdata(intf); if (!intfpriv) { pr_err("%s: intfpriv is NULL\n", __func__); goto err_get_intfdata; } device = get_usb_device(intfpriv); devid = GET_DEVID(intfpriv->devid); pr_debug("%s : devid : %d\n", __func__, devid); smd_intf = get_usb_intf(intfpriv); if (!smd_intf) { pr_err("smd_intf is NULL\n"); goto err_get_usb_intf; } if (smd_intf != intf) { pr_err("smd_intf is not same intf\n"); goto err_mismatched_intf; } usb_driver_release_interface(get_usb_driver(intf), smd_intf); if (!device) usb_put_dev(device); pm_runtime_disable(&device->dev); if (g_usbdev.hsic) cancel_delayed_work(&g_usbdev.hsic->pm_runtime_work); switch (devid) { case FMT_DEV_ID: flush_txurb(&g_usbdev.ipc_urbq); flush_txurb(&g_usbdev.data_urbq); smdctl_request_connection_recover(true); case RAW_DEV_ID: case RFS_DEV_ID: case CMD_DEV_ID: case DOWN_DEV_ID: if (emu_discon_func[devid]) emu_discon_func[devid](g_usbdev.smd_device[devid]); else kfree(intfpriv->data); break; default: pr_warn("%s:Undefined Callback Function\n", __func__); } /* to prevent sleep at connection recover * when, usb suspend and recover routine overlap * it makes huge delay on modem reset */ wake_lock_timeout(&g_usbdev.txwake, 20*HZ); kfree(intfpriv); usb_set_intfdata(intf, NULL); g_usbdev.usbdev = NULL; g_usbdev.suspended = 0; g_usbdev.hsic = NULL; return; err_mismatched_intf: err_get_usb_intf: if (!device) usb_put_dev(device); err_get_intfdata: pr_err("release(2) : %p\n", intf); usb_driver_release_interface(get_usb_driver(intf), intf); return; }
static void smdhsic_disconnect(struct usb_interface *intf) { int devid; struct usb_interface *smd_intf; struct str_intf_priv *intfpriv; struct usb_device *device = NULL; pr_info("%s: Called\n", __func__); intfpriv = usb_get_intfdata(intf); if (!intfpriv) { pr_err("%s: intfpriv is NULL\n", __func__); goto err_get_intfdata; } device = get_usb_device(intfpriv); devid = GET_DEVID(intfpriv->devid); pr_debug("%s : devid : %d\n", __func__, devid); smd_intf = get_usb_intf(intfpriv); if (!smd_intf) { pr_err("smd_intf is NULL\n"); goto err_get_usb_intf; } if (smd_intf != intf) { pr_err("smd_intf is not same intf\n"); goto err_mismatched_intf; } usb_driver_release_interface(get_usb_driver(intf), smd_intf); if (!device) usb_put_dev(device); switch (devid) { case FMT_DEV_ID: pm_runtime_disable(&device->dev); if (g_usbdev.hsic) cancel_delayed_work(&g_usbdev.hsic->pm_runtime_work); smdctl_request_connection_recover(true); case RAW_DEV_ID: case RFS_DEV_ID: case CMD_DEV_ID: case DOWN_DEV_ID: if (emu_discon_func[devid]) emu_discon_func[devid](g_usbdev.smd_device[devid]); else kfree(intfpriv->data); break; default: pr_warn("%s:Undefined Callback Function\n", __func__); } /* Power on/off kernel-panic workaround, * if USB suspend cmd was queued in power.work before disconnect, * reset the runtime PM request value to PM_REQ_NONE */ device->dev.power.request = RPM_REQ_NONE; kfree(intfpriv); usb_set_intfdata(intf, NULL); g_usbdev.usbdev = NULL; g_usbdev.suspended = 0; g_usbdev.hsic = NULL; return; err_mismatched_intf: err_get_usb_intf: if (device) usb_put_dev(device); err_get_intfdata: pr_err("release(2) : %p\n", intf); usb_driver_release_interface(get_usb_driver(intf), intf); return; }