示例#1
0
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;
}
示例#2
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;
}
示例#3
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);

	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;
}