Przeglądaj źródła

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

Linus Torvalds 20 lat temu
rodzic
commit
5420520973
80 zmienionych plików z 7518 dodań i 4188 usunięć
  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. 217 3233
      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
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 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
 8139CP 10/100 FAST ETHERNET DRIVER
 P:	Jeff Garzik
 P:	Jeff Garzik
 M:	jgarzik@pobox.com
 M:	jgarzik@pobox.com

+ 150 - 123
drivers/block/ub.c

@@ -16,9 +16,10 @@
  *  -- verify the 13 conditions and do bulk resets
  *  -- verify the 13 conditions and do bulk resets
  *  -- kill last_pipe and simply do two-state clearing on both pipes
  *  -- kill last_pipe and simply do two-state clearing on both pipes
  *  -- verify protocol (bulk) from USB descriptors (maybe...)
  *  -- verify protocol (bulk) from USB descriptors (maybe...)
- *  -- highmem and sg
+ *  -- highmem
  *  -- move top_sense and work_bcs into separate allocations (if they survive)
  *  -- move top_sense and work_bcs into separate allocations (if they survive)
  *     for cache purists and esoteric architectures.
  *     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
  *  -- prune comments, they are too volumnous
  *  -- Exterminate P3 printks
  *  -- Exterminate P3 printks
  *  -- Resove XXX's
  *  -- Resove XXX's
@@ -171,7 +172,7 @@ struct bulk_cs_wrap {
  */
  */
 struct ub_dev;
 struct ub_dev;
 
 
-#define UB_MAX_REQ_SG	1
+#define UB_MAX_REQ_SG	4
 #define UB_MAX_SECTORS 64
 #define UB_MAX_SECTORS 64
 
 
 /*
 /*
@@ -234,13 +235,10 @@ struct ub_scsi_cmd {
 
 
 	int stat_count;			/* Retries getting status. */
 	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 */
 	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;
 	struct ub_lun *lun;
 	void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
 	void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
@@ -389,17 +387,18 @@ struct ub_dev {
 	struct bulk_cs_wrap work_bcs;
 	struct bulk_cs_wrap work_bcs;
 	struct usb_ctrlrequest work_cr;
 	struct usb_ctrlrequest work_cr;
 
 
+	int sg_stat[UB_MAX_REQ_SG+1];
 	struct ub_scsi_trace tr;
 	struct ub_scsi_trace tr;
 };
 };
 
 
 /*
 /*
  */
  */
 static void ub_cleanup(struct ub_dev *sc);
 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,
 static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_scsi_cmd *cmd, struct request *rq);
     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_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
 static void ub_end_rq(struct request *rq, int uptodate);
 static void ub_end_rq(struct request *rq, int uptodate);
 static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
 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_action(unsigned long _dev);
 static void ub_scsi_dispatch(struct ub_dev *sc);
 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_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 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 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);
 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 usb_interface *intf;
 	struct ub_dev *sc;
 	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,
 	cnt += sprintf(page + cnt,
 	    "qlen %d qmax %d\n",
 	    "qlen %d qmax %d\n",
 	    sc->cmd_queue.qlen, sc->cmd_queue.qmax);
 	    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) {
 	list_for_each (p, &sc->luns) {
 		lun = list_entry(p, struct ub_lun, link);
 		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
  * 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 ub_lun *lun = q->queuedata;
 	struct request *rq;
 	struct request *rq;
 
 
 	while ((rq = elv_next_request(q)) != NULL) {
 	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);
 			blk_stop_queue(q);
 			break;
 			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_dev *sc = lun->udev;
 	struct ub_scsi_cmd *cmd;
 	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));
 	memset(cmd, 0, sizeof(struct ub_scsi_cmd));
 
 
 	blkdev_dequeue_request(rq);
 	blkdev_dequeue_request(rq);
-
 	if (blk_pc_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 {
 	} else {
 		rc = ub_cmd_build_block(sc, lun, cmd, rq);
 		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->back = rq;
 
 
 	cmd->tag = sc->tagcnt++;
 	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_put_cmd(lun, cmd);
 		ub_end_rq(rq, 0);
 		ub_end_rq(rq, 0);
 		return 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)
     struct ub_scsi_cmd *cmd, struct request *rq)
 {
 {
 	int ub_dir;
 	int ub_dir;
-#if 0 /* We use rq->buffer for now */
-	struct scatterlist *sg;
 	int n_elem;
 	int n_elem;
-#endif
 	unsigned int block, nblks;
 	unsigned int block, nblks;
 
 
 	if (rq_data_dir(rq) == WRITE)
 	if (rq_data_dir(rq) == WRITE)
 		ub_dir = UB_DIR_WRITE;
 		ub_dir = UB_DIR_WRITE;
 	else
 	else
 		ub_dir = UB_DIR_READ;
 		ub_dir = UB_DIR_READ;
+	cmd->dir = ub_dir;
 
 
 	/*
 	/*
 	 * get scatterlist from block layer
 	 * 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) {
 	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",
 		printk(KERN_WARNING "%s: request with %d segments\n",
 		    sc->name, n_elem);
 		    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;
 		return -1;
 	}
 	}
+	cmd->nsg = n_elem;
+	sc->sg_stat[n_elem]++;
 
 
 	/*
 	/*
 	 * build the command
 	 * 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[8] = nblks;
 	cmd->cdb_len = 10;
 	cmd->cdb_len = 10;
 
 
-	cmd->dir = ub_dir;
-	cmd->data = rq->buffer;
 	cmd->len = rq->nr_sectors * 512;
 	cmd->len = rq->nr_sectors * 512;
 
 
 	return 0;
 	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) {
 	if (rq->data_len == 0) {
 		cmd->dir = UB_DIR_NONE;
 		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;
 			cmd->dir = UB_DIR_WRITE;
 		else
 		else
 			cmd->dir = UB_DIR_READ;
 			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;
 	cmd->len = rq->data_len;
 
 
 	return 0;
 	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 request *rq = cmd->back;
 	struct ub_lun *lun = cmd->lun;
 	struct ub_lun *lun = cmd->lun;
-	struct gendisk *disk = lun->disk;
-	request_queue_t *q = disk->queue;
 	int uptodate;
 	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;
 		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;
 		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_put_cmd(lun, cmd);
 	ub_end_rq(rq, uptodate);
 	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)
 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;
 	sc->last_pipe = sc->send_bulk_pipe;
 	usb_fill_bulk_urb(&sc->work_urb, sc->dev, 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);
 	    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. */
 	/* Fill what we shouldn't be filling, because usb-storage did so. */
 	sc->work_urb.actual_length = 0;
 	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 urb *urb = &sc->work_urb;
 	struct bulk_cs_wrap *bcs;
 	struct bulk_cs_wrap *bcs;
-	int pipe;
 	int rc;
 	int rc;
 
 
 	if (atomic_read(&sc->poison)) {
 	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;
 			goto Bad_End;
 		}
 		}
 
 
-		if (cmd->dir == UB_DIR_NONE) {
+		if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) {
 			ub_state_stat(sc, cmd);
 			ub_state_stat(sc, cmd);
 			return;
 			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) {
 	} else if (cmd->state == UB_CMDST_DATA) {
 		if (urb->status == -EPIPE) {
 		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) {
 		if (urb->status == -EOVERFLOW) {
 			/*
 			/*
 			 * A babble? Failure, but we must transfer CSW now.
 			 * 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... */
 			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);
 		ub_cmdtr_act_len(sc, cmd);
 
 
+		if (++cmd->current_sg < cmd->nsg) {
+			ub_data_start(sc, cmd);
+			return;
+		}
 		ub_state_stat(sc, cmd);
 		ub_state_stat(sc, cmd);
 
 
 	} else if (cmd->state == UB_CMDST_STAT) {
 	} else if (cmd->state == UB_CMDST_STAT) {
@@ -1399,6 +1375,46 @@ Bad_End: /* Little Excel is dead */
 	ub_state_done(sc, cmd, -EIO);
 	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:
  * Factorization helper for the command state machine:
  * Finish the command.
  * 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;
 	sc->last_pipe = sc->recv_bulk_pipe;
 	usb_fill_bulk_urb(&sc->work_urb, sc->dev, 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_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.actual_length = 0;
 	sc->work_urb.error_count = 0;
 	sc->work_urb.error_count = 0;
 	sc->work_urb.status = 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)
 static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 {
 {
 	struct ub_scsi_cmd *scmd;
 	struct ub_scsi_cmd *scmd;
+	struct scatterlist *sg;
 	int rc;
 	int rc;
 
 
 	if (cmd->cdb[0] == REQUEST_SENSE) {
 	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;
 	scmd = &sc->top_rqs_cmd;
+	memset(scmd, 0, sizeof(struct ub_scsi_cmd));
 	scmd->cdb[0] = REQUEST_SENSE;
 	scmd->cdb[0] = REQUEST_SENSE;
 	scmd->cdb[4] = UB_SENSE_SIZE;
 	scmd->cdb[4] = UB_SENSE_SIZE;
 	scmd->cdb_len = 6;
 	scmd->cdb_len = 6;
 	scmd->dir = UB_DIR_READ;
 	scmd->dir = UB_DIR_READ;
 	scmd->state = UB_CMDST_INIT;
 	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->len = UB_SENSE_SIZE;
 	scmd->lun = cmd->lun;
 	scmd->lun = cmd->lun;
 	scmd->done = ub_top_sense_done;
 	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,
 	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
 	    (unsigned char*) cr, NULL, 0, ub_urb_complete, sc);
 	    (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.actual_length = 0;
 	sc->work_urb.error_count = 0;
 	sc->work_urb.error_count = 0;
 	sc->work_urb.status = 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)
 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;
 	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_capacity *ret)
 {
 {
 	struct ub_scsi_cmd *cmd;
 	struct ub_scsi_cmd *cmd;
+	struct scatterlist *sg;
 	char *p;
 	char *p;
 	enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 };
 	enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 };
 	unsigned long flags;
 	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->cdb_len = 10;
 	cmd->dir = UB_DIR_READ;
 	cmd->dir = UB_DIR_READ;
 	cmd->state = UB_CMDST_INIT;
 	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->len = 8;
 	cmd->lun = lun;
 	cmd->lun = lun;
 	cmd->done = ub_probe_done;
 	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? */
 	disk->driverfs_dev = &sc->intf->dev;	/* XXX Many to one ok? */
 
 
 	rc = -ENOMEM;
 	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;
 		goto err_blkqinit;
 
 
 	disk->queue = q;
 	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,
                       frame, IRDA_USB_SPEED_MTU,
                       speed_bulk_callback, self);
                       speed_bulk_callback, self);
 	urb->transfer_buffer_length = USB_IRDA_HEADER;
 	urb->transfer_buffer_length = USB_IRDA_HEADER;
-	urb->transfer_flags = URB_ASYNC_UNLINK;
+	urb->transfer_flags = 0;
 
 
 	/* Irq disabled -> GFP_ATOMIC */
 	/* Irq disabled -> GFP_ATOMIC */
 	if ((ret = usb_submit_urb(urb, 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,
                       skb->data, IRDA_SKB_MAX_MTU,
                       write_bulk_callback, skb);
                       write_bulk_callback, skb);
 	urb->transfer_buffer_length = skb->len;
 	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
 	/* This flag (URB_ZERO_PACKET) indicates that what we send is not
 	 * a continuous stream of data but separate packets.
 	 * a continuous stream of data but separate packets.
 	 * In this case, the USB layer will insert an empty USB frame (TD)
 	 * 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.
 	 * 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 */
 	 * 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? */
 	/* Generate min turn time. FIXME: can we do better than this? */
 	/* Trying to a turnaround time at this level is trying to measure
 	/* 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
 			 * in completion handler, because urb->status will
 			 * be -ENOENT. We will fix that at the next watchdog,
 			 * be -ENOENT. We will fix that at the next watchdog,
 			 * leaving more time to USB to recover...
 			 * 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 */
 			 * Jean II */
 			done = 1;
 			done = 1;
 			break;
 			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 */
 	/* 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);
 	usb_kill_urb(self->tx_urb);
-	self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 	usb_kill_urb(self->speed_urb);
 	usb_kill_urb(self->speed_urb);
 
 
 	/* Stop and remove instance of IrLAP */
 	/* 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]);
 			usb_kill_urb(self->rx_urb[i]);
 		/* Cancel Tx and speed URB.
 		/* Cancel Tx and speed URB.
 		 * Toggle flags to make sure it's synchronous. */
 		 * Toggle flags to make sure it's synchronous. */
-		self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 		usb_kill_urb(self->tx_urb);
 		usb_kill_urb(self->tx_urb);
-		self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 		usb_kill_urb(self->speed_urb);
 		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),
 			usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD),
 			instance->rcv_buf, PAGE_SIZE,
 			instance->rcv_buf, PAGE_SIZE,
 			cxacru_blocking_completion, &instance->rcv_done, 1);
 			cxacru_blocking_completion, &instance->rcv_done, 1);
-	instance->rcv_urb->transfer_flags |= URB_ASYNC_UNLINK;
 
 
 	usb_fill_int_urb(instance->snd_urb,
 	usb_fill_int_urb(instance->snd_urb,
 			usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD),
 			usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD),
 			instance->snd_buf, PAGE_SIZE,
 			instance->snd_buf, PAGE_SIZE,
 			cxacru_blocking_completion, &instance->snd_done, 4);
 			cxacru_blocking_completion, &instance->snd_done, 4);
-	instance->snd_urb->transfer_flags |= URB_ASYNC_UNLINK;
 
 
 	init_MUTEX(&instance->cm_serialize);
 	init_MUTEX(&instance->cm_serialize);
 
 

+ 18 - 3
drivers/usb/class/Kconfig

@@ -4,9 +4,22 @@
 comment "USB Device Class drivers"
 comment "USB Device Class drivers"
 	depends on USB
 	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
 config USB_AUDIO
 	tristate "USB Audio support"
 	tristate "USB Audio support"
-	depends on USB && SOUND
+	depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
 	help
 	help
 	  Say Y here if you want to connect USB audio equipment such as
 	  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
 	  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
 config USB_MIDI
 	tristate "USB MIDI support"
 	tristate "USB MIDI support"
-	depends on USB && SOUND
+	depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
 	---help---
 	---help---
 	  Say Y here if you want to connect a USB MIDI device to your
 	  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'.
 	  'Universal Serial Bus Device Class Definition for MIDI Device'.
 
 
 	  The following devices are known to work:
 	  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);
 	error = usblp_read_status (usblp, usblp->statusbuf);
 	if (error < 0) {
 	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;
 		return 0;
 	}
 	}
 
 
@@ -604,7 +605,9 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 
 
 			case LPGETSTATUS:
 			case LPGETSTATUS:
 				if (usblp_read_status(usblp, usblp->statusbuf)) {
 				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;
 					retval = -EIO;
 					goto done;
 					goto done;
 				}
 				}

+ 2 - 2
drivers/usb/core/Makefile

@@ -3,14 +3,14 @@
 #
 #
 
 
 usbcore-objs	:= usb.o hub.o hcd.o urb.o message.o \
 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)
 ifeq ($(CONFIG_PCI),y)
 	usbcore-objs	+= hcd-pci.o
 	usbcore-objs	+= hcd-pci.o
 endif
 endif
 
 
 ifeq ($(CONFIG_USB_DEVICEFS),y)
 ifeq ($(CONFIG_USB_DEVICEFS),y)
-	usbcore-objs	+= devio.o inode.o devices.o
+	usbcore-objs	+= inode.o devices.o
 endif
 endif
 
 
 obj-$(CONFIG_USB)	+= usbcore.o
 obj-$(CONFIG_USB)	+= usbcore.o

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

@@ -43,6 +43,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/cdev.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
@@ -50,6 +51,10 @@
 #include "hcd.h"	/* for usbcore internals */
 #include "hcd.h"	/* for usbcore internals */
 #include "usb.h"
 #include "usb.h"
 
 
+#define USB_MAXBUS			64
+#define USB_DEVICE_MAX			USB_MAXBUS * 128
+static struct class *usb_device_class;
+
 struct async {
 struct async {
 	struct list_head asynclist;
 	struct list_head asynclist;
 	struct dev_state *ps;
 	struct dev_state *ps;
@@ -71,6 +76,8 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
 			dev_info( dev , format , ## arg);	\
 			dev_info( dev , format , ## arg);	\
 	} while (0)
 	} while (0)
 
 
+#define USB_DEVICE_DEV		MKDEV(USB_DEVICE_MAJOR, 0)
+
 
 
 #define	MAX_USBFS_BUFFER_SIZE	16384
 #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)
 static int usbdev_open(struct inode *inode, struct file *file)
 {
 {
-	struct usb_device *dev;
+	struct usb_device *dev = NULL;
 	struct dev_state *ps;
 	struct dev_state *ps;
 	int ret;
 	int ret;
 
 
@@ -501,11 +508,16 @@ static int usbdev_open(struct inode *inode, struct file *file)
 
 
 	lock_kernel();
 	lock_kernel();
 	ret = -ENOENT;
 	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) {
 	if (!dev) {
 		kfree(ps);
 		kfree(ps);
 		goto out;
 		goto out;
 	}
 	}
+	usb_get_dev(dev);
 	ret = 0;
 	ret = 0;
 	ps->dev = dev;
 	ps->dev = dev;
 	ps->file = file;
 	ps->file = file;
@@ -1226,7 +1238,6 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
 	int			retval = 0;
 	int			retval = 0;
 	struct usb_interface    *intf = NULL;
 	struct usb_interface    *intf = NULL;
 	struct usb_driver       *driver = NULL;
 	struct usb_driver       *driver = NULL;
-	int			i;
 
 
 	/* get input parameters and alloc buffer */
 	/* get input parameters and alloc buffer */
 	if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
 	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 */
 	/* disconnect kernel driver from interface */
 	case USBDEVFS_DISCONNECT:
 	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);
 		down_write(&usb_bus_type.subsys.rwsem);
 		if (intf->dev.driver) {
 		if (intf->dev.driver) {
 			driver = to_usb_driver(intf->dev.driver);
 			driver = to_usb_driver(intf->dev.driver);
@@ -1477,3 +1479,79 @@ struct file_operations usbfs_device_file_operations = {
 	.open =		usbdev_open,
 	.open =		usbdev_open,
 	.release =	usbdev_release,
 	.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)
  * to preallocate bandwidth)
  */
  */
 #define USB2_HOST_DELAY	5	/* nsec, guess */
 #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)
 	+ 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)
 	+ USB2_HOST_DELAY)
 #define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes))
 #define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes))
 #define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(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;
 	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,
 static int hub_configure(struct usb_hub *hub,
 	struct usb_endpoint_descriptor *endpoint)
 	struct usb_endpoint_descriptor *endpoint)
 {
 {
@@ -610,19 +627,33 @@ static int hub_configure(struct usb_hub *hub,
 			break;
 			break;
 	}
 	}
 
 
+	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
 	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) {
 	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;
 			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;
 			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;
 			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;
 			break;
 	}
 	}
 
 
