Newer
Older
debug("write10: start %lx blocks %x\n", start, blocks);
return ss->transport(srb, ss);
}
#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) {
strncpy((char *)vendor, "SMSC", max_vendor_len);
strncpy((char *)product, "Flash Media Cntrller",
max_product_len);
}
}
#endif /* CONFIG_USB_BIN_FIXUP */
unsigned long usb_stor_read(int device, lbaint_t blknr,
lbaint_t blkcnt, void *buffer)
lbaint_t start, blks;
uintptr_t buf_addr;
unsigned short smallblks;
struct usb_device *dev;
struct us_data *ss;
ccb *srb = &usb_ccb;
if (blkcnt == 0)
return 0;
device &= 0xff;
debug("\nusb_read: dev %d\n", device);
dev = usb_dev_desc[device].priv;
if (!dev) {
debug("%s: No device\n", __func__);
return 0;
ss = (struct us_data *)dev->privptr;
usb_disable_asynch(1); /* asynch transfer not allowed */
buf_addr = (uintptr_t)buffer;
debug("\nusb_read: dev %d startblk " LBAF ", blccnt " LBAF
" buffer %" PRIxPTR "\n", device, start, blks, buf_addr);
/* XXX need some comment here */
retry = 2;
srb->pdata = (unsigned char *)buf_addr;
if (blks > USB_MAX_XFER_BLK)
smallblks = USB_MAX_XFER_BLK;
else
smallblks = (unsigned short) blks;
if (smallblks == USB_MAX_XFER_BLK)
srb->datalen = usb_dev_desc[device].blksz * smallblks;
srb->pdata = (unsigned char *)buf_addr;
if (usb_read_10(srb, ss, start, smallblks)) {
debug("Read ERROR\n");
usb_request_sense(srb, ss);
start += smallblks;
blks -= smallblks;
buf_addr += srb->datalen;
} while (blks != 0);
ss->flags &= ~USB_READY;
debug("usb_read: end startblk " LBAF
", blccnt %x buffer %" PRIxPTR "\n",
start, smallblks, buf_addr);
if (blkcnt >= USB_MAX_XFER_BLK)
unsigned long usb_stor_write(int device, lbaint_t blknr,
lbaint_t blkcnt, const void *buffer)
lbaint_t start, blks;
uintptr_t buf_addr;
unsigned short smallblks;
struct usb_device *dev;
struct us_data *ss;
ccb *srb = &usb_ccb;
if (blkcnt == 0)
return 0;
device &= 0xff;
/* Setup device */
debug("\nusb_write: dev %d\n", device);
dev = usb_dev_desc[device].priv;
if (!dev)
return 0;
ss = (struct us_data *)dev->privptr;
usb_disable_asynch(1); /* asynch transfer not allowed */
srb->lun = usb_dev_desc[device].lun;
buf_addr = (uintptr_t)buffer;
start = blknr;
blks = blkcnt;
debug("\nusb_write: dev %d startblk " LBAF ", blccnt " LBAF
" buffer %" PRIxPTR "\n", device, start, blks, buf_addr);
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;
if (blks > USB_MAX_XFER_BLK)
smallblks = USB_MAX_XFER_BLK;
else
smallblks = (unsigned short) blks;
retry_it:
if (smallblks == USB_MAX_XFER_BLK)
usb_show_progress();
srb->datalen = usb_dev_desc[device].blksz * smallblks;
srb->pdata = (unsigned char *)buf_addr;
if (usb_write_10(srb, ss, start, smallblks)) {
debug("Write ERROR\n");
usb_request_sense(srb, ss);
if (retry--)
goto retry_it;
blkcnt -= blks;
break;
}
start += smallblks;
blks -= smallblks;
buf_addr += srb->datalen;
} while (blks != 0);
ss->flags &= ~USB_READY;
debug("usb_write: end startblk " LBAF ", blccnt %x buffer %"
PRIxPTR "\n", start, smallblks, buf_addr);
usb_disable_asynch(0); /* asynch transfer allowed */
if (blkcnt >= USB_MAX_XFER_BLK)
/* Probe to see if a new device is actually a Storage device */
int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
struct us_data *ss)
struct usb_endpoint_descriptor *ep_desc;
unsigned int flags = 0;
int protocol = 0;
int subclass = 0;
/* let's examine the device now */
iface = &dev->config.if_desc[ifnum];
#if 0
/* this is the place to patch some storage devices */
debug("iVendor %X iProduct %X\n", dev->descriptor.idVendor,
dev->descriptor.idProduct);
if ((dev->descriptor.idVendor) == 0x066b &&
(dev->descriptor.idProduct) == 0x0103) {
debug("patched for E-USB\n");
protocol = US_PR_CB;
subclass = US_SC_UFI; /* an assumption */
}
#endif
if (dev->descriptor.bDeviceClass != 0 ||
iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
iface->desc.bInterfaceSubClass < US_SC_MIN ||
iface->desc.bInterfaceSubClass > US_SC_MAX) {
debug("Not mass storage\n");
/* if it's not a mass storage, we go no further */
return 0;
}
memset(ss, 0, sizeof(struct us_data));
debug("\n\nUSB Mass Storage device detected\n");
/* 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 {
ss->subclass = iface->desc.bInterfaceSubClass;
ss->protocol = iface->desc.bInterfaceProtocol;
}
/* set the handler pointers based on the protocol */
debug("Transport: ");
debug("Control/Bulk\n");
ss->transport = usb_stor_CB_transport;
ss->transport_reset = usb_stor_CB_reset;
break;
case US_PR_CBI:
debug("Control/Bulk/Interrupt\n");
ss->transport = usb_stor_CB_transport;
ss->transport_reset = usb_stor_CB_reset;
break;
debug("Bulk/Bulk/Bulk\n");
ss->transport = usb_stor_BBB_transport;
ss->transport_reset = usb_stor_BBB_reset;
break;
printf("USB Storage Transport unknown / not yet implemented\n");
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.
*/
for (i = 0; i < iface->desc.bNumEndpoints; i++) {
ep_desc = &iface->ep_desc[i];
if ((ep_desc->bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
if (ep_desc->bEndpointAddress & USB_DIR_IN)
ss->ep_in = ep_desc->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
ep_desc->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
}
/* is it an interrupt endpoint? */
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;
debug("Endpoints In %d Out %d Int %d\n",
ss->ep_in, ss->ep_out, ss->ep_int);
/* Do some basic sanity checks, and bail if we find a problem */
if (usb_set_interface(dev, iface->desc.bInterfaceNumber, 0) ||
!ss->ep_in || !ss->ep_out ||
(ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
debug("Problems with device\n");
/* We only handle certain protocols. Currently, these are
* the only ones.
* The SFF8070 accepts the requests used in u-boot
if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI &&
ss->subclass != US_SC_8070) {
printf("Sorry, protocol %d not yet supported.\n", ss->subclass);
if (ss->ep_int) {
/* we had found an interrupt endpoint, prepare irq pipe
* set up the IRQ pipe and handler
*/
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);
int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
block_dev_desc_t *dev_desc)
ALLOC_CACHE_ALIGN_BUFFER(u32, cap, 2);
ALLOC_CACHE_ALIGN_BUFFER(u8, usb_stor_buf, 36);
u32 capacity, blksz;
ccb *pccb = &usb_ccb;
pccb->pdata = usb_stor_buf;
dev_desc->target = dev->devnum;
pccb->lun = dev_desc->lun;
debug(" address %d\n", dev_desc->target);
if (usb_inquiry(pccb, ss)) {
debug("%s: usb_inquiry() failed\n", __func__);
perq = usb_stor_buf[0];
modi = usb_stor_buf[1];
/*
* Skip unknown devices (0x1f) and enclosure service devices (0x0d),
* they would not respond to test_unit_ready .
*/
if (((perq & 0x1f) == 0x1f) || ((perq & 0x1f) == 0x0d)) {
debug("%s: unknown/unsupported device\n", __func__);
if ((modi&0x80) == 0x80) {
/* drive is removable */
dev_desc->removable = 1;
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);
dev_desc->vendor[8] = 0;
dev_desc->product[16] = 0;
dev_desc->revision[4] = 0;
#ifdef CONFIG_USB_BIN_FIXUP
usb_bin_fixup(dev->descriptor, (uchar *)dev_desc->vendor,
(uchar *)dev_desc->product);
#endif /* CONFIG_USB_BIN_FIXUP */
debug("ISO Vers %X, Response Data %X\n", usb_stor_buf[2],
usb_stor_buf[3]);
if (usb_test_unit_ready(pccb, ss)) {
printf("Device NOT ready\n"
" Request Sense returned %02X %02X %02X\n",
pccb->sense_buf[2], pccb->sense_buf[12],
pccb->sense_buf[13]);
if (dev_desc->removable == 1) {
dev_desc->type = perq;
pccb->pdata = (unsigned char *)cap;
memset(pccb->pdata, 0, 8);
if (usb_read_capacity(pccb, ss) != 0) {
cap[0] = 2880;
cap[1] = 0x200;
ss->flags &= ~USB_READY;
debug("Read Capacity returns: 0x%08x, 0x%08x\n", cap[0], cap[1]);
if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */
cap[0] >>= 16;
cap[0] = cpu_to_be32(cap[0]);
cap[1] = cpu_to_be32(cap[1]);
#endif
capacity = be32_to_cpu(cap[0]) + 1;
blksz = be32_to_cpu(cap[1]);
debug("Capacity = 0x%08x, blocksz = 0x%08x\n", capacity, blksz);
dev_desc->lba = capacity;
dev_desc->blksz = blksz;
dev_desc->log2blksz = LOG2(dev_desc->blksz);
dev_desc->type = perq;
debug(" address %d\n", dev_desc->target);
debug("partype: %d\n", dev_desc->part_type);
debug("partype: %d\n", dev_desc->part_type);
#ifdef CONFIG_DM_USB
static int usb_mass_storage_probe(struct udevice *dev)
{
struct usb_device *udev = dev_get_parent_priv(dev);
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
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 */
};
U_BOOT_USB_DEVICE(usb_mass_storage, mass_storage_id_table);