1 /* Driver for Freecom USB/IDE adaptor
2  *
3  * $Id: freecom.c,v 1.21 2001/12/29 03:47:33 mdharm Exp $
4  *
5  * Freecom v0.1:
6  *
7  * First release
8  *
9  * Current development and maintenance by:
10  *   (C) 2000 David Brown <usb-storage@davidb.org>
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by the
14  * Free Software Foundation; either version 2, or (at your option) any
15  * later version.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, write to the Free Software Foundation, Inc.,
24  * 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  * This driver was developed with information provided in FREECOM's USB
27  * Programmers Reference Guide.  For further information contact Freecom
28  * (http://www.freecom.de/)
29  */
30 
31 #include <linux/config.h>
32 #include "transport.h"
33 #include "protocol.h"
34 #include "usb.h"
35 #include "debug.h"
36 #include "freecom.h"
37 #include <linux/hdreg.h>
38 
39 #ifdef CONFIG_USB_STORAGE_DEBUG
40 static void pdump (void *, int);
41 #endif
42 
43 struct freecom_udata {
44         __u8    buffer[64];             /* Common command block. */
45 };
46 typedef struct freecom_udata *freecom_udata_t;
47 
48 /* All of the outgoing packets are 64 bytes long. */
49 struct freecom_cb_wrap {
50         __u8    Type;                   /* Command type. */
51         __u8    Timeout;                /* Timeout in seconds. */
52         __u8    Atapi[12];              /* An ATAPI packet. */
53         __u8    Filler[50];             /* Padding Data. */
54 };
55 
56 struct freecom_xfer_wrap {
57         __u8    Type;                   /* Command type. */
58         __u8    Timeout;                /* Timeout in seconds. */
59         __u32   Count;                  /* Number of bytes to transfer. */
60         __u8    Pad[58];
61 } __attribute__ ((packed));
62 
63 struct freecom_ide_out {
64         __u8    Type;                   /* Type + IDE register. */
65         __u8    Pad;
66         __u16   Value;                  /* Value to write. */
67         __u8    Pad2[60];
68 };
69 
70 struct freecom_ide_in {
71         __u8    Type;                   /* Type | IDE register. */
72         __u8    Pad[63];
73 };
74 
75 struct freecom_status {
76         __u8    Status;
77         __u8    Reason;
78         __u16   Count;
79         __u8    Pad[60];
80 };
81 
82 /* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide
83  * register. */
84 #define FCM_INT_STATUS		0x02 /* INDEX_STAT */
85 #define FCM_STATUS_BUSY		0x80
86 
87 /* These are the packet types.  The low bit indicates that this command
88  * should wait for an interrupt. */
89 #define FCM_PACKET_ATAPI	0x21
90 #define FCM_PACKET_STATUS	0x20
91 
92 /* Receive data from the IDE interface.  The ATAPI packet has already
93  * waited, so the data should be immediately available. */
94 #define FCM_PACKET_INPUT	0x81
95 
96 /* Send data to the IDE interface. */
97 #define FCM_PACKET_OUTPUT	0x01
98 
99 /* Write a value to an ide register.  Or the ide register to write after
100  * munging the address a bit. */
101 #define FCM_PACKET_IDE_WRITE	0x40
102 #define FCM_PACKET_IDE_READ	0xC0
103 
104 /* All packets (except for status) are 64 bytes long. */
105 #define FCM_PACKET_LENGTH	64
106 
107 /*
108  * Transfer an entire SCSI command's worth of data payload over the bulk
109  * pipe.
110  *
111  * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this
112  * function simply determines if we're going to use scatter-gather or not,
113  * and acts appropriately.  For now, it also re-interprets the error codes.
114  */
us_transfer_freecom(Scsi_Cmnd * srb,struct us_data * us,int transfer_amount)115 static void us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer_amount)
116 {
117 	int i;
118 	int result = -1;
119 	struct scatterlist *sg;
120 	unsigned int total_transferred = 0;
121 
122 	/* was someone foolish enough to request more data than available
123 	 * buffer space? */
124 	if (transfer_amount > srb->request_bufflen)
125 		transfer_amount = srb->request_bufflen;
126 
127 	/* are we scatter-gathering? */
128 	if (srb->use_sg) {
129 
130 		/* loop over all the scatter gather structures and
131 		 * make the appropriate requests for each, until done
132 		 */
133 		sg = (struct scatterlist *) srb->request_buffer;
134 		for (i = 0; i < srb->use_sg; i++) {
135 
136 			US_DEBUGP("transfer_amount: %d and total_transferred: %d\n", transfer_amount, total_transferred);
137 
138 			/* End this if we're done */
139 			if (transfer_amount == total_transferred)
140 				break;
141 
142 			/* transfer the lesser of the next buffer or the
143 			 * remaining data */
144 			if (transfer_amount - total_transferred >=
145 					sg[i].length) {
146 				result = usb_stor_transfer_partial(us,
147 						sg[i].address, sg[i].length);
148 				total_transferred += sg[i].length;
149 			} else {
150 				result = usb_stor_transfer_partial(us,
151 						sg[i].address,
152 						transfer_amount - total_transferred);
153 				total_transferred += transfer_amount - total_transferred;
154 			}
155 
156 			/* if we get an error, end the loop here */
157 			if (result)
158 				break;
159 		}
160 	}
161 	else
162 		/* no scatter-gather, just make the request */
163 		result = usb_stor_transfer_partial(us, srb->request_buffer,
164 					     transfer_amount);
165 
166 	/* return the result in the data structure itself */
167 	srb->result = result;
168 }
169 
170 #if 0
171 /* Write a value to an ide register. */
172 static int
173 freecom_ide_write (struct us_data *us, int reg, int value)
174 {
175         freecom_udata_t extra = (freecom_udata_t) us->extra;
176         struct freecom_ide_out *ideout =
177                 (struct freecom_ide_out *) extra->buffer;
178         int opipe;
179         int result, partial;
180 
181         US_DEBUGP("IDE out 0x%02x <- 0x%02x\n", reg, value);
182 
183         /* Get handles for both transports. */
184         opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out);
185 
186         if (reg < 0 || reg > 8)
187                 return USB_STOR_TRANSPORT_ERROR;
188         if (reg < 8)
189                 reg |= 0x20;
190         else
191                 reg = 0x0e;
192 
193         ideout->Type = FCM_PACKET_IDE_WRITE | reg;
194         ideout->Pad = 0;
195         ideout->Value = cpu_to_le16 (value);
196         memset (ideout->Pad2, 0, sizeof (ideout->Pad2));
197 
198         result = usb_stor_bulk_msg (us, ideout, opipe,
199                         FCM_PACKET_LENGTH, &partial);
200         if (result != 0) {
201                 if (result == -ECONNRESET)
202                         return US_BULK_TRANSFER_ABORTED;
203                 else
204                         return USB_STOR_TRANSPORT_ERROR;
205         }
206 
207         return USB_STOR_TRANSPORT_GOOD;
208 }
209 
210 /* Read a value from an ide register. */
211 static int
212 freecom_ide_read (struct us_data *us, int reg, int *value)
213 {
214         freecom_udata_t extra = (freecom_udata_t) us->extra;
215         struct freecom_ide_in *idein =
216                 (struct freecom_ide_in *) extra->buffer;
217         __u8 *buffer = extra->buffer;
218         int ipipe, opipe;
219         int result, partial;
220         int desired_length;
221 
222         /* Get handles for both transports. */
223         opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out);
224         ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in);
225 
226         if (reg < 0 || reg > 8)
227                 return USB_STOR_TRANSPORT_ERROR;
228         if (reg < 8)
229                 reg |= 0x10;
230         else
231                 reg = 0x0e;
232 
233         US_DEBUGP("IDE in request for register 0x%02x\n", reg);
234 
235         idein->Type = FCM_PACKET_IDE_READ | reg;
236         memset (idein->Pad, 0, sizeof (idein->Pad));
237 
238         result = usb_stor_bulk_msg (us, idein, opipe,
239                         FCM_PACKET_LENGTH, &partial);
240         if (result != 0) {
241                 if (result == -ECONNRESET)
242                         return US_BULK_TRANSFER_ABORTED;
243                 else
244                         return USB_STOR_TRANSPORT_ERROR;
245         }
246 
247         desired_length = 1;
248         if (reg == 0x10)
249                 desired_length = 2;
250 
251         result = usb_stor_bulk_msg (us, buffer, ipipe,
252                         desired_length, &partial);
253         if (result != 0) {
254                 if (result == -ECONNRESET)
255                         return US_BULK_TRANSFER_ABORTED;
256                 else
257                         return USB_STOR_TRANSPORT_ERROR;
258         }
259         US_DEBUGP("IDE in partial is %d\n", partial);
260 
261         if (desired_length == 1)
262                 *value = buffer[0];
263         else
264                 *value = le16_to_cpu (*(__u16 *) buffer);
265 
266         US_DEBUGP("IDE in 0x%02x -> 0x%02x\n", reg, *value);
267 
268         return USB_STOR_TRANSPORT_GOOD;
269 }
270 #endif
271 
272 static int
freecom_readdata(Scsi_Cmnd * srb,struct us_data * us,int ipipe,int opipe,int count)273 freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
274                 int ipipe, int opipe, int count)
275 {
276         freecom_udata_t extra = (freecom_udata_t) us->extra;
277         struct freecom_xfer_wrap *fxfr =
278                 (struct freecom_xfer_wrap *) extra->buffer;
279         int result, partial;
280 
281         fxfr->Type = FCM_PACKET_INPUT | 0x00;
282         fxfr->Timeout = 0;    /* Short timeout for debugging. */
283         fxfr->Count = cpu_to_le32 (count);
284         memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
285 
286         US_DEBUGP("Read data Freecom! (c=%d)\n", count);
287 
288         /* Issue the transfer command. */
289         result = usb_stor_bulk_msg (us, fxfr, opipe,
290                         FCM_PACKET_LENGTH, &partial);
291         if (result != 0) {
292                 US_DEBUGP ("Freecom readdata xpot failure: r=%d, p=%d\n",
293                                 result, partial);
294 
295 		/* -ECONNRESET -- we canceled this transfer */
296 		if (result == -ECONNRESET) {
297 			US_DEBUGP("freecom_readdata(): transfer aborted\n");
298 			return US_BULK_TRANSFER_ABORTED;
299 		}
300 
301                 return USB_STOR_TRANSPORT_ERROR;
302         }
303         US_DEBUGP("Done issuing read request: %d %d\n", result, partial);
304 
305         /* Now transfer all of our blocks. */
306 	US_DEBUGP("Start of read\n");
307 	us_transfer_freecom(srb, us, count);
308         US_DEBUGP("freecom_readdata done!\n");
309 
310         return USB_STOR_TRANSPORT_GOOD;
311 }
312 
313 static int
freecom_writedata(Scsi_Cmnd * srb,struct us_data * us,int ipipe,int opipe,int count)314 freecom_writedata (Scsi_Cmnd *srb, struct us_data *us,
315                 int ipipe, int opipe, int count)
316 {
317         freecom_udata_t extra = (freecom_udata_t) us->extra;
318         struct freecom_xfer_wrap *fxfr =
319                 (struct freecom_xfer_wrap *) extra->buffer;
320         int result, partial;
321 
322         fxfr->Type = FCM_PACKET_OUTPUT | 0x00;
323         fxfr->Timeout = 0;    /* Short timeout for debugging. */
324         fxfr->Count = cpu_to_le32 (count);
325         memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
326 
327         US_DEBUGP("Write data Freecom! (c=%d)\n", count);
328 
329         /* Issue the transfer command. */
330         result = usb_stor_bulk_msg (us, fxfr, opipe,
331                         FCM_PACKET_LENGTH, &partial);
332         if (result != 0) {
333                 US_DEBUGP ("Freecom writedata xpot failure: r=%d, p=%d\n",
334                                 result, partial);
335 
336 		/* -ECONNRESET -- we canceled this transfer */
337 		if (result == -ECONNRESET) {
338 			US_DEBUGP("freecom_writedata(): transfer aborted\n");
339 			return US_BULK_TRANSFER_ABORTED;
340 		}
341 
342                 return USB_STOR_TRANSPORT_ERROR;
343         }
344         US_DEBUGP("Done issuing write request: %d %d\n",
345                         result, partial);
346 
347         /* Now transfer all of our blocks. */
348 	US_DEBUGP("Start of write\n");
349 	us_transfer_freecom(srb, us, count);
350 
351         US_DEBUGP("freecom_writedata done!\n");
352         return USB_STOR_TRANSPORT_GOOD;
353 }
354 
355 /*
356  * Transport for the Freecom USB/IDE adaptor.
357  *
358  */
freecom_transport(Scsi_Cmnd * srb,struct us_data * us)359 int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
360 {
361         struct freecom_cb_wrap *fcb;
362         struct freecom_status  *fst;
363         int ipipe, opipe;             /* We need both pipes. */
364         int result;
365         int partial;
366         int length;
367         freecom_udata_t extra;
368 
369         extra = (freecom_udata_t) us->extra;
370 
371         fcb = (struct freecom_cb_wrap *) extra->buffer;
372         fst = (struct freecom_status *) extra->buffer;
373 
374         US_DEBUGP("Freecom TRANSPORT STARTED\n");
375 
376         /* Get handles for both transports. */
377         opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out);
378         ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in);
379 
380         /* The ATAPI Command always goes out first. */
381         fcb->Type = FCM_PACKET_ATAPI | 0x00;
382         fcb->Timeout = 0;
383         memcpy (fcb->Atapi, srb->cmnd, 12);
384         memset (fcb->Filler, 0, sizeof (fcb->Filler));
385 
386         US_DEBUG(pdump (srb->cmnd, 12));
387 
388         /* Send it out. */
389         result = usb_stor_bulk_msg (us, fcb, opipe,
390                         FCM_PACKET_LENGTH, &partial);
391 
392         /* The Freecom device will only fail if there is something wrong in
393          * USB land.  It returns the status in its own registers, which
394          * come back in the bulk pipe. */
395         if (result != 0) {
396                 US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
397                                 result, partial);
398 
399 		/* -ECONNRESET -- we canceled this transfer */
400 		if (result == -ECONNRESET) {
401 			US_DEBUGP("freecom_transport(): transfer aborted\n");
402 			return US_BULK_TRANSFER_ABORTED;
403 		}
404 
405                 return USB_STOR_TRANSPORT_ERROR;
406         }
407 
408         /* There are times we can optimize out this status read, but it
409          * doesn't hurt us to always do it now. */
410         result = usb_stor_bulk_msg (us, fst, ipipe,
411                         FCM_PACKET_LENGTH, &partial);
412         US_DEBUGP("foo Status result %d %d\n", result, partial);
413 	/* -ECONNRESET -- we canceled this transfer */
414 	if (result == -ECONNRESET) {
415 		US_DEBUGP("freecom_transport(): transfer aborted\n");
416 		return US_BULK_TRANSFER_ABORTED;
417 	}
418 
419         US_DEBUG(pdump ((void *) fst, partial));
420 
421 	/* The firmware will time-out commands after 20 seconds. Some commands
422 	 * can legitimately take longer than this, so we use a different
423 	 * command that only waits for the interrupt and then sends status,
424 	 * without having to send a new ATAPI command to the device.
425 	 *
426 	 * NOTE: There is some indication that a data transfer after a timeout
427 	 * may not work, but that is a condition that should never happen.
428 	 */
429 	while (fst->Status & FCM_STATUS_BUSY) {
430 		US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occured!\n");
431 		US_DEBUGP("fst->Status is %x\n", fst->Status);
432 
433 		/* Get the status again */
434 		fcb->Type = FCM_PACKET_STATUS;
435 		fcb->Timeout = 0;
436 		memset (fcb->Atapi, 0, sizeof(fcb->Atapi));
437 		memset (fcb->Filler, 0, sizeof (fcb->Filler));
438 
439         	/* Send it out. */
440 		result = usb_stor_bulk_msg (us, fcb, opipe,
441 				FCM_PACKET_LENGTH, &partial);
442 
443 		/* The Freecom device will only fail if there is something
444 		 * wrong in USB land.  It returns the status in its own
445 		 * registers, which come back in the bulk pipe.
446 		 */
447 		if (result != 0) {
448 			US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
449 					result, partial);
450 
451 			/* -ECONNRESET -- we canceled this transfer */
452 			if (result == -ECONNRESET) {
453 				US_DEBUGP("freecom_transport(): transfer aborted\n");
454 				return US_BULK_TRANSFER_ABORTED;
455 			}
456 
457 			return USB_STOR_TRANSPORT_ERROR;
458 		}
459 
460 		/* get the data */
461         	result = usb_stor_bulk_msg (us, fst, ipipe,
462 				FCM_PACKET_LENGTH, &partial);
463 
464 		US_DEBUGP("bar Status result %d %d\n", result, partial);
465 
466 		/* -ECONNRESET -- we canceled this transfer */
467 		if (result == -ECONNRESET) {
468 			US_DEBUGP("freecom_transport(): transfer aborted\n");
469 			return US_BULK_TRANSFER_ABORTED;
470 		}
471 
472 		US_DEBUG(pdump ((void *) fst, partial));
473 	}
474 
475         if (partial != 4 || result != 0) {
476                 return USB_STOR_TRANSPORT_ERROR;
477         }
478         if ((fst->Status & 1) != 0) {
479                 US_DEBUGP("operation failed\n");
480                 return USB_STOR_TRANSPORT_FAILED;
481         }
482 
483         /* The device might not have as much data available as we
484          * requested.  If you ask for more than the device has, this reads
485          * and such will hang. */
486         US_DEBUGP("Device indicates that it has %d bytes available\n",
487                         le16_to_cpu (fst->Count));
488         US_DEBUGP("SCSI requested %d\n", usb_stor_transfer_length(srb));
489 
490         /* Find the length we desire to read. */
491 	switch (srb->cmnd[0]) {
492 		case INQUIRY:
493 		case REQUEST_SENSE:		/* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
494 		case MODE_SENSE:
495 		case MODE_SENSE_10:
496 			length = fst->Count;
497 			break;
498 		default:
499  			length = usb_stor_transfer_length (srb);
500 	}
501 
502 	/* verify that this amount is legal */
503 	if (length > srb->request_bufflen) {
504 		length = srb->request_bufflen;
505 		US_DEBUGP("Truncating request to match buffer length: %d\n", length);
506 	}
507 
508         /* What we do now depends on what direction the data is supposed to
509          * move in. */
510 
511         switch (us->srb->sc_data_direction) {
512         case SCSI_DATA_READ:
513                 /* Make sure that the status indicates that the device
514                  * wants data as well. */
515                 if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
516                         US_DEBUGP("SCSI wants data, drive doesn't have any\n");
517                         return USB_STOR_TRANSPORT_FAILED;
518                 }
519                 result = freecom_readdata (srb, us, ipipe, opipe, length);
520                 if (result != USB_STOR_TRANSPORT_GOOD)
521                         return result;
522 
523                 US_DEBUGP("FCM: Waiting for status\n");
524                 result = usb_stor_bulk_msg (us, fst, ipipe,
525                                 FCM_PACKET_LENGTH, &partial);
526 		US_DEBUG(pdump ((void *) fst, partial));
527                 if (result == -ECONNRESET) {
528                         US_DEBUGP ("freecom_transport: transfer aborted\n");
529                         return US_BULK_TRANSFER_ABORTED;
530                 }
531                 if (partial != 4 || result != 0)
532                         return USB_STOR_TRANSPORT_ERROR;
533                 if ((fst->Status & ERR_STAT) != 0) {
534                         US_DEBUGP("operation failed\n");
535                         return USB_STOR_TRANSPORT_FAILED;
536                 }
537                 if ((fst->Reason & 3) != 3) {
538                         US_DEBUGP("Drive seems still hungry\n");
539                         return USB_STOR_TRANSPORT_FAILED;
540                 }
541                 US_DEBUGP("Transfer happy\n");
542                 break;
543 
544         case SCSI_DATA_WRITE:
545                 /* Make sure the status indicates that the device wants to
546                  * send us data. */
547                 /* !!IMPLEMENT!! */
548                 result = freecom_writedata (srb, us, ipipe, opipe, length);
549                 if (result != USB_STOR_TRANSPORT_GOOD)
550                         return result;
551 
552                 US_DEBUGP("FCM: Waiting for status\n");
553                 result = usb_stor_bulk_msg (us, fst, ipipe,
554                                 FCM_PACKET_LENGTH, &partial);
555                 if (result == -ECONNRESET) {
556                         US_DEBUGP ("freecom_transport: transfer aborted\n");
557                         return US_BULK_TRANSFER_ABORTED;
558                 }
559                 if (partial != 4 || result != 0)
560                         return USB_STOR_TRANSPORT_ERROR;
561                 if ((fst->Status & ERR_STAT) != 0) {
562                         US_DEBUGP("operation failed\n");
563                         return USB_STOR_TRANSPORT_FAILED;
564                 }
565                 if ((fst->Reason & 3) != 3) {
566                         US_DEBUGP("Drive seems still hungry\n");
567                         return USB_STOR_TRANSPORT_FAILED;
568                 }
569 
570                 US_DEBUGP("Transfer happy\n");
571                 break;
572 
573 
574         case SCSI_DATA_NONE:
575                 /* Easy, do nothing. */
576                 break;
577 
578         default:
579                 US_DEBUGP ("freecom unimplemented direction: %d\n",
580                                 us->srb->sc_data_direction);
581                 // Return fail, SCSI seems to handle this better.
582                 return USB_STOR_TRANSPORT_FAILED;
583                 break;
584         }
585 
586         return USB_STOR_TRANSPORT_GOOD;
587 
588         US_DEBUGP("Freecom: transfer_length = %d\n",
589 			usb_stor_transfer_length (srb));
590 
591         US_DEBUGP("Freecom: direction = %d\n", srb->sc_data_direction);
592 
593         return USB_STOR_TRANSPORT_ERROR;
594 }
595 
596 int
freecom_init(struct us_data * us)597 freecom_init (struct us_data *us)
598 {
599         int result;
600 	char buffer[33];
601 
602         /* Allocate a buffer for us.  The upper usb transport code will
603          * free this for us when cleaning up. */
604         if (us->extra == NULL) {
605                 us->extra = kmalloc (sizeof (struct freecom_udata),
606                                 GFP_KERNEL);
607                 if (us->extra == NULL) {
608                         US_DEBUGP("Out of memory\n");
609                         return USB_STOR_TRANSPORT_ERROR;
610                 }
611         }
612 
613 	result = usb_control_msg(us->pusb_dev,
614 			usb_rcvctrlpipe(us->pusb_dev, 0),
615 			0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
616 	buffer[32] = '\0';
617 	US_DEBUGP("String returned from FC init is: %s\n", buffer);
618 
619 	/* Special thanks to the people at Freecom for providing me with
620 	 * this "magic sequence", which they use in their Windows and MacOS
621 	 * drivers to make sure that all the attached perhiperals are
622 	 * properly reset.
623 	 */
624 
625 	/* send reset */
626 	result = usb_control_msg(us->pusb_dev,
627 			usb_sndctrlpipe(us->pusb_dev, 0),
628 			0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
629 	US_DEBUGP("result from activate reset is %d\n", result);
630 
631 	/* wait 250ms */
632 	mdelay(250);
633 
634 	/* clear reset */
635 	result = usb_control_msg(us->pusb_dev,
636 			usb_sndctrlpipe(us->pusb_dev, 0),
637 			0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
638 	US_DEBUGP("result from clear reset is %d\n", result);
639 
640 	/* wait 3 seconds */
641 	mdelay(3 * 1000);
642 
643         return USB_STOR_TRANSPORT_GOOD;
644 }
645 
usb_stor_freecom_reset(struct us_data * us)646 int usb_stor_freecom_reset(struct us_data *us)
647 {
648         printk (KERN_CRIT "freecom reset called\n");
649 
650         /* We don't really have this feature. */
651         return FAILED;
652 }
653 
654 #ifdef CONFIG_USB_STORAGE_DEBUG
pdump(void * ibuffer,int length)655 static void pdump (void *ibuffer, int length)
656 {
657 	static char line[80];
658 	int offset = 0;
659 	unsigned char *buffer = (unsigned char *) ibuffer;
660 	int i, j;
661 	int from, base;
662 
663 	offset = 0;
664 	for (i = 0; i < length; i++) {
665 		if ((i & 15) == 0) {
666 			if (i > 0) {
667 				offset += sprintf (line+offset, " - ");
668 				for (j = i - 16; j < i; j++) {
669 					if (buffer[j] >= 32 && buffer[j] <= 126)
670 						line[offset++] = buffer[j];
671 					else
672 						line[offset++] = '.';
673 				}
674 				line[offset] = 0;
675 				US_DEBUGP("%s\n", line);
676 				offset = 0;
677 			}
678 			offset += sprintf (line+offset, "%08x:", i);
679 		}
680 		else if ((i & 7) == 0) {
681 			offset += sprintf (line+offset, " -");
682 		}
683 		offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);
684 	}
685 
686 	/* Add the last "chunk" of data. */
687 	from = (length - 1) % 16;
688 	base = ((length - 1) / 16) * 16;
689 
690 	for (i = from + 1; i < 16; i++)
691 		offset += sprintf (line+offset, "   ");
692 	if (from < 8)
693 		offset += sprintf (line+offset, "  ");
694 	offset += sprintf (line+offset, " - ");
695 
696 	for (i = 0; i <= from; i++) {
697 		if (buffer[base+i] >= 32 && buffer[base+i] <= 126)
698 			line[offset++] = buffer[base+i];
699 		else
700 			line[offset++] = '.';
701 	}
702 	line[offset] = 0;
703 	US_DEBUGP("%s\n", line);
704 	offset = 0;
705 }
706 #endif
707 
708