@@ -712,20 +743,36 @@ fail:
 
 
 static unsigned highspeed_hubs;
 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)
 static void hub_disconnect(struct usb_interface *intf)
 {
 {
 	struct usb_hub *hub = usb_get_intfdata (intf);
 	struct usb_hub *hub = usb_get_intfdata (intf);
 	struct usb_device *hdev;
 	struct usb_device *hdev;
+	int n, port1;
 
 
-	if (!hub)
-		return;
+	usb_set_intfdata (intf, NULL);
 	hdev = hub->hdev;
 	hdev = hub->hdev;
 
 
 	if (hdev->speed == USB_SPEED_HIGH)
 	if (hdev->speed == USB_SPEED_HIGH)
 		highspeed_hubs--;
 		highspeed_hubs--;
 
 
-	usb_set_intfdata (intf, NULL);
-
 	hub_quiesce(hub);
 	hub_quiesce(hub);
 	usb_free_urb(hub->urb);
 	usb_free_urb(hub->urb);
 	hub->urb = NULL;
 	hub->urb = NULL;
@@ -746,8 +793,27 @@ static void hub_disconnect(struct usb_interface *intf)
 		hub->buffer = NULL;
 		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)
 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");
 	dev_dbg (&udev->dev, "unregistering device\n");
 	release_address(udev);
 	release_address(udev);
 	usbfs_remove_device(udev);
 	usbfs_remove_device(udev);
+	usbdev_remove(udev);
 	usb_remove_sysfs_dev_files(udev);
 	usb_remove_sysfs_dev_files(udev);
 
 
 	/* Avoid races with recursively_mark_NOTATTACHED() */
 	/* Avoid races with recursively_mark_NOTATTACHED() */
@@ -1290,6 +1357,7 @@ int usb_new_device(struct usb_device *udev)
 	/* USB device state == configured ... usable */
 	/* USB device state == configured ... usable */
 
 
 	/* add a /proc/bus/usb entry */
 	/* add a /proc/bus/usb entry */
+	usbdev_add(udev);
 	usbfs_add_device(udev);
 	usbfs_add_device(udev);
 	return 0;
 	return 0;
 
 
@@ -1428,23 +1496,6 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 	return status;
 	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
  * 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
  * 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;
 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.
  * 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).
  * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
@@ -170,6 +176,7 @@ struct usb_device;
 struct usb_tt {
 struct usb_tt {
 	struct usb_device	*hub;	/* upstream highspeed hub */
 	struct usb_device	*hub;	/* upstream highspeed hub */
 	int			multi;	/* true means one TT per port */
 	int			multi;	/* true means one TT per port */
+	unsigned		think_time;	/* think time in ns */
 
 
 	/* for control/bulk error recovery (CLEAR_TT_BUFFER) */
 	/* for control/bulk error recovery (CLEAR_TT_BUFFER) */
 	spinlock_t		lock;
 	spinlock_t		lock;

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

@@ -728,15 +728,9 @@ int __init usbfs_init(void)
 {
 {
 	int retval;
 	int retval;
 
 
-	retval = usb_register(&usbfs_driver);
-	if (retval)
-		return retval;
-
 	retval = register_filesystem(&usb_fs_type);
 	retval = register_filesystem(&usb_fs_type);
-	if (retval) {
-		usb_deregister(&usbfs_driver);
+	if (retval)
 		return retval;
 		return retval;
-	}
 
 
 	/* create mount point for usbfs */
 	/* create mount point for usbfs */
 	usbdir = proc_mkdir("usb", proc_bus);
 	usbdir = proc_mkdir("usb", proc_bus);
@@ -746,7 +740,6 @@ int __init usbfs_init(void)
 
 
 void usbfs_cleanup(void)
 void usbfs_cleanup(void)
 {
 {
-	usb_deregister(&usbfs_driver);
 	unregister_filesystem(&usb_fs_type);
 	unregister_filesystem(&usb_fs_type);
 	if (usbdir)
 	if (usbdir)
 		remove_proc_entry("usb", proc_bus);
 		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); 	
 	init_completion(&done); 	
 	urb->context = &done;
 	urb->context = &done;
-	urb->transfer_flags |= URB_ASYNC_UNLINK;
 	urb->actual_length = 0;
 	urb->actual_length = 0;
 	status = usb_submit_urb(urb, GFP_NOIO);
 	status = usb_submit_urb(urb, GFP_NOIO);
 
 
@@ -266,7 +265,9 @@ static void sg_complete (struct urb *urb, struct pt_regs *regs)
 				continue;
 				continue;
 			if (found) {
 			if (found) {
 				status = usb_unlink_urb (io->urbs [i]);
 				status = usb_unlink_urb (io->urbs [i]);
-				if (status != -EINPROGRESS && status != -EBUSY)
+				if (status != -EINPROGRESS
+						&& status != -ENODEV
+						&& status != -EBUSY)
 					dev_err (&io->dev->dev,
 					dev_err (&io->dev->dev,
 						"%s, unlink --> %d\n",
 						"%s, unlink --> %d\n",
 						__FUNCTION__, status);
 						__FUNCTION__, status);
@@ -357,8 +358,7 @@ int usb_sg_init (
 	if (!io->urbs)
 	if (!io->urbs)
 		goto nomem;
 		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))
 	if (usb_pipein (pipe))
 		urb_flags |= URB_SHORT_NOT_OK;
 		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;
 	unsigned int	allowed;
 
 
 	/* enforce simple/standard policy */
 	/* 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) {
 	switch (temp) {
 	case PIPE_BULK:
 	case PIPE_BULK:
 		if (is_out)
 		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
  * canceled (rather than any other code) and will quickly be removed
  * from host controller data structures.
  * 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
  * 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
  * given back to the device driver.  When it is called, the completion
  * function will see urb->status == -ECONNRESET.  Failure is indicated
  * function will see urb->status == -ECONNRESET.  Failure is indicated
@@ -453,17 +446,6 @@ int usb_unlink_urb(struct urb *urb)
 {
 {
 	if (!urb)
 	if (!urb)
 		return -EINVAL;
 		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))
 	if (!(urb->dev && urb->dev->bus && urb->dev->bus->op))
 		return -ENODEV;
 		return -ENODEV;
 	return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET);
 	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)
 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;
 	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
  * is neither BINDING nor BOUND.  Rather than sleeping to wait for the
  * lock, the routine polls repeatedly.  This is to prevent deadlock with
  * lock, the routine polls repeatedly.  This is to prevent deadlock with
  * disconnect; in some drivers (such as usb-storage) the disconnect()
  * 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
  * 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
  * 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,
 int usb_lock_device_for_reset(struct usb_device *udev,
 		struct usb_interface *iface)
 		struct usb_interface *iface)
 {
 {
+	unsigned long jiffies_expire = jiffies + HZ;
+
 	if (udev->state == USB_STATE_NOTATTACHED)
 	if (udev->state == USB_STATE_NOTATTACHED)
 		return -ENODEV;
 		return -ENODEV;
 	if (udev->state == USB_STATE_SUSPENDED)
 	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)) {
 	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);
 		msleep(15);
 		if (udev->state == USB_STATE_NOTATTACHED)
 		if (udev->state == USB_STATE_NOTATTACHED)
 			return -ENODEV;
 			return -ENODEV;
@@ -1478,13 +1496,18 @@ static int __init usb_init(void)
 	retval = usb_major_init();
 	retval = usb_major_init();
 	if (retval)
 	if (retval)
 		goto major_init_failed;
 		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();
 	retval = usbfs_init();
 	if (retval)
 	if (retval)
 		goto fs_init_failed;
 		goto fs_init_failed;
 	retval = usb_hub_init();
 	retval = usb_hub_init();
 	if (retval)
 	if (retval)
 		goto hub_init_failed;
 		goto hub_init_failed;
-
 	retval = driver_register(&usb_generic_driver);
 	retval = driver_register(&usb_generic_driver);
 	if (!retval)
 	if (!retval)
 		goto out;
 		goto out;
@@ -1493,7 +1516,11 @@ static int __init usb_init(void)
 hub_init_failed:
 hub_init_failed:
 	usbfs_cleanup();
 	usbfs_cleanup();
 fs_init_failed:
 fs_init_failed:
-	usb_major_cleanup();	
+	usbdev_cleanup();
+usbdevice_init_failed:
+	usb_deregister(&usbfs_driver);
+driver_register_failed:
+	usb_major_cleanup();
 major_init_failed:
 major_init_failed:
 	usb_host_cleanup();
 	usb_host_cleanup();
 host_init_failed:
 host_init_failed:
@@ -1514,6 +1541,8 @@ static void __exit usb_exit(void)
 	driver_unregister(&usb_generic_driver);
 	driver_unregister(&usb_generic_driver);
 	usb_major_cleanup();
 	usb_major_cleanup();
 	usbfs_cleanup();
 	usbfs_cleanup();
+	usb_deregister(&usbfs_driver);
+	usbdev_cleanup();
 	usb_hub_cleanup();
 	usb_hub_cleanup();
 	usb_host_cleanup();
 	usb_host_cleanup();
 	bus_unregister(&usb_bus_type);
 	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 struct file_operations usbfs_device_file_operations;
 extern void usbfs_conn_disc_event(void);
 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 dev_state {
 	struct list_head list;      /* state list */
 	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;
 	u8			cdc = 1, zlp = 1, rndis = 1;
 	struct usb_ep		*in_ep, *out_ep, *status_ep = NULL;
 	struct usb_ep		*in_ep, *out_ep, *status_ep = NULL;
 	int			status = -ENOMEM;
 	int			status = -ENOMEM;
+	int			gcnum;
 
 
 	/* these flags are only ever cleared; compiler take note */
 	/* these flags are only ever cleared; compiler take note */
 #ifndef	DEV_CONFIG_CDC
 #ifndef	DEV_CONFIG_CDC
@@ -2194,44 +2195,26 @@ eth_bind (struct usb_gadget *gadget)
 	 * standard protocol is _strongly_ preferred for interop purposes.
 	 * standard protocol is _strongly_ preferred for interop purposes.
 	 * (By everyone except Microsoft.)
 	 * (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 */
 		/* pxa doesn't support altsettings */
 		cdc = 0;
 		cdc = 0;
 	} else if (gadget_is_sh(gadget)) {
 	} else if (gadget_is_sh(gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204);
 		/* sh doesn't support multiple interfaces or configs */
 		/* sh doesn't support multiple interfaces or configs */
 		cdc = 0;
 		cdc = 0;
 		rndis = 0;
 		rndis = 0;
 	} else if (gadget_is_sa1100 (gadget)) {
 	} else if (gadget_is_sa1100 (gadget)) {
-		device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205);
 		/* hardware can't write zlps */
 		/* hardware can't write zlps */
 		zlp = 0;
 		zlp = 0;
 		/* sa1100 CAN do CDC, without status endpoint ... we use
 		/* sa1100 CAN do CDC, without status endpoint ... we use
 		 * non-CDC to be compatible with ARM Linux-2.4 "usb-eth".
 		 * non-CDC to be compatible with ARM Linux-2.4 "usb-eth".
 		 */
 		 */
 		cdc = 0;
 		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
 		/* can't assume CDC works.  don't want to default to
 		 * anything less functional on CDC-capable hardware,
 		 * anything less functional on CDC-capable hardware,
 		 * so we fail in this case.
 		 * 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)
 static int __init check_parameters(struct fsg_dev *fsg)
 {
 {
 	int	prot;
 	int	prot;
+	int	gcnum;
 
 
 	/* Store the default values */
 	/* Store the default values */
 	mod_data.transport_type = USB_PR_BULK;
 	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;
 		mod_data.can_stall = 0;
 
 
 	if (mod_data.release == 0xffff) {	// Parameter wasn't set
 	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 */
 		/* 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 {
 		else {
 			WARN(fsg, "controller '%s' not recognized\n",
 			WARN(fsg, "controller '%s' not recognized\n",
 				fsg->gadget->name);
 				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
  * This could eventually work like the ARM mach_is_*() stuff, driven by
  * some config file that gets updated as new hardware is supported.
  * 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.
  * NOTE:  some of these controller drivers may not be available yet.
  */
  */
@@ -86,7 +87,61 @@
 #define gadget_is_at91(g)	0
 #define gadget_is_at91(g)	0
 #endif
 #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_SX2
 // CONFIG_USB_GADGET_AU1X00
 // 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;
 	int ret;
 	struct usb_ep *ep;
 	struct usb_ep *ep;
 	struct gs_dev *dev;
 	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;
 		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 =
 		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",
 		printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
 			gadget->name);
 			gadget->name);
 		/* unrecognized, but safe unless bulk is REALLY quirky */
 		/* 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 zero_dev		*dev;
 	struct usb_ep		*ep;
 	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
 	/* Bulk-only drivers like this one SHOULD be able to
 	 * autoconfigure on any sane usb controller driver,
 	 * autoconfigure on any sane usb controller driver,
@@ -1161,43 +1168,10 @@ autoconf_fail:
 	EP_OUT_NAME = ep->name;
 	EP_OUT_NAME = ep->name;
 	ep->driver_data = ep;	/* claim */
 	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
 		/* gadget zero is so simple (for now, no altsettings) that
 		 * it SHOULD NOT have problems with bulk-capable hardware.
 		 * it SHOULD NOT have problems with bulk-capable hardware.
 		 * so warn about unrcognized controllers, don't panic.
 		 * so warn about unrcognized controllers, don't panic.

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

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

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

@@ -700,6 +700,7 @@ iso_stream_init (
 
 
 	} else {
 	} else {
 		u32		addr;
 		u32		addr;
+		int		think_time;
 
 
 		addr = dev->ttport << 24;
 		addr = dev->ttport << 24;
 		if (!ehci_is_TDI(ehci)
 		if (!ehci_is_TDI(ehci)
@@ -709,6 +710,9 @@ iso_stream_init (
 		addr |= epnum << 8;
 		addr |= epnum << 8;
 		addr |= dev->devnum;
 		addr |= dev->devnum;
 		stream->usecs = HS_USECS_ISO (maxp);
 		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) {
 		if (is_input) {
 			u32	tmp;
 			u32	tmp;
 
 

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

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

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

@@ -83,7 +83,7 @@
 #include "../core/hcd.h"
 #include "../core/hcd.h"
 #include "isp116x.h"
 #include "isp116x.h"
 
 
-#define DRIVER_VERSION	"08 Apr 2005"
+#define DRIVER_VERSION	"05 Aug 2005"
 #define DRIVER_DESC	"ISP116x USB Host Controller Driver"
 #define DRIVER_DESC	"ISP116x USB Host Controller Driver"
 
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 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");
 			ERR("Unrecoverable error\n");
 			/* What should we do here? Reset?  */
 			/* 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) {
 		if (intstat & HCINT_RD) {
 			DBG("---- remote wakeup\n");
 			DBG("---- remote wakeup\n");
 			schedule_work(&isp116x->rh_resume);
 			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);
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
 	int ports, i, changed = 0;
 	int ports, i, changed = 0;
+	unsigned long flags;
 
 
 	if (!HC_IS_RUNNING(hcd->state))
 	if (!HC_IS_RUNNING(hcd->state))
 		return -ESHUTDOWN;
 		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))
 	if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC))
 		buf[0] = changed = 1;
 		buf[0] = changed = 1;
 	else
 	else
 		buf[0] = 0;
 		buf[0] = 0;
 
 
 	for (i = 0; i < ports; i++) {
 	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
 		if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
 			      | RH_PS_OCIC | RH_PS_PRSC)) {
 			      | RH_PS_OCIC | RH_PS_PRSC)) {
@@ -947,6 +952,7 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
 			continue;
 			continue;
 		}
 		}
 	}
 	}
+	spin_unlock_irqrestore(&isp116x->lock, flags);
 	return changed;
 	return changed;
 }
 }
 
 
@@ -1463,10 +1469,6 @@ static int isp116x_sw_reset(struct isp116x *isp116x)
 	return ret;
 	return ret;
 }
 }
 
 
-/*
-  Reset. Tries to perform platform-specific hardware
-  reset first; falls back to software reset.
-*/
 static int isp116x_reset(struct usb_hcd *hcd)
 static int isp116x_reset(struct usb_hcd *hcd)
 {
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
@@ -1474,17 +1476,7 @@ static int isp116x_reset(struct usb_hcd *hcd)
 	u16 clkrdy = 0;
 	u16 clkrdy = 0;
 	int ret = 0, timeout = 15 /* ms */ ;
 	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)
 	if (ret)
 		return ret;
 		return ret;
 
 
@@ -1501,10 +1493,7 @@ static int isp116x_reset(struct usb_hcd *hcd)
 		ERR("Clock not ready after 20ms\n");
 		ERR("Clock not ready after 20ms\n");
 		/* After sw_reset the clock won't report to be ready, if
 		/* After sw_reset the clock won't report to be ready, if
 		   H_WAKEUP pin is high. */
 		   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;
 		ret = -ENODEV;
 	}
 	}
 	return ret;
 	return ret;
@@ -1527,15 +1516,7 @@ static void isp116x_stop(struct usb_hcd *hcd)
 	isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
 	isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
 	spin_unlock_irqrestore(&isp116x->lock, flags);
 	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;
 		return -ENODEV;
 	}
 	}
 
 
+	/* To be removed in future */
+	hcd->uses_new_polling = 1;
+
 	isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
 	isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
 	isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
 	isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
 
 
@@ -1569,7 +1553,7 @@ static int isp116x_start(struct usb_hcd *hcd)
 	if (board->sel15Kres)
 	if (board->sel15Kres)
 		val |= HCHWCFG_15KRSEL;
 		val |= HCHWCFG_15KRSEL;
 	/* Remote wakeup won't work without working clock */
 	/* Remote wakeup won't work without working clock */
-	if (board->clknotstop || board->remote_wakeup_enable)
+	if (board->remote_wakeup_enable)
 		val |= HCHWCFG_CLKNOTSTOP;
 		val |= HCHWCFG_CLKNOTSTOP;
 	if (board->oc_enable)
 	if (board->oc_enable)
 		val |= HCHWCFG_ANALOG_OC;
 		val |= HCHWCFG_ANALOG_OC;
@@ -1580,16 +1564,13 @@ static int isp116x_start(struct usb_hcd *hcd)
 	isp116x_write_reg16(isp116x, HCHWCFG, val);
 	isp116x_write_reg16(isp116x, HCHWCFG, val);
 
 
 	/* ----- Root hub conf */
 	/* ----- 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_write_reg32(isp116x, HCRHDESCA, val);
 	isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
 	isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
 
 
@@ -1619,9 +1600,6 @@ static int isp116x_start(struct usb_hcd *hcd)
 
 
 	/* Go operational */
 	/* Go operational */
 	val = HCCONTROL_USB_OPER;
 	val = HCCONTROL_USB_OPER;
-	/* Remote wakeup connected - NOT SUPPORTED */
-	/*  if (board->remote_wakeup_connected)
-	   val |= HCCONTROL_RWC;  */
 	if (board->remote_wakeup_enable)
 	if (board->remote_wakeup_enable)
 		val |= HCCONTROL_RWE;
 		val |= HCCONTROL_RWE;
 	isp116x_write_reg32(isp116x, HCCONTROL, val);
 	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 platform_device *pdev;
 	struct resource *res;
 	struct resource *res;
 
 
-	if(!hcd)
+	if (!hcd)
 		return 0;
 		return 0;
 	isp116x = hcd_to_isp116x(hcd);
 	isp116x = hcd_to_isp116x(hcd);
 	pdev = container_of(dev, struct platform_device, dev);
 	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.
  * This file is licenced under the GPL.
  */
  */
 
 
-#include <asm/usb.h>
-
 /* configure so an HC device and id are always provided */
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
 /* always called with process context; sleeping is OK */
 
 
@@ -23,9 +21,7 @@
  * usb_hcd_ppc_soc_probe - initialize On-Chip HCDs
  * usb_hcd_ppc_soc_probe - initialize On-Chip HCDs
  * Context: !in_interrupt()
  * 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().
  * 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 ohci_hcd	*ohci;
 	struct resource *res;
 	struct resource *res;
 	int irq;
 	int irq;
-	struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
 
 
 	pr_debug("initializing PPC-SOC USB Controller\n");
 	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;
 		goto err2;
 	}
 	}
 
 
