diff options
Diffstat (limited to 'drivers/usb/serial/option.c')
| -rw-r--r-- | drivers/usb/serial/option.c | 86 | 
1 files changed, 55 insertions, 31 deletions
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 417ab1b0aa3..2b0c88da782 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1310,6 +1310,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, @@ -1340,51 +1344,78 @@ static int option_probe(struct usb_serial *serial,  			const struct usb_device_id *id)  {  	struct usb_wwan_intf_private *data; +	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 (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && -		serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && -		serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8) +	/* +	 * 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) @@ -1451,18 +1482,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) @@ -1470,9 +1494,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);  |