diff options
Diffstat (limited to 'drivers/usb')
| -rw-r--r-- | drivers/usb/core/hcd.c | 44 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 70 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 1 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-hub.c | 9 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-q.c | 50 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-sched.c | 9 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-timer.c | 29 | ||||
| -rw-r--r-- | drivers/usb/host/pci-quirks.c | 1 | ||||
| -rw-r--r-- | drivers/usb/host/uhci-hub.c | 3 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 13 | ||||
| -rw-r--r-- | drivers/usb/serial/cp210x.c | 1 | ||||
| -rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 2 | ||||
| -rw-r--r-- | drivers/usb/serial/ftdi_sio_ids.h | 9 | ||||
| -rw-r--r-- | drivers/usb/serial/option.c | 13 | ||||
| -rw-r--r-- | drivers/usb/serial/qcserial.c | 1 | ||||
| -rw-r--r-- | drivers/usb/storage/initializers.c | 76 | ||||
| -rw-r--r-- | drivers/usb/storage/initializers.h | 4 | ||||
| -rw-r--r-- | drivers/usb/storage/unusual_devs.h | 329 | ||||
| -rw-r--r-- | drivers/usb/storage/usb.c | 12 | ||||
| -rw-r--r-- | drivers/usb/storage/usual-tables.c | 15 | 
20 files changed, 299 insertions, 392 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 4225d5e7213..8e64adf8e4d 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -39,6 +39,7 @@  #include <asm/unaligned.h>  #include <linux/platform_device.h>  #include <linux/workqueue.h> +#include <linux/pm_runtime.h>  #include <linux/usb.h>  #include <linux/usb/hcd.h> @@ -1025,6 +1026,49 @@ static int register_root_hub(struct usb_hcd *hcd)  	return retval;  } +/* + * usb_hcd_start_port_resume - a root-hub port is sending a resume signal + * @bus: the bus which the root hub belongs to + * @portnum: the port which is being resumed + * + * HCDs should call this function when they know that a resume signal is + * being sent to a root-hub port.  The root hub will be prevented from + * going into autosuspend until usb_hcd_end_port_resume() is called. + * + * The bus's private lock must be held by the caller. + */ +void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum) +{ +	unsigned bit = 1 << portnum; + +	if (!(bus->resuming_ports & bit)) { +		bus->resuming_ports |= bit; +		pm_runtime_get_noresume(&bus->root_hub->dev); +	} +} +EXPORT_SYMBOL_GPL(usb_hcd_start_port_resume); + +/* + * usb_hcd_end_port_resume - a root-hub port has stopped sending a resume signal + * @bus: the bus which the root hub belongs to + * @portnum: the port which is being resumed + * + * HCDs should call this function when they know that a resume signal has + * stopped being sent to a root-hub port.  The root hub will be allowed to + * autosuspend again. + * + * The bus's private lock must be held by the caller. + */ +void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum) +{ +	unsigned bit = 1 << portnum; + +	if (bus->resuming_ports & bit) { +		bus->resuming_ports &= ~bit; +		pm_runtime_put_noidle(&bus->root_hub->dev); +	} +} +EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume);  /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 957ed2c4148..cbf7168e3ce 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2838,6 +2838,23 @@ void usb_enable_ltm(struct usb_device *udev)  EXPORT_SYMBOL_GPL(usb_enable_ltm);  #ifdef	CONFIG_USB_SUSPEND +/* + * usb_disable_function_remotewakeup - disable usb3.0 + * device's function remote wakeup + * @udev: target device + * + * Assume there's only one function on the USB 3.0 + * device and disable remote wake for the first + * interface. FIXME if the interface association + * descriptor shows there's more than one function. + */ +static int usb_disable_function_remotewakeup(struct usb_device *udev) +{ +	return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), +				USB_REQ_CLEAR_FEATURE, USB_RECIP_INTERFACE, +				USB_INTRF_FUNC_SUSPEND,	0, NULL, 0, +				USB_CTRL_SET_TIMEOUT); +}  /*   * usb_port_suspend - suspend a usb device's upstream port @@ -2955,12 +2972,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  		dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",  				port1, status);  		/* paranoia:  "should not happen" */ -		if (udev->do_remote_wakeup) -			(void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0), -				USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, -				USB_DEVICE_REMOTE_WAKEUP, 0, -				NULL, 0, -				USB_CTRL_SET_TIMEOUT); +		if (udev->do_remote_wakeup) { +			if (!hub_is_superspeed(hub->hdev)) { +				(void) usb_control_msg(udev, +						usb_sndctrlpipe(udev, 0), +						USB_REQ_CLEAR_FEATURE, +						USB_RECIP_DEVICE, +						USB_DEVICE_REMOTE_WAKEUP, 0, +						NULL, 0, +						USB_CTRL_SET_TIMEOUT); +			} else +				(void) usb_disable_function_remotewakeup(udev); + +		}  		/* Try to enable USB2 hardware LPM again */  		if (udev->usb2_hw_lpm_capable == 1) @@ -3052,20 +3076,30 @@ static int finish_port_resume(struct usb_device *udev)  	 * udev->reset_resume  	 */  	} else if (udev->actconfig && !udev->reset_resume) { -		le16_to_cpus(&devstatus); -		if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { -			status = usb_control_msg(udev, -					usb_sndctrlpipe(udev, 0), -					USB_REQ_CLEAR_FEATURE, +		if (!hub_is_superspeed(udev->parent)) { +			le16_to_cpus(&devstatus); +			if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) +				status = usb_control_msg(udev, +						usb_sndctrlpipe(udev, 0), +						USB_REQ_CLEAR_FEATURE,  						USB_RECIP_DEVICE, -					USB_DEVICE_REMOTE_WAKEUP, 0, -					NULL, 0, -					USB_CTRL_SET_TIMEOUT); -			if (status) -				dev_dbg(&udev->dev, -					"disable remote wakeup, status %d\n", -					status); +						USB_DEVICE_REMOTE_WAKEUP, 0, +						NULL, 0, +						USB_CTRL_SET_TIMEOUT); +		} else { +			status = usb_get_status(udev, USB_RECIP_INTERFACE, 0, +					&devstatus); +			le16_to_cpus(&devstatus); +			if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP +					| USB_INTRF_STAT_FUNC_RW)) +				status = +					usb_disable_function_remotewakeup(udev);  		} + +		if (status) +			dev_dbg(&udev->dev, +				"disable remote wakeup, status %d\n", +				status);  		status = 0;  	}  	return status; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 09537b2f100..b416a3fc995 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -797,6 +797,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)  			ehci->reset_done[i] = jiffies + msecs_to_jiffies(25);  			set_bit(i, &ehci->resuming_ports);  			ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); +			usb_hcd_start_port_resume(&hcd->self, i);  			mod_timer(&hcd->rh_timer, ehci->reset_done[i]);  		}  	} diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 4ccb97c0678..4d3b294f203 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -649,7 +649,11 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)  			status = STS_PCD;  		}  	} -	/* FIXME autosuspend idle root hubs */ + +	/* If a resume is in progress, make sure it can finish */ +	if (ehci->resuming_ports) +		mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(25)); +  	spin_unlock_irqrestore (&ehci->lock, flags);  	return status ? retval : 0;  } @@ -851,6 +855,7 @@ static int ehci_hub_control (  				/* resume signaling for 20 msec */  				ehci->reset_done[wIndex] = jiffies  						+ msecs_to_jiffies(20); +				usb_hcd_start_port_resume(&hcd->self, wIndex);  				/* check the port again */  				mod_timer(&ehci_to_hcd(ehci)->rh_timer,  						ehci->reset_done[wIndex]); @@ -862,6 +867,7 @@ static int ehci_hub_control (  				clear_bit(wIndex, &ehci->suspended_ports);  				set_bit(wIndex, &ehci->port_c_suspend);  				ehci->reset_done[wIndex] = 0; +				usb_hcd_end_port_resume(&hcd->self, wIndex);  				/* stop resume signaling */  				temp = ehci_readl(ehci, status_reg); @@ -950,6 +956,7 @@ static int ehci_hub_control (  			ehci->reset_done[wIndex] = 0;  			if (temp & PORT_PE)  				set_bit(wIndex, &ehci->port_c_suspend); +			usb_hcd_end_port_resume(&hcd->self, wIndex);  		}  		if (temp & PORT_OC) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 3d989028c83..fd252f0cfb3 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -1197,17 +1197,26 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)  	if (ehci->async_iaa || ehci->async_unlinking)  		return; -	/* Do all the waiting QHs at once */ -	ehci->async_iaa = ehci->async_unlink; -	ehci->async_unlink = NULL; -  	/* If the controller isn't running, we don't have to wait for it */  	if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) { + +		/* Do all the waiting QHs */ +		ehci->async_iaa = ehci->async_unlink; +		ehci->async_unlink = NULL; +  		if (!nested)		/* Avoid recursion */  			end_unlink_async(ehci);  	/* Otherwise start a new IAA cycle */  	} else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) { +		struct ehci_qh		*qh; + +		/* Do only the first waiting QH (nVidia bug?) */ +		qh = ehci->async_unlink; +		ehci->async_iaa = qh; +		ehci->async_unlink = qh->unlink_next; +		qh->unlink_next = NULL; +  		/* Make sure the unlinks are all visible to the hardware */  		wmb(); @@ -1255,34 +1264,35 @@ static void end_unlink_async(struct ehci_hcd *ehci)  	}  } +static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh); +  static void unlink_empty_async(struct ehci_hcd *ehci)  { -	struct ehci_qh		*qh, *next; -	bool			stopped = (ehci->rh_state < EHCI_RH_RUNNING); +	struct ehci_qh		*qh; +	struct ehci_qh		*qh_to_unlink = NULL;  	bool			check_unlinks_later = false; +	int			count = 0; -	/* Unlink all the async QHs that have been empty for a timer cycle */ -	next = ehci->async->qh_next.qh; -	while (next) { -		qh = next; -		next = qh->qh_next.qh; - +	/* Find the last async QH which has been empty for a timer cycle */ +	for (qh = ehci->async->qh_next.qh; qh; qh = qh->qh_next.qh) {  		if (list_empty(&qh->qtd_list) &&  				qh->qh_state == QH_STATE_LINKED) { -			if (!stopped && qh->unlink_cycle == -					ehci->async_unlink_cycle) +			++count; +			if (qh->unlink_cycle == ehci->async_unlink_cycle)  				check_unlinks_later = true;  			else -				single_unlink_async(ehci, qh); +				qh_to_unlink = qh;  		}  	} -	/* Start a new IAA cycle if any QHs are waiting for it */ -	if (ehci->async_unlink) -		start_iaa_cycle(ehci, false); +	/* If nothing else is being unlinked, unlink the last empty QH */ +	if (!ehci->async_iaa && !ehci->async_unlink && qh_to_unlink) { +		start_unlink_async(ehci, qh_to_unlink); +		--count; +	} -	/* QHs that haven't been empty for long enough will be handled later */ -	if (check_unlinks_later) { +	/* Other QHs will be handled later */ +	if (count > 0) {  		ehci_enable_event(ehci, EHCI_HRTIMER_ASYNC_UNLINKS, true);  		++ehci->async_unlink_cycle;  	} diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 69ebee73c0c..b476daf49f6 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -213,7 +213,7 @@ static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask)  }  static const unsigned char -max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 }; +max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 125, 25 };  /* carryover low/fullspeed bandwidth that crosses uframe boundries */  static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) @@ -2212,11 +2212,11 @@ static void scan_isoc(struct ehci_hcd *ehci)  	}  	ehci->now_frame = now_frame; +	frame = ehci->last_iso_frame;  	for (;;) {  		union ehci_shadow	q, *q_p;  		__hc32			type, *hw_p; -		frame = ehci->last_iso_frame;  restart:  		/* scan each element in frame's queue for completions */  		q_p = &ehci->pshadow [frame]; @@ -2321,6 +2321,9 @@ restart:  		/* Stop when we have reached the current frame */  		if (frame == now_frame)  			break; -		ehci->last_iso_frame = (frame + 1) & fmask; + +		/* The last frame may still have active siTDs */ +		ehci->last_iso_frame = frame; +		frame = (frame + 1) & fmask;  	}  } diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 20dbdcbe9b0..f904071d70d 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -113,14 +113,15 @@ static void ehci_poll_ASS(struct ehci_hcd *ehci)  	if (want != actual) { -		/* Poll again later, but give up after about 20 ms */ -		if (ehci->ASS_poll_count++ < 20) { -			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true); -			return; -		} -		ehci_dbg(ehci, "Waited too long for the async schedule status (%x/%x), giving up\n", -				want, actual); +		/* Poll again later */ +		ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true); +		++ehci->ASS_poll_count; +		return;  	} + +	if (ehci->ASS_poll_count > 20) +		ehci_dbg(ehci, "ASS poll count reached %d\n", +				ehci->ASS_poll_count);  	ehci->ASS_poll_count = 0;  	/* The status is up-to-date; restart or stop the schedule as needed */ @@ -159,14 +160,14 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci)  	if (want != actual) { -		/* Poll again later, but give up after about 20 ms */ -		if (ehci->PSS_poll_count++ < 20) { -			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); -			return; -		} -		ehci_dbg(ehci, "Waited too long for the periodic schedule status (%x/%x), giving up\n", -				want, actual); +		/* Poll again later */ +		ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); +		return;  	} + +	if (ehci->PSS_poll_count > 20) +		ehci_dbg(ehci, "PSS poll count reached %d\n", +				ehci->PSS_poll_count);  	ehci->PSS_poll_count = 0;  	/* The status is up-to-date; restart or stop the schedule as needed */ diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index a3b6d7104ae..4c338ec03a0 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -780,6 +780,7 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)  				"defaulting to EHCI.\n");  		dev_warn(&xhci_pdev->dev,  				"USB 3.0 devices will work at USB 2.0 speeds.\n"); +		usb_disable_xhci_ports(xhci_pdev);  		return;  	} diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 768d54295a2..15d13229ddb 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -116,6 +116,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,  		}  	}  	clear_bit(port, &uhci->resuming_ports); +	usb_hcd_end_port_resume(&uhci_to_hcd(uhci)->self, port);  }  /* Wait for the UHCI controller in HP's iLO2 server management chip. @@ -167,6 +168,8 @@ static void uhci_check_ports(struct uhci_hcd *uhci)  				set_bit(port, &uhci->resuming_ports);  				uhci->ports_timeout = jiffies +  						msecs_to_jiffies(25); +				usb_hcd_start_port_resume( +						&uhci_to_hcd(uhci)->self, port);  				/* Make sure we see the port again  				 * after the resuming period is over. */ diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 59fb5c677db..7f76a49e90d 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1698,7 +1698,7 @@ static void handle_port_status(struct xhci_hcd *xhci,  				faked_port_index + 1);  		if (slot_id && xhci->devs[slot_id])  			xhci_ring_device(xhci, slot_id); -		if (bus_state->port_remote_wakeup && (1 << faked_port_index)) { +		if (bus_state->port_remote_wakeup & (1 << faked_port_index)) {  			bus_state->port_remote_wakeup &=  				~(1 << faked_port_index);  			xhci_test_and_clear_bit(xhci, port_array, @@ -2589,6 +2589,8 @@ cleanup:  				(trb_comp_code != COMP_STALL &&  					trb_comp_code != COMP_BABBLE))  				xhci_urb_free_priv(xhci, urb_priv); +			else +				kfree(urb_priv);  			usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);  			if ((urb->actual_length != urb->transfer_buffer_length && @@ -3108,7 +3110,7 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,  	 * running_total.  	 */  	packets_transferred = (running_total + trb_buff_len) / -		usb_endpoint_maxp(&urb->ep->desc); +		GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));  	if ((total_packet_count - packets_transferred) > 31)  		return 31 << 17; @@ -3642,7 +3644,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  		td_len = urb->iso_frame_desc[i].length;  		td_remain_len = td_len;  		total_packet_count = DIV_ROUND_UP(td_len, -				usb_endpoint_maxp(&urb->ep->desc)); +				GET_MAX_PACKET( +					usb_endpoint_maxp(&urb->ep->desc)));  		/* A zero-length transfer still involves at least one packet. */  		if (total_packet_count == 0)  			total_packet_count++; @@ -3664,9 +3667,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  		td = urb_priv->td[i];  		for (j = 0; j < trbs_per_td; j++) {  			u32 remainder = 0; -			field = TRB_TBC(burst_count) | TRB_TLBPC(residue); +			field = 0;  			if (first_trb) { +				field = TRB_TBC(burst_count) | +					TRB_TLBPC(residue);  				/* Queue the isoc TRB */  				field |= TRB_TYPE(TRB_ISOC);  				/* Assume URB_ISO_ASAP is set */ diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index f14736f647f..edc0f0dcad8 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -60,6 +60,7 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */  	{ USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */  	{ USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */ +	{ USB_DEVICE(0x0FDE, 0xCA05) }, /* OWL Wireless Electricity Monitor CM-160 */  	{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */  	{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */  	{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ba68835d06a..90ceef1776c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -584,6 +584,7 @@ static struct usb_device_id id_table_combined [] = {  	/*  	 * ELV devices:  	 */ +	{ USB_DEVICE(FTDI_ELV_VID, FTDI_ELV_WS300_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) }, @@ -670,6 +671,7 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },  	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },  	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) }, +	{ USB_DEVICE(FTDI_VID, FTDI_OMNI1509) },  	{ USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index fa5d5603827..9d359e189a6 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -147,6 +147,11 @@  #define XSENS_CONVERTER_6_PID	0xD38E  #define XSENS_CONVERTER_7_PID	0xD38F +/** + * Zolix (www.zolix.com.cb) product ids + */ +#define FTDI_OMNI1509			0xD491	/* Omni1509 embedded USB-serial */ +  /*   * NDI (www.ndigital.com) product ids   */ @@ -204,7 +209,7 @@  /*   * ELV USB devices submitted by Christian Abt of ELV (www.elv.de). - * All of these devices use FTDI's vendor ID (0x0403). + * Almost all of these devices use FTDI's vendor ID (0x0403).   * Further IDs taken from ELV Windows .inf file.   *   * The previously included PID for the UO 100 module was incorrect. @@ -212,6 +217,8 @@   *   * Armin Laeuger originally sent the PID for the UM 100 module.   */ +#define FTDI_ELV_VID	0x1B1F	/* ELV AG */ +#define FTDI_ELV_WS300_PID	0xC006	/* eQ3 WS 300 PC II */  #define FTDI_ELV_USR_PID	0xE000	/* ELV Universal-Sound-Recorder */  #define FTDI_ELV_MSM1_PID	0xE001	/* ELV Mini-Sound-Modul */  #define FTDI_ELV_KL100_PID	0xE002	/* ELV Kfz-Leistungsmesser KL 100 */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0d9dac9e7f9..567bc77d639 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -242,6 +242,7 @@ static void option_instat_callback(struct urb *urb);  #define TELIT_PRODUCT_CC864_DUAL		0x1005  #define TELIT_PRODUCT_CC864_SINGLE		0x1006  #define TELIT_PRODUCT_DE910_DUAL		0x1010 +#define TELIT_PRODUCT_LE920			0x1200  /* ZTE PRODUCTS */  #define ZTE_VENDOR_ID				0x19d2 @@ -453,6 +454,10 @@ static void option_instat_callback(struct urb *urb);  #define TPLINK_VENDOR_ID			0x2357  #define TPLINK_PRODUCT_MA180			0x0201 +/* Changhong products */ +#define CHANGHONG_VENDOR_ID			0x2077 +#define CHANGHONG_PRODUCT_CH690			0x7001 +  /* some devices interfaces need special handling due to a number of reasons */  enum option_blacklist_reason {  		OPTION_BLACKLIST_NONE = 0, @@ -534,6 +539,11 @@ static const struct option_blacklist_info zte_1255_blacklist = {  	.reserved = BIT(3) | BIT(4),  }; +static const struct option_blacklist_info telit_le920_blacklist = { +	.sendsetup = BIT(0), +	.reserved = BIT(1) | BIT(5), +}; +  static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },  	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -784,6 +794,8 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) },  	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },  	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, +	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), +		.driver_info = (kernel_ulong_t)&telit_le920_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),  		.driver_info = (kernel_ulong_t)&net_intf1_blacklist }, @@ -1318,6 +1330,7 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) },  	{ USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),  	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, +	{ USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) },  	{ } /* Terminating entry */  };  MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index aa148c21ea4..24662547dc5 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -53,6 +53,7 @@ static const struct usb_device_id id_table[] = {  	{DEVICE_G1K(0x05c6, 0x9221)},	/* Generic Gobi QDL device */  	{DEVICE_G1K(0x05c6, 0x9231)},	/* Generic Gobi QDL device */  	{DEVICE_G1K(0x1f45, 0x0001)},	/* Unknown Gobi QDL device */ +	{DEVICE_G1K(0x1bc7, 0x900e)},	/* Telit Gobi QDL device */  	/* Gobi 2000 devices */  	{USB_DEVICE(0x1410, 0xa010)},	/* Novatel Gobi 2000 QDL device */ diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 105d900150c..16b0bf055ee 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -92,8 +92,8 @@ int usb_stor_ucr61s2b_init(struct us_data *us)  	return 0;  } -/* This places the HUAWEI E220 devices in multi-port mode */ -int usb_stor_huawei_e220_init(struct us_data *us) +/* This places the HUAWEI usb dongles in multi-port mode */ +static int usb_stor_huawei_feature_init(struct us_data *us)  {  	int result; @@ -104,3 +104,75 @@ int usb_stor_huawei_e220_init(struct us_data *us)  	US_DEBUGP("Huawei mode set result is %d\n", result);  	return 0;  } + +/* + * It will send a scsi switch command called rewind' to huawei dongle. + * When the dongle receives this command at the first time, + * it will reboot immediately. After rebooted, it will ignore this command. + * So it is  unnecessary to read its response. + */ +static int usb_stor_huawei_scsi_init(struct us_data *us) +{ +	int result = 0; +	int act_len = 0; +	struct bulk_cb_wrap *bcbw = (struct bulk_cb_wrap *) us->iobuf; +	char rewind_cmd[] = {0x11, 0x06, 0x20, 0x00, 0x00, 0x01, 0x01, 0x00, +			0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +	bcbw->Signature = cpu_to_le32(US_BULK_CB_SIGN); +	bcbw->Tag = 0; +	bcbw->DataTransferLength = 0; +	bcbw->Flags = bcbw->Lun = 0; +	bcbw->Length = sizeof(rewind_cmd); +	memset(bcbw->CDB, 0, sizeof(bcbw->CDB)); +	memcpy(bcbw->CDB, rewind_cmd, sizeof(rewind_cmd)); + +	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcbw, +					US_BULK_CB_WRAP_LEN, &act_len); +	US_DEBUGP("transfer actual length=%d, result=%d\n", act_len, result); +	return result; +} + +/* + * It tries to find the supported Huawei USB dongles. + * In Huawei, they assign the following product IDs + * for all of their mobile broadband dongles, + * including the new dongles in the future. + * So if the product ID is not included in this list, + * it means it is not Huawei's mobile broadband dongles. + */ +static int usb_stor_huawei_dongles_pid(struct us_data *us) +{ +	struct usb_interface_descriptor *idesc; +	int idProduct; + +	idesc = &us->pusb_intf->cur_altsetting->desc; +	idProduct = us->pusb_dev->descriptor.idProduct; +	/* The first port is CDROM, +	 * means the dongle in the single port mode, +	 * and a switch command is required to be sent. */ +	if (idesc && idesc->bInterfaceNumber == 0) { +		if ((idProduct == 0x1001) +			|| (idProduct == 0x1003) +			|| (idProduct == 0x1004) +			|| (idProduct >= 0x1401 && idProduct <= 0x1500) +			|| (idProduct >= 0x1505 && idProduct <= 0x1600) +			|| (idProduct >= 0x1c02 && idProduct <= 0x2202)) { +			return 1; +		} +	} +	return 0; +} + +int usb_stor_huawei_init(struct us_data *us) +{ +	int result = 0; + +	if (usb_stor_huawei_dongles_pid(us)) { +		if (us->pusb_dev->descriptor.idProduct >= 0x1446) +			result = usb_stor_huawei_scsi_init(us); +		else +			result = usb_stor_huawei_feature_init(us); +	} +	return result; +} diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h index 529327fbb06..5376d4fc76f 100644 --- a/drivers/usb/storage/initializers.h +++ b/drivers/usb/storage/initializers.h @@ -46,5 +46,5 @@ int usb_stor_euscsi_init(struct us_data *us);   * flash reader */  int usb_stor_ucr61s2b_init(struct us_data *us); -/* This places the HUAWEI E220 devices in multi-port mode */ -int usb_stor_huawei_e220_init(struct us_data *us); +/* This places the HUAWEI usb dongles in multi-port mode */ +int usb_stor_huawei_init(struct us_data *us); diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index d305a5aa3a5..72923b56bbf 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1527,335 +1527,10 @@ UNUSUAL_DEV(  0x1210, 0x0003, 0x0100, 0x0100,  /* Reported by fangxiaozhi <huananhu@huawei.com>   * This brings the HUAWEI data card devices into multi-port mode   */ -UNUSUAL_DEV(  0x12d1, 0x1001, 0x0000, 0x0000, +UNUSUAL_VENDOR_INTF(0x12d1, 0x08, 0x06, 0x50,  		"HUAWEI MOBILE",  		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1003, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1004, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1401, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1402, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1403, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1404, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1405, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1406, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1407, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1408, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1409, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x140A, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x140B, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x140C, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x140D, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x140E, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x140F, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1410, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1411, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1412, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1413, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1414, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1415, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1416, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1417, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1418, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1419, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x141A, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x141B, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x141C, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x141D, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x141E, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x141F, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1420, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1421, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1422, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1423, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1424, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1425, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1426, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1427, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1428, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1429, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x142A, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x142B, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x142C, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x142D, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x142E, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x142F, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1430, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1431, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1432, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1433, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1434, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1435, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1436, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1437, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1438, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x1439, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x143A, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x143B, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x143C, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x143D, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x143E, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, -		0), -UNUSUAL_DEV(  0x12d1, 0x143F, 0x0000, 0x0000, -		"HUAWEI MOBILE", -		"Mass Storage", -		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, +		USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_init,  		0),  /* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */ diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 31b3e1a61bb..cf09b6ba71f 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -120,6 +120,17 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");  	.useTransport = use_transport,	\  } +#define UNUSUAL_VENDOR_INTF(idVendor, cl, sc, pr, \ +		vendor_name, product_name, use_protocol, use_transport, \ +		init_function, Flags) \ +{ \ +	.vendorName = vendor_name,	\ +	.productName = product_name,	\ +	.useProtocol = use_protocol,	\ +	.useTransport = use_transport,	\ +	.initFunction = init_function,	\ +} +  static struct us_unusual_dev us_unusual_dev_list[] = {  #	include "unusual_devs.h"  	{ }		/* Terminating entry */ @@ -131,6 +142,7 @@ static struct us_unusual_dev for_dynamic_ids =  #undef UNUSUAL_DEV  #undef COMPLIANT_DEV  #undef USUAL_DEV +#undef UNUSUAL_VENDOR_INTF  #ifdef CONFIG_LOCKDEP diff --git a/drivers/usb/storage/usual-tables.c b/drivers/usb/storage/usual-tables.c index b78a526910f..5ef8ce74aae 100644 --- a/drivers/usb/storage/usual-tables.c +++ b/drivers/usb/storage/usual-tables.c @@ -41,6 +41,20 @@  #define USUAL_DEV(useProto, useTrans) \  { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans) } +/* Define the device is matched with Vendor ID and interface descriptors */ +#define UNUSUAL_VENDOR_INTF(id_vendor, cl, sc, pr, \ +			vendorName, productName, useProtocol, useTransport, \ +			initFunction, flags) \ +{ \ +	.match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ +				| USB_DEVICE_ID_MATCH_VENDOR, \ +	.idVendor    = (id_vendor), \ +	.bInterfaceClass = (cl), \ +	.bInterfaceSubClass = (sc), \ +	.bInterfaceProtocol = (pr), \ +	.driver_info = (flags) \ +} +  struct usb_device_id usb_storage_usb_ids[] = {  #	include "unusual_devs.h"  	{ }		/* Terminating entry */ @@ -50,6 +64,7 @@ MODULE_DEVICE_TABLE(usb, usb_storage_usb_ids);  #undef UNUSUAL_DEV  #undef COMPLIANT_DEV  #undef USUAL_DEV +#undef UNUSUAL_VENDOR_INTF  /*   * The table of devices to ignore  |