-	if (pd->start && (retval = pd->start(pdev)))
-		goto err3;
-
 	ohci = hcd_to_ohci(hcd);
 	ohci = hcd_to_ohci(hcd);
 	ohci->flags |= OHCI_BIG_ENDIAN;
 	ohci->flags |= OHCI_BIG_ENDIAN;
 	ohci_hcd_init(ohci);
 	ohci_hcd_init(ohci);
@@ -85,9 +77,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
 		return retval;
 		return retval;
 
 
 	pr_debug("Removing PPC-SOC USB Controller\n");
 	pr_debug("Removing PPC-SOC USB Controller\n");
-	if (pd && pd->stop)
-		pd->stop(pdev);
- err3:
+
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
  err2:
  err2:
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	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
  * @pdev: USB Host Controller being removed
  * Context: !in_interrupt()
  * 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.
  * context, normally "rmmod", "apmd", or something similar.
  *
  *
  */
  */
 static void usb_hcd_ppc_soc_remove(struct usb_hcd *hcd,
 static void usb_hcd_ppc_soc_remove(struct usb_hcd *hcd,
 		struct platform_device *pdev)
 		struct platform_device *pdev)
 {
 {
-	struct usb_hcd_platform_data *pd = pdev->dev.platform_data;
-
 	usb_remove_hcd(hcd);
 	usb_remove_hcd(hcd);
 
 
 	pr_debug("stopping PPC-SOC USB Controller\n");
 	pr_debug("stopping PPC-SOC USB Controller\n");
-	if (pd && pd->stop)
-		pd->stop(pdev);
 
 
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	usb_hcd_put(hcd);
+	usb_put_hcd(hcd);
 }
 }
 
 
 static int __devinit
 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) {
 	if (info->power_control != NULL) {
 		info->port[port-1].power = to;
 		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;
 	struct usb_hcd *hcd = NULL;
 	int retval;
 	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, 1, 1);
+	s3c2410_usb_set_power(dev->dev.platform_data, 2, 1);
 
 
 	hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
 	hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
 	if (hcd == NULL)
 	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
 	  To compile this driver as a module, choose M here: the
 	  module will be called touchkitusb.
 	  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
 config USB_XPAD
 	tristate "X-Box gamepad support"
 	tristate "X-Box gamepad support"
 	depends on USB && INPUT
 	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_POWERMATE)	+= powermate.o
 obj-$(CONFIG_USB_WACOM)		+= wacom.o
 obj-$(CONFIG_USB_WACOM)		+= wacom.o
 obj-$(CONFIG_USB_ACECAD)	+= acecad.o
 obj-$(CONFIG_USB_ACECAD)	+= acecad.o
+obj-$(CONFIG_USB_YEALINK)	+= yealink.o
 obj-$(CONFIG_USB_XPAD)		+= xpad.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_NETWORKANALYSER	0x2020
 #define USB_DEVICE_ID_POWERCONTROL	0x2030
 #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.
  * 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_22, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, 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_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_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_IOW40, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, 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,
 			usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0,
 					 hid_irq_in, hid, interval);
 					 hid_irq_in, hid, interval);
 			hid->urbin->transfer_dma = hid->inbuf_dma;
 			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 {
 		} else {
 			if (hid->urbout)
 			if (hid->urbout)
 				continue;
 				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,
 			usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0,
 					 hid_irq_out, hid, interval);
 					 hid_irq_out, hid, interval);
 			hid->urbout->transfer_dma = hid->outbuf_dma;
 			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->ctrlbuf, 1, hid_ctrl, hid);
 	hid->urbctrl->setup_dma = hid->cr_dma;
 	hid->urbctrl->setup_dma = hid->cr_dma;
 	hid->urbctrl->transfer_dma = hid->ctrlbuf_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;
 	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_endpoint_descriptor *endpoint;
 	struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface));
 	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 */
 	/* allocate memory for our device state and initialize it */
 	remote = kmalloc(sizeof(*remote), GFP_KERNEL);
 	remote = kmalloc(sizeof(*remote), GFP_KERNEL);
 	if (remote == NULL) {
 	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
 /* cancel an urb which is submitted to the chain
    the result is 0 if the urb is cancelled, or -EINPROGRESS if
    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)
 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;
         acep = acp->active;
         if (acep) {
         if (acep) {
                 urbp = acep->urbp;
                 urbp = acep->urbp;
-                urbp->transfer_flags &= ~URB_ASYNC_UNLINK;
                 dbg ("unlink active urb");
                 dbg ("unlink active urb");
                 usb_kill_urb (urbp);
                 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));
 	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);
 	bytes_to_read = min(count, *actual_buffer);
 	if (bytes_to_read < *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);
 			 *actual_buffer-bytes_to_read);
 
 
 	/* copy one interrupt_in_buffer from ring_buffer into userspace */
 	/* 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 */
 	/* write the data into interrupt_out_buffer from userspace */
 	bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
 	bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
 	if (bytes_to_write < count)
 	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)) {
 	if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
 		retval = -EFAULT;
 		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,
 	usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
 		sisusb_bulk_completeout, &sisusb->urbout_context[index]);
 		sisusb_bulk_completeout, &sisusb->urbout_context[index]);
 
 
-	urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
+	urb->transfer_flags |= tflags;
 	urb->actual_length = 0;
 	urb->actual_length = 0;
 
 
 	if ((urb->transfer_dma = transfer_dma))
 	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,
 	usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len,
 			sisusb_bulk_completein, sisusb);
 			sisusb_bulk_completein, sisusb);
 
 
-	urb->transfer_flags |= (tflags | URB_ASYNC_UNLINK);
+	urb->transfer_flags |= tflags;
 	urb->actual_length = 0;
 	urb->actual_length = 0;
 
 
 	if ((urb->transfer_dma = transfer_dma))
 	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->context = &context;
 		u->complete = ctrl_complete;
 		u->complete = ctrl_complete;
-		u->transfer_flags |= URB_ASYNC_UNLINK;
 	}
 	}
 
 
 	/* queue the urbs */
 	/* 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);
 	urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size);
 	if (!urb)
 	if (!urb)
 		return -ENOMEM;
 		return -ENOMEM;
-	urb->transfer_flags |= URB_ASYNC_UNLINK;
 	urb->context = &completion;
 	urb->context = &completion;
 	urb->complete = unlink1_callback;
 	urb->complete = unlink1_callback;
 
 

+ 1 - 1
drivers/usb/mon/Makefile

@@ -2,7 +2,7 @@
 # Makefile for USB Core files and filesystem
 # 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.
 # This does not use CONFIG_USB_MON because we want this to use a tristate.
 obj-$(CONFIG_USB)	+= usbmon.o
 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 len, char ev_type)
 {
 {
 	int pipe = urb->pipe;
 	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)
 	if (len <= 0)
 		return 'L';
 		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. 
 	 * 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);
 	memcpy(ep->data, urb->transfer_buffer, len);
 	return 0;
 	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_add(struct mon_bus *mbus, struct mon_reader *r);
 void mon_reader_del(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 semaphore mon_lock;
 
 
 extern struct file_operations mon_fops_text;
 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
 	  with "minidrivers" built around a common network driver core
 	  that supports deep queues for efficient transfers.  (This gives
 	  that supports deep queues for efficient transfers.  (This gives
 	  better performance with small packets and at high speeds).
 	  better performance with small packets and at high speeds).
-	  
+
 	  The USB host runs "usbnet", and the other end of the link might be:
 	  The USB host runs "usbnet", and the other end of the link might be:
 
 
 	  - Another USB host, when using USB "network" or "data transfer"
 	  - 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
 	  To compile this driver as a module, choose M here: the
 	  module will be called usbnet.
 	  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
 	default y
 	help
 	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
 	depends on USB_USBNET
 	default y
 	default y
 	help
 	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
 	depends on USB_USBNET
 	help
 	help
 	  Choose this option if you're using a host-to-host cable,
 	  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.
 	  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
 	default y
 	depends on USB_USBNET
 	depends on USB_USBNET
 	help
 	help
 	  Choose this option if you're using a host-to-host cable based
 	  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
 	depends on USB_USBNET && EXPERIMENTAL
 	help
 	help
 	  Choose this option if you're using a host-to-host cable
 	  Choose this option if you're using a host-to-host cable
 	  with one of these chips.
 	  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
 	depends on USB_USBNET && EXPERIMENTAL
+	select USB_NET_CDCETHER
 	help
 	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
 	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
 config USB_ARMLINUX
 	boolean "Embedded ARM Linux links (iPaq, ...)"
 	boolean "Embedded ARM Linux links (iPaq, ...)"
-	depends on USB_USBNET
+	depends on USB_NET_CDC_SUBSET
 	default y
 	default y
 	help
 	help
 	  Choose this option to support the "usb-eth" networking driver
 	  Choose this option to support the "usb-eth" networking driver
@@ -212,15 +277,15 @@ config USB_ARMLINUX
 
 
 config USB_EPSON2888
 config USB_EPSON2888
 	boolean "Epson 2888 based firmware (DEVELOPMENT)"
 	boolean "Epson 2888 based firmware (DEVELOPMENT)"
-	depends on USB_USBNET
-	default y
+	depends on USB_NET_CDC_SUBSET
 	help
 	help
 	  Choose this option to support the usb networking links used
 	  Choose this option to support the usb networking links used
 	  by some sample firmware from Epson.
 	  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
 	depends on USB_USBNET
+	select USB_NET_CDCETHER
 	select CRC32
 	select CRC32
 	default y
 	default y
 	help
 	help
@@ -235,61 +300,6 @@ config USB_ZAURUS
 	  really need this non-conformant variant of CDC Ethernet (or in
 	  really need this non-conformant variant of CDC Ethernet (or in
 	  some cases CDC MDLM) protocol, not "g_ether".
 	  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
 config USB_ZD1201
 	tristate "USB ZD1201 based Wireless device support"
 	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_KAWETH)	+= kaweth.o
 obj-$(CONFIG_USB_PEGASUS)	+= pegasus.o
 obj-$(CONFIG_USB_PEGASUS)	+= pegasus.o
 obj-$(CONFIG_USB_RTL8150)	+= rtl8150.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_USBNET)	+= usbnet.o
 obj-$(CONFIG_USB_ZD1201)	+= zd1201.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) {
 	if (urb->status == -ECONNRESET) {
 		dbg("Tx Reset.");
 		dbg("Tx Reset.");
-		urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 		urb->status = 0;
 		urb->status = 0;
 		catc->netdev->trans_start = jiffies;
 		catc->netdev->trans_start = jiffies;
 		catc->stats.tx_errors++;
 		catc->stats.tx_errors++;
@@ -445,7 +444,6 @@ static void catc_tx_timeout(struct net_device *netdev)
 	struct catc *catc = netdev_priv(netdev);
 	struct catc *catc = netdev_priv(netdev);
 
 
 	warn("Transmit timed out.");
 	warn("Transmit timed out.");
-	catc->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 	usb_unlink_urb(catc->tx_urb);
 	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_usb_transmit_complete,
 		      kaweth);
 		      kaweth);
 	kaweth->end = 0;
 	kaweth->end = 0;
-	kaweth->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 
 
 	if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
 	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);
 	pegasus_t *pegasus = netdev_priv(net);
 	if (netif_msg_timer(pegasus))
 	if (netif_msg_timer(pegasus))
 		printk(KERN_WARNING "%s: tx timeout\n", net->name);
 		printk(KERN_WARNING "%s: tx timeout\n", net->name);
-	pegasus->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 	usb_unlink_urb(pegasus->tx_urb);
 	usb_unlink_urb(pegasus->tx_urb);
 	pegasus->stats.tx_errors++;
 	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);
 	rtl8150_t *dev = netdev_priv(netdev);
 	warn("%s: Tx timeout.", netdev->name);
 	warn("%s: Tx timeout.", netdev->name);
-	dev->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 	usb_unlink_urb(dev->tx_urb);
 	usb_unlink_urb(dev->tx_urb);
 	dev->stats.tx_errors++;
 	dev->stats.tx_errors++;
 }
 }

+ 217 - 3233
drivers/usb/net/usbnet.c

@@ -1,10 +1,7 @@
 /*
 /*
- * USB Networking Links
- * Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net>
- * Copyright (C) 2002 Pavel Machek <pavel@ucw.cz>
+ * USB Network driver infrastructure
+ * Copyright (C) 2000-2005 by David Brownell
  * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
  * 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
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -23,95 +20,15 @@
 
 
 /*
 /*
  * This is a generic "USB networking" framework that works with several
  * This is a generic "USB networking" framework that works with several
- * kinds of full and high speed networking devices:
- *
- *   + USB host-to-host "network cables", used for IP-over-USB links.
- *     These are often used for Laplink style connectivity products.
- *	- AnchorChip 2720
- *	- Belkin, eTEK (interops with Win32 drivers)
- *	- GeneSys GL620USB-A
- *	- NetChip 1080 (interoperates with NetChip Win32 drivers)
- *	- Prolific PL-2301/2302 (replaces "plusb" driver)
- *	- KC Technology KC2190
- *
- *   + Smart USB devices can support such links directly, using Internet
- *     standard protocols instead of proprietary host-to-device links.
- *	- Linux PDAs like iPaq, Yopy, and Zaurus
- *	- The BLOB boot loader (for diskless booting)
- *	- Linux "gadgets", perhaps using PXA-2xx or Net2280 controllers
- *	- Devices using EPSON's sample USB firmware
- *	- CDC-Ethernet class devices, such as many cable modems
- *
- *   + Adapters to networks such as Ethernet.
- *	- AX8817X based USB 2.0 products
- *
- * Links to these devices can be bridged using Linux Ethernet bridging.
- * With minor exceptions, these all use similar USB framing for network
- * traffic, but need different protocols for control traffic.
- *
- * USB devices can implement their side of this protocol at the cost
- * of two bulk endpoints; it's not restricted to "cable" applications.
- * See the SA1110, Zaurus, or EPSON device/client support in this driver;
- * slave/target drivers such as "usb-eth" (on most SA-1100 PDAs) or
- * "g_ether" (in the Linux "gadget" framework) implement that behavior
- * within devices.
- *
- *
- * CHANGELOG:
- *
- * 13-sep-2000	experimental, new
- * 10-oct-2000	usb_device_id table created. 
- * 28-oct-2000	misc fixes; mostly, discard more TTL-mangled rx packets.
- * 01-nov-2000	usb_device_id table and probing api update by
- *		Adam J. Richter <adam@yggdrasil.com>.
- * 18-dec-2000	(db) tx watchdog, "net1080" renaming to "usbnet", device_info
- *		and prolific support, isolate net1080-specific bits, cleanup.
- *		fix unlink_urbs oops in D3 PM resume code path.
- *
- * 02-feb-2001	(db) fix tx skb sharing, packet length, match_flags, ...
- * 08-feb-2001	stubbed in "linuxdev", maybe the SA-1100 folk can use it;
- *		AnchorChips 2720 support (from spec) for testing;
- *		fix bit-ordering problem with ethernet multicast addr
- * 19-feb-2001  Support for clearing halt conditions. SA1100 UDC support
- *		updates. Oleg Drokin (green@iXcelerator.com)
- * 25-mar-2001	More SA-1100 updates, including workaround for ip problem
- *		expecting cleared skb->cb and framing change to match latest
- *		handhelds.org version (Oleg).  Enable device IDs from the
- *		Win32 Belkin driver; other cleanups (db).
- * 16-jul-2001	Bugfixes for uhci oops-on-unplug, Belkin support, various
- *		cleanups for problems not yet seen in the field. (db)
- * 17-oct-2001	Handle "Advance USBNET" product, like Belkin/eTEK devices,
- *		from Ioannis Mavroukakis <i.mavroukakis@btinternet.com>;
- *		rx unlinks somehow weren't async; minor cleanup.
- * 03-nov-2001	Merged GeneSys driver; original code from Jiun-Jie Huang
- *		<huangjj@genesyslogic.com.tw>, updated by Stanislav Brabec
- *		<utx@penguin.cz>.  Made framing options (NetChip/GeneSys)
- *		tie mostly to (sub)driver info.  Workaround some PL-2302
- *		chips that seem to reject SET_INTERFACE requests.
- *
- * 06-apr-2002	Added ethtool support, based on a patch from Brad Hards.
- *		Level of diagnostics is more configurable; they use device
- *		location (usb_device->devpath) instead of address (2.5).
- *		For tx_fixup, memflags can't be NOIO.
- * 07-may-2002	Generalize/cleanup keventd support, handling rx stalls (mostly
- *		for USB 2.0 TTs) and memory shortages (potential) too. (db)
- *		Use "locally assigned" IEEE802 address space. (Brad Hards)
- * 18-oct-2002	Support for Zaurus (Pavel Machek), related cleanup (db).
- * 14-dec-2002	Remove Zaurus-private crc32 code (Pavel); 2.5 oops fix,
- * 		cleanups and stubbed PXA-250 support (db), fix for framing
- * 		issues on Z, net1080, and gl620a (Toby Milne)
- *
- * 31-mar-2003	Use endpoint descriptors:  high speed support, simpler sa1100
- * 		vs pxa25x, and CDC Ethernet.  Throttle down log floods on
- * 		disconnect; other cleanups. (db)  Flush net1080 fifos
- * 		after several sequential framing errors. (Johannes Erdfelt)
- * 22-aug-2003	AX8817X support (Dave Hollis).
- * 14-jun-2004  Trivial patch for AX8817X based Buffalo LUA-U2-KTX in Japan
- *		(Neil Bortnak)
- * 03-nov-2004	Trivial patch for KC2190 (KC-190) chip. (Jonathan McDowell)
- *
- * 01-feb-2005	AX88772 support (Phil Chang & Dave Hollis)
- *-------------------------------------------------------------------------*/
+ * kinds of full and high speed networking devices:  host-to-host cables,
+ * smart usb peripherals, and actual Ethernet adapters.
+ *
+ * These devices usually differ in terms of control protocols (if they
+ * even have one!) and sometimes they define new framing to wrap or batch
+ * Ethernet packets.  Otherwise, they talk to USB pretty much the same,
+ * so interface (un)binding, endpoint I/O queues, fault handling, and other
+ * issues can usefully be addressed by this framework.
+ */
 
 
 // #define	DEBUG			// error path messages, extra info
 // #define	DEBUG			// error path messages, extra info
 // #define	VERBOSE			// more; success messages
 // #define	VERBOSE			// more; success messages
