| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* Driver for Freecom USB/IDE adaptor | |||
| 2 | * | |||
| 3 | * $Id: freecom.c,v 1.22 2002/04/22 03:39:43 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 <linux/hdreg.h> | |||
| 33 | ||||
| 34 | #include <scsi/scsi.h> | |||
| 35 | #include <scsi/scsi_cmnd.h> | |||
| 36 | ||||
| 37 | #include "usb.h" | |||
| 38 | #include "transport.h" | |||
| 39 | #include "protocol.h" | |||
| 40 | #include "debug.h" | |||
| 41 | #include "freecom.h" | |||
| 42 | ||||
| 43 | #ifdef CONFIG_USB_STORAGE_DEBUG | |||
| 44 | static void pdump (void *, int); | |||
| 45 | #endif | |||
| 46 | ||||
| 47 | /* Bits of HD_STATUS */ | |||
| 48 | #define ERR_STAT 0x01 | |||
| 49 | #define DRQ_STAT 0x08 | |||
| 50 | ||||
| 51 | /* All of the outgoing packets are 64 bytes long. */ | |||
| 52 | struct freecom_cb_wrap { | |||
| 53 | u8 Type; /* Command type. */ | |||
| 54 | u8 Timeout; /* Timeout in seconds. */ | |||
| 55 | u8 Atapi[12]; /* An ATAPI packet. */ | |||
| 56 | u8 Filler[50]; /* Padding Data. */ | |||
| 57 | }; | |||
| 58 | ||||
| 59 | struct freecom_xfer_wrap { | |||
| 60 | u8 Type; /* Command type. */ | |||
| 61 | u8 Timeout; /* Timeout in seconds. */ | |||
| 62 | __le32 Count; /* Number of bytes to transfer. */ | |||
| 63 | u8 Pad[58]; | |||
| 64 | } __attribute__ ((packed)); | |||
| 65 | ||||
| 66 | struct freecom_ide_out { | |||
| 67 | u8 Type; /* Type + IDE register. */ | |||
| 68 | u8 Pad; | |||
| 69 | __le16 Value; /* Value to write. */ | |||
| 70 | u8 Pad2[60]; | |||
| 71 | }; | |||
| 72 | ||||
| 73 | struct freecom_ide_in { | |||
| 74 | u8 Type; /* Type | IDE register. */ | |||
| 75 | u8 Pad[63]; | |||
| 76 | }; | |||
| 77 | ||||
| 78 | struct freecom_status { | |||
| 79 | u8 Status; | |||
| 80 | u8 Reason; | |||
| 81 | __le16 Count; | |||
| 82 | u8 Pad[60]; | |||
| 83 | }; | |||
| 84 | ||||
| 85 | /* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide | |||
| 86 | * register. */ | |||
| 87 | #define FCM_INT_STATUS 0x02 /* INDEX_STAT */ | |||
| 88 | #define FCM_STATUS_BUSY 0x80 | |||
| 89 | ||||
| 90 | /* These are the packet types. The low bit indicates that this command | |||
| 91 | * should wait for an interrupt. */ | |||
| 92 | #define FCM_PACKET_ATAPI 0x21 | |||
| 93 | #define FCM_PACKET_STATUS 0x20 | |||
| 94 | ||||
| 95 | /* Receive data from the IDE interface. The ATAPI packet has already | |||
| 96 | * waited, so the data should be immediately available. */ | |||
| 97 | #define FCM_PACKET_INPUT 0x81 | |||
| 98 | ||||
| 99 | /* Send data to the IDE interface. */ | |||
| 100 | #define FCM_PACKET_OUTPUT 0x01 | |||
| 101 | ||||
| 102 | /* Write a value to an ide register. Or the ide register to write after | |||
| 103 | * munging the address a bit. */ | |||
| 104 | #define FCM_PACKET_IDE_WRITE 0x40 | |||
| 105 | #define FCM_PACKET_IDE_READ 0xC0 | |||
| 106 | ||||
| 107 | /* All packets (except for status) are 64 bytes long. */ | |||
| 108 | #define FCM_PACKET_LENGTH 64 | |||
| 109 | #define FCM_STATUS_PACKET_LENGTH 4 | |||
| 110 | ||||
| 111 | static int | |||
| 0 | 0 | - | 112 | freecom_readdata (struct scsi_cmnd *srb, struct us_data *us, |
| 113 | unsigned int ipipe, unsigned int opipe, int count) | |||
| 114 | { | |||
| 115 | struct freecom_xfer_wrap *fxfr = | |||
| 116 | (struct freecom_xfer_wrap *) us->iobuf; | |||
| 117 | int result; | |||
| 118 | ||||
| 119 | fxfr->Type = FCM_PACKET_INPUT | 0x00; | |||
| 120 | fxfr->Timeout = 0; /* Short timeout for debugging. */ | |||
| 121 | fxfr->Count = cpu_to_le32 (count); | |||
| 122 | memset (fxfr->Pad, 0, sizeof (fxfr->Pad)); | |||
| 123 | ||||
| 124 | US_DEBUGP("Read data Freecom! (c=%d)\n", count); | |||
| 125 | ||||
| 126 | /* Issue the transfer command. */ | |||
| 127 | result = usb_stor_bulk_transfer_buf (us, opipe, fxfr, | |||
| 128 | FCM_PACKET_LENGTH, NULL); | |||
| 0 | 0 | - | 129 | if (result != USB_STOR_XFER_GOOD) { |
| 130 | US_DEBUGP ("Freecom readdata transport error\n"); | |||
| 0 | - | 131 | return USB_STOR_TRANSPORT_ERROR; | |
| 132 | } | |||
| 133 | ||||
| 134 | /* Now transfer all of our blocks. */ | |||
| 135 | US_DEBUGP("Start of read\n"); | |||
| 136 | result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer, | |||
| 137 | count, srb->use_sg, &srb->resid); | |||
| 138 | US_DEBUGP("freecom_readdata done!\n"); | |||
| 139 | ||||
| 0 | 0 | - | 140 | if (result > USB_STOR_XFER_SHORT) |
| 0 | - | 141 | return USB_STOR_TRANSPORT_ERROR; | |
| 0 | - | 142 | return USB_STOR_TRANSPORT_GOOD; | |
| 143 | } | |||
| 144 | ||||
| 145 | static int | |||
| 0 | 0 | - | 146 | freecom_writedata (struct scsi_cmnd *srb, struct us_data *us, |
| 147 | int unsigned ipipe, unsigned int opipe, int count) | |||
| 148 | { | |||
| 149 | struct freecom_xfer_wrap *fxfr = | |||
| 150 | (struct freecom_xfer_wrap *) us->iobuf; | |||
| 151 | int result; | |||
| 152 | ||||
| 153 | fxfr->Type = FCM_PACKET_OUTPUT | 0x00; | |||
| 154 | fxfr->Timeout = 0; /* Short timeout for debugging. */ | |||
| 155 | fxfr->Count = cpu_to_le32 (count); | |||
| 156 | memset (fxfr->Pad, 0, sizeof (fxfr->Pad)); | |||
| 157 | ||||
| 158 | US_DEBUGP("Write data Freecom! (c=%d)\n", count); | |||
| 159 | ||||
| 160 | /* Issue the transfer command. */ | |||
| 161 | result = usb_stor_bulk_transfer_buf (us, opipe, fxfr, | |||
| 162 | FCM_PACKET_LENGTH, NULL); | |||
| 0 | 0 | - | 163 | if (result != USB_STOR_XFER_GOOD) { |
| 164 | US_DEBUGP ("Freecom writedata transport error\n"); | |||
| 0 | - | 165 | return USB_STOR_TRANSPORT_ERROR; | |
| 166 | } | |||
| 167 | ||||
| 168 | /* Now transfer all of our blocks. */ | |||
| 169 | US_DEBUGP("Start of write\n"); | |||
| 170 | result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer, | |||
| 171 | count, srb->use_sg, &srb->resid); | |||
| 172 | ||||
| 173 | US_DEBUGP("freecom_writedata done!\n"); | |||
| 0 | 0 | - | 174 | if (result > USB_STOR_XFER_SHORT) |
| 0 | - | 175 | return USB_STOR_TRANSPORT_ERROR; | |
| 0 | - | 176 | return USB_STOR_TRANSPORT_GOOD; | |
| 177 | } | |||
| 178 | ||||
| 179 | /* | |||
| 180 | * Transport for the Freecom USB/IDE adaptor. | |||
| 181 | * | |||
| 182 | */ | |||
| 0 | 0 | - | 183 | int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) |
| 184 | { | |||
| 185 | struct freecom_cb_wrap *fcb; | |||
| 186 | struct freecom_status *fst; | |||
| 187 | unsigned int ipipe, opipe; /* We need both pipes. */ | |||
| 188 | int result; | |||
| 189 | unsigned int partial; | |||
| 190 | int length; | |||
| 191 | ||||
| 192 | fcb = (struct freecom_cb_wrap *) us->iobuf; | |||
| 193 | fst = (struct freecom_status *) us->iobuf; | |||
| 194 | ||||
| 195 | US_DEBUGP("Freecom TRANSPORT STARTED\n"); | |||
| 196 | ||||
| 197 | /* Get handles for both transports. */ | |||
| 198 | opipe = us->send_bulk_pipe; | |||
| 199 | ipipe = us->recv_bulk_pipe; | |||
| 200 | ||||
| 201 | /* The ATAPI Command always goes out first. */ | |||
| 202 | fcb->Type = FCM_PACKET_ATAPI | 0x00; | |||
| 203 | fcb->Timeout = 0; | |||
| 204 | memcpy (fcb->Atapi, srb->cmnd, 12); | |||
| 205 | memset (fcb->Filler, 0, sizeof (fcb->Filler)); | |||
| 206 | ||||
| 207 | US_DEBUG(pdump (srb->cmnd, 12)); | |||
| 208 | ||||
| 209 | /* Send it out. */ | |||
| 210 | result = usb_stor_bulk_transfer_buf (us, opipe, fcb, | |||
| 211 | FCM_PACKET_LENGTH, NULL); | |||
| 212 | ||||
| 213 | /* The Freecom device will only fail if there is something wrong in | |||
| 214 | * USB land. It returns the status in its own registers, which | |||
| 215 | * come back in the bulk pipe. */ | |||
| 0 | 0 | - | 216 | if (result != USB_STOR_XFER_GOOD) { |
| 217 | US_DEBUGP ("freecom transport error\n"); | |||
| 0 | - | 218 | return USB_STOR_TRANSPORT_ERROR; | |
| 219 | } | |||
| 220 | ||||
| 221 | /* There are times we can optimize out this status read, but it | |||
| 222 | * doesn't hurt us to always do it now. */ | |||
| 223 | result = usb_stor_bulk_transfer_buf (us, ipipe, fst, | |||
| 224 | FCM_STATUS_PACKET_LENGTH, &partial); | |||
| 225 | US_DEBUGP("foo Status result %d %u\n", result, partial); | |||
| 0 | 0 | - | 226 | if (result != USB_STOR_XFER_GOOD) |
| 0 | - | 227 | return USB_STOR_TRANSPORT_ERROR; | |
| 228 | ||||
| 229 | US_DEBUG(pdump ((void *) fst, partial)); | |||
| 230 | ||||
| 231 | /* The firmware will time-out commands after 20 seconds. Some commands | |||
| 232 | * can legitimately take longer than this, so we use a different | |||
| 233 | * command that only waits for the interrupt and then sends status, | |||
| 234 | * without having to send a new ATAPI command to the device. | |||
| 235 | * | |||
| 236 | * NOTE: There is some indication that a data transfer after a timeout | |||
| 237 | * may not work, but that is a condition that should never happen. | |||
| 238 | */ | |||
| 0 | 0 | - | 239 | while (fst->Status & FCM_STATUS_BUSY) { |
| 240 | US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occurred!\n"); | |||
| 241 | US_DEBUGP("fst->Status is %x\n", fst->Status); | |||
| 242 | ||||
| 243 | /* Get the status again */ | |||
| 244 | fcb->Type = FCM_PACKET_STATUS; | |||
| 245 | fcb->Timeout = 0; | |||
| 246 | memset (fcb->Atapi, 0, sizeof(fcb->Atapi)); | |||
| 247 | memset (fcb->Filler, 0, sizeof (fcb->Filler)); | |||
| 248 | ||||
| 249 | /* Send it out. */ | |||
| 250 | result = usb_stor_bulk_transfer_buf (us, opipe, fcb, | |||
| 251 | FCM_PACKET_LENGTH, NULL); | |||
| 252 | ||||
| 253 | /* The Freecom device will only fail if there is something | |||
| 254 | * wrong in USB land. It returns the status in its own | |||
| 255 | * registers, which come back in the bulk pipe. | |||
| 256 | */ | |||
| 0 | 0 | - | 257 | if (result != USB_STOR_XFER_GOOD) { |
| 258 | US_DEBUGP ("freecom transport error\n"); | |||
| 0 | - | 259 | return USB_STOR_TRANSPORT_ERROR; | |
| 260 | } | |||
| 261 | ||||
| 262 | /* get the data */ | |||
| 263 | result = usb_stor_bulk_transfer_buf (us, ipipe, fst, | |||
| 264 | FCM_STATUS_PACKET_LENGTH, &partial); | |||
| 265 | ||||
| 266 | US_DEBUGP("bar Status result %d %u\n", result, partial); | |||
| 0 | 0 | - | 267 | if (result != USB_STOR_XFER_GOOD) |
| 0 | - | 268 | return USB_STOR_TRANSPORT_ERROR; | |
| 269 | ||||
| 270 | US_DEBUG(pdump ((void *) fst, partial)); | |||
| 271 | } | |||
| 272 | ||||
| 0 | 0 | - | 273 | if (partial != 4) |
| 0 | - | 274 | return USB_STOR_TRANSPORT_ERROR; | |
| 0 | 0 | - | 275 | if ((fst->Status & 1) != 0) { |
| 276 | US_DEBUGP("operation failed\n"); | |||
| 0 | - | 277 | return USB_STOR_TRANSPORT_FAILED; | |
| 278 | } | |||
| 279 | ||||
| 280 | /* The device might not have as much data available as we | |||
| 281 | * requested. If you ask for more than the device has, this reads | |||
| 282 | * and such will hang. */ | |||
| 283 | US_DEBUGP("Device indicates that it has %d bytes available\n", | |||
| 284 | le16_to_cpu (fst->Count)); | |||
| 285 | US_DEBUGP("SCSI requested %d\n", srb->request_bufflen); | |||
| 286 | ||||
| 287 | /* Find the length we desire to read. */ | |||
| 288 | switch (srb->cmnd[0]) { | |||
| 0 | - | 289 | case INQUIRY: | |
| 0 | - | 290 | case REQUEST_SENSE: /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */ | |
| 0 | - | 291 | case MODE_SENSE: | |
| 0 | - | 292 | case MODE_SENSE_10: | |
| 293 | length = le16_to_cpu(fst->Count); | |||
| 0 | - | 294 | break; | |
| 0 | - | 295 | default: | |
| 296 | length = srb->request_bufflen; | |||
| 297 | } | |||
| 298 | ||||
| 299 | /* verify that this amount is legal */ | |||
| 0 | 0 | - | 300 | if (length > srb->request_bufflen) { |
| 301 | length = srb->request_bufflen; | |||
| 302 | US_DEBUGP("Truncating request to match buffer length: %d\n", length); | |||
| 303 | } | |||
| 304 | ||||
| 305 | /* What we do now depends on what direction the data is supposed to | |||
| 306 | * move in. */ | |||
| 307 | ||||
| 308 | switch (us->srb->sc_data_direction) { | |||
| 0 | - | 309 | case DMA_FROM_DEVICE: | |
| 310 | /* catch bogus "read 0 length" case */ | |||
| 0 | 0 | - | 311 | if (!length) |
| 0 | - | 312 | break; | |
| 313 | /* Make sure that the status indicates that the device | |||
| 314 | * wants data as well. */ | |||
| 0 | 0 | - | 315 | if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) { |
| 0 | - | 315 | T || _ | |
| 0 | - | 315 | F || T | |
| 0 | - | 315 | F || F | |
| 316 | US_DEBUGP("SCSI wants data, drive doesn't have any\n"); | |||
| 0 | - | 317 | return USB_STOR_TRANSPORT_FAILED; | |
| 318 | } | |||
| 319 | result = freecom_readdata (srb, us, ipipe, opipe, length); | |||
| 0 | 0 | - | 320 | if (result != USB_STOR_TRANSPORT_GOOD) |
| 0 | - | 321 | return result; | |
| 322 | ||||
| 323 | US_DEBUGP("FCM: Waiting for status\n"); | |||
| 324 | result = usb_stor_bulk_transfer_buf (us, ipipe, fst, | |||
| 325 | FCM_PACKET_LENGTH, &partial); | |||
| 326 | US_DEBUG(pdump ((void *) fst, partial)); | |||
| 327 | ||||
| 0 | 0 | - | 328 | if (partial != 4 || result > USB_STOR_XFER_SHORT) |
| 0 | - | 328 | T || _ | |
| 0 | - | 328 | F || T | |
| 0 | - | 328 | F || F | |
| 0 | - | 329 | return USB_STOR_TRANSPORT_ERROR; | |
| 0 | 0 | - | 330 | if ((fst->Status & ERR_STAT) != 0) { |
| 331 | US_DEBUGP("operation failed\n"); | |||
| 0 | - | 332 | return USB_STOR_TRANSPORT_FAILED; | |
| 333 | } | |||
| 0 | 0 | - | 334 | if ((fst->Reason & 3) != 3) { |
| 335 | US_DEBUGP("Drive seems still hungry\n"); | |||
| 0 | - | 336 | return USB_STOR_TRANSPORT_FAILED; | |
| 337 | } | |||
| 338 | US_DEBUGP("Transfer happy\n"); | |||
| 0 | - | 339 | break; | |
| 340 | ||||
| 0 | - | 341 | case DMA_TO_DEVICE: | |
| 342 | /* catch bogus "write 0 length" case */ | |||
| 0 | 0 | - | 343 | if (!length) |
| 0 | - | 344 | break; | |
| 345 | /* Make sure the status indicates that the device wants to | |||
| 346 | * send us data. */ | |||
| 347 | /* !!IMPLEMENT!! */ | |||
| 348 | result = freecom_writedata (srb, us, ipipe, opipe, length); | |||
| 0 | 0 | - | 349 | if (result != USB_STOR_TRANSPORT_GOOD) |
| 0 | - | 350 | return result; | |
| 351 | ||||
| 352 | US_DEBUGP("FCM: Waiting for status\n"); | |||
| 353 | result = usb_stor_bulk_transfer_buf (us, ipipe, fst, | |||
| 354 | FCM_PACKET_LENGTH, &partial); | |||
| 355 | ||||
| 0 | 0 | - | 356 | if (partial != 4 || result > USB_STOR_XFER_SHORT) |
| 0 | - | 356 | T || _ | |
| 0 | - | 356 | F || T | |
| 0 | - | 356 | F || F | |
| 0 | - | 357 | return USB_STOR_TRANSPORT_ERROR; | |
| 0 | 0 | - | 358 | if ((fst->Status & ERR_STAT) != 0) { |
| 359 | US_DEBUGP("operation failed\n"); | |||
| 0 | - | 360 | return USB_STOR_TRANSPORT_FAILED; | |
| 361 | } | |||
| 0 | 0 | - | 362 | if ((fst->Reason & 3) != 3) { |
| 363 | US_DEBUGP("Drive seems still hungry\n"); | |||
| 0 | - | 364 | return USB_STOR_TRANSPORT_FAILED; | |
| 365 | } | |||
| 366 | ||||
| 367 | US_DEBUGP("Transfer happy\n"); | |||
| 0 | - | 368 | break; | |
| 369 | ||||
| 370 | ||||
| 0 | - | 371 | case DMA_NONE: | |
| 372 | /* Easy, do nothing. */ | |||
| 0 | - | 373 | break; | |
| 374 | ||||
| 0 | - | 375 | default: | |
| 376 | /* should never hit here -- filtered in usb.c */ | |||
| 377 | US_DEBUGP ("freecom unimplemented direction: %d\n", | |||
| 378 | us->srb->sc_data_direction); | |||
| 379 | // Return fail, SCSI seems to handle this better. | |||
| 0 | - | 380 | return USB_STOR_TRANSPORT_FAILED; | |
| 0 | - | 381 | break; | |
| 382 | } | |||
| 383 | ||||
| 0 | - | 384 | return USB_STOR_TRANSPORT_GOOD; | |
| 385 | } | |||
| 386 | ||||
| 387 | int | |||
| 0 | 0 | - | 388 | freecom_init (struct us_data *us) |
| 389 | { | |||
| 390 | int result; | |||
| 391 | char *buffer = us->iobuf; | |||
| 392 | ||||
| 393 | /* The DMA-mapped I/O buffer is 64 bytes long, just right for | |||
| 394 | * all our packets. No need to allocate any extra buffer space. | |||
| 395 | */ | |||
| 396 | ||||
| 397 | result = usb_stor_control_msg(us, us->recv_ctrl_pipe, | |||
| 398 | 0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ); | |||
| 399 | buffer[32] = '\0'; | |||
| 400 | US_DEBUGP("String returned from FC init is: %s\n", buffer); | |||
| 401 | ||||
| 402 | /* Special thanks to the people at Freecom for providing me with | |||
| 403 | * this "magic sequence", which they use in their Windows and MacOS | |||
| 404 | * drivers to make sure that all the attached perhiperals are | |||
| 405 | * properly reset. | |||
| 406 | */ | |||
| 407 | ||||
| 408 | /* send reset */ | |||
| 409 | result = usb_stor_control_msg(us, us->send_ctrl_pipe, | |||
| 410 | 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ); | |||
| 411 | US_DEBUGP("result from activate reset is %d\n", result); | |||
| 412 | ||||
| 413 | /* wait 250ms */ | |||
| 414 | mdelay(250); | |||
| 0 | 0 | - | 414 | ternary-?: ( __builtin_constant_p ( 250 ) && (.. |
| 0 | 0 | - | 414 | ternary-?: __builtin_constant_p ( ( 250 ) * 10.. |
| 0 | 0 | - | 414 | ternary-?: ( ( 250 ) * 1000 ) > 20000 |
| 415 | ||||
| 416 | /* clear reset */ | |||
| 417 | result = usb_stor_control_msg(us, us->send_ctrl_pipe, | |||
| 418 | 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ); | |||
| 419 | US_DEBUGP("result from clear reset is %d\n", result); | |||
| 420 | ||||
| 421 | /* wait 3 seconds */ | |||
| 422 | mdelay(3 * 1000); | |||
| 0 | 0 | - | 422 | ternary-?: ( __builtin_constant_p ( 3 * 1000 ).. |
| 0 | 0 | - | 422 | ternary-?: __builtin_constant_p ( ( 3 * 1000 ).. |
| 0 | 0 | - | 422 | ternary-?: ( ( 3 * 1000 ) * 1000 ) > 20000 |
| 423 | ||||
| 0 | - | 424 | return USB_STOR_TRANSPORT_GOOD; | |
| 425 | } | |||
| 426 | ||||
| 0 | 0 | - | 427 | int usb_stor_freecom_reset(struct us_data *us) |
| 428 | { | |||
| 429 | printk (KERN_CRIT "freecom reset called\n"); | |||
| 430 | ||||
| 431 | /* We don't really have this feature. */ | |||
| 0 | - | 432 | return FAILED; | |
| 433 | } | |||
| 434 | ||||
| 435 | #ifdef CONFIG_USB_STORAGE_DEBUG | |||
| 0 | 0 | - | 436 | static void pdump (void *ibuffer, int length) |
| 437 | { | |||
| 438 | static char line[80]; | |||
| 439 | int offset = 0; | |||
| 440 | unsigned char *buffer = (unsigned char *) ibuffer; | |||
| 441 | int i, j; | |||
| 442 | int from, base; | |||
| 443 | ||||
| 444 | offset = 0; | |||
| 0 | 0 | - | 445 | for (i = 0; i < length; i++) { |
| 0 | 0 | - | 446 | if ((i & 15) == 0) { |
| 0 | 0 | - | 447 | if (i > 0) { |
| 448 | offset += sprintf (line+offset, " - "); | |||
| 0 | 0 | - | 449 | for (j = i - 16; j < i; j++) { |
| 0 | 0 | - | 450 | if (buffer[j] >= 32 && buffer[j] <= 126) |
| 0 | - | 450 | T && T | |
| 0 | - | 450 | T && F | |
| 0 | - | 450 | F && _ | |
| 451 | line[offset++] = buffer[j]; | |||
| 452 | else | |||
| 453 | line[offset++] = '.'; | |||
| 454 | } | |||
| 455 | line[offset] = 0; | |||
| 456 | US_DEBUGP("%s\n", line); | |||
| 457 | offset = 0; | |||
| 458 | } | |||
| 459 | offset += sprintf (line+offset, "%08x:", i); | |||
| 460 | } | |||
| 0 | 0 | - | 461 | else if ((i & 7) == 0) { |
| 462 | offset += sprintf (line+offset, " -"); | |||
| 463 | } | |||
| 464 | offset += sprintf (line+offset, " %02x", buffer[i] & 0xff); | |||
| 465 | } | |||
| 466 | ||||
| 467 | /* Add the last "chunk" of data. */ | |||
| 468 | from = (length - 1) % 16; | |||
| 469 | base = ((length - 1) / 16) * 16; | |||
| 470 | ||||
| 0 | 0 | - | 471 | for (i = from + 1; i < 16; i++) |
| 472 | offset += sprintf (line+offset, " "); | |||
| 0 | 0 | - | 473 | if (from < 8) |
| 474 | offset += sprintf (line+offset, " "); | |||
| 475 | offset += sprintf (line+offset, " - "); | |||
| 476 | ||||
| 0 | 0 | - | 477 | for (i = 0; i <= from; i++) { |
| 0 | 0 | - | 478 | if (buffer[base+i] >= 32 && buffer[base+i] <= 126) |
| 0 | - | 478 | T && T | |
| 0 | - | 478 | T && F | |
| 0 | - | 478 | F && _ | |
| 479 | line[offset++] = buffer[base+i]; | |||
| 480 | else | |||
| 481 | line[offset++] = '.'; | |||
| 482 | } | |||
| 483 | line[offset] = 0; | |||
| 484 | US_DEBUGP("%s\n", line); | |||
| 485 | offset = 0; | |||
| 486 | } | |||
| 487 | #endif | |||
| 488 | ||||
| ***TER 0% (0/140) of SOURCE FILE freecom.c | ||||