* (C) Copyright 2001 Denis Peter, MPL AG Switzerland
*
* For BBB support (C) Copyright 2003
- * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
+ * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
*
* BBB support based on /sys/dev/usb/umass.c from
* FreeBSD.
struct us_data *ss);
unsigned long usb_stor_read(int device, unsigned long blknr,
unsigned long blkcnt, void *buffer);
+unsigned long usb_stor_write(int device, unsigned long blknr,
+ unsigned long blkcnt, const void *buffer);
struct usb_device * usb_get_dev_index(int index);
void uhci_show_temp_int_td(void);
block_dev_desc_t *usb_stor_get_dev(int index)
{
- return (index < USB_MAX_STOR_DEV) ? &usb_dev_desc[index] : NULL;
+ return (index < usb_max_devs) ? &usb_dev_desc[index] : NULL;
}
void usb_show_progress(void)
{
- printf(".");
+ debug(".");
}
/*******************************************************************************
return 1;
}
+static unsigned int usb_get_max_lun(struct us_data *us)
+{
+ int len;
+ unsigned char result;
+ len = usb_control_msg(us->pusb_dev,
+ usb_rcvctrlpipe(us->pusb_dev, 0),
+ US_BBB_GET_MAX_LUN,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ 0, us->ifnum,
+ &result, sizeof(result),
+ USB_CNTL_TIMEOUT * 5);
+ USB_STOR_PRINTF("Get Max LUN -> len = %i, result = %i\n",
+ len, (int) result);
+ return (len > 0) ? result : 0;
+}
+
/*******************************************************************************
* scan the usb and reports device info
* to the user if mode = 1
for (i = 0; i < USB_MAX_STOR_DEV; i++) {
memset(&usb_dev_desc[i], 0, sizeof(block_dev_desc_t));
- usb_dev_desc[i].target = 0xff;
usb_dev_desc[i].if_type = IF_TYPE_USB;
usb_dev_desc[i].dev = i;
usb_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
+ usb_dev_desc[i].target = 0xff;
+ usb_dev_desc[i].type = DEV_TYPE_UNKNOWN;
usb_dev_desc[i].block_read = usb_stor_read;
+ usb_dev_desc[i].block_write = usb_stor_write;
}
usb_max_devs = 0;
break; /* no more devices avaiable */
if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
- /* ok, it is a storage devices
- * get info and fill it in
+ /* OK, it's a storage device. Iterate over its LUNs
+ * and populate `usb_dev_desc'.
*/
- if (usb_stor_get_info(dev, &usb_stor[usb_max_devs],
- &usb_dev_desc[usb_max_devs]))
+ int lun, max_lun, start = usb_max_devs;
+
+ max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
+ for (lun = 0;
+ lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
+ lun++) {
+ usb_dev_desc[usb_max_devs].lun = lun;
+ if (usb_stor_get_info(dev, &usb_stor[start],
+ &usb_dev_desc[usb_max_devs]) == 1) {
usb_max_devs++;
+ }
+ }
}
/* if storage device */
if (usb_max_devs == USB_MAX_STOR_DEV) {
do {
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_INQUIRY;
+ srb->cmd[1] = srb->lun << 5;
srb->cmd[4] = 36;
srb->datalen = 36;
srb->cmdlen = 12;
USB_STOR_PRINTF("inquiry returns %d\n", i);
if (i == 0)
break;
- } while (retry--);
+ } while (--retry);
if (!retry) {
printf("error in inquiry\n");
ptr = (char *)srb->pdata;
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_REQ_SENSE;
+ srb->cmd[1] = srb->lun << 5;
srb->cmd[4] = 18;
srb->datalen = 18;
srb->pdata = &srb->sense_buf[0];
do {
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_TST_U_RDY;
+ srb->cmd[1] = srb->lun << 5;
srb->datalen = 0;
srb->cmdlen = 12;
if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
do {
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_RD_CAPAC;
+ srb->cmd[1] = srb->lun << 5;
srb->datalen = 8;
srb->cmdlen = 12;
if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
{
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_READ10;
+ srb->cmd[1] = srb->lun << 5;
srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
return ss->transport(srb, ss);
}
+static int usb_write_10(ccb *srb, struct us_data *ss, unsigned long start,
+ unsigned short blocks)
+{
+ memset(&srb->cmd[0], 0, 12);
+ srb->cmd[0] = SCSI_WRITE10;
+ srb->cmd[1] = srb->lun << 5;
+ srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
+ srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
+ srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
+ srb->cmd[5] = ((unsigned char) (start)) & 0xff;
+ srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
+ srb->cmd[8] = (unsigned char) blocks & 0xff;
+ srb->cmdlen = 12;
+ USB_STOR_PRINTF("write10: start %lx blocks %x\n", start, blocks);
+ return ss->transport(srb, ss);
+}
+
#ifdef CONFIG_USB_BIN_FIXUP
/*
usb_disable_asynch(0); /* asynch transfer allowed */
if (blkcnt >= USB_MAX_READ_BLK)
- printf("\n");
+ debug("\n");
return blkcnt;
}
+#define USB_MAX_WRITE_BLK 20
+
+unsigned long usb_stor_write(int device, unsigned long blknr,
+ unsigned long blkcnt, const void *buffer)
+{
+ unsigned long start, blks, buf_addr;
+ unsigned short smallblks;
+ struct usb_device *dev;
+ int retry, i;
+ ccb *srb = &usb_ccb;
+
+ if (blkcnt == 0)
+ return 0;
+
+ device &= 0xff;
+ /* Setup device */
+ USB_STOR_PRINTF("\nusb_write: dev %d \n", device);
+ dev = NULL;
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ dev = usb_get_dev_index(i);
+ if (dev == NULL)
+ return 0;
+ if (dev->devnum == usb_dev_desc[device].target)
+ break;
+ }
+
+ usb_disable_asynch(1); /* asynch transfer not allowed */
+
+ srb->lun = usb_dev_desc[device].lun;
+ buf_addr = (unsigned long)buffer;
+ start = blknr;
+ blks = blkcnt;
+ if (usb_test_unit_ready(srb, (struct us_data *)dev->privptr)) {
+ printf("Device NOT ready\n Request Sense returned %02X %02X"
+ " %02X\n", srb->sense_buf[2], srb->sense_buf[12],
+ srb->sense_buf[13]);
+ return 0;
+ }
+
+ USB_STOR_PRINTF("\nusb_write: dev %d startblk %lx, blccnt %lx"
+ " buffer %lx\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_WRITE_BLK)
+ smallblks = USB_MAX_WRITE_BLK;
+ else
+ smallblks = (unsigned short) blks;
+retry_it:
+ if (smallblks == USB_MAX_WRITE_BLK)
+ usb_show_progress();
+ srb->datalen = usb_dev_desc[device].blksz * smallblks;
+ srb->pdata = (unsigned char *)buf_addr;
+ if (usb_write_10(srb, (struct us_data *)dev->privptr, start,
+ smallblks)) {
+ USB_STOR_PRINTF("Write ERROR\n");
+ usb_request_sense(srb, (struct us_data *)dev->privptr);
+ if (retry--)
+ goto retry_it;
+ blkcnt -= blks;
+ break;
+ }
+ start += smallblks;
+ blks -= smallblks;
+ buf_addr += srb->datalen;
+ } while (blks != 0);
+
+ USB_STOR_PRINTF("usb_write: end startblk %lx, blccnt %x buffer %lx\n",
+ start, smallblks, buf_addr);
+
+ usb_disable_asynch(0); /* asynch transfer allowed */
+ if (blkcnt >= USB_MAX_WRITE_BLK)
+ debug("\n");
+ return blkcnt;
+
+}
/* 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_interface_descriptor *iface;
+ struct usb_interface *iface;
int i;
unsigned int flags = 0;
#endif
if (dev->descriptor.bDeviceClass != 0 ||
- iface->bInterfaceClass != USB_CLASS_MASS_STORAGE ||
- iface->bInterfaceSubClass < US_SC_MIN ||
- iface->bInterfaceSubClass > US_SC_MAX) {
+ iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
+ iface->desc.bInterfaceSubClass < US_SC_MIN ||
+ iface->desc.bInterfaceSubClass > US_SC_MAX) {
/* if it's not a mass storage, we go no further */
return 0;
}
ss->subclass = subclass;
ss->protocol = protocol;
} else {
- ss->subclass = iface->bInterfaceSubClass;
- ss->protocol = iface->bInterfaceProtocol;
+ ss->subclass = iface->desc.bInterfaceSubClass;
+ ss->protocol = iface->desc.bInterfaceProtocol;
}
/* set the handler pointers based on the protocol */
* An optional interrupt is OK (necessary for CBI protocol).
* We will ignore any others.
*/
- for (i = 0; i < iface->bNumEndpoints; i++) {
+ for (i = 0; i < iface->desc.bNumEndpoints; i++) {
/* is it an BULK endpoint? */
if ((iface->ep_desc[i].bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
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->bInterfaceNumber, 0) ||
+ if (usb_set_interface(dev, iface->desc.bInterfaceNumber, 0) ||
!ss->ep_in || !ss->ep_out ||
(ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
USB_STOR_PRINTF("Problems with device\n");