@@ -121,24 +38,18 @@
 #   define DEBUG
 #   define DEBUG
 #endif
 #endif
 #include <linux/module.h>
 #include <linux/module.h>
-#include <linux/kmod.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/random.h>
 #include <linux/ethtool.h>
 #include <linux/ethtool.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 #include <linux/mii.h>
 #include <linux/mii.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
-#include <linux/mm.h>
-#include <linux/dma-mapping.h>
 
 
-#define DRIVER_VERSION		"03-Nov-2004"
+#include "usbnet.h"
+
+#define DRIVER_VERSION		"22-Aug-2005"
 
 
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -149,15 +60,14 @@
  * One maximum size Ethernet packet takes twenty four of them.
  * One maximum size Ethernet packet takes twenty four of them.
  * For high speed, each frame comfortably fits almost 36 max size
  * For high speed, each frame comfortably fits almost 36 max size
  * Ethernet packets (so queues should be bigger).
  * Ethernet packets (so queues should be bigger).
+ *
+ * REVISIT qlens should be members of 'struct usbnet'; the goal is to
+ * let the USB host controller be busy for 5msec or more before an irq
+ * is required, under load.  Jumbograms change the equation.
  */
  */
 #define	RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
 #define	RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
 #define	TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
 #define	TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
 
 
-// packets are always ethernet inside
-// ... except they can be bigger (limit of 64K with NetChip framing)
-#define MIN_PACKET	sizeof(struct ethhdr)
-#define MAX_PACKET	32768
-
 // reawaken network queue this soon after stopping; else watchdog barks
 // reawaken network queue this soon after stopping; else watchdog barks
 #define TX_TIMEOUT_JIFFIES	(5*HZ)
 #define TX_TIMEOUT_JIFFIES	(5*HZ)
 
 
@@ -165,2698 +75,150 @@
 // us (it polls at HZ/4 usually) before we report too many false errors.
 // us (it polls at HZ/4 usually) before we report too many false errors.
 #define THROTTLE_JIFFIES	(HZ/8)
 #define THROTTLE_JIFFIES	(HZ/8)
 
 
-// for vendor-specific control operations
-#define	CONTROL_TIMEOUT_MS	500
-
-// between wakeups
-#define UNLINK_TIMEOUT_MS	3
-
-/*-------------------------------------------------------------------------*/
-
-// randomly generated ethernet address
-static u8	node_id [ETH_ALEN];
-
-// state we keep for each device 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];
-
-	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
-};
-
-// device-specific info used by the driver
-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, int flags);
-
-	// FIXME -- also an interrupt mechanism
-	// useful for at least PL2301/2302 and GL620USB-A
-	// and CDC use them to report 'is it connected' changes
-
-	/* for new devices, use the descriptor-reading code instead */
-	int		in;		/* rx endpoint */
-	int		out;		/* tx endpoint */
-
-	unsigned long	data;		/* Misc driver specific data */
-};
-
-// 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;
-};
-
-static const char driver_name [] = "usbnet";
-
-/* use ethtool to change the level for any given device */
-static int msg_level = -1;
-module_param (msg_level, int, 0);
-MODULE_PARM_DESC (msg_level, "Override default message level");
-
-
-#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); \
-
-/*-------------------------------------------------------------------------*/
-
-static void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
-static u32 usbnet_get_link (struct net_device *);
-static u32 usbnet_get_msglevel (struct net_device *);
-static void usbnet_set_msglevel (struct net_device *, u32);
-static void defer_kevent (struct usbnet *, int);
-
-/* mostly for PDA style devices, which are always connected if present */
-static int always_connected (struct usbnet *dev)
-{
-	return 0;
-}
-
-/* handles CDC Ethernet and many other network "bulk data" interfaces */
-static int
-get_endpoints (struct usbnet *dev, struct usb_interface *intf)
-{
-	int				tmp;
-	struct usb_host_interface	*alt = NULL;
-	struct usb_host_endpoint	*in = NULL, *out = NULL;
-	struct usb_host_endpoint	*status = NULL;
-
-	for (tmp = 0; tmp < intf->num_altsetting; tmp++) {
-		unsigned	ep;
-
-		in = out = status = NULL;
-		alt = intf->altsetting + tmp;
-
-		/* take the first altsetting with in-bulk + out-bulk;
-		 * remember any status endpoint, just in case;
-		 * ignore other endpoints and altsetttings.
-		 */
-		for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) {
-			struct usb_host_endpoint	*e;
-			int				intr = 0;
-
-			e = alt->endpoint + ep;
-			switch (e->desc.bmAttributes) {
-			case USB_ENDPOINT_XFER_INT:
-				if (!(e->desc.bEndpointAddress & USB_DIR_IN))
-					continue;
-				intr = 1;
-				/* FALLTHROUGH */
-			case USB_ENDPOINT_XFER_BULK:
-				break;
-			default:
-				continue;
-			}
-			if (e->desc.bEndpointAddress & USB_DIR_IN) {
-				if (!intr && !in)
-					in = e;
-				else if (intr && !status)
-					status = e;
-			} else {
-				if (!out)
-					out = e;
-			}
-		}
-		if (in && out)
-			break;
-	}
-	if (!alt || !in || !out)
-		return -EINVAL;
-
-	if (alt->desc.bAlternateSetting != 0
-			|| !(dev->driver_info->flags & FLAG_NO_SETINT)) {
-		tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber,
-				alt->desc.bAlternateSetting);
-		if (tmp < 0)
-			return tmp;
-	}
-	
-	dev->in = usb_rcvbulkpipe (dev->udev,
-			in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-	dev->out = usb_sndbulkpipe (dev->udev,
-			out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-	dev->status = status;
-	return 0;
-}
-
-static void intr_complete (struct urb *urb, struct pt_regs *regs);
-
-static int init_status (struct usbnet *dev, struct usb_interface *intf)
-{
-	char		*buf = NULL;
-	unsigned	pipe = 0;
-	unsigned	maxp;
-	unsigned	period;
-
-	if (!dev->driver_info->status)
-		return 0;
-
-	pipe = usb_rcvintpipe (dev->udev,
-			dev->status->desc.bEndpointAddress
-				& USB_ENDPOINT_NUMBER_MASK);
-	maxp = usb_maxpacket (dev->udev, pipe, 0);
-
-	/* avoid 1 msec chatter:  min 8 msec poll rate */
-	period = max ((int) dev->status->desc.bInterval,
-		(dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3);
-
-	buf = kmalloc (maxp, SLAB_KERNEL);
-	if (buf) {
-		dev->interrupt = usb_alloc_urb (0, SLAB_KERNEL);
-		if (!dev->interrupt) {
-			kfree (buf);
-			return -ENOMEM;
-		} else {
-			usb_fill_int_urb(dev->interrupt, dev->udev, pipe,
-				buf, maxp, intr_complete, dev, period);
-			dev_dbg(&intf->dev,
-				"status ep%din, %d bytes period %d\n",
-				usb_pipeendpoint(pipe), maxp, period);
-		}
-	}
-	return  0;
-}
-
-static void skb_return (struct usbnet *dev, struct sk_buff *skb)
-{
-	int	status;
-
-	skb->dev = dev->net;
-	skb->protocol = eth_type_trans (skb, dev->net);
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += skb->len;
-
-	if (netif_msg_rx_status (dev))
-		devdbg (dev, "< rx, len %zu, type 0x%x",
-			skb->len + sizeof (struct ethhdr), skb->protocol);
-	memset (skb->cb, 0, sizeof (struct skb_data));
-	status = netif_rx (skb);
-	if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev))
-		devdbg (dev, "netif_rx status %d", status);
-}
-
-
-#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_AX8817X
-/* ASIX AX8817X based USB 2.0 Ethernet Devices */
-
-#define HAVE_HARDWARE
-#define NEED_MII
-
-#include <linux/crc32.h>
-
-#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,
-		CONTROL_TIMEOUT_MS);
-}
-
-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,
-		CONTROL_TIMEOUT_MS);
-}
-
-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);
-			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;
-}
-
-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);
-}
-
-static int ax88172_link_reset(struct usbnet *dev)
-{
-	u16 lpa;
-	u8 mode;
-
-	mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN;
-	lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA);
-	if (lpa & 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_bind(struct usbnet *dev, struct usb_interface *intf)
-{
-	int ret = 0;
-	void *buf;
-	int i;
-	unsigned long gpio_bits = dev->driver_info->data;
-
-	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->set_multicast_list = ax8817x_set_multicast;
-	dev->net->ethtool_ops = &ax8817x_ethtool_ops;
-
-	ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
-	ax8817x_mdio_write(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;
-
-	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;
-
-	/* 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(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
-	ax8817x_mdio_write(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);
-
-	return 0;
-
-out2:
-	kfree(buf);
-out1:
-	return ret;
-}
-
-static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-{
-	u32 *header;
-	char *packet;
-	struct sk_buff *ax_skb;
-	u16 size;
-
-	header = (u32 *) skb->data;
-	le32_to_cpus(header);
-	packet = (char *)(header + 1);
-
-	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;
-			skb_return(dev, ax_skb);
-		} else {
-			return 0;
-		}
-
-		skb_pull(skb, (size + 1) & 0xfffe);
-
-		if (skb->len == 0)
-			break;
-
-		header = (u32 *) skb->data;
-		le32_to_cpus(header);
-		packet = (char *)(header + 1);
-		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,
-					int flags)
-{
-	int padlen;
-	int headroom = skb_headroom(skb);
-	int tailroom = skb_tailroom(skb);
-	u32 *packet_len;
-	u32 *padbytes_ptr;
-
-	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;
-	}
-
-	packet_len = (u32 *) skb_push(skb, 4);
-
-	packet_len = (u32 *) skb->data;
-	*packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
-
-	if ((skb->len % 512) == 0) {
-		padbytes_ptr = (u32 *) skb->tail;
-		*padbytes_ptr = 0xffff0000;
-		skb_put(skb, padlen);
-	}
-	return skb;
-}
-
-static int ax88772_link_reset(struct usbnet *dev)
-{
-	u16 lpa;
-	u16 mode;
-
-	mode = AX88772_MEDIUM_DEFAULT;
-	lpa = ax8817x_mdio_read(dev->net, dev->mii.phy_id, MII_LPA);
-
-	if ((lpa & LPA_DUPLEX) == 0)
-		mode &= ~AX88772_MEDIUM_FULL_DUPLEX;
-	if ((lpa & 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,
-};
-
-#endif /* CONFIG_USB_AX8817X */
-
-
-
-#ifdef	CONFIG_USB_BELKIN
-#define	HAVE_HARDWARE
-
-/*-------------------------------------------------------------------------
- *
- * Belkin F5U104 ... two NetChip 2280 devices + Atmel 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 */
-
-
-
-/*-------------------------------------------------------------------------
- *
- * Communications Device Class declarations.
- * Used by CDC Ethernet, and some CDC variants
- *
- *-------------------------------------------------------------------------*/
-
-#ifdef	CONFIG_USB_CDCETHER
-#define NEED_GENERIC_CDC
-#endif
-
-#ifdef	CONFIG_USB_ZAURUS
-/* Ethernet variant uses funky framing, broken ethernet addressing */
-#define NEED_GENERIC_CDC
-#endif
-
-#ifdef	CONFIG_USB_RNDIS
-/* ACM variant uses even funkier framing, complex control RPC scheme */
-#define NEED_GENERIC_CDC
-#endif
-
-
-#ifdef	NEED_GENERIC_CDC
-
-#include <linux/usb_cdc.h>
-
-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;
-};
-
-static struct usb_driver usbnet_driver;
-
-/*
- * 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.
- */
-static int 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;
-
-	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->net->mtu = le16_to_cpup (
-						&info->ether->wMaxSegmentSize)
-					- ETH_HLEN;
-			/* 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 (&usbnet_driver, info->data, dev);
-	if (status < 0)
-		return status;
-	status = get_endpoints (dev, info->data);
-	if (status < 0) {
-		/* ensure immediate exit from usbnet_disconnect */
-		usb_set_intfdata(info->data, NULL);
-		usb_driver_release_interface (&usbnet_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 (&usbnet_driver, info->data);
-		return -ENODEV;
-	}
-	return 0;
-
-bad_desc:
-	dev_info (&dev->udev->dev, "bad CDC descriptors\n");
-	return -ENODEV;
-}
-
-static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf)
-{
-	struct cdc_state		*info = (void *) &dev->data;
-
-	/* 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 (&usbnet_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 (&usbnet_driver, info->control);
-		info->control = NULL;
-	}
-}
-
-#endif	/* NEED_GENERIC_CDC */
-
-
-#ifdef	CONFIG_USB_CDCETHER
-#define	HAVE_HARDWARE
-
-/*-------------------------------------------------------------------------
- *
- * Communications Device Class, Ethernet Control model
- *
- * Takes two interfaces.  The DATA interface is inactive till an altsetting
- * is selected.  Configuration data includes class descriptors.
- *
- * This should interop with whatever the 2.4 "CDCEther.c" driver
- * (by Brad Hards) talked with.
- *
- *-------------------------------------------------------------------------*/
-
-#include <linux/ctype.h>
-
-
-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;
-	// case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:	/* RNDIS; or unsolicited */
-	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 = 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 (&usbnet_driver, info->data);
-		return status;
-	}
-
-	/* FIXME cdc-ether has some multicast code too, though it complains
-	 * in routine cases.  info->ether describes the multicast support.
-	 */
-	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 =	cdc_unbind,
-	.status =	cdc_status,
-};
-
-#endif	/* CONFIG_USB_CDCETHER */
-
-
-
-#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_GENESYS
-#define	HAVE_HARDWARE
-
-/*-------------------------------------------------------------------------
- *
- * 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.  interrupts should be generic
-// code like all other device I/O, anyway.
-
-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
-		      CONTROL_TIMEOUT_MS);
-	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 = 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);
-			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, int 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;
-
-	// FIXME little endian?
-	*packet_count = 1;
-	*packet_len = length;
-
-	// add padding byte
-	if ((skb->len % dev->maxpacket) == 0)
-		skb_put (skb, 1);
-
-	return skb;
-}
-
-static const struct driver_info	genelink_info = {
-	.description =	"Genesys GeneLink",
-	.flags =	FLAG_FRAMING_GL | FLAG_NO_SETINT,
-	.rx_fixup =	genelink_rx_fixup,
-	.tx_fixup =	genelink_tx_fixup,
-
-	.in = 1, .out = 2,
-
-#ifdef	GENELINK_ACK
-	.check_connect =genelink_check_connect,
-#endif
-};
-
-#endif /* CONFIG_USB_GENESYS */
-
-
-
-#ifdef	CONFIG_USB_NET1080
-#define	HAVE_HARDWARE
-
-/*-------------------------------------------------------------------------
- *
- * Netchip 1080 driver ... http://www.netchip.com
- * Used in LapLink cables
- *
- *-------------------------------------------------------------------------*/
-
-#define dev_packet_id	data[0]
-#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:
-	// u16	vendorId;		// from usb-if
-	// u16	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)
-
-
-/*
- * 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,
-		CONTROL_TIMEOUT_MS);
-	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
-		CONTROL_TIMEOUT_MS);
-}
-
-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)
-			|| MIN_FRAMED > skb->len
-			|| skb->len > FRAMED_SIZE (dev->net->mtu)) {
-		dev->stats.rx_frame_errors++;
-		dbg ("rx framesize %d range %d..%d mtu %d", skb->len,
-			(int)MIN_FRAMED, (int)FRAMED_SIZE (dev->net->mtu),
-			dev->net->mtu);
-		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) > 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, int flags)
-{
-	int			padlen;
-	struct sk_buff		*skb2;
-
-	padlen = ((skb->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 */
-			return skb;
-
-		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 + skb->len;
-			return skb;
-		}
-	}
-
-	/* 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);
-	return skb2;
-}
-
-static const struct driver_info	net1080_info = {
-	.description =	"NetChip TurboCONNECT",
-	.flags =	FLAG_FRAMING_NC,
-	.reset =	net1080_reset,
-	.check_connect =net1080_check_connect,
-	.rx_fixup =	net1080_rx_fixup,
-	.tx_fixup =	net1080_tx_fixup,
-};
-
-#endif /* CONFIG_USB_NET1080 */
-
-
-
-#ifdef CONFIG_USB_PL2301
-#define	HAVE_HARDWARE
-
-/*-------------------------------------------------------------------------
- *
- * 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.
- *
- *-------------------------------------------------------------------------*/
-
-/*
- * 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,
-		CONTROL_TIMEOUT_MS);
-}
-
-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,
-};
-
-#endif /* CONFIG_USB_PL2301 */
-
-
-#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 */
-
-
-#ifdef CONFIG_USB_ZAURUS
-#define	HAVE_HARDWARE
-
-#include <linux/crc32.h>
-
-/*-------------------------------------------------------------------------
- *
- * Zaurus is also a SA-1110 based PDA, but one using a different driver
- * (and framing) for its USB slave/gadget controller than the case above.
- *
- * For the current version of that driver, the main way that framing is
- * nonstandard (also from perspective of the CDC ethernet model!) is a
- * crc32, added to help detect when some sa1100 usb-to-memory DMA errata
- * haven't been fully worked around.  Also, all Zaurii use the same
- * default Ethernet address.
- *
- * PXA based models use the same framing, and also can't implement
- * set_interface properly.
- *
- * All known Zaurii lie about their standards conformance.  Most lie by
- * saying they support CDC Ethernet.  Some lie and say they support CDC
- * MDLM (as if for access to cell phone modems).  Someone, please beat 
- * on Sharp (and other such vendors) for a while with a cluestick.
- *
- *-------------------------------------------------------------------------*/
-
-static struct sk_buff *
-zaurus_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
-{
-	int			padlen;
-	struct sk_buff		*skb2;
+// between wakeups
+#define UNLINK_TIMEOUT_MS	3
 
 
-	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;
-}
+// randomly generated ethernet address
+static u8	node_id [ETH_ALEN];
 
 
-static const struct driver_info	zaurus_sl5x00_info = {
-	.description =	"Sharp Zaurus SL-5x00",
-	.flags =	FLAG_FRAMING_Z,
-	.check_connect = always_connected,
-	.bind =		generic_cdc_bind,
-	.unbind =	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 =		generic_cdc_bind,
-	.unbind =	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 =		generic_cdc_bind,
-	.unbind =	cdc_unbind,
-	.tx_fixup = 	zaurus_tx_fixup,
-};
-#define	OLYMPUS_MXL_INFO	((unsigned long)&olympus_mxl_info)
+static const char driver_name [] = "usbnet";
 
 
+/* use ethtool to change the level for any given device */
+static int msg_level = -1;
+module_param (msg_level, int, 0);
+MODULE_PARM_DESC (msg_level, "Override default message level");
 
 
-/* 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)
+/* handles CDC Ethernet and many other network "bulk data" interfaces */
+int usbnet_get_endpoints(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;
+	int				tmp;
+	struct usb_host_interface	*alt = NULL;
+	struct usb_host_endpoint	*in = NULL, *out = NULL;
+	struct usb_host_endpoint	*status = NULL;
+
+	for (tmp = 0; tmp < intf->num_altsetting; tmp++) {
+		unsigned	ep;
 
 
-	while (len > 3) {
-		if (buf [1] != USB_DT_CS_INTERFACE)
-			goto next_desc;
+		in = out = status = NULL;
+		alt = intf->altsetting + tmp;
 
 
-		/* use bDescriptorSubType, and just verify that we get a
-		 * "BLAN" (or "SAFE") descriptor.
+		/* take the first altsetting with in-bulk + out-bulk;
+		 * remember any status endpoint, just in case;
+		 * ignore other endpoints and altsetttings.
 		 */
 		 */
-		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;
+		for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) {
+			struct usb_host_endpoint	*e;
+			int				intr = 0;
+
+			e = alt->endpoint + ep;
+			switch (e->desc.bmAttributes) {
+			case USB_ENDPOINT_XFER_INT:
+				if (!(e->desc.bEndpointAddress & USB_DIR_IN))
+					continue;
+				intr = 1;
+				/* FALLTHROUGH */
+			case USB_ENDPOINT_XFER_BULK:
 				break;
 				break;
 			default:
 			default:
-				goto bad_detail;
+				continue;
 			}
 			}
-
-			/* 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] & ~02) != 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;
+			if (e->desc.bEndpointAddress & USB_DIR_IN) {
+				if (!intr && !in)
+					in = e;
+				else if (intr && !status)
+					status = e;
+			} else {
+				if (!out)
+					out = e;
 			}
 			}
-			break;
 		}
 		}
-next_desc:
-		len -= buf [0];	/* bLength */
-		buf += buf [0];
+		if (in && out)
+			break;
 	}
 	}
