Blame view

common/usb_storage.c 39 KB
affae2bff   wdenk   Initial revision
1
  /*
460c322f1   Wolfgang Denk   (re)enabled scsi ...
2
3
4
5
6
7
8
9
10
11
   * Most of this source has been derived from the Linux USB
   * project:
   *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
   *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
   *   (c) 1999 Michael Gee (michael@linuxspecific.com)
   *   (c) 2000 Yggdrasil Computing, Inc.
   *
   *
   * Adapted for U-Boot:
   *   (C) Copyright 2001 Denis Peter, MPL AG Switzerland
acf277af6   Simon Glass   dm: usb: Convert ...
12
13
   * Driver model conversion:
   *   (C) Copyright 2015 Google, Inc
affae2bff   wdenk   Initial revision
14
   *
149dded2b   wdenk   * Add support for...
15
   * For BBB support (C) Copyright 2003
792a09eb9   Detlev Zundel   Fix e-mail addres...
16
   * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
149dded2b   wdenk   * Add support for...
17
   *
460c322f1   Wolfgang Denk   (re)enabled scsi ...
18
   * BBB support based on /sys/dev/usb/umass.c from
149dded2b   wdenk   * Add support for...
19
   * FreeBSD.
affae2bff   wdenk   Initial revision
20
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
21
   * SPDX-License-Identifier:	GPL-2.0+
affae2bff   wdenk   Initial revision
22
23
24
25
26
27
28
   */
  
  /* Note:
   * Currently only the CBI transport protocoll has been implemented, and it
   * is only tested with a TEAC USB Floppy. Other Massstorages with CBI or CB
   * transport protocoll may work as well.
   */
149dded2b   wdenk   * Add support for...
29
30
31
32
  /*
   * New Note:
   * Support for USB Mass Storage Devices (BBB) has been added. It has
   * only been tested with USB memory sticks.
149dded2b   wdenk   * Add support for...
33
   */
affae2bff   wdenk   Initial revision
34

affae2bff   wdenk   Initial revision
35
36
  #include <common.h>
  #include <command.h>
acf277af6   Simon Glass   dm: usb: Convert ...
37
  #include <dm.h>
91557579a   Simon Glass   dm: usb: Move sto...
38
  #include <errno.h>
4fd074de0   Simon Glass   usb: Use correct ...
39
  #include <inttypes.h>
051081323   Simon Glass   dm: usb: Adjust u...
40
  #include <mapmem.h>
c918261c6   Christian Eggers   USB: replace old ...
41
  #include <asm/byteorder.h>
affae2bff   wdenk   Initial revision
42
  #include <asm/processor.h>
acf277af6   Simon Glass   dm: usb: Convert ...
43
  #include <dm/device-internal.h>
affae2bff   wdenk   Initial revision
44

735dd97b1   Grant Likely   [PATCH 1_4] Merge...
45
  #include <part.h>
affae2bff   wdenk   Initial revision
46
  #include <usb.h>
80885a9d5   wdenk   * Patch by Markus...
47
48
  #undef BBB_COMDAT_TRACE
  #undef BBB_XPORT_TRACE
affae2bff   wdenk   Initial revision
49

affae2bff   wdenk   Initial revision
50
51
52
53
  #include <scsi.h>
  /* direction table -- this indicates the direction of the data
   * transfer for each command code -- a 1 indicates input
   */
2ff122854   Mike Frysinger   usb_storage: cons...
54
  static const unsigned char us_direction[256/8] = {
affae2bff   wdenk   Initial revision
55
56
57
58
59
60
  	0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
  	0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
  	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  };
  #define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
f57661394   Puneet Saxena   USB: Align buffer...
61
  static ccb usb_ccb __attribute__((aligned(ARCH_DMA_MINALIGN)));
a0cb3fc31   Michael Trimarchi   USB storage clean...
62
  static __u32 CBWTag;
149dded2b   wdenk   * Add support for...
63

affae2bff   wdenk   Initial revision
64
  #define USB_MAX_STOR_DEV 5
a0cb3fc31   Michael Trimarchi   USB storage clean...
65
  static int usb_max_devs; /* number of highest available usb device */
affae2bff   wdenk   Initial revision
66
67
68
69
  
  static block_dev_desc_t usb_dev_desc[USB_MAX_STOR_DEV];
  
  struct us_data;
a0cb3fc31   Michael Trimarchi   USB storage clean...
70
71
  typedef int (*trans_cmnd)(ccb *cb, struct us_data *data);
  typedef int (*trans_reset)(struct us_data *data);
affae2bff   wdenk   Initial revision
72
73
  
  struct us_data {
a0cb3fc31   Michael Trimarchi   USB storage clean...
74
75
76
  	struct usb_device *pusb_dev;	 /* this usb_device */
  
  	unsigned int	flags;			/* from filter initially */
3e8581bb9   Benoît Thébaudeau   usb_stor_BBB_tran...
77
  #	define USB_READY	(1 << 0)
a0cb3fc31   Michael Trimarchi   USB storage clean...
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  	unsigned char	ifnum;			/* interface number */
  	unsigned char	ep_in;			/* in endpoint */
  	unsigned char	ep_out;			/* out ....... */
  	unsigned char	ep_int;			/* interrupt . */
  	unsigned char	subclass;		/* as in overview */
  	unsigned char	protocol;		/* .............. */
  	unsigned char	attention_done;		/* force attn on first cmd */
  	unsigned short	ip_data;		/* interrupt data */
  	int		action;			/* what to do */
  	int		ip_wanted;		/* needed */
  	int		*irq_handle;		/* for USB int requests */
  	unsigned int	irqpipe;	 	/* pipe for release_irq */
  	unsigned char	irqmaxp;		/* max packed for irq Pipe */
  	unsigned char	irqinterval;		/* Intervall for IRQ Pipe */
  	ccb		*srb;			/* current srb */
  	trans_reset	transport_reset;	/* reset routine */
  	trans_cmnd	transport;		/* transport routine */
affae2bff   wdenk   Initial revision
95
  };
cffcc5035   Benoît Thébaudeau   usb_storage: Rest...
96
  #ifdef CONFIG_USB_EHCI
1b4bd0e66   Stefan Herbrechtsmeier   usb_storage: fix ...
97
  /*
4bee5c83e   Benoît Thébaudeau   usb_storage: Remo...
98
99
100
   * The U-Boot EHCI driver can handle any transfer length as long as there is
   * enough free heap space left, but the SCSI READ(10) and WRITE(10) commands are
   * limited to 65535 blocks.
1b4bd0e66   Stefan Herbrechtsmeier   usb_storage: fix ...
101
   */
4bee5c83e   Benoît Thébaudeau   usb_storage: Remo...
102
  #define USB_MAX_XFER_BLK	65535
cffcc5035   Benoît Thébaudeau   usb_storage: Rest...
103
  #else
4bee5c83e   Benoît Thébaudeau   usb_storage: Remo...
104
  #define USB_MAX_XFER_BLK	20
cffcc5035   Benoît Thébaudeau   usb_storage: Rest...
105
  #endif
1b4bd0e66   Stefan Herbrechtsmeier   usb_storage: fix ...
106

affae2bff   wdenk   Initial revision
107
  static struct us_data usb_stor[USB_MAX_STOR_DEV];
80885a9d5   wdenk   * Patch by Markus...
108
  #define USB_STOR_TRANSPORT_GOOD	   0
affae2bff   wdenk   Initial revision
109
110
  #define USB_STOR_TRANSPORT_FAILED -1
  #define USB_STOR_TRANSPORT_ERROR  -2
a0cb3fc31   Michael Trimarchi   USB storage clean...
111
112
113
114
  int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
  		      block_dev_desc_t *dev_desc);
  int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
  		      struct us_data *ss);
ff8fef566   Sascha Silbe   Fix block device ...
115
  unsigned long usb_stor_read(int device, lbaint_t blknr,
e81e79ede   Gabe Black   usb: Support the ...
116
  			    lbaint_t blkcnt, void *buffer);
ff8fef566   Sascha Silbe   Fix block device ...
117
  unsigned long usb_stor_write(int device, lbaint_t blknr,
e81e79ede   Gabe Black   usb: Support the ...
118
  			     lbaint_t blkcnt, const void *buffer);
affae2bff   wdenk   Initial revision
119
  void uhci_show_temp_int_td(void);
df3fc5260   Matthew McClintock   disk/part.c: Make...
120
  #ifdef CONFIG_PARTITIONS
affae2bff   wdenk   Initial revision
121
122
  block_dev_desc_t *usb_stor_get_dev(int index)
  {
aaad108b8   Kim B. Heino   USB storage count
123
  	return (index < usb_max_devs) ? &usb_dev_desc[index] : NULL;
affae2bff   wdenk   Initial revision
124
  }
df3fc5260   Matthew McClintock   disk/part.c: Make...
125
  #endif
affae2bff   wdenk   Initial revision
126

199adb601   Kim Phillips   common/misc: spar...
127
  static void usb_show_progress(void)
affae2bff   wdenk   Initial revision
128
  {
226fa9bb9   Wolfgang Denk   usb_storage.c: ch...
129
  	debug(".");
affae2bff   wdenk   Initial revision
130
  }
a0cb3fc31   Michael Trimarchi   USB storage clean...
131
  /*******************************************************************************
9c998aa83   Wolfgang Denk   Fix low-level OHC...
132
133
134
   * show info on storage devices; 'usb start/init' must be invoked earlier
   * as we only retrieve structures populated during devices initialization
   */
f6b44e0e4   Aras Vaichas   USB Storage, add ...
135
  int usb_stor_info(void)
