1 /* Driver for Freecom USB/IDE adaptor
3 * $Id: freecom.c,v 1.7 2000/08/25 00:13:51 mdharm Exp $
9 * Current development and maintenance by:
10 * (C) 2000 David Brown <usb-storage@davidb.org>
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
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.
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.
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/)
31 #include "transport.h"
37 static void pdump (void *, int);
39 struct freecom_udata
{
40 __u8 buffer
[64]; /* Common command block. */
42 typedef struct freecom_udata
*freecom_udata_t
;
44 /* All of the outgoing packets are 64 bytes long. */
45 struct freecom_cb_wrap
{
46 __u8 Type
; /* Command type. */
47 __u8 Timeout
; /* Timeout in seconds. */
48 __u8 Atapi
[12]; /* An ATAPI packet. */
49 __u8 Filler
[50]; /* Padding Data. */
52 struct freecom_xfer_wrap
{
53 __u8 Type
; /* Command type. */
54 __u8 Timeout
; /* Timeout in seconds. */
55 __u32 Count
; /* Number of bytes to transfer. */
59 struct freecom_status
{
66 /* These are the packet types. The low bit indicates that this command
67 * should wait for an interrupt. */
68 #define FCM_PACKET_ATAPI 0x21
70 /* Receive data from the IDE interface. The ATAPI packet has already
71 * waited, so the data should be immediately available. */
72 #define FCM_PACKET_INPUT 0x90
74 /* All packets (except for status) are 64 bytes long. */
75 #define FCM_PACKET_LENGTH 64
78 freecom_readdata (Scsi_Cmnd
*srb
, struct us_data
*us
,
79 int ipipe
, int opipe
, int count
)
81 freecom_udata_t extra
= (freecom_udata_t
) us
->extra
;
82 struct freecom_xfer_wrap
*fxfr
=
83 (struct freecom_xfer_wrap
*) extra
->buffer
;
86 __u8
*buffer
= extra
->buffer
;
88 fxfr
->Type
= FCM_PACKET_INPUT
| 0x00;
89 fxfr
->Timeout
= 0; /* Short timeout for debugging. */
90 fxfr
->Count
= cpu_to_le32 (count
);
91 memset (fxfr
->Pad
, 0, sizeof (fxfr
->Pad
));
93 printk (KERN_DEBUG
"Read data Freecom! (c=%d)\n", count
);
95 /* Issue the transfer command. */
96 result
= usb_stor_bulk_msg (us
, fxfr
, opipe
,
97 FCM_PACKET_LENGTH
, &partial
);
99 US_DEBUGP ("Freecom readdata xpot failure: r=%d, p=%d\n",
102 /* -ENOENT -- we canceled this transfer */
103 if (result
== -ENOENT
) {
104 US_DEBUGP("us_transfer_partial(): transfer aborted\n");
105 return US_BULK_TRANSFER_ABORTED
;
108 return USB_STOR_TRANSPORT_ERROR
;
110 printk (KERN_DEBUG
"Done issuing read request: %d %d\n",
113 /* Now transfer all of our blocks. */
115 US_DEBUGP ("Need to implement scatter-gather\n");
116 return USB_STOR_TRANSPORT_ERROR
;
120 while (offset
< count
) {
121 printk (KERN_DEBUG
"Start of read\n");
122 /* Use the given buffer directly, but only if there
123 * is space for an entire packet. */
125 if (offset
+ 64 <= srb
->request_bufflen
) {
126 result
= usb_stor_bulk_msg (
127 us
, srb
->request_buffer
+offset
,
128 ipipe
, 64, &partial
);
129 printk (KERN_DEBUG
"Read111 = %d, %d\n",
131 pdump (srb
->request_buffer
+offset
,
134 result
= usb_stor_bulk_msg (
136 ipipe
, 64, &partial
);
137 printk (KERN_DEBUG
"Read112 = %d, %d\n",
139 memcpy (srb
->request_buffer
+offset
,
141 srb
->request_bufflen
- offset
);
142 pdump (srb
->request_buffer
+offset
,
143 srb
->request_bufflen
- offset
);
147 US_DEBUGP ("Freecom readblock r=%d, p=%d\n",
150 /* -ENOENT -- we canceled this transfer */
151 if (result
== -ENOENT
) {
152 US_DEBUGP("us_transfer_partial(): transfer aborted\n");
153 return US_BULK_TRANSFER_ABORTED
;
156 return USB_STOR_TRANSPORT_ERROR
;
163 printk (KERN_DEBUG
"freecom_readdata done!\n");
164 return USB_STOR_TRANSPORT_GOOD
;
168 * Transport for the Freecom USB/IDE adaptor.
171 int freecom_transport(Scsi_Cmnd
*srb
, struct us_data
*us
)
173 struct freecom_cb_wrap
*fcb
;
174 struct freecom_status
*fst
;
175 int ipipe
, opipe
; /* We need both pipes. */
179 freecom_udata_t extra
;
181 /* Allocate a buffer for us. The upper usb transport code will
182 * free this for us when cleaning up. */
183 if (us
->extra
== NULL
) {
184 us
->extra
= kmalloc (sizeof (struct freecom_udata
),
186 if (us
->extra
== NULL
) {
187 printk (KERN_WARNING USB_STORAGE
"Out of memory\n");
188 return USB_STOR_TRANSPORT_ERROR
;
192 extra
= (freecom_udata_t
) us
->extra
;
194 fcb
= (struct freecom_cb_wrap
*) extra
->buffer
;
195 fst
= (struct freecom_status
*) extra
->buffer
;
197 printk (KERN_DEBUG
"Freecom TRANSPORT STARTED\n");
199 /* Get handles for both transports. */
200 opipe
= usb_sndbulkpipe (us
->pusb_dev
, us
->ep_out
);
201 ipipe
= usb_rcvbulkpipe (us
->pusb_dev
, us
->ep_in
);
204 /* Yuck, let's see if this helps us. Artificially increase the
206 if (srb
->cmnd
[0] == 0x03 && srb
->cmnd
[4] == 0x12)
210 /* The ATAPI Command always goes out first. */
211 fcb
->Type
= FCM_PACKET_ATAPI
;
213 memcpy (fcb
->Atapi
, srb
->cmnd
, 12);
214 memset (fcb
->Filler
, 0, sizeof (fcb
->Filler
));
216 pdump (srb
->cmnd
, 12);
219 result
= usb_stor_bulk_msg (us
, fcb
, opipe
,
220 FCM_PACKET_LENGTH
, &partial
);
222 /* The Freecom device will only fail if there is something wrong in
223 * USB land. It returns the status in its own registers, which
224 * come back in the bulk pipe. */
226 US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
229 /* -ENOENT -- we canceled this transfer */
230 if (result
== -ENOENT
) {
231 US_DEBUGP("us_transfer_partial(): transfer aborted\n");
232 return US_BULK_TRANSFER_ABORTED
;
235 return USB_STOR_TRANSPORT_ERROR
;
238 /* There are times we can optimize out this status read, but it
239 * doesn't hurt us to always do it now. */
240 result
= usb_stor_bulk_msg (us
, fst
, ipipe
,
241 FCM_PACKET_LENGTH
, &partial
);
242 printk (KERN_DEBUG
"foo Status result %d %d\n", result
, partial
);
243 /* -ENOENT -- we canceled this transfer */
244 if (result
== -ENOENT
) {
245 US_DEBUGP("us_transfer_partial(): transfer aborted\n");
246 return US_BULK_TRANSFER_ABORTED
;
249 pdump ((void *) fst
, partial
);
250 if (partial
!= 4 || result
!= 0) {
251 return USB_STOR_TRANSPORT_ERROR
;
253 if ((fst
->Reason
& 1) != 0) {
254 printk (KERN_DEBUG
"operation failed\n");
255 return USB_STOR_TRANSPORT_FAILED
;
258 /* The device might not have as much data available as we
259 * requested. If you ask for more than the device has, this reads
260 * and such will hang. */
261 printk (KERN_DEBUG
"Device indicates that it has %d bytes available\n",
262 le16_to_cpu (fst
->Count
));
264 /* Find the length we desire to read. It is the lesser of the SCSI
265 * layer's requested length, and the length the device claims to
267 length
= us_transfer_length (srb
);
268 printk (KERN_DEBUG
"SCSI requested %d\n", length
);
269 if (length
> le16_to_cpu (fst
->Count
))
270 length
= le16_to_cpu (fst
->Count
);
272 /* What we do now depends on what direction the data is supposed to
275 switch (us
->srb
->sc_data_direction
) {
277 result
= freecom_readdata (srb
, us
, ipipe
, opipe
, length
);
278 if (result
!= USB_STOR_TRANSPORT_GOOD
)
283 US_DEBUGP ("freecom unimplemented direction: %d\n",
284 us
->srb
->sc_data_direction
);
285 // Return fail, SCSI seems to handle this better.
286 return USB_STOR_TRANSPORT_FAILED
;
291 /* After the transfer, we can read our status register. */
292 printk (KERN_DEBUG
"Going to read status register\n");
293 result
= usb_stor_bulk_msg (us
, &fst
, ipipe
,
294 FCM_PACKET_LENGTH
, &partial
);
295 printk (KERN_DEBUG
"Result from read %d %d\n", result
, partial
);
297 return USB_STOR_TRANSPORT_ERROR
;
299 if ((fst
.Reason
& 1) != 0) {
300 return USB_STOR_TRANSPORT_FAILED
;
304 return USB_STOR_TRANSPORT_GOOD
;
306 printk (KERN_DEBUG
"Freecom: transfer_length = %d\n",
307 us_transfer_length (srb
));
309 printk (KERN_DEBUG
"Freecom: direction = %d\n",
310 srb
->sc_data_direction
);
312 return USB_STOR_TRANSPORT_ERROR
;
315 int usb_stor_freecom_reset(struct us_data
*us
)
317 printk (KERN_DEBUG
"freecom reset called\n");
319 /* We don't really have this feature. */
320 return USB_STOR_TRANSPORT_ERROR
;
323 static void pdump (void *ibuffer
, int length
)
325 static char line
[80];
327 unsigned char *buffer
= (unsigned char *) ibuffer
;
332 for (i
= 0; i
< length
; i
++) {
335 offset
+= sprintf (line
+offset
, " - ");
336 for (j
= i
- 16; j
< i
; j
++) {
337 if (buffer
[j
] >= 32 && buffer
[j
] <= 126)
338 line
[offset
++] = buffer
[j
];
340 line
[offset
++] = '.';
343 printk (KERN_DEBUG
"%s\n", line
);
346 offset
+= sprintf (line
+offset
, "%08x:", i
);
348 else if ((i
& 7) == 0) {
349 offset
+= sprintf (line
+offset
, " -");
351 offset
+= sprintf (line
+offset
, " %02x", buffer
[i
] & 0xff);
354 /* Add the last "chunk" of data. */
355 from
= (length
- 1) % 16;
356 base
= ((length
- 1) / 16) * 16;
358 for (i
= from
+ 1; i
< 16; i
++)
359 offset
+= sprintf (line
+offset
, " ");
361 offset
+= sprintf (line
+offset
, " ");
362 offset
+= sprintf (line
+offset
, " - ");
364 for (i
= 0; i
<= from
; i
++) {
365 if (buffer
[base
+i
] >= 32 && buffer
[base
+i
] <= 126)
366 line
[offset
++] = buffer
[base
+i
];
368 line
[offset
++] = '.';
371 printk (KERN_DEBUG
"%s\n", line
);