+	if (!alt || !in || !out)
+		return -EINVAL;
 
 
-	if (!desc || !detail) {
-		dev_dbg (&intf->dev, "missing cdc mdlm %s%sdescriptor\n",
-			desc ? "" : "func ",
-			detail ? "" : "detail ");
-		goto bad_desc;
+	if (alt->desc.bAlternateSetting != 0
+			|| !(dev->driver_info->flags & FLAG_NO_SETINT)) {
+		tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber,
+				alt->desc.bAlternateSetting);
+		if (tmp < 0)
+			return tmp;
 	}
 	}
+	
+	dev->in = usb_rcvbulkpipe (dev->udev,
+			in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+	dev->out = usb_sndbulkpipe (dev->udev,
+			out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+	dev->status = status;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usbnet_get_endpoints);
 
 
-	/* 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 get_endpoints (dev, intf);
+static void intr_complete (struct urb *urb, struct pt_regs *regs);
 
 
-bad_desc:
-	dev_info (&dev->udev->dev, "unsupported MDLM descriptors\n");
-	return -ENODEV;
-}
+static int init_status (struct usbnet *dev, struct usb_interface *intf)
+{
+	char		*buf = NULL;
+	unsigned	pipe = 0;
+	unsigned	maxp;
+	unsigned	period;
 
 
-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,
-};
+	if (!dev->driver_info->status)
+		return 0;
+
+	pipe = usb_rcvintpipe (dev->udev,
+			dev->status->desc.bEndpointAddress
+				& USB_ENDPOINT_NUMBER_MASK);
+	maxp = usb_maxpacket (dev->udev, pipe, 0);
+
+	/* avoid 1 msec chatter:  min 8 msec poll rate */
+	period = max ((int) dev->status->desc.bInterval,
+		(dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3);
+
+	buf = kmalloc (maxp, SLAB_KERNEL);
+	if (buf) {
+		dev->interrupt = usb_alloc_urb (0, SLAB_KERNEL);
+		if (!dev->interrupt) {
+			kfree (buf);
+			return -ENOMEM;
+		} else {
+			usb_fill_int_urb(dev->interrupt, dev->udev, pipe,
+				buf, maxp, intr_complete, dev, period);
+			dev_dbg(&intf->dev,
+				"status ep%din, %d bytes period %d\n",
+				usb_pipeendpoint(pipe), maxp, period);
+		}
+	}
+	return  0;
+}
 
 
-#else
+/* Passes this packet up the stack, updating its accounting.
+ * Some link protocols batch packets, so their rx_fixup paths
+ * can return clones as well as just modify the original skb.
+ */
+void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
+{
+	int	status;
 
 
-/* blacklist all those devices */
-#define	ZAURUS_STRONGARM_INFO	0
-#define	ZAURUS_PXA_INFO		0
-#define	OLYMPUS_MXL_INFO	0
+	skb->dev = dev->net;
+	skb->protocol = eth_type_trans (skb, dev->net);
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += skb->len;
 
 
-#endif
+	if (netif_msg_rx_status (dev))
+		devdbg (dev, "< rx, len %zu, type 0x%x",
+			skb->len + sizeof (struct ethhdr), skb->protocol);
+	memset (skb->cb, 0, sizeof (struct skb_data));
+	status = netif_rx (skb);
+	if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev))
+		devdbg (dev, "netif_rx status %d", status);
+}
+EXPORT_SYMBOL_GPL(usbnet_skb_return);
 
 
 
 
 /*-------------------------------------------------------------------------
 /*-------------------------------------------------------------------------
@@ -2868,22 +230,12 @@ static const struct driver_info	bogus_mdlm_info = {
 static int usbnet_change_mtu (struct net_device *net, int new_mtu)
 static int usbnet_change_mtu (struct net_device *net, int new_mtu)
 {
 {
 	struct usbnet	*dev = netdev_priv(net);
 	struct usbnet	*dev = netdev_priv(net);
+	int		ll_mtu = new_mtu + net->hard_header_len;
 
 
-	if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET)
+	if (new_mtu <= 0 || ll_mtu > dev->hard_mtu)
 		return -EINVAL;
 		return -EINVAL;
-#ifdef	CONFIG_USB_NET1080
-	if (((dev->driver_info->flags) & FLAG_FRAMING_NC)) {
-		if (FRAMED_SIZE (new_mtu) > MAX_PACKET)
-			return -EINVAL;
-	}
-#endif
-#ifdef	CONFIG_USB_GENESYS
-	if (((dev->driver_info->flags) & FLAG_FRAMING_GL)
-			&& new_mtu > GL_MAX_PACKET_LEN)
-		return -EINVAL;
-#endif
 	// no second zero-length packet read wanted after mtu-sized packets
 	// no second zero-length packet read wanted after mtu-sized packets
-	if (((new_mtu + sizeof (struct ethhdr)) % dev->maxpacket) == 0)
+	if ((ll_mtu % dev->maxpacket) == 0)
 		return -EDOM;
 		return -EDOM;
 	net->mtu = new_mtu;
 	net->mtu = new_mtu;
 	return 0;
 	return 0;
@@ -2922,7 +274,7 @@ static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_hea
  * NOTE:  annoying asymmetry:  if it's active, schedule_work() fails,
  * NOTE:  annoying asymmetry:  if it's active, schedule_work() fails,
  * but tasklet_schedule() doesn't.  hope the failure is rare.
  * but tasklet_schedule() doesn't.  hope the failure is rare.
  */
  */
-static void defer_kevent (struct usbnet *dev, int work)
+void usbnet_defer_kevent (struct usbnet *dev, int work)
 {
 {
 	set_bit (work, &dev->flags);
 	set_bit (work, &dev->flags);
 	if (!schedule_work (&dev->kevent))
 	if (!schedule_work (&dev->kevent))
@@ -2930,50 +282,24 @@ static void defer_kevent (struct usbnet *dev, int work)
 	else
 	else
 		devdbg (dev, "kevent %d scheduled", work);
 		devdbg (dev, "kevent %d scheduled", work);
 }
 }
+EXPORT_SYMBOL_GPL(usbnet_defer_kevent);
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 static void rx_complete (struct urb *urb, struct pt_regs *regs);
 static void rx_complete (struct urb *urb, struct pt_regs *regs);
 
 
-static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
+static void rx_submit (struct usbnet *dev, struct urb *urb, unsigned flags)
 {
 {
 	struct sk_buff		*skb;
 	struct sk_buff		*skb;
 	struct skb_data		*entry;
 	struct skb_data		*entry;
 	int			retval = 0;
 	int			retval = 0;
 	unsigned long		lockflags;
 	unsigned long		lockflags;
-	size_t			size;
-
-#ifdef CONFIG_USB_NET1080
-	if (dev->driver_info->flags & FLAG_FRAMING_NC)
-		size = FRAMED_SIZE (dev->net->mtu);
-	else
-#endif
-#ifdef CONFIG_USB_GENESYS
-	if (dev->driver_info->flags & FLAG_FRAMING_GL)
-		size = GL_RCV_BUF_SIZE;
-	else
-#endif
-#ifdef CONFIG_USB_ZAURUS
-	if (dev->driver_info->flags & FLAG_FRAMING_Z)
-		size = 6 + (sizeof (struct ethhdr) + dev->net->mtu);
-	else
-#endif
-#ifdef CONFIG_USB_RNDIS
-	if (dev->driver_info->flags & FLAG_FRAMING_RN)
-		size = RNDIS_MAX_TRANSFER;
-	else
-#endif
-#ifdef CONFIG_USB_AX8817X
-	if (dev->driver_info->flags & FLAG_FRAMING_AX)
-		size = 2048;
-	else
-#endif
-		size = (sizeof (struct ethhdr) + dev->net->mtu);
+	size_t			size = dev->rx_urb_size;
 
 
 	if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) {
 	if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) {
 		if (netif_msg_rx_err (dev))
 		if (netif_msg_rx_err (dev))
 			devdbg (dev, "no rx skb");
 			devdbg (dev, "no rx skb");
-		defer_kevent (dev, EVENT_RX_MEMORY);
+		usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
 		usb_free_urb (urb);
 		usb_free_urb (urb);
 		return;
 		return;
 	}
 	}
@@ -2987,7 +313,6 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
 
 
 	usb_fill_bulk_urb (urb, dev->udev, dev->in,
 	usb_fill_bulk_urb (urb, dev->udev, dev->in,
 		skb->data, size, rx_complete, skb);
 		skb->data, size, rx_complete, skb);
-	urb->transfer_flags |= URB_ASYNC_UNLINK;
 
 
 	spin_lock_irqsave (&dev->rxq.lock, lockflags);
 	spin_lock_irqsave (&dev->rxq.lock, lockflags);
 
 
@@ -2996,10 +321,10 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
 			&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
 			&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
 		switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ 
 		switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ 
 		case -EPIPE:
 		case -EPIPE:
-			defer_kevent (dev, EVENT_RX_HALT);
+			usbnet_defer_kevent (dev, EVENT_RX_HALT);
 			break;
 			break;
 		case -ENOMEM:
 		case -ENOMEM:
-			defer_kevent (dev, EVENT_RX_MEMORY);
+			usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
 			break;
 			break;
 		case -ENODEV:
 		case -ENODEV:
 			if (netif_msg_ifdown (dev))
 			if (netif_msg_ifdown (dev))
@@ -3037,7 +362,7 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
 	// else network stack removes extra byte if we forced a short packet
 	// else network stack removes extra byte if we forced a short packet
 
 
 	if (skb->len)
 	if (skb->len)
