Browse Source

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6

Linus Torvalds 20 years ago
parent
commit
5420520973
80 changed files with 7439 additions and 3731 deletions
  1. 203 0
      Documentation/input/yealink.txt
  2. 6 0
      MAINTAINERS
  3. 150 123
      drivers/block/ub.c
  4. 2 11
      drivers/net/irda/irda-usb.c
  5. 0 2
      drivers/usb/atm/cxacru.c
  6. 18 3
      drivers/usb/class/Kconfig
  7. 6 3
      drivers/usb/class/usblp.c
  8. 2 2
      drivers/usb/core/Makefile
  9. 90 12
      drivers/usb/core/devio.c
  10. 4 4
      drivers/usb/core/hcd.h
  11. 83 32
      drivers/usb/core/hub.c
  12. 7 0
      drivers/usb/core/hub.h
  13. 1 8
      drivers/usb/core/inode.c
  14. 4 4
      drivers/usb/core/message.c
  15. 4 22
      drivers/usb/core/urb.c
  16. 32 3
      drivers/usb/core/usb.c
  17. 5 0
      drivers/usb/core/usb.h
  18. 8 25
      drivers/usb/gadget/ether.c
  19. 7 26
      drivers/usb/gadget/file_storage.c
  20. 55 0
      drivers/usb/gadget/gadget_chips.h
  21. 11 40
      drivers/usb/gadget/serial.c
  22. 11 37
      drivers/usb/gadget/zero.c
  23. 7 0
      drivers/usb/host/ehci-q.c
  24. 4 0
      drivers/usb/host/ehci-sched.c
  25. 2 0
      drivers/usb/host/ehci.h
  26. 33 55
      drivers/usb/host/isp116x-hcd.c
  27. 5 19
      drivers/usb/host/ohci-ppc-soc.c
  28. 2 2
      drivers/usb/host/ohci-s3c2410.c
  29. 14 0
      drivers/usb/input/Kconfig
  30. 1 0
      drivers/usb/input/Makefile
  31. 6 3
      drivers/usb/input/hid-core.c
  32. 0 5
      drivers/usb/input/keyspan_remote.c
  33. 189 0
      drivers/usb/input/map_to_7segment.h
  34. 1013 0
      drivers/usb/input/yealink.c
  35. 220 0
      drivers/usb/input/yealink.h
  36. 1 2
      drivers/usb/misc/auerswald.c
  37. 3 3
      drivers/usb/misc/ldusb.c
  38. 2 2
      drivers/usb/misc/sisusbvga/sisusb.c
  39. 0 2
      drivers/usb/misc/usbtest.c
  40. 1 1
      drivers/usb/mon/Makefile
  41. 55 0
      drivers/usb/mon/mon_dma.c
  42. 17 18
      drivers/usb/mon/mon_text.c
  43. 4 0
      drivers/usb/mon/usb_mon.h
  44. 109 99
      drivers/usb/net/Kconfig
  45. 8 0
      drivers/usb/net/Makefile
  46. 948 0
      drivers/usb/net/asix.c
  47. 0 2
      drivers/usb/net/catc.c
  48. 509 0
      drivers/usb/net/cdc_ether.c
  49. 335 0
      drivers/usb/net/cdc_subset.c
  50. 407 0
      drivers/usb/net/gl620a.c
  51. 0 1
      drivers/usb/net/kaweth.c
  52. 622 0
      drivers/usb/net/net1080.c
  53. 0 1
      drivers/usb/net/pegasus.c
  54. 156 0
      drivers/usb/net/plusb.c
  55. 615 0
      drivers/usb/net/rndis_host.c
  56. 0 1
      drivers/usb/net/rtl8150.c
  57. 138 2776
      drivers/usb/net/usbnet.c
  58. 193 0
      drivers/usb/net/usbnet.h
  59. 386 0
      drivers/usb/net/zaurus.c
  60. 0 1
      drivers/usb/net/zd1201.c
  61. 152 99
      drivers/usb/serial/cypress_m8.c
  62. 55 1
      drivers/usb/serial/ftdi_sio.c
  63. 50 4
      drivers/usb/serial/ftdi_sio.h
  64. 1 7
      drivers/usb/serial/keyspan.c
  65. 90 113
      drivers/usb/serial/option.c
  66. 4 2
      drivers/usb/serial/pl2303.c
  67. 12 12
      drivers/usb/serial/usb-serial.c
  68. 12 0
      drivers/usb/storage/Kconfig
  69. 1 0
      drivers/usb/storage/Makefile
  70. 210 0
      drivers/usb/storage/onetouch.c
  71. 9 0
      drivers/usb/storage/onetouch.h
  72. 8 0
      drivers/usb/storage/scsiglue.c
  73. 32 65
      drivers/usb/storage/shuttle_usbat.c
  74. 5 12
      drivers/usb/storage/transport.c
  75. 19 0
      drivers/usb/storage/unusual_devs.h
  76. 51 28
      drivers/usb/storage/usb.c
  77. 1 0
      drivers/usb/storage/usb.h
  78. 3 8
      include/linux/usb.h
  79. 6 24
      include/linux/usb_isp116x.h
  80. 4 6
      sound/usb/usbaudio.c

+ 203 - 0
Documentation/input/yealink.txt

@@ -0,0 +1,203 @@
+Driver documentation for yealink usb-p1k phones
+
+0. Status
+~~~~~~~~~
+
+The p1k is a relatively cheap usb 1.1 phone with:
+  - keyboard		full support, yealink.ko / input event API
+  - LCD			full support, yealink.ko / sysfs API
+  - LED			full support, yealink.ko / sysfs API
+  - dialtone		full support, yealink.ko / sysfs API
+  - ringtone		full support, yealink.ko / sysfs API
+  - audio playback   	full support, snd_usb_audio.ko / alsa API
+  - audio record     	full support, snd_usb_audio.ko / alsa API
+
+For vendor documentation see http://www.yealink.com
+
+
+1. Compilation (stand alone version)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Currently only kernel 2.6.x.y versions are supported.
+In order to build the yealink.ko module do:
+
+  make
+
+If you encounter problems please check if in the MAKE_OPTS variable in
+the Makefile is pointing to the location where your kernel sources
+are located, default /usr/src/linux.
+
+
+
+2. keyboard features
+~~~~~~~~~~~~~~~~~~~~
+The current mapping in the kernel is provided by the map_p1k_to_key
+function:
+
+   Physical USB-P1K button layout	input events
+
+
+              up			     up
+        IN           OUT		left,	right
+             down			    down
+
+      pickup   C    hangup		enter, backspace, escape
+        1      2      3			1, 2, 3
+        4      5      6			4, 5, 6,
+        7      8      9			7, 8, 9,
+        *      0      #			*, 0, #,
+
+  The "up" and "down" keys, are symbolised by arrows on the button.
+  The "pickup" and "hangup" keys are symbolised by a green and red phone
+  on the button.
+
+
+3. LCD features
+~~~~~~~~~~~~~~~
+The LCD is divided and organised as a 3 line display:
+
+    |[]   [][]   [][]   [][]   in   |[][]
+    |[] M [][] D [][] : [][]   out  |[][]
+                              store
+
+    NEW REP         SU MO TU WE TH FR SA
+
+    [] [] [] [] [] [] [] [] [] [] [] []
+    [] [] [] [] [] [] [] [] [] [] [] []
+
+
+Line 1	Format (see below)	: 18.e8.M8.88...188
+	Icon names		:   M  D  :  IN OUT STORE
+Line 2  Format			: .........
+	Icon name		: NEW REP SU MO TU WE TH FR SA
+Line 3  Format			: 888888888888
+
+
+Format description:
+  From a user space perspective the world is seperated in "digits" and "icons".
+  A digit can have a character set, an icon can only be ON or OFF.
+
+  Format specifier
+    '8' :  Generic 7 segment digit with individual addressable segments
+
+    Reduced capabillity 7 segm digit, when segments are hard wired together.
+    '1' : 2 segments digit only able to produce a 1.
+    'e' : Most significant day of the month digit,
+          able to produce at least 1 2 3.
+    'M' : Most significant minute digit,
+          able to produce at least 0 1 2 3 4 5.
+
+    Icons or pictograms:
+    '.' : For example like AM, PM, SU, a 'dot' .. or other single segment
+	  elements.
+
+
+4. Driver usage
+~~~~~~~~~~~~~~~
+For userland the following interfaces are available using the sysfs interface:
+  /sys/.../
+           line1	Read/Write, lcd line1
+           line2	Read/Write, lcd line2
+           line3	Read/Write, lcd line3
+
+	   get_icons    Read, returns a set of available icons.
+	   hide_icon    Write, hide the element by writing the icon name.
+	   show_icon    Write, display the element by writing the icon name.
+
+	   map_seg7	Read/Write, the 7 segments char set, common for all
+	   		yealink phones. (see map_to_7segment.h)
+
+	   ringtone	Write, upload binary representation of a ringtone,
+	   		see yealink.c. status EXPERIMENTAL due to potential
+			races between async. and sync usb calls.
+
+
+4.1 lineX
+~~~~~~~~~
+Reading /sys/../lineX will return the format string with its current value:
+
+  Example:
+  cat ./line3
+  888888888888
+  Linux Rocks!
+
+Writing to /sys/../lineX will set the coresponding LCD line.
+ - Excess characters are ignored.
+ - If less characters are written than allowed, the remaining digits are
+   unchanged.
+ - The tab '\t'and '\n' char does not overwrite the original content.
+ - Writing a space to an icon will always hide its content.
+
+  Example:
+  date +"%m.%e.%k:%M"  | sed 's/^0/ /' > ./line1
+
+  Will update the LCD with the current date & time.
+
+
+4.2 get_icons
+~~~~~~~~~~~~~
+Reading will return all available icon names and its current settings:
+
+  cat ./get_icons
+  on M
+  on D
+  on :
+     IN
+     OUT
+     STORE
+     NEW
+     REP
+     SU
+     MO
+     TU
+     WE
+     TH
+     FR
+     SA
+     LED
+     DIALTONE
+     RINGTONE
+
+
+4.3 show/hide icons
+~~~~~~~~~~~~~~~~~~~
+Writing to these files will update the state of the icon.
+Only one icon at a time can be updated.
+
+If an icon is also on a ./lineX the corresponding value is
+updated with the first letter of the icon.
+
+  Example - light up the store icon:
+  echo -n "STORE" > ./show_icon
+
+  cat ./line1
+  18.e8.M8.88...188
+               S
+
+  Example - sound the ringtone for 10 seconds:
+  echo -n RINGTONE > /sys/..../show_icon
+  sleep 10
+  echo -n RINGTONE > /sys/..../hide_icon
+
+
+5. Sound features
+~~~~~~~~~~~~~~~~~
+Sound is supported by the ALSA driver: snd_usb_audio
+
+One 16-bit channel with sample and playback rates of 8000 Hz is the practical
+limit of the device.
+
+  Example - recording test:
+  arecord -v -d 10 -r 8000 -f S16_LE -t wav  foobar.wav
+
+  Example - playback test:
+  aplay foobar.wav
+
+
+6. Credits & Acknowledgments
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  - Olivier Vandorpe, for starting the usbb2k-api project doing much of
+	the reverse engineering.
+  - Martin Diehl, for pointing out how to handle USB memory allocation.
+  - Dmitry Torokhov, for the numerous code reviews and suggestions.
+

+ 6 - 0
MAINTAINERS

@@ -116,6 +116,12 @@ M:	ajk@iehk.rwth-aachen.de
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
+YEALINK PHONE DRIVER
+P:	Henk Vergonet
+M:	Henk.Vergonet@gmail.com
+L:	usbb2k-api-dev@nongnu.org
+S:	Maintained
+
 8139CP 10/100 FAST ETHERNET DRIVER
 P:	Jeff Garzik
 M:	jgarzik@pobox.com

+ 150 - 123
drivers/block/ub.c

@@ -16,9 +16,10 @@
  *  -- verify the 13 conditions and do bulk resets
  *  -- kill last_pipe and simply do two-state clearing on both pipes
  *  -- verify protocol (bulk) from USB descriptors (maybe...)
- *  -- highmem and sg
+ *  -- highmem
  *  -- move top_sense and work_bcs into separate allocations (if they survive)
  *     for cache purists and esoteric architectures.
+ *  -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ?
  *  -- prune comments, they are too volumnous
  *  -- Exterminate P3 printks
  *  -- Resove XXX's
@@ -171,7 +172,7 @@ struct bulk_cs_wrap {
  */
 struct ub_dev;
 
-#define UB_MAX_REQ_SG	1
+#define UB_MAX_REQ_SG	4
 #define UB_MAX_SECTORS 64
 
 /*
@@ -234,13 +235,10 @@ struct ub_scsi_cmd {
 
 	int stat_count;			/* Retries getting status. */
 
-	/*
-	 * We do not support transfers from highmem pages
-	 * because the underlying USB framework does not do what we need.
-	 */
-	char *data;			/* Requested buffer */
 	unsigned int len;		/* Requested length */
-	// struct scatterlist sgv[UB_MAX_REQ_SG];
+	unsigned int current_sg;
+	unsigned int nsg;		/* sgv[nsg] */
+	struct scatterlist sgv[UB_MAX_REQ_SG];
 
 	struct ub_lun *lun;
 	void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
@@ -389,17 +387,18 @@ struct ub_dev {
 	struct bulk_cs_wrap work_bcs;
 	struct usb_ctrlrequest work_cr;
 
+	int sg_stat[UB_MAX_REQ_SG+1];
 	struct ub_scsi_trace tr;
 };
 
 /*
  */
 static void ub_cleanup(struct ub_dev *sc);
-static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq);
+static int ub_request_fn_1(struct ub_lun *lun, struct request *rq);
 static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_scsi_cmd *cmd, struct request *rq);
-static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    struct request *rq);
+static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_scsi_cmd *cmd, struct request *rq);
 static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
 static void ub_end_rq(struct request *rq, int uptodate);
 static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
@@ -407,6 +406,7 @@ static void ub_urb_complete(struct urb *urb, struct pt_regs *pt);
 static void ub_scsi_action(unsigned long _dev);
 static void ub_scsi_dispatch(struct ub_dev *sc);
 static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
+static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
 static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc);
 static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
 static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
@@ -500,7 +500,8 @@ static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
 	}
 }
 
-static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr, char *page)
+static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr,
+    char *page)
 {
 	struct usb_interface *intf;
 	struct ub_dev *sc;
@@ -523,6 +524,13 @@ static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr, c
 	cnt += sprintf(page + cnt,
 	    "qlen %d qmax %d\n",
 	    sc->cmd_queue.qlen, sc->cmd_queue.qmax);
+	cnt += sprintf(page + cnt,
+	    "sg %d %d %d %d %d\n",
+	    sc->sg_stat[0],
+	    sc->sg_stat[1],
+	    sc->sg_stat[2],
+	    sc->sg_stat[3],
+	    sc->sg_stat[4]);
 
 	list_for_each (p, &sc->luns) {
 		lun = list_entry(p, struct ub_lun, link);
@@ -744,20 +752,20 @@ static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc)
  * The request function is our main entry point
  */
 
-static void ub_bd_rq_fn(request_queue_t *q)
+static void ub_request_fn(request_queue_t *q)
 {
 	struct ub_lun *lun = q->queuedata;
 	struct request *rq;
 
 	while ((rq = elv_next_request(q)) != NULL) {
-		if (ub_bd_rq_fn_1(lun, rq) != 0) {
+		if (ub_request_fn_1(lun, rq) != 0) {
 			blk_stop_queue(q);
 			break;
 		}
 	}
 }
 
-static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq)
+static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
 {
 	struct ub_dev *sc = lun->udev;
 	struct ub_scsi_cmd *cmd;
@@ -774,9 +782,8 @@ static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq)
 	memset(cmd, 0, sizeof(struct ub_scsi_cmd));
 
 	blkdev_dequeue_request(rq);
-
 	if (blk_pc_request(rq)) {
-		rc = ub_cmd_build_packet(sc, cmd, rq);
+		rc = ub_cmd_build_packet(sc, lun, cmd, rq);
 	} else {
 		rc = ub_cmd_build_block(sc, lun, cmd, rq);
 	}
@@ -791,7 +798,7 @@ static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq)
 	cmd->back = rq;
 
 	cmd->tag = sc->tagcnt++;
-	if ((rc = ub_submit_scsi(sc, cmd)) != 0) {
+	if (ub_submit_scsi(sc, cmd) != 0) {
 		ub_put_cmd(lun, cmd);
 		ub_end_rq(rq, 0);
 		return 0;
@@ -804,58 +811,31 @@ static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_scsi_cmd *cmd, struct request *rq)
 {
 	int ub_dir;
-#if 0 /* We use rq->buffer for now */
-	struct scatterlist *sg;
 	int n_elem;
-#endif
 	unsigned int block, nblks;
 
 	if (rq_data_dir(rq) == WRITE)
 		ub_dir = UB_DIR_WRITE;
 	else
 		ub_dir = UB_DIR_READ;
+	cmd->dir = ub_dir;
 
 	/*
 	 * get scatterlist from block layer
 	 */
-#if 0 /* We use rq->buffer for now */
-	sg = &cmd->sgv[0];
-	n_elem = blk_rq_map_sg(q, rq, sg);
+	n_elem = blk_rq_map_sg(lun->disk->queue, rq, &cmd->sgv[0]);
 	if (n_elem <= 0) {
-		ub_put_cmd(lun, cmd);
-		ub_end_rq(rq, 0);
-		blk_start_queue(q);
-		return 0;		/* request with no s/g entries? */
+		printk(KERN_INFO "%s: failed request map (%d)\n",
+		    sc->name, n_elem); /* P3 */
+		return -1;		/* request with no s/g entries? */
 	}
-
-	if (n_elem != 1) {		/* Paranoia */
+	if (n_elem > UB_MAX_REQ_SG) {	/* Paranoia */
 		printk(KERN_WARNING "%s: request with %d segments\n",
 		    sc->name, n_elem);
-		ub_put_cmd(lun, cmd);
-		ub_end_rq(rq, 0);
-		blk_start_queue(q);
-		return 0;
-	}
-#endif
-
-	/*
-	 * XXX Unfortunately, this check does not work. It is quite possible
-	 * to get bogus non-null rq->buffer if you allow sg by mistake.
-	 */
-	if (rq->buffer == NULL) {
-		/*
-		 * This must not happen if we set the queue right.
-		 * The block level must create bounce buffers for us.
-		 */
-		static int do_print = 1;
-		if (do_print) {
-			printk(KERN_WARNING "%s: unmapped block request"
-			    " flags 0x%lx sectors %lu\n",
-			    sc->name, rq->flags, rq->nr_sectors);
-			do_print = 0;
-		}
 		return -1;
 	}
+	cmd->nsg = n_elem;
+	sc->sg_stat[n_elem]++;
 
 	/*
 	 * build the command
@@ -876,30 +856,15 @@ static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
 	cmd->cdb[8] = nblks;
 	cmd->cdb_len = 10;
 
-	cmd->dir = ub_dir;
-	cmd->data = rq->buffer;
 	cmd->len = rq->nr_sectors * 512;
 
 	return 0;
 }
 
-static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
-    struct request *rq)
+static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
+    struct ub_scsi_cmd *cmd, struct request *rq)
 {
-
-	if (rq->data_len != 0 && rq->data == NULL) {
-		static int do_print = 1;
-		if (do_print) {
-			printk(KERN_WARNING "%s: unmapped packet request"
-			    " flags 0x%lx length %d\n",
-			    sc->name, rq->flags, rq->data_len);
-			do_print = 0;
-		}
-		return -1;
-	}
-
-	memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
-	cmd->cdb_len = rq->cmd_len;
+	int n_elem;
 
 	if (rq->data_len == 0) {
 		cmd->dir = UB_DIR_NONE;
@@ -908,8 +873,29 @@ static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
 			cmd->dir = UB_DIR_WRITE;
 		else
 			cmd->dir = UB_DIR_READ;
+
+	}
+
+	/*
+	 * get scatterlist from block layer
+	 */
+	n_elem = blk_rq_map_sg(lun->disk->queue, rq, &cmd->sgv[0]);
+	if (n_elem < 0) {
+		printk(KERN_INFO "%s: failed request map (%d)\n",
+		    sc->name, n_elem); /* P3 */
+		return -1;
 	}
-	cmd->data = rq->data;
+	if (n_elem > UB_MAX_REQ_SG) {	/* Paranoia */
+		printk(KERN_WARNING "%s: request with %d segments\n",
+		    sc->name, n_elem);
+		return -1;
+	}
+	cmd->nsg = n_elem;
+	sc->sg_stat[n_elem]++;
+
+	memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
+	cmd->cdb_len = rq->cmd_len;
+
 	cmd->len = rq->data_len;
 
 	return 0;
@@ -919,24 +905,34 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 {
 	struct request *rq = cmd->back;
 	struct ub_lun *lun = cmd->lun;
-	struct gendisk *disk = lun->disk;
-	request_queue_t *q = disk->queue;
 	int uptodate;
 
-	if (blk_pc_request(rq)) {
-		/* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
-		memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
-		rq->sense_len = UB_SENSE_SIZE;
-	}
-
-	if (cmd->error == 0)
+	if (cmd->error == 0) {
 		uptodate = 1;
-	else
+
+		if (blk_pc_request(rq)) {
+			if (cmd->act_len >= rq->data_len)
+				rq->data_len = 0;
+			else
+				rq->data_len -= cmd->act_len;
+		}
+	} else {
 		uptodate = 0;
 
+		if (blk_pc_request(rq)) {
+			/* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
+			memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
+			rq->sense_len = UB_SENSE_SIZE;
+			if (sc->top_sense[0] != 0)
+				rq->errors = SAM_STAT_CHECK_CONDITION;
+			else
+				rq->errors = DID_ERROR << 16;
+		}
+	}
+
 	ub_put_cmd(lun, cmd);
 	ub_end_rq(rq, uptodate);
-	blk_start_queue(q);
+	blk_start_queue(lun->disk->queue);
 }
 
 static void ub_end_rq(struct request *rq, int uptodate)
@@ -1014,7 +1010,7 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 	sc->last_pipe = sc->send_bulk_pipe;
 	usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,
 	    bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);
-	sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
+	sc->work_urb.transfer_flags = 0;
 
 	/* Fill what we shouldn't be filling, because usb-storage did so. */
 	sc->work_urb.actual_length = 0;
@@ -1103,7 +1099,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 {
 	struct urb *urb = &sc->work_urb;
 	struct bulk_cs_wrap *bcs;
-	int pipe;
 	int rc;
 
 	if (atomic_read(&sc->poison)) {
@@ -1204,38 +1199,13 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 			goto Bad_End;
 		}
 
-		if (cmd->dir == UB_DIR_NONE) {
+		if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) {
 			ub_state_stat(sc, cmd);
 			return;
 		}
 
-		UB_INIT_COMPLETION(sc->work_done);
-
-		if (cmd->dir == UB_DIR_READ)
-			pipe = sc->recv_bulk_pipe;
-		else
-			pipe = sc->send_bulk_pipe;
-		sc->last_pipe = pipe;
-		usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,
-		    cmd->data, cmd->len, ub_urb_complete, sc);
-		sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
-		sc->work_urb.actual_length = 0;
-		sc->work_urb.error_count = 0;
-		sc->work_urb.status = 0;
-
-		if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
-			/* XXX Clear stalls */
-			printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
-			ub_complete(&sc->work_done);
-			ub_state_done(sc, cmd, rc);
-			return;
-		}
-
-		sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
-		add_timer(&sc->work_timer);
-
-		cmd->state = UB_CMDST_DATA;
-		ub_cmdtr_state(sc, cmd);
+		// udelay(125);		// usb-storage has this
+		ub_data_start(sc, cmd);
 
 	} else if (cmd->state == UB_CMDST_DATA) {
 		if (urb->status == -EPIPE) {
@@ -1257,16 +1227,22 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 		if (urb->status == -EOVERFLOW) {
 			/*
 			 * A babble? Failure, but we must transfer CSW now.
+			 * XXX This is going to end in perpetual babble. Reset.
 			 */
 			cmd->error = -EOVERFLOW;	/* A cheap trick... */
-		} else {
-			if (urb->status != 0)
-				goto Bad_End;
+			ub_state_stat(sc, cmd);
+			return;
 		}
+		if (urb->status != 0)
+			goto Bad_End;
 
-		cmd->act_len = urb->actual_length;
+		cmd->act_len += urb->actual_length;
 		ub_cmdtr_act_len(sc, cmd);
 
+		if (++cmd->current_sg < cmd->nsg) {
+			ub_data_start(sc, cmd);
+			return;
+		}
 		ub_state_stat(sc, cmd);
 
 	} else if (cmd->state == UB_CMDST_STAT) {
@@ -1399,6 +1375,46 @@ Bad_End: /* Little Excel is dead */
 	ub_state_done(sc, cmd, -EIO);
 }
 
+/*
+ * Factorization helper for the command state machine:
+ * Initiate a data segment transfer.
+ */
+static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+	struct scatterlist *sg = &cmd->sgv[cmd->current_sg];
+	int pipe;
+	int rc;
+
+	UB_INIT_COMPLETION(sc->work_done);
+
+	if (cmd->dir == UB_DIR_READ)
+		pipe = sc->recv_bulk_pipe;
+	else
+		pipe = sc->send_bulk_pipe;
+	sc->last_pipe = pipe;
+	usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,
+	    page_address(sg->page) + sg->offset, sg->length,
+	    ub_urb_complete, sc);
+	sc->work_urb.transfer_flags = 0;
+	sc->work_urb.actual_length = 0;
+	sc->work_urb.error_count = 0;
+	sc->work_urb.status = 0;
+
+	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+		/* XXX Clear stalls */
+		printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
+		ub_complete(&sc->work_done);
+		ub_state_done(sc, cmd, rc);
+		return;
+	}
+
+	sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
+	add_timer(&sc->work_timer);
+
+	cmd->state = UB_CMDST_DATA;
+	ub_cmdtr_state(sc, cmd);
+}
+
 /*
  * Factorization helper for the command state machine:
  * Finish the command.
@@ -1426,7 +1442,7 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 	sc->last_pipe = sc->recv_bulk_pipe;
 	usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,
 	    &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
-	sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
+	sc->work_urb.transfer_flags = 0;
 	sc->work_urb.actual_length = 0;
 	sc->work_urb.error_count = 0;
 	sc->work_urb.status = 0;
@@ -1484,6 +1500,7 @@ static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 {
 	struct ub_scsi_cmd *scmd;
+	struct scatterlist *sg;
 	int rc;
 
 	if (cmd->cdb[0] == REQUEST_SENSE) {
@@ -1492,12 +1509,17 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 	}
 
 	scmd = &sc->top_rqs_cmd;
+	memset(scmd, 0, sizeof(struct ub_scsi_cmd));
 	scmd->cdb[0] = REQUEST_SENSE;
 	scmd->cdb[4] = UB_SENSE_SIZE;
 	scmd->cdb_len = 6;
 	scmd->dir = UB_DIR_READ;
 	scmd->state = UB_CMDST_INIT;
-	scmd->data = sc->top_sense;
+	scmd->nsg = 1;
+	sg = &scmd->sgv[0];
+	sg->page = virt_to_page(sc->top_sense);
+	sg->offset = (unsigned int)sc->top_sense & (PAGE_SIZE-1);
+	sg->length = UB_SENSE_SIZE;
 	scmd->len = UB_SENSE_SIZE;
 	scmd->lun = cmd->lun;
 	scmd->done = ub_top_sense_done;
@@ -1541,7 +1563,7 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
 
 	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
 	    (unsigned char*) cr, NULL, 0, ub_urb_complete, sc);
-	sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
+	sc->work_urb.transfer_flags = 0;
 	sc->work_urb.actual_length = 0;
 	sc->work_urb.error_count = 0;
 	sc->work_urb.status = 0;
@@ -1560,7 +1582,7 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
  */
 static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
 {
-	unsigned char *sense = scmd->data;
+	unsigned char *sense = sc->top_sense;
 	struct ub_scsi_cmd *cmd;
 
 	/*
@@ -1852,6 +1874,7 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_capacity *ret)
 {
 	struct ub_scsi_cmd *cmd;
+	struct scatterlist *sg;
 	char *p;
 	enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 };
 	unsigned long flags;
@@ -1872,7 +1895,11 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
 	cmd->cdb_len = 10;
 	cmd->dir = UB_DIR_READ;
 	cmd->state = UB_CMDST_INIT;
-	cmd->data = p;
+	cmd->nsg = 1;
+	sg = &cmd->sgv[0];
+	sg->page = virt_to_page(p);
+	sg->offset = (unsigned int)p & (PAGE_SIZE-1);
+	sg->length = 8;
 	cmd->len = 8;
 	cmd->lun = lun;
 	cmd->done = ub_probe_done;
@@ -2289,7 +2316,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
 	disk->driverfs_dev = &sc->intf->dev;	/* XXX Many to one ok? */
 
 	rc = -ENOMEM;
-	if ((q = blk_init_queue(ub_bd_rq_fn, &sc->lock)) == NULL)
+	if ((q = blk_init_queue(ub_request_fn, &sc->lock)) == NULL)
 		goto err_blkqinit;
 
 	disk->queue = q;

+ 2 - 11
drivers/net/irda/irda-usb.c

@@ -267,7 +267,7 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
                       frame, IRDA_USB_SPEED_MTU,
                       speed_bulk_callback, self);
 	urb->transfer_buffer_length = USB_IRDA_HEADER;
-	urb->transfer_flags = URB_ASYNC_UNLINK;
+	urb->transfer_flags = 0;
 
 	/* Irq disabled -> GFP_ATOMIC */
 	if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) {
@@ -401,15 +401,12 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
                       skb->data, IRDA_SKB_MAX_MTU,
                       write_bulk_callback, skb);
 	urb->transfer_buffer_length = skb->len;
-	/* Note : unlink *must* be Asynchronous because of the code in 
-	 * irda_usb_net_timeout() -> call in irq - Jean II */
-	urb->transfer_flags = URB_ASYNC_UNLINK;
 	/* This flag (URB_ZERO_PACKET) indicates that what we send is not
 	 * a continuous stream of data but separate packets.
 	 * In this case, the USB layer will insert an empty USB frame (TD)
 	 * after each of our packets that is exact multiple of the frame size.
 	 * This is how the dongle will detect the end of packet - Jean II */
-	urb->transfer_flags |= URB_ZERO_PACKET;
+	urb->transfer_flags = URB_ZERO_PACKET;
 
 	/* Generate min turn time. FIXME: can we do better than this? */
 	/* Trying to a turnaround time at this level is trying to measure
@@ -630,8 +627,6 @@ static void irda_usb_net_timeout(struct net_device *netdev)
 			 * in completion handler, because urb->status will
 			 * be -ENOENT. We will fix that at the next watchdog,
 			 * leaving more time to USB to recover...
-			 * Also, we are in interrupt, so we need to have
-			 * URB_ASYNC_UNLINK to work properly...
 			 * Jean II */
 			done = 1;
 			break;
@@ -1008,9 +1003,7 @@ static int irda_usb_net_close(struct net_device *netdev)
 		}
 	}
 	/* Cancel Tx and speed URB - need to be synchronous to avoid races */
-	self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 	usb_kill_urb(self->tx_urb);
-	self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 	usb_kill_urb(self->speed_urb);
 
 	/* Stop and remove instance of IrLAP */
@@ -1521,9 +1514,7 @@ static void irda_usb_disconnect(struct usb_interface *intf)
 			usb_kill_urb(self->rx_urb[i]);
 		/* Cancel Tx and speed URB.
 		 * Toggle flags to make sure it's synchronous. */
-		self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 		usb_kill_urb(self->tx_urb);
-		self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 		usb_kill_urb(self->speed_urb);
 	}
 

+ 0 - 2
drivers/usb/atm/cxacru.c

@@ -715,13 +715,11 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
 			usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD),
 			instance->rcv_buf, PAGE_SIZE,
 			cxacru_blocking_completion, &instance->rcv_done, 1);
-	instance->rcv_urb->transfer_flags |= URB_ASYNC_UNLINK;
 
 	usb_fill_int_urb(instance->snd_urb,
 			usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD),
 			instance->snd_buf, PAGE_SIZE,
 			cxacru_blocking_completion, &instance->snd_done, 4);
-	instance->snd_urb->transfer_flags |= URB_ASYNC_UNLINK;
 
 	init_MUTEX(&instance->cm_serialize);
 

+ 18 - 3
drivers/usb/class/Kconfig

@@ -4,9 +4,22 @@
 comment "USB Device Class drivers"
 	depends on USB
 
+config OBSOLETE_OSS_USB_DRIVER
+	bool "Obsolete OSS USB drivers"
+	depends on USB && SOUND
+	help
+	  This option enables support for the obsolete USB Audio and Midi
+	  drivers that are scheduled for removal in the near future since
+	  there are ALSA drivers for the same hardware.
+
+	  Please contact Adrian Bunk <bunk@stusta.de> if you had to
+	  say Y here because of missing support in the ALSA drivers.
+
+	  If unsure, say N.
+
 config USB_AUDIO
 	tristate "USB Audio support"
-	depends on USB && SOUND
+	depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
 	help
 	  Say Y here if you want to connect USB audio equipment such as
 	  speakers to your computer's USB port. You only need this if you use
@@ -40,10 +53,12 @@ config USB_BLUETOOTH_TTY
 
 config USB_MIDI
 	tristate "USB MIDI support"
-	depends on USB && SOUND
+	depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
 	---help---
 	  Say Y here if you want to connect a USB MIDI device to your
-	  computer's USB port. This driver is for devices that comply with
+	  computer's USB port.  You only need this if you use the OSS
+	  sound system; USB MIDI devices are supported by ALSA's USB
+	  audio driver. This driver is for devices that comply with
 	  'Universal Serial Bus Device Class Definition for MIDI Device'.
 
 	  The following devices are known to work:

+ 6 - 3
drivers/usb/class/usblp.c

@@ -310,8 +310,9 @@ static int usblp_check_status(struct usblp *usblp, int err)
 
 	error = usblp_read_status (usblp, usblp->statusbuf);
 	if (error < 0) {
-		err("usblp%d: error %d reading printer status",
-			usblp->minor, error);
+		if (printk_ratelimit())
+			err("usblp%d: error %d reading printer status",
+				usblp->minor, error);
 		return 0;
 	}
 
@@ -604,7 +605,9 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 
 			case LPGETSTATUS:
 				if (usblp_read_status(usblp, usblp->statusbuf)) {
-					err("usblp%d: failed reading printer status", usblp->minor);
+					if (printk_ratelimit())
+						err("usblp%d: failed reading printer status",
+							usblp->minor);
 					retval = -EIO;
 					goto done;
 				}

+ 2 - 2
drivers/usb/core/Makefile

@@ -3,14 +3,14 @@
 #
 
 usbcore-objs	:= usb.o hub.o hcd.o urb.o message.o \
-			config.o file.o buffer.o sysfs.o
+			config.o file.o buffer.o sysfs.o devio.o
 
 ifeq ($(CONFIG_PCI),y)
 	usbcore-objs	+= hcd-pci.o
 endif
 
 ifeq ($(CONFIG_USB_DEVICEFS),y)
-	usbcore-objs	+= devio.o inode.o devices.o
+	usbcore-objs	+= inode.o devices.o
 endif
 
 obj-$(CONFIG_USB)	+= usbcore.o

+ 90 - 12
drivers/usb/core/devio.c

@@ -43,6 +43,7 @@
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/cdev.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <linux/moduleparam.h>
@@ -50,6 +51,10 @@
 #include "hcd.h"	/* for usbcore internals */
 #include "usb.h"
 
+#define USB_MAXBUS			64
+#define USB_DEVICE_MAX			USB_MAXBUS * 128
+static struct class *usb_device_class;
+
 struct async {
 	struct list_head asynclist;
 	struct dev_state *ps;
@@ -71,6 +76,8 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
 			dev_info( dev , format , ## arg);	\
 	} while (0)
 
+#define USB_DEVICE_DEV		MKDEV(USB_DEVICE_MAJOR, 0)
+
 
 #define	MAX_USBFS_BUFFER_SIZE	16384
 
@@ -487,7 +494,7 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
  */
 static int usbdev_open(struct inode *inode, struct file *file)
 {
-	struct usb_device *dev;
+	struct usb_device *dev = NULL;
 	struct dev_state *ps;
 	int ret;
 
@@ -501,11 +508,16 @@ static int usbdev_open(struct inode *inode, struct file *file)
 
 	lock_kernel();
 	ret = -ENOENT;
-	dev = usb_get_dev(inode->u.generic_ip);
+	/* check if we are called from a real node or usbfs */
+	if (imajor(inode) == USB_DEVICE_MAJOR)
+		dev = usbdev_lookup_minor(iminor(inode));
+	if (!dev)
+		dev = inode->u.generic_ip;
 	if (!dev) {
 		kfree(ps);
 		goto out;
 	}
+	usb_get_dev(dev);
 	ret = 0;
 	ps->dev = dev;
 	ps->file = file;
@@ -1226,7 +1238,6 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
 	int			retval = 0;
 	struct usb_interface    *intf = NULL;
 	struct usb_driver       *driver = NULL;
-	int			i;
 
 	/* get input parameters and alloc buffer */
 	if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
@@ -1258,15 +1269,6 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
 	/* disconnect kernel driver from interface */
 	case USBDEVFS_DISCONNECT:
 
-		/* don't allow the user to unbind the hub driver from
-		 * a hub with children to manage */
-		for (i = 0; i < ps->dev->maxchild; ++i) {
-			if (ps->dev->children[i])
-				retval = -EBUSY;
-		}
-		if (retval)
-			break;
-
 		down_write(&usb_bus_type.subsys.rwsem);
 		if (intf->dev.driver) {
 			driver = to_usb_driver(intf->dev.driver);
@@ -1477,3 +1479,79 @@ struct file_operations usbfs_device_file_operations = {
 	.open =		usbdev_open,
 	.release =	usbdev_release,
 };
+
+struct usb_device *usbdev_lookup_minor(int minor)
+{
+	struct class_device *class_dev;
+	struct usb_device *dev = NULL;
+
+	down(&usb_device_class->sem);
+	list_for_each_entry(class_dev, &usb_device_class->children, node) {
+		if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+			dev = class_dev->class_data;
+			break;
+		}
+	}
+	up(&usb_device_class->sem);
+
+	return dev;
+};
+
+void usbdev_add(struct usb_device *dev)
+{
+	int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
+
+	dev->class_dev = class_device_create(usb_device_class,
+				MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+				"usbdev%d.%d", dev->bus->busnum, dev->devnum);
+
+	dev->class_dev->class_data = dev;
+}
+
+void usbdev_remove(struct usb_device *dev)
+{
+	class_device_unregister(dev->class_dev);
+}
+
+static struct cdev usb_device_cdev = {
+	.kobj   = {.name = "usb_device", },
+	.owner  = THIS_MODULE,
+};
+
+int __init usbdev_init(void)
+{
+	int retval;
+
+	retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
+			"usb_device");
+	if (retval) {
+		err("unable to register minors for usb_device");
+		goto out;
+	}
+	cdev_init(&usb_device_cdev, &usbfs_device_file_operations);
+	retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
+	if (retval) {
+		err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
+		unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
+		goto out;
+	}
+	usb_device_class = class_create(THIS_MODULE, "usb_device");
+	if (IS_ERR(usb_device_class)) {
+		err("unable to register usb_device class");
+		retval = PTR_ERR(usb_device_class);
+		usb_device_class = NULL;
+		cdev_del(&usb_device_cdev);
+		unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
+	}
+
+out:
+	return retval;
+}
+
+void usbdev_cleanup(void)
+{
+	class_destroy(usb_device_class);
+	cdev_del(&usb_device_cdev);
+	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
+}
+

+ 4 - 4
drivers/usb/core/hcd.h

@@ -339,11 +339,11 @@ extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
  * to preallocate bandwidth)
  */
 #define USB2_HOST_DELAY	5	/* nsec, guess */
-#define HS_NSECS(bytes) ( ((55 * 8 * 2083)/1000) \
-	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
+#define HS_NSECS(bytes) ( ((55 * 8 * 2083) \
+	+ (2083UL * (3 + BitTime(bytes))))/1000 \
 	+ USB2_HOST_DELAY)
-#define HS_NSECS_ISO(bytes) ( ((38 * 8 * 2083)/1000) \
-	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
+#define HS_NSECS_ISO(bytes) ( ((38 * 8 * 2083) \
+	+ (2083UL * (3 + BitTime(bytes))))/1000 \
 	+ USB2_HOST_DELAY)
 #define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes))
 #define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(bytes))

+ 83 - 32
drivers/usb/core/hub.c

@@ -492,6 +492,23 @@ static int hub_hub_status(struct usb_hub *hub,
 	return ret;
 }
 
+static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
+{
+	struct usb_device *hdev = hub->hdev;
+	int ret;
+
+	if (hdev->children[port1-1] && set_state) {
+		usb_set_device_state(hdev->children[port1-1],
+				USB_STATE_NOTATTACHED);
+	}
+	ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
+	if (ret)
+		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
+			port1, ret);
+
+	return ret;
+}
+
 static int hub_configure(struct usb_hub *hub,
 	struct usb_endpoint_descriptor *endpoint)
 {
@@ -610,19 +627,33 @@ static int hub_configure(struct usb_hub *hub,
 			break;
 	}
 
+	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
 	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) {
-		case 0x00:
-			if (hdev->descriptor.bDeviceProtocol != 0)
-				dev_dbg(hub_dev, "TT requires at most 8 FS bit times\n");
+		case HUB_TTTT_8_BITS:
+			if (hdev->descriptor.bDeviceProtocol != 0) {
+				hub->tt.think_time = 666;
+				dev_dbg(hub_dev, "TT requires at most %d "
+						"FS bit times (%d ns)\n",
+					8, hub->tt.think_time);
+			}
 			break;
-		case 0x20:
-			dev_dbg(hub_dev, "TT requires at most 16 FS bit times\n");
+		case HUB_TTTT_16_BITS:
+			hub->tt.think_time = 666 * 2;
+			dev_dbg(hub_dev, "TT requires at most %d "
+					"FS bit times (%d ns)\n",
+				16, hub->tt.think_time);
 			break;
-		case 0x40:
-			dev_dbg(hub_dev, "TT requires at most 24 FS bit times\n");
+		case HUB_TTTT_24_BITS:
+			hub->tt.think_time = 666 * 3;
+			dev_dbg(hub_dev, "TT requires at most %d "
+					"FS bit times (%d ns)\n",
+				24, hub->tt.think_time);
 			break;
-		case 0x60:
-			dev_dbg(hub_dev, "TT requires at most 32 FS bit times\n");
+		case HUB_TTTT_32_BITS:
+			hub->tt.think_time = 666 * 4;
+			dev_dbg(hub_dev, "TT requires at most %d "
+					"FS bit times (%d ns)\n",
+				32, hub->tt.think_time);
 			break;
 	}
 
@@ -712,20 +743,36 @@ fail:
 
 static unsigned highspeed_hubs;
 
+/* Called after the hub driver is unbound from a hub with children */
+static void hub_remove_children_work(void *__hub)
+{
+	struct usb_hub		*hub = __hub;
+	struct usb_device	*hdev = hub->hdev;
+	int			i;
+
+	kfree(hub);
+
+	usb_lock_device(hdev);
+	for (i = 0; i < hdev->maxchild; ++i) {
+		if (hdev->children[i])
+			usb_disconnect(&hdev->children[i]);
+	}
+	usb_unlock_device(hdev);
+	usb_put_dev(hdev);
+}
+
 static void hub_disconnect(struct usb_interface *intf)
 {
 	struct usb_hub *hub = usb_get_intfdata (intf);
 	struct usb_device *hdev;
+	int n, port1;
 
-	if (!hub)
-		return;
+	usb_set_intfdata (intf, NULL);
 	hdev = hub->hdev;
 
 	if (hdev->speed == USB_SPEED_HIGH)
 		highspeed_hubs--;
 
-	usb_set_intfdata (intf, NULL);
-
 	hub_quiesce(hub);
 	usb_free_urb(hub->urb);
 	hub->urb = NULL;
@@ -746,8 +793,27 @@ static void hub_disconnect(struct usb_interface *intf)
 		hub->buffer = NULL;
 	}
 
-	/* Free the memory */
-	kfree(hub);
+	/* If there are any children then this is an unbind only, not a
+	 * physical disconnection.  The active ports must be disabled
+	 * and later on we must call usb_disconnect().  We can't call
+	 * it now because we may not hold the hub's device lock.
+	 */
+	n = 0;
+	for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
+		if (hdev->children[port1 - 1]) {
+			++n;
+			hub_port_disable(hub, port1, 1);
+		}
+	}
+
+	if (n == 0)
+		kfree(hub);
+	else {
+		/* Reuse the hub->leds work_struct for our own purposes */
+		INIT_WORK(&hub->leds, hub_remove_children_work, hub);
+		schedule_work(&hub->leds);
+		usb_get_dev(hdev);
+	}
 }
 
 static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -1051,6 +1117,7 @@ void usb_disconnect(struct usb_device **pdev)
 	dev_dbg (&udev->dev, "unregistering device\n");
 	release_address(udev);
 	usbfs_remove_device(udev);
+	usbdev_remove(udev);
 	usb_remove_sysfs_dev_files(udev);
 
 	/* Avoid races with recursively_mark_NOTATTACHED() */
@@ -1290,6 +1357,7 @@ int usb_new_device(struct usb_device *udev)
 	/* USB device state == configured ... usable */
 
 	/* add a /proc/bus/usb entry */
+	usbdev_add(udev);
 	usbfs_add_device(udev);
 	return 0;
 
@@ -1428,23 +1496,6 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 	return status;
 }
 
-static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
-{
-	struct usb_device *hdev = hub->hdev;
-	int ret;
-
-	if (hdev->children[port1-1] && set_state) {
-		usb_set_device_state(hdev->children[port1-1],
-				USB_STATE_NOTATTACHED);
-	}
-	ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
-	if (ret)
-		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
-			port1, ret);
-
-	return ret;
-}
-
 /*
  * Disable a port and mark a logical connnect-change event, so that some
  * time later khubd will disconnect() any existing usb_device on the port

+ 7 - 0
drivers/usb/core/hub.h

@@ -157,6 +157,12 @@ enum hub_led_mode {
 
 struct usb_device;
 
+/* Transaction Translator Think Times, in bits */
+#define HUB_TTTT_8_BITS		0x00
+#define HUB_TTTT_16_BITS	0x20
+#define HUB_TTTT_24_BITS	0x40
+#define HUB_TTTT_32_BITS	0x60
+
 /*
  * As of USB 2.0, full/low speed devices are segregated into trees.
  * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
@@ -170,6 +176,7 @@ struct usb_device;
 struct usb_tt {
 	struct usb_device	*hub;	/* upstream highspeed hub */
 	int			multi;	/* true means one TT per port */
+	unsigned		think_time;	/* think time in ns */
 
 	/* for control/bulk error recovery (CLEAR_TT_BUFFER) */
 	spinlock_t		lock;

+ 1 - 8
drivers/usb/core/inode.c

@@ -728,15 +728,9 @@ int __init usbfs_init(void)
 {
 	int retval;
 
-	retval = usb_register(&usbfs_driver);
-	if (retval)
-		return retval;
-
 	retval = register_filesystem(&usb_fs_type);
-	if (retval) {
-		usb_deregister(&usbfs_driver);
+	if (retval)
 		return retval;
-	}
 
 	/* create mount point for usbfs */
 	usbdir = proc_mkdir("usb", proc_bus);
@@ -746,7 +740,6 @@ int __init usbfs_init(void)
 
 void usbfs_cleanup(void)
 {
-	usb_deregister(&usbfs_driver);
 	unregister_filesystem(&usb_fs_type);
 	if (usbdir)
 		remove_proc_entry("usb", proc_bus);

+ 4 - 4
drivers/usb/core/message.c

@@ -48,7 +48,6 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
 
 	init_completion(&done); 	
 	urb->context = &done;
-	urb->transfer_flags |= URB_ASYNC_UNLINK;
 	urb->actual_length = 0;
 	status = usb_submit_urb(urb, GFP_NOIO);
 
@@ -266,7 +265,9 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs)
 				continue;
 			if (found) {
 				status = usb_unlink_urb (io->urbs [i]);
-				if (status != -EINPROGRESS && status != -EBUSY)
+				if (status != -EINPROGRESS
+						&& status != -ENODEV
+						&& status != -EBUSY)
 					dev_err (&io->dev->dev,
 						"%s, unlink --> %d\n",
 						__FUNCTION__, status);
@@ -357,8 +358,7 @@ int usb_sg_init (
 	if (!io->urbs)
 		goto nomem;
 
-	urb_flags = URB_ASYNC_UNLINK | URB_NO_TRANSFER_DMA_MAP
-			| URB_NO_INTERRUPT;
+	urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
 	if (usb_pipein (pipe))
 		urb_flags |= URB_SHORT_NOT_OK;
 

+ 4 - 22
drivers/usb/core/urb.c

@@ -309,9 +309,8 @@ int usb_submit_urb(struct urb *urb, unsigned mem_flags)
 	unsigned int	allowed;
 
 	/* enforce simple/standard policy */
-	allowed = URB_ASYNC_UNLINK;	// affects later unlinks
-	allowed |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
-	allowed |= URB_NO_INTERRUPT;
+	allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
+			URB_NO_INTERRUPT);
 	switch (temp) {
 	case PIPE_BULK:
 		if (is_out)
@@ -400,14 +399,8 @@ int usb_submit_urb(struct urb *urb, unsigned mem_flags)
  * canceled (rather than any other code) and will quickly be removed
  * from host controller data structures.
  *
- * In the past, clearing the URB_ASYNC_UNLINK transfer flag for the
- * URB indicated that the request was synchronous.  This usage is now
- * deprecated; if the flag is clear the call will be forwarded to
- * usb_kill_urb() and the return value will be 0.  In the future, drivers
- * should call usb_kill_urb() directly for synchronous unlinking.
- *
- * When the URB_ASYNC_UNLINK transfer flag for the URB is set, this
- * request is asynchronous.  Success is indicated by returning -EINPROGRESS,
+ * This request is always asynchronous.
+ * Success is indicated by returning -EINPROGRESS,
  * at which time the URB will normally have been unlinked but not yet
  * given back to the device driver.  When it is called, the completion
  * function will see urb->status == -ECONNRESET.  Failure is indicated
@@ -453,17 +446,6 @@ int usb_unlink_urb(struct urb *urb)
 {
 	if (!urb)
 		return -EINVAL;
-	if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) {
-#ifdef CONFIG_DEBUG_KERNEL
-		if (printk_ratelimit()) {
-			printk(KERN_NOTICE "usb_unlink_urb() is deprecated for "
-				"synchronous unlinks.  Use usb_kill_urb() instead.\n");
-			WARN_ON(1);
-		}
-#endif
-		usb_kill_urb(urb);
-		return 0;
-	}
 	if (!(urb->dev && urb->dev->bus && urb->dev->bus->op))
 		return -ENODEV;
 	return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET);

+ 32 - 3
drivers/usb/core/usb.c

@@ -65,6 +65,16 @@ static int generic_probe (struct device *dev)
 }
 static int generic_remove (struct device *dev)
 {
+	struct usb_device *udev = to_usb_device(dev);
+
+	/* if this is only an unbind, not a physical disconnect, then
+	 * unconfigure the device */
+	if (udev->state == USB_STATE_CONFIGURED)
+		usb_set_configuration(udev, 0);
+
+	/* in case the call failed or the device was suspended */
+	if (udev->state >= USB_STATE_CONFIGURED)
+		usb_disable_device(udev, 0);
 	return 0;
 }
 
@@ -912,7 +922,7 @@ int usb_trylock_device(struct usb_device *udev)
  * is neither BINDING nor BOUND.  Rather than sleeping to wait for the
  * lock, the routine polls repeatedly.  This is to prevent deadlock with
  * disconnect; in some drivers (such as usb-storage) the disconnect()
- * callback will block waiting for a device reset to complete.
+ * or suspend() method will block waiting for a device reset to complete.
  *
  * Returns a negative error code for failure, otherwise 1 or 0 to indicate
  * that the device will or will not have to be unlocked.  (0 can be
@@ -922,6 +932,8 @@ int usb_trylock_device(struct usb_device *udev)
 int usb_lock_device_for_reset(struct usb_device *udev,
 		struct usb_interface *iface)
 {
+	unsigned long jiffies_expire = jiffies + HZ;
+
 	if (udev->state == USB_STATE_NOTATTACHED)
 		return -ENODEV;
 	if (udev->state == USB_STATE_SUSPENDED)
@@ -938,6 +950,12 @@ int usb_lock_device_for_reset(struct usb_device *udev,
 	}
 
 	while (!usb_trylock_device(udev)) {
+
+		/* If we can't acquire the lock after waiting one second,
+		 * we're probably deadlocked */
+		if (time_after(jiffies, jiffies_expire))
+			return -EBUSY;
+
 		msleep(15);
 		if (udev->state == USB_STATE_NOTATTACHED)
 			return -ENODEV;
@@ -1478,13 +1496,18 @@ static int __init usb_init(void)
 	retval = usb_major_init();
 	if (retval)
 		goto major_init_failed;
+	retval = usb_register(&usbfs_driver);
+	if (retval)
+		goto driver_register_failed;
+	retval = usbdev_init();
+	if (retval)
+		goto usbdevice_init_failed;
 	retval = usbfs_init();
 	if (retval)
 		goto fs_init_failed;
 	retval = usb_hub_init();
 	if (retval)
 		goto hub_init_failed;
-
 	retval = driver_register(&usb_generic_driver);
 	if (!retval)
 		goto out;
@@ -1493,7 +1516,11 @@ static int __init usb_init(void)
 hub_init_failed:
 	usbfs_cleanup();
 fs_init_failed:
-	usb_major_cleanup();	
+	usbdev_cleanup();
+usbdevice_init_failed:
+	usb_deregister(&usbfs_driver);
+driver_register_failed:
+	usb_major_cleanup();
 major_init_failed:
 	usb_host_cleanup();
 host_init_failed:
@@ -1514,6 +1541,8 @@ static void __exit usb_exit(void)
 	driver_unregister(&usb_generic_driver);
 	usb_major_cleanup();
 	usbfs_cleanup();
+	usb_deregister(&usbfs_driver);
+	usbdev_cleanup();
 	usb_hub_cleanup();
 	usb_host_cleanup();
 	bus_unregister(&usb_bus_type);

+ 5 - 0
drivers/usb/core/usb.h

@@ -37,6 +37,11 @@ extern struct file_operations usbfs_devices_fops;
 extern struct file_operations usbfs_device_file_operations;
 extern void usbfs_conn_disc_event(void);
 
+extern int usbdev_init(void);
+extern void usbdev_cleanup(void);
+extern void usbdev_add(struct usb_device *dev);
+extern void usbdev_remove(struct usb_device *dev);
+extern struct usb_device *usbdev_lookup_minor(int minor);
 
 struct dev_state {
 	struct list_head list;      /* state list */

+ 8 - 25
drivers/usb/gadget/ether.c

@@ -2181,6 +2181,7 @@ eth_bind (struct usb_gadget *gadget)
 	u8			cdc = 1, zlp = 1, rndis = 1;
 	struct usb_ep		*in_ep, *out_ep, *status_ep = NULL;
 	int			status = -ENOMEM;
+	int			gcnum;
 
 	/* these flags are only ever cleared; compiler take note */
 #ifndef	DEV_CONFIG_CDC
@@ -2194,44 +2195,26 @@ eth_bind (struct usb_gadget *gadget)
 	 * standard protocol is _strongly_ preferred for interop purposes.
 	 * (By everyone except Microsoft.)
 	 */
-	if (gadget_is_net2280 (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
-	} else if (gadget_is_dummy (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0202);
-	} else if (gadget_is_pxa (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203);
+	if (gadget_is_pxa (gadget)) {
 		/* pxa doesn't support altsettings */
 		cdc = 0;
 	} else if (gadget_is_sh(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204);
 		/* sh doesn't support multiple interfaces or configs */
 		cdc = 0;
 		rndis = 0;
 	} else if (gadget_is_sa1100 (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205);
 		/* hardware can't write zlps */
 		zlp = 0;
 		/* sa1100 CAN do CDC, without status endpoint ... we use
 		 * non-CDC to be compatible with ARM Linux-2.4 "usb-eth".
 		 */
 		cdc = 0;
-	} else if (gadget_is_goku (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206);
-	} else if (gadget_is_mq11xx (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
-	} else if (gadget_is_omap (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
-	} else if (gadget_is_lh7a40x(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
-	} else if (gadget_is_n9604(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
-	} else if (gadget_is_pxa27x(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
-	} else if (gadget_is_s3c2410(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
-	} else if (gadget_is_at91(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0213);
-	} else {
+	}
+
+	gcnum = usb_gadget_controller_number (gadget);
+	if (gcnum >= 0)
+		device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
+	else {
 		/* can't assume CDC works.  don't want to default to
 		 * anything less functional on CDC-capable hardware,
 		 * so we fail in this case.

+ 7 - 26
drivers/usb/gadget/file_storage.c

@@ -3713,6 +3713,7 @@ static void fsg_unbind(struct usb_gadget *gadget)
 static int __init check_parameters(struct fsg_dev *fsg)
 {
 	int	prot;
+	int	gcnum;
 
 	/* Store the default values */
 	mod_data.transport_type = USB_PR_BULK;
@@ -3724,33 +3725,13 @@ static int __init check_parameters(struct fsg_dev *fsg)
 		mod_data.can_stall = 0;
 
 	if (mod_data.release == 0xffff) {	// Parameter wasn't set
-		if (gadget_is_net2280(fsg->gadget))
-			mod_data.release = 0x0301;
-		else if (gadget_is_dummy(fsg->gadget))
-			mod_data.release = 0x0302;
-		else if (gadget_is_pxa(fsg->gadget))
-			mod_data.release = 0x0303;
-		else if (gadget_is_sh(fsg->gadget))
-			mod_data.release = 0x0304;
-
 		/* The sa1100 controller is not supported */
-
-		else if (gadget_is_goku(fsg->gadget))
-			mod_data.release = 0x0306;
-		else if (gadget_is_mq11xx(fsg->gadget))
-			mod_data.release = 0x0307;
-		else if (gadget_is_omap(fsg->gadget))
-			mod_data.release = 0x0308;
-		else if (gadget_is_lh7a40x(fsg->gadget))
-			mod_data.release = 0x0309;
-		else if (gadget_is_n9604(fsg->gadget))
-			mod_data.release = 0x0310;
-		else if (gadget_is_pxa27x(fsg->gadget))
-			mod_data.release = 0x0311;
-		else if (gadget_is_s3c2410(gadget))
-			mod_data.release = 0x0312;
-		else if (gadget_is_at91(fsg->gadget))
-			mod_data.release = 0x0313;
+		if (gadget_is_sa1100(fsg->gadget))
+			gcnum = -1;
+		else
+			gcnum = usb_gadget_controller_number(fsg->gadget);
+		if (gcnum >= 0)
+			mod_data.release = 0x0300 + gcnum;
 		else {
 			WARN(fsg, "controller '%s' not recognized\n",
 				fsg->gadget->name);

+ 55 - 0
drivers/usb/gadget/gadget_chips.h

@@ -5,6 +5,7 @@
  *
  * This could eventually work like the ARM mach_is_*() stuff, driven by
  * some config file that gets updated as new hardware is supported.
+ * (And avoiding the runtime comparisons in typical one-choice cases.)
  *
  * NOTE:  some of these controller drivers may not be available yet.
  */
@@ -86,7 +87,61 @@
 #define gadget_is_at91(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_IMX
+#define gadget_is_imx(g)	!strcmp("imx_udc", (g)->name)
+#else
+#define gadget_is_imx(g)	0
+#endif
+
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
 // ...
 
+
+/**
+ * usb_gadget_controller_number - support bcdDevice id convention
+ * @gadget: the controller being driven
+ *
+ * Return a 2-digit BCD value associated with the peripheral controller,
+ * suitable for use as part of a bcdDevice value, or a negative error code.
+ *
+ * NOTE:  this convention is purely optional, and has no meaning in terms of
+ * any USB specification.  If you want to use a different convention in your
+ * gadget driver firmware -- maybe a more formal revision ID -- feel free.
+ *
+ * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
+ * to change their behavior accordingly.  For example it might help avoiding
+ * some chip bug.
+ */
+static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
+{
+	if (gadget_is_net2280(gadget))
+		return 0x01;
+	else if (gadget_is_dummy(gadget))
+		return 0x02;
+	else if (gadget_is_pxa(gadget))
+		return 0x03;
+	else if (gadget_is_sh(gadget))
+		return 0x04;
+	else if (gadget_is_sa1100(gadget))
+		return 0x05;
+	else if (gadget_is_goku(gadget))
+		return 0x06;
+	else if (gadget_is_mq11xx(gadget))
+		return 0x07;
+	else if (gadget_is_omap(gadget))
+		return 0x08;
+	else if (gadget_is_lh7a40x(gadget))
+		return 0x09;
+	else if (gadget_is_n9604(gadget))
+		return 0x10;
+	else if (gadget_is_pxa27x(gadget))
+		return 0x11;
+	else if (gadget_is_s3c2410(gadget))
+		return 0x12;
+	else if (gadget_is_at91(gadget))
+		return 0x13;
+	else if (gadget_is_imx(gadget))
+		return 0x14;
+	return -ENOENT;
+}

+ 11 - 40
drivers/usb/gadget/serial.c

@@ -1422,49 +1422,20 @@ static int gs_bind(struct usb_gadget *gadget)
 	int ret;
 	struct usb_ep *ep;
 	struct gs_dev *dev;
+	int gcnum;
 
-	/* device specific */
-	if (gadget_is_net2280(gadget)) {
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0001);
-	} else if (gadget_is_pxa(gadget)) {
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0002);
-	} else if (gadget_is_sh(gadget)) {
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0003);
-		/* sh doesn't support multiple interfaces or configs */
+	/* Some controllers can't support CDC ACM:
+	 * - sh doesn't support multiple interfaces or configs;
+	 * - sa1100 doesn't have a third interrupt endpoint
+	 */
+	if (gadget_is_sh(gadget) || gadget_is_sa1100(gadget))
 		use_acm = 0;
-	} else if (gadget_is_sa1100(gadget)) {
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0004);
-		/* sa1100 doesn't support necessary endpoints */
-		use_acm = 0;
-	} else if (gadget_is_goku(gadget)) {
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0005);
-	} else if (gadget_is_mq11xx(gadget)) {
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0006);
-	} else if (gadget_is_omap(gadget)) {
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0007);
-	} else if (gadget_is_lh7a40x(gadget)) {
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0008);
-	} else if (gadget_is_n9604(gadget)) {
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0009);
-	} else if (gadget_is_pxa27x(gadget)) {
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0011);
-	} else if (gadget_is_s3c2410(gadget)) {
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0012);
-	} else if (gadget_is_at91(gadget)) {
+
+	gcnum = usb_gadget_controller_number(gadget);
+	if (gcnum >= 0)
 		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0013);
-	} else {
+				cpu_to_le16(GS_VERSION_NUM | gcnum);
+	else {
 		printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
 			gadget->name);
 		/* unrecognized, but safe unless bulk is REALLY quirky */

+ 11 - 37
drivers/usb/gadget/zero.c

@@ -1139,6 +1139,13 @@ zero_bind (struct usb_gadget *gadget)
 {
 	struct zero_dev		*dev;
 	struct usb_ep		*ep;
+	int			gcnum;
+
+	/* FIXME this can't yet work right with SH ... it has only
+	 * one configuration, numbered one.
+	 */
+	if (gadget_is_sh(gadget))
+		return -ENODEV;
 
 	/* Bulk-only drivers like this one SHOULD be able to
 	 * autoconfigure on any sane usb controller driver,
@@ -1161,43 +1168,10 @@ autoconf_fail:
 	EP_OUT_NAME = ep->name;
 	ep->driver_data = ep;	/* claim */
 
-
-	/*
-	 * DRIVER POLICY CHOICE:  you may want to do this differently.
-	 * One thing to avoid is reusing a bcdDevice revision code
-	 * with different host-visible configurations or behavior
-	 * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
-	 */
-	if (gadget_is_net2280 (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
-	} else if (gadget_is_pxa (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203);
-#if 0
-	} else if (gadget_is_sh(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204);
-		/* SH has only one configuration; see "loopdefault" */
-		device_desc.bNumConfigurations = 1;
-		/* FIXME make 1 == default.bConfigurationValue */
-#endif
-	} else if (gadget_is_sa1100 (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205);
-	} else if (gadget_is_goku (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206);
-	} else if (gadget_is_mq11xx (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
-	} else if (gadget_is_omap (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
-	} else if (gadget_is_lh7a40x(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209);
-	} else if (gadget_is_n9604(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210);
-	} else if (gadget_is_pxa27x(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211);
-	} else if (gadget_is_s3c2410(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0212);
-	} else if (gadget_is_at91(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0213);
-	} else {
+	gcnum = usb_gadget_controller_number (gadget);
+	if (gcnum >= 0)
+		device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
+	else {
 		/* gadget zero is so simple (for now, no altsettings) that
 		 * it SHOULD NOT have problems with bulk-capable hardware.
 		 * so warn about unrcognized controllers, don't panic.

+ 7 - 0
drivers/usb/host/ehci-q.c

@@ -677,6 +677,9 @@ qh_make (
 				goto done;
 			}
 		} else {
+			struct usb_tt	*tt = urb->dev->tt;
+			int		think_time;
+
 			/* gap is f(FS/LS transfer times) */
 			qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,
 					is_input, 0, maxp) / (125 * 1000);
@@ -690,6 +693,10 @@ qh_make (
 				qh->c_usecs = HS_USECS (0);
 			}
 
+			think_time = tt ? tt->think_time : 0;
+			qh->tt_usecs = NS_TO_US (think_time +
+					usb_calc_bus_time (urb->dev->speed,
+					is_input, 0, max_packet (maxp)));
 			qh->period = urb->interval;
 		}
 	}

+ 4 - 0
drivers/usb/host/ehci-sched.c

@@ -700,6 +700,7 @@ iso_stream_init (
 
 	} else {
 		u32		addr;
+		int		think_time;
 
 		addr = dev->ttport << 24;
 		if (!ehci_is_TDI(ehci)
@@ -709,6 +710,9 @@ iso_stream_init (
 		addr |= epnum << 8;
 		addr |= dev->devnum;
 		stream->usecs = HS_USECS_ISO (maxp);
+		think_time = dev->tt ? dev->tt->think_time : 0;
+		stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (
+				dev->speed, is_input, 1, maxp));
 		if (is_input) {
 			u32	tmp;
 

+ 2 - 0
drivers/usb/host/ehci.h

@@ -421,6 +421,7 @@ struct ehci_qh {
 	u8			usecs;		/* intr bandwidth */
 	u8			gap_uf;		/* uframes split/csplit gap */
 	u8			c_usecs;	/* ... split completion bw */
+	u16			tt_usecs;	/* tt downstream bandwidth */
 	unsigned short		period;		/* polling interval */
 	unsigned short		start;		/* where polling starts */
 #define NO_FRAME ((unsigned short)~0)			/* pick new start */
@@ -479,6 +480,7 @@ struct ehci_iso_stream {
 	 */
 	u8			interval;
 	u8			usecs, c_usecs;
+	u16			tt_usecs;
 	u16			maxp;
 	u16			raw_mask;
 	unsigned		bandwidth;

+ 33 - 55
drivers/usb/host/isp116x-hcd.c

@@ -83,7 +83,7 @@
 #include "../core/hcd.h"
 #include "isp116x.h"
 
-#define DRIVER_VERSION	"08 Apr 2005"
+#define DRIVER_VERSION	"05 Aug 2005"
 #define DRIVER_DESC	"ISP116x USB Host Controller Driver"
 
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -629,14 +629,12 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 			ERR("Unrecoverable error\n");
 			/* What should we do here? Reset?  */
 		}
-		if (intstat & HCINT_RHSC) {
-			isp116x->rhstatus =
-			    isp116x_read_reg32(isp116x, HCRHSTATUS);
-			isp116x->rhport[0] =
-			    isp116x_read_reg32(isp116x, HCRHPORT1);
-			isp116x->rhport[1] =
-			    isp116x_read_reg32(isp116x, HCRHPORT2);
-		}
+		if (intstat & HCINT_RHSC)
+			/* When root hub or any of its ports is going
+			   to come out of suspend, it may take more
+			   than 10ms for status bits to stabilize. */
+			mod_timer(&hcd->rh_timer, jiffies
+				  + msecs_to_jiffies(20) + 1);
 		if (intstat & HCINT_RD) {
 			DBG("---- remote wakeup\n");
 			schedule_work(&isp116x->rh_resume);
@@ -925,20 +923,27 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
 	int ports, i, changed = 0;
+	unsigned long flags;
 
 	if (!HC_IS_RUNNING(hcd->state))
 		return -ESHUTDOWN;
 
-	ports = isp116x->rhdesca & RH_A_NDP;
+	/* Report no status change now, if we are scheduled to be
+	   called later */
+	if (timer_pending(&hcd->rh_timer))
+		return 0;
 
-	/* init status */
+	ports = isp116x->rhdesca & RH_A_NDP;
+	spin_lock_irqsave(&isp116x->lock, flags);
+	isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
 	if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC))
 		buf[0] = changed = 1;
 	else
 		buf[0] = 0;
 
 	for (i = 0; i < ports; i++) {
-		u32 status = isp116x->rhport[i];
+		u32 status = isp116x->rhport[i] =
+		    isp116x_read_reg32(isp116x, i ? HCRHPORT2 : HCRHPORT1);
 
 		if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
 			      | RH_PS_OCIC | RH_PS_PRSC)) {
@@ -947,6 +952,7 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
 			continue;
 		}
 	}
+	spin_unlock_irqrestore(&isp116x->lock, flags);
 	return changed;
 }
 
@@ -1463,10 +1469,6 @@ static int isp116x_sw_reset(struct isp116x *isp116x)
 	return ret;
 }
 
-/*
-  Reset. Tries to perform platform-specific hardware
-  reset first; falls back to software reset.
-*/
 static int isp116x_reset(struct usb_hcd *hcd)
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
@@ -1474,17 +1476,7 @@ static int isp116x_reset(struct usb_hcd *hcd)
 	u16 clkrdy = 0;
 	int ret = 0, timeout = 15 /* ms */ ;
 
-	if (isp116x->board && isp116x->board->reset) {
-		/* Hardware reset */
-		isp116x->board->reset(hcd->self.controller, 1);
-		msleep(10);
-		if (isp116x->board->clock)
-			isp116x->board->clock(hcd->self.controller, 1);
-		msleep(1);
-		isp116x->board->reset(hcd->self.controller, 0);
-	} else
-		ret = isp116x_sw_reset(isp116x);
-
+	ret = isp116x_sw_reset(isp116x);
 	if (ret)
 		return ret;
 
@@ -1501,10 +1493,7 @@ static int isp116x_reset(struct usb_hcd *hcd)
 		ERR("Clock not ready after 20ms\n");
 		/* After sw_reset the clock won't report to be ready, if
 		   H_WAKEUP pin is high. */
-		if (!isp116x->board || !isp116x->board->reset)
-			ERR("The driver does not support hardware wakeup.\n");
-			ERR("Please make sure that the H_WAKEUP pin "
-				"is pulled low!\n");
+		ERR("Please make sure that the H_WAKEUP pin is pulled low!\n");
 		ret = -ENODEV;
 	}
 	return ret;
@@ -1527,15 +1516,7 @@ static void isp116x_stop(struct usb_hcd *hcd)
 	isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
 	spin_unlock_irqrestore(&isp116x->lock, flags);
 
-	/* Put the chip into reset state */
-	if (isp116x->board && isp116x->board->reset)
-		isp116x->board->reset(hcd->self.controller, 0);
-	else
-		isp116x_sw_reset(isp116x);
-
-	/* Stop the clock */
-	if (isp116x->board && isp116x->board->clock)
-		isp116x->board->clock(hcd->self.controller, 0);
+	isp116x_sw_reset(isp116x);
 }
 
 /*
@@ -1561,6 +1542,9 @@ static int isp116x_start(struct usb_hcd *hcd)
 		return -ENODEV;
 	}
 
+	/* To be removed in future */
+	hcd->uses_new_polling = 1;
+
 	isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
 	isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
 
@@ -1569,7 +1553,7 @@ static int isp116x_start(struct usb_hcd *hcd)
 	if (board->sel15Kres)
 		val |= HCHWCFG_15KRSEL;
 	/* Remote wakeup won't work without working clock */
-	if (board->clknotstop || board->remote_wakeup_enable)
+	if (board->remote_wakeup_enable)
 		val |= HCHWCFG_CLKNOTSTOP;
 	if (board->oc_enable)
 		val |= HCHWCFG_ANALOG_OC;
@@ -1580,16 +1564,13 @@ static int isp116x_start(struct usb_hcd *hcd)
 	isp116x_write_reg16(isp116x, HCHWCFG, val);
 
 	/* ----- Root hub conf */
-	val = 0;
-	/* AN10003_1.pdf recommends NPS to be always 1 */
-	if (board->no_power_switching)
-		val |= RH_A_NPS;
-	if (board->power_switching_mode)
-		val |= RH_A_PSM;
-	if (board->potpg)
-		val |= (board->potpg << 24) & RH_A_POTPGT;
-	else
-		val |= (25 << 24) & RH_A_POTPGT;
+	val = (25 << 24) & RH_A_POTPGT;
+	/* AN10003_1.pdf recommends RH_A_NPS (no power switching) to
+	   be always set. Yet, instead, we request individual port
+	   power switching. */
+	val |= RH_A_PSM;
+	/* Report overcurrent per port */
+	val |= RH_A_OCPM;
 	isp116x_write_reg32(isp116x, HCRHDESCA, val);
 	isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
 
@@ -1619,9 +1600,6 @@ static int isp116x_start(struct usb_hcd *hcd)
 
 	/* Go operational */
 	val = HCCONTROL_USB_OPER;
-	/* Remote wakeup connected - NOT SUPPORTED */
-	/*  if (board->remote_wakeup_connected)
-	   val |= HCCONTROL_RWC;  */
 	if (board->remote_wakeup_enable)
 		val |= HCCONTROL_RWE;
 	isp116x_write_reg32(isp116x, HCCONTROL, val);
@@ -1670,7 +1648,7 @@ static int __init_or_module isp116x_remove(struct device *dev)
 	struct platform_device *pdev;
 	struct resource *res;
 
-	if(!hcd)
+	if (!hcd)
 		return 0;
 	isp116x = hcd_to_isp116x(hcd);
 	pdev = container_of(dev, struct platform_device, dev);

+ 5 - 19
drivers/usb/host/ohci-ppc-soc.c

@@ -14,8 +14,6 @@
  * This file is licenced under the GPL.
  */
 
-#include <asm/usb.h>
-
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
 
@@ -23,9 +21,7 @@
  * usb_hcd_ppc_soc_probe - initialize On-Chip HCDs
  * Context: !in_interrupt()
  *
- * Allocates basic resources for this USB host controller, and
- * then invokes the start() method for the HCD associated with it
- * through the hotplug entry's driver_data.
+ * Allocates basic resources for this USB host controller.
  *
  * Store this function in the HCD's struct pci_driver as probe().
  */
@@ -37,7 +33,6 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
 	struct ohci_hcd	*ohci;
 	struct resource *res;
 	int irq;
-	struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
 
 	pr_debug("initializing PPC-SOC USB Controller\n");
 
@@ -73,9 +68,6 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
 		goto err2;
 	}
 
-	if (pd->start && (retval = pd->start(pdev)))
-		goto err3;
-
 	ohci = hcd_to_ohci(hcd);
 	ohci->flags |= OHCI_BIG_ENDIAN;
 	ohci_hcd_init(ohci);
@@ -85,9 +77,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
 		return retval;
 
 	pr_debug("Removing PPC-SOC USB Controller\n");
-	if (pd && pd->stop)
-		pd->stop(pdev);
- err3:
+
 	iounmap(hcd->regs);
  err2:
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
@@ -105,25 +95,21 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
  * @pdev: USB Host Controller being removed
  * Context: !in_interrupt()
  *
- * Reverses the effect of usb_hcd_ppc_soc_probe(), first invoking
- * the HCD's stop() method.  It is always called from a thread
+ * Reverses the effect of usb_hcd_ppc_soc_probe().
+ * It is always called from a thread
  * context, normally "rmmod", "apmd", or something similar.
  *
  */
 static void usb_hcd_ppc_soc_remove(struct usb_hcd *hcd,
 		struct platform_device *pdev)
 {
-	struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
-
 	usb_remove_hcd(hcd);
 
 	pr_debug("stopping PPC-SOC USB Controller\n");
-	if (pd && pd->stop)
-		pd->stop(pdev);
 
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	usb_hcd_put(hcd);
+	usb_put_hcd(hcd);
 }
 
 static int __devinit

+ 2 - 2
drivers/usb/host/ohci-s3c2410.c

@@ -129,7 +129,7 @@ static void s3c2410_usb_set_power(struct s3c2410_hcd_info *info,
 
 	if (info->power_control != NULL) {
 		info->port[port-1].power = to;
-		(info->power_control)(port, to);
+		(info->power_control)(port-1, to);
 	}
 }
 
@@ -339,8 +339,8 @@ int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
 	struct usb_hcd *hcd = NULL;
 	int retval;
 
-	s3c2410_usb_set_power(dev->dev.platform_data, 0, 1);
 	s3c2410_usb_set_power(dev->dev.platform_data, 1, 1);
+	s3c2410_usb_set_power(dev->dev.platform_data, 2, 1);
 
 	hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
 	if (hcd == NULL)

+ 14 - 0
drivers/usb/input/Kconfig

@@ -230,6 +230,20 @@ config USB_EGALAX
 	  To compile this driver as a module, choose M here: the
 	  module will be called touchkitusb.
 
+config USB_YEALINK
+	tristate "Yealink usb-p1k voip phone"
+	depends on USB && INPUT && EXPERIMENTAL
+	---help---
+	  Say Y here if you want to enable keyboard and LCD functions of the
+	  Yealink usb-p1k usb phones. The audio part is enabled by the generic
+	  usb sound driver, so you might want to enable that as well.
+
+	  For information about how to use these additional functions, see
+	  <file:Documentation/input/yealink.txt>.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called yealink.
+
 config USB_XPAD
 	tristate "X-Box gamepad support"
 	depends on USB && INPUT

+ 1 - 0
drivers/usb/input/Makefile

@@ -39,4 +39,5 @@ obj-$(CONFIG_USB_EGALAX)	+= touchkitusb.o
 obj-$(CONFIG_USB_POWERMATE)	+= powermate.o
 obj-$(CONFIG_USB_WACOM)		+= wacom.o
 obj-$(CONFIG_USB_ACECAD)	+= acecad.o
+obj-$(CONFIG_USB_YEALINK)	+= yealink.o
 obj-$(CONFIG_USB_XPAD)		+= xpad.o

+ 6 - 3
drivers/usb/input/hid-core.c

@@ -1444,6 +1444,8 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_DEVICE_ID_NETWORKANALYSER	0x2020
 #define USB_DEVICE_ID_POWERCONTROL	0x2030
 
+#define USB_VENDOR_ID_APPLE		0x05ac
+#define USB_DEVICE_ID_APPLE_BLUETOOTH  	0x1000
 
 /*
  * Alphabetically sorted blacklist by quirk type.
@@ -1462,6 +1464,7 @@ static struct hid_blacklist {
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_BLUETOOTH, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
@@ -1685,7 +1688,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 			usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0,
 					 hid_irq_in, hid, interval);
 			hid->urbin->transfer_dma = hid->inbuf_dma;
-			hid->urbin->transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK);
+			hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 		} else {
 			if (hid->urbout)
 				continue;
@@ -1695,7 +1698,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 			usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0,
 					 hid_irq_out, hid, interval);
 			hid->urbout->transfer_dma = hid->outbuf_dma;
-			hid->urbout->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK);
+			hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 		}
 	}
 
@@ -1747,7 +1750,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 			     hid->ctrlbuf, 1, hid_ctrl, hid);
 	hid->urbctrl->setup_dma = hid->cr_dma;
 	hid->urbctrl->transfer_dma = hid->ctrlbuf_dma;
-	hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | URB_ASYNC_UNLINK);
+	hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
 
 	return hid;
 

+ 0 - 5
drivers/usb/input/keyspan_remote.c

@@ -431,11 +431,6 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface));
 
-	/* See if the offered device matches what we can accept */
-	if ((udev->descriptor.idVendor != USB_KEYSPAN_VENDOR_ID) ||
-	    (udev->descriptor.idProduct != USB_KEYSPAN_PRODUCT_UIA11) )
-		return -ENODEV;
-
 	/* allocate memory for our device state and initialize it */
 	remote = kmalloc(sizeof(*remote), GFP_KERNEL);
 	if (remote == NULL) {

+ 189 - 0
drivers/usb/input/map_to_7segment.h

@@ -0,0 +1,189 @@
+/*
+ * drivers/usb/input/map_to_7segment.h
+ *
+ * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MAP_TO_7SEGMENT_H
+#define MAP_TO_7SEGMENT_H
+
+/* This file provides translation primitives and tables for the conversion
+ * of (ASCII) characters to a 7-segments notation.
+ *
+ * The 7 segment's wikipedia notation below is used as standard.
+ * See: http://en.wikipedia.org/wiki/Seven_segment_display
+ *
+ * Notation:	+-a-+
+ *		f   b
+ *		+-g-+
+ *		e   c
+ *		+-d-+
+ *
+ * Usage:
+ *
+ *   Register a map variable, and fill it with a character set:
+ * 	static SEG7_DEFAULT_MAP(map_seg7);
+ *
+ *
+ *   Then use for conversion:
+ *	seg7 = map_to_seg7(&map_seg7, some_char);
+ *	...
+ *
+ * In device drivers it is recommended, if required, to make the char map
+ * accessible via the sysfs interface using the following scheme:
+ *
+ * static ssize_t show_map(struct device *dev, char *buf) {
+ *	memcpy(buf, &map_seg7, sizeof(map_seg7));
+ *	return sizeof(map_seg7);
+ * }
+ * static ssize_t store_map(struct device *dev, const char *buf, size_t cnt) {
+ *	if(cnt != sizeof(map_seg7))
+ *		return -EINVAL;
+ *	memcpy(&map_seg7, buf, cnt);
+ *	return cnt;
+ * }
+ * static DEVICE_ATTR(map_seg7, PERMS_RW, show_map, store_map);
+ *
+ * History:
+ * 2005-05-31	RFC linux-kernel@vger.kernel.org
+ */
+#include <linux/errno.h>
+
+
+#define BIT_SEG7_A		0
+#define BIT_SEG7_B		1
+#define BIT_SEG7_C		2
+#define BIT_SEG7_D		3
+#define BIT_SEG7_E		4
+#define BIT_SEG7_F		5
+#define BIT_SEG7_G		6
+#define BIT_SEG7_RESERVED	7
+
+struct seg7_conversion_map {
+	unsigned char	table[128];
+};
+
+static inline int map_to_seg7(struct seg7_conversion_map *map, int c)
+{
+	return c & 0x7f ? map->table[c] : -EINVAL;
+}
+
+#define SEG7_CONVERSION_MAP(_name, _map)	\
+	struct seg7_conversion_map _name = { .table = { _map } }
+
+/*
+ * It is recommended to use a facility that allows user space to redefine
+ * custom character sets for LCD devices. Please use a sysfs interface
+ * as described above.
+ */
+#define MAP_TO_SEG7_SYSFS_FILE	"map_seg7"
+
+/*******************************************************************************
+ * ASCII conversion table
+ ******************************************************************************/
+
+#define _SEG7(l,a,b,c,d,e,f,g)	\
+      (	a<<BIT_SEG7_A |	b<<BIT_SEG7_B |	c<<BIT_SEG7_C |	d<<BIT_SEG7_D |	\
+	e<<BIT_SEG7_E |	f<<BIT_SEG7_F |	g<<BIT_SEG7_G )
+
+#define _MAP_0_32_ASCII_SEG7_NON_PRINTABLE	\
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+#define _MAP_33_47_ASCII_SEG7_SYMBOL		\
+ _SEG7('!',0,0,0,0,1,1,0), _SEG7('"',0,1,0,0,0,1,0), _SEG7('#',0,1,1,0,1,1,0),\
+ _SEG7('$',1,0,1,1,0,1,1), _SEG7('%',0,0,1,0,0,1,0), _SEG7('&',1,0,1,1,1,1,1),\
+ _SEG7('\'',0,0,0,0,0,1,0),_SEG7('(',1,0,0,1,1,1,0), _SEG7(')',1,1,1,1,0,0,0),\
+ _SEG7('*',0,1,1,0,1,1,1), _SEG7('+',0,1,1,0,0,0,1), _SEG7(',',0,0,0,0,1,0,0),\
+ _SEG7('-',0,0,0,0,0,0,1), _SEG7('.',0,0,0,0,1,0,0), _SEG7('/',0,1,0,0,1,0,1),
+
+#define _MAP_48_57_ASCII_SEG7_NUMERIC		\
+ _SEG7('0',1,1,1,1,1,1,0), _SEG7('1',0,1,1,0,0,0,0), _SEG7('2',1,1,0,1,1,0,1),\
+ _SEG7('3',1,1,1,1,0,0,1), _SEG7('4',0,1,1,0,0,1,1), _SEG7('5',1,0,1,1,0,1,1),\
+ _SEG7('6',1,0,1,1,1,1,1), _SEG7('7',1,1,1,0,0,0,0), _SEG7('8',1,1,1,1,1,1,1),\
+ _SEG7('9',1,1,1,1,0,1,1),
+
+#define _MAP_58_64_ASCII_SEG7_SYMBOL		\
+ _SEG7(':',0,0,0,1,0,0,1), _SEG7(';',0,0,0,1,0,0,1), _SEG7('<',1,0,0,0,0,1,1),\
+ _SEG7('=',0,0,0,1,0,0,1), _SEG7('>',1,1,0,0,0,0,1), _SEG7('?',1,1,1,0,0,1,0),\
+ _SEG7('@',1,1,0,1,1,1,1),
+
+#define _MAP_65_90_ASCII_SEG7_ALPHA_UPPR	\
+ _SEG7('A',1,1,1,0,1,1,1), _SEG7('B',1,1,1,1,1,1,1), _SEG7('C',1,0,0,1,1,1,0),\
+ _SEG7('D',1,1,1,1,1,1,0), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
+ _SEG7('G',1,1,1,1,0,1,1), _SEG7('H',0,1,1,0,1,1,1), _SEG7('I',0,1,1,0,0,0,0),\
+ _SEG7('J',0,1,1,1,0,0,0), _SEG7('K',0,1,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
+ _SEG7('M',1,1,1,0,1,1,0), _SEG7('N',1,1,1,0,1,1,0), _SEG7('O',1,1,1,1,1,1,0),\
+ _SEG7('P',1,1,0,0,1,1,1), _SEG7('Q',1,1,1,1,1,1,0), _SEG7('R',1,1,1,0,1,1,1),\
+ _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('U',0,1,1,1,1,1,0),\
+ _SEG7('V',0,1,1,1,1,1,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
+ _SEG7('Y',0,1,1,0,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
+
+#define _MAP_91_96_ASCII_SEG7_SYMBOL		\
+ _SEG7('[',1,0,0,1,1,1,0), _SEG7('\\',0,0,1,0,0,1,1),_SEG7(']',1,1,1,1,0,0,0),\
+ _SEG7('^',1,1,0,0,0,1,0), _SEG7('_',0,0,0,1,0,0,0), _SEG7('`',0,1,0,0,0,0,0),
+
+#define _MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
+ _SEG7('A',1,1,1,0,1,1,1), _SEG7('b',0,0,1,1,1,1,1), _SEG7('c',0,0,0,1,1,0,1),\
+ _SEG7('d',0,1,1,1,1,0,1), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
+ _SEG7('G',1,1,1,1,0,1,1), _SEG7('h',0,0,1,0,1,1,1), _SEG7('i',0,0,1,0,0,0,0),\
+ _SEG7('j',0,0,1,1,0,0,0), _SEG7('k',0,0,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
+ _SEG7('M',1,1,1,0,1,1,0), _SEG7('n',0,0,1,0,1,0,1), _SEG7('o',0,0,1,1,1,0,1),\
+ _SEG7('P',1,1,0,0,1,1,1), _SEG7('q',1,1,1,0,0,1,1), _SEG7('r',0,0,0,0,1,0,1),\
+ _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('u',0,0,1,1,1,0,0),\
+ _SEG7('v',0,0,1,1,1,0,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
+ _SEG7('y',0,1,1,1,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
+
+#define _MAP_123_126_ASCII_SEG7_SYMBOL		\
+ _SEG7('{',1,0,0,1,1,1,0), _SEG7('|',0,0,0,0,1,1,0), _SEG7('}',1,1,1,1,0,0,0),\
+ _SEG7('~',1,0,0,0,0,0,0),
+
+/* Maps */
+
+/* This set tries to map as close as possible to the visible characteristics
+ * of the ASCII symbol, lowercase and uppercase letters may differ in
+ * presentation on the display.
+ */
+#define MAP_ASCII7SEG_ALPHANUM			\
+	_MAP_0_32_ASCII_SEG7_NON_PRINTABLE	\
+	_MAP_33_47_ASCII_SEG7_SYMBOL		\
+	_MAP_48_57_ASCII_SEG7_NUMERIC		\
+	_MAP_58_64_ASCII_SEG7_SYMBOL		\
+	_MAP_65_90_ASCII_SEG7_ALPHA_UPPR	\
+	_MAP_91_96_ASCII_SEG7_SYMBOL		\
+	_MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
+	_MAP_123_126_ASCII_SEG7_SYMBOL
+
+/* This set tries to map as close as possible to the symbolic characteristics
+ * of the ASCII character for maximum discrimination.
+ * For now this means all alpha chars are in lower case representations.
+ * (This for example facilitates the use of hex numbers with uppercase input.)
+ */
+#define MAP_ASCII7SEG_ALPHANUM_LC			\
+	_MAP_0_32_ASCII_SEG7_NON_PRINTABLE	\
+	_MAP_33_47_ASCII_SEG7_SYMBOL		\
+	_MAP_48_57_ASCII_SEG7_NUMERIC		\
+	_MAP_58_64_ASCII_SEG7_SYMBOL		\
+	_MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
+	_MAP_91_96_ASCII_SEG7_SYMBOL		\
+	_MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
+	_MAP_123_126_ASCII_SEG7_SYMBOL
+
+#define SEG7_DEFAULT_MAP(_name)		\
+	SEG7_CONVERSION_MAP(_name,MAP_ASCII7SEG_ALPHANUM)
+
+#endif	/* MAP_TO_7SEGMENT_H */
+

+ 1013 - 0
drivers/usb/input/yealink.c

@@ -0,0 +1,1013 @@
+/*
+ * drivers/usb/input/yealink.c
+ *
+ * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * Description:
+ *   Driver for the USB-P1K voip usb phone.
+ *   This device is produced by Yealink Network Technology Co Ltd
+ *   but may be branded under several names:
+ *	- Yealink usb-p1k
+ *	- Tiptel 115
+ *	- ...
+ *
+ * This driver is based on:
+ *   - the usbb2k-api	http://savannah.nongnu.org/projects/usbb2k-api/
+ *   - information from	http://memeteau.free.fr/usbb2k
+ *   - the xpad-driver	drivers/usb/input/xpad.c
+ *
+ * Thanks to:
+ *   - Olivier Vandorpe, for providing the usbb2k-api.
+ *   - Martin Diehl, for spotting my memory allocation bug.
+ *
+ * History:
+ *   20050527 henk	First version, functional keyboard. Keyboard events
+ *			will pop-up on the ../input/eventX bus.
+ *   20050531 henk	Added led, LCD, dialtone and sysfs interface.
+ *   20050610 henk	Cleanups, make it ready for public consumption.
+ *   20050630 henk	Cleanups, fixes in response to comments.
+ *   20050701 henk	sysfs write serialisation, fix potential unload races
+ *   20050801 henk	Added ringtone, restructure USB
+ *   20050816 henk	Merge 2.6.13-rc6
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+#include <linux/usb.h>
+
+#include "map_to_7segment.h"
+#include "yealink.h"
+
+#define DRIVER_VERSION "yld-20050816"
+#define DRIVER_AUTHOR "Henk Vergonet"
+#define DRIVER_DESC "Yealink phone driver"
+
+#define YEALINK_POLLING_FREQUENCY	10	/* in [Hz] */
+
+struct yld_status {
+	u8	lcd[24];
+	u8	led;
+	u8	dialtone;
+	u8	ringtone;
+	u8	keynum;
+} __attribute__ ((packed));
+
+/*
+ * Register the LCD segment and icon map
+ */
+#define _LOC(k,l)	{ .a = (k), .m = (l) }
+#define _SEG(t, a, am, b, bm, c, cm, d, dm, e, em, f, fm, g, gm)	\
+	{ .type	= (t),							\
+	  .u = { .s = {	_LOC(a, am), _LOC(b, bm), _LOC(c, cm),		\
+		        _LOC(d, dm), _LOC(e, em), _LOC(g, gm),		\
+			_LOC(f, fm) } } }
+#define _PIC(t, h, hm, n)						\
+	{ .type	= (t),							\
+ 	  .u = { .p = { .name = (n), .a = (h), .m = (hm) } } }
+
+static const struct lcd_segment_map {
+	char	type;
+	union {
+		struct pictogram_map {
+			u8	a,m;
+			char	name[10];
+		}	p;
+		struct segment_map {
+			u8	a,m;
+		} s[7];
+	} u;
+} lcdMap[] = {
+#include "yealink.h"
+};
+
+struct yealink_dev {
+	struct input_dev idev;		/* input device */
+	struct usb_device *udev;	/* usb device */
+
+	/* irq input channel */
+	struct yld_ctl_packet	*irq_data;
+	dma_addr_t 		irq_dma;
+	struct urb		*urb_irq;
+
+	/* control output channel */
+	struct yld_ctl_packet	*ctl_data;
+	dma_addr_t		ctl_dma;
+	struct usb_ctrlrequest	*ctl_req;
+	dma_addr_t		ctl_req_dma;
+	struct urb		*urb_ctl;
+
+	char phys[64];			/* physical device path */
+
+	u8 lcdMap[ARRAY_SIZE(lcdMap)];	/* state of LCD, LED ... */
+	int key_code;			/* last reported key	 */
+
+	int	stat_ix;
+	union {
+		struct yld_status s;
+		u8		  b[sizeof(struct yld_status)];
+	} master, copy;
+};
+
+
+/*******************************************************************************
+ * Yealink lcd interface
+ ******************************************************************************/
+
+/*
+ * Register a default 7 segment character set
+ */
+static SEG7_DEFAULT_MAP(map_seg7);
+
+ /* Display a char,
+  * char '\9' and '\n' are placeholders and do not overwrite the original text.
+  * A space will always hide an icon.
+  */
+static int setChar(struct yealink_dev *yld, int el, int chr)
+{
+	int i, a, m, val;
+
+	if (el >= ARRAY_SIZE(lcdMap))
+		return -EINVAL;
+
+	if (chr == '\t' || chr == '\n')
+	    return 0;
+
+	yld->lcdMap[el] = chr;
+
+	if (lcdMap[el].type == '.') {
+		a = lcdMap[el].u.p.a;
+		m = lcdMap[el].u.p.m;
+		if (chr != ' ')
+			yld->master.b[a] |= m;
+		else
+			yld->master.b[a] &= ~m;
+		return 0;
+	}
+
+	val = map_to_seg7(&map_seg7, chr);
+	for (i = 0; i < ARRAY_SIZE(lcdMap[0].u.s); i++) {
+		m = lcdMap[el].u.s[i].m;
+
+		if (m == 0)
+			continue;
+
+		a = lcdMap[el].u.s[i].a;
+		if (val & 1)
+			yld->master.b[a] |= m;
+		else
+			yld->master.b[a] &= ~m;
+		val = val >> 1;
+	}
+	return 0;
+};
+
+/*******************************************************************************
+ * Yealink key interface
+ ******************************************************************************/
+
+/* Map device buttons to internal key events.
+ *
+ * USB-P1K button layout:
+ *
+ *             up
+ *       IN           OUT
+ *            down
+ *
+ *     pickup   C    hangup
+ *       1      2      3
+ *       4      5      6
+ *       7      8      9
+ *       *      0      #
+ *
+ * The "up" and "down" keys, are symbolised by arrows on the button.
+ * The "pickup" and "hangup" keys are symbolised by a green and red phone
+ * on the button.
+ */
+static int map_p1k_to_key(int scancode)
+{
+	switch(scancode) {		/* phone key:	*/
+	case 0x23: return KEY_LEFT;	/*   IN		*/
+	case 0x33: return KEY_UP;	/*   up		*/
+	case 0x04: return KEY_RIGHT;	/*   OUT	*/
+	case 0x24: return KEY_DOWN;	/*   down	*/
+	case 0x03: return KEY_ENTER;	/*   pickup	*/
+	case 0x14: return KEY_BACKSPACE; /*  C		*/
+	case 0x13: return KEY_ESC;	/*   hangup	*/
+	case 0x00: return KEY_1;	/*   1		*/
+	case 0x01: return KEY_2;	/*   2 		*/
+	case 0x02: return KEY_3;	/*   3		*/
+	case 0x10: return KEY_4;	/*   4		*/
+	case 0x11: return KEY_5;	/*   5		*/
+	case 0x12: return KEY_6;	/*   6		*/
+	case 0x20: return KEY_7;	/*   7		*/
+	case 0x21: return KEY_8;	/*   8		*/
+	case 0x22: return KEY_9;	/*   9		*/
+	case 0x30: return KEY_KPASTERISK; /* *		*/
+	case 0x31: return KEY_0;	/*   0		*/
+	case 0x32: return KEY_LEFTSHIFT |
+			  KEY_3 << 8;	/*   #		*/
+	}
+	return -EINVAL;
+}
+
+/* Completes a request by converting the data into events for the
+ * input subsystem.
+ *
+ * The key parameter can be cascaded: key2 << 8 | key1
+ */
+static void report_key(struct yealink_dev *yld, int key, struct pt_regs *regs)
+{
+	struct input_dev *idev = &yld->idev;
+
+	input_regs(idev, regs);
+	if (yld->key_code >= 0) {
+		/* old key up */
+		input_report_key(idev, yld->key_code & 0xff, 0);
+		if (yld->key_code >> 8)
+			input_report_key(idev, yld->key_code >> 8, 0);
+	}
+
+	yld->key_code = key;
+	if (key >= 0) {
+		/* new valid key */
+		input_report_key(idev, key & 0xff, 1);
+		if (key >> 8)
+			input_report_key(idev, key >> 8, 1);
+	}
+	input_sync(idev);
+}
+
+/*******************************************************************************
+ * Yealink usb communication interface
+ ******************************************************************************/
+
+static int yealink_cmd(struct yealink_dev *yld, struct yld_ctl_packet *p)
+{
+	u8	*buf = (u8 *)p;
+	int	i;
+	u8	sum = 0;
+
+	for(i=0; i<USB_PKT_LEN-1; i++)
+		sum -= buf[i];
+	p->sum = sum;
+	return usb_control_msg(yld->udev,
+			usb_sndctrlpipe(yld->udev, 0),
+			USB_REQ_SET_CONFIGURATION,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+			0x200, 3,
+			p, sizeof(*p),
+			USB_CTRL_SET_TIMEOUT);
+}
+
+static u8 default_ringtone[] = {
+	0xEF,			/* volume [0-255] */
+	0xFB, 0x1E, 0x00, 0x0C,	/* 1250 [hz], 12/100 [s] */
+	0xFC, 0x18, 0x00, 0x0C,	/* 1000 [hz], 12/100 [s] */
+	0xFB, 0x1E, 0x00, 0x0C,
+	0xFC, 0x18, 0x00, 0x0C,
+	0xFB, 0x1E, 0x00, 0x0C,
+	0xFC, 0x18, 0x00, 0x0C,
+	0xFB, 0x1E, 0x00, 0x0C,
+	0xFC, 0x18, 0x00, 0x0C,
+	0xFF, 0xFF, 0x01, 0x90,	/* silent, 400/100 [s] */
+	0x00, 0x00		/* end of sequence */
+};
+
+static int yealink_set_ringtone(struct yealink_dev *yld, u8 *buf, size_t size)
+{
+	struct yld_ctl_packet *p = yld->ctl_data;
+	int	ix, len;
+
+	if (size <= 0)
+		return -EINVAL;
+
+	/* Set the ringtone volume */
+	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+	yld->ctl_data->cmd	= CMD_RING_VOLUME;
+	yld->ctl_data->size	= 1;
+	yld->ctl_data->data[0]	= buf[0];
+	yealink_cmd(yld, p);
+
+	buf++;
+	size--;
+
+	p->cmd = CMD_RING_NOTE;
+	ix = 0;
+	while (size != ix) {
+		len = size - ix;
+		if (len > sizeof(p->data))
+			len = sizeof(p->data);
+		p->size	  = len;
+		p->offset = cpu_to_be16(ix);
+		memcpy(p->data, &buf[ix], len);
+		yealink_cmd(yld, p);
+		ix += len;
+	}
+	return 0;
+}
+
+/* keep stat_master & stat_copy in sync.
+ */
+static int yealink_do_idle_tasks(struct yealink_dev *yld)
+{
+	u8 val;
+	int i, ix, len;
+
+	ix = yld->stat_ix;
+
+	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+	yld->ctl_data->cmd  = CMD_KEYPRESS;
+	yld->ctl_data->size = 1;
+	yld->ctl_data->sum  = 0xff - CMD_KEYPRESS;
+
+	/* If state update pointer wraps do a KEYPRESS first. */
+	if (ix >= sizeof(yld->master)) {
+		yld->stat_ix = 0;
+		return 0;
+	}
+
+	/* find update candidates: copy != master */
+	do {
+		val = yld->master.b[ix];
+		if (val != yld->copy.b[ix])
+			goto send_update;
+	} while (++ix < sizeof(yld->master));
+
+	/* nothing todo, wait a bit and poll for a KEYPRESS */
+	yld->stat_ix = 0;
+	/* TODO how can we wait abit. ??
+	 * msleep_interruptible(1000 / YEALINK_POLLING_FREQUENCY);
+	 */
+	return 0;
+
+send_update:
+
+	/* Setup an appropriate update request */
+	yld->copy.b[ix] = val;
+	yld->ctl_data->data[0] = val;
+
+	switch(ix) {
+	case offsetof(struct yld_status, led):
+		yld->ctl_data->cmd	= CMD_LED;
+		yld->ctl_data->sum	= -1 - CMD_LED - val;
+		break;
+	case offsetof(struct yld_status, dialtone):
+		yld->ctl_data->cmd	= CMD_DIALTONE;
+		yld->ctl_data->sum	= -1 - CMD_DIALTONE - val;
+		break;
+	case offsetof(struct yld_status, ringtone):
+		yld->ctl_data->cmd	= CMD_RINGTONE;
+		yld->ctl_data->sum	= -1 - CMD_RINGTONE - val;
+		break;
+	case offsetof(struct yld_status, keynum):
+		val--;
+		val &= 0x1f;
+		yld->ctl_data->cmd	= CMD_SCANCODE;
+		yld->ctl_data->offset	= cpu_to_be16(val);
+		yld->ctl_data->data[0]	= 0;
+		yld->ctl_data->sum	= -1 - CMD_SCANCODE - val;
+		break;
+	default:
+		len = sizeof(yld->master.s.lcd) - ix;
+		if (len > sizeof(yld->ctl_data->data))
+			len = sizeof(yld->ctl_data->data);
+
+		/* Combine up to <len> consecutive LCD bytes in a singe request
+		 */
+		yld->ctl_data->cmd	= CMD_LCD;
+		yld->ctl_data->offset	= cpu_to_be16(ix);
+		yld->ctl_data->size	= len;
+		yld->ctl_data->sum	= -CMD_LCD - ix - val - len;
+		for(i=1; i<len; i++) {
+			ix++;
+			val = yld->master.b[ix];
+			yld->copy.b[ix]		= val;
+			yld->ctl_data->data[i]	= val;
+			yld->ctl_data->sum     -= val;
+		}
+	}
+	yld->stat_ix = ix + 1;
+	return 1;
+}
+
+/* Decide on how to handle responses
+ *
+ * The state transition diagram is somethhing like:
+ *
+ *          syncState<--+
+ *               |      |
+ *               |    idle
+ *              \|/     |
+ * init --ok--> waitForKey --ok--> getKey
+ *  ^               ^                |
+ *  |               +-------ok-------+
+ * error,start
+ *
+ */
+static void urb_irq_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct yealink_dev *yld = urb->context;
+	int ret;
+
+	if (urb->status)
+		err("%s - urb status %d", __FUNCTION__, urb->status);
+
+	switch (yld->irq_data->cmd) {
+	case CMD_KEYPRESS:
+
+		yld->master.s.keynum = yld->irq_data->data[0];
+		break;
+
+	case CMD_SCANCODE:
+		dbg("get scancode %x", yld->irq_data->data[0]);
+
+		report_key(yld, map_p1k_to_key(yld->irq_data->data[0]), regs);
+		break;
+
+	default:
+		err("unexpected response %x", yld->irq_data->cmd);
+	}
+
+	yealink_do_idle_tasks(yld);
+
+	ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
+	if (ret)
+		err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
+}
+
+static void urb_ctl_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct yealink_dev *yld = urb->context;
+	int ret;
+
+	if (urb->status)
+		err("%s - urb status %d", __FUNCTION__, urb->status);
+
+	switch (yld->ctl_data->cmd) {
+	case CMD_KEYPRESS:
+	case CMD_SCANCODE:
+		/* ask for a response */
+		ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
+		break;
+	default:
+		/* send new command */
+		yealink_do_idle_tasks(yld);
+		ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
+	}
+
+	if (ret)
+		err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
+}
+
+/*******************************************************************************
+ * input event interface
+ ******************************************************************************/
+
+/* TODO should we issue a ringtone on a SND_BELL event?
+static int input_ev(struct input_dev *dev, unsigned int type,
+		unsigned int code, int value)
+{
+
+	if (type != EV_SND)
+		return -EINVAL;
+
+	switch (code) {
+	case SND_BELL:
+	case SND_TONE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+*/
+
+static int input_open(struct input_dev *dev)
+{
+	struct yealink_dev *yld = dev->private;
+	int i, ret;
+
+	dbg("%s", __FUNCTION__);
+
+	/* force updates to device */
+	for (i = 0; i<sizeof(yld->master); i++)
+		yld->copy.b[i] = ~yld->master.b[i];
+	yld->key_code = -1;	/* no keys pressed */
+
+        yealink_set_ringtone(yld, default_ringtone, sizeof(default_ringtone));
+
+	/* issue INIT */
+	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+	yld->ctl_data->cmd	= CMD_INIT;
+	yld->ctl_data->size	= 10;
+	yld->ctl_data->sum	= 0x100-CMD_INIT-10;
+	if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) {
+		dbg("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static void input_close(struct input_dev *dev)
+{
+	struct yealink_dev *yld = dev->private;
+
+	usb_kill_urb(yld->urb_ctl);
+	usb_kill_urb(yld->urb_irq);
+}
+
+/*******************************************************************************
+ * sysfs interface
+ ******************************************************************************/
+
+static DECLARE_RWSEM(sysfs_rwsema);
+
+/* Interface to the 7-segments translation table aka. char set.
+ */
+static ssize_t show_map(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	memcpy(buf, &map_seg7, sizeof(map_seg7));
+	return sizeof(map_seg7);
+}
+
+static ssize_t store_map(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t cnt)
+{
+	if (cnt != sizeof(map_seg7))
+		return -EINVAL;
+	memcpy(&map_seg7, buf, sizeof(map_seg7));
+	return sizeof(map_seg7);
+}
+
+/* Interface to the LCD.
+ */
+
+/* Reading /sys/../lineX will return the format string with its settings:
+ *
+ * Example:
+ * cat ./line3
+ * 888888888888
+ * Linux Rocks!
+ */
+static ssize_t show_line(struct device *dev, char *buf, int a, int b)
+{
+	struct yealink_dev *yld;
+	int i;
+
+	down_read(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_read(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	for (i = a; i < b; i++)
+		*buf++ = lcdMap[i].type;
+	*buf++ = '\n';
+	for (i = a; i < b; i++)
+		*buf++ = yld->lcdMap[i];
+	*buf++ = '\n';
+	*buf = 0;
+
+	up_read(&sysfs_rwsema);
+	return 3 + ((b - a) << 1);
+}
+
+static ssize_t show_line1(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	return show_line(dev, buf, LCD_LINE1_OFFSET, LCD_LINE2_OFFSET);
+}
+
+static ssize_t show_line2(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	return show_line(dev, buf, LCD_LINE2_OFFSET, LCD_LINE3_OFFSET);
+}
+
+static ssize_t show_line3(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	return show_line(dev, buf, LCD_LINE3_OFFSET, LCD_LINE4_OFFSET);
+}
+
+/* Writing to /sys/../lineX will set the coresponding LCD line.
+ * - Excess characters are ignored.
+ * - If less characters are written than allowed, the remaining digits are
+ *   unchanged.
+ * - The '\n' or '\t' char is a placeholder, it does not overwrite the
+ *   original content.
+ */
+static ssize_t store_line(struct device *dev, const char *buf, size_t count,
+		int el, size_t len)
+{
+	struct yealink_dev *yld;
+	int i;
+
+	down_write(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_write(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	if (len > count)
+		len = count;
+	for (i = 0; i < len; i++)
+		setChar(yld, el++, buf[i]);
+
+	up_write(&sysfs_rwsema);
+	return count;
+}
+
+static ssize_t store_line1(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return store_line(dev, buf, count, LCD_LINE1_OFFSET, LCD_LINE1_SIZE);
+}
+
+static ssize_t store_line2(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return store_line(dev, buf, count, LCD_LINE2_OFFSET, LCD_LINE2_SIZE);
+}
+
+static ssize_t store_line3(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return store_line(dev, buf, count, LCD_LINE3_OFFSET, LCD_LINE3_SIZE);
+}
+
+/* Interface to visible and audible "icons", these include:
+ * pictures on the LCD, the LED, and the dialtone signal.
+ */
+
+/* Get a list of "switchable elements" with their current state. */
+static ssize_t get_icons(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct yealink_dev *yld;
+	int i, ret = 1;
+
+	down_read(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_read(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
+		if (lcdMap[i].type != '.')
+			continue;
+		ret += sprintf(&buf[ret], "%s %s\n",
+				yld->lcdMap[i] == ' ' ? "  " : "on",
+				lcdMap[i].u.p.name);
+	}
+	up_read(&sysfs_rwsema);
+	return ret;
+}
+
+/* Change the visibility of a particular element. */
+static ssize_t set_icon(struct device *dev, const char *buf, size_t count,
+			int chr)
+{
+	struct yealink_dev *yld;
+	int i;
+
+	down_write(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_write(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
+		if (lcdMap[i].type != '.')
+			continue;
+		if (strncmp(buf, lcdMap[i].u.p.name, count) == 0) {
+			setChar(yld, i, chr);
+			break;
+		}
+	}
+
+	up_write(&sysfs_rwsema);
+	return count;
+}
+
+static ssize_t show_icon(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	return set_icon(dev, buf, count, buf[0]);
+}
+
+static ssize_t hide_icon(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	return set_icon(dev, buf, count, ' ');
+}
+
+/* Upload a ringtone to the device.
+ */
+
+/* Stores raw ringtone data in the phone */
+static ssize_t store_ringtone(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct yealink_dev *yld;
+
+	down_write(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_write(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	/* TODO locking with async usb control interface??? */
+	yealink_set_ringtone(yld, (char *)buf, count);
+	up_write(&sysfs_rwsema);
+	return count;
+}
+
+#define _M444	S_IRUGO
+#define _M664	S_IRUGO|S_IWUSR|S_IWGRP
+#define _M220	S_IWUSR|S_IWGRP
+
+static DEVICE_ATTR(map_seg7	, _M664, show_map	, store_map	);
+static DEVICE_ATTR(line1	, _M664, show_line1	, store_line1	);
+static DEVICE_ATTR(line2	, _M664, show_line2	, store_line2	);
+static DEVICE_ATTR(line3	, _M664, show_line3	, store_line3	);
+static DEVICE_ATTR(get_icons	, _M444, get_icons	, NULL		);
+static DEVICE_ATTR(show_icon	, _M220, NULL		, show_icon	);
+static DEVICE_ATTR(hide_icon	, _M220, NULL		, hide_icon	);
+static DEVICE_ATTR(ringtone	, _M220, NULL		, store_ringtone);
+
+static struct attribute *yld_attributes[] = {
+	&dev_attr_line1.attr,
+	&dev_attr_line2.attr,
+	&dev_attr_line3.attr,
+	&dev_attr_get_icons.attr,
+	&dev_attr_show_icon.attr,
+	&dev_attr_hide_icon.attr,
+	&dev_attr_map_seg7.attr,
+	&dev_attr_ringtone.attr,
+	NULL
+};
+
+static struct attribute_group yld_attr_group = {
+	.attrs = yld_attributes
+};
+
+/*******************************************************************************
+ * Linux interface and usb initialisation
+ ******************************************************************************/
+
+static const struct yld_device {
+	u16 idVendor;
+	u16 idProduct;
+	char *name;
+} yld_device[] = {
+	{ 0x6993, 0xb001, "Yealink usb-p1k" },
+};
+
+static struct usb_device_id usb_table [] = {
+	{ USB_INTERFACE_INFO(USB_CLASS_HID, 0, 0) },
+	{ }
+};
+
+static int usb_cleanup(struct yealink_dev *yld, int err)
+{
+	if (yld == NULL)
+		return err;
+
+        if (yld->urb_irq) {
+		usb_kill_urb(yld->urb_irq);
+		usb_free_urb(yld->urb_irq);
+	}
+        if (yld->urb_ctl)
+		usb_free_urb(yld->urb_ctl);
+        if (yld->idev.dev)
+		input_unregister_device(&yld->idev);
+	if (yld->ctl_req)
+		usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)),
+				yld->ctl_req, yld->ctl_req_dma);
+	if (yld->ctl_data)
+		usb_buffer_free(yld->udev, USB_PKT_LEN,
+				yld->ctl_data, yld->ctl_dma);
+	if (yld->irq_data)
+		usb_buffer_free(yld->udev, USB_PKT_LEN,
+				yld->irq_data, yld->irq_dma);
+	kfree(yld);
+	return err;
+}
+
+static void usb_disconnect(struct usb_interface *intf)
+{
+	struct yealink_dev *yld;
+
+	down_write(&sysfs_rwsema);
+	yld = usb_get_intfdata(intf);
+	sysfs_remove_group(&intf->dev.kobj, &yld_attr_group);
+	usb_set_intfdata(intf, NULL);
+	up_write(&sysfs_rwsema);
+
+	usb_cleanup(yld, 0);
+}
+
+static int usb_match(struct usb_device *udev)
+{
+	int i;
+	u16 idVendor = le16_to_cpu(udev->descriptor.idVendor);
+	u16 idProduct = le16_to_cpu(udev->descriptor.idProduct);
+
+	for (i = 0; i < ARRAY_SIZE(yld_device); i++) {
+		if ((idVendor == yld_device[i].idVendor) &&
+		    (idProduct == yld_device[i].idProduct))
+			return i;
+	}
+	return -ENODEV;
+}
+
+static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev (intf);
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct yealink_dev *yld;
+	char path[64];
+	int ret, pipe, i;
+
+	i = usb_match(udev);
+	if (i < 0)
+		return -ENODEV;
+
+	interface = intf->cur_altsetting;
+	endpoint = &interface->endpoint[0].desc;
+	if (!(endpoint->bEndpointAddress & 0x80))
+		return -EIO;
+	if ((endpoint->bmAttributes & 3) != 3)
+		return -EIO;
+
+	if ((yld = kmalloc(sizeof(struct yealink_dev), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	memset(yld, 0, sizeof(*yld));
+	yld->udev = udev;
+
+	/* allocate usb buffers */
+	yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
+					SLAB_ATOMIC, &yld->irq_dma);
+	if (yld->irq_data == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	yld->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
+					SLAB_ATOMIC, &yld->ctl_dma);
+	if (!yld->ctl_data)
+		return usb_cleanup(yld, -ENOMEM);
+
+	yld->ctl_req = usb_buffer_alloc(udev, sizeof(*(yld->ctl_req)),
+					SLAB_ATOMIC, &yld->ctl_req_dma);
+	if (yld->ctl_req == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	/* allocate urb structures */
+	yld->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
+        if (yld->urb_irq == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	yld->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
+        if (yld->urb_ctl == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	/* get a handle to the interrupt data pipe */
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	if (ret != USB_PKT_LEN)
+		err("invalid payload size %d, expected %d", ret, USB_PKT_LEN);
+
+	/* initialise irq urb */
+	usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data,
+			USB_PKT_LEN,
+			urb_irq_callback,
+			yld, endpoint->bInterval);
+	yld->urb_irq->transfer_dma = yld->irq_dma;
+	yld->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	yld->urb_irq->dev = udev;
+
+	/* initialise ctl urb */
+	yld->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+				      USB_DIR_OUT;
+	yld->ctl_req->bRequest	= USB_REQ_SET_CONFIGURATION;
+	yld->ctl_req->wValue	= cpu_to_le16(0x200);
+	yld->ctl_req->wIndex	= cpu_to_le16(interface->desc.bInterfaceNumber);
+	yld->ctl_req->wLength	= cpu_to_le16(USB_PKT_LEN);
+
+	usb_fill_control_urb(yld->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
+			(void *)yld->ctl_req, yld->ctl_data, USB_PKT_LEN,
+			urb_ctl_callback, yld);
+	yld->urb_ctl->setup_dma	= yld->ctl_req_dma;
+	yld->urb_ctl->transfer_dma	= yld->ctl_dma;
+	yld->urb_ctl->transfer_flags	|= URB_NO_SETUP_DMA_MAP |
+					URB_NO_TRANSFER_DMA_MAP;
+	yld->urb_ctl->dev = udev;
+
+	/* find out the physical bus location */
+	if (usb_make_path(udev, path, sizeof(path)) > 0)
+		snprintf(yld->phys, sizeof(yld->phys)-1,  "%s/input0", path);
+
+	/* register settings for the input device */
+	init_input_dev(&yld->idev);
+	yld->idev.private	= yld;
+	yld->idev.id.bustype	= BUS_USB;
+	yld->idev.id.vendor	= le16_to_cpu(udev->descriptor.idVendor);
+	yld->idev.id.product	= le16_to_cpu(udev->descriptor.idProduct);
+	yld->idev.id.version	= le16_to_cpu(udev->descriptor.bcdDevice);
+	yld->idev.dev		= &intf->dev;
+	yld->idev.name		= yld_device[i].name;
+	yld->idev.phys		= yld->phys;
+	/* yld->idev.event		= input_ev;	TODO */
+	yld->idev.open		= input_open;
+	yld->idev.close		= input_close;
+
+	/* register available key events */
+	yld->idev.evbit[0] = BIT(EV_KEY);
+	for (i = 0; i < 256; i++) {
+		int k = map_p1k_to_key(i);
+		if (k >= 0) {
+			set_bit(k & 0xff, yld->idev.keybit);
+			if (k >> 8)
+				set_bit(k >> 8, yld->idev.keybit);
+		}
+	}
+
+	printk(KERN_INFO "input: %s on %s\n", yld->idev.name, path);
+
+	input_register_device(&yld->idev);
+
+	usb_set_intfdata(intf, yld);
+
+	/* clear visible elements */
+	for (i=0; i<ARRAY_SIZE(lcdMap); i++)
+		setChar(yld, i, ' ');
+
+	/* display driver version on LCD line 3 */
+	store_line3(&intf->dev, NULL,
+			DRIVER_VERSION, sizeof(DRIVER_VERSION));
+
+	/* Register sysfs hooks (don't care about failure) */
+	sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
+	return 0;
+}
+
+static struct usb_driver yealink_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "yealink",
+	.probe		= usb_probe,
+	.disconnect	= usb_disconnect,
+	.id_table	= usb_table,
+};
+
+static int __init yealink_dev_init(void)
+{
+	int ret = usb_register(&yealink_driver);
+	if (ret == 0)
+		info(DRIVER_DESC ":" DRIVER_VERSION);
+	return ret;
+}
+
+static void __exit yealink_dev_exit(void)
+{
+	usb_deregister(&yealink_driver);
+}
+
+module_init(yealink_dev_init);
+module_exit(yealink_dev_exit);
+
+MODULE_DEVICE_TABLE (usb, usb_table);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");

+ 220 - 0
drivers/usb/input/yealink.h

@@ -0,0 +1,220 @@
+/*
+ * drivers/usb/input/yealink.h
+ *
+ * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef INPUT_YEALINK_H
+#define INPUT_YEALINK_H
+
+/* Using the control channel on interface 3 various aspects of the phone
+ * can be controlled like LCD, LED, dialtone and the ringtone.
+ */
+
+struct yld_ctl_packet {
+	u8	cmd;		/* command code, see below */
+	u8	size;		/* 1-11, size of used data bytes. */
+	u16	offset;		/* internal packet offset */
+	u8	data[11];
+	s8	sum;		/* negative sum of 15 preceding bytes */
+} __attribute__ ((packed));
+
+#define USB_PKT_LEN	sizeof(struct yld_ctl_packet)
+
+/* The following yld_ctl_packet's are available: */
+
+/* Init registers
+ *
+ * cmd		0x8e
+ * size		10
+ * offset	0
+ * data		0,0,0,0....
+ */
+#define CMD_INIT		0x8e
+
+/* Request key scan
+ *
+ * cmd		0x80
+ * size		1
+ * offset	0
+ * data[0]	on return returns the key number, if it changes there's a new
+ * 		key pressed.
+ */
+#define CMD_KEYPRESS		0x80
+
+/* Request scancode
+ *
+ * cmd		0x81
+ * size		1
+ * offset	key number [0-1f]
+ * data[0]	on return returns the scancode
+ */
+#define CMD_SCANCODE		0x81
+
+/* Set LCD
+ *
+ * cmd		0x04
+ * size		1-11
+ * offset	0-23
+ * data		segment bits
+ */
+#define CMD_LCD			0x04
+
+/* Set led
+ *
+ * cmd		0x05
+ * size		1
+ * offset	0
+ * data[0]	0 OFF / 1 ON
+ */
+#define CMD_LED			0x05
+
+/* Set ringtone volume
+ *
+ * cmd		0x11
+ * size		1
+ * offset	0
+ * data[0]	0-0xff  volume
+ */
+#define CMD_RING_VOLUME		0x11
+
+/* Set ringtone notes
+ *
+ * cmd		0x02
+ * size		1-11
+ * offset	0->
+ * data		binary representation LE16(-freq), LE16(duration) ....
+ */
+#define CMD_RING_NOTE		0x02
+
+/* Sound ringtone via the speaker on the back
+ *
+ * cmd		0x03
+ * size		1
+ * offset	0
+ * data[0]	0 OFF / 0x24 ON
+ */
+#define CMD_RINGTONE		0x03
+
+/* Sound dial tone via the ear speaker
+ *
+ * cmd		0x09
+ * size		1
+ * offset	0
+ * data[0]	0 OFF / 1 ON
+ */
+#define CMD_DIALTONE		0x09
+
+#endif /* INPUT_YEALINK_H */
+
+
+#if defined(_SEG) && defined(_PIC)
+/* This table maps the LCD segments onto individual bit positions in the
+ * yld_status struct.
+ */
+
+/* LCD, each segment must be driven seperately.
+ *
+ * Layout:
+ *
+ *   |[]   [][]   [][]   [][]   in   |[][]
+ *   |[] M [][] D [][] : [][]   out  |[][]
+ *                             store
+ *
+ *    NEW REP         SU MO TU WE TH FR SA
+ *
+ *    [] [] [] [] [] [] [] [] [] [] [] []
+ *    [] [] [] [] [] [] [] [] [] [] [] []
+ */
+
+/* Line 1
+ *	Format		: 18.e8.M8.88...188
+ *	Icon names	: M D : IN OUT STORE
+ */
+#define LCD_LINE1_OFFSET	0
+#define LCD_LINE1_SIZE		17
+
+/* Note: first g then f =>			       !      !      */
+/* _SEG(    type    a      b      c      d      e      g      f   )  */
+	_SEG('1',  0,0 , 22,2 , 22,2 ,  0,0 ,  0,0 ,  0,0 ,  0,0	),
+	_SEG('8', 20,1 , 20,2 , 20,4 , 20,8 , 21,4 , 21,2 , 21,1	),
+	_PIC('.', 22,1 , "M"						),
+	_SEG('e', 18,1 , 18,2 , 18,4 , 18,1 , 19,2 , 18,1 , 19,1	),
+	_SEG('8', 16,1 , 16,2 , 16,4 , 16,8 , 17,4 , 17,2 , 17,1	),
+	_PIC('.', 15,8 , "D"						),
+	_SEG('M', 14,1 , 14,2 , 14,4 , 14,1 , 15,4 , 15,2 , 15,1	),
+	_SEG('8', 12,1 , 12,2 , 12,4 , 12,8 , 13,4 , 13,2 , 13,1	),
+	_PIC('.', 11,8 , ":"						),
+	_SEG('8', 10,1 , 10,2 , 10,4 , 10,8 , 11,4 , 11,2 , 11,1	),
+	_SEG('8',  8,1 ,  8,2 ,  8,4 ,  8,8 ,  9,4 ,  9,2 ,  9,1	),
+	_PIC('.',  7,1 , "IN"						),
+	_PIC('.',  7,2 , "OUT"						),
+	_PIC('.',  7,4 , "STORE"					),
+	_SEG('1',  0,0 ,  5,1 ,  5,1 ,  0,0 ,  0,0 ,  0,0 ,  0,0	),
+	_SEG('8',  4,1 ,  4,2 ,  4,4 ,  4,8 ,  5,8 ,  5,4 ,  5,2	),
+	_SEG('8',  2,1 ,  2,2 ,  2,4 ,  2,8 ,  3,4 ,  3,2 ,  3,1	),
+
+/* Line 2
+ *	Format		: .........
+ *	Pict. name	: NEW REP SU MO TU WE TH FR SA
+ */
+#define LCD_LINE2_OFFSET	LCD_LINE1_OFFSET + LCD_LINE1_SIZE
+#define LCD_LINE2_SIZE		9
+
+	_PIC('.', 23,2 , "NEW"	),
+	_PIC('.', 23,4 , "REP"	),
+	_PIC('.',  1,8 , "SU"	),
+	_PIC('.',  1,4 , "MO"	),
+	_PIC('.',  1,2 , "TU"	),
+	_PIC('.',  1,1 , "WE"	),
+	_PIC('.',  0,1 , "TH"	),
+	_PIC('.',  0,2 , "FR"	),
+	_PIC('.',  0,4 , "SA"	),
+
+/* Line 3
+ *	Format		: 888888888888
+ */
+#define LCD_LINE3_OFFSET	LCD_LINE2_OFFSET + LCD_LINE2_SIZE
+#define LCD_LINE3_SIZE		12
+
+	_SEG('8', 22,16, 22,32, 22,64, 22,128, 23,128, 23,64, 23,32  ),
+	_SEG('8', 20,16, 20,32, 20,64, 20,128, 21,128, 21,64, 21,32  ),
+	_SEG('8', 18,16, 18,32, 18,64, 18,128, 19,128, 19,64, 19,32  ),
+	_SEG('8', 16,16, 16,32, 16,64, 16,128, 17,128, 17,64, 17,32  ),
+	_SEG('8', 14,16, 14,32, 14,64, 14,128, 15,128, 15,64, 15,32  ),
+	_SEG('8', 12,16, 12,32, 12,64, 12,128, 13,128, 13,64, 13,32  ),
+	_SEG('8', 10,16, 10,32, 10,64, 10,128, 11,128, 11,64, 11,32  ),
+	_SEG('8',  8,16,  8,32,  8,64,  8,128,  9,128,  9,64,  9,32  ),
+	_SEG('8',  6,16,  6,32,  6,64,  6,128,  7,128,  7,64,  7,32  ),
+	_SEG('8',  4,16,  4,32,  4,64,  4,128,  5,128,  5,64,  5,32  ),
+	_SEG('8',  2,16,  2,32,  2,64,  2,128,  3,128,  3,64,  3,32  ),
+	_SEG('8',  0,16,  0,32,  0,64,  0,128,  1,128,  1,64,  1,32  ),
+
+/* Line 4
+ *
+ * The LED, DIALTONE and RINGTONE are implemented as icons and use the same
+ * sysfs interface.
+ */
+#define LCD_LINE4_OFFSET	LCD_LINE3_OFFSET + LCD_LINE3_SIZE
+
+	_PIC('.', offsetof(struct yld_status, led)	, 0x01, "LED" ),
+	_PIC('.', offsetof(struct yld_status, dialtone) , 0x01, "DIALTONE" ),
+	_PIC('.', offsetof(struct yld_status, ringtone) , 0x24, "RINGTONE" ),
+
+#undef _SEG
+#undef _PIC
+#endif /* _SEG && _PIC */

+ 1 - 2
drivers/usb/misc/auerswald.c

@@ -426,7 +426,7 @@ static int auerchain_submit_urb (pauerchain_t acp, struct urb * urb)
 
 /* cancel an urb which is submitted to the chain
    the result is 0 if the urb is cancelled, or -EINPROGRESS if
-   URB_ASYNC_UNLINK is set and the function is successfully started.
+   the function is successfully started.
 */
 static int auerchain_unlink_urb (pauerchain_t acp, struct urb * urb)
 {
@@ -515,7 +515,6 @@ static void auerchain_unlink_all (pauerchain_t acp)
         acep = acp->active;
         if (acep) {
                 urbp = acep->urbp;
-                urbp->transfer_flags &= ~URB_ASYNC_UNLINK;
                 dbg ("unlink active urb");
                 usb_kill_urb (urbp);
         }

+ 3 - 3
drivers/usb/misc/ldusb.c

@@ -464,7 +464,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
 	actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_tail*(sizeof(size_t)+dev->interrupt_in_endpoint_size));
 	bytes_to_read = min(count, *actual_buffer);
 	if (bytes_to_read < *actual_buffer)
-		dev_warn(&dev->intf->dev, "Read buffer overflow, %d bytes dropped\n",
+		dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",
 			 *actual_buffer-bytes_to_read);
 
 	/* copy one interrupt_in_buffer from ring_buffer into userspace */
@@ -528,8 +528,8 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
 	/* write the data into interrupt_out_buffer from userspace */
 	bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
 	if (bytes_to_write < count)
-		dev_warn(&dev->intf->dev, "Write buffer overflow, %d bytes dropped\n",count-bytes_to_write);
-	dbg_info(&dev->intf->dev, "%s: count = %d, bytes_to_write = %d\n", __FUNCTION__, count, bytes_to_write);
+		dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
+	dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __FUNCTION__, count, bytes_to_write);
 
 	if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
 		retval = -EFAULT;

+ 2 - 2
drivers/usb/misc/sisusbvga/sisusb.c

@@ -229,7 +229,7 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe,
 	usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
 		sisusb_bulk_completeout, &sisusb->urbout_context[index]);
 
-	urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
+	urb->transfer_flags |= tflags;
 	urb->actual_length = 0;
 
 	if ((urb->transfer_dma = transfer_dma))
@@ -295,7 +295,7 @@ sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data,
 	usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
 			sisusb_bulk_completein, sisusb);
 
-	urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
+	urb->transfer_flags |= tflags;
 	urb->actual_length = 0;
 
 	if ((urb->transfer_dma = transfer_dma))

+ 0 - 2
drivers/usb/misc/usbtest.c

@@ -986,7 +986,6 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
 
 		u->context = &context;
 		u->complete = ctrl_complete;
-		u->transfer_flags |= URB_ASYNC_UNLINK;
 	}
 
 	/* queue the urbs */
@@ -1052,7 +1051,6 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
 	urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size);
 	if (!urb)
 		return -ENOMEM;
-	urb->transfer_flags |= URB_ASYNC_UNLINK;
 	urb->context = &completion;
 	urb->complete = unlink1_callback;
 

+ 1 - 1
drivers/usb/mon/Makefile

@@ -2,7 +2,7 @@
 # Makefile for USB Core files and filesystem
 #
 
-usbmon-objs	:= mon_main.o mon_stat.o mon_text.o
+usbmon-objs	:= mon_main.o mon_stat.o mon_text.o mon_dma.o
 
 # This does not use CONFIG_USB_MON because we want this to use a tristate.
 obj-$(CONFIG_USB)	+= usbmon.o

+ 55 - 0
drivers/usb/mon/mon_dma.c

@@ -0,0 +1,55 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * mon_dma.c: Library which snoops on DMA areas.
+ *
+ * Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com)
+ */
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/highmem.h>
+#include <asm/page.h>
+
+#include <linux/usb.h>	/* Only needed for declarations in usb_mon.h */
+#include "usb_mon.h"
+
+#ifdef __i386__		/* CONFIG_ARCH_I386 does not exit */
+#define MON_HAS_UNMAP 1
+
+#define phys_to_page(phys)	pfn_to_page((phys) >> PAGE_SHIFT)
+
+char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
+{
+	struct page *pg;
+	unsigned long flags;
+	unsigned char *map;
+	unsigned char *ptr;
+
+	/*
+	 * On i386, a DMA handle is the "physical" address of a page.
+	 * In other words, the bus address is equal to physical address.
+	 * There is no IOMMU.
+	 */
+	pg = phys_to_page(dma_addr);
+
+	/*
+	 * We are called from hardware IRQs in case of callbacks.
+	 * But we can be called from softirq or process context in case
+	 * of submissions. In such case, we need to protect KM_IRQ0.
+	 */
+	local_irq_save(flags);
+	map = kmap_atomic(pg, KM_IRQ0);
+	ptr = map + (dma_addr & (PAGE_SIZE-1));
+	memcpy(dst, ptr, len);
+	kunmap_atomic(map, KM_IRQ0);
+	local_irq_restore(flags);
+	return 0;
+}
+#endif /* __i386__ */
+
+#ifndef MON_HAS_UNMAP
+char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
+{
+	return 'D';
+}
+#endif

+ 17 - 18
drivers/usb/mon/mon_text.c

@@ -91,25 +91,11 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
     int len, char ev_type)
 {
 	int pipe = urb->pipe;
-	unsigned char *data;
-
-	/*
-	 * The check to see if it's safe to poke at data has an enormous
-	 * number of corner cases, but it seems that the following is
-	 * more or less safe.
-	 *
-	 * We do not even try to look transfer_buffer, because it can
-	 * contain non-NULL garbage in case the upper level promised to
-	 * set DMA for the HCD.
-	 */
-	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
-		return 'D';
 
 	if (len <= 0)
 		return 'L';
-
-	if ((data = urb->transfer_buffer) == NULL)
-		return 'Z';	/* '0' would be not as pretty. */
+	if (len >= DATA_MAX)
+		len = DATA_MAX;
 
 	/*
 	 * Bulk is easy to shortcut reliably. 
@@ -126,8 +112,21 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
 		}
 	}
 
-	if (len >= DATA_MAX)
-		len = DATA_MAX;
+	/*
+	 * The check to see if it's safe to poke at data has an enormous
+	 * number of corner cases, but it seems that the following is
+	 * more or less safe.
+	 *
+	 * We do not even try to look transfer_buffer, because it can
+	 * contain non-NULL garbage in case the upper level promised to
+	 * set DMA for the HCD.
+	 */
+	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
+		return mon_dmapeek(ep->data, urb->transfer_dma, len);
+
+	if (urb->transfer_buffer == NULL)
+		return 'Z';	/* '0' would be not as pretty. */
+
 	memcpy(ep->data, urb->transfer_buffer, len);
 	return 0;
 }

+ 4 - 0
drivers/usb/mon/usb_mon.h

@@ -45,6 +45,10 @@ struct mon_reader {
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
 void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
 
+/*
+ */
+extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
+
 extern struct semaphore mon_lock;
 
 extern struct file_operations mon_fops_text;

+ 109 - 99
drivers/usb/net/Kconfig

@@ -99,7 +99,7 @@ config USB_USBNET
 	  with "minidrivers" built around a common network driver core
 	  that supports deep queues for efficient transfers.  (This gives
 	  better performance with small packets and at high speeds).
-	  
+
 	  The USB host runs "usbnet", and the other end of the link might be:
 
 	  - Another USB host, when using USB "network" or "data transfer"
@@ -125,38 +125,63 @@ config USB_USBNET
 	  To compile this driver as a module, choose M here: the
 	  module will be called usbnet.
 
-comment "USB Host-to-Host Cables"
-	depends on USB_USBNET
-
-config USB_ALI_M5632
-	boolean "ALi M5632 based 'USB 2.0 Data Link' cables"
-	depends on USB_USBNET
+config USB_NET_AX8817X
+	tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters"
+	depends on USB_USBNET && NET_ETHERNET
+	select CRC32
+	select MII
 	default y
 	help
-	  Choose this option if you're using a host-to-host cable
-	  based on this design, which supports USB 2.0 high speed.
+	  This option adds support for ASIX AX88xxx based USB 2.0
+	  10/100 Ethernet adapters.
 
-config USB_AN2720
-	boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
-	depends on USB_USBNET
-	default y
-	help
-	  Choose this option if you're using a host-to-host cable
-	  based on this design.  Note that AnchorChips is now a
-	  Cypress brand.
+ 	  This driver should work with at least the following devices:
+	    * Aten UC210T
+	    * ASIX AX88172
+	    * Billionton Systems, USB2AR
+	    * Buffalo LUA-U2-KTX
+	    * Corega FEther USB2-TX
+	    * D-Link DUB-E100
+	    * Hawking UF200
+	    * Linksys USB200M
+	    * Netgear FA120
+	    * Sitecom LN-029
+	    * Intellinet USB 2.0 Ethernet
+	    * ST Lab USB 2.0 Ethernet
+	    * TrendNet TU2-ET100
 
-config USB_BELKIN
-	boolean "eTEK based host-to-host cables (Advance, Belkin, ...)"
+	  This driver creates an interface named "ethX", where X depends on
+	  what other networking devices you have in use.
+
+
+config USB_NET_CDCETHER
+	tristate "CDC Ethernet support (smart devices such as cable modems)"
 	depends on USB_USBNET
 	default y
 	help
-	  Choose this option if you're using a host-to-host cable
-	  based on this design:  two NetChip 2890 chips and an Atmel
-	  microcontroller, with LEDs that indicate traffic.
+	  This option supports devices conforming to the Communication Device
+	  Class (CDC) Ethernet Control Model, a specification that's easy to
+	  implement in device firmware.  The CDC specifications are available
+	  from <http://www.usb.org/>.
 
-config USB_GENESYS
-	boolean "GeneSys GL620USB-A based cables"
-	default y
+	  CDC Ethernet is an implementation option for DOCSIS cable modems
+	  that support USB connectivity, used for non-Microsoft USB hosts.
+	  The Linux-USB CDC Ethernet Gadget driver is an open implementation.
+ 	  This driver should work with at least the following devices:
+
+ 	    * Ericsson PipeRider (all variants)
+ 	    * Motorola (DM100 and SB4100)
+ 	    * Broadcom Cable Modem (reference design)
+ 	    * Toshiba PCX1100U
+	    * ...
+
+	  This driver creates an interface named "ethX", where X depends on
+	  what other networking devices you have in use.  However, if the
+	  IEEE 802 "local assignment" bit is set in the address, a "usbX"
+	  name is used instead.
+
+config USB_NET_GL620A
+	tristate "GeneSys GL620USB-A based cables"
 	depends on USB_USBNET
 	help
 	  Choose this option if you're using a host-to-host cable,
@@ -164,38 +189,78 @@ config USB_GENESYS
 
 	  Note that the half-duplex "GL620USB" is not supported.
 
-config USB_NET1080
-	boolean "NetChip 1080 based cables (Laplink, ...)"
+config USB_NET_NET1080
+	tristate "NetChip 1080 based cables (Laplink, ...)"
 	default y
 	depends on USB_USBNET
 	help
 	  Choose this option if you're using a host-to-host cable based
-	  on this design:  one NetChip 1080 chips and supporting logic,
-	  supporting LEDs that indicate traffic
+	  on this design:  one NetChip 1080 chip and supporting logic,
+	  optionally with LEDs that indicate traffic
 
-config USB_PL2301
-	boolean "Prolific PL-2301/2302 based cables"
-	default y
-	# handshake/init/reset problems, from original 'plusb' driver
+config USB_NET_PLUSB
+	tristate "Prolific PL-2301/2302 based cables"
+	# if the handshake/init/reset problems, from original 'plusb',
+	# are ever resolved ... then remove "experimental"
 	depends on USB_USBNET && EXPERIMENTAL
 	help
 	  Choose this option if you're using a host-to-host cable
 	  with one of these chips.
 
-config USB_KC2190
-	boolean "KT Technology KC2190 based cables (InstaNet)"
-	default y
+config USB_NET_RNDIS_HOST
+	tristate "Host for RNDIS devices (EXPERIMENTAL)"
 	depends on USB_USBNET && EXPERIMENTAL
+	select USB_NET_CDCETHER
 	help
-	  Choose this option if you're using a host-to-host cable
-	  with one of these chips.
+	  This option enables hosting "Remote NDIS" USB networking links,
+	  as encouraged by Microsoft (instead of CDC Ethernet!) for use in
+	  various devices that may only support this protocol.
 
-comment "Intelligent USB Devices/Gadgets"
+	  Avoid using this protocol unless you have no better options.
+	  The protocol specification is incomplete, and is controlled by
+	  (and for) Microsoft; it isn't an "Open" ecosystem or market.
+
+config USB_NET_CDC_SUBSET
+	tristate "Simple USB Network Links (CDC Ethernet subset)"
 	depends on USB_USBNET
+	help
+	  This driver module supports USB network devices that can work
+	  without any device-specific information.  Select it if you have
+	  one of these drivers.
+
+	  Note that while many USB host-to-host cables can work in this mode,
+	  that may mean not being able to talk to Win32 systems or more
+	  commonly not being able to handle certain events (like replugging
+	  the host on the other end) very well.  Also, these devices will
+	  not generally have permanently assigned Ethernet addresses.
+
+config USB_ALI_M5632
+	boolean "ALi M5632 based 'USB 2.0 Data Link' cables"
+	depends on USB_NET_CDC_SUBSET
+	help
+	  Choose this option if you're using a host-to-host cable
+	  based on this design, which supports USB 2.0 high speed.
+
+config USB_AN2720
+	boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
+	depends on USB_NET_CDC_SUBSET
+	help
+	  Choose this option if you're using a host-to-host cable
+	  based on this design.  Note that AnchorChips is now a
+	  Cypress brand.
+
+config USB_BELKIN
+	boolean "eTEK based host-to-host cables (Advance, Belkin, ...)"
+	depends on USB_NET_CDC_SUBSET
+	default y
+	help
+	  Choose this option if you're using a host-to-host cable
+	  based on this design:  two NetChip 2890 chips and an Atmel
+	  microcontroller, with LEDs that indicate traffic.
 
 config USB_ARMLINUX
 	boolean "Embedded ARM Linux links (iPaq, ...)"
-	depends on USB_USBNET
+	depends on USB_NET_CDC_SUBSET
 	default y
 	help
 	  Choose this option to support the "usb-eth" networking driver
@@ -212,15 +277,15 @@ config USB_ARMLINUX
 
 config USB_EPSON2888
 	boolean "Epson 2888 based firmware (DEVELOPMENT)"
-	depends on USB_USBNET
-	default y
+	depends on USB_NET_CDC_SUBSET
 	help
 	  Choose this option to support the usb networking links used
 	  by some sample firmware from Epson.
 
-config USB_ZAURUS
-	boolean "Sharp Zaurus (stock ROMs) and compatible"
+config USB_NET_ZAURUS
+	tristate "Sharp Zaurus (stock ROMs) and compatible"
 	depends on USB_USBNET
+	select USB_NET_CDCETHER
 	select CRC32
 	default y
 	help
@@ -235,61 +300,6 @@ config USB_ZAURUS
 	  really need this non-conformant variant of CDC Ethernet (or in
 	  some cases CDC MDLM) protocol, not "g_ether".
 
-config USB_CDCETHER
-	boolean "CDC Ethernet support (smart devices such as cable modems)"
-	depends on USB_USBNET
-	default y
-	help
-	  This option supports devices conforming to the Communication Device
-	  Class (CDC) Ethernet Control Model, a specification that's easy to
-	  implement in device firmware.  The CDC specifications are available
-	  from <http://www.usb.org/>.
-	  
-	  CDC Ethernet is an implementation option for DOCSIS cable modems
-	  that support USB connectivity, used for non-Microsoft USB hosts.
- 	  This driver should work with at least the following devices:
-
- 	    * Ericsson PipeRider (all variants)
- 	    * Motorola (DM100 and SB4100)
- 	    * Broadcom Cable Modem (reference design)
- 	    * Toshiba PCX1100U
-	    * ...
-
-	  This driver creates an interface named "ethX", where X depends on
-	  what other networking devices you have in use.  However, if the
-	  IEEE 802 "local assignment" bit is set in the address, a "usbX"
-	  name is used instead.
-
-comment "USB Network Adapters"
-	depends on USB_USBNET
-
-config USB_AX8817X
-	boolean "ASIX AX88xxx Based USB 2.0 Ethernet Devices"
-	depends on USB_USBNET && NET_ETHERNET
-	select CRC32
-	select MII
-	default y
-	help
-	  This option adds support for ASIX AX88xxx based USB 2.0
-	  10/100 Ethernet devices.
-
- 	  This driver should work with at least the following devices:
-	    * Aten UC210T
-	    * ASIX AX88172
-	    * Billionton Systems, USB2AR 
-	    * Buffalo LUA-U2-KTX
-	    * Corega FEther USB2-TX
-	    * D-Link DUB-E100
-	    * Hawking UF200
-	    * Linksys USB200M
-	    * Netgear FA120
-	    * Sitecom LN-029
-	    * Intellinet USB 2.0 Ethernet
-	    * ST Lab USB 2.0 Ethernet
-	    * TrendNet TU2-ET100
-
-	  This driver creates an interface named "ethX", where X depends on
-	  what other networking devices you have in use.  
 
 config USB_ZD1201
 	tristate "USB ZD1201 based Wireless device support"

+ 8 - 0
drivers/usb/net/Makefile

@@ -6,5 +6,13 @@ obj-$(CONFIG_USB_CATC)		+= catc.o
 obj-$(CONFIG_USB_KAWETH)	+= kaweth.o
 obj-$(CONFIG_USB_PEGASUS)	+= pegasus.o
 obj-$(CONFIG_USB_RTL8150)	+= rtl8150.o
+obj-$(CONFIG_USB_NET_AX8817X)	+= asix.o
+obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
+obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o
+obj-$(CONFIG_USB_NET_NET1080)	+= net1080.o
+obj-$(CONFIG_USB_NET_PLUSB)	+= plusb.o
+obj-$(CONFIG_USB_NET_RNDIS_HOST)	+= rndis_host.o
+obj-$(CONFIG_USB_NET_CDC_SUBSET)	+= cdc_subset.o
+obj-$(CONFIG_USB_NET_ZAURUS)	+= zaurus.o
 obj-$(CONFIG_USB_USBNET)	+= usbnet.o
 obj-$(CONFIG_USB_ZD1201)	+= zd1201.o

+ 948 - 0
drivers/usb/net/asix.c

@@ -0,0 +1,948 @@
+/*
+ * ASIX AX8817X based USB 2.0 Ethernet Devices
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * Copyright (c) 2002-2003 TiVo Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// #define	DEBUG			// error path messages, extra info
+// #define	VERBOSE			// more; success messages
+
+#include <linux/config.h>
+#ifdef	CONFIG_USB_DEBUG
+#   define DEBUG
+#endif
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+
+#include "usbnet.h"
+
+
+/* ASIX AX8817X based USB 2.0 Ethernet Devices */
+
+#define AX_CMD_SET_SW_MII		0x06
+#define AX_CMD_READ_MII_REG		0x07
+#define AX_CMD_WRITE_MII_REG		0x08
+#define AX_CMD_SET_HW_MII		0x0a
+#define AX_CMD_READ_EEPROM		0x0b
+#define AX_CMD_WRITE_EEPROM		0x0c
+#define AX_CMD_WRITE_ENABLE		0x0d
+#define AX_CMD_WRITE_DISABLE		0x0e
+#define AX_CMD_WRITE_RX_CTL		0x10
+#define AX_CMD_READ_IPG012		0x11
+#define AX_CMD_WRITE_IPG0		0x12
+#define AX_CMD_WRITE_IPG1		0x13
+#define AX_CMD_WRITE_IPG2		0x14
+#define AX_CMD_WRITE_MULTI_FILTER	0x16
+#define AX_CMD_READ_NODE_ID		0x17
+#define AX_CMD_READ_PHY_ID		0x19
+#define AX_CMD_READ_MEDIUM_STATUS	0x1a
+#define AX_CMD_WRITE_MEDIUM_MODE	0x1b
+#define AX_CMD_READ_MONITOR_MODE	0x1c
+#define AX_CMD_WRITE_MONITOR_MODE	0x1d
+#define AX_CMD_WRITE_GPIOS		0x1f
+#define AX_CMD_SW_RESET			0x20
+#define AX_CMD_SW_PHY_STATUS		0x21
+#define AX_CMD_SW_PHY_SELECT		0x22
+#define AX88772_CMD_READ_NODE_ID	0x13
+
+#define AX_MONITOR_MODE			0x01
+#define AX_MONITOR_LINK			0x02
+#define AX_MONITOR_MAGIC		0x04
+#define AX_MONITOR_HSFS			0x10
+
+/* AX88172 Medium Status Register values */
+#define AX_MEDIUM_FULL_DUPLEX		0x02
+#define AX_MEDIUM_TX_ABORT_ALLOW	0x04
+#define AX_MEDIUM_FLOW_CONTROL_EN	0x10
+
+#define AX_MCAST_FILTER_SIZE		8
+#define AX_MAX_MCAST			64
+
+#define AX_EEPROM_LEN			0x40
+
+#define AX_SWRESET_CLEAR		0x00
+#define AX_SWRESET_RR			0x01
+#define AX_SWRESET_RT			0x02
+#define AX_SWRESET_PRTE			0x04
+#define AX_SWRESET_PRL			0x08
+#define AX_SWRESET_BZ			0x10
+#define AX_SWRESET_IPRL			0x20
+#define AX_SWRESET_IPPD			0x40
+
+#define AX88772_IPG0_DEFAULT		0x15
+#define AX88772_IPG1_DEFAULT		0x0c
+#define AX88772_IPG2_DEFAULT		0x12
+
+#define AX88772_MEDIUM_FULL_DUPLEX	0x0002
+#define AX88772_MEDIUM_RESERVED		0x0004
+#define AX88772_MEDIUM_RX_FC_ENABLE	0x0010
+#define AX88772_MEDIUM_TX_FC_ENABLE	0x0020
+#define AX88772_MEDIUM_PAUSE_FORMAT	0x0080
+#define AX88772_MEDIUM_RX_ENABLE	0x0100
+#define AX88772_MEDIUM_100MB		0x0200
+#define AX88772_MEDIUM_DEFAULT	\
+	(AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \
+	 AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \
+	 AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE )
+
+#define AX_EEPROM_MAGIC			0xdeadbeef
+
+/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
+struct ax8817x_data {
+	u8 multi_filter[AX_MCAST_FILTER_SIZE];
+};
+
+struct ax88172_int_data {
+	u16 res1;
+	u8 link;
+	u16 res2;
+	u8 status;
+	u16 res3;
+} __attribute__ ((packed));
+
+static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+			    u16 size, void *data)
+{
+	return usb_control_msg(
+		dev->udev,
+		usb_rcvctrlpipe(dev->udev, 0),
+		cmd,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		value,
+		index,
+		data,
+		size,
+		USB_CTRL_GET_TIMEOUT);
+}
+
+static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+			     u16 size, void *data)
+{
+	return usb_control_msg(
+		dev->udev,
+		usb_sndctrlpipe(dev->udev, 0),
+		cmd,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		value,
+		index,
+		data,
+		size,
+		USB_CTRL_SET_TIMEOUT);
+}
+
+static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
+
+	if (urb->status < 0)
+		printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d",
+			urb->status);
+
+	kfree(req);
+	usb_free_urb(urb);
+}
+
+static void ax8817x_status(struct usbnet *dev, struct urb *urb)
+{
+	struct ax88172_int_data *event;
+	int link;
+
+	if (urb->actual_length < 8)
+		return;
+
+	event = urb->transfer_buffer;
+	link = event->link & 0x01;
+	if (netif_carrier_ok(dev->net) != link) {
+		if (link) {
+			netif_carrier_on(dev->net);
+			usbnet_defer_kevent (dev, EVENT_LINK_RESET );
+		} else
+			netif_carrier_off(dev->net);
+		devdbg(dev, "ax8817x - Link Status is: %d", link);
+	}
+}
+
+static void
+ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+				    u16 size, void *data)
+{
+	struct usb_ctrlrequest *req;
+	int status;
+	struct urb *urb;
+
+	if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
+		devdbg(dev, "Error allocating URB in write_cmd_async!");
+		return;
+	}
+
+	if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {
+		deverr(dev, "Failed to allocate memory for control request");
+		usb_free_urb(urb);
+		return;
+	}
+
+	req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+	req->bRequest = cmd;
+	req->wValue = cpu_to_le16(value);
+	req->wIndex = cpu_to_le16(index);
+	req->wLength = cpu_to_le16(size);
+
+	usb_fill_control_urb(urb, dev->udev,
+			     usb_sndctrlpipe(dev->udev, 0),
+			     (void *)req, data, size,
+			     ax8817x_async_cmd_callback, req);
+
+	if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+		deverr(dev, "Error submitting the control message: status=%d",
+				status);
+		kfree(req);
+		usb_free_urb(urb);
+	}
+}
+
+static void ax8817x_set_multicast(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+	u8 rx_ctl = 0x8c;
+
+	if (net->flags & IFF_PROMISC) {
+		rx_ctl |= 0x01;
+	} else if (net->flags & IFF_ALLMULTI
+		   || net->mc_count > AX_MAX_MCAST) {
+		rx_ctl |= 0x02;
+	} else if (net->mc_count == 0) {
+		/* just broadcast and directed */
+	} else {
+		/* We use the 20 byte dev->data
+		 * for our 8 byte filter buffer
+		 * to avoid allocating memory that
+		 * is tricky to free later */
+		struct dev_mc_list *mc_list = net->mc_list;
+		u32 crc_bits;
+		int i;
+
+		memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
+
+		/* Build the multicast hash filter. */
+		for (i = 0; i < net->mc_count; i++) {
+			crc_bits =
+			    ether_crc(ETH_ALEN,
+				      mc_list->dmi_addr) >> 26;
+			data->multi_filter[crc_bits >> 3] |=
+			    1 << (crc_bits & 7);
+			mc_list = mc_list->next;
+		}
+
+		ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
+				   AX_MCAST_FILTER_SIZE, data->multi_filter);
+
+		rx_ctl |= 0x10;
+	}
+
+	ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
+}
+
+static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	u16 res;
+	u8 buf[1];
+
+	ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf);
+	ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
+				(__u16)loc, 2, (u16 *)&res);
+	ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf);
+
+	return res & 0xffff;
+}
+
+/* same as above, but converts resulting value to cpu byte order */
+static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc)
+{
+	return le16_to_cpu(ax8817x_mdio_read(netdev,phy_id, loc));
+}
+
+static void
+ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	u16 res = val;
+	u8 buf[1];
+
+	ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf);
+	ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
+				(__u16)loc, 2, (u16 *)&res);
+	ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf);
+}
+
+/* same as above, but converts new value to le16 byte order before writing */
+static void
+ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val)
+{
+	ax8817x_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) );
+}
+
+static int ax88172_link_reset(struct usbnet *dev)
+{
+	u16 lpa;
+	u16 adv;
+	u16 res;
+	u8 mode;
+
+	mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN;
+	lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
+	adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
+	res = mii_nway_result(lpa|adv);
+	if (res & LPA_DUPLEX)
+		mode |= AX_MEDIUM_FULL_DUPLEX;
+	ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+
+	return 0;
+}
+
+static void
+ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+{
+	struct usbnet *dev = netdev_priv(net);
+	u8 opt;
+
+	if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
+		wolinfo->supported = 0;
+		wolinfo->wolopts = 0;
+		return;
+	}
+	wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
+	wolinfo->wolopts = 0;
+	if (opt & AX_MONITOR_MODE) {
+		if (opt & AX_MONITOR_LINK)
+			wolinfo->wolopts |= WAKE_PHY;
+		if (opt & AX_MONITOR_MAGIC)
+			wolinfo->wolopts |= WAKE_MAGIC;
+	}
+}
+
+static int
+ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+{
+	struct usbnet *dev = netdev_priv(net);
+	u8 opt = 0;
+	u8 buf[1];
+
+	if (wolinfo->wolopts & WAKE_PHY)
+		opt |= AX_MONITOR_LINK;
+	if (wolinfo->wolopts & WAKE_MAGIC)
+		opt |= AX_MONITOR_MAGIC;
+	if (opt != 0)
+		opt |= AX_MONITOR_MODE;
+
+	if (ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
+			      opt, 0, 0, &buf) < 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ax8817x_get_eeprom_len(struct net_device *net)
+{
+	return AX_EEPROM_LEN;
+}
+
+static int ax8817x_get_eeprom(struct net_device *net,
+			      struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct usbnet *dev = netdev_priv(net);
+	u16 *ebuf = (u16 *)data;
+	int i;
+
+	/* Crude hack to ensure that we don't overwrite memory
+	 * if an odd length is supplied
+	 */
+	if (eeprom->len % 2)
+		return -EINVAL;
+
+	eeprom->magic = AX_EEPROM_MAGIC;
+
+	/* ax8817x returns 2 bytes from eeprom on read */
+	for (i=0; i < eeprom->len / 2; i++) {
+		if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM,
+			eeprom->offset + i, 0, 2, &ebuf[i]) < 0)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static void ax8817x_get_drvinfo (struct net_device *net,
+				 struct ethtool_drvinfo *info)
+{
+	/* Inherit standard device info */
+	usbnet_get_drvinfo(net, info);
+	info->eedump_len = 0x3e;
+}
+
+static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	return mii_ethtool_gset(&dev->mii,cmd);
+}
+
+static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	return mii_ethtool_sset(&dev->mii,cmd);
+}
+
+/* We need to override some ethtool_ops so we require our
+   own structure so we don't interfere with other usbnet
+   devices that may be connected at the same time. */
+static struct ethtool_ops ax8817x_ethtool_ops = {
+	.get_drvinfo		= ax8817x_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+	.get_msglevel		= usbnet_get_msglevel,
+	.set_msglevel		= usbnet_set_msglevel,
+	.get_wol		= ax8817x_get_wol,
+	.set_wol		= ax8817x_set_wol,
+	.get_eeprom_len		= ax8817x_get_eeprom_len,
+	.get_eeprom		= ax8817x_get_eeprom,
+	.get_settings		= ax8817x_get_settings,
+	.set_settings		= ax8817x_set_settings,
+};
+
+static int ax8817x_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int ret = 0;
+	void *buf;
+	int i;
+	unsigned long gpio_bits = dev->driver_info->data;
+
+	usbnet_get_endpoints(dev,intf);
+
+	buf = kmalloc(ETH_ALEN, GFP_KERNEL);
+	if(!buf) {
+		ret = -ENOMEM;
+		goto out1;
+	}
+
+	/* Toggle the GPIOs in a manufacturer/model specific way */
+	for (i = 2; i >= 0; i--) {
+		if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
+					(gpio_bits >> (i * 8)) & 0xff, 0, 0,
+					buf)) < 0)
+			goto out2;
+		msleep(5);
+	}
+
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+				0x80, 0, 0, buf)) < 0) {
+		dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret);
+		goto out2;
+	}
+
+	/* Get the MAC address */
+	memset(buf, 0, ETH_ALEN);
+	if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID,
+				0, 0, 6, buf)) < 0) {
+		dbg("read AX_CMD_READ_NODE_ID failed: %d", ret);
+		goto out2;
+	}
+	memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+
+	/* Get the PHY id */
+	if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID,
+				0, 0, 2, buf)) < 0) {
+		dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret);
+		goto out2;
+	} else if (ret < 2) {
+		/* this should always return 2 bytes */
+		dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x",
+				ret);
+		ret = -EIO;
+		goto out2;
+	}
+
+	/* Initialize MII structure */
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = ax8817x_mdio_read;
+	dev->mii.mdio_write = ax8817x_mdio_write;
+	dev->mii.phy_id_mask = 0x3f;
+	dev->mii.reg_num_mask = 0x1f;
+	dev->mii.phy_id = *((u8 *)buf + 1);
+	dev->net->do_ioctl = ax8817x_ioctl;
+
+	dev->net->set_multicast_list = ax8817x_set_multicast;
+	dev->net->ethtool_ops = &ax8817x_ethtool_ops;
+
+	ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+		ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	mii_nway_restart(&dev->mii);
+
+	return 0;
+out2:
+	kfree(buf);
+out1:
+	return ret;
+}
+
+static struct ethtool_ops ax88772_ethtool_ops = {
+	.get_drvinfo		= ax8817x_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+	.get_msglevel		= usbnet_get_msglevel,
+	.set_msglevel		= usbnet_set_msglevel,
+	.get_wol		= ax8817x_get_wol,
+	.set_wol		= ax8817x_set_wol,
+	.get_eeprom_len		= ax8817x_get_eeprom_len,
+	.get_eeprom		= ax8817x_get_eeprom,
+	.get_settings		= ax8817x_get_settings,
+	.set_settings		= ax8817x_set_settings,
+};
+
+static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int ret;
+	void *buf;
+
+	usbnet_get_endpoints(dev,intf);
+
+	buf = kmalloc(6, GFP_KERNEL);
+	if(!buf) {
+		dbg ("Cannot allocate memory for buffer");
+		ret = -ENOMEM;
+		goto out1;
+	}
+
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
+				     0x00B0, 0, 0, buf)) < 0)
+		goto out2;
+
+	msleep(5);
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
+				0x0001, 0, 0, buf)) < 0) {
+		dbg("Select PHY #1 failed: %d", ret);
+		goto out2;
+	}
+
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD,
+				0, 0, buf)) < 0) {
+		dbg("Failed to power down internal PHY: %d", ret);
+		goto out2;
+	}
+
+	msleep(150);
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR,
+				0, 0, buf)) < 0) {
+		dbg("Failed to perform software reset: %d", ret);
+		goto out2;
+	}
+
+	msleep(150);
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+	     			AX_SWRESET_IPRL | AX_SWRESET_PRL,
+				0, 0, buf)) < 0) {
+		dbg("Failed to set Internal/External PHY reset control: %d",
+					ret);
+		goto out2;
+	}
+
+	msleep(150);
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+				0x0000, 0, 0, buf)) < 0) {
+		dbg("Failed to reset RX_CTL: %d", ret);
+		goto out2;
+	}
+
+	/* Get the MAC address */
+	memset(buf, 0, ETH_ALEN);
+	if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID,
+				0, 0, ETH_ALEN, buf)) < 0) {
+		dbg("Failed to read MAC address: %d", ret);
+		goto out2;
+	}
+	memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII,
+				0, 0, 0, buf)) < 0) {
+		dbg("Enabling software MII failed: %d", ret);
+		goto out2;
+	}
+
+	if (((ret = ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG,
+	      			0x0010, 2, 2, buf)) < 0)
+			|| (*((u16 *)buf) != 0x003b)) {
+		dbg("Read PHY register 2 must be 0x3b00: %d", ret);
+		goto out2;
+	}
+
+	/* Initialize MII structure */
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = ax8817x_mdio_read;
+	dev->mii.mdio_write = ax8817x_mdio_write;
+	dev->mii.phy_id_mask = 0xff;
+	dev->mii.reg_num_mask = 0xff;
+	dev->net->do_ioctl = ax8817x_ioctl;
+
+	/* Get the PHY id */
+	if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID,
+			0, 0, 2, buf)) < 0) {
+		dbg("Error reading PHY ID: %02x", ret);
+		goto out2;
+	} else if (ret < 2) {
+		/* this should always return 2 bytes */
+		dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x",
+		    ret);
+		ret = -EIO;
+		goto out2;
+	}
+	dev->mii.phy_id = *((u8 *)buf + 1);
+
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL,
+				0, 0, buf)) < 0) {
+		dbg("Set external PHY reset pin level: %d", ret);
+		goto out2;
+	}
+	msleep(150);
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+	     			AX_SWRESET_IPRL | AX_SWRESET_PRL,
+				0, 0, buf)) < 0) {
+		dbg("Set Internal/External PHY reset control: %d", ret);
+		goto out2;
+	}
+	msleep(150);
+
+
+	dev->net->set_multicast_list = ax8817x_set_multicast;
+	dev->net->ethtool_ops = &ax88772_ethtool_ops;
+
+	ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+			ADVERTISE_ALL | ADVERTISE_CSMA);
+	mii_nway_restart(&dev->mii);
+
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
+				AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) {
+		dbg("Write medium mode register: %d", ret);
+		goto out2;
+	}
+
+	if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0,
+				AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
+				AX88772_IPG2_DEFAULT, 0, buf)) < 0) {
+		dbg("Write IPG,IPG1,IPG2 failed: %d", ret);
+		goto out2;
+	}
+	if ((ret =
+	     ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) {
+		dbg("Failed to set hardware MII: %02x", ret);
+		goto out2;
+	}
+
+	/* Set RX_CTL to default values with 2k buffer, and enable cactus */
+	if ((ret =
+	     ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0,
+			       buf)) < 0) {
+		dbg("Reset RX_CTL failed: %d", ret);
+		goto out2;
+	}
+
+	kfree(buf);
+
+	/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
+	if (dev->driver_info->flags & FLAG_FRAMING_AX) {
+		/* hard_mtu  is still the default - the device does not support
+		   jumbo eth frames */
+		dev->rx_urb_size = 2048;
+	}
+
+	return 0;
+
+out2:
+	kfree(buf);
+out1:
+	return ret;
+}
+
+static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	u8  *head;
+	u32  header;
+	char *packet;
+	struct sk_buff *ax_skb;
+	u16 size;
+
+	head = (u8 *) skb->data;
+	memcpy(&header, head, sizeof(header));
+	le32_to_cpus(&header);
+	packet = head + sizeof(header);
+
+	skb_pull(skb, 4);
+
+	while (skb->len > 0) {
+		if ((short)(header & 0x0000ffff) !=
+		    ~((short)((header & 0xffff0000) >> 16))) {
+			devdbg(dev,"header length data is error");
+		}
+		/* get the packet length */
+		size = (u16) (header & 0x0000ffff);
+
+		if ((skb->len) - ((size + 1) & 0xfffe) == 0)
+			return 2;
+		if (size > ETH_FRAME_LEN) {
+			devdbg(dev,"invalid rx length %d", size);
+			return 0;
+		}
+		ax_skb = skb_clone(skb, GFP_ATOMIC);
+		if (ax_skb) {
+			ax_skb->len = size;
+			ax_skb->data = packet;
+			ax_skb->tail = packet + size;
+			usbnet_skb_return(dev, ax_skb);
+		} else {
+			return 0;
+		}
+
+		skb_pull(skb, (size + 1) & 0xfffe);
+
+		if (skb->len == 0)
+			break;
+
+		head = (u8 *) skb->data;
+		memcpy(&header, head, sizeof(header));
+		le32_to_cpus(&header);
+		packet = head + sizeof(header);
+		skb_pull(skb, 4);
+	}
+
+	if (skb->len < 0) {
+		devdbg(dev,"invalid rx length %d", skb->len);
+		return 0;
+	}
+	return 1;
+}
+
+static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+					unsigned flags)
+{
+	int padlen;
+	int headroom = skb_headroom(skb);
+	int tailroom = skb_tailroom(skb);
+	u32 packet_len;
+	u32 padbytes = 0xffff0000;
+
+	padlen = ((skb->len + 4) % 512) ? 0 : 4;
+
+	if ((!skb_cloned(skb))
+	    && ((headroom + tailroom) >= (4 + padlen))) {
+		if ((headroom < 4) || (tailroom < padlen)) {
+			skb->data = memmove(skb->head + 4, skb->data, skb->len);
+			skb->tail = skb->data + skb->len;
+		}
+	} else {
+		struct sk_buff *skb2;
+		skb2 = skb_copy_expand(skb, 4, padlen, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	skb_push(skb, 4);
+	packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+	memcpy(skb->data, &packet_len, sizeof(packet_len));
+
+	if ((skb->len % 512) == 0) {
+		memcpy( skb->tail, &padbytes, sizeof(padbytes));
+		skb_put(skb, sizeof(padbytes));
+	}
+	return skb;
+}
+
+static int ax88772_link_reset(struct usbnet *dev)
+{
+	u16 lpa;
+	u16 adv;
+	u16 res;
+	u16 mode;
+
+	mode = AX88772_MEDIUM_DEFAULT;
+	lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
+	adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
+	res = mii_nway_result(lpa|adv);
+
+	if ((res & LPA_DUPLEX) == 0)
+		mode &= ~AX88772_MEDIUM_FULL_DUPLEX;
+	if ((res & LPA_100) == 0)
+		mode &= ~AX88772_MEDIUM_100MB;
+	ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+
+	return 0;
+}
+
+static const struct driver_info ax8817x_info = {
+	.description = "ASIX AX8817x USB 2.0 Ethernet",
+	.bind = ax8817x_bind,
+	.status = ax8817x_status,
+	.link_reset = ax88172_link_reset,
+	.reset = ax88172_link_reset,
+	.flags =  FLAG_ETHER,
+	.data = 0x00130103,
+};
+
+static const struct driver_info dlink_dub_e100_info = {
+	.description = "DLink DUB-E100 USB Ethernet",
+	.bind = ax8817x_bind,
+	.status = ax8817x_status,
+	.link_reset = ax88172_link_reset,
+	.reset = ax88172_link_reset,
+	.flags =  FLAG_ETHER,
+	.data = 0x009f9d9f,
+};
+
+static const struct driver_info netgear_fa120_info = {
+	.description = "Netgear FA-120 USB Ethernet",
+	.bind = ax8817x_bind,
+	.status = ax8817x_status,
+	.link_reset = ax88172_link_reset,
+	.reset = ax88172_link_reset,
+	.flags =  FLAG_ETHER,
+	.data = 0x00130103,
+};
+
+static const struct driver_info hawking_uf200_info = {
+	.description = "Hawking UF200 USB Ethernet",
+	.bind = ax8817x_bind,
+	.status = ax8817x_status,
+	.link_reset = ax88172_link_reset,
+	.reset = ax88172_link_reset,
+	.flags =  FLAG_ETHER,
+	.data = 0x001f1d1f,
+};
+
+static const struct driver_info ax88772_info = {
+	.description = "ASIX AX88772 USB 2.0 Ethernet",
+	.bind = ax88772_bind,
+	.status = ax8817x_status,
+	.link_reset = ax88772_link_reset,
+	.reset = ax88772_link_reset,
+	.flags = FLAG_ETHER | FLAG_FRAMING_AX,
+	.rx_fixup = ax88772_rx_fixup,
+	.tx_fixup = ax88772_tx_fixup,
+	.data = 0x00130103,
+};
+
+static const struct usb_device_id	products [] = {
+{
+	// Linksys USB200M
+	USB_DEVICE (0x077b, 0x2226),
+	.driver_info =	(unsigned long) &ax8817x_info,
+}, {
+	// Netgear FA120
+	USB_DEVICE (0x0846, 0x1040),
+	.driver_info =  (unsigned long) &netgear_fa120_info,
+}, {
+	// DLink DUB-E100
+	USB_DEVICE (0x2001, 0x1a00),
+	.driver_info =  (unsigned long) &dlink_dub_e100_info,
+}, {
+	// Intellinet, ST Lab USB Ethernet
+	USB_DEVICE (0x0b95, 0x1720),
+	.driver_info =  (unsigned long) &ax8817x_info,
+}, {
+	// Hawking UF200, TrendNet TU2-ET100
+	USB_DEVICE (0x07b8, 0x420a),
+	.driver_info =  (unsigned long) &hawking_uf200_info,
+}, {
+        // Billionton Systems, USB2AR
+        USB_DEVICE (0x08dd, 0x90ff),
+        .driver_info =  (unsigned long) &ax8817x_info,
+}, {
+	// ATEN UC210T
+	USB_DEVICE (0x0557, 0x2009),
+	.driver_info =  (unsigned long) &ax8817x_info,
+}, {
+	// Buffalo LUA-U2-KTX
+	USB_DEVICE (0x0411, 0x003d),
+	.driver_info =  (unsigned long) &ax8817x_info,
+}, {
+	// Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter"
+	USB_DEVICE (0x6189, 0x182d),
+	.driver_info =  (unsigned long) &ax8817x_info,
+}, {
+	// corega FEther USB2-TX
+	USB_DEVICE (0x07aa, 0x0017),
+	.driver_info =  (unsigned long) &ax8817x_info,
+}, {
+	// Surecom EP-1427X-2
+	USB_DEVICE (0x1189, 0x0893),
+	.driver_info = (unsigned long) &ax8817x_info,
+}, {
+	// goodway corp usb gwusb2e
+	USB_DEVICE (0x1631, 0x6200),
+	.driver_info = (unsigned long) &ax8817x_info,
+}, {
+	// ASIX AX88772 10/100
+        USB_DEVICE (0x0b95, 0x7720),
+        .driver_info = (unsigned long) &ax88772_info,
+},
+	{ },		// END
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver asix_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"asix",
+	.id_table =	products,
+	.probe =	usbnet_probe,
+	.suspend =	usbnet_suspend,
+	.resume =	usbnet_resume,
+	.disconnect =	usbnet_disconnect,
+};
+
+static int __init asix_init(void)
+{
+ 	return usb_register(&asix_driver);
+}
+module_init(asix_init);
+
+static void __exit asix_exit(void)
+{
+ 	usb_deregister(&asix_driver);
+}
+module_exit(asix_exit);
+
+MODULE_AUTHOR("David Hollis");
+MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices");
+MODULE_LICENSE("GPL");
+

+ 0 - 2
drivers/usb/net/catc.c

@@ -383,7 +383,6 @@ static void catc_tx_done(struct urb *urb, struct pt_regs *regs)
 
 	if (urb->status == -ECONNRESET) {
 		dbg("Tx Reset.");
-		urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 		urb->status = 0;
 		catc->netdev->trans_start = jiffies;
 		catc->stats.tx_errors++;
@@ -445,7 +444,6 @@ static void catc_tx_timeout(struct net_device *netdev)
 	struct catc *catc = netdev_priv(netdev);
 
 	warn("Transmit timed out.");
-	catc->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 	usb_unlink_urb(catc->tx_urb);
 }
 

+ 509 - 0
drivers/usb/net/cdc_ether.c

@@ -0,0 +1,509 @@
+/*
+ * CDC Ethernet based networking peripherals
+ * Copyright (C) 2003-2005 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// #define	DEBUG			// error path messages, extra info
+// #define	VERBOSE			// more; success messages
+
+#include <linux/config.h>
+#ifdef	CONFIG_USB_DEBUG
+#   define DEBUG
+#endif
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ctype.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb_cdc.h>
+
+#include "usbnet.h"
+
+
+/*
+ * probes control interface, claims data interface, collects the bulk
+ * endpoints, activates data interface (if needed), maybe sets MTU.
+ * all pure cdc, except for certain firmware workarounds, and knowing
+ * that rndis uses one different rule.
+ */
+int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	u8				*buf = intf->cur_altsetting->extra;
+	int				len = intf->cur_altsetting->extralen;
+	struct usb_interface_descriptor	*d;
+	struct cdc_state		*info = (void *) &dev->data;
+	int				status;
+	int				rndis;
+	struct usb_driver		*driver = driver_of(intf);
+
+	if (sizeof dev->data < sizeof *info)
+		return -EDOM;
+
+	/* expect strict spec conformance for the descriptors, but
+	 * cope with firmware which stores them in the wrong place
+	 */
+	if (len == 0 && dev->udev->actconfig->extralen) {
+		/* Motorola SB4100 (and others: Brad Hards says it's
+		 * from a Broadcom design) put CDC descriptors here
+		 */
+		buf = dev->udev->actconfig->extra;
+		len = dev->udev->actconfig->extralen;
+		if (len)
+			dev_dbg(&intf->dev,
+				"CDC descriptors on config\n");
+	}
+
+	/* this assumes that if there's a non-RNDIS vendor variant
+	 * of cdc-acm, it'll fail RNDIS requests cleanly.
+	 */
+	rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
+
+	memset(info, 0, sizeof *info);
+	info->control = intf;
+	while (len > 3) {
+		if (buf [1] != USB_DT_CS_INTERFACE)
+			goto next_desc;
+
+		/* use bDescriptorSubType to identify the CDC descriptors.
+		 * We expect devices with CDC header and union descriptors.
+		 * For CDC Ethernet we need the ethernet descriptor.
+		 * For RNDIS, ignore two (pointless) CDC modem descriptors
+		 * in favor of a complicated OID-based RPC scheme doing what
+		 * CDC Ethernet achieves with a simple descriptor.
+		 */
+		switch (buf [2]) {
+		case USB_CDC_HEADER_TYPE:
+			if (info->header) {
+				dev_dbg(&intf->dev, "extra CDC header\n");
+				goto bad_desc;
+			}
+			info->header = (void *) buf;
+			if (info->header->bLength != sizeof *info->header) {
+				dev_dbg(&intf->dev, "CDC header len %u\n",
+					info->header->bLength);
+				goto bad_desc;
+			}
+			break;
+		case USB_CDC_UNION_TYPE:
+			if (info->u) {
+				dev_dbg(&intf->dev, "extra CDC union\n");
+				goto bad_desc;
+			}
+			info->u = (void *) buf;
+			if (info->u->bLength != sizeof *info->u) {
+				dev_dbg(&intf->dev, "CDC union len %u\n",
+					info->u->bLength);
+				goto bad_desc;
+			}
+
+			/* we need a master/control interface (what we're
+			 * probed with) and a slave/data interface; union
+			 * descriptors sort this all out.
+			 */
+			info->control = usb_ifnum_to_if(dev->udev,
+						info->u->bMasterInterface0);
+			info->data = usb_ifnum_to_if(dev->udev,
+						info->u->bSlaveInterface0);
+			if (!info->control || !info->data) {
+				dev_dbg(&intf->dev,
+					"master #%u/%p slave #%u/%p\n",
+					info->u->bMasterInterface0,
+					info->control,
+					info->u->bSlaveInterface0,
+					info->data);
+				goto bad_desc;
+			}
+			if (info->control != intf) {
+				dev_dbg(&intf->dev, "bogus CDC Union\n");
+				/* Ambit USB Cable Modem (and maybe others)
+				 * interchanges master and slave interface.
+				 */
+				if (info->data == intf) {
+					info->data = info->control;
+					info->control = intf;
+				} else
+					goto bad_desc;
+			}
+
+			/* a data interface altsetting does the real i/o */
+			d = &info->data->cur_altsetting->desc;
+			if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
+				dev_dbg(&intf->dev, "slave class %u\n",
+					d->bInterfaceClass);
+				goto bad_desc;
+			}
+			break;
+		case USB_CDC_ETHERNET_TYPE:
+			if (info->ether) {
+				dev_dbg(&intf->dev, "extra CDC ether\n");
+				goto bad_desc;
+			}
+			info->ether = (void *) buf;
+			if (info->ether->bLength != sizeof *info->ether) {
+				dev_dbg(&intf->dev, "CDC ether len %u\n",
+					info->ether->bLength);
+				goto bad_desc;
+			}
+			dev->hard_mtu = le16_to_cpu(
+						info->ether->wMaxSegmentSize);
+			/* because of Zaurus, we may be ignoring the host
+			 * side link address we were given.
+			 */
+			break;
+		}
+next_desc:
+		len -= buf [0];	/* bLength */
+		buf += buf [0];
+	}
+
+	if (!info->header || !info->u || (!rndis && !info->ether)) {
+		dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
+			info->header ? "" : "header ",
+			info->u ? "" : "union ",
+			info->ether ? "" : "ether ");
+		goto bad_desc;
+	}
+
+	/* claim data interface and set it up ... with side effects.
+	 * network traffic can't flow until an altsetting is enabled.
+	 */
+	status = usb_driver_claim_interface(driver, info->data, dev);
+	if (status < 0)
+		return status;
+	status = usbnet_get_endpoints(dev, info->data);
+	if (status < 0) {
+		/* ensure immediate exit from usbnet_disconnect */
+		usb_set_intfdata(info->data, NULL);
+		usb_driver_release_interface(driver, info->data);
+		return status;
+	}
+
+	/* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */
+	dev->status = NULL;
+	if (info->control->cur_altsetting->desc.bNumEndpoints == 1) {
+		struct usb_endpoint_descriptor	*desc;
+
+		dev->status = &info->control->cur_altsetting->endpoint [0];
+		desc = &dev->status->desc;
+		if (desc->bmAttributes != USB_ENDPOINT_XFER_INT
+				|| !(desc->bEndpointAddress & USB_DIR_IN)
+				|| (le16_to_cpu(desc->wMaxPacketSize)
+					< sizeof(struct usb_cdc_notification))
+				|| !desc->bInterval) {
+			dev_dbg(&intf->dev, "bad notification endpoint\n");
+			dev->status = NULL;
+		}
+	}
+	if (rndis && !dev->status) {
+		dev_dbg(&intf->dev, "missing RNDIS status endpoint\n");
+		usb_set_intfdata(info->data, NULL);
+		usb_driver_release_interface(driver, info->data);
+		return -ENODEV;
+	}
+	return 0;
+
+bad_desc:
+	dev_info(&dev->udev->dev, "bad CDC descriptors\n");
+	return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind);
+
+void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+	struct cdc_state		*info = (void *) &dev->data;
+	struct usb_driver		*driver = driver_of(intf);
+
+	/* disconnect master --> disconnect slave */
+	if (intf == info->control && info->data) {
+		/* ensure immediate exit from usbnet_disconnect */
+		usb_set_intfdata(info->data, NULL);
+		usb_driver_release_interface(driver, info->data);
+		info->data = NULL;
+	}
+
+	/* and vice versa (just in case) */
+	else if (intf == info->data && info->control) {
+		/* ensure immediate exit from usbnet_disconnect */
+		usb_set_intfdata(info->control, NULL);
+		usb_driver_release_interface(driver, info->control);
+		info->control = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Communications Device Class, Ethernet Control model
+ *
+ * Takes two interfaces.  The DATA interface is inactive till an altsetting
+ * is selected.  Configuration data includes class descriptors.  There's
+ * an optional status endpoint on the control interface.
+ *
+ * This should interop with whatever the 2.4 "CDCEther.c" driver
+ * (by Brad Hards) talked with, with more functionality.
+ *
+ *-------------------------------------------------------------------------*/
+
+static void dumpspeed(struct usbnet *dev, __le32 *speeds)
+{
+	if (netif_msg_timer(dev))
+		devinfo(dev, "link speeds: %u kbps up, %u kbps down",
+			__le32_to_cpu(speeds[0]) / 1000,
+		__le32_to_cpu(speeds[1]) / 1000);
+}
+
+static void cdc_status(struct usbnet *dev, struct urb *urb)
+{
+	struct usb_cdc_notification	*event;
+
+	if (urb->actual_length < sizeof *event)
+		return;
+
+	/* SPEED_CHANGE can get split into two 8-byte packets */
+	if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
+		dumpspeed(dev, (__le32 *) urb->transfer_buffer);
+		return;
+	}
+
+	event = urb->transfer_buffer;
+	switch (event->bNotificationType) {
+	case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+		if (netif_msg_timer(dev))
+			devdbg(dev, "CDC: carrier %s",
+					event->wValue ? "on" : "off");
+		if (event->wValue)
+			netif_carrier_on(dev->net);
+		else
+			netif_carrier_off(dev->net);
+		break;
+	case USB_CDC_NOTIFY_SPEED_CHANGE:	/* tx/rx rates */
+		if (netif_msg_timer(dev))
+			devdbg(dev, "CDC: speed change (len %d)",
+					urb->actual_length);
+		if (urb->actual_length != (sizeof *event + 8))
+			set_bit(EVENT_STS_SPLIT, &dev->flags);
+		else
+			dumpspeed(dev, (__le32 *) &event[1]);
+		break;
+	/* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS),
+	 * but there are no standard formats for the response data.
+	 */
+	default:
+		deverr(dev, "CDC: unexpected notification %02x!",
+				 event->bNotificationType);
+		break;
+	}
+}
+
+static u8 nibble(unsigned char c)
+{
+	if (likely(isdigit(c)))
+		return c - '0';
+	c = toupper(c);
+	if (likely(isxdigit(c)))
+		return 10 + c - 'A';
+	return 0;
+}
+
+static inline int
+get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e)
+{
+	int 		tmp, i;
+	unsigned char	buf [13];
+
+	tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf);
+	if (tmp != 12) {
+		dev_dbg(&dev->udev->dev,
+			"bad MAC string %d fetch, %d\n", e->iMACAddress, tmp);
+		if (tmp >= 0)
+			tmp = -EINVAL;
+		return tmp;
+	}
+	for (i = tmp = 0; i < 6; i++, tmp += 2)
+		dev->net->dev_addr [i] =
+			(nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]);
+	return 0;
+}
+
+static int cdc_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int				status;
+	struct cdc_state		*info = (void *) &dev->data;
+
+	status = usbnet_generic_cdc_bind(dev, intf);
+	if (status < 0)
+		return status;
+
+	status = get_ethernet_addr(dev, info->ether);
+	if (status < 0) {
+		usb_set_intfdata(info->data, NULL);
+		usb_driver_release_interface(driver_of(intf), info->data);
+		return status;
+	}
+
+	/* FIXME cdc-ether has some multicast code too, though it complains
+	 * in routine cases.  info->ether describes the multicast support.
+	 * Implement that here, manipulating the cdc filter as needed.
+	 */
+	return 0;
+}
+
+static const struct driver_info	cdc_info = {
+	.description =	"CDC Ethernet Device",
+	.flags =	FLAG_ETHER,
+	// .check_connect = cdc_check_connect,
+	.bind =		cdc_bind,
+	.unbind =	usbnet_cdc_unbind,
+	.status =	cdc_status,
+};
+
+/*-------------------------------------------------------------------------*/
+
+
+static const struct usb_device_id	products [] = {
+/*
+ * BLACKLIST !!
+ *
+ * First blacklist any products that are egregiously nonconformant
+ * with the CDC Ethernet specs.  Minor braindamage we cope with; when
+ * they're not even trying, needing a separate driver is only the first
+ * of the differences to show up.
+ */
+
+#define	ZAURUS_MASTER_INTERFACE \
+	.bInterfaceClass	= USB_CLASS_COMM, \
+	.bInterfaceSubClass	= USB_CDC_SUBCLASS_ETHERNET, \
+	.bInterfaceProtocol	= USB_CDC_PROTO_NONE
+
+/* SA-1100 based Sharp Zaurus ("collie"), or compatible;
+ * wire-incompatible with true CDC Ethernet implementations.
+ * (And, it seems, needlessly so...)
+ */
+{
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8004,
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info		= 0,
+},
+
+/* PXA-25x based Sharp Zaurii.  Note that it seems some of these
+ * (later models especially) may have shipped only with firmware
+ * advertising false "CDC MDLM" compatibility ... but we're not
+ * clear which models did that, so for now let's assume the worst.
+ */
+{
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8005,	/* A-300 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info		= 0,
+}, {
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8006,	/* B-500/SL-5600 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info		= 0,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+	          | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8007,	/* C-700 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info		= 0,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+		 | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor               = 0x04DD,
+	.idProduct              = 0x9031,	/* C-750 C-760 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info		= 0,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+		 | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor               = 0x04DD,
+	.idProduct              = 0x9032,	/* SL-6000 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info		= 0,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+		 | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor               = 0x04DD,
+	/* reported with some C860 units */
+	.idProduct              = 0x9050,	/* C-860 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info		= 0,
+},
+
+/*
+ * WHITELIST!!!
+ *
+ * CDC Ether uses two interfaces, not necessarily consecutive.
+ * We match the main interface, ignoring the optional device
+ * class so we could handle devices that aren't exclusively
+ * CDC ether.
+ *
+ * NOTE:  this match must come AFTER entries blacklisting devices
+ * because of bugs/quirks in a given product (like Zaurus, above).
+ */
+{
+	USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
+			USB_CDC_PROTO_NONE),
+	.driver_info = (unsigned long) &cdc_info,
+},
+	{ },		// END
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver cdc_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"cdc_ether",
+	.id_table =	products,
+	.probe =	usbnet_probe,
+	.disconnect =	usbnet_disconnect,
+	.suspend =	usbnet_suspend,
+	.resume =	usbnet_resume,
+};
+
+
+static int __init cdc_init(void)
+{
+	BUG_ON((sizeof(((struct usbnet *)0)->data)
+			< sizeof(struct cdc_state)));
+
+ 	return usb_register(&cdc_driver);
+}
+module_init(cdc_init);
+
+static void __exit cdc_exit(void)
+{
+ 	usb_deregister(&cdc_driver);
+}
+module_exit(cdc_exit);
+
+MODULE_AUTHOR("David Brownell");
+MODULE_DESCRIPTION("USB CDC Ethernet devices");
+MODULE_LICENSE("GPL");

+ 335 - 0
drivers/usb/net/cdc_subset.c

@@ -0,0 +1,335 @@
+/*
+ * Simple "CDC Subset" USB Networking Links
+ * Copyright (C) 2000-2005 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/config.h>
+#ifdef	CONFIG_USB_DEBUG
+#   define DEBUG
+#endif
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+
+#include "usbnet.h"
+
+
+/*
+ * This supports simple USB network links that don't require any special
+ * framing or hardware control operations.  The protocol used here is a
+ * strict subset of CDC Ethernet, with three basic differences reflecting
+ * the goal that almost any hardware should run it:
+ *
+ *  - Minimal runtime control:  one interface, no altsettings, and
+ *    no vendor or class specific control requests.  If a device is
+ *    configured, it is allowed to exchange packets with the host.
+ *    Fancier models would mean not working on some hardware.
+ *
+ *  - Minimal manufacturing control:  no IEEE "Organizationally
+ *    Unique ID" required, or an EEPROMs to store one.  Each host uses
+ *    one random "locally assigned" Ethernet address instead, which can
+ *    of course be overridden using standard tools like "ifconfig".
+ *    (With 2^46 such addresses, same-net collisions are quite rare.)
+ *
+ *  - There is no additional framing data for USB.  Packets are written
+ *    exactly as in CDC Ethernet, starting with an Ethernet header and
+ *    terminated by a short packet.  However, the host will never send a
+ *    zero length packet; some systems can't handle those robustly.
+ *
+ * Anything that can transmit and receive USB bulk packets can implement
+ * this protocol.  That includes both smart peripherals and quite a lot
+ * of "host-to-host" USB cables (which embed two devices back-to-back).
+ *
+ * Note that although Linux may use many of those host-to-host links
+ * with this "cdc_subset" framing, that doesn't mean there may not be a
+ * better approach.  Handling the "other end unplugs/replugs" scenario
+ * well tends to require chip-specific vendor requests.  Also, Windows
+ * peers at the other end of host-to-host cables may expect their own
+ * framing to be used rather than this "cdc_subset" model.
+ */
+
+#if defined(CONFIG_USB_EPSON2888) || defined(CONFIG_USB_ARMLINUX)
+/* PDA style devices are always connected if present */
+static int always_connected (struct usbnet *dev)
+{
+	return 0;
+}
+#endif
+
+#ifdef	CONFIG_USB_ALI_M5632
+#define	HAVE_HARDWARE
+
+/*-------------------------------------------------------------------------
+ *
+ * ALi M5632 driver ... does high speed
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	ali_m5632_info = {
+	.description =	"ALi M5632",
+};
+
+
+#endif
+
+
+#ifdef	CONFIG_USB_AN2720
+#define	HAVE_HARDWARE
+
+/*-------------------------------------------------------------------------
+ *
+ * AnchorChips 2720 driver ... http://www.cypress.com
+ *
+ * This doesn't seem to have a way to detect whether the peer is
+ * connected, or need any reset handshaking.  It's got pretty big
+ * internal buffers (handles most of a frame's worth of data).
+ * Chip data sheets don't describe any vendor control messages.
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	an2720_info = {
+	.description =	"AnchorChips/Cypress 2720",
+	// no reset available!
+	// no check_connect available!
+
+	.in = 2, .out = 2,		// direction distinguishes these
+};
+
+#endif	/* CONFIG_USB_AN2720 */
+
+
+#ifdef	CONFIG_USB_BELKIN
+#define	HAVE_HARDWARE
+
+/*-------------------------------------------------------------------------
+ *
+ * Belkin F5U104 ... two NetChip 2280 devices + Atmel AVR microcontroller
+ *
+ * ... also two eTEK designs, including one sold as "Advance USBNET"
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	belkin_info = {
+	.description =	"Belkin, eTEK, or compatible",
+};
+
+#endif	/* CONFIG_USB_BELKIN */
+
+
+
+#ifdef	CONFIG_USB_EPSON2888
+#define	HAVE_HARDWARE
+
+/*-------------------------------------------------------------------------
+ *
+ * EPSON USB clients
+ *
+ * This is the same idea as Linux PDAs (below) except the firmware in the
+ * device might not be Tux-powered.  Epson provides reference firmware that
+ * implements this interface.  Product developers can reuse or modify that
+ * code, such as by using their own product and vendor codes.
+ *
+ * Support was from Juro Bystricky <bystricky.juro@erd.epson.com>
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	epson2888_info = {
+	.description =	"Epson USB Device",
+	.check_connect = always_connected,
+
+	.in = 4, .out = 3,
+};
+
+#endif	/* CONFIG_USB_EPSON2888 */
+
+
+#ifdef CONFIG_USB_KC2190
+#define HAVE_HARDWARE
+static const struct driver_info kc2190_info = {
+	.description =  "KC Technology KC-190",
+};
+#endif /* CONFIG_USB_KC2190 */
+
+
+#ifdef	CONFIG_USB_ARMLINUX
+#define	HAVE_HARDWARE
+
+/*-------------------------------------------------------------------------
+ *
+ * Intel's SA-1100 chip integrates basic USB support, and is used
+ * in PDAs like some iPaqs, the Yopy, some Zaurus models, and more.
+ * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to
+ * network using minimal USB framing data.
+ *
+ * This describes the driver currently in standard ARM Linux kernels.
+ * The Zaurus uses a different driver (see later).
+ *
+ * PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support
+ * and different USB endpoint numbering than the SA1100 devices.  The
+ * mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100
+ * so we rely on the endpoint descriptors.
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	linuxdev_info = {
+	.description =	"Linux Device",
+	.check_connect = always_connected,
+};
+
+static const struct driver_info	yopy_info = {
+	.description =	"Yopy",
+	.check_connect = always_connected,
+};
+
+static const struct driver_info	blob_info = {
+	.description =	"Boot Loader OBject",
+	.check_connect = always_connected,
+};
+
+#endif	/* CONFIG_USB_ARMLINUX */
+
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef	HAVE_HARDWARE
+#error You need to configure some hardware for this driver
+#endif
+
+/*
+ * chip vendor names won't normally be on the cables, and
+ * may not be on the device.
+ */
+
+static const struct usb_device_id	products [] = {
+
+#ifdef	CONFIG_USB_ALI_M5632
+{
+	USB_DEVICE (0x0402, 0x5632),	// ALi defaults
+	.driver_info =	(unsigned long) &ali_m5632_info,
+},
+#endif
+
+#ifdef	CONFIG_USB_AN2720
+{
+	USB_DEVICE (0x0547, 0x2720),	// AnchorChips defaults
+	.driver_info =	(unsigned long) &an2720_info,
+}, {
+	USB_DEVICE (0x0547, 0x2727),	// Xircom PGUNET
+	.driver_info =	(unsigned long) &an2720_info,
+},
+#endif
+
+#ifdef	CONFIG_USB_BELKIN
+{
+	USB_DEVICE (0x050d, 0x0004),	// Belkin
+	.driver_info =	(unsigned long) &belkin_info,
+}, {
+	USB_DEVICE (0x056c, 0x8100),	// eTEK
+	.driver_info =	(unsigned long) &belkin_info,
+}, {
+	USB_DEVICE (0x0525, 0x9901),	// Advance USBNET (eTEK)
+	.driver_info =	(unsigned long) &belkin_info,
+},
+#endif
+
+#ifdef	CONFIG_USB_EPSON2888
+{
+	USB_DEVICE (0x0525, 0x2888),	// EPSON USB client
+	.driver_info	= (unsigned long) &epson2888_info,
+},
+#endif
+
+#ifdef CONFIG_USB_KC2190
+{
+	USB_DEVICE (0x050f, 0x0190),	// KC-190
+	.driver_info =	(unsigned long) &kc2190_info,
+},
+#endif
+
+#ifdef	CONFIG_USB_ARMLINUX
+/*
+ * SA-1100 using standard ARM Linux kernels, or compatible.
+ * Often used when talking to Linux PDAs (iPaq, Yopy, etc).
+ * The sa-1100 "usb-eth" driver handles the basic framing.
+ *
+ * PXA25x or PXA210 ...  these use a "usb-eth" driver much like
+ * the sa1100 one, but hardware uses different endpoint numbers.
+ *
+ * Or the Linux "Ethernet" gadget on hardware that can't talk
+ * CDC Ethernet (e.g., no altsettings), in either of two modes:
+ *  - acting just like the old "usb-eth" firmware, though
+ *    the implementation is different
+ *  - supporting RNDIS as the first/default configuration for
+ *    MS-Windows interop; Linux needs to use the other config
+ */
+{
+	// 1183 = 0x049F, both used as hex values?
+	// Compaq "Itsy" vendor/product id
+	USB_DEVICE (0x049F, 0x505A),	// usb-eth, or compatible
+	.driver_info =	(unsigned long) &linuxdev_info,
+}, {
+	USB_DEVICE (0x0E7E, 0x1001),	// G.Mate "Yopy"
+	.driver_info =	(unsigned long) &yopy_info,
+}, {
+	USB_DEVICE (0x8086, 0x07d3),	// "blob" bootloader
+	.driver_info =	(unsigned long) &blob_info,
+}, {
+	// Linux Ethernet/RNDIS gadget on pxa210/25x/26x, second config
+	// e.g. Gumstix, current OpenZaurus, ...
+	USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203),
+	.driver_info =	(unsigned long) &linuxdev_info,
+},
+#endif
+
+	{ },		// END
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_driver cdc_subset_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"cdc_subset",
+	.probe =	usbnet_probe,
+	.suspend =	usbnet_suspend,
+	.resume =	usbnet_resume,
+	.disconnect =	usbnet_disconnect,
+	.id_table =	products,
+};
+
+static int __init cdc_subset_init(void)
+{
+ 	return usb_register(&cdc_subset_driver);
+}
+module_init(cdc_subset_init);
+
+static void __exit cdc_subset_exit(void)
+{
+ 	usb_deregister(&cdc_subset_driver);
+}
+module_exit(cdc_subset_exit);
+
+MODULE_AUTHOR("David Brownell");
+MODULE_DESCRIPTION("Simple 'CDC Subset' USB networking links");
+MODULE_LICENSE("GPL");

+ 407 - 0
drivers/usb/net/gl620a.c

@@ -0,0 +1,407 @@
+/*
+ * GeneSys GL620USB-A based links
+ * Copyright (C) 2001 by Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
+ * Copyright (C) 2001 by Stanislav Brabec <utx@penguin.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// #define	DEBUG			// error path messages, extra info
+// #define	VERBOSE			// more; success messages
+
+#include <linux/config.h>
+#ifdef	CONFIG_USB_DEBUG
+#   define DEBUG
+#endif
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+
+#include "usbnet.h"
+
+
+/*
+ * GeneSys GL620USB-A (www.genesyslogic.com.tw)
+ *
+ * ... should partially interop with the Win32 driver for this hardware.
+ * The GeneSys docs imply there's some NDIS issue motivating this framing.
+ *
+ * Some info from GeneSys:
+ *  - GL620USB-A is full duplex; GL620USB is only half duplex for bulk.
+ *    (Some cables, like the BAFO-100c, use the half duplex version.)
+ *  - For the full duplex model, the low bit of the version code says
+ *    which side is which ("left/right").
+ *  - For the half duplex type, a control/interrupt handshake settles
+ *    the transfer direction.  (That's disabled here, partially coded.)
+ *    A control URB would block until other side writes an interrupt.
+ *
+ * Original code from Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
+ * and merged into "usbnet" by Stanislav Brabec <utx@penguin.cz>.
+ */
+
+// control msg write command
+#define GENELINK_CONNECT_WRITE			0xF0
+// interrupt pipe index
+#define GENELINK_INTERRUPT_PIPE			0x03
+// interrupt read buffer size
+#define INTERRUPT_BUFSIZE			0x08
+// interrupt pipe interval value
+#define GENELINK_INTERRUPT_INTERVAL		0x10
+// max transmit packet number per transmit
+#define GL_MAX_TRANSMIT_PACKETS			32
+// max packet length
+#define GL_MAX_PACKET_LEN			1514
+// max receive buffer size
+#define GL_RCV_BUF_SIZE		\
+	(((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
+
+struct gl_packet {
+	u32		packet_length;
+	char		packet_data [1];
+};
+
+struct gl_header {
+	u32			packet_count;
+	struct gl_packet	packets;
+};
+
+#ifdef	GENELINK_ACK
+
+// FIXME:  this code is incomplete, not debugged; it doesn't
+// handle interrupts correctly; it should use the generic
+// status IRQ code (which didn't exist back in 2001).
+
+struct gl_priv {
+	struct urb	*irq_urb;
+	char		irq_buf [INTERRUPT_BUFSIZE];
+};
+
+static inline int gl_control_write(struct usbnet *dev, u8 request, u16 value)
+{
+	int retval;
+
+	retval = usb_control_msg(dev->udev,
+		      usb_sndctrlpipe(dev->udev, 0),
+		      request,
+		      USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+		      value,
+		      0,			// index
+		      0,			// data buffer
+		      0,			// size
+		      USB_CTRL_SET_TIMEOUT);
+	return retval;
+}
+
+static void gl_interrupt_complete(struct urb *urb, struct pt_regs *regs)
+{
+	int status = urb->status;
+
+	switch (status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d",
+				__FUNCTION__, status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d",
+				__FUNCTION__, urb->status);
+	}
+
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status)
+		err("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, status);
+}
+
+static int gl_interrupt_read(struct usbnet *dev)
+{
+	struct gl_priv	*priv = dev->priv_data;
+	int		retval;
+
+	// issue usb interrupt read
+	if (priv && priv->irq_urb) {
+		// submit urb
+		if ((retval = usb_submit_urb(priv->irq_urb, GFP_KERNEL)) != 0)
+			dbg("gl_interrupt_read: submit fail - %X...", retval);
+		else
+			dbg("gl_interrupt_read: submit success...");
+	}
+
+	return 0;
+}
+
+// check whether another side is connected
+static int genelink_check_connect(struct usbnet *dev)
+{
+	int			retval;
+
+	dbg("genelink_check_connect...");
+
+	// detect whether another side is connected
+	if ((retval = gl_control_write(dev, GENELINK_CONNECT_WRITE, 0)) != 0) {
+		dbg("%s: genelink_check_connect write fail - %X",
+			dev->net->name, retval);
+		return retval;
+	}
+
+	// usb interrupt read to ack another side
+	if ((retval = gl_interrupt_read(dev)) != 0) {
+		dbg("%s: genelink_check_connect read fail - %X",
+			dev->net->name, retval);
+		return retval;
+	}
+
+	dbg("%s: genelink_check_connect read success", dev->net->name);
+	return 0;
+}
+
+// allocate and initialize the private data for genelink
+static int genelink_init(struct usbnet *dev)
+{
+	struct gl_priv *priv;
+
+	// allocate the private data structure
+	if ((priv = kmalloc(sizeof *priv, GFP_KERNEL)) == 0) {
+		dbg("%s: cannot allocate private data per device",
+			dev->net->name);
+		return -ENOMEM;
+	}
+
+	// allocate irq urb
+	if ((priv->irq_urb = usb_alloc_urb(0, GFP_KERNEL)) == 0) {
+		dbg("%s: cannot allocate private irq urb per device",
+			dev->net->name);
+		kfree(priv);
+		return -ENOMEM;
+	}
+
+	// fill irq urb
+	usb_fill_int_urb(priv->irq_urb, dev->udev,
+		usb_rcvintpipe(dev->udev, GENELINK_INTERRUPT_PIPE),
+		priv->irq_buf, INTERRUPT_BUFSIZE,
+		gl_interrupt_complete, 0,
+		GENELINK_INTERRUPT_INTERVAL);
+
+	// set private data pointer
+	dev->priv_data = priv;
+
+	return 0;
+}
+
+// release the private data
+static int genelink_free(struct usbnet *dev)
+{
+	struct gl_priv	*priv = dev->priv_data;
+
+	if (!priv)
+		return 0;
+
+// FIXME:  can't cancel here; it's synchronous, and
+// should have happened earlier in any case (interrupt
+// handling needs to be generic)
+
+	// cancel irq urb first
+	usb_kill_urb(priv->irq_urb);
+
+	// free irq urb
+	usb_free_urb(priv->irq_urb);
+
+	// free the private data structure
+	kfree(priv);
+
+	return 0;
+}
+
+#endif
+
+static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	struct gl_header	*header;
+	struct gl_packet	*packet;
+	struct sk_buff		*gl_skb;
+	u32			size;
+
+	header = (struct gl_header *) skb->data;
+
+	// get the packet count of the received skb
+	le32_to_cpus(&header->packet_count);
+	if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS)
+			|| (header->packet_count < 0)) {
+		dbg("genelink: invalid received packet count %d",
+			header->packet_count);
+		return 0;
+	}
+
+	// set the current packet pointer to the first packet
+	packet = &header->packets;
+
+	// decrement the length for the packet count size 4 bytes
+	skb_pull(skb, 4);
+
+	while (header->packet_count > 1) {
+		// get the packet length
+		size = le32_to_cpu(packet->packet_length);
+
+		// this may be a broken packet
+		if (size > GL_MAX_PACKET_LEN) {
+			dbg("genelink: invalid rx length %d", size);
+			return 0;
+		}
+
+		// allocate the skb for the individual packet
+		gl_skb = alloc_skb(size, GFP_ATOMIC);
+		if (gl_skb) {
+
+			// copy the packet data to the new skb
+			memcpy(skb_put(gl_skb, size),
+					packet->packet_data, size);
+			usbnet_skb_return(dev, gl_skb);
+		}
+
+		// advance to the next packet
+		packet = (struct gl_packet *)
+			&packet->packet_data [size];
+		header->packet_count--;
+
+		// shift the data pointer to the next gl_packet
+		skb_pull(skb, size + 4);
+	}
+
+	// skip the packet length field 4 bytes
+	skb_pull(skb, 4);
+
+	if (skb->len > GL_MAX_PACKET_LEN) {
+		dbg("genelink: invalid rx length %d", skb->len);
+		return 0;
+	}
+	return 1;
+}
+
+static struct sk_buff *
+genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags)
+{
+	int 	padlen;
+	int	length = skb->len;
+	int	headroom = skb_headroom(skb);
+	int	tailroom = skb_tailroom(skb);
+	u32	*packet_count;
+	u32	*packet_len;
+
+	// FIXME:  magic numbers, bleech
+	padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
+
+	if ((!skb_cloned(skb))
+			&& ((headroom + tailroom) >= (padlen + (4 + 4*1)))) {
+		if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
+			skb->data = memmove(skb->head + (4 + 4*1),
+					     skb->data, skb->len);
+			skb->tail = skb->data + skb->len;
+		}
+	} else {
+		struct sk_buff	*skb2;
+		skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	// attach the packet count to the header
+	packet_count = (u32 *) skb_push(skb, (4 + 4*1));
+	packet_len = packet_count + 1;
+
+	*packet_count = cpu_to_le32(1);
+	*packet_len = cpu_to_le32(length);
+
+	// add padding byte
+	if ((skb->len % dev->maxpacket) == 0)
+		skb_put(skb, 1);
+
+	return skb;
+}
+
+static int genelink_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	dev->hard_mtu = GL_RCV_BUF_SIZE;
+	dev->net->hard_header_len += 4;
+	dev->in = usb_rcvbulkpipe(dev->udev, dev->driver_info->in);
+	dev->out = usb_sndbulkpipe(dev->udev, dev->driver_info->out);
+	return 0;
+}
+
+static const struct driver_info	genelink_info = {
+	.description =	"Genesys GeneLink",
+	.flags =	FLAG_FRAMING_GL | FLAG_NO_SETINT,
+	.bind =		genelink_bind,
+	.rx_fixup =	genelink_rx_fixup,
+	.tx_fixup =	genelink_tx_fixup,
+
+	.in = 1, .out = 2,
+
+#ifdef	GENELINK_ACK
+	.check_connect =genelink_check_connect,
+#endif
+};
+
+static const struct usb_device_id	products [] = {
+
+{
+	USB_DEVICE(0x05e3, 0x0502),	// GL620USB-A
+	.driver_info =	(unsigned long) &genelink_info,
+},
+	/* NOT: USB_DEVICE(0x05e3, 0x0501),	// GL620USB
+	 * that's half duplex, not currently supported
+	 */
+	{ },		// END
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver gl620a_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"gl620a",
+	.id_table =	products,
+	.probe =	usbnet_probe,
+	.disconnect =	usbnet_disconnect,
+	.suspend =	usbnet_suspend,
+	.resume =	usbnet_resume,
+};
+
+static int __init usbnet_init(void)
+{
+ 	return usb_register(&gl620a_driver);
+}
+module_init(usbnet_init);
+
+static void __exit usbnet_exit(void)
+{
+ 	usb_deregister(&gl620a_driver);
+}
+module_exit(usbnet_exit);
+
+MODULE_AUTHOR("Jiun-Jie Huang");
+MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables");
+MODULE_LICENSE("GPL");
+

+ 0 - 1
drivers/usb/net/kaweth.c

@@ -787,7 +787,6 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
 		      kaweth_usb_transmit_complete,
 		      kaweth);
 	kaweth->end = 0;
-	kaweth->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 
 	if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
 	{

+ 622 - 0
drivers/usb/net/net1080.c

@@ -0,0 +1,622 @@
+/*
+ * Net1080 based USB host-to-host cables
+ * Copyright (C) 2000-2005 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// #define	DEBUG			// error path messages, extra info
+// #define	VERBOSE			// more; success messages
+
+#include <linux/config.h>
+#ifdef	CONFIG_USB_DEBUG
+#   define DEBUG
+#endif
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+
+#include <asm/unaligned.h>
+
+#include "usbnet.h"
+
+
+/*
+ * Netchip 1080 driver ... http://www.netchip.com
+ * (Sept 2004:  End-of-life announcement has been sent.)
+ * Used in (some) LapLink cables
+ */
+
+#define frame_errors	data[1]
+
+/*
+ * NetChip framing of ethernet packets, supporting additional error
+ * checks for links that may drop bulk packets from inside messages.
+ * Odd USB length == always short read for last usb packet.
+ *	- nc_header
+ *	- Ethernet header (14 bytes)
+ *	- payload
+ *	- (optional padding byte, if needed so length becomes odd)
+ *	- nc_trailer
+ *
+ * This framing is to be avoided for non-NetChip devices.
+ */
+
+struct nc_header {		// packed:
+	__le16	hdr_len;		// sizeof nc_header (LE, all)
+	__le16	packet_len;		// payload size (including ethhdr)
+	__le16	packet_id;		// detects dropped packets
+#define MIN_HEADER	6
+
+	// all else is optional, and must start with:
+	// __le16	vendorId;	// from usb-if
+	// __le16	productId;
+} __attribute__((__packed__));
+
+#define	PAD_BYTE	((unsigned char)0xAC)
+
+struct nc_trailer {
+	__le16	packet_id;
+} __attribute__((__packed__));
+
+// packets may use FLAG_FRAMING_NC and optional pad
+#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
+				+ sizeof (struct ethhdr) \
+				+ (mtu) \
+				+ 1 \
+				+ sizeof (struct nc_trailer))
+
+#define MIN_FRAMED	FRAMED_SIZE(0)
+
+/* packets _could_ be up to 64KB... */
+#define NC_MAX_PACKET	32767
+
+
+/*
+ * Zero means no timeout; else, how long a 64 byte bulk packet may be queued
+ * before the hardware drops it.  If that's done, the driver will need to
+ * frame network packets to guard against the dropped USB packets.  The win32
+ * driver sets this for both sides of the link.
+ */
+#define	NC_READ_TTL_MS	((u8)255)	// ms
+
+/*
+ * We ignore most registers and EEPROM contents.
+ */
+#define	REG_USBCTL	((u8)0x04)
+#define REG_TTL		((u8)0x10)
+#define REG_STATUS	((u8)0x11)
+
+/*
+ * Vendor specific requests to read/write data
+ */
+#define	REQUEST_REGISTER	((u8)0x10)
+#define	REQUEST_EEPROM		((u8)0x11)
+
+static int
+nc_vendor_read(struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr)
+{
+	int status = usb_control_msg(dev->udev,
+		usb_rcvctrlpipe(dev->udev, 0),
+		req,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		0, regnum,
+		retval_ptr, sizeof *retval_ptr,
+		USB_CTRL_GET_TIMEOUT);
+	if (status > 0)
+		status = 0;
+	if (!status)
+		le16_to_cpus(retval_ptr);
+	return status;
+}
+
+static inline int
+nc_register_read(struct usbnet *dev, u8 regnum, u16 *retval_ptr)
+{
+	return nc_vendor_read(dev, REQUEST_REGISTER, regnum, retval_ptr);
+}
+
+// no retval ... can become async, usable in_interrupt()
+static void
+nc_vendor_write(struct usbnet *dev, u8 req, u8 regnum, u16 value)
+{
+	usb_control_msg(dev->udev,
+		usb_sndctrlpipe(dev->udev, 0),
+		req,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		value, regnum,
+		NULL, 0,			// data is in setup packet
+		USB_CTRL_SET_TIMEOUT);
+}
+
+static inline void
+nc_register_write(struct usbnet *dev, u8 regnum, u16 value)
+{
+	nc_vendor_write(dev, REQUEST_REGISTER, regnum, value);
+}
+
+
+#if 0
+static void nc_dump_registers(struct usbnet *dev)
+{
+	u8	reg;
+	u16	*vp = kmalloc(sizeof (u16));
+
+	if (!vp) {
+		dbg("no memory?");
+		return;
+	}
+
+	dbg("%s registers:", dev->net->name);
+	for (reg = 0; reg < 0x20; reg++) {
+		int retval;
+
+		// reading some registers is trouble
+		if (reg >= 0x08 && reg <= 0xf)
+			continue;
+		if (reg >= 0x12 && reg <= 0x1e)
+			continue;
+
+		retval = nc_register_read(dev, reg, vp);
+		if (retval < 0)
+			dbg("%s reg [0x%x] ==> error %d",
+				dev->net->name, reg, retval);
+		else
+			dbg("%s reg [0x%x] = 0x%x",
+				dev->net->name, reg, *vp);
+	}
+	kfree(vp);
+}
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Control register
+ */
+
+#define	USBCTL_WRITABLE_MASK	0x1f0f
+// bits 15-13 reserved, r/o
+#define	USBCTL_ENABLE_LANG	(1 << 12)
+#define	USBCTL_ENABLE_MFGR	(1 << 11)
+#define	USBCTL_ENABLE_PROD	(1 << 10)
+#define	USBCTL_ENABLE_SERIAL	(1 << 9)
+#define	USBCTL_ENABLE_DEFAULTS	(1 << 8)
+// bits 7-4 reserved, r/o
+#define	USBCTL_FLUSH_OTHER	(1 << 3)
+#define	USBCTL_FLUSH_THIS	(1 << 2)
+#define	USBCTL_DISCONN_OTHER	(1 << 1)
+#define	USBCTL_DISCONN_THIS	(1 << 0)
+
+static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl)
+{
+	if (!netif_msg_link(dev))
+		return;
+	devdbg(dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;"
+			" this%s%s;"
+			" other%s%s; r/o 0x%x",
+		dev->udev->bus->bus_name, dev->udev->devpath,
+		usbctl,
+		(usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",
+		(usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",
+		(usbctl & USBCTL_ENABLE_PROD) ? " prod" : "",
+		(usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "",
+		(usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "",
+
+		(usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "",
+		(usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "",
+		(usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "",
+		(usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "",
+		usbctl & ~USBCTL_WRITABLE_MASK
+		);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Status register
+ */
+
+#define	STATUS_PORT_A		(1 << 15)
+
+#define	STATUS_CONN_OTHER	(1 << 14)
+#define	STATUS_SUSPEND_OTHER	(1 << 13)
+#define	STATUS_MAILBOX_OTHER	(1 << 12)
+#define	STATUS_PACKETS_OTHER(n)	(((n) >> 8) && 0x03)
+
+#define	STATUS_CONN_THIS	(1 << 6)
+#define	STATUS_SUSPEND_THIS	(1 << 5)
+#define	STATUS_MAILBOX_THIS	(1 << 4)
+#define	STATUS_PACKETS_THIS(n)	(((n) >> 0) && 0x03)
+
+#define	STATUS_UNSPEC_MASK	0x0c8c
+#define	STATUS_NOISE_MASK 	((u16)~(0x0303|STATUS_UNSPEC_MASK))
+
+
+static inline void nc_dump_status(struct usbnet *dev, u16 status)
+{
+	if (!netif_msg_link(dev))
+		return;
+	devdbg(dev, "net1080 %s-%s status 0x%x:"
+			" this (%c) PKT=%d%s%s%s;"
+			" other PKT=%d%s%s%s; unspec 0x%x",
+		dev->udev->bus->bus_name, dev->udev->devpath,
+		status,
+
+		// XXX the packet counts don't seem right
+		// (1 at reset, not 0); maybe UNSPEC too
+
+		(status & STATUS_PORT_A) ? 'A' : 'B',
+		STATUS_PACKETS_THIS(status),
+		(status & STATUS_CONN_THIS) ? " CON" : "",
+		(status & STATUS_SUSPEND_THIS) ? " SUS" : "",
+		(status & STATUS_MAILBOX_THIS) ? " MBOX" : "",
+
+		STATUS_PACKETS_OTHER(status),
+		(status & STATUS_CONN_OTHER) ? " CON" : "",
+		(status & STATUS_SUSPEND_OTHER) ? " SUS" : "",
+		(status & STATUS_MAILBOX_OTHER) ? " MBOX" : "",
+
+		status & STATUS_UNSPEC_MASK
+		);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * TTL register
+ */
+
+#define	TTL_THIS(ttl)	(0x00ff & ttl)
+#define	TTL_OTHER(ttl)	(0x00ff & (ttl >> 8))
+#define MK_TTL(this,other)	((u16)(((other)<<8)|(0x00ff&(this))))
+
+static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl)
+{
+	if (netif_msg_link(dev))
+		devdbg(dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d",
+			dev->udev->bus->bus_name, dev->udev->devpath,
+			ttl, TTL_THIS(ttl), TTL_OTHER(ttl));
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int net1080_reset(struct usbnet *dev)
+{
+	u16		usbctl, status, ttl;
+	u16		*vp = kmalloc(sizeof (u16), GFP_KERNEL);
+	int		retval;
+
+	if (!vp)
+		return -ENOMEM;
+
+	// nc_dump_registers(dev);
+
+	if ((retval = nc_register_read(dev, REG_STATUS, vp)) < 0) {
+		dbg("can't read %s-%s status: %d",
+			dev->udev->bus->bus_name, dev->udev->devpath, retval);
+		goto done;
+	}
+	status = *vp;
+	nc_dump_status(dev, status);
+
+	if ((retval = nc_register_read(dev, REG_USBCTL, vp)) < 0) {
+		dbg("can't read USBCTL, %d", retval);
+		goto done;
+	}
+	usbctl = *vp;
+	nc_dump_usbctl(dev, usbctl);
+
+	nc_register_write(dev, REG_USBCTL,
+			USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER);
+
+	if ((retval = nc_register_read(dev, REG_TTL, vp)) < 0) {
+		dbg("can't read TTL, %d", retval);
+		goto done;
+	}
+	ttl = *vp;
+	// nc_dump_ttl(dev, ttl);
+
+	nc_register_write(dev, REG_TTL,
+			MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) );
+	dbg("%s: assigned TTL, %d ms", dev->net->name, NC_READ_TTL_MS);
+
+	if (netif_msg_link(dev))
+		devinfo(dev, "port %c, peer %sconnected",
+			(status & STATUS_PORT_A) ? 'A' : 'B',
+			(status & STATUS_CONN_OTHER) ? "" : "dis"
+			);
+	retval = 0;
+
+done:
+	kfree(vp);
+	return retval;
+}
+
+static int net1080_check_connect(struct usbnet *dev)
+{
+	int			retval;
+	u16			status;
+	u16			*vp = kmalloc(sizeof (u16), GFP_KERNEL);
+
+	if (!vp)
+		return -ENOMEM;
+	retval = nc_register_read(dev, REG_STATUS, vp);
+	status = *vp;
+	kfree(vp);
+	if (retval != 0) {
+		dbg("%s net1080_check_conn read - %d", dev->net->name, retval);
+		return retval;
+	}
+	if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER)
+		return -ENOLINK;
+	return 0;
+}
+
+static void nc_flush_complete(struct urb *urb, struct pt_regs *regs)
+{
+	kfree(urb->context);
+	usb_free_urb(urb);
+}
+
+static void nc_ensure_sync(struct usbnet *dev)
+{
+	dev->frame_errors++;
+	if (dev->frame_errors > 5) {
+		struct urb		*urb;
+		struct usb_ctrlrequest	*req;
+		int			status;
+
+		/* Send a flush */
+		urb = usb_alloc_urb(0, SLAB_ATOMIC);
+		if (!urb)
+			return;
+
+		req = kmalloc(sizeof *req, GFP_ATOMIC);
+		if (!req) {
+			usb_free_urb(urb);
+			return;
+		}
+
+		req->bRequestType = USB_DIR_OUT
+			| USB_TYPE_VENDOR
+			| USB_RECIP_DEVICE;
+		req->bRequest = REQUEST_REGISTER;
+		req->wValue = cpu_to_le16(USBCTL_FLUSH_THIS
+				| USBCTL_FLUSH_OTHER);
+		req->wIndex = cpu_to_le16(REG_USBCTL);
+		req->wLength = cpu_to_le16(0);
+
+		/* queue an async control request, we don't need
+		 * to do anything when it finishes except clean up.
+		 */
+		usb_fill_control_urb(urb, dev->udev,
+			usb_sndctrlpipe(dev->udev, 0),
+			(unsigned char *) req,
+			NULL, 0,
+			nc_flush_complete, req);
+		status = usb_submit_urb(urb, GFP_ATOMIC);
+		if (status) {
+			kfree(req);
+			usb_free_urb(urb);
+			return;
+		}
+
+		if (netif_msg_rx_err(dev))
+			devdbg(dev, "flush net1080; too many framing errors");
+		dev->frame_errors = 0;
+	}
+}
+
+static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	struct nc_header	*header;
+	struct nc_trailer	*trailer;
+	u16			hdr_len, packet_len;
+
+	if (!(skb->len & 0x01)) {
+#ifdef DEBUG
+		struct net_device	*net = dev->net;
+		dbg("rx framesize %d range %d..%d mtu %d", skb->len,
+			net->hard_header_len, dev->hard_mtu, net->mtu);
+#endif
+		dev->stats.rx_frame_errors++;
+		nc_ensure_sync(dev);
+		return 0;
+	}
+
+	header = (struct nc_header *) skb->data;
+	hdr_len = le16_to_cpup(&header->hdr_len);
+	packet_len = le16_to_cpup(&header->packet_len);
+	if (FRAMED_SIZE(packet_len) > NC_MAX_PACKET) {
+		dev->stats.rx_frame_errors++;
+		dbg("packet too big, %d", packet_len);
+		nc_ensure_sync(dev);
+		return 0;
+	} else if (hdr_len < MIN_HEADER) {
+		dev->stats.rx_frame_errors++;
+		dbg("header too short, %d", hdr_len);
+		nc_ensure_sync(dev);
+		return 0;
+	} else if (hdr_len > MIN_HEADER) {
+		// out of band data for us?
+		dbg("header OOB, %d bytes", hdr_len - MIN_HEADER);
+		nc_ensure_sync(dev);
+		// switch (vendor/product ids) { ... }
+	}
+	skb_pull(skb, hdr_len);
+
+	trailer = (struct nc_trailer *)
+		(skb->data + skb->len - sizeof *trailer);
+	skb_trim(skb, skb->len - sizeof *trailer);
+
+	if ((packet_len & 0x01) == 0) {
+		if (skb->data [packet_len] != PAD_BYTE) {
+			dev->stats.rx_frame_errors++;
+			dbg("bad pad");
+			return 0;
+		}
+		skb_trim(skb, skb->len - 1);
+	}
+	if (skb->len != packet_len) {
+		dev->stats.rx_frame_errors++;
+		dbg("bad packet len %d (expected %d)",
+			skb->len, packet_len);
+		nc_ensure_sync(dev);
+		return 0;
+	}
+	if (header->packet_id != get_unaligned(&trailer->packet_id)) {
+		dev->stats.rx_fifo_errors++;
+		dbg("(2+ dropped) rx packet_id mismatch 0x%x 0x%x",
+			le16_to_cpu(header->packet_id),
+			le16_to_cpu(trailer->packet_id));
+		return 0;
+	}
+#if 0
+	devdbg(dev, "frame <rx h %d p %d id %d", header->hdr_len,
+		header->packet_len, header->packet_id);
+#endif
+	dev->frame_errors = 0;
+	return 1;
+}
+
+static struct sk_buff *
+net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags)
+{
+	int			padlen;
+	struct sk_buff		*skb2;
+	struct nc_header	*header = NULL;
+	struct nc_trailer	*trailer = NULL;
+	int			len = skb->len;
+
+	padlen = ((len + sizeof (struct nc_header)
+			+ sizeof (struct nc_trailer)) & 0x01) ? 0 : 1;
+	if (!skb_cloned(skb)) {
+		int	headroom = skb_headroom(skb);
+		int	tailroom = skb_tailroom(skb);
+
+		if ((padlen + sizeof (struct nc_trailer)) <= tailroom
+			    && sizeof (struct nc_header) <= headroom)
+			/* There's enough head and tail room */
+			goto encapsulate;
+
+		if ((sizeof (struct nc_header) + padlen
+					+ sizeof (struct nc_trailer)) <
+				(headroom + tailroom)) {
+			/* There's enough total room, so just readjust */
+			skb->data = memmove(skb->head
+						+ sizeof (struct nc_header),
+					    skb->data, skb->len);
+			skb->tail = skb->data + len;
+			goto encapsulate;
+		}
+	}
+
+	/* Create a new skb to use with the correct size */
+	skb2 = skb_copy_expand(skb,
+				sizeof (struct nc_header),
+				sizeof (struct nc_trailer) + padlen,
+				flags);
+	dev_kfree_skb_any(skb);
+	if (!skb2)
+		return skb2;
+	skb = skb2;
+
+encapsulate:
+	/* header first */
+	header = (struct nc_header *) skb_push(skb, sizeof *header);
+	header->hdr_len = cpu_to_le16(sizeof (*header));
+	header->packet_len = cpu_to_le16(len);
+	header->packet_id = cpu_to_le16((u16)dev->xid++);
+
+	/* maybe pad; then trailer */
+	if (!((skb->len + sizeof *trailer) & 0x01))
+		*skb_put(skb, 1) = PAD_BYTE;
+	trailer = (struct nc_trailer *) skb_put(skb, sizeof *trailer);
+	put_unaligned(header->packet_id, &trailer->packet_id);
+#if 0
+	devdbg(dev, "frame >tx h %d p %d id %d",
+		header->hdr_len, header->packet_len,
+		header->packet_id);
+#endif
+	return skb;
+}
+
+static int net1080_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	unsigned	extra = sizeof (struct nc_header)
+				+ 1
+				+ sizeof (struct nc_trailer);
+
+	dev->net->hard_header_len += extra;
+	dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu;
+	dev->hard_mtu = NC_MAX_PACKET;
+	return usbnet_get_endpoints (dev, intf);
+}
+
+static const struct driver_info	net1080_info = {
+	.description =	"NetChip TurboCONNECT",
+	.flags =	FLAG_FRAMING_NC,
+	.bind =		net1080_bind,
+	.reset =	net1080_reset,
+	.check_connect = net1080_check_connect,
+	.rx_fixup =	net1080_rx_fixup,
+	.tx_fixup =	net1080_tx_fixup,
+};
+
+static const struct usb_device_id	products [] = {
+{
+	USB_DEVICE(0x0525, 0x1080),	// NetChip ref design
+	.driver_info =	(unsigned long) &net1080_info,
+}, {
+	USB_DEVICE(0x06D0, 0x0622),	// Laplink Gold
+	.driver_info =	(unsigned long) &net1080_info,
+},
+	{ },		// END
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver net1080_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"net1080",
+	.id_table =	products,
+	.probe =	usbnet_probe,
+	.disconnect =	usbnet_disconnect,
+	.suspend =	usbnet_suspend,
+	.resume =	usbnet_resume,
+};
+
+static int __init net1080_init(void)
+{
+ 	return usb_register(&net1080_driver);
+}
+module_init(net1080_init);
+
+static void __exit net1080_exit(void)
+{
+ 	usb_deregister(&net1080_driver);
+}
+module_exit(net1080_exit);
+
+MODULE_AUTHOR("David Brownell");
+MODULE_DESCRIPTION("NetChip 1080 based USB Host-to-Host Links");
+MODULE_LICENSE("GPL");

+ 0 - 1
drivers/usb/net/pegasus.c

@@ -825,7 +825,6 @@ static void pegasus_tx_timeout(struct net_device *net)
 	pegasus_t *pegasus = netdev_priv(net);
 	if (netif_msg_timer(pegasus))
 		printk(KERN_WARNING "%s: tx timeout\n", net->name);
-	pegasus->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 	usb_unlink_urb(pegasus->tx_urb);
 	pegasus->stats.tx_errors++;
 }

+ 156 - 0
drivers/usb/net/plusb.c

@@ -0,0 +1,156 @@
+/*
+ * PL-2301/2302 USB host-to-host link cables
+ * Copyright (C) 2000-2005 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// #define	DEBUG			// error path messages, extra info
+// #define	VERBOSE			// more; success messages
+
+#include <linux/config.h>
+#ifdef	CONFIG_USB_DEBUG
+#   define DEBUG
+#endif
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+
+#include "usbnet.h"
+
+
+/*
+ * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com
+ *
+ * The protocol and handshaking used here should be bug-compatible
+ * with the Linux 2.2 "plusb" driver, by Deti Fliegl.
+ *
+ * HEADS UP:  this handshaking isn't all that robust.  This driver
+ * gets confused easily if you unplug one end of the cable then
+ * try to connect it again; you'll need to restart both ends. The
+ * "naplink" software (used by some PlayStation/2 deveopers) does
+ * the handshaking much better!   Also, sometimes this hardware
+ * seems to get wedged under load.  Prolific docs are weak, and
+ * don't identify differences between PL2301 and PL2302, much less
+ * anything to explain the different PL2302 versions observed.
+ */
+
+/*
+ * Bits 0-4 can be used for software handshaking; they're set from
+ * one end, cleared from the other, "read" with the interrupt byte.
+ */
+#define	PL_S_EN		(1<<7)		/* (feature only) suspend enable */
+/* reserved bit -- rx ready (6) ? */
+#define	PL_TX_READY	(1<<5)		/* (interrupt only) transmit ready */
+#define	PL_RESET_OUT	(1<<4)		/* reset output pipe */
+#define	PL_RESET_IN	(1<<3)		/* reset input pipe */
+#define	PL_TX_C		(1<<2)		/* transmission complete */
+#define	PL_TX_REQ	(1<<1)		/* transmission received */
+#define	PL_PEER_E	(1<<0)		/* peer exists */
+
+static inline int
+pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index)
+{
+	return usb_control_msg(dev->udev,
+		usb_rcvctrlpipe(dev->udev, 0),
+		req,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		val, index,
+		NULL, 0,
+		USB_CTRL_GET_TIMEOUT);
+}
+
+static inline int
+pl_clear_QuickLink_features(struct usbnet *dev, int val)
+{
+	return pl_vendor_req(dev, 1, (u8) val, 0);
+}
+
+static inline int
+pl_set_QuickLink_features(struct usbnet *dev, int val)
+{
+	return pl_vendor_req(dev, 3, (u8) val, 0);
+}
+
+static int pl_reset(struct usbnet *dev)
+{
+	/* some units seem to need this reset, others reject it utterly.
+	 * FIXME be more like "naplink" or windows drivers.
+	 */
+	(void) pl_set_QuickLink_features(dev,
+		PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E);
+	return 0;
+}
+
+static const struct driver_info	prolific_info = {
+	.description =	"Prolific PL-2301/PL-2302",
+	.flags =	FLAG_NO_SETINT,
+		/* some PL-2302 versions seem to fail usb_set_interface() */
+	.reset =	pl_reset,
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Proilific's name won't normally be on the cables, and
+ * may not be on the device.
+ */
+
+static const struct usb_device_id	products [] = {
+
+{
+	USB_DEVICE(0x067b, 0x0000),	// PL-2301
+	.driver_info =	(unsigned long) &prolific_info,
+}, {
+	USB_DEVICE(0x067b, 0x0001),	// PL-2302
+	.driver_info =	(unsigned long) &prolific_info,
+},
+
+	{ },		// END
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver plusb_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"plusb",
+	.id_table =	products,
+	.probe =	usbnet_probe,
+	.disconnect =	usbnet_disconnect,
+	.suspend =	usbnet_suspend,
+	.resume =	usbnet_resume,
+};
+
+static int __init plusb_init(void)
+{
+ 	return usb_register(&plusb_driver);
+}
+module_init(plusb_init);
+
+static void __exit plusb_exit(void)
+{
+ 	usb_deregister(&plusb_driver);
+}
+module_exit(plusb_exit);
+
+MODULE_AUTHOR("David Brownell");
+MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver");
+MODULE_LICENSE("GPL");

+ 615 - 0
drivers/usb/net/rndis_host.c

@@ -0,0 +1,615 @@
+/*
+ * Host Side support for RNDIS Networking Links
+ * Copyright (C) 2005 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// #define	DEBUG			// error path messages, extra info
+// #define	VERBOSE			// more; success messages
+
+#include <linux/config.h>
+#ifdef	CONFIG_USB_DEBUG
+#   define DEBUG
+#endif
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb_cdc.h>
+
+#include "usbnet.h"
+
+
+/*
+ * RNDIS is NDIS remoted over USB.  It's a MSFT variant of CDC ACM ... of
+ * course ACM was intended for modems, not Ethernet links!  USB's standard
+ * for Ethernet links is "CDC Ethernet", which is significantly simpler.
+ */
+
+/*
+ * CONTROL uses CDC "encapsulated commands" with funky notifications.
+ *  - control-out:  SEND_ENCAPSULATED
+ *  - interrupt-in:  RESPONSE_AVAILABLE
+ *  - control-in:  GET_ENCAPSULATED
+ *
+ * We'll try to ignore the RESPONSE_AVAILABLE notifications.
+ */
+struct rndis_msg_hdr {
+	__le32	msg_type;			/* RNDIS_MSG_* */
+	__le32	msg_len;
+	// followed by data that varies between messages
+	__le32	request_id;
+	__le32	status;
+	// ... and more
+} __attribute__ ((packed));
+
+/* RNDIS defines this (absurdly huge) control timeout */
+#define	RNDIS_CONTROL_TIMEOUT_MS	(10 * 1000)
+
+
+#define ccpu2 __constant_cpu_to_le32
+
+#define RNDIS_MSG_COMPLETION	ccpu2(0x80000000)
+
+/* codes for "msg_type" field of rndis messages;
+ * only the data channel uses packet messages (maybe batched);
+ * everything else goes on the control channel.
+ */
+#define RNDIS_MSG_PACKET	ccpu2(0x00000001)	/* 1-N packets */
+#define RNDIS_MSG_INIT		ccpu2(0x00000002)
+#define RNDIS_MSG_INIT_C 	(RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_HALT		ccpu2(0x00000003)
+#define RNDIS_MSG_QUERY		ccpu2(0x00000004)
+#define RNDIS_MSG_QUERY_C 	(RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_SET		ccpu2(0x00000005)
+#define RNDIS_MSG_SET_C 	(RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_RESET		ccpu2(0x00000006)
+#define RNDIS_MSG_RESET_C 	(RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_INDICATE	ccpu2(0x00000007)
+#define RNDIS_MSG_KEEPALIVE	ccpu2(0x00000008)
+#define RNDIS_MSG_KEEPALIVE_C 	(RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
+
+/* codes for "status" field of completion messages */
+#define	RNDIS_STATUS_SUCCESS		ccpu2(0x00000000)
+#define	RNDIS_STATUS_FAILURE		ccpu2(0xc0000001)
+#define	RNDIS_STATUS_INVALID_DATA	ccpu2(0xc0010015)
+#define	RNDIS_STATUS_NOT_SUPPORTED	ccpu2(0xc00000bb)
+#define	RNDIS_STATUS_MEDIA_CONNECT	ccpu2(0x4001000b)
+#define	RNDIS_STATUS_MEDIA_DISCONNECT	ccpu2(0x4001000c)
+
+
+struct rndis_data_hdr {
+	__le32	msg_type;		/* RNDIS_MSG_PACKET */
+	__le32	msg_len;		// rndis_data_hdr + data_len + pad
+	__le32	data_offset;		// 36 -- right after header
+	__le32	data_len;		// ... real packet size
+
+	__le32	oob_data_offset;	// zero
+	__le32	oob_data_len;		// zero
+	__le32	num_oob;		// zero
+	__le32	packet_data_offset;	// zero
+
+	__le32	packet_data_len;	// zero
+	__le32	vc_handle;		// zero
+	__le32	reserved;		// zero
+} __attribute__ ((packed));
+
+struct rndis_init {		/* OUT */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_INIT */
+	__le32	msg_len;			// 24
+	__le32	request_id;
+	__le32	major_version;			// of rndis (1.0)
+	__le32	minor_version;
+	__le32	max_transfer_size;
+} __attribute__ ((packed));
+
+struct rndis_init_c {		/* IN */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_INIT_C */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	status;
+	__le32	major_version;			// of rndis (1.0)
+	__le32	minor_version;
+	__le32	device_flags;
+	__le32	medium;				// zero == 802.3
+	__le32	max_packets_per_message;
+	__le32	max_transfer_size;
+	__le32	packet_alignment;		// max 7; (1<<n) bytes
+	__le32	af_list_offset;			// zero
+	__le32	af_list_size;			// zero
+} __attribute__ ((packed));
+
+struct rndis_halt {		/* OUT (no reply) */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_HALT */
+	__le32	msg_len;
+	__le32	request_id;
+} __attribute__ ((packed));
+
+struct rndis_query {		/* OUT */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_QUERY */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	oid;
+	__le32	len;
+	__le32	offset;
+/*?*/	__le32	handle;				// zero
+} __attribute__ ((packed));
+
+struct rndis_query_c {		/* IN */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_QUERY_C */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	status;
+	__le32	len;
+	__le32	offset;
+} __attribute__ ((packed));
+
+struct rndis_set {		/* OUT */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_SET */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	oid;
+	__le32	len;
+	__le32	offset;
+/*?*/	__le32	handle;				// zero
+} __attribute__ ((packed));
+
+struct rndis_set_c {		/* IN */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_SET_C */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	status;
+} __attribute__ ((packed));
+
+struct rndis_reset {		/* IN */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_RESET */
+	__le32	msg_len;
+	__le32	reserved;
+} __attribute__ ((packed));
+
+struct rndis_reset_c {		/* OUT */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_RESET_C */
+	__le32	msg_len;
+	__le32	status;
+	__le32	addressing_lost;
+} __attribute__ ((packed));
+
+struct rndis_indicate {		/* IN (unrequested) */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_INDICATE */
+	__le32	msg_len;
+	__le32	status;
+	__le32	length;
+	__le32	offset;
+/**/	__le32	diag_status;
+	__le32	error_offset;
+/**/	__le32	message;
+} __attribute__ ((packed));
+
+struct rndis_keepalive {	/* OUT (optionally IN) */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_KEEPALIVE */
+	__le32	msg_len;
+	__le32	request_id;
+} __attribute__ ((packed));
+
+struct rndis_keepalive_c {	/* IN (optionally OUT) */
+	// header and:
+	__le32	msg_type;			/* RNDIS_MSG_KEEPALIVE_C */
+	__le32	msg_len;
+	__le32	request_id;
+	__le32	status;
+} __attribute__ ((packed));
+
+/* NOTE:  about 30 OIDs are "mandatory" for peripherals to support ... and
+ * there are gobs more that may optionally be supported.  We'll avoid as much
+ * of that mess as possible.
+ */
+#define OID_802_3_PERMANENT_ADDRESS	ccpu2(0x01010101)
+#define OID_GEN_CURRENT_PACKET_FILTER	ccpu2(0x0001010e)
+
+/*
+ * RNDIS notifications from device: command completion; "reverse"
+ * keepalives; etc
+ */
+static void rndis_status(struct usbnet *dev, struct urb *urb)
+{
+	devdbg(dev, "rndis status urb, len %d stat %d",
+		urb->actual_length, urb->status);
+	// FIXME for keepalives, respond immediately (asynchronously)
+	// if not an RNDIS status, do like cdc_status(dev,urb) does
+}
+
+/*
+ * RPC done RNDIS-style.  Caller guarantees:
+ * - message is properly byteswapped
+ * - there's no other request pending
+ * - buf can hold up to 1KB response (required by RNDIS spec)
+ * On return, the first few entries are already byteswapped.
+ *
+ * Call context is likely probe(), before interface name is known,
+ * which is why we won't try to use it in the diagnostics.
+ */
+static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
+{
+	struct cdc_state	*info = (void *) &dev->data;
+	int			retval;
+	unsigned		count;
+	__le32			rsp;
+	u32			xid = 0, msg_len, request_id;
+
+	/* REVISIT when this gets called from contexts other than probe() or
+	 * disconnect(): either serialize, or dispatch responses on xid
+	 */
+
+	/* Issue the request; don't bother byteswapping our xid */
+	if (likely(buf->msg_type != RNDIS_MSG_HALT
+			&& buf->msg_type != RNDIS_MSG_RESET)) {
+		xid = dev->xid++;
+		if (!xid)
+			xid = dev->xid++;
+		buf->request_id = (__force __le32) xid;
+	}
+	retval = usb_control_msg(dev->udev,
+		usb_sndctrlpipe(dev->udev, 0),
+		USB_CDC_SEND_ENCAPSULATED_COMMAND,
+		USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+		0, info->u->bMasterInterface0,
+		buf, le32_to_cpu(buf->msg_len),
+		RNDIS_CONTROL_TIMEOUT_MS);
+	if (unlikely(retval < 0 || xid == 0))
+		return retval;
+
+	// FIXME Seems like some devices discard responses when
+	// we time out and cancel our "get response" requests...
+	// so, this is fragile.  Probably need to poll for status.
+
+	/* ignore status endpoint, just poll the control channel;
+	 * the request probably completed immediately
+	 */
+	rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
+	for (count = 0; count < 10; count++) {
+		memset(buf, 0, 1024);
+		retval = usb_control_msg(dev->udev,
+			usb_rcvctrlpipe(dev->udev, 0),
+			USB_CDC_GET_ENCAPSULATED_RESPONSE,
+			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			0, info->u->bMasterInterface0,
+			buf, 1024,
+			RNDIS_CONTROL_TIMEOUT_MS);
+		if (likely(retval >= 8)) {
+			msg_len = le32_to_cpu(buf->msg_len);
+			request_id = (__force u32) buf->request_id;
+			if (likely(buf->msg_type == rsp)) {
+				if (likely(request_id == xid)) {
+					if (unlikely(rsp == RNDIS_MSG_RESET_C))
+						return 0;
+					if (likely(RNDIS_STATUS_SUCCESS
+							== buf->status))
+						return 0;
+					dev_dbg(&info->control->dev,
+						"rndis reply status %08x\n",
+						le32_to_cpu(buf->status));
+					return -EL3RST;
+				}
+				dev_dbg(&info->control->dev,
+					"rndis reply id %d expected %d\n",
+					request_id, xid);
+				/* then likely retry */
+			} else switch (buf->msg_type) {
+			case RNDIS_MSG_INDICATE: {	/* fault */
+				// struct rndis_indicate *msg = (void *)buf;
+				dev_info(&info->control->dev,
+					 "rndis fault indication\n");
+				}
+				break;
+			case RNDIS_MSG_KEEPALIVE: {	/* ping */
+				struct rndis_keepalive_c *msg = (void *)buf;
+
+				msg->msg_type = RNDIS_MSG_KEEPALIVE_C;
+				msg->msg_len = ccpu2(sizeof *msg);
+				msg->status = RNDIS_STATUS_SUCCESS;
+				retval = usb_control_msg(dev->udev,
+					usb_sndctrlpipe(dev->udev, 0),
+					USB_CDC_SEND_ENCAPSULATED_COMMAND,
+					USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+					0, info->u->bMasterInterface0,
+					msg, sizeof *msg,
+					RNDIS_CONTROL_TIMEOUT_MS);
+				if (unlikely(retval < 0))
+					dev_dbg(&info->control->dev,
+						"rndis keepalive err %d\n",
+						retval);
+				}
+				break;
+			default:
+				dev_dbg(&info->control->dev,
+					"unexpected rndis msg %08x len %d\n",
+					le32_to_cpu(buf->msg_type), msg_len);
+			}
+		} else {
+			/* device probably issued a protocol stall; ignore */
+			dev_dbg(&info->control->dev,
+				"rndis response error, code %d\n", retval);
+		}
+		msleep(2);
+	}
+	dev_dbg(&info->control->dev, "rndis response timeout\n");
+	return -ETIMEDOUT;
+}
+
+static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int			retval;
+	struct net_device	*net = dev->net;
+	union {
+		void			*buf;
+		struct rndis_msg_hdr	*header;
+		struct rndis_init	*init;
+		struct rndis_init_c	*init_c;
+		struct rndis_query	*get;
+		struct rndis_query_c	*get_c;
+		struct rndis_set	*set;
+		struct rndis_set_c	*set_c;
+	} u;
+	u32			tmp;
+
+	/* we can't rely on i/o from stack working, or stack allocation */
+	u.buf = kmalloc(1024, GFP_KERNEL);
+	if (!u.buf)
+		return -ENOMEM;
+	retval = usbnet_generic_cdc_bind(dev, intf);
+	if (retval < 0)
+		goto done;
+
+	net->hard_header_len += sizeof (struct rndis_data_hdr);
+
+	/* initialize; max transfer is 16KB at full speed */
+	u.init->msg_type = RNDIS_MSG_INIT;
+	u.init->msg_len = ccpu2(sizeof *u.init);
+	u.init->major_version = ccpu2(1);
+	u.init->minor_version = ccpu2(0);
+	u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
+
+	retval = rndis_command(dev, u.header);
+	if (unlikely(retval < 0)) {
+		/* it might not even be an RNDIS device!! */
+		dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
+fail:
+		usb_driver_release_interface(driver_of(intf),
+			((struct cdc_state *)&(dev->data))->data);
+		goto done;
+	}
+	dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
+	/* REVISIT:  peripheral "alignment" request is ignored ... */
+	dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
+		1 << le32_to_cpu(u.init_c->packet_alignment));
+
+	/* get designated host ethernet address */
+	memset(u.get, 0, sizeof *u.get);
+	u.get->msg_type = RNDIS_MSG_QUERY;
+	u.get->msg_len = ccpu2(sizeof *u.get);
+	u.get->oid = OID_802_3_PERMANENT_ADDRESS;
+
+	retval = rndis_command(dev, u.header);
+	if (unlikely(retval < 0)) {
+		dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
+		goto fail;
+	}
+	tmp = le32_to_cpu(u.get_c->offset);
+	if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
+			|| u.get_c->len != ccpu2(ETH_ALEN))) {
+		dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
+			tmp, le32_to_cpu(u.get_c->len));
+		retval = -EDOM;
+		goto fail;
+	}
+	memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN);
+
+	/* set a nonzero filter to enable data transfers */
+	memset(u.set, 0, sizeof *u.set);
+	u.set->msg_type = RNDIS_MSG_SET;
+	u.set->msg_len = ccpu2(4 + sizeof *u.set);
+	u.set->oid = OID_GEN_CURRENT_PACKET_FILTER;
+	u.set->len = ccpu2(4);
+	u.set->offset = ccpu2((sizeof *u.set) - 8);
+	*(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER);
+
+	retval = rndis_command(dev, u.header);
+	if (unlikely(retval < 0)) {
+		dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
+		goto fail;
+	}
+
+	retval = 0;
+done:
+	kfree(u.buf);
+	return retval;
+}
+
+static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+	struct rndis_halt	*halt;
+
+	/* try to clear any rndis state/activity (no i/o from stack!) */
+	halt = kcalloc(1, sizeof *halt, SLAB_KERNEL);
+	if (halt) {
+		halt->msg_type = RNDIS_MSG_HALT;
+		halt->msg_len = ccpu2(sizeof *halt);
+		(void) rndis_command(dev, (void *)halt);
+		kfree(halt);
+	}
+
+	return usbnet_cdc_unbind(dev, intf);
+}
+
+/*
+ * DATA -- host must not write zlps
+ */
+static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	/* peripheral may have batched packets to us... */
+	while (likely(skb->len)) {
+		struct rndis_data_hdr	*hdr = (void *)skb->data;
+		struct sk_buff		*skb2;
+		u32			msg_len, data_offset, data_len;
+
+		msg_len = le32_to_cpu(hdr->msg_len);
+		data_offset = le32_to_cpu(hdr->data_offset);
+		data_len = le32_to_cpu(hdr->data_len);
+
+		/* don't choke if we see oob, per-packet data, etc */
+		if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET
+				|| skb->len < msg_len
+				|| (data_offset + data_len + 8) > msg_len)) {
+			dev->stats.rx_frame_errors++;
+			devdbg(dev, "bad rndis message %d/%d/%d/%d, len %d",
+				le32_to_cpu(hdr->msg_type),
+				msg_len, data_offset, data_len, skb->len);
+			return 0;
+		}
+		skb_pull(skb, 8 + data_offset);
+
+		/* at most one packet left? */
+		if (likely((data_len - skb->len) <= sizeof *hdr)) {
+			skb_trim(skb, data_len);
+			break;
+		}
+
+		/* try to return all the packets in the batch */
+		skb2 = skb_clone(skb, GFP_ATOMIC);
+		if (unlikely(!skb2))
+			break;
+		skb_pull(skb, msg_len - sizeof *hdr);
+		skb_trim(skb2, data_len);
+		usbnet_skb_return(dev, skb2);
+	}
+
+	/* caller will usbnet_skb_return the remaining packet */
+	return 1;
+}
+
+static struct sk_buff *
+rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags)
+{
+	struct rndis_data_hdr	*hdr;
+	struct sk_buff		*skb2;
+	unsigned		len = skb->len;
+
+	if (likely(!skb_cloned(skb))) {
+		int	room = skb_headroom(skb);
+
+		/* enough head room as-is? */
+		if (unlikely((sizeof *hdr) <= room))
+			goto fill;
+
+		/* enough room, but needs to be readjusted? */
+		room += skb_tailroom(skb);
+		if (likely((sizeof *hdr) <= room)) {
+			skb->data = memmove(skb->head + sizeof *hdr,
+					    skb->data, len);
+			skb->tail = skb->data + len;
+			goto fill;
+		}
+	}
+
+	/* create a new skb, with the correct size (and tailpad) */
+	skb2 = skb_copy_expand(skb, sizeof *hdr, 1, flags);
+	dev_kfree_skb_any(skb);
+	if (unlikely(!skb2))
+		return skb2;
+	skb = skb2;
+
+	/* fill out the RNDIS header.  we won't bother trying to batch
+	 * packets; Linux minimizes wasted bandwidth through tx queues.
+	 */
+fill:
+	hdr = (void *) __skb_push(skb, sizeof *hdr);
+	memset(hdr, 0, sizeof *hdr);
+	hdr->msg_type = RNDIS_MSG_PACKET;
+	hdr->msg_len = cpu_to_le32(skb->len);
+	hdr->data_offset = ccpu2(sizeof(*hdr) - 8);
+	hdr->data_len = cpu_to_le32(len);
+
+	/* FIXME make the last packet always be short ... */
+	return skb;
+}
+
+
+static const struct driver_info	rndis_info = {
+	.description =	"RNDIS device",
+	.flags =	FLAG_ETHER | FLAG_FRAMING_RN,
+	.bind =		rndis_bind,
+	.unbind =	rndis_unbind,
+	.status =	rndis_status,
+	.rx_fixup =	rndis_rx_fixup,
+	.tx_fixup =	rndis_tx_fixup,
+};
+
+#undef ccpu2
+
+
+/*-------------------------------------------------------------------------*/
+
+static const struct usb_device_id	products [] = {
+{
+	/* RNDIS is MSFT's un-official variant of CDC ACM */
+	USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
+	.driver_info = (unsigned long) &rndis_info,
+},
+	{ },		// END
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver rndis_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"rndis_host",
+	.id_table =	products,
+	.probe =	usbnet_probe,
+	.disconnect =	usbnet_disconnect,
+	.suspend =	usbnet_suspend,
+	.resume =	usbnet_resume,
+};
+
+static int __init rndis_init(void)
+{
+ 	return usb_register(&rndis_driver);
+}
+module_init(rndis_init);
+
+static void __exit rndis_exit(void)
+{
+ 	usb_deregister(&rndis_driver);
+}
+module_exit(rndis_exit);
+
+MODULE_AUTHOR("David Brownell");
+MODULE_DESCRIPTION("USB Host side RNDIS driver");
+MODULE_LICENSE("GPL");

+ 0 - 1
drivers/usb/net/rtl8150.c

@@ -653,7 +653,6 @@ static void rtl8150_tx_timeout(struct net_device *netdev)
 {
 	rtl8150_t *dev = netdev_priv(netdev);
 	warn("%s: Tx timeout.", netdev->name);
-	dev->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 	usb_unlink_urb(dev->tx_urb);
 	dev->stats.tx_errors++;
 }

File diff suppressed because it is too large
+ 138 - 2776
drivers/usb/net/usbnet.c


+ 193 - 0
drivers/usb/net/usbnet.h

@@ -0,0 +1,193 @@
+/*
+ * USB Networking Link Interface
+ *
+ * Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net>
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef	__USBNET_H
+#define	__USBNET_H
+
+
+/* interface from usbnet core to each USB networking link we handle */
+struct usbnet {
+	/* housekeeping */
+	struct usb_device	*udev;
+	struct driver_info	*driver_info;
+	wait_queue_head_t	*wait;
+
+	/* i/o info: pipes etc */
+	unsigned		in, out;
+	struct usb_host_endpoint *status;
+	unsigned		maxpacket;
+	struct timer_list	delay;
+
+	/* protocol/interface state */
+	struct net_device	*net;
+	struct net_device_stats	stats;
+	int			msg_enable;
+	unsigned long		data [5];
+	u32			xid;
+	u32			hard_mtu;	/* count any extra framing */
+	size_t		        rx_urb_size;    /* size for rx urbs  */
+	struct mii_if_info	mii;
+
+	/* various kinds of pending driver work */
+	struct sk_buff_head	rxq;
+	struct sk_buff_head	txq;
+	struct sk_buff_head	done;
+	struct urb		*interrupt;
+	struct tasklet_struct	bh;
+
+	struct work_struct	kevent;
+	unsigned long		flags;
+#		define EVENT_TX_HALT	0
+#		define EVENT_RX_HALT	1
+#		define EVENT_RX_MEMORY	2
+#		define EVENT_STS_SPLIT	3
+#		define EVENT_LINK_RESET	4
+};
+
+static inline struct usb_driver *driver_of(struct usb_interface *intf)
+{
+	return to_usb_driver(intf->dev.driver);
+}
+
+/* interface from the device/framing level "minidriver" to core */
+struct driver_info {
+	char		*description;
+
+	int		flags;
+/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */
+#define FLAG_FRAMING_NC	0x0001		/* guard against device dropouts */
+#define FLAG_FRAMING_GL	0x0002		/* genelink batches packets */
+#define FLAG_FRAMING_Z	0x0004		/* zaurus adds a trailer */
+#define FLAG_FRAMING_RN	0x0008		/* RNDIS batches, plus huge header */
+
+#define FLAG_NO_SETINT	0x0010		/* device can't set_interface() */
+#define FLAG_ETHER	0x0020		/* maybe use "eth%d" names */
+
+#define FLAG_FRAMING_AX 0x0040          /* AX88772/178 packets */
+
+	/* init device ... can sleep, or cause probe() failure */
+	int	(*bind)(struct usbnet *, struct usb_interface *);
+
+	/* cleanup device ... can sleep, but can't fail */
+	void	(*unbind)(struct usbnet *, struct usb_interface *);
+
+	/* reset device ... can sleep */
+	int	(*reset)(struct usbnet *);
+
+	/* see if peer is connected ... can sleep */
+	int	(*check_connect)(struct usbnet *);
+
+	/* for status polling */
+	void	(*status)(struct usbnet *, struct urb *);
+
+	/* link reset handling, called from defer_kevent */
+	int	(*link_reset)(struct usbnet *);
+
+	/* fixup rx packet (strip framing) */
+	int	(*rx_fixup)(struct usbnet *dev, struct sk_buff *skb);
+
+	/* fixup tx packet (add framing) */
+	struct sk_buff	*(*tx_fixup)(struct usbnet *dev,
+				struct sk_buff *skb, unsigned flags);
+
+	/* for new devices, use the descriptor-reading code instead */
+	int		in;		/* rx endpoint */
+	int		out;		/* tx endpoint */
+
+	unsigned long	data;		/* Misc driver specific data */
+};
+
+/* Minidrivers are just drivers using the "usbnet" core as a powerful
+ * network-specific subroutine library ... that happens to do pretty
+ * much everything except custom framing and chip-specific stuff.
+ */
+extern int usbnet_probe(struct usb_interface *, const struct usb_device_id *);
+extern int usbnet_suspend (struct usb_interface *, pm_message_t );
+extern int usbnet_resume (struct usb_interface *);
+extern void usbnet_disconnect(struct usb_interface *);
+
+
+/* Drivers that reuse some of the standard USB CDC infrastructure
+ * (notably, using multiple interfaces according to the the CDC
+ * union descriptor) get some helper code.
+ */
+struct cdc_state {
+	struct usb_cdc_header_desc	*header;
+	struct usb_cdc_union_desc	*u;
+	struct usb_cdc_ether_desc	*ether;
+	struct usb_interface		*control;
+	struct usb_interface		*data;
+};
+
+extern int usbnet_generic_cdc_bind (struct usbnet *, struct usb_interface *);
+extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *);
+
+/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */
+#define	DEFAULT_FILTER	(USB_CDC_PACKET_TYPE_BROADCAST \
+ 			|USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+ 			|USB_CDC_PACKET_TYPE_PROMISCUOUS \
+ 			|USB_CDC_PACKET_TYPE_DIRECTED)
+
+
+/* we record the state for each of our queued skbs */
+enum skb_state {
+	illegal = 0,
+	tx_start, tx_done,
+	rx_start, rx_done, rx_cleanup
+};
+
+struct skb_data {	/* skb->cb is one of these */
+	struct urb		*urb;
+	struct usbnet		*dev;
+	enum skb_state		state;
+	size_t			length;
+};
+
+
+extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *);
+extern void usbnet_defer_kevent (struct usbnet *, int);
+extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
+
+extern u32 usbnet_get_msglevel (struct net_device *);
+extern void usbnet_set_msglevel (struct net_device *, u32);
+extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
+
+/* messaging support includes the interface name, so it must not be
+ * used before it has one ... notably, in minidriver bind() calls.
+ */
+#ifdef DEBUG
+#define devdbg(usbnet, fmt, arg...) \
+	printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
+#else
+#define devdbg(usbnet, fmt, arg...) do {} while(0)
+#endif
+
+#define deverr(usbnet, fmt, arg...) \
+	printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
+#define devwarn(usbnet, fmt, arg...) \
+	printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
+
+#define devinfo(usbnet, fmt, arg...) \
+	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \
+
+
+#endif	/* __USBNET_H */

+ 386 - 0
drivers/usb/net/zaurus.c

@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2002 Pavel Machek <pavel@ucw.cz>
+ * Copyright (C) 2002-2005 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// #define	DEBUG			// error path messages, extra info
+// #define	VERBOSE			// more; success messages
+
+#include <linux/config.h>
+#ifdef	CONFIG_USB_DEBUG
+#   define DEBUG
+#endif
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/usb.h>
+#include <linux/usb_cdc.h>
+
+#include "usbnet.h"
+
+
+/*
+ * All known Zaurii lie about their standards conformance.  At least
+ * the earliest SA-1100 models lie by saying they support CDC Ethernet.
+ * Some later models (especially PXA-25x and PXA-27x based ones) lie
+ * and say they support CDC MDLM (for access to cell phone modems).
+ *
+ * There are non-Zaurus products that use these same protocols too.
+ *
+ * The annoying thing is that at the same time Sharp was developing
+ * that annoying standards-breaking software, the Linux community had
+ * a simple "CDC Subset" working reliably on the same SA-1100 hardware.
+ * That is, the same functionality but not violating standards.
+ *
+ * The CDC Ethernet nonconformance points are troublesome to hosts
+ * with a true CDC Ethernet implementation:
+ *   - Framing appends a CRC, which the spec says drivers "must not" do;
+ *   - Transfers data in altsetting zero, instead of altsetting 1;
+ *   - All these peripherals use the same ethernet address.
+ *
+ * The CDC MDLM nonconformance is less immediately troublesome, since all
+ * MDLM implementations are quasi-proprietary anyway.
+ */
+
+static struct sk_buff *
+zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, unsigned flags)
+{
+	int			padlen;
+	struct sk_buff		*skb2;
+
+	padlen = 2;
+	if (!skb_cloned(skb)) {
+		int	tailroom = skb_tailroom(skb);
+		if ((padlen + 4) <= tailroom)
+			goto done;
+	}
+	skb2 = skb_copy_expand(skb, 0, 4 + padlen, flags);
+	dev_kfree_skb_any(skb);
+	skb = skb2;
+	if (skb) {
+		u32		fcs;
+done:
+		fcs = crc32_le(~0, skb->data, skb->len);
+		fcs = ~fcs;
+
+		*skb_put (skb, 1) = fcs       & 0xff;
+		*skb_put (skb, 1) = (fcs>> 8) & 0xff;
+		*skb_put (skb, 1) = (fcs>>16) & 0xff;
+		*skb_put (skb, 1) = (fcs>>24) & 0xff;
+	}
+	return skb;
+}
+
+static int zaurus_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	/* Belcarra's funky framing has other options; mostly
+	 * TRAILERS (!) with 4 bytes CRC, and maybe 2 pad bytes.
+	 */
+	dev->net->hard_header_len += 6;
+	dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu;
+	return usbnet_generic_cdc_bind(dev, intf);
+}
+
+/* PDA style devices are always connected if present */
+static int always_connected (struct usbnet *dev)
+{
+	return 0;
+}
+
+static const struct driver_info	zaurus_sl5x00_info = {
+	.description =	"Sharp Zaurus SL-5x00",
+	.flags =	FLAG_FRAMING_Z,
+	.check_connect = always_connected,
+	.bind =		zaurus_bind,
+	.unbind =	usbnet_cdc_unbind,
+	.tx_fixup = 	zaurus_tx_fixup,
+};
+#define	ZAURUS_STRONGARM_INFO	((unsigned long)&zaurus_sl5x00_info)
+
+static const struct driver_info	zaurus_pxa_info = {
+	.description =	"Sharp Zaurus, PXA-2xx based",
+	.flags =	FLAG_FRAMING_Z,
+	.check_connect = always_connected,
+	.bind =		zaurus_bind,
+	.unbind =	usbnet_cdc_unbind,
+	.tx_fixup = 	zaurus_tx_fixup,
+};
+#define	ZAURUS_PXA_INFO		((unsigned long)&zaurus_pxa_info)
+
+static const struct driver_info	olympus_mxl_info = {
+	.description =	"Olympus R1000",
+	.flags =	FLAG_FRAMING_Z,
+	.check_connect = always_connected,
+	.bind =		zaurus_bind,
+	.unbind =	usbnet_cdc_unbind,
+	.tx_fixup = 	zaurus_tx_fixup,
+};
+#define	OLYMPUS_MXL_INFO	((unsigned long)&olympus_mxl_info)
+
+
+/* Some more recent products using Lineo/Belcarra code will wrongly claim
+ * CDC MDLM conformance.  They aren't conformant:  data endpoints live
+ * in the control interface, there's no data interface, and it's not used
+ * to talk to a cell phone radio.  But at least we can detect these two
+ * pseudo-classes, rather than growing this product list with entries for
+ * each new nonconformant product (sigh).
+ */
+static const u8 safe_guid[16] = {
+	0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+	0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+};
+static const u8 blan_guid[16] = {
+	0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70,
+	0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37,
+};
+
+static int blan_mdlm_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	u8				*buf = intf->cur_altsetting->extra;
+	int				len = intf->cur_altsetting->extralen;
+	struct usb_cdc_mdlm_desc	*desc = NULL;
+	struct usb_cdc_mdlm_detail_desc	*detail = NULL;
+
+	while (len > 3) {
+		if (buf [1] != USB_DT_CS_INTERFACE)
+			goto next_desc;
+
+		/* use bDescriptorSubType, and just verify that we get a
+		 * "BLAN" (or "SAFE") descriptor.
+		 */
+		switch (buf [2]) {
+		case USB_CDC_MDLM_TYPE:
+			if (desc) {
+				dev_dbg(&intf->dev, "extra MDLM\n");
+				goto bad_desc;
+			}
+			desc = (void *) buf;
+			if (desc->bLength != sizeof *desc) {
+				dev_dbg(&intf->dev, "MDLM len %u\n",
+					desc->bLength);
+				goto bad_desc;
+			}
+			/* expect bcdVersion 1.0, ignore */
+			if (memcmp(&desc->bGUID, blan_guid, 16)
+				    && memcmp(&desc->bGUID, safe_guid, 16) ) {
+				/* hey, this one might _really_ be MDLM! */
+				dev_dbg(&intf->dev, "MDLM guid\n");
+				goto bad_desc;
+			}
+			break;
+		case USB_CDC_MDLM_DETAIL_TYPE:
+			if (detail) {
+				dev_dbg(&intf->dev, "extra MDLM detail\n");
+				goto bad_desc;
+			}
+			detail = (void *) buf;
+			switch (detail->bGuidDescriptorType) {
+			case 0:			/* "SAFE" */
+				if (detail->bLength != (sizeof *detail + 2))
+					goto bad_detail;
+				break;
+			case 1:			/* "BLAN" */
+				if (detail->bLength != (sizeof *detail + 3))
+					goto bad_detail;
+				break;
+			default:
+				goto bad_detail;
+			}
+
+			/* assuming we either noticed BLAN already, or will
+			 * find it soon, there are some data bytes here:
+			 *  - bmNetworkCapabilities (unused)
+			 *  - bmDataCapabilities (bits, see below)
+			 *  - bPad (ignored, for PADAFTER -- BLAN-only)
+			 * bits are:
+			 *  - 0x01 -- Zaurus framing (add CRC)
+			 *  - 0x02 -- PADBEFORE (CRC includes some padding)
+			 *  - 0x04 -- PADAFTER (some padding after CRC)
+			 *  - 0x08 -- "fermat" packet mangling (for hw bugs)
+			 * the PADBEFORE appears not to matter; we interop
+			 * with devices that use it and those that don't.
+			 */
+			if ((detail->bDetailData[1] & ~0x02) != 0x01) {
+				/* bmDataCapabilites == 0 would be fine too,
+				 * but framing is minidriver-coupled for now.
+				 */
+bad_detail:
+				dev_dbg(&intf->dev,
+						"bad MDLM detail, %d %d %d\n",
+						detail->bLength,
+						detail->bDetailData[0],
+						detail->bDetailData[2]);
+				goto bad_desc;
+			}
+			break;
+		}
+next_desc:
+		len -= buf [0];	/* bLength */
+		buf += buf [0];
+	}
+
+	if (!desc || !detail) {
+		dev_dbg(&intf->dev, "missing cdc mdlm %s%sdescriptor\n",
+			desc ? "" : "func ",
+			detail ? "" : "detail ");
+		goto bad_desc;
+	}
+
+	/* There's probably a CDC Ethernet descriptor there, but we can't
+	 * rely on the Ethernet address it provides since not all vendors
+	 * bother to make it unique.  Likewise there's no point in tracking
+	 * of the CDC event notifications.
+	 */
+	return usbnet_get_endpoints(dev, intf);
+
+bad_desc:
+	dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n");
+	return -ENODEV;
+}
+
+static const struct driver_info	bogus_mdlm_info = {
+	.description =	"pseudo-MDLM (BLAN) device",
+	.flags =	FLAG_FRAMING_Z,
+	.check_connect = always_connected,
+	.tx_fixup = 	zaurus_tx_fixup,
+	.bind =		blan_mdlm_bind,
+};
+
+static const struct usb_device_id	products [] = {
+#define	ZAURUS_MASTER_INTERFACE \
+	.bInterfaceClass	= USB_CLASS_COMM, \
+	.bInterfaceSubClass	= USB_CDC_SUBCLASS_ETHERNET, \
+	.bInterfaceProtocol	= USB_CDC_PROTO_NONE
+
+/* SA-1100 based Sharp Zaurus ("collie"), or compatible. */
+{
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8004,
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info = ZAURUS_STRONGARM_INFO,
+},
+
+/* PXA-2xx based models are also lying-about-cdc.  If you add any
+ * more devices that claim to be CDC Ethernet, make sure they get
+ * added to the blacklist in cdc_ether too.
+ *
+ * NOTE:  OpenZaurus versions with 2.6 kernels won't use these entries,
+ * unlike the older ones with 2.4 "embedix" kernels.
+ */
+{
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8005,	/* A-300 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info = ZAURUS_PXA_INFO,
+}, {
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8006,	/* B-500/SL-5600 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info = ZAURUS_PXA_INFO,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+	          | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8007,	/* C-700 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info = ZAURUS_PXA_INFO,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+		 | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor               = 0x04DD,
+	.idProduct              = 0x9031,	/* C-750 C-760 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info = ZAURUS_PXA_INFO,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+		 | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor               = 0x04DD,
+	.idProduct              = 0x9032,	/* SL-6000 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info = ZAURUS_PXA_INFO,
+}, {
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+		 | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor               = 0x04DD,
+	/* reported with some C860 units */
+	.idProduct              = 0x9050,	/* C-860 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info = ZAURUS_PXA_INFO,
+},
+
+
+/* At least some of the newest PXA units have very different lies about
+ * their standards support:  they claim to be cell phones offering
+ * direct access to their radios!  (No, they don't conform to CDC MDLM.)
+ */
+{
+	USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM,
+			USB_CDC_PROTO_NONE),
+	.driver_info = (unsigned long) &bogus_mdlm_info,
+},
+
+/* Olympus has some models with a Zaurus-compatible option.
+ * R-1000 uses a FreeScale i.MXL cpu (ARMv4T)
+ */
+{
+	.match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+		 | USB_DEVICE_ID_MATCH_DEVICE,
+	.idVendor               = 0x07B4,
+	.idProduct              = 0x0F02,	/* R-1000 */
+	ZAURUS_MASTER_INTERFACE,
+	.driver_info = OLYMPUS_MXL_INFO,
+},
+	{ },		// END
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver zaurus_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"zaurus",
+	.id_table =	products,
+	.probe =	usbnet_probe,
+	.disconnect =	usbnet_disconnect,
+	.suspend =	usbnet_suspend,
+	.resume =	usbnet_resume,
+};
+
+static int __init zaurus_init(void)
+{
+ 	return usb_register(&zaurus_driver);
+}
+module_init(zaurus_init);
+
+static void __exit zaurus_exit(void)
+{
+ 	usb_deregister(&zaurus_driver);
+}
+module_exit(zaurus_exit);
+
+MODULE_AUTHOR("Pavel Machek, David Brownell");
+MODULE_DESCRIPTION("Sharp Zaurus PDA, and compatible products");
+MODULE_LICENSE("GPL");

+ 0 - 1
drivers/usb/net/zd1201.c

@@ -847,7 +847,6 @@ static void zd1201_tx_timeout(struct net_device *dev)
 		return;
 	dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n",
 	    dev->name);
-	zd->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 	usb_unlink_urb(zd->tx_urb);
 	zd->stats.tx_errors++;
 	/* Restart the timeout to quiet the watchdog: */

+ 152 - 99
drivers/usb/serial/cypress_m8.c

@@ -453,8 +453,8 @@ static int generic_startup (struct usb_serial *serial)
 	priv->cbr_mask = B300;
 	usb_set_serial_port_data(serial->port[0], priv);
 	
-	return (0);	
-}	
+	return 0;
+}
 
 
 static int cypress_earthmate_startup (struct usb_serial *serial)
@@ -464,14 +464,15 @@ static int cypress_earthmate_startup (struct usb_serial *serial)
 	dbg("%s", __FUNCTION__);
 
 	if (generic_startup(serial)) {
-		dbg("%s - Failed setting up port %d", __FUNCTION__, serial->port[0]->number);
+		dbg("%s - Failed setting up port %d", __FUNCTION__,
+				serial->port[0]->number);
 		return 1;
 	}
 
 	priv = usb_get_serial_port_data(serial->port[0]);
 	priv->chiptype = CT_EARTHMATE;
-	
-	return (0);	
+
+	return 0;
 } /* cypress_earthmate_startup */
 
 
@@ -482,14 +483,15 @@ static int cypress_hidcom_startup (struct usb_serial *serial)
 	dbg("%s", __FUNCTION__);
 
 	if (generic_startup(serial)) {
-		dbg("%s - Failed setting up port %d", __FUNCTION__, serial->port[0]->number);
+		dbg("%s - Failed setting up port %d", __FUNCTION__,
+				serial->port[0]->number);
 		return 1;
 	}
 
 	priv = usb_get_serial_port_data(serial->port[0]);
 	priv->chiptype = CT_CYPHIDCOM;
 	
-	return (0);	
+	return 0;
 } /* cypress_hidcom_startup */
 
 
@@ -909,7 +911,8 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi
 } /* cypress_ioctl */
 
 
-static void cypress_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void cypress_set_termios (struct usb_serial_port *port,
+		struct termios *old_termios)
 {
 	struct cypress_private *priv = usb_get_serial_port_data(port);
 	struct tty_struct *tty;
@@ -918,7 +921,7 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
 	unsigned long flags;
 	__u8 oldlines;
 	int linechange = 0;
-	
+
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	tty = port->tty;
@@ -931,10 +934,12 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
 	if (!priv->termios_initialized) {
 		if (priv->chiptype == CT_EARTHMATE) {
 			*(tty->termios) = tty_std_termios;
-			tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
+			tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL |
+				CLOCAL;
 		} else if (priv->chiptype == CT_CYPHIDCOM) {
 			*(tty->termios) = tty_std_termios;
-			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
+				CLOCAL;
 		}
 		priv->termios_initialized = 1;
 	}
@@ -946,12 +951,15 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
 	/* check if there are new settings */
 	if (old_termios) {
 		if ((cflag != old_termios->c_cflag) ||
-		    (RELEVANT_IFLAG(iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg("%s - attempting to set new termios settings", __FUNCTION__);
-			/* should make a copy of this in case something goes wrong in the function, we can restore it */
+			(RELEVANT_IFLAG(iflag) !=
+			 RELEVANT_IFLAG(old_termios->c_iflag))) {
+			dbg("%s - attempting to set new termios settings",
+					__FUNCTION__);
+			/* should make a copy of this in case something goes
+			 * wrong in the function, we can restore it */
 			spin_lock_irqsave(&priv->lock, flags);
 			priv->tmp_termios = *(tty->termios);
-			spin_unlock_irqrestore(&priv->lock, flags); 
+			spin_unlock_irqrestore(&priv->lock, flags);
 		} else {
 			dbg("%s - nothing to do, exiting", __FUNCTION__);
 			return;
@@ -962,21 +970,34 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
 	/* set number of data bits, parity, stop bits */
 	/* when parity is disabled the parity type bit is ignored */
 
-	stop_bits = cflag & CSTOPB ? 1 : 0; /* 1 means 2 stop bits, 0 means 1 stop bit */
-	
+	/* 1 means 2 stop bits, 0 means 1 stop bit */
+	stop_bits = cflag & CSTOPB ? 1 : 0;
+
 	if (cflag & PARENB) {
 		parity_enable = 1;
-		parity_type = cflag & PARODD ? 1 : 0; /* 1 means odd parity, 0 means even parity */
+		/* 1 means odd parity, 0 means even parity */
+		parity_type = cflag & PARODD ? 1 : 0;
 	} else
 		parity_enable = parity_type = 0;
 
 	if (cflag & CSIZE) {
 		switch (cflag & CSIZE) {
-			case CS5: data_bits = 0; break;
-			case CS6: data_bits = 1; break;
-			case CS7: data_bits = 2; break;
-			case CS8: data_bits = 3; break;
-			default: err("%s - CSIZE was set, but not CS5-CS8", __FUNCTION__); data_bits = 3;
+			case CS5:
+				data_bits = 0;
+				break;
+			case CS6:
+				data_bits = 1;
+				break;
+			case CS7:
+				data_bits = 2;
+				break;
+			case CS8:
+				data_bits = 3;
+				break;
+			default:
+				err("%s - CSIZE was set, but not CS5-CS8",
+						__FUNCTION__);
+				data_bits = 3;
 		}
 	} else
 		data_bits = 3;
@@ -991,63 +1012,85 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
 	} else {
 		baud_mask = (cflag & CBAUD);
 		switch(baud_mask) {
-			case B300: dbg("%s - setting baud 300bps", __FUNCTION__); break;
-			case B600: dbg("%s - setting baud 600bps", __FUNCTION__); break;
-			case B1200: dbg("%s - setting baud 1200bps", __FUNCTION__); break;
-			case B2400: dbg("%s - setting baud 2400bps", __FUNCTION__); break;
-			case B4800: dbg("%s - setting baud 4800bps", __FUNCTION__); break;
-			case B9600: dbg("%s - setting baud 9600bps", __FUNCTION__); break;
-			case B19200: dbg("%s - setting baud 19200bps", __FUNCTION__); break;
-			case B38400: dbg("%s - setting baud 38400bps", __FUNCTION__); break;
-			case B57600: dbg("%s - setting baud 57600bps", __FUNCTION__); break;
-			case B115200: dbg("%s - setting baud 115200bps", __FUNCTION__); break;
-			default: dbg("%s - unknown masked baud rate", __FUNCTION__);
+			case B300:
+				dbg("%s - setting baud 300bps", __FUNCTION__);
+				break;
+			case B600:
+				dbg("%s - setting baud 600bps", __FUNCTION__);
+				break;
+			case B1200:
+				dbg("%s - setting baud 1200bps", __FUNCTION__);
+				break;
+			case B2400:
+				dbg("%s - setting baud 2400bps", __FUNCTION__);
+				break;
+			case B4800:
+				dbg("%s - setting baud 4800bps", __FUNCTION__);
+				break;
+			case B9600:
+				dbg("%s - setting baud 9600bps", __FUNCTION__);
+				break;
+			case B19200:
+				dbg("%s - setting baud 19200bps", __FUNCTION__);
+				break;
+			case B38400:
+				dbg("%s - setting baud 38400bps", __FUNCTION__);
+				break;
+			case B57600:
+				dbg("%s - setting baud 57600bps", __FUNCTION__);
+				break;
+			case B115200:
+				dbg("%s - setting baud 115200bps", __FUNCTION__);
+				break;
+			default:
+				dbg("%s - unknown masked baud rate", __FUNCTION__);
 		}
 		priv->line_control = (CONTROL_DTR | CONTROL_RTS);
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
-	
-	dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, %d data_bits (+5)", __FUNCTION__,
-	    stop_bits, parity_enable, parity_type, data_bits);
 
-	cypress_serial_control(port, baud_mask, data_bits, stop_bits, parity_enable,
-			       parity_type, 0, CYPRESS_SET_CONFIG);
+	dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, "
+			"%d data_bits (+5)", __FUNCTION__, stop_bits,
+			parity_enable, parity_type, data_bits);
+
+	cypress_serial_control(port, baud_mask, data_bits, stop_bits,
+			parity_enable, parity_type, 0, CYPRESS_SET_CONFIG);
 
-	/* we perform a CYPRESS_GET_CONFIG so that the current settings are filled into the private structure
-         * this should confirm that all is working if it returns what we just set */
+	/* we perform a CYPRESS_GET_CONFIG so that the current settings are
+	 * filled into the private structure this should confirm that all is
+	 * working if it returns what we just set */
 	cypress_serial_control(port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG);
 
-	/* Here we can define custom tty settings for devices
-         *
-         * the main tty termios flag base comes from empeg.c
-         */
+	/* Here we can define custom tty settings for devices; the main tty
+	 * termios flag base comes from empeg.c */
 
-	spin_lock_irqsave(&priv->lock, flags);	
+	spin_lock_irqsave(&priv->lock, flags);
 	if ( (priv->chiptype == CT_EARTHMATE) && (priv->baud_rate == 4800) ) {
-
-		dbg("Using custom termios settings for a baud rate of 4800bps.");
+		dbg("Using custom termios settings for a baud rate of "
+				"4800bps.");
 		/* define custom termios settings for NMEA protocol */
 
 		tty->termios->c_iflag /* input modes - */
-			&= ~(IGNBRK		/* disable ignore break */
-			| BRKINT		/* disable break causes interrupt */
-			| PARMRK		/* disable mark parity errors */
-			| ISTRIP		/* disable clear high bit of input characters */
-			| INLCR			/* disable translate NL to CR */
-			| IGNCR			/* disable ignore CR */
-			| ICRNL			/* disable translate CR to NL */
-			| IXON);		/* disable enable XON/XOFF flow control */
-		
+			&= ~(IGNBRK  /* disable ignore break */
+			| BRKINT     /* disable break causes interrupt */
+			| PARMRK     /* disable mark parity errors */
+			| ISTRIP     /* disable clear high bit of input char */
+			| INLCR      /* disable translate NL to CR */
+			| IGNCR      /* disable ignore CR */
+			| ICRNL      /* disable translate CR to NL */
+			| IXON);     /* disable enable XON/XOFF flow control */
+
 		tty->termios->c_oflag /* output modes */
-			&= ~OPOST;		/* disable postprocess output characters */
-		
-		tty->termios->c_lflag /* line discipline modes */
-			&= ~(ECHO 		/* disable echo input characters */
-			| ECHONL		/* disable echo new line */
-			| ICANON		/* disable erase, kill, werase, and rprnt special characters */
-			| ISIG			/* disable interrupt, quit, and suspend special characters */
-			| IEXTEN);		/* disable non-POSIX special characters */
+			&= ~OPOST;    /* disable postprocess output char */
 
+		tty->termios->c_lflag /* line discipline modes */
+			&= ~(ECHO     /* disable echo input characters */
+			| ECHONL      /* disable echo new line */
+			| ICANON      /* disable erase, kill, werase, and rprnt
+					 special characters */
+			| ISIG        /* disable interrupt, quit, and suspend
+					 special characters */
+			| IEXTEN);    /* disable non-POSIX special characters */
 	} /* CT_CYPHIDCOM: Application should handle this for device */
 
 	linechange = (priv->line_control != oldlines);
@@ -1060,7 +1103,7 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
 	}
 } /* cypress_set_termios */
 
- 
+
 /* returns amount of data still left in soft buffer */
 static int cypress_chars_in_buffer(struct usb_serial_port *port)
 {
@@ -1088,7 +1131,7 @@ static void cypress_throttle (struct usb_serial_port *port)
 
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->rx_flags = THROTTLED;
-	spin_unlock_irqrestore(&priv->lock, flags);	   
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 
@@ -1110,7 +1153,8 @@ static void cypress_unthrottle (struct usb_serial_port *port)
 
 		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 		if (result)
-			dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+			dev_err(&port->dev, "%s - failed submitting read urb, "
+					"error %d\n", __FUNCTION__, result);
 	}
 }
 
@@ -1122,7 +1166,7 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	unsigned long flags;
-	char tty_flag = TTY_NORMAL;	
+	char tty_flag = TTY_NORMAL;
 	int havedata = 0;
 	int bytes = 0;
 	int result;
@@ -1131,7 +1175,8 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (urb->status) {
-		dbg("%s - nonzero read status received: %d", __FUNCTION__, urb->status);
+		dbg("%s - nonzero read status received: %d", __FUNCTION__,
+				urb->status);
 		return;
 	}
 
@@ -1155,51 +1200,55 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
 		case 32:
 			/* This is for the CY7C64013... */
 			priv->current_status = data[0] & 0xF8;
-			bytes = data[1]+2;
-			i=2;
+			bytes = data[1] + 2;
+			i = 2;
 			if (bytes > 2)
 				havedata = 1;
 			break;
 		case 8:
 			/* This is for the CY7C63743... */
 			priv->current_status = data[0] & 0xF8;
-			bytes = (data[0] & 0x07)+1;
-			i=1;
+			bytes = (data[0] & 0x07) + 1;
+			i = 1;
 			if (bytes > 1)
 				havedata = 1;
 			break;
 		default:
-			dbg("%s - wrong packet size - received %d bytes", __FUNCTION__, urb->actual_length);
+			dbg("%s - wrong packet size - received %d bytes",
+					__FUNCTION__, urb->actual_length);
 			spin_unlock_irqrestore(&priv->lock, flags);
 			goto continue_read;
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	usb_serial_debug_data (debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+	usb_serial_debug_data (debug, &port->dev, __FUNCTION__,
+			urb->actual_length, data);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	/* check to see if status has changed */
 	if (priv != NULL) {
 		if (priv->current_status != priv->prev_status) {
-			priv->diff_status |= priv->current_status ^ priv->prev_status;
+			priv->diff_status |= priv->current_status ^
+				priv->prev_status;
 			wake_up_interruptible(&priv->delta_msr_wait);
 			priv->prev_status = priv->current_status;
 		}
 	}
-	spin_unlock_irqrestore(&priv->lock, flags);	
+	spin_unlock_irqrestore(&priv->lock, flags);
 
-	/* hangup, as defined in acm.c... this might be a bad place for it though */
-	if (tty && !(tty->termios->c_cflag & CLOCAL) && !(priv->current_status & UART_CD)) {
+	/* hangup, as defined in acm.c... this might be a bad place for it
+	 * though */
+	if (tty && !(tty->termios->c_cflag & CLOCAL) &&
+			!(priv->current_status & UART_CD)) {
 		dbg("%s - calling hangup", __FUNCTION__);
 		tty_hangup(tty);
 		goto continue_read;
 	}
 
-	/* There is one error bit... I'm assuming it is a parity error indicator
-	 * as the generic firmware will set this bit to 1 if a parity error occurs.
-	 * I can not find reference to any other error events.
-	 *
-	 */
+	/* There is one error bit... I'm assuming it is a parity error
+	 * indicator as the generic firmware will set this bit to 1 if a
+	 * parity error occurs.
+	 * I can not find reference to any other error events. */
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->current_status & CYP_ERROR) {
 		spin_unlock_irqrestore(&priv->lock, flags);
@@ -1211,7 +1260,8 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
 	/* process read if there is data other than line status */
 	if (tty && (bytes > i)) {
 		for (; i < bytes ; ++i) {
-			dbg("pushing byte number %d - %d - %c",i,data[i],data[i]);
+			dbg("pushing byte number %d - %d - %c", i, data[i],
+					data[i]);
 			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
 				tty_flip_buffer_push(tty);
 			}
@@ -1221,25 +1271,28 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
-	priv->bytes_in += bytes;  /* control and status byte(s) are also counted */
+	/* control and status byte(s) are also counted */
+	priv->bytes_in += bytes;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 continue_read:
-	
-	/* Continue trying to always read... unless the port has closed.  */
+
+	/* Continue trying to always read... unless the port has closed. */
 
 	if (port->open_count > 0) {
-	usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
-		usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress),
-		port->interrupt_in_urb->transfer_buffer,
-		port->interrupt_in_urb->transfer_buffer_length,
-		cypress_read_int_callback, port,
-		interval);
-	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
-	if (result)
-		dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+		usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
+				usb_rcvintpipe(port->serial->dev,
+					port->interrupt_in_endpointAddress),
+				port->interrupt_in_urb->transfer_buffer,
+				port->interrupt_in_urb->transfer_buffer_length,
+				cypress_read_int_callback, port, interval);
+		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+		if (result)
+			dev_err(&urb->dev->dev, "%s - failed resubmitting "
+					"read urb, error %d\n", __FUNCTION__,
+					result);
 	}
-	
+
 	return;
 } /* cypress_read_int_callback */
 

+ 55 - 1
drivers/usb/serial/ftdi_sio.c

@@ -269,6 +269,8 @@
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
 static int debug;
+static __u16 vendor = FTDI_VID;
+static __u16 product;
 
 /* struct ftdi_sio_quirk is used by devices requiring special attention. */
 struct ftdi_sio_quirk {
@@ -407,6 +409,34 @@ static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) },
+	/*
+	 * These will probably use user-space drivers.  Uncomment them if
+	 * you need them or use the user-specified vendor/product module
+	 * parameters (see ftdi_sio.h for the numbers).  Make a fuss if
+	 * you think the driver should recognize any of them by default.
+	 */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
+	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
  	{ USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
  	{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
  	{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
@@ -418,6 +448,7 @@ static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
 	{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
 	{ USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
+	{ USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
 	{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
@@ -427,12 +458,21 @@ static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
+	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
+	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) },
+	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) },
+	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_3_PID) },
+	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_4_PID) },
+	{ 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(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
 	{ USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
-	{ }						/* Terminating entry */
+	{ },					/* Optional parameter entry */
+	{ }					/* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
@@ -2030,6 +2070,15 @@ static int __init ftdi_init (void)
 	int retval;
 
 	dbg("%s", __FUNCTION__);
+	if (vendor > 0 && product > 0) {
+		/* Add user specified VID/PID to reserved element of table. */
+		int i;
+		for (i = 0; id_table_combined[i].idVendor; i++)
+			;
+		id_table_combined[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+		id_table_combined[i].idVendor = vendor;
+		id_table_combined[i].idProduct = product;
+	}
 	retval = usb_serial_register(&ftdi_sio_device);
 	if (retval)
 		goto failed_sio_register;
@@ -2066,4 +2115,9 @@ MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(vendor, ushort, 0);
+MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
+		__MODULE_STRING(FTDI_VID)")");
+module_param(product, ushort, 0);
+MODULE_PARM_DESC(vendor, "User specified product ID");
 

+ 50 - 4
drivers/usb/serial/ftdi_sio.h

@@ -142,10 +142,43 @@
 /* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
 #define FTDI_USB_UIRT_PID	0xF850	/* Product Id */
 
-/* ELV USB Module UO100 (PID sent by Stefan Frings) */
-#define FTDI_ELV_UO100_PID	0xFB58	/* Product Id */
-/* ELV USB Module UM100 (PID sent by Arnim Laeuger) */
-#define FTDI_ELV_UM100_PID	0xFB5A	/* Product Id */
+/*
+ * ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
+ * All of these devices use FTDI's vendor ID (0x0403).
+ *
+ * The previously included PID for the UO 100 module was incorrect.
+ * In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58).
+ *
+ * Armin Laeuger originally sent the PID for the UM 100 module.
+ */
+#define FTDI_ELV_UR100_PID	0xFB58	/* USB-RS232-Umsetzer (UR 100) */
+#define FTDI_ELV_UM100_PID	0xFB5A	/* USB-Modul UM 100 */
+#define FTDI_ELV_UO100_PID	0xFB5B	/* USB-Modul UO 100 */
+#define FTDI_ELV_ALC8500_PID	0xF06E	/* ALC 8500 Expert */
+/* Additional ELV PIDs that default to using the FTDI D2XX drivers on
+ * MS Windows, rather than the FTDI Virtual Com Port drivers.
+ * Maybe these will be easier to use with the libftdi/libusb user-space
+ * drivers, or possibly the Comedi drivers in some cases. */
+#define FTDI_ELV_CLI7000_PID	0xFB59	/* Computer-Light-Interface (CLI 7000) */
+#define FTDI_ELV_PPS7330_PID	0xFB5C	/* Processor-Power-Supply (PPS 7330) */
+#define FTDI_ELV_TFM100_PID	0xFB5D	/* Temperartur-Feuchte Messgeraet (TFM 100) */
+#define FTDI_ELV_UDF77_PID	0xFB5E	/* USB DCF Funkurh (UDF 77) */
+#define FTDI_ELV_UIO88_PID	0xFB5F	/* USB-I/O Interface (UIO 88) */
+#define FTDI_ELV_UAD8_PID	0xF068	/* USB-AD-Wandler (UAD 8) */
+#define FTDI_ELV_UDA7_PID	0xF069	/* USB-DA-Wandler (UDA 7) */
+#define FTDI_ELV_USI2_PID	0xF06A	/* USB-Schrittmotoren-Interface (USI 2) */
+#define FTDI_ELV_T1100_PID	0xF06B	/* Thermometer (T 1100) */
+#define FTDI_ELV_PCD200_PID	0xF06C	/* PC-Datenlogger (PCD 200) */
+#define FTDI_ELV_ULA200_PID	0xF06D	/* USB-LCD-Ansteuerung (ULA 200) */
+#define FTDI_ELV_FHZ1000PC_PID	0xF06F	/* FHZ 1000 PC */
+#define FTDI_ELV_CSI8_PID	0xE0F0	/* Computer-Schalt-Interface (CSI 8) */
+#define FTDI_ELV_EM1000DL_PID	0xE0F1	/* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */
+#define FTDI_ELV_PCK100_PID	0xE0F2	/* PC-Kabeltester (PCK 100) */
+#define FTDI_ELV_RFP500_PID	0xE0F3	/* HF-Leistungsmesser (RFP 500) */
+#define FTDI_ELV_FS20SIG_PID	0xE0F4	/* Signalgeber (FS 20 SIG) */
+#define FTDI_ELV_WS300PC_PID	0xE0F6	/* PC-Wetterstation (WS 300 PC) */
+#define FTDI_ELV_FHZ1300PC_PID	0xE0E8	/* FHZ 1300 PC */
+#define FTDI_ELV_WS500_PID	0xE0E9	/* PC-Wetterstation (WS 500) */
 
 /*
  * Definitions for ID TECH (www.idt-net.com) devices
@@ -222,6 +255,7 @@
  */
 #define FALCOM_VID		0x0F94	/* Vendor Id */
 #define FALCOM_TWIST_PID	0x0001	/* Falcom Twist USB GPRS modem */
+#define FALCOM_SAMBA_PID	0x0005	/* Falcom Samba USB GPRS modem */
 
 /*
  * SUUNTO product ids
@@ -276,6 +310,18 @@
  */
 #define FTDI_ACTIVE_ROBOTS_PID	0xE548	/* USB comms board */
 
+/*
+ * Xsens Technologies BV products (http://www.xsens.com).
+ */
+#define XSENS_CONVERTER_0_PID	0xD388
+#define XSENS_CONVERTER_1_PID	0xD389
+#define XSENS_CONVERTER_2_PID	0xD38A
+#define XSENS_CONVERTER_3_PID	0xD38B
+#define XSENS_CONVERTER_4_PID	0xD38C
+#define XSENS_CONVERTER_5_PID	0xD38D
+#define XSENS_CONVERTER_6_PID	0xD38E
+#define XSENS_CONVERTER_7_PID	0xD38F
+
 /*
  * Evolution Robotics products (http://www.evolution.com/).
  * Submitted by Shawn M. Lavelle.

+ 1 - 7
drivers/usb/serial/keyspan.c

@@ -383,11 +383,8 @@ static int keyspan_write(struct usb_serial_port *port,
 		dbg("%s - endpoint %d flip %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), flip);
 
 		if (this_urb->status == -EINPROGRESS) {
-			if (this_urb->transfer_flags & URB_ASYNC_UNLINK)
-				break;
 			if (time_before(jiffies, p_priv->tx_start_time[flip] + 10 * HZ))
 				break;
-			this_urb->transfer_flags |= URB_ASYNC_UNLINK;
 			usb_unlink_urb(this_urb);
 			break;
 		}
@@ -402,7 +399,6 @@ static int keyspan_write(struct usb_serial_port *port,
 		/* send the data out the bulk port */
 		this_urb->transfer_buffer_length = todo + dataOffset;
 
-		this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 		this_urb->dev = port->serial->dev;
 		if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
 			dbg("usb_submit_urb(write bulk) failed (%d)", err);
@@ -1119,10 +1115,8 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
 
 static inline void stop_urb(struct urb *urb)
 {
-	if (urb && urb->status == -EINPROGRESS) {
-		urb->transfer_flags &= ~URB_ASYNC_UNLINK;
+	if (urb && urb->status == -EINPROGRESS)
 		usb_kill_urb(urb);
-	}
 }
 
 static void keyspan_close(struct usb_serial_port *port, struct file *filp)

+ 90 - 113
drivers/usb/serial/option.c

@@ -45,29 +45,29 @@
 #include "usb-serial.h"
 
 /* Function prototypes */
-static int  option_open (struct usb_serial_port *port, struct file *filp);
-static void option_close (struct usb_serial_port *port, struct file *filp);
-static int  option_startup (struct usb_serial *serial);
-static void option_shutdown (struct usb_serial *serial);
-static void option_rx_throttle (struct usb_serial_port *port);
-static void option_rx_unthrottle (struct usb_serial_port *port);
-static int  option_write_room (struct usb_serial_port *port);
+static int  option_open(struct usb_serial_port *port, struct file *filp);
+static void option_close(struct usb_serial_port *port, struct file *filp);
+static int  option_startup(struct usb_serial *serial);
+static void option_shutdown(struct usb_serial *serial);
+static void option_rx_throttle(struct usb_serial_port *port);
+static void option_rx_unthrottle(struct usb_serial_port *port);
+static int  option_write_room(struct usb_serial_port *port);
 
 static void option_instat_callback(struct urb *urb, struct pt_regs *regs);
 
-static int  option_write (struct usb_serial_port *port,
-                          const unsigned char *buf, int count);
+static int option_write(struct usb_serial_port *port,
+			const unsigned char *buf, int count);
 
-static int  option_chars_in_buffer (struct usb_serial_port *port);
-static int  option_ioctl (struct usb_serial_port *port, struct file *file,
-                          unsigned int cmd, unsigned long arg);
-static void option_set_termios (struct usb_serial_port *port,
-                                struct termios *old);
-static void option_break_ctl (struct usb_serial_port *port, int break_state);
-static int  option_tiocmget (struct usb_serial_port *port, struct file *file);
-static int  option_tiocmset (struct usb_serial_port *port, struct file *file,
-                             unsigned int set, unsigned int clear);
-static int  option_send_setup (struct usb_serial_port *port);
+static int  option_chars_in_buffer(struct usb_serial_port *port);
+static int  option_ioctl(struct usb_serial_port *port, struct file *file,
+			unsigned int cmd, unsigned long arg);
+static void option_set_termios(struct usb_serial_port *port,
+				struct termios *old);
+static void option_break_ctl(struct usb_serial_port *port, int break_state);
+static int  option_tiocmget(struct usb_serial_port *port, struct file *file);
+static int  option_tiocmset(struct usb_serial_port *port, struct file *file,
+				unsigned int set, unsigned int clear);
+static int  option_send_setup(struct usb_serial_port *port);
 
 /* Vendor and product IDs */
 #define OPTION_VENDOR_ID			0x0AF0
@@ -76,7 +76,6 @@ static int  option_send_setup (struct usb_serial_port *port);
 #define OPTION_PRODUCT_FUSION	0x6000
 #define OPTION_PRODUCT_FUSION2	0x6300
 
-
 static struct usb_device_id option_ids[] = {
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
@@ -129,7 +128,6 @@ static int debug;
 #define debug 0
 #endif
 
-
 /* per port private data */
 
 #define N_IN_URB 4
@@ -156,10 +154,8 @@ struct option_port_private {
 	unsigned long tx_start_time[N_OUT_URB];
 };
 
-
 /* Functions used by new usb-serial code. */
-static int __init
-option_init (void)
+static int __init option_init(void)
 {
 	int retval;
 	retval = usb_serial_register(&option_3port_device);
@@ -179,8 +175,7 @@ failed_3port_device_register:
 	return retval;
 }
 
-static void __exit
-option_exit (void)
+static void __exit option_exit(void)
 {
 	usb_deregister (&option_driver);
 	usb_serial_deregister (&option_3port_device);
@@ -189,39 +184,31 @@ option_exit (void)
 module_init(option_init);
 module_exit(option_exit);
 
-static void
-option_rx_throttle (struct usb_serial_port *port)
+static void option_rx_throttle(struct usb_serial_port *port)
 {
 	dbg("%s", __FUNCTION__);
 }
 
-
-static void
-option_rx_unthrottle (struct usb_serial_port *port)
+static void option_rx_unthrottle(struct usb_serial_port *port)
 {
 	dbg("%s", __FUNCTION__);
 }
 
-
-static void
-option_break_ctl (struct usb_serial_port *port, int break_state)
+static void option_break_ctl(struct usb_serial_port *port, int break_state)
 {
 	/* Unfortunately, I don't know how to send a break */
 	dbg("%s", __FUNCTION__);
 }
 
-
-static void
-option_set_termios (struct usb_serial_port *port,
-                    struct termios *old_termios)
+static void option_set_termios(struct usb_serial_port *port,
+			struct termios *old_termios)
 {
 	dbg("%s", __FUNCTION__);
 
 	option_send_setup(port);
 }
 
-static int
-option_tiocmget (struct usb_serial_port *port, struct file *file)
+static int option_tiocmget(struct usb_serial_port *port, struct file *file)
 {
 	unsigned int value;
 	struct option_port_private *portdata;
@@ -238,9 +225,8 @@ option_tiocmget (struct usb_serial_port *port, struct file *file)
 	return value;
 }
 
-static int
-option_tiocmset (struct usb_serial_port *port, struct file *file,
-                 unsigned int set, unsigned int clear)
+static int option_tiocmset(struct usb_serial_port *port, struct file *file,
+			unsigned int set, unsigned int clear)
 {
 	struct option_port_private *portdata;
 
@@ -258,17 +244,15 @@ option_tiocmset (struct usb_serial_port *port, struct file *file,
 	return option_send_setup(port);
 }
 
-static int
-option_ioctl (struct usb_serial_port *port, struct file *file,
-              unsigned int cmd, unsigned long arg)
+static int option_ioctl(struct usb_serial_port *port, struct file *file,
+			unsigned int cmd, unsigned long arg)
 {
 	return -ENOIOCTLCMD;
 }
 
 /* Write */
-static int
-option_write (struct usb_serial_port *port,
-			  const unsigned char *buf, int count)
+static int option_write(struct usb_serial_port *port,
+			const unsigned char *buf, int count)
 {
 	struct option_port_private *portdata;
 	int i;
@@ -289,28 +273,29 @@ option_write (struct usb_serial_port *port,
 
 		this_urb = portdata->out_urbs[i];
 		if (this_urb->status == -EINPROGRESS) {
-			if (this_urb->transfer_flags & URB_ASYNC_UNLINK)
-				continue;
-			if (time_before(jiffies, portdata->tx_start_time[i] + 10 * HZ))
+			if (time_before(jiffies,
+					portdata->tx_start_time[i] + 10 * HZ))
 				continue;
-			this_urb->transfer_flags |= URB_ASYNC_UNLINK;
 			usb_unlink_urb(this_urb);
 			continue;
 		}
 		if (this_urb->status != 0)
-			dbg("usb_write %p failed (err=%d)", this_urb, this_urb->status);
+			dbg("usb_write %p failed (err=%d)",
+				this_urb, this_urb->status);
 
-		dbg("%s: endpoint %d buf %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), i);
+		dbg("%s: endpoint %d buf %d", __FUNCTION__,
+			usb_pipeendpoint(this_urb->pipe), i);
 
 		/* send the data */
 		memcpy (this_urb->transfer_buffer, buf, todo);
 		this_urb->transfer_buffer_length = todo;
 
-		this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 		this_urb->dev = port->serial->dev;
 		err = usb_submit_urb(this_urb, GFP_ATOMIC);
 		if (err) {
-			dbg("usb_submit_urb %p (write bulk) failed (%d, has %d)", this_urb, err, this_urb->status);
+			dbg("usb_submit_urb %p (write bulk) failed "
+				"(%d, has %d)", this_urb,
+				err, this_urb->status);
 			continue;
 		}
 		portdata->tx_start_time[i] = jiffies;
@@ -323,8 +308,7 @@ option_write (struct usb_serial_port *port,
 	return count;
 }
 
-static void
-option_indat_callback (struct urb *urb, struct pt_regs *regs)
+static void option_indat_callback(struct urb *urb, struct pt_regs *regs)
 {
 	int i, err;
 	int endpoint;
@@ -357,14 +341,14 @@ option_indat_callback (struct urb *urb, struct pt_regs *regs)
 		if (port->open_count && urb->status != -ESHUTDOWN) {
 			err = usb_submit_urb(urb, GFP_ATOMIC);
 			if (err)
-				printk(KERN_ERR "%s: resubmit read urb failed. (%d)", __FUNCTION__, err);
+				printk(KERN_ERR "%s: resubmit read urb failed. "
+					"(%d)", __FUNCTION__, err);
 		}
 	}
 	return;
 }
 
-static void
-option_outdat_callback (struct urb *urb, struct pt_regs *regs)
+static void option_outdat_callback(struct urb *urb, struct pt_regs *regs)
 {
 	struct usb_serial_port *port;
 
@@ -376,8 +360,7 @@ option_outdat_callback (struct urb *urb, struct pt_regs *regs)
 		schedule_work(&port->work);
 }
 
-static void
-option_instat_callback (struct urb *urb, struct pt_regs *regs)
+static void option_instat_callback(struct urb *urb, struct pt_regs *regs)
 {
 	int err;
 	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
@@ -395,10 +378,12 @@ option_instat_callback (struct urb *urb, struct pt_regs *regs)
 			dbg("%s: NULL req_pkt\n", __FUNCTION__);
 			return;
 		}
-		if ((req_pkt->bRequestType == 0xA1) && (req_pkt->bRequest == 0x20)) {
+		if ((req_pkt->bRequestType == 0xA1) &&
+				(req_pkt->bRequest == 0x20)) {
 			int old_dcd_state;
 			unsigned char signals = *((unsigned char *)
-					urb->transfer_buffer + sizeof(struct usb_ctrlrequest));
+					urb->transfer_buffer +
+					sizeof(struct usb_ctrlrequest));
 
 			dbg("%s: signal x%x", __FUNCTION__, signals);
 
@@ -408,12 +393,13 @@ option_instat_callback (struct urb *urb, struct pt_regs *regs)
 			portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
 			portdata->ri_state = ((signals & 0x08) ? 1 : 0);
 
-			if (port->tty && !C_CLOCAL(port->tty)
-					&& old_dcd_state && !portdata->dcd_state) {
+			if (port->tty && !C_CLOCAL(port->tty) &&
+					old_dcd_state && !portdata->dcd_state)
 				tty_hangup(port->tty);
-			}
-		} else
-			dbg("%s: type %x req %x", __FUNCTION__, req_pkt->bRequestType,req_pkt->bRequest);
+		} else {
+			dbg("%s: type %x req %x", __FUNCTION__,
+				req_pkt->bRequestType,req_pkt->bRequest);
+		}
 	} else
 		dbg("%s: error %d", __FUNCTION__, urb->status);
 
@@ -422,13 +408,12 @@ option_instat_callback (struct urb *urb, struct pt_regs *regs)
 		urb->dev = serial->dev;
 		err = usb_submit_urb(urb, GFP_ATOMIC);
 		if (err)
-			dbg("%s: resubmit intr urb failed. (%d)", __FUNCTION__, err);
+			dbg("%s: resubmit intr urb failed. (%d)",
+				__FUNCTION__, err);
 	}
 }
 
-
-static int
-option_write_room (struct usb_serial_port *port)
+static int option_write_room(struct usb_serial_port *port)
 {
 	struct option_port_private *portdata;
 	int i;
@@ -447,9 +432,7 @@ option_write_room (struct usb_serial_port *port)
 	return data_len;
 }
 
-
-static int
-option_chars_in_buffer (struct usb_serial_port *port)
+static int option_chars_in_buffer(struct usb_serial_port *port)
 {
 	struct option_port_private *portdata;
 	int i;
@@ -467,9 +450,7 @@ option_chars_in_buffer (struct usb_serial_port *port)
 	return data_len;
 }
 
-
-static int
-option_open (struct usb_serial_port *port, struct file *filp)
+static int option_open(struct usb_serial_port *port, struct file *filp)
 {
 	struct option_port_private *portdata;
 	struct usb_serial *serial = port->serial;
@@ -490,17 +471,21 @@ option_open (struct usb_serial_port *port, struct file *filp)
 		if (! urb)
 			continue;
 		if (urb->dev != serial->dev) {
-			dbg("%s: dev %p != %p", __FUNCTION__, urb->dev, serial->dev);
+			dbg("%s: dev %p != %p", __FUNCTION__,
+				urb->dev, serial->dev);
 			continue;
 		}
 
-		/* make sure endpoint data toggle is synchronized with the device */
-
+		/*
+		 * make sure endpoint data toggle is synchronized with the
+		 * device
+		 */
 		usb_clear_halt(urb->dev, urb->pipe);
 
 		err = usb_submit_urb(urb, GFP_KERNEL);
 		if (err) {
-			dbg("%s: submit urb %d failed (%d) %d", __FUNCTION__, i, err,
+			dbg("%s: submit urb %d failed (%d) %d",
+				__FUNCTION__, i, err,
 				urb->transfer_buffer_length);
 		}
 	}
@@ -511,7 +496,8 @@ option_open (struct usb_serial_port *port, struct file *filp)
 		if (! urb)
 			continue;
 		urb->dev = serial->dev;
-		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */
+		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+				usb_pipeout(urb->pipe), 0); */
 	}
 
 	port->tty->low_latency = 1;
@@ -521,17 +507,13 @@ option_open (struct usb_serial_port *port, struct file *filp)
 	return (0);
 }
 
-static inline void
-stop_urb (struct urb *urb)
+static inline void stop_urb(struct urb *urb)
 {
-	if (urb && urb->status == -EINPROGRESS) {
-		urb->transfer_flags &= ~URB_ASYNC_UNLINK;
+	if (urb && urb->status == -EINPROGRESS)
 		usb_kill_urb(urb);
-	}
 }
 
-static void
-option_close (struct usb_serial_port *port, struct file *filp)
+static void option_close(struct usb_serial_port *port, struct file *filp)
 {
 	int i;
 	struct usb_serial *serial = port->serial;
@@ -555,12 +537,10 @@ option_close (struct usb_serial_port *port, struct file *filp)
 	port->tty = NULL;
 }
 
-
 /* Helper functions used by option_setup_urbs */
-static struct urb *
-option_setup_urb (struct usb_serial *serial, int endpoint,
-                  int dir, void *ctx, char *buf, int len,
-                  void (*callback)(struct urb *, struct pt_regs *regs))
+static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
+		int dir, void *ctx, char *buf, int len,
+		void (*callback)(struct urb *, struct pt_regs *regs))
 {
 	struct urb *urb;
 
@@ -582,8 +562,7 @@ option_setup_urb (struct usb_serial *serial, int endpoint,
 }
 
 /* Setup urbs */
-static void
-option_setup_urbs (struct usb_serial *serial)
+static void option_setup_urbs(struct usb_serial *serial)
 {
 	int j;
 	struct usb_serial_port *port;
@@ -609,9 +588,7 @@ option_setup_urbs (struct usb_serial *serial)
 	}
 }
 
-
-static int
-option_send_setup (struct usb_serial_port *port)
+static int option_send_setup(struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
 	struct option_port_private *portdata;
@@ -627,16 +604,15 @@ 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,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+		return usb_control_msg(serial->dev,
+				usb_rcvctrlpipe(serial->dev, 0),
+				0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
 	}
 
 	return 0;
 }
 
-
-static int
-option_startup (struct usb_serial *serial)
+static int option_startup(struct usb_serial *serial)
 {
 	int i, err;
 	struct usb_serial_port *port;
@@ -647,9 +623,10 @@ option_startup (struct usb_serial *serial)
 	/* Now setup per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
-		portdata = kmalloc(sizeof(struct option_port_private), GFP_KERNEL);
+		portdata = kmalloc(sizeof(*portdata), GFP_KERNEL);
 		if (!portdata) {
-			dbg("%s: kmalloc for option_port_private (%d) failed!.", __FUNCTION__, i);
+			dbg("%s: kmalloc for option_port_private (%d) failed!.",
+					__FUNCTION__, i);
 			return (1);
 		}
 		memset(portdata, 0, sizeof(struct option_port_private));
@@ -660,7 +637,8 @@ option_startup (struct usb_serial *serial)
 			continue;
 		err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (err)
-			dbg("%s: submit irq_in urb failed %d", __FUNCTION__, err);
+			dbg("%s: submit irq_in urb failed %d",
+				__FUNCTION__, err);
 	}
 
 	option_setup_urbs(serial);
@@ -668,8 +646,7 @@ option_startup (struct usb_serial *serial)
 	return (0);
 }
 
-static void
-option_shutdown (struct usb_serial *serial)
+static void option_shutdown(struct usb_serial *serial)
 {
 	int i, j;
 	struct usb_serial_port *port;

+ 4 - 2
drivers/usb/serial/pl2303.c

@@ -538,8 +538,10 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp)
 
 	dbg("%s -  port %d", __FUNCTION__, port->number);
 
-	usb_clear_halt(serial->dev, port->write_urb->pipe);
-	usb_clear_halt(serial->dev, port->read_urb->pipe);
+	if (priv->type != HX) {
+		usb_clear_halt(serial->dev, port->write_urb->pipe);
+		usb_clear_halt(serial->dev, port->read_urb->pipe);
+	}
 
 	buf = kmalloc(10, GFP_KERNEL);
 	if (buf==NULL)

+ 12 - 12
drivers/usb/serial/usb-serial.c

@@ -531,7 +531,7 @@ bailout_kref_put:
 
 static void serial_close(struct tty_struct *tty, struct file * filp)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial_port *port = tty->driver_data;
 
 	if (!port)
 		return;
@@ -561,7 +561,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
 
 static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial_port *port = tty->driver_data;
 	int retval = -EINVAL;
 
 	dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
@@ -580,7 +580,7 @@ exit:
 
 static int serial_write_room (struct tty_struct *tty) 
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial_port *port = tty->driver_data;
 	int retval = -EINVAL;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
@@ -599,7 +599,7 @@ exit:
 
 static int serial_chars_in_buffer (struct tty_struct *tty) 
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial_port *port = tty->driver_data;
 	int retval = -EINVAL;
 
 	dbg("%s = port %d", __FUNCTION__, port->number);
@@ -618,7 +618,7 @@ exit:
 
 static void serial_throttle (struct tty_struct * tty)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial_port *port = tty->driver_data;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -634,7 +634,7 @@ static void serial_throttle (struct tty_struct * tty)
 
 static void serial_unthrottle (struct tty_struct * tty)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial_port *port = tty->driver_data;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -650,7 +650,7 @@ static void serial_unthrottle (struct tty_struct * tty)
 
 static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial_port *port = tty->driver_data;
 	int retval = -ENODEV;
 
 	dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
@@ -672,7 +672,7 @@ exit:
 
 static void serial_set_termios (struct tty_struct *tty, struct termios * old)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial_port *port = tty->driver_data;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -688,7 +688,7 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
 
 static void serial_break (struct tty_struct *tty, int break_state)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial_port *port = tty->driver_data;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -749,7 +749,7 @@ done:
 
 static int serial_tiocmget (struct tty_struct *tty, struct file *file)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial_port *port = tty->driver_data;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -768,7 +768,7 @@ exit:
 static int serial_tiocmset (struct tty_struct *tty, struct file *file,
 			    unsigned int set, unsigned int clear)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial_port *port = tty->driver_data;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -786,7 +786,7 @@ exit:
 
 void usb_serial_port_softint(void *private)
 {
-	struct usb_serial_port *port = (struct usb_serial_port *)private;
+	struct usb_serial_port *port = private;
 	struct tty_struct *tty;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);

+ 12 - 0
drivers/usb/storage/Kconfig

@@ -111,3 +111,15 @@ config USB_STORAGE_JUMPSHOT
 	  Say Y here to include additional code to support the Lexar Jumpshot
 	  USB CompactFlash reader.
 
+
+config USB_STORAGE_ONETOUCH
+	bool "Support OneTouch Button on Maxtor Hard Drives (EXPERIMENTAL)"
+	depends on USB_STORAGE && INPUT_EVDEV && EXPERIMENTAL
+	help
+	  Say Y here to include additional code to support the Maxtor OneTouch
+	  USB hard drive's onetouch button.
+
+	  This code registers the button on the front of Maxtor OneTouch USB
+	  hard drive's as an input device. An action can be associated with
+	  this input in any keybinding software. (e.g. gnome's keyboard short-
+	  cuts)

+ 1 - 0
drivers/usb/storage/Makefile

@@ -18,6 +18,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM)	+= dpcm.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200)	+= isd200.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB)	+= datafab.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT)	+= jumpshot.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH)	+= onetouch.o
 
 usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
 			initializers.o $(usb-storage-obj-y)

+ 210 - 0
drivers/usb/storage/onetouch.c

@@ -0,0 +1,210 @@
+/*
+ * Support for the Maxtor OneTouch USB hard drive's button
+ *
+ * Current development and maintenance by:
+ *	Copyright (c) 2005 Nick Sillik <n.sillik@temple.edu>
+ *
+ * Initial work by:
+ * 	Copyright (c) 2003 Erik Thyren <erth7411@student.uu.se>
+ *
+ * Based on usbmouse.c (Vojtech Pavlik) and xpad.c (Marko Friedemann)
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_input.h>
+#include "usb.h"
+#include "onetouch.h"
+#include "debug.h"
+
+void onetouch_release_input(void *onetouch_);
+
+struct usb_onetouch {
+	char name[128];
+	char phys[64];
+	struct input_dev dev;	/* input device interface */
+	struct usb_device *udev;	/* usb device */
+
+	struct urb *irq;	/* urb for interrupt in report */
+	unsigned char *data;	/* input data */
+	dma_addr_t data_dma;
+};
+
+static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_onetouch *onetouch = urb->context;
+	signed char *data = onetouch->data;
+	struct input_dev *dev = &onetouch->dev;
+	int status;
+
+	switch (urb->status) {
+	case 0:			/* success */
+		break;
+	case -ECONNRESET:	/* unlink */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	/* -EPIPE:  should clear the halt */
+	default:		/* error */
+		goto resubmit;
+	}
+
+	input_regs(dev, regs);
+
+	input_report_key(&onetouch->dev, ONETOUCH_BUTTON,
+			 data[0] & 0x02);
+
+	input_sync(dev);
+resubmit:
+	status = usb_submit_urb (urb, SLAB_ATOMIC);
+	if (status)
+		err ("can't resubmit intr, %s-%s/input0, status %d",
+			onetouch->udev->bus->bus_name,
+			onetouch->udev->devpath, status);
+}
+
+static int usb_onetouch_open(struct input_dev *dev)
+{
+	struct usb_onetouch *onetouch = dev->private;
+
+	onetouch->irq->dev = onetouch->udev;
+	if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) {
+		err("usb_submit_urb failed");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void usb_onetouch_close(struct input_dev *dev)
+{
+	struct usb_onetouch *onetouch = dev->private;
+
+	usb_kill_urb(onetouch->irq);
+}
+
+int onetouch_connect_input(struct us_data *ss)
+{
+	struct usb_device *udev = ss->pusb_dev;
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_onetouch *onetouch;
+	int pipe, maxp;
+	char path[64];
+
+	interface = ss->pusb_intf->cur_altsetting;
+
+	if (interface->desc.bNumEndpoints != 3)
+		return -ENODEV;
+
+	endpoint = &interface->endpoint[2].desc;
+	if(!(endpoint->bEndpointAddress & USB_DIR_IN))
+		return -ENODEV;
+	if((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+			!= USB_ENDPOINT_XFER_INT)
+		return -ENODEV;
+
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+	if (!(onetouch = kcalloc(1, sizeof(struct usb_onetouch), GFP_KERNEL)))
+		return -ENOMEM;
+
+	onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN,
+					  SLAB_ATOMIC, &onetouch->data_dma);
+	if (!onetouch->data){
+		kfree(onetouch);
+		return -ENOMEM;
+	}
+
+	onetouch->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!onetouch->irq){
+		kfree(onetouch);
+		usb_buffer_free(udev, ONETOUCH_PKT_LEN,
+				onetouch->data, onetouch->data_dma);
+		return -ENODEV;
+	}
+
+
+	onetouch->udev = udev;
+
+	set_bit(EV_KEY, onetouch->dev.evbit);
+	set_bit(ONETOUCH_BUTTON, onetouch->dev.keybit);
+	clear_bit(0, onetouch->dev.keybit);
+
+	onetouch->dev.private = onetouch;
+	onetouch->dev.open = usb_onetouch_open;
+	onetouch->dev.close = usb_onetouch_close;
+
+	usb_make_path(udev, path, sizeof(path));
+	sprintf(onetouch->phys, "%s/input0", path);
+
+	onetouch->dev.name = onetouch->name;
+	onetouch->dev.phys = onetouch->phys;
+
+	usb_to_input_id(udev, &onetouch->dev.id);
+
+	onetouch->dev.dev = &udev->dev;
+
+	if (udev->manufacturer)
+		strcat(onetouch->name, udev->manufacturer);
+	if (udev->product)
+		sprintf(onetouch->name, "%s %s", onetouch->name,
+			udev->product);
+	if (!strlen(onetouch->name))
+		sprintf(onetouch->name, "Maxtor Onetouch %04x:%04x",
+			onetouch->dev.id.vendor, onetouch->dev.id.product);
+
+	usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data,
+			 (maxp > 8 ? 8 : maxp),
+			 usb_onetouch_irq, onetouch, endpoint->bInterval);
+	onetouch->irq->transfer_dma = onetouch->data_dma;
+	onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	ss->extra_destructor = onetouch_release_input;
+	ss->extra = onetouch;
+
+	input_register_device(&onetouch->dev);
+	printk(KERN_INFO "usb-input: %s on %s\n", onetouch->dev.name, path);
+
+	return 0;
+}
+
+void onetouch_release_input(void *onetouch_)
+{
+	struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
+
+	if (onetouch) {
+		usb_kill_urb(onetouch->irq);
+		input_unregister_device(&onetouch->dev);
+		usb_free_urb(onetouch->irq);
+		usb_buffer_free(onetouch->udev, ONETOUCH_PKT_LEN,
+				onetouch->data, onetouch->data_dma);
+		printk(KERN_INFO "usb-input: deregistering %s\n",
+				onetouch->dev.name);
+	}
+}

+ 9 - 0
drivers/usb/storage/onetouch.h

@@ -0,0 +1,9 @@
+#ifndef _ONETOUCH_H_
+#define _ONETOUCH_H_
+
+#define ONETOUCH_PKT_LEN        0x02
+#define ONETOUCH_BUTTON         KEY_PROG1
+
+int onetouch_connect_input(struct us_data *ss);
+
+#endif

+ 8 - 0
drivers/usb/storage/scsiglue.c

@@ -156,6 +156,14 @@ static int slave_configure(struct scsi_device *sdev)
 		if (us->flags & US_FL_FIX_CAPACITY)
 			sdev->fix_capacity = 1;
 
+		/* Some devices report a SCSI revision level above 2 but are
+		 * unable to handle the REPORT LUNS command (for which
+		 * support is mandatory at level 3).  Since we already have
+		 * a Get-Max-LUN request, we won't lose much by setting the
+		 * revision level down to 2.  The only devices that would be
+		 * affected are those with sparse LUNs. */
+		sdev->scsi_level = SCSI_2;
+
 		/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
 		 * Hardware Error) when any low-level error occurs,
 		 * recoverable or not.  Setting this flag tells the SCSI

+ 32 - 65
drivers/usb/storage/shuttle_usbat.c

@@ -839,34 +839,31 @@ static int usbat_identify_device(struct us_data *us,
 	rc = usbat_device_reset(us);
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 		return rc;
+	msleep(25);
 
 	/*
-	 * By examining the device signature after a reset, we can identify
-	 * whether the device supports the ATAPI packet interface.
-	 * The flash-devices do not support this, whereas the HP CDRW's obviously
-	 * do.
-	 *
-	 * This method is not ideal, but works because no other devices have been
-	 * produced based on the USBAT/USBAT02.
-	 *
-	 * Section 9.1 of the ATAPI-4 spec states (amongst other things) that
-	 * after a device reset, a Cylinder low of 0x14 indicates that the device
-	 * does support packet commands.
+	 * In attempt to distinguish between HP CDRW's and Flash readers, we now
+	 * execute the IDENTIFY PACKET DEVICE command. On ATA devices (i.e. flash
+	 * readers), this command should fail with error. On ATAPI devices (i.e.
+	 * CDROM drives), it should succeed.
 	 */
-	rc = usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, &status);
-	if (rc != USB_STOR_XFER_GOOD)
-		return USB_STOR_TRANSPORT_ERROR;
+	rc = usbat_write(us, USBAT_ATA, USBAT_ATA_CMD, 0xA1);
+ 	if (rc != USB_STOR_XFER_GOOD)
+ 		return USB_STOR_TRANSPORT_ERROR;
 
-	US_DEBUGP("usbat_identify_device: Cylinder low is %02X\n", status);
+	rc = usbat_get_status(us, &status);
+ 	if (rc != USB_STOR_XFER_GOOD)
+ 		return USB_STOR_TRANSPORT_ERROR;
 
-	if (status == 0x14) {
+	// Check for error bit
+	if (status & 0x01) {
+		 // Device is a CompactFlash reader/writer
+		US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n");
+		info->devicetype = USBAT_DEV_FLASH;
+	} else {
 		// Device is HP 8200
 		US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n");
 		info->devicetype = USBAT_DEV_HP8200;
-	} else {
-		// Device is a CompactFlash reader/writer
-		US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n");
-		info->devicetype = USBAT_DEV_FLASH;
 	}
 
 	return USB_STOR_TRANSPORT_GOOD;
@@ -1239,16 +1236,10 @@ static int usbat_select_and_test_registers(struct us_data *us)
 {
 	int selector;
 	unsigned char *status = us->iobuf;
-	unsigned char max_selector = 0xB0;
-	if (usbat_get_device_type(us) == USBAT_DEV_FLASH)
-		max_selector = 0xA0;
 
 	// try device = master, then device = slave.
-
-	for (selector = 0xA0; selector <= max_selector; selector += 0x10) {
-
-		if (usbat_get_device_type(us) == USBAT_DEV_HP8200 &&
-			usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) != 
+	for (selector = 0xA0; selector <= 0xB0; selector += 0x10) {
+		if (usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) !=
 				USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
 
@@ -1334,60 +1325,30 @@ int init_usbat(struct us_data *us)
 
 	US_DEBUGP("INIT 3\n");
 
-	// At this point, we need to detect which device we are using
-	if (usbat_set_transport(us, info))
-		return USB_STOR_TRANSPORT_ERROR;
-
-	US_DEBUGP("INIT 4\n");
-
-	if (usbat_get_device_type(us) == USBAT_DEV_HP8200) {
-		msleep(250);
-
-		// Write 0x80 to ISA port 0x3F
-		rc = usbat_write(us, USBAT_ISA, 0x3F, 0x80);
-		if (rc != USB_STOR_XFER_GOOD)
-			return USB_STOR_TRANSPORT_ERROR;
-
-		US_DEBUGP("INIT 5\n");
-
-		// Read ISA port 0x27
-		rc = usbat_read(us, USBAT_ISA, 0x27, status);
-		if (rc != USB_STOR_XFER_GOOD)
-			return USB_STOR_TRANSPORT_ERROR;
-
-		US_DEBUGP("INIT 6\n");
-
-		rc = usbat_read_user_io(us, status);
-		if (rc != USB_STOR_XFER_GOOD)
-			return USB_STOR_TRANSPORT_ERROR;
-
-		US_DEBUGP("INIT 7\n");
-	}
-
 	rc = usbat_select_and_test_registers(us);
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 		return rc;
 
-	US_DEBUGP("INIT 8\n");
+	US_DEBUGP("INIT 4\n");
 
 	rc = usbat_read_user_io(us, status);
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	US_DEBUGP("INIT 9\n");
+	US_DEBUGP("INIT 5\n");
 
 	// Enable peripheral control signals and card detect
 	rc = usbat_device_enable_cdt(us);
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 		return rc;
 
-	US_DEBUGP("INIT 10\n");
+	US_DEBUGP("INIT 6\n");
 
 	rc = usbat_read_user_io(us, status);
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	US_DEBUGP("INIT 11\n");
+	US_DEBUGP("INIT 7\n");
 
 	msleep(1400);
 
@@ -1395,13 +1356,19 @@ int init_usbat(struct us_data *us)
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	US_DEBUGP("INIT 12\n");
+	US_DEBUGP("INIT 8\n");
 
 	rc = usbat_select_and_test_registers(us);
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 		return rc;
 
-	US_DEBUGP("INIT 13\n");
+	US_DEBUGP("INIT 9\n");
+
+	// At this point, we need to detect which device we are using
+	if (usbat_set_transport(us, info))
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("INIT 10\n");
 
 	if (usbat_get_device_type(us) == USBAT_DEV_FLASH) { 
 		subcountH = 0x02;
@@ -1412,7 +1379,7 @@ int init_usbat(struct us_data *us)
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	US_DEBUGP("INIT 14\n");
+	US_DEBUGP("INIT 11\n");
 
 	return USB_STOR_TRANSPORT_GOOD;
 }

+ 5 - 12
drivers/usb/storage/transport.c

@@ -96,8 +96,8 @@
  * or before the URB_ACTIVE bit was set.  If so, it's essential to cancel
  * the URB if it hasn't been cancelled already (i.e., if the URB_ACTIVE bit
  * is still set).  Either way, the function must then wait for the URB to
- * finish.  Note that because the URB_ASYNC_UNLINK flag is set, the URB can
- * still be in progress even after a call to usb_unlink_urb() returns.
+ * finish.  Note that the URB can still be in progress even after a call to
+ * usb_unlink_urb() returns.
  *
  * The idea is that (1) once the ABORTING or DISCONNECTING bit is set,
  * either the stop_transport() function or the submitting function
@@ -158,8 +158,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
 	 * hasn't been mapped for DMA.  Yes, this is clunky, but it's
 	 * easier than always having the caller tell us whether the
 	 * transfer buffer has already been mapped. */
-	us->current_urb->transfer_flags =
-			URB_ASYNC_UNLINK | URB_NO_SETUP_DMA_MAP;
+	us->current_urb->transfer_flags = URB_NO_SETUP_DMA_MAP;
 	if (us->current_urb->transfer_buffer == us->iobuf)
 		us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	us->current_urb->transfer_dma = us->iobuf_dma;
@@ -611,7 +610,6 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 		unsigned char old_sc_data_direction;
 		unsigned char old_cmd_len;
 		unsigned char old_cmnd[MAX_COMMAND_SIZE];
-		unsigned long old_serial_number;
 		int old_resid;
 
 		US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
@@ -648,10 +646,6 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 		old_sg = srb->use_sg;
 		srb->use_sg = 0;
 
-		/* change the serial number -- toggle the high bit*/
-		old_serial_number = srb->serial_number;
-		srb->serial_number ^= 0x80000000;
-
 		/* issue the auto-sense command */
 		old_resid = srb->resid;
 		srb->resid = 0;
@@ -662,7 +656,6 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 		srb->request_buffer = old_request_buffer;
 		srb->request_bufflen = old_request_bufflen;
 		srb->use_sg = old_sg;
-		srb->serial_number = old_serial_number;
 		srb->sc_data_direction = old_sc_data_direction;
 		srb->cmd_len = old_cmd_len;
 		memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
@@ -985,7 +978,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = cpu_to_le32(transfer_length);
 	bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
-	bcb->Tag = srb->serial_number;
+	bcb->Tag = ++us->tag;
 	bcb->Lun = srb->device->lun;
 	if (us->flags & US_FL_SCM_MULT_TARG)
 		bcb->Lun |= srb->device->id << 4;
@@ -1074,7 +1067,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
 	US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
 			le32_to_cpu(bcs->Signature), bcs->Tag, 
 			residue, bcs->Status);
-	if (bcs->Tag != srb->serial_number || bcs->Status > US_BULK_STAT_PHASE) {
+	if (bcs->Tag != us->tag || bcs->Status > US_BULK_STAT_PHASE) {
 		US_DEBUGP("Bulk logical error\n");
 		return USB_STOR_TRANSPORT_ERROR;
 	}

+ 19 - 0
drivers/usb/storage/unusual_devs.h

@@ -79,6 +79,13 @@ UNUSUAL_DEV(  0x03f0, 0x0307, 0x0001, 0x0001,
 		US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), 
 #endif
 
+/* Patch submitted by Mihnea-Costin Grigore <mihnea@zulu.ro> */
+UNUSUAL_DEV(  0x040d, 0x6205, 0x0003, 0x0003,
+		"VIA Technologies Inc.",
+		"USB 2.0 Card Reader",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
 /* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
  * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
  * always fails and confuses drive.
@@ -929,6 +936,18 @@ UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
 	       US_FL_SINGLE_LUN ),
 #endif
 
+/* Submitted by: Nick Sillik <n.sillik@temple.edu>
+ * Needed for OneTouch extension to usb-storage
+ *
+ */
+#ifdef CONFIG_USB_STORAGE_ONETOUCH
+	UNUSUAL_DEV(  0x0d49, 0x7010, 0x0000, 0x9999,
+			"Maxtor",
+			"OneTouch External Harddrive",
+			US_SC_DEVICE, US_PR_DEVICE, onetouch_connect_input,
+			0),
+#endif
+
 /* Submitted by Joris Struyve <joris@struyve.be> */
 UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
 		"Medion",

+ 51 - 28
drivers/usb/storage/usb.c

@@ -90,7 +90,9 @@
 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
 #include "jumpshot.h"
 #endif
-
+#ifdef CONFIG_USB_STORAGE_ONETOUCH
+#include "onetouch.h"
+#endif
 
 /* Some informational data */
 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -786,6 +788,7 @@ static void usb_stor_release_resources(struct us_data *us)
 	 * any more commands.
 	 */
 	US_DEBUGP("-- sending exit command to thread\n");
+	set_bit(US_FLIDX_DISCONNECTING, &us->flags);
 	up(&us->sema);
 
 	/* Call the destructor routine, if it exists */
@@ -816,6 +819,49 @@ static void dissociate_dev(struct us_data *us)
 	usb_set_intfdata(us->pusb_intf, NULL);
 }
 
+/* First stage of disconnect processing: stop all commands and remove
+ * the host */
+static void quiesce_and_remove_host(struct us_data *us)
+{
+	/* Prevent new USB transfers, stop the current command, and
+	 * interrupt a SCSI-scan or device-reset delay */
+	set_bit(US_FLIDX_DISCONNECTING, &us->flags);
+	usb_stor_stop_transport(us);
+	wake_up(&us->delay_wait);
+
+	/* It doesn't matter if the SCSI-scanning thread is still running.
+	 * The thread will exit when it sees the DISCONNECTING flag. */
+
+	/* Wait for the current command to finish, then remove the host */
+	down(&us->dev_semaphore);
+	up(&us->dev_semaphore);
+
+	/* queuecommand won't accept any new commands and the control
+	 * thread won't execute a previously-queued command.  If there
+	 * is such a command pending, complete it with an error. */
+	if (us->srb) {
+		us->srb->result = DID_NO_CONNECT << 16;
+		scsi_lock(us_to_host(us));
+		us->srb->scsi_done(us->srb);
+		us->srb = NULL;
+		scsi_unlock(us_to_host(us));
+	}
+
+	/* Now we own no commands so it's safe to remove the SCSI host */
+	scsi_remove_host(us_to_host(us));
+}
+
+/* Second stage of disconnect processing: deallocate all resources */
+static void release_everything(struct us_data *us)
+{
+	usb_stor_release_resources(us);
+	dissociate_dev(us);
+
+	/* Drop our reference to the host; the SCSI core will free it
+	 * (and "us" along with it) when the refcount becomes 0. */
+	scsi_host_put(us_to_host(us));
+}
+
 /* Thread to carry out delayed SCSI-device scanning */
 static int usb_stor_scan_thread(void * __us)
 {
@@ -956,7 +1002,7 @@ static int storage_probe(struct usb_interface *intf,
 	if (result < 0) {
 		printk(KERN_WARNING USB_STORAGE 
 		       "Unable to start the device-scanning thread\n");
-		scsi_remove_host(host);
+		quiesce_and_remove_host(us);
 		goto BadDevice;
 	}
 	atomic_inc(&total_threads);
@@ -969,10 +1015,7 @@ static int storage_probe(struct usb_interface *intf,
 	/* We come here if there are any problems */
 BadDevice:
 	US_DEBUGP("storage_probe() failed\n");
-	set_bit(US_FLIDX_DISCONNECTING, &us->flags);
-	usb_stor_release_resources(us);
-	dissociate_dev(us);
-	scsi_host_put(host);
+	release_everything(us);
 	return result;
 }
 
@@ -982,28 +1025,8 @@ static void storage_disconnect(struct usb_interface *intf)
 	struct us_data *us = usb_get_intfdata(intf);
 
 	US_DEBUGP("storage_disconnect() called\n");
-
-	/* Prevent new USB transfers, stop the current command, and
-	 * interrupt a SCSI-scan or device-reset delay */
-	set_bit(US_FLIDX_DISCONNECTING, &us->flags);
-	usb_stor_stop_transport(us);
-	wake_up(&us->delay_wait);
-
-	/* It doesn't matter if the SCSI-scanning thread is still running.
-	 * The thread will exit when it sees the DISCONNECTING flag. */
-
-	/* Wait for the current command to finish, then remove the host */
-	down(&us->dev_semaphore);
-	up(&us->dev_semaphore);
-	scsi_remove_host(us_to_host(us));
-
-	/* Wait for everything to become idle and release all our resources */
-	usb_stor_release_resources(us);
-	dissociate_dev(us);
-
-	/* Drop our reference to the host; the SCSI core will free it
-	 * (and "us" along with it) when the refcount becomes 0. */
-	scsi_host_put(us_to_host(us));
+	quiesce_and_remove_host(us);
+	release_everything(us);
 }
 
 /***********************************************************************

+ 1 - 0
drivers/usb/storage/usb.h

@@ -158,6 +158,7 @@ struct us_data {
 
 	/* SCSI interfaces */
 	struct scsi_cmnd	*srb;		 /* current srb		*/
+	unsigned int		tag;		 /* current dCBWTag	*/
 
 	/* thread information */
 	int			pid;		 /* control thread	 */

+ 3 - 8
include/linux/usb.h

@@ -5,6 +5,7 @@
 #include <linux/usb_ch9.h>
 
 #define USB_MAJOR			180
+#define USB_DEVICE_MAJOR		189
 
 
 #ifdef __KERNEL__
@@ -349,6 +350,7 @@ struct usb_device {
 	char *manufacturer;
 	char *serial;			/* static strings from the device */
 	struct list_head filelist;
+	struct class_device *class_dev;
 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the device */
 
 	/*
@@ -614,7 +616,6 @@ extern int usb_disabled(void);
 #define URB_ISO_ASAP		0x0002	/* iso-only, urb->start_frame ignored */
 #define URB_NO_TRANSFER_DMA_MAP	0x0004	/* urb->transfer_dma valid on submit */
 #define URB_NO_SETUP_DMA_MAP	0x0008	/* urb->setup_dma valid on submit */
-#define URB_ASYNC_UNLINK	0x0010	/* usb_unlink_urb() returns asap */
 #define URB_NO_FSBR		0x0020	/* UHCI-specific */
 #define URB_ZERO_PACKET		0x0040	/* Finish bulk OUTs with short packet */
 #define URB_NO_INTERRUPT	0x0080	/* HINT: no non-error interrupt needed */
@@ -722,13 +723,7 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
  * Initialization:
  *
  * All URBs submitted must initialize the dev, pipe, transfer_flags (may be
- * zero), and complete fields.
- * The URB_ASYNC_UNLINK transfer flag affects later invocations of
- * the usb_unlink_urb() routine.  Note: Failure to set URB_ASYNC_UNLINK
- * with usb_unlink_urb() is deprecated.  For synchronous unlinks use
- * usb_kill_urb() instead.
- *
- * All URBs must also initialize 
+ * zero), and complete fields.  All URBs must also initialize
  * transfer_buffer and transfer_buffer_length.  They may provide the
  * URB_SHORT_NOT_OK transfer flag, indicating that short reads are
  * to be treated as errors; that flag is invalid for write requests.

+ 6 - 24
include/linux/usb_isp116x.h

@@ -7,36 +7,18 @@
 struct isp116x_platform_data {
 	/* Enable internal resistors on downstream ports */
 	unsigned sel15Kres:1;
-	/* Chip's internal clock won't be stopped in suspended state.
-	   Setting/unsetting this bit takes effect only if
-	   'remote_wakeup_enable' below is not set. */
-	unsigned clknotstop:1;
-	/* On-chip overcurrent protection */
+	/* On-chip overcurrent detection */
 	unsigned oc_enable:1;
 	/* INT output polarity */
 	unsigned int_act_high:1;
 	/* INT edge or level triggered */
 	unsigned int_edge_triggered:1;
-	/* WAKEUP pin connected - NOT SUPPORTED  */
-	/* unsigned remote_wakeup_connected:1; */
-	/* Wakeup by devices on usb bus enabled */
+	/* Enable wakeup by devices on usb bus (e.g. wakeup
+	   by attachment/detachment or by device activity
+	   such as moving a mouse). When chosen, this option
+	   prevents stopping internal clock, increasing
+	   thereby power consumption in suspended state. */
 	unsigned remote_wakeup_enable:1;
-	/* Switch or not to switch (keep always powered) */
-	unsigned no_power_switching:1;
-	/* Ganged port power switching (0) or individual port
-	   power switching (1) */
-	unsigned power_switching_mode:1;
-	/* Given port_power, msec/2 after power on till power good */
-	u8 potpg;
-	/* Hardware reset set/clear. If implemented, this function must:
-	   if set == 0,   deassert chip's HW reset pin
-	   otherwise,     assert chip's HW reset pin       */
-	void (*reset) (struct device * dev, int set);
-	/* Hardware clock start/stop. If implemented, this function must:
-	   if start == 0,    stop the external clock
-	   otherwise,        start the external clock
-	 */
-	void (*clock) (struct device * dev, int start);
 	/* Inter-io delay (ns). The chip is picky about access timings; it
 	   expects at least:
 	   150ns delay between consecutive accesses to DATA_REG,

+ 4 - 6
sound/usb/usbaudio.c

@@ -735,10 +735,9 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep)
 		if (test_bit(i, &subs->active_mask)) {
 			if (! test_and_set_bit(i, &subs->unlink_mask)) {
 				struct urb *u = subs->dataurb[i].urb;
-				if (async) {
-					u->transfer_flags |= URB_ASYNC_UNLINK;
+				if (async)
 					usb_unlink_urb(u);
-				} else
+				else
 					usb_kill_urb(u);
 			}
 		}
@@ -748,10 +747,9 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep)
 			if (test_bit(i+16, &subs->active_mask)) {
  				if (! test_and_set_bit(i+16, &subs->unlink_mask)) {
 					struct urb *u = subs->syncurb[i].urb;
-					if (async) {
-						u->transfer_flags |= URB_ASYNC_UNLINK;
+					if (async)
 						usb_unlink_urb(u);
-					} else
+					else
 						usb_kill_urb(u);
 				}
 			}

Some files were not shown because too many files changed in this diff