0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/module.h>
0018 #include <scsi/scsi.h>
0019 #include <scsi/scsi_cmnd.h>
0020
0021 #include "usb.h"
0022 #include "transport.h"
0023 #include "protocol.h"
0024 #include "debug.h"
0025 #include "scsiglue.h"
0026
0027 #define DRV_NAME "ums-freecom"
0028
0029 MODULE_DESCRIPTION("Driver for Freecom USB/IDE adaptor");
0030 MODULE_AUTHOR("David Brown <usb-storage@davidb.org>");
0031 MODULE_LICENSE("GPL");
0032 MODULE_IMPORT_NS(USB_STORAGE);
0033
0034 #ifdef CONFIG_USB_STORAGE_DEBUG
0035 static void pdump(struct us_data *us, void *ibuffer, int length);
0036 #endif
0037
0038
0039 #define ERR_STAT 0x01
0040 #define DRQ_STAT 0x08
0041
0042
0043 struct freecom_cb_wrap {
0044 u8 Type;
0045 u8 Timeout;
0046 u8 Atapi[12];
0047 u8 Filler[50];
0048 };
0049
0050 struct freecom_xfer_wrap {
0051 u8 Type;
0052 u8 Timeout;
0053 __le32 Count;
0054 u8 Pad[58];
0055 } __attribute__ ((packed));
0056
0057 struct freecom_ide_out {
0058 u8 Type;
0059 u8 Pad;
0060 __le16 Value;
0061 u8 Pad2[60];
0062 };
0063
0064 struct freecom_ide_in {
0065 u8 Type;
0066 u8 Pad[63];
0067 };
0068
0069 struct freecom_status {
0070 u8 Status;
0071 u8 Reason;
0072 __le16 Count;
0073 u8 Pad[60];
0074 };
0075
0076
0077
0078
0079
0080 #define FCM_INT_STATUS 0x02
0081 #define FCM_STATUS_BUSY 0x80
0082
0083
0084
0085
0086
0087 #define FCM_PACKET_ATAPI 0x21
0088 #define FCM_PACKET_STATUS 0x20
0089
0090
0091
0092
0093
0094 #define FCM_PACKET_INPUT 0x81
0095
0096
0097 #define FCM_PACKET_OUTPUT 0x01
0098
0099
0100
0101
0102
0103 #define FCM_PACKET_IDE_WRITE 0x40
0104 #define FCM_PACKET_IDE_READ 0xC0
0105
0106
0107 #define FCM_PACKET_LENGTH 64
0108 #define FCM_STATUS_PACKET_LENGTH 4
0109
0110 static int init_freecom(struct us_data *us);
0111
0112
0113
0114
0115
0116 #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
0117 vendorName, productName, useProtocol, useTransport, \
0118 initFunction, flags) \
0119 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
0120 .driver_info = (flags) }
0121
0122 static struct usb_device_id freecom_usb_ids[] = {
0123 # include "unusual_freecom.h"
0124 { }
0125 };
0126 MODULE_DEVICE_TABLE(usb, freecom_usb_ids);
0127
0128 #undef UNUSUAL_DEV
0129
0130
0131
0132
0133 #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
0134 vendor_name, product_name, use_protocol, use_transport, \
0135 init_function, Flags) \
0136 { \
0137 .vendorName = vendor_name, \
0138 .productName = product_name, \
0139 .useProtocol = use_protocol, \
0140 .useTransport = use_transport, \
0141 .initFunction = init_function, \
0142 }
0143
0144 static struct us_unusual_dev freecom_unusual_dev_list[] = {
0145 # include "unusual_freecom.h"
0146 { }
0147 };
0148
0149 #undef UNUSUAL_DEV
0150
0151 static int
0152 freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
0153 unsigned int ipipe, unsigned int opipe, int count)
0154 {
0155 struct freecom_xfer_wrap *fxfr =
0156 (struct freecom_xfer_wrap *) us->iobuf;
0157 int result;
0158
0159 fxfr->Type = FCM_PACKET_INPUT | 0x00;
0160 fxfr->Timeout = 0;
0161 fxfr->Count = cpu_to_le32 (count);
0162 memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
0163
0164 usb_stor_dbg(us, "Read data Freecom! (c=%d)\n", count);
0165
0166
0167 result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
0168 FCM_PACKET_LENGTH, NULL);
0169 if (result != USB_STOR_XFER_GOOD) {
0170 usb_stor_dbg(us, "Freecom readdata transport error\n");
0171 return USB_STOR_TRANSPORT_ERROR;
0172 }
0173
0174
0175 usb_stor_dbg(us, "Start of read\n");
0176 result = usb_stor_bulk_srb(us, ipipe, srb);
0177 usb_stor_dbg(us, "freecom_readdata done!\n");
0178
0179 if (result > USB_STOR_XFER_SHORT)
0180 return USB_STOR_TRANSPORT_ERROR;
0181 return USB_STOR_TRANSPORT_GOOD;
0182 }
0183
0184 static int
0185 freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
0186 int unsigned ipipe, unsigned int opipe, int count)
0187 {
0188 struct freecom_xfer_wrap *fxfr =
0189 (struct freecom_xfer_wrap *) us->iobuf;
0190 int result;
0191
0192 fxfr->Type = FCM_PACKET_OUTPUT | 0x00;
0193 fxfr->Timeout = 0;
0194 fxfr->Count = cpu_to_le32 (count);
0195 memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
0196
0197 usb_stor_dbg(us, "Write data Freecom! (c=%d)\n", count);
0198
0199
0200 result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
0201 FCM_PACKET_LENGTH, NULL);
0202 if (result != USB_STOR_XFER_GOOD) {
0203 usb_stor_dbg(us, "Freecom writedata transport error\n");
0204 return USB_STOR_TRANSPORT_ERROR;
0205 }
0206
0207
0208 usb_stor_dbg(us, "Start of write\n");
0209 result = usb_stor_bulk_srb(us, opipe, srb);
0210
0211 usb_stor_dbg(us, "freecom_writedata done!\n");
0212 if (result > USB_STOR_XFER_SHORT)
0213 return USB_STOR_TRANSPORT_ERROR;
0214 return USB_STOR_TRANSPORT_GOOD;
0215 }
0216
0217
0218
0219
0220
0221 static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
0222 {
0223 struct freecom_cb_wrap *fcb;
0224 struct freecom_status *fst;
0225 unsigned int ipipe, opipe;
0226 int result;
0227 unsigned int partial;
0228 int length;
0229
0230 fcb = (struct freecom_cb_wrap *) us->iobuf;
0231 fst = (struct freecom_status *) us->iobuf;
0232
0233 usb_stor_dbg(us, "Freecom TRANSPORT STARTED\n");
0234
0235
0236 opipe = us->send_bulk_pipe;
0237 ipipe = us->recv_bulk_pipe;
0238
0239
0240 fcb->Type = FCM_PACKET_ATAPI | 0x00;
0241 fcb->Timeout = 0;
0242 memcpy (fcb->Atapi, srb->cmnd, 12);
0243 memset (fcb->Filler, 0, sizeof (fcb->Filler));
0244
0245 US_DEBUG(pdump(us, srb->cmnd, 12));
0246
0247
0248 result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
0249 FCM_PACKET_LENGTH, NULL);
0250
0251
0252
0253
0254
0255
0256 if (result != USB_STOR_XFER_GOOD) {
0257 usb_stor_dbg(us, "freecom transport error\n");
0258 return USB_STOR_TRANSPORT_ERROR;
0259 }
0260
0261
0262
0263
0264
0265 result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
0266 FCM_STATUS_PACKET_LENGTH, &partial);
0267 usb_stor_dbg(us, "foo Status result %d %u\n", result, partial);
0268 if (result != USB_STOR_XFER_GOOD)
0269 return USB_STOR_TRANSPORT_ERROR;
0270
0271 US_DEBUG(pdump(us, (void *)fst, partial));
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282 while (fst->Status & FCM_STATUS_BUSY) {
0283 usb_stor_dbg(us, "20 second USB/ATAPI bridge TIMEOUT occurred!\n");
0284 usb_stor_dbg(us, "fst->Status is %x\n", fst->Status);
0285
0286
0287 fcb->Type = FCM_PACKET_STATUS;
0288 fcb->Timeout = 0;
0289 memset (fcb->Atapi, 0, sizeof(fcb->Atapi));
0290 memset (fcb->Filler, 0, sizeof (fcb->Filler));
0291
0292
0293 result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
0294 FCM_PACKET_LENGTH, NULL);
0295
0296
0297
0298
0299
0300
0301 if (result != USB_STOR_XFER_GOOD) {
0302 usb_stor_dbg(us, "freecom transport error\n");
0303 return USB_STOR_TRANSPORT_ERROR;
0304 }
0305
0306
0307 result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
0308 FCM_STATUS_PACKET_LENGTH, &partial);
0309
0310 usb_stor_dbg(us, "bar Status result %d %u\n", result, partial);
0311 if (result != USB_STOR_XFER_GOOD)
0312 return USB_STOR_TRANSPORT_ERROR;
0313
0314 US_DEBUG(pdump(us, (void *)fst, partial));
0315 }
0316
0317 if (partial != 4)
0318 return USB_STOR_TRANSPORT_ERROR;
0319 if ((fst->Status & 1) != 0) {
0320 usb_stor_dbg(us, "operation failed\n");
0321 return USB_STOR_TRANSPORT_FAILED;
0322 }
0323
0324
0325
0326
0327
0328
0329 usb_stor_dbg(us, "Device indicates that it has %d bytes available\n",
0330 le16_to_cpu(fst->Count));
0331 usb_stor_dbg(us, "SCSI requested %d\n", scsi_bufflen(srb));
0332
0333
0334 switch (srb->cmnd[0]) {
0335 case INQUIRY:
0336 case REQUEST_SENSE:
0337 case MODE_SENSE:
0338 case MODE_SENSE_10:
0339 length = le16_to_cpu(fst->Count);
0340 break;
0341 default:
0342 length = scsi_bufflen(srb);
0343 }
0344
0345
0346 if (length > scsi_bufflen(srb)) {
0347 length = scsi_bufflen(srb);
0348 usb_stor_dbg(us, "Truncating request to match buffer length: %d\n",
0349 length);
0350 }
0351
0352
0353
0354
0355
0356
0357 switch (us->srb->sc_data_direction) {
0358 case DMA_FROM_DEVICE:
0359
0360 if (!length)
0361 break;
0362
0363
0364
0365
0366 if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
0367 usb_stor_dbg(us, "SCSI wants data, drive doesn't have any\n");
0368 return USB_STOR_TRANSPORT_FAILED;
0369 }
0370 result = freecom_readdata (srb, us, ipipe, opipe, length);
0371 if (result != USB_STOR_TRANSPORT_GOOD)
0372 return result;
0373
0374 usb_stor_dbg(us, "Waiting for status\n");
0375 result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
0376 FCM_PACKET_LENGTH, &partial);
0377 US_DEBUG(pdump(us, (void *)fst, partial));
0378
0379 if (partial != 4 || result > USB_STOR_XFER_SHORT)
0380 return USB_STOR_TRANSPORT_ERROR;
0381 if ((fst->Status & ERR_STAT) != 0) {
0382 usb_stor_dbg(us, "operation failed\n");
0383 return USB_STOR_TRANSPORT_FAILED;
0384 }
0385 if ((fst->Reason & 3) != 3) {
0386 usb_stor_dbg(us, "Drive seems still hungry\n");
0387 return USB_STOR_TRANSPORT_FAILED;
0388 }
0389 usb_stor_dbg(us, "Transfer happy\n");
0390 break;
0391
0392 case DMA_TO_DEVICE:
0393
0394 if (!length)
0395 break;
0396
0397
0398
0399
0400
0401 result = freecom_writedata (srb, us, ipipe, opipe, length);
0402 if (result != USB_STOR_TRANSPORT_GOOD)
0403 return result;
0404
0405 usb_stor_dbg(us, "Waiting for status\n");
0406 result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
0407 FCM_PACKET_LENGTH, &partial);
0408
0409 if (partial != 4 || result > USB_STOR_XFER_SHORT)
0410 return USB_STOR_TRANSPORT_ERROR;
0411 if ((fst->Status & ERR_STAT) != 0) {
0412 usb_stor_dbg(us, "operation failed\n");
0413 return USB_STOR_TRANSPORT_FAILED;
0414 }
0415 if ((fst->Reason & 3) != 3) {
0416 usb_stor_dbg(us, "Drive seems still hungry\n");
0417 return USB_STOR_TRANSPORT_FAILED;
0418 }
0419
0420 usb_stor_dbg(us, "Transfer happy\n");
0421 break;
0422
0423
0424 case DMA_NONE:
0425
0426 break;
0427
0428 default:
0429
0430 usb_stor_dbg(us, "freecom unimplemented direction: %d\n",
0431 us->srb->sc_data_direction);
0432
0433 return USB_STOR_TRANSPORT_FAILED;
0434 }
0435
0436 return USB_STOR_TRANSPORT_GOOD;
0437 }
0438
0439 static int init_freecom(struct us_data *us)
0440 {
0441 int result;
0442 char *buffer = us->iobuf;
0443
0444
0445
0446
0447
0448
0449 result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
0450 0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
0451 buffer[32] = '\0';
0452 usb_stor_dbg(us, "String returned from FC init is: %s\n", buffer);
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462 result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0463 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
0464 usb_stor_dbg(us, "result from activate reset is %d\n", result);
0465
0466
0467 msleep(250);
0468
0469
0470 result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0471 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
0472 usb_stor_dbg(us, "result from clear reset is %d\n", result);
0473
0474
0475 msleep(3 * 1000);
0476
0477 return USB_STOR_TRANSPORT_GOOD;
0478 }
0479
0480 static int usb_stor_freecom_reset(struct us_data *us)
0481 {
0482 printk (KERN_CRIT "freecom reset called\n");
0483
0484
0485 return FAILED;
0486 }
0487
0488 #ifdef CONFIG_USB_STORAGE_DEBUG
0489 static void pdump(struct us_data *us, void *ibuffer, int length)
0490 {
0491 static char line[80];
0492 int offset = 0;
0493 unsigned char *buffer = (unsigned char *) ibuffer;
0494 int i, j;
0495 int from, base;
0496
0497 offset = 0;
0498 for (i = 0; i < length; i++) {
0499 if ((i & 15) == 0) {
0500 if (i > 0) {
0501 offset += sprintf (line+offset, " - ");
0502 for (j = i - 16; j < i; j++) {
0503 if (buffer[j] >= 32 && buffer[j] <= 126)
0504 line[offset++] = buffer[j];
0505 else
0506 line[offset++] = '.';
0507 }
0508 line[offset] = 0;
0509 usb_stor_dbg(us, "%s\n", line);
0510 offset = 0;
0511 }
0512 offset += sprintf (line+offset, "%08x:", i);
0513 } else if ((i & 7) == 0) {
0514 offset += sprintf (line+offset, " -");
0515 }
0516 offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);
0517 }
0518
0519
0520 from = (length - 1) % 16;
0521 base = ((length - 1) / 16) * 16;
0522
0523 for (i = from + 1; i < 16; i++)
0524 offset += sprintf (line+offset, " ");
0525 if (from < 8)
0526 offset += sprintf (line+offset, " ");
0527 offset += sprintf (line+offset, " - ");
0528
0529 for (i = 0; i <= from; i++) {
0530 if (buffer[base+i] >= 32 && buffer[base+i] <= 126)
0531 line[offset++] = buffer[base+i];
0532 else
0533 line[offset++] = '.';
0534 }
0535 line[offset] = 0;
0536 usb_stor_dbg(us, "%s\n", line);
0537 offset = 0;
0538 }
0539 #endif
0540
0541 static struct scsi_host_template freecom_host_template;
0542
0543 static int freecom_probe(struct usb_interface *intf,
0544 const struct usb_device_id *id)
0545 {
0546 struct us_data *us;
0547 int result;
0548
0549 result = usb_stor_probe1(&us, intf, id,
0550 (id - freecom_usb_ids) + freecom_unusual_dev_list,
0551 &freecom_host_template);
0552 if (result)
0553 return result;
0554
0555 us->transport_name = "Freecom";
0556 us->transport = freecom_transport;
0557 us->transport_reset = usb_stor_freecom_reset;
0558 us->max_lun = 0;
0559
0560 result = usb_stor_probe2(us);
0561 return result;
0562 }
0563
0564 static struct usb_driver freecom_driver = {
0565 .name = DRV_NAME,
0566 .probe = freecom_probe,
0567 .disconnect = usb_stor_disconnect,
0568 .suspend = usb_stor_suspend,
0569 .resume = usb_stor_resume,
0570 .reset_resume = usb_stor_reset_resume,
0571 .pre_reset = usb_stor_pre_reset,
0572 .post_reset = usb_stor_post_reset,
0573 .id_table = freecom_usb_ids,
0574 .soft_unbind = 1,
0575 .no_dynamic_id = 1,
0576 };
0577
0578 module_usb_stor_driver(freecom_driver, freecom_host_template, DRV_NAME);