-		skb_return (dev, skb);
+		usbnet_skb_return (dev, skb);
 	else {
 	else {
 		if (netif_msg_rx_err (dev))
 		if (netif_msg_rx_err (dev))
 			devdbg (dev, "drop");
 			devdbg (dev, "drop");
@@ -3063,7 +388,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
 	switch (urb_status) {
 	switch (urb_status) {
 	    // success
 	    // success
 	    case 0:
 	    case 0:
-		if (MIN_PACKET > skb->len || skb->len > MAX_PACKET) {
+		if (skb->len < dev->net->hard_header_len) {
 			entry->state = rx_cleanup;
 			entry->state = rx_cleanup;
 			dev->stats.rx_errors++;
 			dev->stats.rx_errors++;
 			dev->stats.rx_length_errors++;
 			dev->stats.rx_length_errors++;
@@ -3078,7 +403,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
 	    // storm, recovering as needed.
 	    // storm, recovering as needed.
 	    case -EPIPE:
 	    case -EPIPE:
 		dev->stats.rx_errors++;
 		dev->stats.rx_errors++;
-		defer_kevent (dev, EVENT_RX_HALT);
+		usbnet_defer_kevent (dev, EVENT_RX_HALT);
 		// FALLTHROUGH
 		// FALLTHROUGH
 
 
 	    // software-driven interface shutdown
 	    // software-driven interface shutdown
@@ -3320,55 +645,58 @@ done:
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
+/* ethtool methods; minidrivers may need to add some more, but
+ * they'll probably want to use this base set.
+ */
+
+void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
 {
 {
 	struct usbnet *dev = netdev_priv(net);
 	struct usbnet *dev = netdev_priv(net);
 
 
+	/* REVISIT don't always return "usbnet" */
 	strncpy (info->driver, driver_name, sizeof info->driver);
 	strncpy (info->driver, driver_name, sizeof info->driver);
 	strncpy (info->version, DRIVER_VERSION, sizeof info->version);
 	strncpy (info->version, DRIVER_VERSION, sizeof info->version);
 	strncpy (info->fw_version, dev->driver_info->description,
 	strncpy (info->fw_version, dev->driver_info->description,
 		sizeof info->fw_version);
 		sizeof info->fw_version);
 	usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info);
 	usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info);
 }
 }
+EXPORT_SYMBOL_GPL(usbnet_get_drvinfo);
 
 
 static u32 usbnet_get_link (struct net_device *net)
 static u32 usbnet_get_link (struct net_device *net)
 {
 {
 	struct usbnet *dev = netdev_priv(net);
 	struct usbnet *dev = netdev_priv(net);
 
 
-	/* If a check_connect is defined, return it's results */
+	/* If a check_connect is defined, return its result */
 	if (dev->driver_info->check_connect)
 	if (dev->driver_info->check_connect)
 		return dev->driver_info->check_connect (dev) == 0;
 		return dev->driver_info->check_connect (dev) == 0;
 
 
-	/* Otherwise, we're up to avoid breaking scripts */
+	/* Otherwise, say we're up (to avoid breaking scripts) */
 	return 1;
 	return 1;
 }
 }
 
 
-static u32 usbnet_get_msglevel (struct net_device *net)
+u32 usbnet_get_msglevel (struct net_device *net)
 {
 {
 	struct usbnet *dev = netdev_priv(net);
 	struct usbnet *dev = netdev_priv(net);
 
 
 	return dev->msg_enable;
 	return dev->msg_enable;
 }
 }
+EXPORT_SYMBOL_GPL(usbnet_get_msglevel);
 
 
-static void usbnet_set_msglevel (struct net_device *net, u32 level)
+void usbnet_set_msglevel (struct net_device *net, u32 level)
 {
 {
 	struct usbnet *dev = netdev_priv(net);
 	struct usbnet *dev = netdev_priv(net);
 
 
 	dev->msg_enable = level;
 	dev->msg_enable = level;
 }
 }
+EXPORT_SYMBOL_GPL(usbnet_set_msglevel);
 
 
-static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
-{
-#ifdef NEED_MII
-	{
-	struct usbnet *dev = netdev_priv(net);
-
-	if (dev->mii.mdio_read != NULL && dev->mii.mdio_write != NULL)
-		return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
-	}
-#endif
-	return -EOPNOTSUPP;
-}
+/* drivers may override default ethtool_ops in their bind() routine */
+static struct ethtool_ops usbnet_ethtool_ops = {
+	.get_drvinfo		= usbnet_get_drvinfo,
+	.get_link		= usbnet_get_link,
+	.get_msglevel		= usbnet_get_msglevel,
+	.set_msglevel		= usbnet_set_msglevel,
+};
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -3387,19 +715,24 @@ kevent (void *data)
 	if (test_bit (EVENT_TX_HALT, &dev->flags)) {
 	if (test_bit (EVENT_TX_HALT, &dev->flags)) {
 		unlink_urbs (dev, &dev->txq);
 		unlink_urbs (dev, &dev->txq);
 		status = usb_clear_halt (dev->udev, dev->out);
 		status = usb_clear_halt (dev->udev, dev->out);
-		if (status < 0 && status != -EPIPE) {
+		if (status < 0
+				&& status != -EPIPE
+				&& status != -ESHUTDOWN) {
 			if (netif_msg_tx_err (dev))
 			if (netif_msg_tx_err (dev))
 				deverr (dev, "can't clear tx halt, status %d",
 				deverr (dev, "can't clear tx halt, status %d",
 					status);
 					status);
 		} else {
 		} else {
 			clear_bit (EVENT_TX_HALT, &dev->flags);
 			clear_bit (EVENT_TX_HALT, &dev->flags);
-			netif_wake_queue (dev->net);
+			if (status != -ESHUTDOWN)
+				netif_wake_queue (dev->net);
 		}
 		}
 	}
 	}
 	if (test_bit (EVENT_RX_HALT, &dev->flags)) {
 	if (test_bit (EVENT_RX_HALT, &dev->flags)) {
 		unlink_urbs (dev, &dev->rxq);
 		unlink_urbs (dev, &dev->rxq);
 		status = usb_clear_halt (dev->udev, dev->in);
 		status = usb_clear_halt (dev->udev, dev->in);
-		if (status < 0 && status != -EPIPE) {
+		if (status < 0
+				&& status != -EPIPE
+				&& status != -ESHUTDOWN) {
 			if (netif_msg_rx_err (dev))
 			if (netif_msg_rx_err (dev))
 				deverr (dev, "can't clear rx halt, status %d",
 				deverr (dev, "can't clear rx halt, status %d",
 					status);
 					status);
@@ -3458,7 +791,7 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs)
 
 
 		switch (urb->status) {
 		switch (urb->status) {
 		case -EPIPE:
 		case -EPIPE:
-			defer_kevent (dev, EVENT_TX_HALT);
+			usbnet_defer_kevent (dev, EVENT_TX_HALT);
 			break;
 			break;
 
 
 		/* software-driven interface shutdown */
 		/* software-driven interface shutdown */
@@ -3515,10 +848,6 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
 	struct skb_data		*entry;
 	struct skb_data		*entry;
 	struct driver_info	*info = dev->driver_info;
 	struct driver_info	*info = dev->driver_info;
 	unsigned long		flags;
 	unsigned long		flags;
-#ifdef	CONFIG_USB_NET1080
-	struct nc_header	*header = NULL;
-	struct nc_trailer	*trailer = NULL;
-#endif	/* CONFIG_USB_NET1080 */
 
 
 	// some devices want funky USB-level framing, for
 	// some devices want funky USB-level framing, for
 	// win32 driver (usually) and/or hardware quirks
 	// win32 driver (usually) and/or hardware quirks
@@ -3544,24 +873,8 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
 	entry->state = tx_start;
 	entry->state = tx_start;
 	entry->length = length;
 	entry->length = length;
 
 
-	// FIXME: reorganize a bit, so that fixup() fills out NetChip
-	// framing too. (Packet ID update needs the spinlock...)
-	// [ BETTER:  we already own net->xmit_lock, that's enough ]
-
-#ifdef	CONFIG_USB_NET1080
-	if (info->flags & FLAG_FRAMING_NC) {
-		header = (struct nc_header *) skb_push (skb, sizeof *header);
-		header->hdr_len = cpu_to_le16 (sizeof (*header));
-		header->packet_len = cpu_to_le16 (length);
-		if (!((skb->len + sizeof *trailer) & 0x01))
-			*skb_put (skb, 1) = PAD_BYTE;
-		trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer);
-	}
-#endif	/* CONFIG_USB_NET1080 */
-
 	usb_fill_bulk_urb (urb, dev->udev, dev->out,
 	usb_fill_bulk_urb (urb, dev->udev, dev->out,
 			skb->data, skb->len, tx_complete, skb);
 			skb->data, skb->len, tx_complete, skb);
-	urb->transfer_flags |= URB_ASYNC_UNLINK;
 
 
 	/* don't assume the hardware handles USB_ZERO_PACKET
 	/* don't assume the hardware handles USB_ZERO_PACKET
 	 * NOTE:  strictly conforming cdc-ether devices should expect
 	 * NOTE:  strictly conforming cdc-ether devices should expect
@@ -3574,22 +887,10 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
 
 
 	spin_lock_irqsave (&dev->txq.lock, flags);
 	spin_lock_irqsave (&dev->txq.lock, flags);
 
 
-#ifdef	CONFIG_USB_NET1080
-	if (info->flags & FLAG_FRAMING_NC) {
-		header->packet_id = cpu_to_le16 ((u16)dev->dev_packet_id++);
-		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
-	}
-#endif	/* CONFIG_USB_NET1080 */
-
 	switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) {
 	switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) {
 	case -EPIPE:
 	case -EPIPE:
 		netif_stop_queue (net);
 		netif_stop_queue (net);
-		defer_kevent (dev, EVENT_TX_HALT);
+		usbnet_defer_kevent (dev, EVENT_TX_HALT);
 		break;
 		break;
 	default:
 	default:
 		if (netif_msg_tx_err (dev))
 		if (netif_msg_tx_err (dev))
@@ -3692,7 +993,7 @@ static void usbnet_bh (unsigned long param)
  
  
 // precondition: never called in_interrupt
 // precondition: never called in_interrupt
 
 
-static void usbnet_disconnect (struct usb_interface *intf)
+void usbnet_disconnect (struct usb_interface *intf)
 {
 {
 	struct usbnet		*dev;
 	struct usbnet		*dev;
 	struct usb_device	*xdev;
 	struct usb_device	*xdev;
@@ -3706,7 +1007,8 @@ static void usbnet_disconnect (struct usb_interface *intf)
 	xdev = interface_to_usbdev (intf);
 	xdev = interface_to_usbdev (intf);
 
 
 	if (netif_msg_probe (dev))
 	if (netif_msg_probe (dev))
-		devinfo (dev, "unregister usbnet usb-%s-%s, %s",
+		devinfo (dev, "unregister '%s' usb-%s-%s, %s",
+			intf->dev.driver->name,
 			xdev->bus->bus_name, xdev->devpath,
 			xdev->bus->bus_name, xdev->devpath,
 			dev->driver_info->description);
 			dev->driver_info->description);
 	
 	
@@ -3722,15 +1024,14 @@ static void usbnet_disconnect (struct usb_interface *intf)
 	free_netdev(net);
 	free_netdev(net);
 	usb_put_dev (xdev);
 	usb_put_dev (xdev);
 }
 }
+EXPORT_SYMBOL_GPL(usbnet_disconnect);
 
 
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static struct ethtool_ops usbnet_ethtool_ops;
-
 // precondition: never called in_interrupt
 // precondition: never called in_interrupt
 
 
-static int
+int
 usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 {
 {
 	struct usbnet			*dev;
 	struct usbnet			*dev;
@@ -3779,6 +1080,10 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 	strcpy (net->name, "usb%d");
 	strcpy (net->name, "usb%d");
 	memcpy (net->dev_addr, node_id, sizeof node_id);
 	memcpy (net->dev_addr, node_id, sizeof node_id);
 
 
+	/* rx and tx sides can use different message sizes;
+	 * bind() should set rx_urb_size in that case.
+	 */
+	dev->hard_mtu = net->mtu + net->hard_header_len;
 #if 0
 #if 0
 // dma_supported() is deeply broken on almost all architectures
 // dma_supported() is deeply broken on almost all architectures
 	// possible with some EHCI controllers
 	// possible with some EHCI controllers
@@ -3793,7 +1098,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 	net->stop = usbnet_stop;
 	net->stop = usbnet_stop;
 	net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
 	net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
 	net->tx_timeout = usbnet_tx_timeout;
 	net->tx_timeout = usbnet_tx_timeout;
-	net->do_ioctl = usbnet_ioctl;
 	net->ethtool_ops = &usbnet_ethtool_ops;
 	net->ethtool_ops = &usbnet_ethtool_ops;
 
 
 	// allow device-specific bind/init procedures
 	// allow device-specific bind/init procedures
@@ -3806,8 +1110,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 		if ((dev->driver_info->flags & FLAG_ETHER) != 0
 		if ((dev->driver_info->flags & FLAG_ETHER) != 0
 				&& (net->dev_addr [0] & 0x02) == 0)
 				&& (net->dev_addr [0] & 0x02) == 0)
 			strcpy (net->name, "eth%d");
 			strcpy (net->name, "eth%d");
-	} else if (!info->in || info->out)
-		status = get_endpoints (dev, udev);
+
+		/* maybe the remote can't receive an Ethernet MTU */
+		if (net->mtu > (dev->hard_mtu - net->hard_header_len))
+			net->mtu = dev->hard_mtu - net->hard_header_len;
+	} else if (!info->in || !info->out)
+		status = usbnet_get_endpoints (dev, udev);
 	else {
 	else {
 		dev->in = usb_rcvbulkpipe (xdev, info->in);
 		dev->in = usb_rcvbulkpipe (xdev, info->in);
 		dev->out = usb_sndbulkpipe (xdev, info->out);
 		dev->out = usb_sndbulkpipe (xdev, info->out);
@@ -3819,12 +1127,13 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 			status = 0;
 			status = 0;
 
 
 	}
 	}
-
 	if (status == 0 && dev->status)
 	if (status == 0 && dev->status)
 		status = init_status (dev, udev);
 		status = init_status (dev, udev);
 	if (status < 0)
 	if (status < 0)
 		goto out1;
 		goto out1;
 
 
+	if (!dev->rx_urb_size)
+		dev->rx_urb_size = dev->hard_mtu;
 	dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1);
 	dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1);
 	
 	
 	SET_NETDEV_DEV(net, &udev->dev);
 	SET_NETDEV_DEV(net, &udev->dev);
@@ -3832,8 +1141,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
 	if (status)
 	if (status)
 		goto out3;
 		goto out3;
 	if (netif_msg_probe (dev))
 	if (netif_msg_probe (dev))
-		devinfo (dev, "register usbnet at usb-%s-%s, %s, "
+		devinfo (dev, "register '%s' at usb-%s-%s, %s, "
 				"%02x:%02x:%02x:%02x:%02x:%02x",
 				"%02x:%02x:%02x:%02x:%02x:%02x",
+			udev->dev.driver->name,
 			xdev->bus->bus_name, xdev->devpath,
 			xdev->bus->bus_name, xdev->devpath,
 			dev->driver_info->description,
 			dev->driver_info->description,
 			net->dev_addr [0], net->dev_addr [1],
 			net->dev_addr [0], net->dev_addr [1],
@@ -3857,12 +1167,15 @@ out:
 	usb_put_dev(xdev);
 	usb_put_dev(xdev);
 	return status;
 	return status;
 }
 }
+EXPORT_SYMBOL_GPL(usbnet_probe);
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-#ifdef	CONFIG_PM
+/* FIXME these suspend/resume methods assume non-CDC style
+ * devices, with only one interface.
+ */
 
 
-static int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
+int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
 {
 {
 	struct usbnet		*dev = usb_get_intfdata(intf);
 	struct usbnet		*dev = usb_get_intfdata(intf);
 	
 	
@@ -3875,8 +1188,9 @@ static int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
 	intf->dev.power.power_state = PMSG_SUSPEND;
 	intf->dev.power.power_state = PMSG_SUSPEND;
 	return 0;
 	return 0;
 }
 }
+EXPORT_SYMBOL_GPL(usbnet_suspend);
 
 
-static int usbnet_resume (struct usb_interface *intf)
+int usbnet_resume (struct usb_interface *intf)
 {
 {
 	struct usbnet		*dev = usb_get_intfdata(intf);
 	struct usbnet		*dev = usb_get_intfdata(intf);
 
 
@@ -3885,357 +1199,27 @@ static int usbnet_resume (struct usb_interface *intf)
 	tasklet_schedule (&dev->bh);
 	tasklet_schedule (&dev->bh);
 	return 0;
 	return 0;
 }
 }
+EXPORT_SYMBOL_GPL(usbnet_resume);
 
 
-#else	/* !CONFIG_PM */
-
-#define	usbnet_suspend	NULL
-#define	usbnet_resume	NULL
-
-#endif	/* CONFIG_PM */
-
-/*-------------------------------------------------------------------------*/
-
-#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_AX8817X
-{
-	// 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,
-},
-#endif
-
-#ifdef	CONFIG_USB_EPSON2888
-{
-	USB_DEVICE (0x0525, 0x2888),	// EPSON USB client
-	.driver_info	= (unsigned long) &epson2888_info,
-},
-#endif
-
-#ifdef	CONFIG_USB_GENESYS
-{
-	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
-	 */
-#endif
-
-#ifdef	CONFIG_USB_NET1080
-{
-	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,
-},
-#endif
-
-#ifdef CONFIG_USB_PL2301
-{
-	USB_DEVICE (0x067b, 0x0000),	// PL-2301
-	.driver_info =	(unsigned long) &prolific_info,
-}, {
-	USB_DEVICE (0x067b, 0x0001),	// PL-2302
-	.driver_info =	(unsigned long) &prolific_info,
-},
-#endif
-
-#ifdef CONFIG_USB_KC2190
-{
-	USB_DEVICE (0x050f, 0x0190),	// KC-190
-	.driver_info =	(unsigned long) &kc2190_info,
-},
-#endif
-
-#ifdef	CONFIG_USB_RNDIS
-{
-	/* 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,
-},
-#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
-	// e.g. Gumstix, current OpenZaurus, ...
-	USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203),
-	.driver_info =	(unsigned long) &linuxdev_info,
-}, 
-#endif
-
-#if	defined(CONFIG_USB_ZAURUS) || defined(CONFIG_USB_CDCETHER)
-/*
- * SA-1100 based Sharp Zaurus ("collie"), or compatible.
- * Same idea as above, but different framing.
- *
- * PXA-2xx based models are also lying-about-cdc.
- * Some models don't even tell the same lies ...
- *
- * NOTE:  OpenZaurus versions with 2.6 kernels won't use these entries,
- * unlike the older ones with 2.4 "embedix" kernels.
- *
- * NOTE:  These entries do double-duty, serving as blacklist entries
- * whenever Zaurus support isn't enabled, but CDC Ethernet is.
- */
-#define	ZAURUS_MASTER_INTERFACE \
-	.bInterfaceClass	= USB_CLASS_COMM, \
-	.bInterfaceSubClass	= USB_CDC_SUBCLASS_ETHERNET, \
-	.bInterfaceProtocol	= USB_CDC_PROTO_NONE
-{
-	.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,
-}, {
-	.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,
-},
-
-#ifdef	CONFIG_USB_ZAURUS
-	/* At least some (reports vary) PXA units have very different lies
-	 * about their standards support:  they claim to be cell phones with
-	 * direct access to their radios.  (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,
-},
-#endif
-
-/* 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,
-},
-#endif
-
-#ifdef	CONFIG_USB_CDCETHER
-{
-	/* 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 working around
-	 * 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,
-},
-#endif
-
-	{ },		// END
-};
-MODULE_DEVICE_TABLE (usb, products);
-
-static struct usb_driver usbnet_driver = {
-	.owner =	THIS_MODULE,
-	.name =		driver_name,
-	.id_table =	products,
-	.probe =	usbnet_probe,
-	.disconnect =	usbnet_disconnect,
-	.suspend =	usbnet_suspend,
-	.resume =	usbnet_resume,
-};
-
-/* Default ethtool_ops assigned.  Devices can override in their bind() routine */
-static struct ethtool_ops usbnet_ethtool_ops = {
-	.get_drvinfo		= usbnet_get_drvinfo,
-	.get_link		= usbnet_get_link,
-	.get_msglevel		= usbnet_get_msglevel,
-	.set_msglevel		= usbnet_set_msglevel,
-};
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static int __init usbnet_init (void)
+static int __init usbnet_init(void)
 {
 {
-	// compiler should optimize these out
+	/* compiler should optimize this out */
 	BUG_ON (sizeof (((struct sk_buff *)0)->cb)
 	BUG_ON (sizeof (((struct sk_buff *)0)->cb)
 			< sizeof (struct skb_data));
 			< sizeof (struct skb_data));
-#ifdef	CONFIG_USB_CDCETHER
-	BUG_ON ((sizeof (((struct usbnet *)0)->data)
-			< sizeof (struct cdc_state)));
-#endif
 
 
 	random_ether_addr(node_id);
 	random_ether_addr(node_id);
-
- 	return usb_register(&usbnet_driver);
+ 	return 0;
 }
 }
-module_init (usbnet_init);
+module_init(usbnet_init);
 
 
-static void __exit usbnet_exit (void)
+static void __exit usbnet_exit(void)
 {
 {
- 	usb_deregister (&usbnet_driver);
 }
 }
-module_exit (usbnet_exit);
+module_exit(usbnet_exit);
 
 
-MODULE_AUTHOR ("David Brownell <dbrownell@users.sourceforge.net>");
-MODULE_DESCRIPTION ("USB Host-to-Host Link Drivers (numerous vendors)");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("David Brownell");
+MODULE_DESCRIPTION("USB network driver framework");
+MODULE_LICENSE("GPL");

+ 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;
 		return;
 	dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n",
 	dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n",
 	    dev->name);
 	    dev->name);
-	zd->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 	usb_unlink_urb(zd->tx_urb);
 	usb_unlink_urb(zd->tx_urb);
 	zd->stats.tx_errors++;
 	zd->stats.tx_errors++;
 	/* Restart the timeout to quiet the watchdog: */
 	/* 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;
 	priv->cbr_mask = B300;
 	usb_set_serial_port_data(serial->port[0], priv);
 	usb_set_serial_port_data(serial->port[0], priv);
 	
 	
-	return (0);	
-}	
+	return 0;
+}
 
 
 
 
 static int cypress_earthmate_startup (struct usb_serial *serial)
 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__);
 	dbg("%s", __FUNCTION__);
 
 
 	if (generic_startup(serial)) {
 	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;
 		return 1;
 	}
 	}
 
 
 	priv = usb_get_serial_port_data(serial->port[0]);
 	priv = usb_get_serial_port_data(serial->port[0]);
 	priv->chiptype = CT_EARTHMATE;
 	priv->chiptype = CT_EARTHMATE;
-	
-	return (0);	
+
+	return 0;
 } /* cypress_earthmate_startup */
 } /* cypress_earthmate_startup */
 
 
 
 
@@ -482,14 +483,15 @@ static int cypress_hidcom_startup (struct usb_serial *serial)
 	dbg("%s", __FUNCTION__);
 	dbg("%s", __FUNCTION__);
 
 
 	if (generic_startup(serial)) {
 	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;
 		return 1;
 	}
 	}
 
 
 	priv = usb_get_serial_port_data(serial->port[0]);
 	priv = usb_get_serial_port_data(serial->port[0]);
 	priv->chiptype = CT_CYPHIDCOM;
 	priv->chiptype = CT_CYPHIDCOM;
 	
 	
-	return (0);	
+	return 0;
 } /* cypress_hidcom_startup */
 } /* cypress_hidcom_startup */
 
 
 
 
@@ -909,7 +911,8 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi
 } /* cypress_ioctl */
 } /* 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 cypress_private *priv = usb_get_serial_port_data(port);
 	struct tty_struct *tty;
 	struct tty_struct *tty;
@@ -918,7 +921,7 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
 	unsigned long flags;
 	unsigned long flags;
 	__u8 oldlines;
 	__u8 oldlines;
 	int linechange = 0;
 	int linechange = 0;
-	
+
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
 	tty = port->tty;
 	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->termios_initialized) {
 		if (priv->chiptype == CT_EARTHMATE) {
 		if (priv->chiptype == CT_EARTHMATE) {
 			*(tty->termios) = tty_std_termios;
 			*(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) {
 		} else if (priv->chiptype == CT_CYPHIDCOM) {
 			*(tty->termios) = tty_std_termios;
 			*(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;
 		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 */
 	/* check if there are new settings */
 	if (old_termios) {
 	if (old_termios) {
 		if ((cflag != old_termios->c_cflag) ||
 		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);
 			spin_lock_irqsave(&priv->lock, flags);
 			priv->tmp_termios = *(tty->termios);
 			priv->tmp_termios = *(tty->termios);
-			spin_unlock_irqrestore(&priv->lock, flags); 
+			spin_unlock_irqrestore(&priv->lock, flags);
 		} else {
 		} else {
 			dbg("%s - nothing to do, exiting", __FUNCTION__);
 			dbg("%s - nothing to do, exiting", __FUNCTION__);
 			return;
 			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 */
 	/* set number of data bits, parity, stop bits */
 	/* when parity is disabled the parity type bit is ignored */
 	/* 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) {
 	if (cflag & PARENB) {
 		parity_enable = 1;
 		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
 	} else
 		parity_enable = parity_type = 0;
 		parity_enable = parity_type = 0;
 
 
 	if (cflag & CSIZE) {
 	if (cflag & CSIZE) {
 		switch (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
 	} else
 		data_bits = 3;
 		data_bits = 3;
@@ -991,63 +1012,85 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
 	} else {
 	} else {
 		baud_mask = (cflag & CBAUD);
 		baud_mask = (cflag & CBAUD);
 		switch(baud_mask) {
 		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);
 		priv->line_control = (CONTROL_DTR | CONTROL_RTS);
 	}
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 	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);
 	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) ) {
 	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 */
 		/* define custom termios settings for NMEA protocol */
 
 
 		tty->termios->c_iflag /* input modes - */
 		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 */
 		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 */
 	} /* CT_CYPHIDCOM: Application should handle this for device */
 
 
 	linechange = (priv->line_control != oldlines);
 	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 */
 } /* cypress_set_termios */
 
 
