diff options
Diffstat (limited to 'drivers/usb/serial/qcserial.c')
| -rw-r--r-- | drivers/usb/serial/qcserial.c | 64 | 
1 files changed, 47 insertions, 17 deletions
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 53a2d5a935a..04bb759536b 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -15,6 +15,8 @@  #include <linux/tty_flip.h>  #include <linux/usb.h>  #include <linux/usb/serial.h> +#include <linux/slab.h> +#include "usb-wwan.h"  #define DRIVER_AUTHOR "Qualcomm Inc"  #define DRIVER_DESC "Qualcomm USB Serial driver" @@ -76,6 +78,8 @@ static const struct usb_device_id id_table[] = {  	{USB_DEVICE(0x1199, 0x900a)},	/* Sierra Wireless Gobi 2000 Modem device (VT773) */  	{USB_DEVICE(0x16d8, 0x8001)},	/* CMDTech Gobi 2000 QDL device (VU922) */  	{USB_DEVICE(0x16d8, 0x8002)},	/* CMDTech Gobi 2000 Modem device (VU922) */ +	{USB_DEVICE(0x05c6, 0x9204)},	/* Gobi 2000 QDL device */ +	{USB_DEVICE(0x05c6, 0x9205)},	/* Gobi 2000 Modem device */  	{ }				/* Terminating entry */  };  MODULE_DEVICE_TABLE(usb, id_table); @@ -92,6 +96,8 @@ static struct usb_driver qcdriver = {  static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)  { +	struct usb_wwan_intf_private *data; +	struct usb_host_interface *intf = serial->interface->cur_altsetting;  	int retval = -ENODEV;  	__u8 nintf;  	__u8 ifnum; @@ -100,33 +106,45 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)  	nintf = serial->dev->actconfig->desc.bNumInterfaces;  	dbg("Num Interfaces = %d", nintf); -	ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; +	ifnum = intf->desc.bInterfaceNumber;  	dbg("This Interface = %d", ifnum); +	data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), +					 GFP_KERNEL); +	if (!data) +		return -ENOMEM; + +	spin_lock_init(&data->susp_lock); +  	switch (nintf) {  	case 1:  		/* QDL mode */ -		if (serial->interface->num_altsetting == 2) { -			struct usb_host_interface *intf; - +		/* Gobi 2000 has a single altsetting, older ones have two */ +		if (serial->interface->num_altsetting == 2)  			intf = &serial->interface->altsetting[1]; -			if (intf->desc.bNumEndpoints == 2) { -				if (usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && -				    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { -					dbg("QDL port found"); -					retval = usb_set_interface(serial->dev, ifnum, 1); -					if (retval < 0) { -						dev_err(&serial->dev->dev, -							"Could not set interface, error %d\n", -							retval); -						retval = -ENODEV; -					} -					return retval; -				} +		else if (serial->interface->num_altsetting > 2) +			break; + +		if (intf->desc.bNumEndpoints == 2 && +		    usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && +		    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { +			dbg("QDL port found"); + +			if (serial->interface->num_altsetting == 1) +				return 0; + +			retval = usb_set_interface(serial->dev, ifnum, 1); +			if (retval < 0) { +				dev_err(&serial->dev->dev, +					"Could not set interface, error %d\n", +					retval); +				retval = -ENODEV;  			} +			return retval;  		}  		break; +	case 3:  	case 4:  		/* Composite mode */  		if (ifnum == 2) { @@ -161,6 +179,18 @@ static struct usb_serial_driver qcdevice = {  	.usb_driver          = &qcdriver,  	.num_ports           = 1,  	.probe               = qcprobe, +	.open		     = usb_wwan_open, +	.close		     = usb_wwan_close, +	.write		     = usb_wwan_write, +	.write_room	     = usb_wwan_write_room, +	.chars_in_buffer     = usb_wwan_chars_in_buffer, +	.attach		     = usb_wwan_startup, +	.disconnect	     = usb_wwan_disconnect, +	.release	     = usb_wwan_release, +#ifdef CONFIG_PM +	.suspend	     = usb_wwan_suspend, +	.resume		     = usb_wwan_resume, +#endif  };  static int __init qcinit(void)  |