9c998aa83   Wolfgang Denk   Fix low-level OHC...
136
137
  {
  	int i;
f6b44e0e4   Aras Vaichas   USB Storage, add ...
138
  	if (usb_max_devs > 0) {
9c998aa83   Wolfgang Denk   Fix low-level OHC...
139
  		for (i = 0; i < usb_max_devs; i++) {
a0cb3fc31   Michael Trimarchi   USB storage clean...
140
  			printf("  Device %d: ", i);
9c998aa83   Wolfgang Denk   Fix low-level OHC...
141
142
  			dev_print(&usb_dev_desc[i]);
  		}
b9e749e95   Markus Klotzbuecher   USB, Storage: fix...
143
  		return 0;
f6b44e0e4   Aras Vaichas   USB Storage, add ...
144
  	}
1aeed8d71   Wolfgang Denk   Coding Style clea...
145

b9e749e95   Markus Klotzbuecher   USB, Storage: fix...
146
147
148
  	printf("No storage devices, perhaps not 'usb start'ed..?
  ");
  	return 1;
9c998aa83   Wolfgang Denk   Fix low-level OHC...
149
  }
99e9ed1f4   Ludovic Courtès   usb: Add support ...
150
151
152
  static unsigned int usb_get_max_lun(struct us_data *us)
  {
  	int len;
f57661394   Puneet Saxena   USB: Align buffer...
153
  	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, result, 1);
99e9ed1f4   Ludovic Courtès   usb: Add support ...
154
155
156
157
158
  	len = usb_control_msg(us->pusb_dev,
  			      usb_rcvctrlpipe(us->pusb_dev, 0),
  			      US_BBB_GET_MAX_LUN,
  			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
  			      0, us->ifnum,
f57661394   Puneet Saxena   USB: Align buffer...
159
  			      result, sizeof(char),
99e9ed1f4   Ludovic Courtès   usb: Add support ...
160
  			      USB_CNTL_TIMEOUT * 5);
ceb4972a8   Vivek Gautam   usb: common: Weed...
161
162
  	debug("Get Max LUN -> len = %i, result = %i
  ", len, (int) *result);
f57661394   Puneet Saxena   USB: Align buffer...
163
  	return (len > 0) ? *result : 0;
99e9ed1f4   Ludovic Courtès   usb: Add support ...
164
  }
91557579a   Simon Glass   dm: usb: Move sto...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  static int usb_stor_probe_device(struct usb_device *dev)
  {
  	if (dev == NULL)
  		return -ENOENT; /* no more devices available */
  
  	debug("
  
  Probing for storage
  ");
  	if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
  		/* OK, it's a storage device.  Iterate over its LUNs
  			* and populate `usb_dev_desc'.
  			*/
  		int lun, max_lun, start = usb_max_devs;
  
  		max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
  		for (lun = 0;
  			lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
  			lun++) {
  			struct block_dev_desc *blkdev;
  
  			blkdev = &usb_dev_desc[usb_max_devs];
  			memset(blkdev, '\0', sizeof(block_dev_desc_t));
  			blkdev->if_type = IF_TYPE_USB;
  			blkdev->dev = usb_max_devs;
  			blkdev->part_type = PART_TYPE_UNKNOWN;
  			blkdev->target = 0xff;
  			blkdev->type = DEV_TYPE_UNKNOWN;
  			blkdev->block_read = usb_stor_read;
  			blkdev->block_write = usb_stor_write;
  			blkdev->lun = lun;
  			blkdev->priv = dev;
  
  			if (usb_stor_get_info(dev, &usb_stor[start],
  					      &usb_dev_desc[usb_max_devs]) ==
  					      1) {
  				usb_max_devs++;
  				debug("%s: Found device %p
  ", __func__, dev);
  			}
  		}
  	}
  
  	/* if storage device */
  	if (usb_max_devs == USB_MAX_STOR_DEV) {
  		printf("max USB Storage Device reached: %d stopping
  ",
  		       usb_max_devs);
  		return -ENOSPC;
  	}
  
  	return 0;
  }
  
  void usb_stor_reset(void)
  {
  	usb_max_devs = 0;
  }
acf277af6   Simon Glass   dm: usb: Convert ...
223
  #ifndef CONFIG_DM_USB
a0cb3fc31   Michael Trimarchi   USB storage clean...
224
  /*******************************************************************************
9c998aa83   Wolfgang Denk   Fix low-level OHC...
225
   * scan the usb and reports device info
affae2bff   wdenk   Initial revision
226
227
228
229
230
   * to the user if mode = 1
   * returns current device or -1 if no
   */
  int usb_stor_scan(int mode)
  {
7fc2c1ea7   Simon Glass   Revert "usb_stora...
231
  	unsigned char i;
affae2bff   wdenk   Initial revision
232

a0cb3fc31   Michael Trimarchi   USB storage clean...
233
  	if (mode == 1)
93c2582fe   Lucas Stach   usb: add support ...
234
  		printf("       scanning usb for storage devices... ");
a0cb3fc31   Michael Trimarchi   USB storage clean...
235

affae2bff   wdenk   Initial revision
236
  	usb_disable_asynch(1); /* asynch transfer not allowed */
91557579a   Simon Glass   dm: usb: Move sto...
237
  	usb_stor_reset();
a0cb3fc31   Michael Trimarchi   USB storage clean...
238
  	for (i = 0; i < USB_MAX_DEVICE; i++) {
91557579a   Simon Glass   dm: usb: Move sto...
239
  		struct usb_device *dev;
a0cb3fc31   Michael Trimarchi   USB storage clean...
240
  		dev = usb_get_dev_index(i); /* get device */
ceb4972a8   Vivek Gautam   usb: common: Weed...
241
242
  		debug("i=%d
  ", i);
91557579a   Simon Glass   dm: usb: Move sto...
243
  		if (usb_stor_probe_device(dev))
affae2bff   wdenk   Initial revision
244
  			break;
affae2bff   wdenk   Initial revision
245
  	} /* for */
095b8a379   Wolfgang Denk   Coding style cleanup
246

affae2bff   wdenk   Initial revision
247
  	usb_disable_asynch(0); /* asynch transfer allowed */
9c998aa83   Wolfgang Denk   Fix low-level OHC...
248
249
  	printf("%d Storage Device(s) found
  ", usb_max_devs);
a0cb3fc31   Michael Trimarchi   USB storage clean...
250
  	if (usb_max_devs > 0)
affae2bff   wdenk   Initial revision
251
  		return 0;
a0cb3fc31   Michael Trimarchi   USB storage clean...
252
  	return -1;
affae2bff   wdenk   Initial revision
253
  }
acf277af6   Simon Glass   dm: usb: Convert ...
254
  #endif
affae2bff   wdenk   Initial revision
255
256
257
258
  
  static int usb_stor_irq(struct usb_device *dev)
  {
  	struct us_data *us;
a0cb3fc31   Michael Trimarchi   USB storage clean...
259
  	us = (struct us_data *)dev->privptr;
affae2bff   wdenk   Initial revision
260

a0cb3fc31   Michael Trimarchi   USB storage clean...
261
262
  	if (us->ip_wanted)
  		us->ip_wanted = 0;
affae2bff   wdenk   Initial revision
263
264
  	return 0;
  }
ceb4972a8   Vivek Gautam   usb: common: Weed...
265
  #ifdef	DEBUG
affae2bff   wdenk   Initial revision
266

a0cb3fc31   Michael Trimarchi   USB storage clean...
267
  static void usb_show_srb(ccb *pccb)
affae2bff   wdenk   Initial revision
268
269
  {
  	int i;
a0cb3fc31   Michael Trimarchi   USB storage clean...
270
271
272
273
  	printf("SRB: len %d datalen 0x%lX
   ", pccb->cmdlen, pccb->datalen);
  	for (i = 0; i < 12; i++)
  		printf("%02X ", pccb->cmd[i]);
affae2bff   wdenk   Initial revision
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  	printf("
  ");
  }
  
  static void display_int_status(unsigned long tmp)
  {
  	printf("Status: %s %s %s %s %s %s %s
  ",
  		(tmp & USB_ST_ACTIVE) ? "Active" : "",
  		(tmp & USB_ST_STALLED) ? "Stalled" : "",
  		(tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "",
  		(tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "",
  		(tmp & USB_ST_NAK_REC) ? "NAKed" : "",
  		(tmp & USB_ST_CRC_ERR) ? "CRC Error" : "",
  		(tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : "");
  }
  #endif
  /***********************************************************************
   * Data transfer routines
   ***********************************************************************/
  
  static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
  {
  	int max_size;
  	int this_xfer;
  	int result;
  	int partial;
  	int maxtry;
  	int stat;
  
  	/* determine the maximum packet size for these transfers */
  	max_size = usb_maxpacket(us->pusb_dev, pipe) * 16;
  
  	/* while we have data left to transfer */
  	while (length) {
  
  		/* calculate how long this will be -- maximum or a remainder */
  		this_xfer = length > max_size ? max_size : length;
  		length -= this_xfer;
  
  		/* setup the retry counter */
  		maxtry = 10;
  
  		/* set up the transfer loop */
  		do {
  			/* transfer the data */
051081323   Simon Glass   dm: usb: Adjust u...
320
321
322
323
  			debug("Bulk xfer 0x%lx(%d) try #%d
  ",
  			      (ulong)map_to_sysmem(buf), this_xfer,
  			      11 - maxtry);
affae2bff   wdenk   Initial revision
324
  			result = usb_bulk_msg(us->pusb_dev, pipe, buf,
a0cb3fc31   Michael Trimarchi   USB storage clean...
325
326
  					      this_xfer, &partial,
  					      USB_CNTL_TIMEOUT * 5);
ceb4972a8   Vivek Gautam   usb: common: Weed...
327
328
329
  			debug("bulk_msg returned %d xferred %d/%d
  ",
  			      result, partial, this_xfer);
a0cb3fc31   Michael Trimarchi   USB storage clean...
330
331
332
333
  			if (us->pusb_dev->status != 0) {
  				/* if we stall, we need to clear it before
  				 * we go on
  				 */
ceb4972a8   Vivek Gautam   usb: common: Weed...
334
  #ifdef DEBUG
affae2bff   wdenk   Initial revision
335
336
337
  				display_int_status(us->pusb_dev->status);
  #endif
  				if (us->pusb_dev->status & USB_ST_STALLED) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
338
339
340
  					debug("stalled ->clearing endpoint" \
  					      "halt for pipe 0x%x
  ", pipe);
affae2bff   wdenk   Initial revision
341
342
  					stat = us->pusb_dev->status;
  					usb_clear_halt(us->pusb_dev, pipe);
a0cb3fc31   Michael Trimarchi   USB storage clean...
343
344
  					us->pusb_dev->status = stat;
  					if (this_xfer == partial) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
345
346
347
348
349
  						debug("bulk transferred" \
  						      "with error %lX," \
  						      " but data ok
  ",
  						      us->pusb_dev->status);
affae2bff   wdenk   Initial revision
350
351
352
353
354
355
  						return 0;
  					}
  					else
  						return result;
  				}
  				if (us->pusb_dev->status & USB_ST_NAK_REC) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
356
357
  					debug("Device NAKed bulk_msg
  ");
affae2bff   wdenk   Initial revision
358
359
  					return result;
  				}
ceb4972a8   Vivek Gautam   usb: common: Weed...
360
  				debug("bulk transferred with error");
a0cb3fc31   Michael Trimarchi   USB storage clean...
361
  				if (this_xfer == partial) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
362
363
364
  					debug(" %ld, but data ok
  ",
  					      us->pusb_dev->status);
affae2bff   wdenk   Initial revision
365
366
367
  					return 0;
  				}
  				/* if our try counter reaches 0, bail out */
ceb4972a8   Vivek Gautam   usb: common: Weed...
368
369
370
  					debug(" %ld, data %d
  ",
  					      us->pusb_dev->status, partial);
affae2bff   wdenk   Initial revision
371
372
373
374
375
376
377
  				if (!maxtry--)
  						return result;
  			}
  			/* update to show what data was transferred */
  			this_xfer -= partial;
  			buf += partial;
  			/* continue until this transfer is done */
a0cb3fc31   Michael Trimarchi   USB storage clean...
378
  		} while (this_xfer);
affae2bff   wdenk   Initial revision
379
380
381
382
383
  	}
  
  	/* if we get here, we're done and successful */
  	return 0;
  }
149dded2b   wdenk   * Add support for...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
  static int usb_stor_BBB_reset(struct us_data *us)
  {
  	int result;
  	unsigned int pipe;
  
  	/*
  	 * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
  	 *
  	 * For Reset Recovery the host shall issue in the following order:
  	 * a) a Bulk-Only Mass Storage Reset
  	 * b) a Clear Feature HALT to the Bulk-In endpoint
  	 * c) a Clear Feature HALT to the Bulk-Out endpoint
  	 *
  	 * This is done in 3 steps.
  	 *
  	 * If the reset doesn't succeed, the device should be port reset.
  	 *
  	 * This comment stolen from FreeBSD's /sys/dev/usb/umass.c.
  	 */
ceb4972a8   Vivek Gautam   usb: common: Weed...
403
404
  	debug("BBB_reset
  ");
a0cb3fc31   Michael Trimarchi   USB storage clean...
405
406
407
  	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
  				 US_BBB_RESET,
  				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
199adb601   Kim Phillips   common/misc: spar...
408
  				 0, us->ifnum, NULL, 0, USB_CNTL_TIMEOUT * 5);
9c998aa83   Wolfgang Denk   Fix low-level OHC...
409

a0cb3fc31   Michael Trimarchi   USB storage clean...
410
  	if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
411
412
  		debug("RESET:stall
  ");
149dded2b   wdenk   * Add support for...
413
414
  		return -1;
  	}
9c998aa83   Wolfgang Denk   Fix low-level OHC...
415

149dded2b   wdenk   * Add support for...
416
  	/* long wait for reset */
5b84dd67c   Mike Frysinger   usb: replace wait...
417
  	mdelay(150);
ceb4972a8   Vivek Gautam   usb: common: Weed...
418
419
420
  	debug("BBB_reset result %d: status %lX reset
  ",
  	      result, us->pusb_dev->status);
149dded2b   wdenk   * Add support for...
421
422
423
  	pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
  	result = usb_clear_halt(us->pusb_dev, pipe);
  	/* long wait for reset */
5b84dd67c   Mike Frysinger   usb: replace wait...
424
  	mdelay(150);
ceb4972a8   Vivek Gautam   usb: common: Weed...
425
426
427
  	debug("BBB_reset result %d: status %lX clearing IN endpoint
  ",
  	      result, us->pusb_dev->status);
149dded2b   wdenk   * Add support for...
428
429
430
  	/* long wait for reset */
  	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
  	result = usb_clear_halt(us->pusb_dev, pipe);
5b84dd67c   Mike Frysinger   usb: replace wait...
431
  	mdelay(150);
ceb4972a8   Vivek Gautam   usb: common: Weed...
432
433
434
435
436
  	debug("BBB_reset result %d: status %lX clearing OUT endpoint
  ",
  	      result, us->pusb_dev->status);
  	debug("BBB_reset done
  ");
149dded2b   wdenk   * Add support for...
437
438
  	return 0;
  }
affae2bff   wdenk   Initial revision
439
440
441
442
443
444
445
446
  /* FIXME: this reset function doesn't really reset the port, and it
   * should. Actually it should probably do what it's doing here, and
   * reset the port physically
   */
  static int usb_stor_CB_reset(struct us_data *us)
  {
  	unsigned char cmd[12];
  	int result;
ceb4972a8   Vivek Gautam   usb: common: Weed...
447
448
  	debug("CB_reset
  ");
a0cb3fc31   Michael Trimarchi   USB storage clean...
449
  	memset(cmd, 0xff, sizeof(cmd));
affae2bff   wdenk   Initial revision
450
451
  	cmd[0] = SCSI_SEND_DIAG;
  	cmd[1] = 4;
a0cb3fc31   Michael Trimarchi   USB storage clean...
452
453
454
455
456
  	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
  				 US_CBI_ADSC,
  				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
  				 0, us->ifnum, cmd, sizeof(cmd),
  				 USB_CNTL_TIMEOUT * 5);
affae2bff   wdenk   Initial revision
457
458
  
  	/* long wait for reset */
5b84dd67c   Mike Frysinger   usb: replace wait...
459
  	mdelay(1500);
ceb4972a8   Vivek Gautam   usb: common: Weed...
460
461
462
  	debug("CB_reset result %d: status %lX clearing endpoint halt
  ",
  	      result, us->pusb_dev->status);
affae2bff   wdenk   Initial revision
463
464
  	usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
  	usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
ceb4972a8   Vivek Gautam   usb: common: Weed...
465
466
  	debug("CB_reset done
  ");
affae2bff   wdenk   Initial revision
467
468
  	return 0;
  }
149dded2b   wdenk   * Add support for...
469
470
471
472
  /*
   * Set up the command for a BBB device. Note that the actual SCSI
   * command is copied into cbw.CBWCDB.
   */
199adb601   Kim Phillips   common/misc: spar...
473
  static int usb_stor_BBB_comdat(ccb *srb, struct us_data *us)
149dded2b   wdenk   * Add support for...
474
475
476
477
478
  {
  	int result;
  	int actlen;
  	int dir_in;
  	unsigned int pipe;
2e17c87eb   Simon Glass   dm: usb: Move USB...
479
  	ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_cbw, cbw, 1);
149dded2b   wdenk   * Add support for...
480
481
482
483
  
  	dir_in = US_DIRECTION(srb->cmd[0]);
  
  #ifdef BBB_COMDAT_TRACE
605bd75af   Vivek Gautam   USB: Some cleanup...
484
485
  	printf("dir %d lun %d cmdlen %d cmd %p datalen %lu pdata %p
  ",
a0cb3fc31   Michael Trimarchi   USB storage clean...
486
487
  		dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen,
  		srb->pdata);
149dded2b   wdenk   * Add support for...
488
  	if (srb->cmdlen) {
a0cb3fc31   Michael Trimarchi   USB storage clean...
489
  		for (result = 0; result < srb->cmdlen; result++)
149dded2b   wdenk   * Add support for...
490
491
492
493
494
495
496
  			printf("cmd[%d] %#x ", result, srb->cmd[result]);
  		printf("
  ");
  	}
  #endif
  	/* sanity checks */
  	if (!(srb->cmdlen <= CBWCDBLENGTH)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
497
498
  		debug("usb_stor_BBB_comdat:cmdlen too large
  ");
149dded2b   wdenk   * Add support for...
499
500
501
502
503
  		return -1;
  	}
  
  	/* always OUT to the ep */
  	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
f57661394   Puneet Saxena   USB: Align buffer...
504
505
506
507
508
509
  	cbw->dCBWSignature = cpu_to_le32(CBWSIGNATURE);
  	cbw->dCBWTag = cpu_to_le32(CBWTag++);
  	cbw->dCBWDataTransferLength = cpu_to_le32(srb->datalen);
  	cbw->bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT);
  	cbw->bCBWLUN = srb->lun;
  	cbw->bCDBLength = srb->cmdlen;
149dded2b   wdenk   * Add support for...
510
511
  	/* copy the command data into the CBW command data buffer */
  	/* DST SRC LEN!!! */
f65708713   Sergey Temerkhanov   usb_storage:Fix U...
512

f57661394   Puneet Saxena   USB: Align buffer...
513
514
  	memcpy(cbw->CBWCDB, srb->cmd, srb->cmdlen);
  	result = usb_bulk_msg(us->pusb_dev, pipe, cbw, UMASS_BBB_CBW_SIZE,
a0cb3fc31   Michael Trimarchi   USB storage clean...
515
  			      &actlen, USB_CNTL_TIMEOUT * 5);
149dded2b   wdenk   * Add support for...
516
  	if (result < 0)
ceb4972a8   Vivek Gautam   usb: common: Weed...
517
518
  		debug("usb_stor_BBB_comdat:usb_bulk_msg error
  ");
149dded2b   wdenk   * Add support for...
519
520
  	return result;
  }
affae2bff   wdenk   Initial revision
521
522
523
  /* FIXME: we also need a CBI_command which sets up the completion
   * interrupt, and waits for it
   */
199adb601   Kim Phillips   common/misc: spar...
524
  static int usb_stor_CB_comdat(ccb *srb, struct us_data *us)
affae2bff   wdenk   Initial revision
525
  {
77ddac948   Wolfgang Denk   Cleanup for GCC-4.x
526
  	int result = 0;
a0cb3fc31   Michael Trimarchi   USB storage clean...
527
  	int dir_in, retry;
affae2bff   wdenk   Initial revision
528
529
  	unsigned int pipe;
  	unsigned long status;
a0cb3fc31   Michael Trimarchi   USB storage clean...
530
531
  	retry = 5;
  	dir_in = US_DIRECTION(srb->cmd[0]);
affae2bff   wdenk   Initial revision
532

a0cb3fc31   Michael Trimarchi   USB storage clean...
533
534
535
536
537
538
  	if (dir_in)
  		pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
  	else
  		pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
  
  	while (retry--) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
539
540
541
  		debug("CBI gets a command: Try %d
  ", 5 - retry);
  #ifdef DEBUG
affae2bff   wdenk   Initial revision
542
543
544
  		usb_show_srb(srb);
  #endif
  		/* let's send the command via the control pipe */
a0cb3fc31   Michael Trimarchi   USB storage clean...
545
546
547
548
  		result = usb_control_msg(us->pusb_dev,
  					 usb_sndctrlpipe(us->pusb_dev , 0),
  					 US_CBI_ADSC,
  					 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
affae2bff   wdenk   Initial revision
549
  					 0, us->ifnum,
a0cb3fc31   Michael Trimarchi   USB storage clean...
550
551
  					 srb->cmd, srb->cmdlen,
  					 USB_CNTL_TIMEOUT * 5);
ceb4972a8   Vivek Gautam   usb: common: Weed...
552
553
554
  		debug("CB_transport: control msg returned %d, status %lX
  ",
  		      result, us->pusb_dev->status);
affae2bff   wdenk   Initial revision
555
556
  		/* check the return code for the command */
  		if (result < 0) {
a0cb3fc31   Michael Trimarchi   USB storage clean...
557
558
  			if (us->pusb_dev->status & USB_ST_STALLED) {
  				status = us->pusb_dev->status;
ceb4972a8   Vivek Gautam   usb: common: Weed...
559
560
561
  				debug(" stall during command found," \
  				      " clear pipe
  ");
a0cb3fc31   Michael Trimarchi   USB storage clean...
562
563
564
  				usb_clear_halt(us->pusb_dev,
  					      usb_sndctrlpipe(us->pusb_dev, 0));
  				us->pusb_dev->status = status;
affae2bff   wdenk   Initial revision
565
  			}
ceb4972a8   Vivek Gautam   usb: common: Weed...
566
567
568
569
  			debug(" error during command %02X" \
  			      " Stat = %lX
  ", srb->cmd[0],
  			      us->pusb_dev->status);
affae2bff   wdenk   Initial revision
570
571
572
  			return result;
  		}
  		/* transfer the data payload for this command, if one exists*/
ceb4972a8   Vivek Gautam   usb: common: Weed...
573
574
575
576
  		debug("CB_transport: control msg returned %d," \
  		      " direction is %s to go 0x%lx
  ", result,
  		      dir_in ? "IN" : "OUT", srb->datalen);
affae2bff   wdenk   Initial revision
577
  		if (srb->datalen) {
a0cb3fc31   Michael Trimarchi   USB storage clean...
578
579
  			result = us_one_transfer(us, pipe, (char *)srb->pdata,
  						 srb->datalen);
ceb4972a8   Vivek Gautam   usb: common: Weed...
580
581
582
583
584
  			debug("CBI attempted to transfer data," \
  			      " result is %d status %lX, len %d
  ",
  			      result, us->pusb_dev->status,
  				us->pusb_dev->act_len);
a0cb3fc31   Michael Trimarchi   USB storage clean...
585
  			if (!(us->pusb_dev->status & USB_ST_NAK_REC))
affae2bff   wdenk   Initial revision
586
587
588
589
590
591
592
593
594
  				break;
  		} /* if (srb->datalen) */
  		else
  			break;
  	}
  	/* return result */
  
  	return result;
  }
199adb601   Kim Phillips   common/misc: spar...
595
  static int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)
affae2bff   wdenk   Initial revision
596
597
  {
  	int timeout;
80885a9d5   wdenk   * Patch by Markus...
598
  	us->ip_wanted = 1;
a0cb3fc31   Michael Trimarchi   USB storage clean...
599
  	submit_int_msg(us->pusb_dev, us->irqpipe,
80885a9d5   wdenk   * Patch by Markus...
600
601
602
  			(void *) &us->ip_data, us->irqmaxp, us->irqinterval);
  	timeout = 1000;
  	while (timeout--) {
f65708713   Sergey Temerkhanov   usb_storage:Fix U...
603
  		if (us->ip_wanted == 0)
affae2bff   wdenk   Initial revision
604
  			break;
5b84dd67c   Mike Frysinger   usb: replace wait...
605
  		mdelay(10);
affae2bff   wdenk   Initial revision
606
607
  	}
  	if (us->ip_wanted) {
a0cb3fc31   Michael Trimarchi   USB storage clean...
608
609
  		printf("	Did not get interrupt on CBI
  ");
affae2bff   wdenk   Initial revision
610
611
612
  		us->ip_wanted = 0;
  		return USB_STOR_TRANSPORT_ERROR;
  	}
ceb4972a8   Vivek Gautam   usb: common: Weed...
613
614
615
616
  	debug("Got interrupt data 0x%x, transfered %d status 0x%lX
  ",
  	      us->ip_data, us->pusb_dev->irq_act_len,
  	      us->pusb_dev->irq_status);
affae2bff   wdenk   Initial revision
617
618
619
620
621
  	/* UFI gives us ASC and ASCQ, like a request sense */
  	if (us->subclass == US_SC_UFI) {
  		if (srb->cmd[0] == SCSI_REQ_SENSE ||
  		    srb->cmd[0] == SCSI_INQUIRY)
  			return USB_STOR_TRANSPORT_GOOD; /* Good */
80885a9d5   wdenk   * Patch by Markus...
622
623
  		else if (us->ip_data)
  			return USB_STOR_TRANSPORT_FAILED;
affae2bff   wdenk   Initial revision
624
  		else
80885a9d5   wdenk   * Patch by Markus...
625
  			return USB_STOR_TRANSPORT_GOOD;
affae2bff   wdenk   Initial revision
626
627
628
  	}
  	/* otherwise, we interpret the data normally */
  	switch (us->ip_data) {
80885a9d5   wdenk   * Patch by Markus...
629
630
631
632
633
634
635
  	case 0x0001:
  		return USB_STOR_TRANSPORT_GOOD;
  	case 0x0002:
  		return USB_STOR_TRANSPORT_FAILED;
  	default:
  		return USB_STOR_TRANSPORT_ERROR;
  	}			/* switch */
affae2bff   wdenk   Initial revision
636
637
638
639
640
  	return USB_STOR_TRANSPORT_ERROR;
  }
  
  #define USB_TRANSPORT_UNKNOWN_RETRY 5
  #define USB_TRANSPORT_NOT_READY_RETRY 10
149dded2b   wdenk   * Add support for...
641
  /* clear a stall on an endpoint - special for BBB devices */
199adb601   Kim Phillips   common/misc: spar...
642
  static int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt)
149dded2b   wdenk   * Add support for...
643
644
645
646
  {
  	int result;
  
  	/* ENDPOINT_HALT = 0, so set value to 0 */
a0cb3fc31   Michael Trimarchi   USB storage clean...
647
  	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
149dded2b   wdenk   * Add support for...
648
  				USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
199adb601   Kim Phillips   common/misc: spar...
649
  				0, endpt, NULL, 0, USB_CNTL_TIMEOUT * 5);
149dded2b   wdenk   * Add support for...
650
651
  	return result;
  }
199adb601   Kim Phillips   common/misc: spar...
652
  static int usb_stor_BBB_transport(ccb *srb, struct us_data *us)
149dded2b   wdenk   * Add support for...
653
654
655
656
657
  {
  	int result, retry;
  	int dir_in;
  	int actlen, data_actlen;
  	unsigned int pipe, pipein, pipeout;
2e17c87eb   Simon Glass   dm: usb: Move USB...
658
  	ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_csw, csw, 1);
149dded2b   wdenk   * Add support for...
659
660
661
662
663
664
665
666
  #ifdef BBB_XPORT_TRACE
  	unsigned char *ptr;
  	int index;
  #endif
  
  	dir_in = US_DIRECTION(srb->cmd[0]);
  
  	/* COMMAND phase */
ceb4972a8   Vivek Gautam   usb: common: Weed...
667
668
  	debug("COMMAND phase
  ");
149dded2b   wdenk   * Add support for...
669
670
  	result = usb_stor_BBB_comdat(srb, us);
  	if (result < 0) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
671
672
673
  		debug("failed to send CBW status %ld
  ",
  		      us->pusb_dev->status);
149dded2b   wdenk   * Add support for...
674
675
676
  		usb_stor_BBB_reset(us);
  		return USB_STOR_TRANSPORT_FAILED;
  	}
3e8581bb9   Benoît Thébaudeau   usb_stor_BBB_tran...
677
678
  	if (!(us->flags & USB_READY))
  		mdelay(5);
149dded2b   wdenk   * Add support for...
679
680
681
  	pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
  	pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
  	/* DATA phase + error handling */
149dded2b   wdenk   * Add support for...
682
683
684
685
  	data_actlen = 0;
  	/* no data, go immediately to the STATUS phase */
  	if (srb->datalen == 0)
  		goto st;
ceb4972a8   Vivek Gautam   usb: common: Weed...
686
687
  	debug("DATA phase
  ");
149dded2b   wdenk   * Add support for...
688
689
690
691
  	if (dir_in)
  		pipe = pipein;
  	else
  		pipe = pipeout;
f65708713   Sergey Temerkhanov   usb_storage:Fix U...
692

a0cb3fc31   Michael Trimarchi   USB storage clean...
693
694
  	result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen,
  			      &data_actlen, USB_CNTL_TIMEOUT * 5);
149dded2b   wdenk   * Add support for...
695
  	/* special handling of STALL in DATA phase */
a0cb3fc31   Michael Trimarchi   USB storage clean...
696
  	if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
697
698
  		debug("DATA:stall
  ");
149dded2b   wdenk   * Add support for...
699
  		/* clear the STALL on the endpoint */
a0cb3fc31   Michael Trimarchi   USB storage clean...
700
701
  		result = usb_stor_BBB_clear_endpt_stall(us,
  					dir_in ? us->ep_in : us->ep_out);
149dded2b   wdenk   * Add support for...
702
703
704
705
706
  		if (result >= 0)
  			/* continue on to STATUS phase */
  			goto st;
  	}
  	if (result < 0) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
707
708
709
  		debug("usb_bulk_msg error status %ld
  ",
  		      us->pusb_dev->status);
149dded2b   wdenk   * Add support for...
710
711
712
713
714
715
716
717
718
719
  		usb_stor_BBB_reset(us);
  		return USB_STOR_TRANSPORT_FAILED;
  	}
  #ifdef BBB_XPORT_TRACE
  	for (index = 0; index < data_actlen; index++)
  		printf("pdata[%d] %#x ", index, srb->pdata[index]);
  	printf("
  ");
  #endif
  	/* STATUS phase + error handling */
a0cb3fc31   Michael Trimarchi   USB storage clean...
720
  st:
149dded2b   wdenk   * Add support for...
721
  	retry = 0;
a0cb3fc31   Michael Trimarchi   USB storage clean...
722
  again:
ceb4972a8   Vivek Gautam   usb: common: Weed...
723
724
  	debug("STATUS phase
  ");
f57661394   Puneet Saxena   USB: Align buffer...
725
  	result = usb_bulk_msg(us->pusb_dev, pipein, csw, UMASS_BBB_CSW_SIZE,
9c998aa83   Wolfgang Denk   Fix low-level OHC...
726
  				&actlen, USB_CNTL_TIMEOUT*5);
149dded2b   wdenk   * Add support for...
727
  	/* special handling of STALL in STATUS phase */
a0cb3fc31   Michael Trimarchi   USB storage clean...
728
729
  	if ((result < 0) && (retry < 1) &&
  	    (us->pusb_dev->status & USB_ST_STALLED)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
730
731
  		debug("STATUS:stall
  ");
149dded2b   wdenk   * Add support for...
732
733
734
735
736
737
738
  		/* clear the STALL on the endpoint */
  		result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in);
  		if (result >= 0 && (retry++ < 1))
  			/* do a retry */
  			goto again;
  	}
  	if (result < 0) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
739
740
741
  		debug("usb_bulk_msg error status %ld
  ",
  		      us->pusb_dev->status);
149dded2b   wdenk   * Add support for...
742
743
744
745
  		usb_stor_BBB_reset(us);
  		return USB_STOR_TRANSPORT_FAILED;
  	}
  #ifdef BBB_XPORT_TRACE
f57661394   Puneet Saxena   USB: Align buffer...
746
  	ptr = (unsigned char *)csw;
149dded2b   wdenk   * Add support for...
747
748
749
750
751
752
  	for (index = 0; index < UMASS_BBB_CSW_SIZE; index++)
  		printf("ptr[%d] %#x ", index, ptr[index]);
  	printf("
  ");
  #endif
  	/* misuse pipe to get the residue */
f57661394   Puneet Saxena   USB: Align buffer...
753
  	pipe = le32_to_cpu(csw->dCSWDataResidue);
149dded2b   wdenk   * Add support for...
754
755
  	if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0)
  		pipe = srb->datalen - data_actlen;
f57661394   Puneet Saxena   USB: Align buffer...
756
  	if (CSWSIGNATURE != le32_to_cpu(csw->dCSWSignature)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
757
758
  		debug("!CSWSIGNATURE
  ");
149dded2b   wdenk   * Add support for...
759
760
  		usb_stor_BBB_reset(us);
  		return USB_STOR_TRANSPORT_FAILED;
f57661394   Puneet Saxena   USB: Align buffer...
761
  	} else if ((CBWTag - 1) != le32_to_cpu(csw->dCSWTag)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
762
763
  		debug("!Tag
  ");
149dded2b   wdenk   * Add support for...
764
765
  		usb_stor_BBB_reset(us);
  		return USB_STOR_TRANSPORT_FAILED;
f57661394   Puneet Saxena   USB: Align buffer...
766
  	} else if (csw->bCSWStatus > CSWSTATUS_PHASE) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
767
768
  		debug(">PHASE
  ");
149dded2b   wdenk   * Add support for...
769
770
  		usb_stor_BBB_reset(us);
  		return USB_STOR_TRANSPORT_FAILED;
f57661394   Puneet Saxena   USB: Align buffer...
771
  	} else if (csw->bCSWStatus == CSWSTATUS_PHASE) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
772
773
  		debug("=PHASE
  ");
149dded2b   wdenk   * Add support for...
774
775
776
  		usb_stor_BBB_reset(us);
  		return USB_STOR_TRANSPORT_FAILED;
  	} else if (data_actlen > srb->datalen) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
777
778
779
  		debug("transferred %dB instead of %ldB
  ",
  		      data_actlen, srb->datalen);
149dded2b   wdenk   * Add support for...
780
  		return USB_STOR_TRANSPORT_FAILED;
f57661394   Puneet Saxena   USB: Align buffer...
781
  	} else if (csw->bCSWStatus == CSWSTATUS_FAILED) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
782
783
  		debug("FAILED
  ");
149dded2b   wdenk   * Add support for...
784
785
786
787
788
  		return USB_STOR_TRANSPORT_FAILED;
  	}
  
  	return result;
  }
199adb601   Kim Phillips   common/misc: spar...
789
  static int usb_stor_CB_transport(ccb *srb, struct us_data *us)
affae2bff   wdenk   Initial revision
790
  {
a0cb3fc31   Michael Trimarchi   USB storage clean...
791
  	int result, status;
affae2bff   wdenk   Initial revision
792
793
  	ccb *psrb;
  	ccb reqsrb;
a0cb3fc31   Michael Trimarchi   USB storage clean...
794
  	int retry, notready;
affae2bff   wdenk   Initial revision
795

d0ff51ba5   Wolfgang Denk   Code cleanup: fix...
796
  	psrb = &reqsrb;
a0cb3fc31   Michael Trimarchi   USB storage clean...
797
798
799
  	status = USB_STOR_TRANSPORT_GOOD;
  	retry = 0;
  	notready = 0;
affae2bff   wdenk   Initial revision
800
801
  	/* issue the command */
  do_retry:
a0cb3fc31   Michael Trimarchi   USB storage clean...
802
  	result = usb_stor_CB_comdat(srb, us);
ceb4972a8   Vivek Gautam   usb: common: Weed...
803
804
805
  	debug("command / Data returned %d, status %lX
  ",
  	      result, us->pusb_dev->status);
affae2bff   wdenk   Initial revision
806
  	/* if this is an CBI Protocol, get IRQ */
a0cb3fc31   Michael Trimarchi   USB storage clean...
807
808
  	if (us->protocol == US_PR_CBI) {
  		status = usb_stor_CBI_get_status(srb, us);
affae2bff   wdenk   Initial revision
809
  		/* if the status is error, report it */
a0cb3fc31   Michael Trimarchi   USB storage clean...
810
  		if (status == USB_STOR_TRANSPORT_ERROR) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
811
812
  			debug(" USB CBI Command Error
  ");
affae2bff   wdenk   Initial revision
813
814
  			return status;
  		}
a0cb3fc31   Michael Trimarchi   USB storage clean...
815
816
817
818
819
  		srb->sense_buf[12] = (unsigned char)(us->ip_data >> 8);
  		srb->sense_buf[13] = (unsigned char)(us->ip_data & 0xff);
  		if (!us->ip_data) {
  			/* if the status is good, report it */
  			if (status == USB_STOR_TRANSPORT_GOOD) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
820
821
  				debug(" USB CBI Command Good
  ");
affae2bff   wdenk   Initial revision
822
823
824
825
826
827
  				return status;
  			}
  		}
  	}
  	/* do we have to issue an auto request? */
  	/* HERE we have to check the result */
a0cb3fc31   Michael Trimarchi   USB storage clean...
828
  	if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
829
830
  		debug("ERROR %lX
  ", us->pusb_dev->status);
affae2bff   wdenk   Initial revision
831
832
833
  		us->transport_reset(us);
  		return USB_STOR_TRANSPORT_ERROR;
  	}
a0cb3fc31   Michael Trimarchi   USB storage clean...
834
835
836
837
  	if ((us->protocol == US_PR_CBI) &&
  	    ((srb->cmd[0] == SCSI_REQ_SENSE) ||
  	    (srb->cmd[0] == SCSI_INQUIRY))) {
  		/* do not issue an autorequest after request sense */
ceb4972a8   Vivek Gautam   usb: common: Weed...
838
839
  		debug("No auto request and good
  ");
affae2bff   wdenk   Initial revision
840
841
842
  		return USB_STOR_TRANSPORT_GOOD;
  	}
  	/* issue an request_sense */
a0cb3fc31   Michael Trimarchi   USB storage clean...
843
844
845
846
847
  	memset(&psrb->cmd[0], 0, 12);
  	psrb->cmd[0] = SCSI_REQ_SENSE;
  	psrb->cmd[1] = srb->lun << 5;
  	psrb->cmd[4] = 18;
  	psrb->datalen = 18;
d0ff51ba5   Wolfgang Denk   Code cleanup: fix...
848
  	psrb->pdata = &srb->sense_buf[0];
a0cb3fc31   Michael Trimarchi   USB storage clean...
849
  	psrb->cmdlen = 12;
affae2bff   wdenk   Initial revision
850
  	/* issue the command */
a0cb3fc31   Michael Trimarchi   USB storage clean...
851
  	result = usb_stor_CB_comdat(psrb, us);
ceb4972a8   Vivek Gautam   usb: common: Weed...
852
853
  	debug("auto request returned %d
  ", result);
affae2bff   wdenk   Initial revision
854
  	/* if this is an CBI Protocol, get IRQ */
a0cb3fc31   Michael Trimarchi   USB storage clean...
855
856
857
858
  	if (us->protocol == US_PR_CBI)
  		status = usb_stor_CBI_get_status(psrb, us);
  
  	if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
859
860
861
  		debug(" AUTO REQUEST ERROR %ld
  ",
  		      us->pusb_dev->status);
affae2bff   wdenk   Initial revision
862
863
  		return USB_STOR_TRANSPORT_ERROR;
  	}
ceb4972a8   Vivek Gautam   usb: common: Weed...
864
865
866
867
  	debug("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X
  ",
  	      srb->sense_buf[0], srb->sense_buf[2],
  	      srb->sense_buf[12], srb->sense_buf[13]);
affae2bff   wdenk   Initial revision
868
  	/* Check the auto request result */
a0cb3fc31   Michael Trimarchi   USB storage clean...
869
870
871
872
  	if ((srb->sense_buf[2] == 0) &&
  	    (srb->sense_buf[12] == 0) &&
  	    (srb->sense_buf[13] == 0)) {
  		/* ok, no sense */
affae2bff   wdenk   Initial revision
873
  		return USB_STOR_TRANSPORT_GOOD;
a0cb3fc31   Michael Trimarchi   USB storage clean...
874
  	}
affae2bff   wdenk   Initial revision
875
  	/* Check the auto request result */
a0cb3fc31   Michael Trimarchi   USB storage clean...
876
877
878
  	switch (srb->sense_buf[2]) {
  	case 0x01:
  		/* Recovered Error */
149dded2b   wdenk   * Add support for...
879
  		return USB_STOR_TRANSPORT_GOOD;
80885a9d5   wdenk   * Patch by Markus...
880
  		break;
a0cb3fc31   Michael Trimarchi   USB storage clean...
881
882
883
884
885
886
887
888
  	case 0x02:
  		/* Not Ready */
  		if (notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
  			printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
  			       " 0x%02X (NOT READY)
  ", srb->cmd[0],
  				srb->sense_buf[0], srb->sense_buf[2],
  				srb->sense_buf[12], srb->sense_buf[13]);
149dded2b   wdenk   * Add support for...
889
890
  			return USB_STOR_TRANSPORT_FAILED;
  		} else {
5b84dd67c   Mike Frysinger   usb: replace wait...
891
  			mdelay(100);
149dded2b   wdenk   * Add support for...
892
893
894
895
  			goto do_retry;
  		}
  		break;
  	default:
a0cb3fc31   Michael Trimarchi   USB storage clean...
896
897
898
899
900
901
  		if (retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
  			printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
  			       " 0x%02X
  ", srb->cmd[0], srb->sense_buf[0],
  				srb->sense_buf[2], srb->sense_buf[12],
  				srb->sense_buf[13]);
149dded2b   wdenk   * Add support for...
902
  			return USB_STOR_TRANSPORT_FAILED;
a0cb3fc31   Michael Trimarchi   USB storage clean...
903
  		} else
149dded2b   wdenk   * Add support for...
904
  			goto do_retry;
149dded2b   wdenk   * Add support for...
905
  		break;
affae2bff   wdenk   Initial revision
906
907
908
  	}
  	return USB_STOR_TRANSPORT_FAILED;
  }
a0cb3fc31   Michael Trimarchi   USB storage clean...
909
  static int usb_inquiry(ccb *srb, struct us_data *ss)
affae2bff   wdenk   Initial revision
910
  {
a0cb3fc31   Michael Trimarchi   USB storage clean...
911
912
  	int retry, i;
  	retry = 5;
affae2bff   wdenk   Initial revision
913
  	do {
a0cb3fc31   Michael Trimarchi   USB storage clean...
914
915
  		memset(&srb->cmd[0], 0, 12);
  		srb->cmd[0] = SCSI_INQUIRY;
99e9ed1f4   Ludovic Courtès   usb: Add support ...
916
  		srb->cmd[1] = srb->lun << 5;
a0cb3fc31   Michael Trimarchi   USB storage clean...
917
918
919
920
  		srb->cmd[4] = 36;
  		srb->datalen = 36;
  		srb->cmdlen = 12;
  		i = ss->transport(srb, ss);
ceb4972a8   Vivek Gautam   usb: common: Weed...
921
922
  		debug("inquiry returns %d
  ", i);
a0cb3fc31   Michael Trimarchi   USB storage clean...
923
  		if (i == 0)
affae2bff   wdenk   Initial revision
924
  			break;
fac71cc49   Kim B. Heino   USB storage probe
925
  	} while (--retry);
149dded2b   wdenk   * Add support for...
926

a0cb3fc31   Michael Trimarchi   USB storage clean...
927
  	if (!retry) {
affae2bff   wdenk   Initial revision
928
929
930
931
932
933
  		printf("error in inquiry
  ");
  		return -1;
  	}
  	return 0;
  }
a0cb3fc31   Michael Trimarchi   USB storage clean...
934
  static int usb_request_sense(ccb *srb, struct us_data *ss)
affae2bff   wdenk   Initial revision
935
936
  {
  	char *ptr;
80885a9d5   wdenk   * Patch by Markus...
937

a0cb3fc31   Michael Trimarchi   USB storage clean...
938
939
940
  	ptr = (char *)srb->pdata;
  	memset(&srb->cmd[0], 0, 12);
  	srb->cmd[0] = SCSI_REQ_SENSE;
99e9ed1f4   Ludovic Courtès   usb: Add support ...
941
  	srb->cmd[1] = srb->lun << 5;
a0cb3fc31   Michael Trimarchi   USB storage clean...
942
943
  	srb->cmd[4] = 18;
  	srb->datalen = 18;
d0ff51ba5   Wolfgang Denk   Code cleanup: fix...
944
  	srb->pdata = &srb->sense_buf[0];
a0cb3fc31   Michael Trimarchi   USB storage clean...
945
946
  	srb->cmdlen = 12;
  	ss->transport(srb, ss);
ceb4972a8   Vivek Gautam   usb: common: Weed...
947
948
949
950
  	debug("Request Sense returned %02X %02X %02X
  ",
  	      srb->sense_buf[2], srb->sense_buf[12],
  	      srb->sense_buf[13]);
a0cb3fc31   Michael Trimarchi   USB storage clean...
951
  	srb->pdata = (uchar *)ptr;
affae2bff   wdenk   Initial revision
952
953
  	return 0;
  }
a0cb3fc31   Michael Trimarchi   USB storage clean...
954
  static int usb_test_unit_ready(ccb *srb, struct us_data *ss)
affae2bff   wdenk   Initial revision
955
  {
9c998aa83   Wolfgang Denk   Fix low-level OHC...
956
  	int retries = 10;
149dded2b   wdenk   * Add support for...
957

affae2bff   wdenk   Initial revision
958
  	do {
a0cb3fc31   Michael Trimarchi   USB storage clean...
959
960
  		memset(&srb->cmd[0], 0, 12);
  		srb->cmd[0] = SCSI_TST_U_RDY;
99e9ed1f4   Ludovic Courtès   usb: Add support ...
961
  		srb->cmd[1] = srb->lun << 5;
a0cb3fc31   Michael Trimarchi   USB storage clean...
962
963
  		srb->datalen = 0;
  		srb->cmdlen = 12;
3e8581bb9   Benoît Thébaudeau   usb_stor_BBB_tran...
964
965
  		if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) {
  			ss->flags |= USB_READY;
affae2bff   wdenk   Initial revision
966
  			return 0;
3e8581bb9   Benoît Thébaudeau   usb_stor_BBB_tran...
967
  		}
a0cb3fc31   Michael Trimarchi   USB storage clean...
968
  		usb_request_sense(srb, ss);
8b57e2f08   Vincent Palatin   usb: properly det...
969
970
971
972
973
974
975
976
977
978
  		/*
  		 * Check the Key Code Qualifier, if it matches
  		 * "Not Ready - medium not present"
  		 * (the sense Key equals 0x2 and the ASC is 0x3a)
  		 * return immediately as the medium being absent won't change
  		 * unless there is a user action.
  		 */
  		if ((srb->sense_buf[2] == 0x02) &&
  		    (srb->sense_buf[12] == 0x3a))
  			return -1;
5b84dd67c   Mike Frysinger   usb: replace wait...
979
  		mdelay(100);
a0cb3fc31   Michael Trimarchi   USB storage clean...
980
  	} while (retries--);
149dded2b   wdenk   * Add support for...
981

affae2bff   wdenk   Initial revision
982
983
  	return -1;
  }
a0cb3fc31   Michael Trimarchi   USB storage clean...
984
  static int usb_read_capacity(ccb *srb, struct us_data *ss)
affae2bff   wdenk   Initial revision
985
986
  {
  	int retry;
a0cb3fc31   Michael Trimarchi   USB storage clean...
987
988
  	/* XXX retries */
  	retry = 3;
affae2bff   wdenk   Initial revision
989
  	do {
a0cb3fc31   Michael Trimarchi   USB storage clean...
990
991
  		memset(&srb->cmd[0], 0, 12);
  		srb->cmd[0] = SCSI_RD_CAPAC;
99e9ed1f4   Ludovic Courtès   usb: Add support ...
992
  		srb->cmd[1] = srb->lun << 5;
a0cb3fc31   Michael Trimarchi   USB storage clean...
993
994
995
  		srb->datalen = 8;
  		srb->cmdlen = 12;
  		if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
affae2bff   wdenk   Initial revision
996
  			return 0;
a0cb3fc31   Michael Trimarchi   USB storage clean...
997
  	} while (retry--);
149dded2b   wdenk   * Add support for...
998

affae2bff   wdenk   Initial revision
999
1000
  	return -1;
  }
a0cb3fc31   Michael Trimarchi   USB storage clean...
1001
1002
  static int usb_read_10(ccb *srb, struct us_data *ss, unsigned long start,
  		       unsigned short blocks)
affae2bff   wdenk   Initial revision
1003
  {
a0cb3fc31   Michael Trimarchi   USB storage clean...
1004
1005
  	memset(&srb->cmd[0], 0, 12);
  	srb->cmd[0] = SCSI_READ10;
99e9ed1f4   Ludovic Courtès   usb: Add support ...
1006
  	srb->cmd[1] = srb->lun << 5;
a0cb3fc31   Michael Trimarchi   USB storage clean...
1007
1008
1009
1010
1011
1012
1013
  	srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
  	srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
  	srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
  	srb->cmd[5] = ((unsigned char) (start)) & 0xff;
  	srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
  	srb->cmd[8] = (unsigned char) blocks & 0xff;
  	srb->cmdlen = 12;
ceb4972a8   Vivek Gautam   usb: common: Weed...
1014
1015
  	debug("read10: start %lx blocks %x
  ", start, blocks);
a0cb3fc31   Michael Trimarchi   USB storage clean...
1016
  	return ss->transport(srb, ss);
affae2bff   wdenk   Initial revision
1017
  }
127e10842   Mahavir Jain   usb: write comman...
1018
1019
1020
1021
1022
  static int usb_write_10(ccb *srb, struct us_data *ss, unsigned long start,
  			unsigned short blocks)
  {
  	memset(&srb->cmd[0], 0, 12);
  	srb->cmd[0] = SCSI_WRITE10;
99e9ed1f4   Ludovic Courtès   usb: Add support ...
1023
  	srb->cmd[1] = srb->lun << 5;
127e10842   Mahavir Jain   usb: write comman...
1024
1025
1026
1027
1028
1029
1030
  	srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
  	srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
  	srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
  	srb->cmd[5] = ((unsigned char) (start)) & 0xff;
  	srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
  	srb->cmd[8] = (unsigned char) blocks & 0xff;
  	srb->cmdlen = 12;
ceb4972a8   Vivek Gautam   usb: common: Weed...
1031
1032
  	debug("write10: start %lx blocks %x
  ", start, blocks);
127e10842   Mahavir Jain   usb: write comman...
1033
1034
  	return ss->transport(srb, ss);
  }
affae2bff   wdenk   Initial revision
1035

ddde6b7cf   Bartlomiej Sieka   Add a fix for a b...
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
  #ifdef CONFIG_USB_BIN_FIXUP
  /*
   * Some USB storage devices queried for SCSI identification data respond with
   * binary strings, which if output to the console freeze the terminal. The
   * workaround is to modify the vendor and product strings read from such
   * device with proper values (as reported by 'usb info').
   *
   * Vendor and product length limits are taken from the definition of
   * block_dev_desc_t in include/part.h.
   */
  static void usb_bin_fixup(struct usb_device_descriptor descriptor,
  				unsigned char vendor[],
  				unsigned char product[]) {
  	const unsigned char max_vendor_len = 40;
  	const unsigned char max_product_len = 20;
  	if (descriptor.idVendor == 0x0424 && descriptor.idProduct == 0x223a) {
a0cb3fc31   Michael Trimarchi   USB storage clean...
1052
1053
1054
  		strncpy((char *)vendor, "SMSC", max_vendor_len);
  		strncpy((char *)product, "Flash Media Cntrller",
  			max_product_len);
ddde6b7cf   Bartlomiej Sieka   Add a fix for a b...
1055
1056
1057
  	}
  }
  #endif /* CONFIG_USB_BIN_FIXUP */
ff8fef566   Sascha Silbe   Fix block device ...
1058
  unsigned long usb_stor_read(int device, lbaint_t blknr,
e81e79ede   Gabe Black   usb: Support the ...
1059
  			    lbaint_t blkcnt, void *buffer)
affae2bff   wdenk   Initial revision
1060
  {
e81e79ede   Gabe Black   usb: Support the ...
1061
1062
  	lbaint_t start, blks;
  	uintptr_t buf_addr;
affae2bff   wdenk   Initial revision
1063
1064
  	unsigned short smallblks;
  	struct usb_device *dev;
5dd95cf93   Kyle Moffett   usb_storage: Fix ...
1065
  	struct us_data *ss;
84073b6f3   Simon Glass   dm: usb: Simply d...
1066
  	int retry;
f8d813e34   wdenk   * Fix SDRAM timin...
1067
1068
1069
1070
1071
1072
  	ccb *srb = &usb_ccb;
  
  	if (blkcnt == 0)
  		return 0;
  
  	device &= 0xff;
a0cb3fc31   Michael Trimarchi   USB storage clean...
1073
  	/* Setup  device */
84073b6f3   Simon Glass   dm: usb: Simply d...
1074
1075
1076
1077
1078
1079
1080
1081
  	debug("
  usb_read: dev %d
  ", device);
  	dev = usb_dev_desc[device].priv;
  	if (!dev) {
  		debug("%s: No device
  ", __func__);
  		return 0;
affae2bff   wdenk   Initial revision
1082
  	}
5dd95cf93   Kyle Moffett   usb_storage: Fix ...
1083
  	ss = (struct us_data *)dev->privptr;
affae2bff   wdenk   Initial revision
1084
1085
  
  	usb_disable_asynch(1); /* asynch transfer not allowed */
a0cb3fc31   Michael Trimarchi   USB storage clean...
1086
  	srb->lun = usb_dev_desc[device].lun;
f65708713   Sergey Temerkhanov   usb_storage:Fix U...
1087
  	buf_addr = (uintptr_t)buffer;
a0cb3fc31   Michael Trimarchi   USB storage clean...
1088
1089
  	start = blknr;
  	blks = blkcnt;
a0cb3fc31   Michael Trimarchi   USB storage clean...
1090

ceb4972a8   Vivek Gautam   usb: common: Weed...
1091
1092
  	debug("
  usb_read: dev %d startblk " LBAF ", blccnt " LBAF
4fd074de0   Simon Glass   usb: Use correct ...
1093
1094
  	      " buffer %" PRIxPTR "
  ", device, start, blks, buf_addr);
a0cb3fc31   Michael Trimarchi   USB storage clean...
1095

affae2bff   wdenk   Initial revision
1096
  	do {
a0cb3fc31   Michael Trimarchi   USB storage clean...
1097
1098
1099
  		/* XXX need some comment here */
  		retry = 2;
  		srb->pdata = (unsigned char *)buf_addr;
4bee5c83e   Benoît Thébaudeau   usb_storage: Remo...
1100
1101
  		if (blks > USB_MAX_XFER_BLK)
  			smallblks = USB_MAX_XFER_BLK;
a0cb3fc31   Michael Trimarchi   USB storage clean...
1102
1103
  		else
  			smallblks = (unsigned short) blks;
affae2bff   wdenk   Initial revision
1104
  retry_it:
4bee5c83e   Benoît Thébaudeau   usb_storage: Remo...
1105
  		if (smallblks == USB_MAX_XFER_BLK)
affae2bff   wdenk   Initial revision
1106
  			usb_show_progress();
a0cb3fc31   Michael Trimarchi   USB storage clean...
1107
1108
  		srb->datalen = usb_dev_desc[device].blksz * smallblks;
  		srb->pdata = (unsigned char *)buf_addr;
5dd95cf93   Kyle Moffett   usb_storage: Fix ...
1109
  		if (usb_read_10(srb, ss, start, smallblks)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
1110
1111
  			debug("Read ERROR
  ");
5dd95cf93   Kyle Moffett   usb_storage: Fix ...
1112
  			usb_request_sense(srb, ss);
a0cb3fc31   Michael Trimarchi   USB storage clean...
1113
  			if (retry--)
affae2bff   wdenk   Initial revision
1114
  				goto retry_it;
a0cb3fc31   Michael Trimarchi   USB storage clean...
1115
  			blkcnt -= blks;
affae2bff   wdenk   Initial revision
1116
1117
  			break;
  		}
a0cb3fc31   Michael Trimarchi   USB storage clean...
1118
1119
1120
1121
  		start += smallblks;
  		blks -= smallblks;
  		buf_addr += srb->datalen;
  	} while (blks != 0);
3e8581bb9   Benoît Thébaudeau   usb_stor_BBB_tran...
1122
  	ss->flags &= ~USB_READY;
a0cb3fc31   Michael Trimarchi   USB storage clean...
1123

ceb4972a8   Vivek Gautam   usb: common: Weed...
1124
  	debug("usb_read: end startblk " LBAF
4fd074de0   Simon Glass   usb: Use correct ...
1125
1126
  	      ", blccnt %x buffer %" PRIxPTR "
  ",
ceb4972a8   Vivek Gautam   usb: common: Weed...
1127
  	      start, smallblks, buf_addr);
a0cb3fc31   Michael Trimarchi   USB storage clean...
1128

affae2bff   wdenk   Initial revision
1129
  	usb_disable_asynch(0); /* asynch transfer allowed */
4bee5c83e   Benoît Thébaudeau   usb_storage: Remo...
1130
  	if (blkcnt >= USB_MAX_XFER_BLK)
226fa9bb9   Wolfgang Denk   usb_storage.c: ch...
1131
1132
  		debug("
  ");
a0cb3fc31   Michael Trimarchi   USB storage clean...
1133
  	return blkcnt;
affae2bff   wdenk   Initial revision
1134
  }
ff8fef566   Sascha Silbe   Fix block device ...
1135
  unsigned long usb_stor_write(int device, lbaint_t blknr,
e81e79ede   Gabe Black   usb: Support the ...
1136
  				lbaint_t blkcnt, const void *buffer)
127e10842   Mahavir Jain   usb: write comman...
1137
  {
e81e79ede   Gabe Black   usb: Support the ...
1138
1139
  	lbaint_t start, blks;
  	uintptr_t buf_addr;
127e10842   Mahavir Jain   usb: write comman...
1140
1141
  	unsigned short smallblks;
  	struct usb_device *dev;
5dd95cf93   Kyle Moffett   usb_storage: Fix ...
1142
  	struct us_data *ss;
84073b6f3   Simon Glass   dm: usb: Simply d...
1143
  	int retry;
127e10842   Mahavir Jain   usb: write comman...
1144
1145
1146
1147
1148
1149
1150
  	ccb *srb = &usb_ccb;
  
  	if (blkcnt == 0)
  		return 0;
  
  	device &= 0xff;
  	/* Setup  device */
84073b6f3   Simon Glass   dm: usb: Simply d...
1151
1152
1153
1154
1155
1156
  	debug("
  usb_write: dev %d
  ", device);
  	dev = usb_dev_desc[device].priv;
  	if (!dev)
  		return 0;
5dd95cf93   Kyle Moffett   usb_storage: Fix ...
1157
  	ss = (struct us_data *)dev->privptr;
127e10842   Mahavir Jain   usb: write comman...
1158
1159
1160
1161
  
  	usb_disable_asynch(1); /* asynch transfer not allowed */
  
  	srb->lun = usb_dev_desc[device].lun;
f65708713   Sergey Temerkhanov   usb_storage:Fix U...
1162
  	buf_addr = (uintptr_t)buffer;
127e10842   Mahavir Jain   usb: write comman...
1163
1164
  	start = blknr;
  	blks = blkcnt;
127e10842   Mahavir Jain   usb: write comman...
1165

ceb4972a8   Vivek Gautam   usb: common: Weed...
1166
1167
  	debug("
  usb_write: dev %d startblk " LBAF ", blccnt " LBAF
4fd074de0   Simon Glass   usb: Use correct ...
1168
1169
  	      " buffer %" PRIxPTR "
  ", device, start, blks, buf_addr);
127e10842   Mahavir Jain   usb: write comman...
1170
1171
1172
1173
1174
1175
1176
  
  	do {
  		/* If write fails retry for max retry count else
  		 * return with number of blocks written successfully.
  		 */
  		retry = 2;
  		srb->pdata = (unsigned char *)buf_addr;
4bee5c83e   Benoît Thébaudeau   usb_storage: Remo...
1177
1178
  		if (blks > USB_MAX_XFER_BLK)
  			smallblks = USB_MAX_XFER_BLK;
127e10842   Mahavir Jain   usb: write comman...
1179
1180
1181
  		else
  			smallblks = (unsigned short) blks;
  retry_it:
4bee5c83e   Benoît Thébaudeau   usb_storage: Remo...
1182
  		if (smallblks == USB_MAX_XFER_BLK)
127e10842   Mahavir Jain   usb: write comman...
1183
1184
1185
  			usb_show_progress();
  		srb->datalen = usb_dev_desc[device].blksz * smallblks;
  		srb->pdata = (unsigned char *)buf_addr;
5dd95cf93   Kyle Moffett   usb_storage: Fix ...
1186
  		if (usb_write_10(srb, ss, start, smallblks)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
1187
1188
  			debug("Write ERROR
  ");
5dd95cf93   Kyle Moffett   usb_storage: Fix ...
1189
  			usb_request_sense(srb, ss);
127e10842   Mahavir Jain   usb: write comman...
1190
1191
1192
1193
1194
1195
1196
1197
1198
  			if (retry--)
  				goto retry_it;
  			blkcnt -= blks;
  			break;
  		}
  		start += smallblks;
  		blks -= smallblks;
  		buf_addr += srb->datalen;
  	} while (blks != 0);
3e8581bb9   Benoît Thébaudeau   usb_stor_BBB_tran...
1199
  	ss->flags &= ~USB_READY;
127e10842   Mahavir Jain   usb: write comman...
1200

4fd074de0   Simon Glass   usb: Use correct ...
1201
1202
1203
  	debug("usb_write: end startblk " LBAF ", blccnt %x buffer %"
  	      PRIxPTR "
  ", start, smallblks, buf_addr);
127e10842   Mahavir Jain   usb: write comman...
1204
1205
  
  	usb_disable_asynch(0); /* asynch transfer allowed */
4bee5c83e   Benoît Thébaudeau   usb_storage: Remo...
1206
  	if (blkcnt >= USB_MAX_XFER_BLK)
226fa9bb9   Wolfgang Denk   usb_storage.c: ch...
1207
1208
  		debug("
  ");
127e10842   Mahavir Jain   usb: write comman...
1209
1210
1211
  	return blkcnt;
  
  }
affae2bff   wdenk   Initial revision
1212
1213
  
  /* Probe to see if a new device is actually a Storage device */
a0cb3fc31   Michael Trimarchi   USB storage clean...
1214
1215
  int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
  		      struct us_data *ss)
affae2bff   wdenk   Initial revision
1216
  {
8f8bd565f   Tom Rix   USB Consolidate d...
1217
  	struct usb_interface *iface;
affae2bff   wdenk   Initial revision
1218
  	int i;
605bd75af   Vivek Gautam   USB: Some cleanup...
1219
  	struct usb_endpoint_descriptor *ep_desc;
affae2bff   wdenk   Initial revision
1220
1221
1222
1223
  	unsigned int flags = 0;
  
  	int protocol = 0;
  	int subclass = 0;
affae2bff   wdenk   Initial revision
1224
1225
1226
1227
1228
  	/* let's examine the device now */
  	iface = &dev->config.if_desc[ifnum];
  
  #if 0
  	/* this is the place to patch some storage devices */
ceb4972a8   Vivek Gautam   usb: common: Weed...
1229
1230
  	debug("iVendor %X iProduct %X
  ", dev->descriptor.idVendor,
a0cb3fc31   Michael Trimarchi   USB storage clean...
1231
1232
1233
1234
  			dev->descriptor.idProduct);
  
  	if ((dev->descriptor.idVendor) == 0x066b &&
  	    (dev->descriptor.idProduct) == 0x0103) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
1235
1236
  		debug("patched for E-USB
  ");
affae2bff   wdenk   Initial revision
1237
1238
1239
1240
1241
1242
  		protocol = US_PR_CB;
  		subclass = US_SC_UFI;	    /* an assumption */
  	}
  #endif
  
  	if (dev->descriptor.bDeviceClass != 0 ||
8f8bd565f   Tom Rix   USB Consolidate d...
1243
1244
1245
  			iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
  			iface->desc.bInterfaceSubClass < US_SC_MIN ||
  			iface->desc.bInterfaceSubClass > US_SC_MAX) {
1d5827a12   Simon Glass   dm: usb: Fix type...
1246
1247
  		debug("Not mass storage
  ");
affae2bff   wdenk   Initial revision
1248
1249
1250
  		/* if it's not a mass storage, we go no further */
  		return 0;
  	}
9c998aa83   Wolfgang Denk   Fix low-level OHC...
1251
  	memset(ss, 0, sizeof(struct us_data));
affae2bff   wdenk   Initial revision
1252
  	/* At this point, we know we've got a live one */
ceb4972a8   Vivek Gautam   usb: common: Weed...
1253
1254
1255
1256
  	debug("
  
  USB Mass Storage device detected
  ");
affae2bff   wdenk   Initial revision
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
  
  	/* Initialize the us_data structure with some useful info */
  	ss->flags = flags;
  	ss->ifnum = ifnum;
  	ss->pusb_dev = dev;
  	ss->attention_done = 0;
  
  	/* If the device has subclass and protocol, then use that.  Otherwise,
  	 * take data from the specific interface.
  	 */
  	if (subclass) {
  		ss->subclass = subclass;
  		ss->protocol = protocol;
  	} else {
8f8bd565f   Tom Rix   USB Consolidate d...
1271
1272
  		ss->subclass = iface->desc.bInterfaceSubClass;
  		ss->protocol = iface->desc.bInterfaceProtocol;
affae2bff   wdenk   Initial revision
1273
1274
1275
  	}
  
  	/* set the handler pointers based on the protocol */
ceb4972a8   Vivek Gautam   usb: common: Weed...
1276
  	debug("Transport: ");
affae2bff   wdenk   Initial revision
1277
1278
  	switch (ss->protocol) {
  	case US_PR_CB:
ceb4972a8   Vivek Gautam   usb: common: Weed...
1279
1280
  		debug("Control/Bulk
  ");
affae2bff   wdenk   Initial revision
1281
1282
1283
1284
1285
  		ss->transport = usb_stor_CB_transport;
  		ss->transport_reset = usb_stor_CB_reset;
  		break;
  
  	case US_PR_CBI:
ceb4972a8   Vivek Gautam   usb: common: Weed...
1286
1287
  		debug("Control/Bulk/Interrupt
  ");
affae2bff   wdenk   Initial revision
1288
1289
1290
  		ss->transport = usb_stor_CB_transport;
  		ss->transport_reset = usb_stor_CB_reset;
  		break;
149dded2b   wdenk   * Add support for...
1291
  	case US_PR_BULK:
ceb4972a8   Vivek Gautam   usb: common: Weed...
1292
1293
  		debug("Bulk/Bulk/Bulk
  ");
149dded2b   wdenk   * Add support for...
1294
1295
1296
  		ss->transport = usb_stor_BBB_transport;
  		ss->transport_reset = usb_stor_BBB_reset;
  		break;
affae2bff   wdenk   Initial revision
1297
  	default:
80885a9d5   wdenk   * Patch by Markus...
1298
1299
  		printf("USB Storage Transport unknown / not yet implemented
  ");
affae2bff   wdenk   Initial revision
1300
1301
1302
1303
1304
1305
1306
1307
1308
  		return 0;
  		break;
  	}
  
  	/*
  	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
  	 * An optional interrupt is OK (necessary for CBI protocol).
  	 * We will ignore any others.
  	 */
8f8bd565f   Tom Rix   USB Consolidate d...
1309
  	for (i = 0; i < iface->desc.bNumEndpoints; i++) {
605bd75af   Vivek Gautam   USB: Some cleanup...
1310
  		ep_desc = &iface->ep_desc[i];
affae2bff   wdenk   Initial revision
1311
  		/* is it an BULK endpoint? */
605bd75af   Vivek Gautam   USB: Some cleanup...
1312
  		if ((ep_desc->bmAttributes &
a0cb3fc31   Michael Trimarchi   USB storage clean...
1313
  		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
605bd75af   Vivek Gautam   USB: Some cleanup...
1314
1315
1316
  			if (ep_desc->bEndpointAddress & USB_DIR_IN)
  				ss->ep_in = ep_desc->bEndpointAddress &
  						USB_ENDPOINT_NUMBER_MASK;
affae2bff   wdenk   Initial revision
1317
  			else
a0cb3fc31   Michael Trimarchi   USB storage clean...
1318
  				ss->ep_out =
605bd75af   Vivek Gautam   USB: Some cleanup...
1319
  					ep_desc->bEndpointAddress &
affae2bff   wdenk   Initial revision
1320
1321
1322
1323
  					USB_ENDPOINT_NUMBER_MASK;
  		}
  
  		/* is it an interrupt endpoint? */
605bd75af   Vivek Gautam   USB: Some cleanup...
1324
1325
1326
1327
1328
  		if ((ep_desc->bmAttributes &
  		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
  			ss->ep_int = ep_desc->bEndpointAddress &
  						USB_ENDPOINT_NUMBER_MASK;
  			ss->irqinterval = ep_desc->bInterval;
affae2bff   wdenk   Initial revision
1329
1330
  		}
  	}
ceb4972a8   Vivek Gautam   usb: common: Weed...
1331
1332
1333
  	debug("Endpoints In %d Out %d Int %d
  ",
  	      ss->ep_in, ss->ep_out, ss->ep_int);
affae2bff   wdenk   Initial revision
1334
1335
  
  	/* Do some basic sanity checks, and bail if we find a problem */
8f8bd565f   Tom Rix   USB Consolidate d...
1336
  	if (usb_set_interface(dev, iface->desc.bInterfaceNumber, 0) ||
affae2bff   wdenk   Initial revision
1337
1338
  	    !ss->ep_in || !ss->ep_out ||
  	    (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
ceb4972a8   Vivek Gautam   usb: common: Weed...
1339
1340
  		debug("Problems with device
  ");
affae2bff   wdenk   Initial revision
1341
1342
1343
  		return 0;
  	}
  	/* set class specific stuff */
149dded2b   wdenk   * Add support for...
1344
1345
  	/* We only handle certain protocols.  Currently, these are
  	 * the only ones.
80885a9d5   wdenk   * Patch by Markus...
1346
  	 * The SFF8070 accepts the requests used in u-boot
affae2bff   wdenk   Initial revision
1347
  	 */
80885a9d5   wdenk   * Patch by Markus...
1348
1349
  	if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI &&
  	    ss->subclass != US_SC_8070) {
a0cb3fc31   Michael Trimarchi   USB storage clean...
1350
1351
  		printf("Sorry, protocol %d not yet supported.
  ", ss->subclass);
affae2bff   wdenk   Initial revision
1352
1353
  		return 0;
  	}
a0cb3fc31   Michael Trimarchi   USB storage clean...
1354
1355
1356
1357
  	if (ss->ep_int) {
  		/* we had found an interrupt endpoint, prepare irq pipe
  		 * set up the IRQ pipe and handler
  		 */
affae2bff   wdenk   Initial revision
1358
1359
1360
  		ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255;
  		ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
  		ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
a0cb3fc31   Michael Trimarchi   USB storage clean...
1361
  		dev->irq_handle = usb_stor_irq;
affae2bff   wdenk   Initial revision
1362
  	}
a0cb3fc31   Michael Trimarchi   USB storage clean...
1363
  	dev->privptr = (void *)ss;
affae2bff   wdenk   Initial revision
1364
1365
  	return 1;
  }
a0cb3fc31   Michael Trimarchi   USB storage clean...
1366
1367
  int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
  		      block_dev_desc_t *dev_desc)
affae2bff   wdenk   Initial revision
1368
  {
a0cb3fc31   Michael Trimarchi   USB storage clean...
1369
  	unsigned char perq, modi;
f65708713   Sergey Temerkhanov   usb_storage:Fix U...
1370
1371
1372
  	ALLOC_CACHE_ALIGN_BUFFER(u32, cap, 2);
  	ALLOC_CACHE_ALIGN_BUFFER(u8, usb_stor_buf, 36);
  	u32 capacity, blksz;
9c998aa83   Wolfgang Denk   Fix low-level OHC...
1373
  	ccb *pccb = &usb_ccb;
9c998aa83   Wolfgang Denk   Fix low-level OHC...
1374
1375
1376
1377
  	pccb->pdata = usb_stor_buf;
  
  	dev_desc->target = dev->devnum;
  	pccb->lun = dev_desc->lun;
ceb4972a8   Vivek Gautam   usb: common: Weed...
1378
1379
  	debug(" address %d
  ", dev_desc->target);
affae2bff   wdenk   Initial revision
1380

1d5827a12   Simon Glass   dm: usb: Fix type...
1381
1382
1383
  	if (usb_inquiry(pccb, ss)) {
  		debug("%s: usb_inquiry() failed
  ", __func__);
affae2bff   wdenk   Initial revision
1384
  		return -1;
1d5827a12   Simon Glass   dm: usb: Fix type...
1385
  	}
095b8a379   Wolfgang Denk   Coding style cleanup
1386

9c998aa83   Wolfgang Denk   Fix low-level OHC...
1387
1388
  	perq = usb_stor_buf[0];
  	modi = usb_stor_buf[1];
a0cb3fc31   Michael Trimarchi   USB storage clean...
1389

6a559bbe2   Soeren Moch   usb_storage: blac...
1390
1391
1392
1393
1394
  	/*
  	 * Skip unknown devices (0x1f) and enclosure service devices (0x0d),
  	 * they would not respond to test_unit_ready .
  	 */
  	if (((perq & 0x1f) == 0x1f) || ((perq & 0x1f) == 0x0d)) {
1d5827a12   Simon Glass   dm: usb: Fix type...
1395
1396
  		debug("%s: unknown/unsupported device
  ", __func__);
a0cb3fc31   Michael Trimarchi   USB storage clean...
1397
  		return 0;
affae2bff   wdenk   Initial revision
1398
  	}
a0cb3fc31   Michael Trimarchi   USB storage clean...
1399
1400
  	if ((modi&0x80) == 0x80) {
  		/* drive is removable */
9c998aa83   Wolfgang Denk   Fix low-level OHC...
1401
  		dev_desc->removable = 1;
affae2bff   wdenk   Initial revision
1402
  	}
f65708713   Sergey Temerkhanov   usb_storage:Fix U...
1403
1404
1405
  	memcpy(dev_desc->vendor, (const void *)&usb_stor_buf[8], 8);
  	memcpy(dev_desc->product, (const void *)&usb_stor_buf[16], 16);
  	memcpy(dev_desc->revision, (const void *)&usb_stor_buf[32], 4);
9c998aa83   Wolfgang Denk   Fix low-level OHC...
1406
1407
1408
  	dev_desc->vendor[8] = 0;
  	dev_desc->product[16] = 0;
  	dev_desc->revision[4] = 0;
ddde6b7cf   Bartlomiej Sieka   Add a fix for a b...
1409
  #ifdef CONFIG_USB_BIN_FIXUP
a0cb3fc31   Michael Trimarchi   USB storage clean...
1410
1411
  	usb_bin_fixup(dev->descriptor, (uchar *)dev_desc->vendor,
  		      (uchar *)dev_desc->product);
ddde6b7cf   Bartlomiej Sieka   Add a fix for a b...
1412
  #endif /* CONFIG_USB_BIN_FIXUP */
ceb4972a8   Vivek Gautam   usb: common: Weed...
1413
1414
1415
  	debug("ISO Vers %X, Response Data %X
  ", usb_stor_buf[2],
  	      usb_stor_buf[3]);
a0cb3fc31   Michael Trimarchi   USB storage clean...
1416
1417
1418
1419
1420
1421
1422
1423
  	if (usb_test_unit_ready(pccb, ss)) {
  		printf("Device NOT ready
  "
  		       "   Request Sense returned %02X %02X %02X
  ",
  		       pccb->sense_buf[2], pccb->sense_buf[12],
  		       pccb->sense_buf[13]);
  		if (dev_desc->removable == 1) {
9c998aa83   Wolfgang Denk   Fix low-level OHC...
1424
  			dev_desc->type = perq;
affae2bff   wdenk   Initial revision
1425
1426
  			return 1;
  		}
a0cb3fc31   Michael Trimarchi   USB storage clean...
1427
  		return 0;
affae2bff   wdenk   Initial revision
1428
  	}
f65708713   Sergey Temerkhanov   usb_storage:Fix U...
1429
  	pccb->pdata = (unsigned char *)cap;
a0cb3fc31   Michael Trimarchi   USB storage clean...
1430
1431
  	memset(pccb->pdata, 0, 8);
  	if (usb_read_capacity(pccb, ss) != 0) {
affae2bff   wdenk   Initial revision
1432
1433
  		printf("READ_CAP ERROR
  ");
9c998aa83   Wolfgang Denk   Fix low-level OHC...
1434
1435
  		cap[0] = 2880;
  		cap[1] = 0x200;
affae2bff   wdenk   Initial revision
1436
  	}
3e8581bb9   Benoît Thébaudeau   usb_stor_BBB_tran...
1437
  	ss->flags &= ~USB_READY;
f65708713   Sergey Temerkhanov   usb_storage:Fix U...
1438
1439
  	debug("Read Capacity returns: 0x%08x, 0x%08x
  ", cap[0], cap[1]);
affae2bff   wdenk   Initial revision
1440
  #if 0
a0cb3fc31   Michael Trimarchi   USB storage clean...
1441
1442
  	if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */
  		cap[0] >>= 16;
f65708713   Sergey Temerkhanov   usb_storage:Fix U...
1443

c918261c6   Christian Eggers   USB: replace old ...
1444
1445
  	cap[0] = cpu_to_be32(cap[0]);
  	cap[1] = cpu_to_be32(cap[1]);
f65708713   Sergey Temerkhanov   usb_storage:Fix U...
1446
1447
1448
1449
  #endif
  
  	capacity = be32_to_cpu(cap[0]) + 1;
  	blksz = be32_to_cpu(cap[1]);
c918261c6   Christian Eggers   USB: replace old ...
1450

f65708713   Sergey Temerkhanov   usb_storage:Fix U...
1451
1452
1453
1454
  	debug("Capacity = 0x%08x, blocksz = 0x%08x
  ", capacity, blksz);
  	dev_desc->lba = capacity;
  	dev_desc->blksz = blksz;
0472fbfd3   Egbert Eich   part/dev_desc: Ad...
1455
  	dev_desc->log2blksz = LOG2(dev_desc->blksz);
9c998aa83   Wolfgang Denk   Fix low-level OHC...
1456
  	dev_desc->type = perq;
ceb4972a8   Vivek Gautam   usb: common: Weed...
1457
1458
1459
1460
  	debug(" address %d
  ", dev_desc->target);
  	debug("partype: %d
  ", dev_desc->part_type);
affae2bff   wdenk   Initial revision
1461
1462
  
  	init_part(dev_desc);
ceb4972a8   Vivek Gautam   usb: common: Weed...
1463
1464
  	debug("partype: %d
  ", dev_desc->part_type);
affae2bff   wdenk   Initial revision
1465
1466
  	return 1;
  }
acf277af6   Simon Glass   dm: usb: Convert ...
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
  
  #ifdef CONFIG_DM_USB
  
  static int usb_mass_storage_probe(struct udevice *dev)
  {
  	struct usb_device *udev = dev_get_parentdata(dev);
  	int ret;
  
  	usb_disable_asynch(1); /* asynch transfer not allowed */
  	ret = usb_stor_probe_device(udev);
  	usb_disable_asynch(0); /* asynch transfer allowed */
  
  	return ret;
  }
  
  static const struct udevice_id usb_mass_storage_ids[] = {
  	{ .compatible = "usb-mass-storage" },
  	{ }
  };
  
  U_BOOT_DRIVER(usb_mass_storage) = {
  	.name	= "usb_mass_storage",
  	.id	= UCLASS_MASS_STORAGE,
  	.of_match = usb_mass_storage_ids,
  	.probe = usb_mass_storage_probe,
  };
  
  UCLASS_DRIVER(usb_mass_storage) = {
  	.id		= UCLASS_MASS_STORAGE,
  	.name		= "usb_mass_storage",
  };
  
  static const struct usb_device_id mass_storage_id_table[] = {
  	{
  		.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
  		.bInterfaceClass = USB_CLASS_MASS_STORAGE
  	},
  	{ }		/* Terminating entry */
  };
  
  USB_DEVICE(usb_mass_storage, mass_storage_id_table);
  
  #endif