- 
+
 /* returns amount of data still left in soft buffer */
 /* returns amount of data still left in soft buffer */
 static int cypress_chars_in_buffer(struct usb_serial_port *port)
 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);
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->rx_flags = THROTTLED;
 	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);
 		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 		if (result)
 		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;
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	unsigned char *data = urb->transfer_buffer;
 	unsigned long flags;
 	unsigned long flags;
-	char tty_flag = TTY_NORMAL;	
+	char tty_flag = TTY_NORMAL;
 	int havedata = 0;
 	int havedata = 0;
 	int bytes = 0;
 	int bytes = 0;
 	int result;
 	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);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
 	if (urb->status) {
 	if (urb->status) {
-		dbg("%s - nonzero read status received: %d", __FUNCTION__, urb->status);
+		dbg("%s - nonzero read status received: %d", __FUNCTION__,
+				urb->status);
 		return;
 		return;
 	}
 	}
 
 
@@ -1155,51 +1200,55 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
 		case 32:
 		case 32:
 			/* This is for the CY7C64013... */
 			/* This is for the CY7C64013... */
 			priv->current_status = data[0] & 0xF8;
 			priv->current_status = data[0] & 0xF8;
-			bytes = data[1]+2;
-			i=2;
+			bytes = data[1] + 2;
+			i = 2;
 			if (bytes > 2)
 			if (bytes > 2)
 				havedata = 1;
 				havedata = 1;
 			break;
 			break;
 		case 8:
 		case 8:
 			/* This is for the CY7C63743... */
 			/* This is for the CY7C63743... */
 			priv->current_status = data[0] & 0xF8;
 			priv->current_status = data[0] & 0xF8;
-			bytes = (data[0] & 0x07)+1;
-			i=1;
+			bytes = (data[0] & 0x07) + 1;
+			i = 1;
 			if (bytes > 1)
 			if (bytes > 1)
 				havedata = 1;
 				havedata = 1;
 			break;
 			break;
 		default:
 		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);
 			spin_unlock_irqrestore(&priv->lock, flags);
 			goto continue_read;
 			goto continue_read;
 	}
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 	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);
 	spin_lock_irqsave(&priv->lock, flags);
 	/* check to see if status has changed */
 	/* check to see if status has changed */
 	if (priv != NULL) {
 	if (priv != NULL) {
 		if (priv->current_status != priv->prev_status) {
 		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);
 			wake_up_interruptible(&priv->delta_msr_wait);
 			priv->prev_status = priv->current_status;
 			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__);
 		dbg("%s - calling hangup", __FUNCTION__);
 		tty_hangup(tty);
 		tty_hangup(tty);
 		goto continue_read;
 		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);
 	spin_lock_irqsave(&priv->lock, flags);
 	if (priv->current_status & CYP_ERROR) {
 	if (priv->current_status & CYP_ERROR) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		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 */
 	/* process read if there is data other than line status */
 	if (tty && (bytes > i)) {
 	if (tty && (bytes > i)) {
 		for (; i < 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) {
 			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
 				tty_flip_buffer_push(tty);
 				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);
 	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);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 
 continue_read:
 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) {
 	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;
 	return;
 } /* cypress_read_int_callback */
 } /* cypress_read_int_callback */
 
 

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

@@ -269,6 +269,8 @@
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
 
 static int debug;
 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 is used by devices requiring special attention. */
 struct ftdi_sio_quirk {
 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_GUDEADS_E88F_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_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_SDMUSBQSS_PID) },
  	{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
  	{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
  	{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_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_VALUECAN_PID) },
 	{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
 	{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
 	{ USB_DEVICE(FALCOM_VID, FALCOM_TWIST_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_SUUNTO_SPORTS_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
 	{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_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_0_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_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, 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(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
 	{ USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
 	{ USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
-	{ }						/* Terminating entry */
+	{ },					/* Optional parameter entry */
+	{ }					/* Terminating entry */
 };
 };
 
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 MODULE_DEVICE_TABLE (usb, id_table_combined);
@@ -2030,6 +2070,15 @@ static int __init ftdi_init (void)
 	int retval;
 	int retval;
 
 
 	dbg("%s", __FUNCTION__);
 	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);
 	retval = usb_serial_register(&ftdi_sio_device);
 	if (retval)
 	if (retval)
 		goto failed_sio_register;
 		goto failed_sio_register;
@@ -2066,4 +2115,9 @@ MODULE_LICENSE("GPL");
 
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 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 */
 /* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
 #define FTDI_USB_UIRT_PID	0xF850	/* Product Id */
 #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
  * Definitions for ID TECH (www.idt-net.com) devices
@@ -222,6 +255,7 @@
  */
  */
 #define FALCOM_VID		0x0F94	/* Vendor Id */
 #define FALCOM_VID		0x0F94	/* Vendor Id */
 #define FALCOM_TWIST_PID	0x0001	/* Falcom Twist USB GPRS modem */
 #define FALCOM_TWIST_PID	0x0001	/* Falcom Twist USB GPRS modem */
+#define FALCOM_SAMBA_PID	0x0005	/* Falcom Samba USB GPRS modem */
 
 
 /*
 /*
  * SUUNTO product ids
  * SUUNTO product ids
@@ -276,6 +310,18 @@
  */
  */
 #define FTDI_ACTIVE_ROBOTS_PID	0xE548	/* USB comms board */
 #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/).
  * Evolution Robotics products (http://www.evolution.com/).
  * Submitted by Shawn M. Lavelle.
  * 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);
 		dbg("%s - endpoint %d flip %d", __FUNCTION__, usb_pipeendpoint(this_urb->pipe), flip);
 
 
 		if (this_urb->status == -EINPROGRESS) {
 		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))
 			if (time_before(jiffies, p_priv->tx_start_time[flip] + 10 * HZ))
 				break;
 				break;
-			this_urb->transfer_flags |= URB_ASYNC_UNLINK;
 			usb_unlink_urb(this_urb);
 			usb_unlink_urb(this_urb);
 			break;
 			break;
 		}
 		}
@@ -402,7 +399,6 @@ static int keyspan_write(struct usb_serial_port *port,
 		/* send the data out the bulk port */
 		/* send the data out the bulk port */
 		this_urb->transfer_buffer_length = todo + dataOffset;
 		this_urb->transfer_buffer_length = todo + dataOffset;
 
 
-		this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 		this_urb->dev = port->serial->dev;
 		this_urb->dev = port->serial->dev;
 		if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
 		if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) {
 			dbg("usb_submit_urb(write bulk) failed (%d)", err);
 			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)
 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);
 		usb_kill_urb(urb);
-	}
 }
 }
 
 
 static void keyspan_close(struct usb_serial_port *port, struct file *filp)
 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"
 #include "usb-serial.h"
 
 
 /* Function prototypes */
 /* 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 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 */
 /* Vendor and product IDs */
 #define OPTION_VENDOR_ID			0x0AF0
 #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_FUSION	0x6000
 #define OPTION_PRODUCT_FUSION2	0x6300
 #define OPTION_PRODUCT_FUSION2	0x6300
 
 
-
 static struct usb_device_id option_ids[] = {
 static struct usb_device_id option_ids[] = {
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
@@ -129,7 +128,6 @@ static int debug;
 #define debug 0
 #define debug 0
 #endif
 #endif
 
 
-
 /* per port private data */
 /* per port private data */
 
 
 #define N_IN_URB 4
 #define N_IN_URB 4
@@ -156,10 +154,8 @@ struct option_port_private {
 	unsigned long tx_start_time[N_OUT_URB];
 	unsigned long tx_start_time[N_OUT_URB];
 };
 };
 
 
-
 /* Functions used by new usb-serial code. */
 /* Functions used by new usb-serial code. */
-static int __init
-option_init (void)
+static int __init option_init(void)
 {
 {
 	int retval;
 	int retval;
 	retval = usb_serial_register(&option_3port_device);
 	retval = usb_serial_register(&option_3port_device);
@@ -179,8 +175,7 @@ failed_3port_device_register:
 	return retval;
 	return retval;
 }
 }
 
 
-static void __exit
-option_exit (void)
+static void __exit option_exit(void)
 {
 {
 	usb_deregister (&option_driver);
 	usb_deregister (&option_driver);
 	usb_serial_deregister (&option_3port_device);
 	usb_serial_deregister (&option_3port_device);
@@ -189,39 +184,31 @@ option_exit (void)
 module_init(option_init);
 module_init(option_init);
 module_exit(option_exit);
 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__);
 	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__);
 	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 */
 	/* Unfortunately, I don't know how to send a break */
 	dbg("%s", __FUNCTION__);
 	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__);
 	dbg("%s", __FUNCTION__);
 
 
 	option_send_setup(port);
 	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;
 	unsigned int value;
 	struct option_port_private *portdata;
 	struct option_port_private *portdata;
@@ -238,9 +225,8 @@ option_tiocmget (struct usb_serial_port *port, struct file *file)
 	return value;
 	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;
 	struct option_port_private *portdata;
 
 
@@ -258,17 +244,15 @@ option_tiocmset (struct usb_serial_port *port, struct file *file,
 	return option_send_setup(port);
 	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;
 	return -ENOIOCTLCMD;
 }
 }
 
 
 /* Write */
 /* 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;
 	struct option_port_private *portdata;
 	int i;
 	int i;
@@ -289,28 +273,29 @@ option_write (struct usb_serial_port *port,
 
 
 		this_urb = portdata->out_urbs[i];
 		this_urb = portdata->out_urbs[i];
 		if (this_urb->status == -EINPROGRESS) {
 		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;
 				continue;
-			this_urb->transfer_flags |= URB_ASYNC_UNLINK;
 			usb_unlink_urb(this_urb);
 			usb_unlink_urb(this_urb);
 			continue;
 			continue;
 		}
 		}
 		if (this_urb->status != 0)
 		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 */
 		/* send the data */
 		memcpy (this_urb->transfer_buffer, buf, todo);
 		memcpy (this_urb->transfer_buffer, buf, todo);
 		this_urb->transfer_buffer_length = todo;
 		this_urb->transfer_buffer_length = todo;
 
 
-		this_urb->transfer_flags &= ~URB_ASYNC_UNLINK;
 		this_urb->dev = port->serial->dev;
 		this_urb->dev = port->serial->dev;
 		err = usb_submit_urb(this_urb, GFP_ATOMIC);
 		err = usb_submit_urb(this_urb, GFP_ATOMIC);
 		if (err) {
 		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;
 			continue;
 		}
 		}
 		portdata->tx_start_time[i] = jiffies;
 		portdata->tx_start_time[i] = jiffies;
@@ -323,8 +308,7 @@ option_write (struct usb_serial_port *port,
 	return count;
 	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 i, err;
 	int endpoint;
 	int endpoint;
@@ -357,14 +341,14 @@ option_indat_callback (struct urb *urb, struct pt_regs *regs)
 		if (port->open_count && urb->status != -ESHUTDOWN) {
 		if (port->open_count && urb->status != -ESHUTDOWN) {
 			err = usb_submit_urb(urb, GFP_ATOMIC);
 			err = usb_submit_urb(urb, GFP_ATOMIC);
 			if (err)
 			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;
 	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;
 	struct usb_serial_port *port;
 
 
@@ -376,8 +360,7 @@ option_outdat_callback (struct urb *urb, struct pt_regs *regs)
 		schedule_work(&port->work);
 		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;
 	int err;
 	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
 	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__);
 			dbg("%s: NULL req_pkt\n", __FUNCTION__);
 			return;
 			return;
 		}
 		}
