diff options
Diffstat (limited to 'drivers/usb/serial/option.c')
| -rw-r--r-- | drivers/usb/serial/option.c | 124 | 
1 files changed, 92 insertions, 32 deletions
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e668a2460bd4..08ff9b862049 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -236,6 +236,7 @@ static void option_instat_callback(struct urb *urb);  #define NOVATELWIRELESS_PRODUCT_G1		0xA001  #define NOVATELWIRELESS_PRODUCT_G1_M		0xA002  #define NOVATELWIRELESS_PRODUCT_G2		0xA010 +#define NOVATELWIRELESS_PRODUCT_MC551		0xB001  /* AMOI PRODUCTS */  #define AMOI_VENDOR_ID				0x1614 @@ -496,6 +497,19 @@ static void option_instat_callback(struct urb *urb);  /* MediaTek products */  #define MEDIATEK_VENDOR_ID			0x0e8d +#define MEDIATEK_PRODUCT_DC_1COM		0x00a0 +#define MEDIATEK_PRODUCT_DC_4COM		0x00a5 +#define MEDIATEK_PRODUCT_DC_5COM		0x00a4 +#define MEDIATEK_PRODUCT_7208_1COM		0x7101 +#define MEDIATEK_PRODUCT_7208_2COM		0x7102 +#define MEDIATEK_PRODUCT_FP_1COM		0x0003 +#define MEDIATEK_PRODUCT_FP_2COM		0x0023 +#define MEDIATEK_PRODUCT_FPDC_1COM		0x0043 +#define MEDIATEK_PRODUCT_FPDC_2COM		0x0033 + +/* Cellient products */ +#define CELLIENT_VENDOR_ID			0x2692 +#define CELLIENT_PRODUCT_MEN200			0x9005  /* some devices interfaces need special handling due to a number of reasons */  enum option_blacklist_reason { @@ -549,6 +563,10 @@ static const struct option_blacklist_info net_intf1_blacklist = {  	.reserved = BIT(1),  }; +static const struct option_blacklist_info net_intf2_blacklist = { +	.reserved = BIT(2), +}; +  static const struct option_blacklist_info net_intf3_blacklist = {  	.reserved = BIT(3),  }; @@ -734,6 +752,8 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1) },  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1_M) },  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) }, +	/* Novatel Ovation MC551 a.k.a. Verizon USB551L */ +	{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) },  	{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) },  	{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, @@ -916,6 +936,8 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff),  	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff), +	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),  	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), @@ -1092,6 +1114,8 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff), +		.driver_info = (kernel_ulong_t)&net_intf2_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff,  	  0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, @@ -1233,6 +1257,18 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) },  	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) },  	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) },        /* MediaTek MT6276M modem & app port */ +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_1COM, 0x0a, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x02, 0x01) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x02, 0x01) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_1COM, 0x02, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_2COM, 0x02, 0x02, 0x01) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_1COM, 0x0a, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, +	{ USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },  	{ } /* Terminating entry */  };  MODULE_DEVICE_TABLE(usb, option_ids); @@ -1276,6 +1312,10 @@ static struct usb_serial_driver * const serial_drivers[] = {  static bool debug; +struct option_private { +	u8 bInterfaceNumber; +}; +  module_usb_serial_driver(serial_drivers, option_ids);  static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, @@ -1306,51 +1346,78 @@ static int option_probe(struct usb_serial *serial,  			const struct usb_device_id *id)  {  	struct usb_wwan_intf_private *data; - -	/* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */ -	if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && -		serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && -		serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8) +	struct option_private *priv; +	struct usb_interface_descriptor *iface_desc = +				&serial->interface->cur_altsetting->desc; +	struct usb_device_descriptor *dev_desc = &serial->dev->descriptor; + +	/* +	 * D-Link DWM 652 still exposes CD-Rom emulation interface in modem +	 * mode. +	 */ +	if (dev_desc->idVendor == DLINK_VENDOR_ID && +		dev_desc->idProduct == DLINK_PRODUCT_DWM_652 && +		iface_desc->bInterfaceClass == 0x08)  		return -ENODEV;  	/* Bandrich modem and AT command interface is 0xff */ -	if ((serial->dev->descriptor.idVendor == BANDRICH_VENDOR_ID || -		serial->dev->descriptor.idVendor == PIRELLI_VENDOR_ID) && -		serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff) +	if ((dev_desc->idVendor == BANDRICH_VENDOR_ID || +		dev_desc->idVendor == PIRELLI_VENDOR_ID) && +		iface_desc->bInterfaceClass != 0xff)  		return -ENODEV; - -	/* Don't bind reserved interfaces (like network ones) which often have +	/* +	 * Don't bind reserved interfaces (like network ones) which often have  	 * the same class/subclass/protocol as the serial interfaces.  Look at  	 * the Windows driver .INF files for reserved interface numbers.  	 */  	if (is_blacklisted( -		serial->interface->cur_altsetting->desc.bInterfaceNumber, +		iface_desc->bInterfaceNumber,  		OPTION_BLACKLIST_RESERVED_IF,  		(const struct option_blacklist_info *) id->driver_info))  		return -ENODEV; - -	/* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */ -	if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID && -		serial->dev->descriptor.idProduct == SAMSUNG_PRODUCT_GT_B3730 && -		serial->interface->cur_altsetting->desc.bInterfaceClass != USB_CLASS_CDC_DATA) +	/* +	 * Don't bind network interface on Samsung GT-B3730, it is handled by +	 * a separate module. +	 */ +	if (dev_desc->idVendor == SAMSUNG_VENDOR_ID && +		dev_desc->idProduct == SAMSUNG_PRODUCT_GT_B3730 && +		iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA)  		return -ENODEV; -	data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); +	data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);  	if (!data)  		return -ENOMEM; -	data->send_setup = option_send_setup; + +	priv = kzalloc(sizeof(*priv), GFP_KERNEL); +	if (!priv) { +		kfree(data); +		return -ENOMEM; +	} + +	priv->bInterfaceNumber = iface_desc->bInterfaceNumber; +	data->private = priv; + +	if (!is_blacklisted(iface_desc->bInterfaceNumber, +			OPTION_BLACKLIST_SENDSETUP, +			(struct option_blacklist_info *)id->driver_info)) { +		data->send_setup = option_send_setup; +	}  	spin_lock_init(&data->susp_lock); -	data->private = (void *)id->driver_info; + +	usb_set_serial_data(serial, data); +  	return 0;  }  static void option_release(struct usb_serial *serial)  { -	struct usb_wwan_intf_private *priv = usb_get_serial_data(serial); +	struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); +	struct option_private *priv = intfdata->private;  	usb_wwan_release(serial);  	kfree(priv); +	kfree(intfdata);  }  static void option_instat_callback(struct urb *urb) @@ -1417,18 +1484,11 @@ static void option_instat_callback(struct urb *urb)  static int option_send_setup(struct usb_serial_port *port)  {  	struct usb_serial *serial = port->serial; -	struct usb_wwan_intf_private *intfdata = -		(struct usb_wwan_intf_private *) serial->private; +	struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); +	struct option_private *priv = intfdata->private;  	struct usb_wwan_port_private *portdata; -	int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;  	int val = 0; -	if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP, -			(struct option_blacklist_info *) intfdata->private)) { -		dbg("No send_setup on blacklisted interface #%d\n", ifNum); -		return -EIO; -	} -  	portdata = usb_get_serial_port_data(port);  	if (portdata->dtr_state) @@ -1436,9 +1496,9 @@ static int option_send_setup(struct usb_serial_port *port)  	if (portdata->rts_state)  		val |= 0x02; -	return usb_control_msg(serial->dev, -		usb_rcvctrlpipe(serial->dev, 0), -		0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT); +	return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), +				0x22, 0x21, val, priv->bInterfaceNumber, NULL, +				0, USB_CTRL_SET_TIMEOUT);  }  MODULE_AUTHOR(DRIVER_AUTHOR);  | 
