Skip to content
Snippets Groups Projects
usb_storage.c 34.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    	/* 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->bInterfaceSubClass;
    		ss->protocol = iface->bInterfaceProtocol;
    	}
    
    	/* set the handler pointers based on the protocol */
    	USB_STOR_PRINTF("Transport: ");
    	switch (ss->protocol) {
    	case US_PR_CB:
    		USB_STOR_PRINTF("Control/Bulk\n");
    		ss->transport = usb_stor_CB_transport;
    		ss->transport_reset = usb_stor_CB_reset;
    		break;
    
    	case US_PR_CBI:
    		USB_STOR_PRINTF("Control/Bulk/Interrupt\n");
    		ss->transport = usb_stor_CB_transport;
    		ss->transport_reset = usb_stor_CB_reset;
    		break;
    
    	case US_PR_BULK:
    		USB_STOR_PRINTF("Bulk/Bulk/Bulk\n");
    		ss->transport = usb_stor_BBB_transport;
    		ss->transport_reset = usb_stor_BBB_reset;
    		break;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	default:
    
    		printf("USB Storage Transport unknown / not yet implemented\n");
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		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->bNumEndpoints; i++) {
    		/* is it an BULK endpoint? */
    		if ((iface->ep_desc[i].bmAttributes &  USB_ENDPOINT_XFERTYPE_MASK)
    		    == USB_ENDPOINT_XFER_BULK) {
    			if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN)
    				ss->ep_in = iface->ep_desc[i].bEndpointAddress &
    					USB_ENDPOINT_NUMBER_MASK;
    			else
    				ss->ep_out = iface->ep_desc[i].bEndpointAddress &
    					USB_ENDPOINT_NUMBER_MASK;
    		}
    
    		/* is it an interrupt endpoint? */
    		if ((iface->ep_desc[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
    		    == USB_ENDPOINT_XFER_INT) {
    			ss->ep_int = iface->ep_desc[i].bEndpointAddress &
    				USB_ENDPOINT_NUMBER_MASK;
    			ss->irqinterval = iface->ep_desc[i].bInterval;
    		}
    	}
    	USB_STOR_PRINTF("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->bInterfaceNumber, 0) ||
    	    !ss->ep_in || !ss->ep_out ||
    	    (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
    		USB_STOR_PRINTF("Problems with device\n");
    		return 0;
    	}
    	/* set class specific stuff */
    
    	/* We only handle certain protocols.  Currently, these are
    	 * the only ones.
    
    	 * The SFF8070 accepts the requests used in u-boot
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	 */
    
    	if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI &&
    	    ss->subclass != US_SC_8070) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		printf("Sorry, protocol %d not yet supported.\n",ss->subclass);
    		return 0;
    	}
    
    	if(ss->ep_int) { /* we had found an interrupt endpoint, prepare irq pipe */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		/* 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);
    		dev->irq_handle=usb_stor_irq;
    	}
    
    	dev->privptr=(void *)ss;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	return 1;
    }
    
    int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t *dev_desc)
    {
    	unsigned char perq,modi;
    	unsigned long cap[2];
    	unsigned long *capacity,*blksz;
    	ccb *pccb=&usb_ccb;
    
    
    	/* For some mysterious reason the 256MB flash disk of Ours Technology, Inc
    	 * doesn't survive this reset */
    	if (dev->descriptor.idVendor != 0xea0 || dev->descriptor.idProduct != 0x6828)
    		ss->transport_reset(ss);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	pccb->pdata=usb_stor_buf;
    
    	dev_desc->target=dev->devnum;
    	pccb->lun=dev_desc->lun;
    	USB_STOR_PRINTF(" address %d\n",dev_desc->target);
    
    	if(usb_inquiry(pccb,ss))
    		return -1;
    	perq=usb_stor_buf[0];
    	modi=usb_stor_buf[1];
    	if((perq & 0x1f)==0x1f) {
    		return 0; /* skip unknown devices */
    	}
    	if((modi&0x80)==0x80) {/* drive is removable */
    		dev_desc->removable=1;
    	}
    	memcpy(&dev_desc->vendor[0], &usb_stor_buf[8], 8);
    	memcpy(&dev_desc->product[0], &usb_stor_buf[16], 16);
    	memcpy(&dev_desc->revision[0], &usb_stor_buf[32], 4);
    	dev_desc->vendor[8]=0;
    	dev_desc->product[16]=0;
    	dev_desc->revision[4]=0;
    	USB_STOR_PRINTF("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;
    			return 1;
    		}
    		else
    			return 0;
    	}
    	pccb->pdata=(unsigned char *)&cap[0];
    	memset(pccb->pdata,0,8);
    	if(usb_read_capacity(pccb,ss)!=0) {
    		printf("READ_CAP ERROR\n");
    		cap[0]=2880;
    		cap[1]=0x200;
    	}
    	USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n",cap[0],cap[1]);
    #if 0
    	if(cap[0]>(0x200000 * 10)) /* greater than 10 GByte */
    		cap[0]>>=16;
    #endif
    
    #ifdef LITTLEENDIAN
    	cap[0] = ((unsigned long)(
    		(((unsigned long)(cap[0]) & (unsigned long)0x000000ffUL) << 24) |
    		(((unsigned long)(cap[0]) & (unsigned long)0x0000ff00UL) <<  8) |
    		(((unsigned long)(cap[0]) & (unsigned long)0x00ff0000UL) >>  8) |
    		(((unsigned long)(cap[0]) & (unsigned long)0xff000000UL) >> 24) ));
    	cap[1] = ((unsigned long)(
    		(((unsigned long)(cap[1]) & (unsigned long)0x000000ffUL) << 24) |
    		(((unsigned long)(cap[1]) & (unsigned long)0x0000ff00UL) <<  8) |
    		(((unsigned long)(cap[1]) & (unsigned long)0x00ff0000UL) >>  8) |
    		(((unsigned long)(cap[1]) & (unsigned long)0xff000000UL) >> 24) ));
    #endif
    	/* this assumes bigendian! */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	cap[0]+=1;
    	capacity=&cap[0];
    	blksz=&cap[1];
    	USB_STOR_PRINTF("Capacity = 0x%lx, blocksz = 0x%lx\n",*capacity,*blksz);
    	dev_desc->lba=*capacity;
    	dev_desc->blksz=*blksz;
    	dev_desc->type=perq;
    	USB_STOR_PRINTF(" address %d\n",dev_desc->target);
    	USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);
    
    	init_part(dev_desc);
    
    	USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);
    	return 1;
    }
    
    #endif /* CONFIG_USB_STORAGE */
    
    #endif /* CFG_CMD_USB */