-		if ((req_pkt->bRequestType == 0xA1) && (req_pkt->bRequest == 0x20)) {
+		if ((req_pkt->bRequestType == 0xA1) &&
+				(req_pkt->bRequest == 0x20)) {
 			int old_dcd_state;
 			int old_dcd_state;
 			unsigned char signals = *((unsigned char *)
 			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);
 			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->dsr_state = ((signals & 0x02) ? 1 : 0);
 			portdata->ri_state = ((signals & 0x08) ? 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);
 				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
 	} else
 		dbg("%s: error %d", __FUNCTION__, urb->status);
 		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;
 		urb->dev = serial->dev;
 		err = usb_submit_urb(urb, GFP_ATOMIC);
 		err = usb_submit_urb(urb, GFP_ATOMIC);
 		if (err)
 		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;
 	struct option_port_private *portdata;
 	int i;
 	int i;
@@ -447,9 +432,7 @@ option_write_room (struct usb_serial_port *port)
 	return data_len;
 	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;
 	struct option_port_private *portdata;
 	int i;
 	int i;
@@ -467,9 +450,7 @@ option_chars_in_buffer (struct usb_serial_port *port)
 	return data_len;
 	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 option_port_private *portdata;
 	struct usb_serial *serial = port->serial;
 	struct usb_serial *serial = port->serial;
@@ -490,17 +471,21 @@ option_open (struct usb_serial_port *port, struct file *filp)
 		if (! urb)
 		if (! urb)
 			continue;
 			continue;
 		if (urb->dev != serial->dev) {
 		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;
 			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);
 		usb_clear_halt(urb->dev, urb->pipe);
 
 
 		err = usb_submit_urb(urb, GFP_KERNEL);
 		err = usb_submit_urb(urb, GFP_KERNEL);
 		if (err) {
 		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);
 				urb->transfer_buffer_length);
 		}
 		}
 	}
 	}
@@ -511,7 +496,8 @@ option_open (struct usb_serial_port *port, struct file *filp)
 		if (! urb)
 		if (! urb)
 			continue;
 			continue;
 		urb->dev = serial->dev;
 		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;
 	port->tty->low_latency = 1;
@@ -521,17 +507,13 @@ option_open (struct usb_serial_port *port, struct file *filp)
 	return (0);
 	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);
 		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;
 	int i;
 	struct usb_serial *serial = port->serial;
 	struct usb_serial *serial = port->serial;
@@ -555,12 +537,10 @@ option_close (struct usb_serial_port *port, struct file *filp)
 	port->tty = NULL;
 	port->tty = NULL;
 }
 }
 
 
-
 /* Helper functions used by option_setup_urbs */
 /* 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;
 	struct urb *urb;
 
 
@@ -582,8 +562,7 @@ option_setup_urb (struct usb_serial *serial, int endpoint,
 }
 }
 
 
 /* Setup urbs */
 /* Setup urbs */
-static void
-option_setup_urbs (struct usb_serial *serial)
+static void option_setup_urbs(struct usb_serial *serial)
 {
 {
 	int j;
 	int j;
 	struct usb_serial_port *port;
 	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 usb_serial *serial = port->serial;
 	struct option_port_private *portdata;
 	struct option_port_private *portdata;
@@ -627,16 +604,15 @@ option_send_setup (struct usb_serial_port *port)
 		if (portdata->rts_state)
 		if (portdata->rts_state)
 			val |= 0x02;
 			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;
 	return 0;
 }
 }
 
 
-
-static int
-option_startup (struct usb_serial *serial)
+static int option_startup(struct usb_serial *serial)
 {
 {
 	int i, err;
 	int i, err;
 	struct usb_serial_port *port;
 	struct usb_serial_port *port;
@@ -647,9 +623,10 @@ option_startup (struct usb_serial *serial)
 	/* Now setup per port private data */
 	/* Now setup per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
 		port = serial->port[i];
-		portdata = kmalloc(sizeof(struct option_port_private), GFP_KERNEL);
+		portdata = kmalloc(sizeof(*portdata), GFP_KERNEL);
 		if (!portdata) {
 		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);
 			return (1);
 		}
 		}
 		memset(portdata, 0, sizeof(struct option_port_private));
 		memset(portdata, 0, sizeof(struct option_port_private));
@@ -660,7 +637,8 @@ option_startup (struct usb_serial *serial)
 			continue;
 			continue;
 		err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (err)
 		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);
 	option_setup_urbs(serial);
@@ -668,8 +646,7 @@ option_startup (struct usb_serial *serial)
 	return (0);
 	return (0);
 }
 }
 
 
-static void
-option_shutdown (struct usb_serial *serial)
+static void option_shutdown(struct usb_serial *serial)
 {
 {
 	int i, j;
 	int i, j;
 	struct usb_serial_port *port;
 	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);
 	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);
 	buf = kmalloc(10, GFP_KERNEL);
 	if (buf==NULL)
 	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)
 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)
 	if (!port)
 		return;
 		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)
 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;
 	int retval = -EINVAL;
 
 
 	dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
 	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) 
 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;
 	int retval = -EINVAL;
 
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - port %d", __FUNCTION__, port->number);
@@ -599,7 +599,7 @@ exit:
 
 
 static int serial_chars_in_buffer (struct tty_struct *tty) 
 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;
 	int retval = -EINVAL;
 
 
 	dbg("%s = port %d", __FUNCTION__, port->number);
 	dbg("%s = port %d", __FUNCTION__, port->number);
@@ -618,7 +618,7 @@ exit:
 
 
 static void serial_throttle (struct tty_struct * tty)
 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);
 	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)
 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);
 	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)
 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;
 	int retval = -ENODEV;
 
 
 	dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
 	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)
 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);
 	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)
 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);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
@@ -749,7 +749,7 @@ done:
 
 
 static int serial_tiocmget (struct tty_struct *tty, struct file *file)
 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);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
@@ -768,7 +768,7 @@ exit:
 static int serial_tiocmset (struct tty_struct *tty, struct file *file,
 static int serial_tiocmset (struct tty_struct *tty, struct file *file,
 			    unsigned int set, unsigned int clear)
 			    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);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
@@ -786,7 +786,7 @@ exit:
 
 
 void usb_serial_port_softint(void *private)
 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;
 	struct tty_struct *tty;
 
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	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
 	  Say Y here to include additional code to support the Lexar Jumpshot
 	  USB CompactFlash reader.
 	  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_ISD200)	+= isd200.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB)	+= datafab.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_JUMPSHOT)	+= jumpshot.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH)	+= onetouch.o
 
 
 usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
 usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
 			initializers.o $(usb-storage-obj-y)
 			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)
 		if (us->flags & US_FL_FIX_CAPACITY)
 			sdev->fix_capacity = 1;
 			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
 		/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
 		 * Hardware Error) when any low-level error occurs,
 		 * Hardware Error) when any low-level error occurs,
 		 * recoverable or not.  Setting this flag tells the SCSI
 		 * 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);
 	rc = usbat_device_reset(us);
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 		return rc;
 		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
 		// Device is HP 8200
 		US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n");
 		US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n");
 		info->devicetype = USBAT_DEV_HP8200;
 		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;
 	return USB_STOR_TRANSPORT_GOOD;
@@ -1239,16 +1236,10 @@ static int usbat_select_and_test_registers(struct us_data *us)
 {
 {
 	int selector;
 	int selector;
 	unsigned char *status = us->iobuf;
 	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.
 	// 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)
 				USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
 			return USB_STOR_TRANSPORT_ERROR;
 
 
@@ -1334,60 +1325,30 @@ int init_usbat(struct us_data *us)
 
 
 	US_DEBUGP("INIT 3\n");
 	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);
 	rc = usbat_select_and_test_registers(us);
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 		return rc;
 		return rc;
 
 
-	US_DEBUGP("INIT 8\n");
+	US_DEBUGP("INIT 4\n");
 
 
 	rc = usbat_read_user_io(us, status);
 	rc = usbat_read_user_io(us, status);
 	if (rc != USB_STOR_XFER_GOOD)
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 		return USB_STOR_TRANSPORT_ERROR;
 
 
-	US_DEBUGP("INIT 9\n");
+	US_DEBUGP("INIT 5\n");
 
 
 	// Enable peripheral control signals and card detect
 	// Enable peripheral control signals and card detect
 	rc = usbat_device_enable_cdt(us);
 	rc = usbat_device_enable_cdt(us);
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 		return rc;
 		return rc;
 
 
-	US_DEBUGP("INIT 10\n");
+	US_DEBUGP("INIT 6\n");
 
 
 	rc = usbat_read_user_io(us, status);
 	rc = usbat_read_user_io(us, status);
 	if (rc != USB_STOR_XFER_GOOD)
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 		return USB_STOR_TRANSPORT_ERROR;
 
 
-	US_DEBUGP("INIT 11\n");
+	US_DEBUGP("INIT 7\n");
 
 
 	msleep(1400);
 	msleep(1400);
 
 
@@ -1395,13 +1356,19 @@ int init_usbat(struct us_data *us)
 	if (rc != USB_STOR_XFER_GOOD)
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 		return USB_STOR_TRANSPORT_ERROR;
 
 
-	US_DEBUGP("INIT 12\n");
+	US_DEBUGP("INIT 8\n");
 
 
 	rc = usbat_select_and_test_registers(us);
 	rc = usbat_select_and_test_registers(us);
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 		return rc;
 		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) { 
 	if (usbat_get_device_type(us) == USBAT_DEV_FLASH) { 
 		subcountH = 0x02;
 		subcountH = 0x02;
@@ -1412,7 +1379,7 @@ int init_usbat(struct us_data *us)
 	if (rc != USB_STOR_XFER_GOOD)
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 		return USB_STOR_TRANSPORT_ERROR;
 
 
-	US_DEBUGP("INIT 14\n");
+	US_DEBUGP("INIT 11\n");
 
 
 	return USB_STOR_TRANSPORT_GOOD;
 	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
  * 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
  * 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
  * 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,
  * The idea is that (1) once the ABORTING or DISCONNECTING bit is set,
  * either the stop_transport() function or the submitting function
  * 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
 	 * hasn't been mapped for DMA.  Yes, this is clunky, but it's
 	 * easier than always having the caller tell us whether the
 	 * easier than always having the caller tell us whether the
 	 * transfer buffer has already been mapped. */
 	 * 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)
 	if (us->current_urb->transfer_buffer == us->iobuf)
 		us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 		us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	us->current_urb->transfer_dma = us->iobuf_dma;
 	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_sc_data_direction;
 		unsigned char old_cmd_len;
 		unsigned char old_cmd_len;
 		unsigned char old_cmnd[MAX_COMMAND_SIZE];
 		unsigned char old_cmnd[MAX_COMMAND_SIZE];
-		unsigned long old_serial_number;
 		int old_resid;
 		int old_resid;
 
 
 		US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
 		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;
 		old_sg = srb->use_sg;
 		srb->use_sg = 0;
 		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 */
 		/* issue the auto-sense command */
 		old_resid = srb->resid;
 		old_resid = srb->resid;
 		srb->resid = 0;
 		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_buffer = old_request_buffer;
 		srb->request_bufflen = old_request_bufflen;
 		srb->request_bufflen = old_request_bufflen;
 		srb->use_sg = old_sg;
 		srb->use_sg = old_sg;
-		srb->serial_number = old_serial_number;
 		srb->sc_data_direction = old_sc_data_direction;
 		srb->sc_data_direction = old_sc_data_direction;
 		srb->cmd_len = old_cmd_len;
 		srb->cmd_len = old_cmd_len;
 		memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
 		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->Signature = cpu_to_le32(US_BULK_CB_SIGN);
 	bcb->DataTransferLength = cpu_to_le32(transfer_length);
 	bcb->DataTransferLength = cpu_to_le32(transfer_length);
 	bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
 	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;
 	bcb->Lun = srb->device->lun;
 	if (us->flags & US_FL_SCM_MULT_TARG)
 	if (us->flags & US_FL_SCM_MULT_TARG)
 		bcb->Lun |= srb->device->id << 4;
 		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",
 	US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
 			le32_to_cpu(bcs->Signature), bcs->Tag, 
 			le32_to_cpu(bcs->Signature), bcs->Tag, 
 			residue, bcs->Status);
 			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");
 		US_DEBUGP("Bulk logical error\n");
 		return USB_STOR_TRANSPORT_ERROR;
 		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), 
 		US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), 
 #endif
 #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>
 /* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
  * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
  * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
  * always fails and confuses drive.
  * always fails and confuses drive.
@@ -929,6 +936,18 @@ UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
 	       US_FL_SINGLE_LUN ),
 	       US_FL_SINGLE_LUN ),
 #endif
 #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> */
 /* Submitted by Joris Struyve <joris@struyve.be> */
 UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
 UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
 		"Medion",
 		"Medion",

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

@@ -90,7 +90,9 @@
 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
 #include "jumpshot.h"
 #include "jumpshot.h"
 #endif
 #endif
-
+#ifdef CONFIG_USB_STORAGE_ONETOUCH
+#include "onetouch.h"
+#endif
 
 
 /* Some informational data */
 /* Some informational data */
 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
 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.
 	 * any more commands.
 	 */
 	 */
 	US_DEBUGP("-- sending exit command to thread\n");
 	US_DEBUGP("-- sending exit command to thread\n");
+	set_bit(US_FLIDX_DISCONNECTING, &us->flags);
 	up(&us->sema);
 	up(&us->sema);
 
 
 	/* Call the destructor routine, if it exists */
 	/* 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);
 	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 */
 /* Thread to carry out delayed SCSI-device scanning */
 static int usb_stor_scan_thread(void * __us)
 static int usb_stor_scan_thread(void * __us)
 {
 {
@@ -956,7 +1002,7 @@ static int storage_probe(struct usb_interface *intf,
 	if (result < 0) {
 	if (result < 0) {
 		printk(KERN_WARNING USB_STORAGE 
 		printk(KERN_WARNING USB_STORAGE 
 		       "Unable to start the device-scanning thread\n");
 		       "Unable to start the device-scanning thread\n");
-		scsi_remove_host(host);
+		quiesce_and_remove_host(us);
 		goto BadDevice;
 		goto BadDevice;
 	}
 	}
 	atomic_inc(&total_threads);
 	atomic_inc(&total_threads);
@@ -969,10 +1015,7 @@ static int storage_probe(struct usb_interface *intf,
 	/* We come here if there are any problems */
 	/* We come here if there are any problems */
 BadDevice:
 BadDevice:
 	US_DEBUGP("storage_probe() failed\n");
 	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;
 	return result;
 }
 }
 
 
@@ -982,28 +1025,8 @@ static void storage_disconnect(struct usb_interface *intf)
 	struct us_data *us = usb_get_intfdata(intf);
 	struct us_data *us = usb_get_intfdata(intf);
 
 
 	US_DEBUGP("storage_disconnect() called\n");
 	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 */
 	/* SCSI interfaces */
 	struct scsi_cmnd	*srb;		 /* current srb		*/
 	struct scsi_cmnd	*srb;		 /* current srb		*/
+	unsigned int		tag;		 /* current dCBWTag	*/
 
 
 	/* thread information */
 	/* thread information */
 	int			pid;		 /* control thread	 */
 	int			pid;		 /* control thread	 */

+ 3 - 8
include/linux/usb.h

@@ -5,6 +5,7 @@
 #include <linux/usb_ch9.h>
 #include <linux/usb_ch9.h>
 
 
 #define USB_MAJOR			180
 #define USB_MAJOR			180
+#define USB_DEVICE_MAJOR		189
 
 
 
 
 #ifdef __KERNEL__
 #ifdef __KERNEL__
@@ -349,6 +350,7 @@ struct usb_device {
 	char *manufacturer;
 	char *manufacturer;
 	char *serial;			/* static strings from the device */
 	char *serial;			/* static strings from the device */
 	struct list_head filelist;
 	struct list_head filelist;
+	struct class_device *class_dev;
 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the device */
 	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_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_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_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_NO_FSBR		0x0020	/* UHCI-specific */
 #define URB_ZERO_PACKET		0x0040	/* Finish bulk OUTs with short packet */
 #define URB_ZERO_PACKET		0x0040	/* Finish bulk OUTs with short packet */
 #define URB_NO_INTERRUPT	0x0080	/* HINT: no non-error interrupt needed */
 #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:
  * Initialization:
  *
  *
  * All URBs submitted must initialize the dev, pipe, transfer_flags (may be
  * 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
  * transfer_buffer and transfer_buffer_length.  They may provide the
  * URB_SHORT_NOT_OK transfer flag, indicating that short reads are
  * URB_SHORT_NOT_OK transfer flag, indicating that short reads are
  * to be treated as errors; that flag is invalid for write requests.
  * 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 {
 struct isp116x_platform_data {
 	/* Enable internal resistors on downstream ports */
 	/* Enable internal resistors on downstream ports */
 	unsigned sel15Kres:1;
 	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;
 	unsigned oc_enable:1;
 	/* INT output polarity */
 	/* INT output polarity */
 	unsigned int_act_high:1;
 	unsigned int_act_high:1;
 	/* INT edge or level triggered */
 	/* INT edge or level triggered */
 	unsigned int_edge_triggered:1;
 	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;
 	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
 	/* Inter-io delay (ns). The chip is picky about access timings; it
 	   expects at least:
 	   expects at least:
 	   150ns delay between consecutive accesses to DATA_REG,
 	   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_bit(i, &subs->active_mask)) {
 			if (! test_and_set_bit(i, &subs->unlink_mask)) {
 			if (! test_and_set_bit(i, &subs->unlink_mask)) {
 				struct urb *u = subs->dataurb[i].urb;
 				struct urb *u = subs->dataurb[i].urb;
-				if (async) {
-					u->transfer_flags |= URB_ASYNC_UNLINK;
+				if (async)
 					usb_unlink_urb(u);
 					usb_unlink_urb(u);
-				} else
+				else
 					usb_kill_urb(u);
 					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_bit(i+16, &subs->active_mask)) {
  				if (! test_and_set_bit(i+16, &subs->unlink_mask)) {
  				if (! test_and_set_bit(i+16, &subs->unlink_mask)) {
 					struct urb *u = subs->syncurb[i].urb;
 					struct urb *u = subs->syncurb[i].urb;
-					if (async) {
-						u->transfer_flags |= URB_ASYNC_UNLINK;
+					if (async)
 						usb_unlink_urb(u);
 						usb_unlink_urb(u);
-					} else
+					else
 						usb_kill_urb(u);
 						usb_kill_urb(u);
 				}
 				}
 			}
 			}