Exemple #1
0
s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun)
{
	s32 retval;

	if(lun >= dev->max_lun)
		return IPC_EINVAL;

	usleep(50);
	retval = __usbstorage_clearerrors(dev, lun);
	if (retval<0)
	{
		usb_log("Error __usbstorage_clearerrors: %i. Reset & retry again.\n",retval);
		USBStorage_Reset(dev);
		retval = __usbstorage_clearerrors(dev, lun);
		if (retval<0) usb_log("Error __usbstorage_clearerrors(2): %i.\n",retval);
		//return retval;
	}
	else usb_log("__usbstorage_clearerrors Ok\n");
	
	retval = USBStorage_Inquiry(dev,  lun);
	usb_log("USBStorage_Inquiry: %i\n", retval);
	
	retval = USBStorage_ReadCapacity(dev, lun, &dev->sector_size[lun], NULL);
	usb_log("USBStorage_ReadCapacity: %i    sector size: %i\n", retval,dev->sector_size[lun]);
	return retval;
}
/* perform 512 time the same read */
s32 USBStorage_Read_Stress(u32 sector, u32 numSectors, void *buffer)
{
    s32 retval;
    int i;
    if(__mounted != 1)
        return false;
    
    for(i=0;i<512;i++){
        retval = USBStorage_Read(&__usbfd, __lun, sector, numSectors, buffer);
        sector+=numSectors;
        if(retval == USBSTORAGE_ETIMEDOUT)
        {
            __mounted = 0;
            USBStorage_Close(&__usbfd);
        }
        if(retval < 0)
            return false;
    }
    return true;
    
}
// temp function before libfat is available */
s32 USBStorage_Try_Device(struct ehci_device *fd)
{
    int maxLun,j,retval;
    if(USBStorage_Open(&__usbfd, fd) < 0)
        return -EINVAL;
    
    maxLun = USBStorage_GetMaxLUN(&__usbfd);
    if(maxLun == USBSTORAGE_ETIMEDOUT)
        return -EINVAL;
    for(j = 0; j < maxLun; j++)
    {
        retval = USBStorage_MountLUN(&__usbfd, j);
        if(retval == USBSTORAGE_ETIMEDOUT)
        {
            USBStorage_Reset(&__usbfd);
            USBStorage_Close(&__usbfd);
            break;
        }
        
        if(retval < 0)
            continue;
        
        (*context.device)->GetDeviceVendor(context.device, &__vid);
        (*context.device)->GetDeviceProduct(context.device, &__pid);
        __mounted = 1;
        __lun = j;
        return 0;
    }
    return -EINVAL;
}
Exemple #3
0
s32 USBStorage_Open(ehci_device_data * device_data) {
	s32 retval = -1;
	u8 conf, *max_lun = NULL;
	u32 iConf, iInterface, iEp;
	static usb_devdesc udd;
	usb_configurationdesc *ucd;
	usb_interfacedesc *uid;
	usb_endpointdesc *ued;
	
	struct ehci_hcd * ehci = device_data->__ehci;
	usbstorage_handle *dev = &device_data->__usbfd;
	struct ehci_device *fd = device_data->__dev;

	device_data->__lun = 16; // select bad LUN

	max_lun = USB_Alloc(1);
	if (max_lun == NULL) return -ENOMEM;

	memset(dev, 0, sizeof (*dev));

	dev->tag = TAG_START;
	dev->usb_fd = fd;


	retval = USB_GetDescriptors(ehci, dev->usb_fd, &udd);

#ifdef MEM_PRINT
	s_printf("USBStorage_Open(): USB_GetDescriptors %i\n", retval);
#ifdef MEM_PRINT
	log_status(ehci, "after USB_GetDescriptors");
#endif

#endif

	if (retval < 0)
		goto free_and_return;

	/*
	// test device changed without unmount (prevent device write corruption)
	if (ums_init_done) {
		if (my_memcmp((void *) &_old_udd, (void *) &udd, sizeof (usb_devdesc) - 4)) {
			USB_Free(max_lun);
			USB_FreeDescriptors(&udd);
#ifdef MEM_PRINT
			s_printf("USBStorage_Open(): device changed!!!\n");

#endif
			return -ENODEV;
		}
	}
	 */ 
	_old_udd = udd;
	try_status = -128;
	for (iConf = 0; iConf < udd.bNumConfigurations; iConf++) {
		ucd = &udd.configurations[iConf];
		for (iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++) {
			uid = &ucd->interfaces[iInterface];
			//      debug_printf("interface %d, class:%x subclass %x protocol %x\n",iInterface,uid->bInterfaceClass,uid->bInterfaceSubClass, uid->bInterfaceProtocol);
			if (uid->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
					(uid->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS
					|| uid->bInterfaceSubClass == MASS_STORAGE_RBC_COMMANDS
					|| uid->bInterfaceSubClass == MASS_STORAGE_ATA_COMMANDS
					|| uid->bInterfaceSubClass == MASS_STORAGE_QIC_COMMANDS
					|| uid->bInterfaceSubClass == MASS_STORAGE_UFI_COMMANDS
					|| uid->bInterfaceSubClass == MASS_STORAGE_SFF8070_COMMANDS) &&
					uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY && uid->bNumEndpoints >= 2) {

				dev->ata_protocol = 0;
				if (uid->bInterfaceSubClass != MASS_STORAGE_SCSI_COMMANDS || uid->bInterfaceSubClass != MASS_STORAGE_RBC_COMMANDS)
					dev->ata_protocol = 1;

#ifdef MEM_PRINT
				s_printf("USBStorage_Open(): interface subclass %i ata_prot %i \n", uid->bInterfaceSubClass, dev->ata_protocol);

#endif
				dev->ep_in = dev->ep_out = 0;
				for (iEp = 0; iEp < uid->bNumEndpoints; iEp++) {
					ued = &uid->endpoints[iEp];
					if (ued->bmAttributes != USB_ENDPOINT_BULK)
						continue;

					if (ued->bEndpointAddress & USB_ENDPOINT_IN)
						dev->ep_in = ued->bEndpointAddress;
					else
						dev->ep_out = ued->bEndpointAddress;
				}
				if (dev->ep_in != 0 && dev->ep_out != 0) {
					dev->configuration = ucd->bConfigurationValue;
					dev->interface = uid->bInterfaceNumber;
					dev->altInterface = uid->bAlternateSetting;

					goto found;
				}
			} else {


				if (uid->endpoints != NULL)
					USB_Free(uid->endpoints);
				uid->endpoints = NULL;
				if (uid->extra != NULL)
					USB_Free(uid->extra);
				uid->extra = NULL;

				if (uid->bInterfaceClass == USB_CLASS_HUB) {
					retval = USBSTORAGE_ENOINTERFACE;
					try_status = -20000;

					USB_FreeDescriptors(&udd);

					goto free_and_return;
				}

				if (uid->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
						uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY && uid->bNumEndpoints >= 2) {
					try_status = -(10000 + uid->bInterfaceSubClass);
				}
			}
		}
	}

#ifdef MEM_PRINT
	s_printf("USBStorage_Open(): cannot find any interface!!!\n");

#endif
	USB_FreeDescriptors(&udd);
	retval = USBSTORAGE_ENOINTERFACE;
	debug_printf("cannot find any interface\n");
	goto free_and_return;

found:
	USB_FreeDescriptors(&udd);

	retval = USBSTORAGE_EINIT;
	try_status = -1201;

#ifdef MEM_PRINT
	s_printf("USBStorage_Open(): conf: %x altInterface: %x\n", dev->configuration, dev->altInterface);

#endif

	if (USB_GetConfiguration(ehci, dev->usb_fd, &conf) < 0)
		goto free_and_return;
	try_status = -1202;

#ifdef MEM_PRINT
	log_status(ehci, "after USB_GetConfiguration");
#endif

#ifdef MEM_PRINT
	if (conf != dev->configuration)
		s_printf("USBStorage_Open(): changing conf from %x\n", conf);

#endif
	if (/*conf != dev->configuration &&*/ USB_SetConfiguration(ehci, dev->usb_fd, dev->configuration) < 0)
		goto free_and_return;

	try_status = -1203;
	if (dev->altInterface != 0 && USB_SetAlternativeInterface(ehci, dev->usb_fd, dev->interface, dev->altInterface) < 0)
		goto free_and_return;

	try_status = -1204;

#ifdef MEM_PRINT
	log_status(ehci, "Before USBStorage_Reset");
#endif
	retval = USBStorage_Reset(ehci, dev);
#ifdef MEM_PRINT
	log_status(ehci, "After USBStorage_Reset");
#endif
	if (retval < 0)
		goto free_and_return;



	/*	retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_GET_MAX_LUN, 0, dev->interface, 1, max_lun);
		if(retval < 0 )
			dev->max_lun = 1;
		else
			dev->max_lun = (*max_lun+1);


		if(retval == USBSTORAGE_ETIMEDOUT)*/

	/* NOTE: from usbmassbulk_10.pdf "Devices that do not support multiple LUNs may STALL this command." */
	dev->max_lun = 8; // max_lun can be from 1 to 16, but some devices do not support lun

	retval = USBSTORAGE_OK;

	/*if(dev->max_lun == 0)
		dev->max_lun++;*/

	/* taken from linux usbstorage module (drivers/usb/storage/transport.c) */
	/*
	 * Some devices (i.e. Iomega Zip100) need this -- apparently
	 * the bulk pipes get STALLed when the GetMaxLUN request is
	 * processed.   This is, in theory, harmless to all other devices
	 * (regardless of if they stall or not).
	 */
	//USB_ClearHalt(dev->usb_fd, dev->ep_in);
	//USB_ClearHalt(dev->usb_fd, dev->ep_out);

	dev->buffer = USB_Alloc(MAX_TRANSFER_SIZE + 16);

	if (dev->buffer == NULL) {
		retval = -ENOMEM;
		try_status = -1205;
	} else retval = USBSTORAGE_OK;

free_and_return:

	if (max_lun != NULL) USB_Free(max_lun);

	if (retval < 0) {
		if (dev->buffer != NULL)
			USB_Free(dev->buffer);
		memset(dev, 0, sizeof (*dev));

#ifdef MEM_PRINT
		s_printf("USBStorage_Open(): try_status %i\n", try_status);

#endif
		return retval;
	}

#ifdef MEM_PRINT
	s_printf("USBStorage_Open(): return 0\n");

#endif

	return 0;
}
Exemple #4
0
s32 USBStorage_Open(usbstorage_handle *dev, s32 device_id, u16 vid, u16 pid)
{
	s32 retval = -1;
	u8 conf = -1;
	u8 *max_lun;
	u32 iConf, iInterface, iEp;
	usb_devdesc udd;
	usb_configurationdesc *ucd;
	usb_interfacedesc *uid;
	usb_endpointdesc *ued;
	bool reset_flag = false;

	max_lun = __lwp_heap_allocate(&__heap, 1);
	if (!max_lun)
		return IPC_ENOMEM;

	memset(dev, 0, sizeof(*dev));
	dev->usb_fd = -1;

	dev->tag = TAG_START;

	usb_log("USBStorage_Open id: %i\n",device_id);

	if (LWP_MutexInit(&dev->lock, false) < 0)
		goto free_and_return;

	if (SYS_CreateAlarm(&dev->alarm) < 0)
		goto free_and_return;

retry_init:

	retval = USB_OpenDevice(device_id, vid, pid, &dev->usb_fd);
	usb_log("USB_OpenDevice, ret: %i\n",retval);
	if (retval < 0)
		goto free_and_return;

	retval = USB_GetDescriptors(dev->usb_fd, &udd);
	if (retval < 0)
	{
		usb_log("USB_GetDescriptors error, ret: %i\n",retval);
		goto free_and_return;
	}
	else 
	
		usb_log("USB_GetDescriptors OK, configurations: %i\n",udd.bNumConfigurations);


	for (iConf = 0; iConf < udd.bNumConfigurations; iConf++) {
		ucd = &udd.configurations[iConf];
		usb_log("  Configuration: %i\n",iConf);
		for (iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++) {
			uid = &ucd->interfaces[iInterface];
			usb_log("    Interface: %i  InterfaceClass: 0x%x  numendpoints: %i\n",iInterface,uid->bInterfaceClass,uid->bNumEndpoints);
			if(uid->bInterfaceClass    == USB_CLASS_MASS_STORAGE && /*
				   (uid->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS
					|| uid->bInterfaceSubClass == MASS_STORAGE_RBC_COMMANDS
					|| uid->bInterfaceSubClass == MASS_STORAGE_ATA_COMMANDS
					|| uid->bInterfaceSubClass == MASS_STORAGE_QIC_COMMANDS
					|| uid->bInterfaceSubClass == MASS_STORAGE_UFI_COMMANDS
					|| uid->bInterfaceSubClass == MASS_STORAGE_SFF8070_COMMANDS) &&*/
				   uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY)
			{
				
				if (uid->bNumEndpoints < 2)
					continue;
				

				dev->ep_in = dev->ep_out = 0;
				for (iEp = 0; iEp < uid->bNumEndpoints; iEp++) {
					ued = &uid->endpoints[iEp];
					if (ued->bmAttributes != USB_ENDPOINT_BULK)
						continue;
					usb_log("      USB_ENDPOINT_BULK found: 0x%x  MaxPacketSize: %i\n",ued->bEndpointAddress,ued->wMaxPacketSize);

					if (ued->bEndpointAddress & USB_ENDPOINT_IN) {
						dev->ep_in = ued->bEndpointAddress;
					}
					else {
						dev->ep_out = ued->bEndpointAddress;
						if(ued->wMaxPacketSize > 64 && (dev->usb_fd>=0x20 || dev->usb_fd<-1)) 
							usb2_mode=true;
						else 
							usb2_mode=false;
					}
				}

				if (dev->ep_in != 0 && dev->ep_out != 0) {
					dev->configuration = ucd->bConfigurationValue;
					dev->interface = uid->bInterfaceNumber;
					dev->altInterface = uid->bAlternateSetting;
					goto found;
				}
			}
		}
	}
	usb_log("Device not found device\n");


	USB_FreeDescriptors(&udd);
	retval = USBSTORAGE_ENOINTERFACE;
	goto free_and_return;

found:
	usb_log("Found device, InterfaceSubClass: %i\n",uid->bInterfaceSubClass);
	dev->bInterfaceSubClass = uid->bInterfaceSubClass;

	USB_FreeDescriptors(&udd);

	retval = USBSTORAGE_EINIT;
	// some devices return an error, ignore it
	USB_GetConfiguration(dev->usb_fd, &conf);

	if(method==0 || method==4)
	{
		if (conf != dev->configuration && USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
		{
			usb_log("Error USB_SetConfiguration\n");
			goto free_and_return;
		}
		else usb_log("USB_SetConfiguration ok\n");
		
		if (dev->altInterface !=0 && USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
		{
			usb_log("Error USB_SetAlternativeInterface, alt: %i int: %i\n",dev->altInterface,dev->interface);
			goto free_and_return;
		}
		else usb_log("USB_SetAlternativeInterface ok, alt: %i int: %i\n",dev->altInterface,dev->interface);
		
		dev->suspended = 0;
		
		
		if(!reset_flag && dev->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS)
		{
			reset_flag = true;
			retval = USBStorage_Reset(dev);
			usb_log("USBStorage_Open, USBStorage_Reset: %i\n",retval);
			if (retval < 0)
			{
				USB_CloseDevice(&dev->usb_fd);
				goto retry_init;
			}
		}
	}
	else if(method==1)
	{
		if ( USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
		{
			usb_log("Error USB_SetConfiguration\n");
		}
		else usb_log("USB_SetConfiguration ok\n");
		
		if (USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
		{
			usb_log("Error USB_SetAlternativeInterface, alt: %i int: %i\n",dev->altInterface,dev->interface);
		}
		else usb_log("USB_SetAlternativeInterface ok, alt: %i int: %i\n",dev->altInterface,dev->interface);

		dev->suspended = 0;
	}
	else if(method==2)
	{
		if ( USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
		{
			usb_log("Error USB_SetConfiguration\n");
		}
		else usb_log("USB_SetConfiguration ok\n");
		
		if (USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
		{
			usb_log("Error USB_SetAlternativeInterface, alt: %i int: %i\n",dev->altInterface,dev->interface);
		}
		else usb_log("USB_SetAlternativeInterface ok, alt: %i int: %i\n",dev->altInterface,dev->interface);

		dev->suspended = 0;

		if(!reset_flag && dev->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS)
		{
			reset_flag = true;
			retval = USBStorage_Reset(dev);
			usb_log("USBStorage_Open, USBStorage_Reset: %i\n",retval);
			if (retval < 0)
			{
				USB_CloseDevice(&dev->usb_fd);
				goto retry_init;
			}
		}
	}
	else if(method==3)
	{
		if (USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
		{
			usb_log("Error USB_SetConfiguration\n");
			goto free_and_return;
		}
		else usb_log("USB_SetConfiguration ok\n");
		
		if (dev->altInterface !=0 && USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
		{
			usb_log("Error USB_SetAlternativeInterface, alt: %i int: %i\n",dev->altInterface,dev->interface);
			goto free_and_return;
		}
		else usb_log("USB_SetAlternativeInterface ok, alt: %i int: %i\n",dev->altInterface,dev->interface);
		
		dev->suspended = 0;
		
		retval = USBStorage_Reset(dev);
		usb_log("USBStorage_Open, USBStorage_Reset: %i\n",retval);
	}
	else if(method==5 || method==6)
	{
		if (conf != dev->configuration && USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
		{
			usb_log("Error USB_SetConfiguration\n");
			//goto free_and_return;
		}
		else usb_log("USB_SetConfiguration ok\n");
		
		if (dev->altInterface !=0 && USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
		{
			usb_log("Error USB_SetAlternativeInterface, alt: %i int: %i\n",dev->altInterface,dev->interface);
			//goto free_and_return;
		}
		else usb_log("USB_SetAlternativeInterface ok, alt: %i int: %i\n",dev->altInterface,dev->interface);
		if(!usb2_mode)
		{
			retval = USBStorage_Reset(dev);
			usb_log("USBStorage_Open, USBStorage_Reset: %i\n",retval);
		}
		dev->suspended = 0;
		
	}

	if(method==6)
	{
		dev->max_lun = 2;
		usb_log("No get max lun call,  max_lun: %i\n",dev->max_lun);
	}
	else
	{
	LWP_MutexLock(dev->lock);
	retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_GET_MAX_LUN, 0, dev->interface, 1, max_lun);
	LWP_MutexUnlock(dev->lock);
	

	if (retval < 0)
		dev->max_lun = 1;
	else
		dev->max_lun = *max_lun + 1;

	usb_log("USBSTORAGE_GET_MAX_LUN, ret: %i   max_lun: %i\n",retval,dev->max_lun);
	}
	if (retval == USBSTORAGE_ETIMEDOUT)
		goto free_and_return;

	retval = USBSTORAGE_OK;
	dev->sector_size = (u32 *) calloc(dev->max_lun, sizeof(u32));
	if(!dev->sector_size) {
		retval = IPC_ENOMEM;
		goto free_and_return;
	}

	/* taken from linux usbstorage module (drivers/usb/storage/transport.c)
	 *
	 * Some devices (i.e. Iomega Zip100) need this -- apparently
	 * the bulk pipes get STALLed when the GetMaxLUN request is
	 * processed.   This is, in theory, harmless to all other devices
	 * (regardless of if they stall or not).
	 *
	 * 8/9/10: If anyone wants to actually use a Zip100, they can add this back.
	 * But for now, it seems to be breaking things more than it is helping.
	 */
	//USB_ClearHalt(dev->usb_fd, dev->ep_in);
	//USB_ClearHalt(dev->usb_fd, dev->ep_out);

	if(!dev->buffer)
		dev->buffer = __lwp_heap_allocate(&__heap, MAX_TRANSFER_SIZE_V5);

	if(!dev->buffer) {
		retval = IPC_ENOMEM;
	} else {
		USB_DeviceRemovalNotifyAsync(dev->usb_fd,__usb_deviceremoved_cb,dev);
		retval = USBSTORAGE_OK;
	}

free_and_return:
	if (max_lun)
		__lwp_heap_free(&__heap, max_lun);

	if (retval < 0) {
		USBStorage_Close(dev);
		return retval;
	}

	return 0;
}
Exemple #5
0
s32 USBStorage_Open(usbstorage_handle *dev, struct ehci_device *fd)
{
	s32 retval = -1;
	u8 conf,*max_lun = NULL;
	u32 iConf, iInterface, iEp;
	usb_devdesc udd;
	usb_configurationdesc *ucd;
	usb_interfacedesc *uid;
	usb_endpointdesc *ued;

	max_lun = USB_Alloc(1);
	if(max_lun==NULL) return -ENOMEM;

	memset(dev, 0, sizeof(*dev));

	dev->tag = TAG_START;
        dev->usb_fd = fd;

	retval = USB_GetDescriptors(dev->usb_fd, &udd);
	if(retval < 0)
		goto free_and_return;

	for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
	{
		ucd = &udd.configurations[iConf];		
		for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
		{
			uid = &ucd->interfaces[iInterface];
			if(uid->bInterfaceClass    == USB_CLASS_MASS_STORAGE &&
			   uid->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS &&
			   uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY)
			{
				if(uid->bNumEndpoints < 2)
					continue;

				dev->ep_in = dev->ep_out = 0;
				for(iEp = 0; iEp < uid->bNumEndpoints; iEp++)
				{
					ued = &uid->endpoints[iEp];
					if(ued->bmAttributes != USB_ENDPOINT_BULK)
						continue;

					if(ued->bEndpointAddress & USB_ENDPOINT_IN)
						dev->ep_in = ued->bEndpointAddress;
					else
						dev->ep_out = ued->bEndpointAddress;
				}
				if(dev->ep_in != 0 && dev->ep_out != 0)
				{
					dev->configuration = ucd->bConfigurationValue;
					dev->interface = uid->bInterfaceNumber;
					dev->altInterface = uid->bAlternateSetting;
					goto found;
				}
			}
		}
	}

	USB_FreeDescriptors(&udd);
	retval = USBSTORAGE_ENOINTERFACE;
	goto free_and_return;

found:
	USB_FreeDescriptors(&udd);

	retval = USBSTORAGE_EINIT;
	if(USB_GetConfiguration(dev->usb_fd, &conf) < 0)
		goto free_and_return;
	if(conf != dev->configuration && USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
		goto free_and_return;
	if(dev->altInterface != 0 && USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
		goto free_and_return;
	dev->suspended = 0;

	retval = USBStorage_Reset(dev);
	if(retval < 0)
		goto free_and_return;

	retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_GET_MAX_LUN, 0, dev->interface, 1, max_lun);
	if(retval < 0)
		dev->max_lun = 1;
	else
		dev->max_lun = *max_lun;

	
	if(retval == USBSTORAGE_ETIMEDOUT)
		goto free_and_return;

	retval = USBSTORAGE_OK;

	if(dev->max_lun == 0)
		dev->max_lun++;

	/* taken from linux usbstorage module (drivers/usb/storage/transport.c) */
	/*
	 * Some devices (i.e. Iomega Zip100) need this -- apparently
	 * the bulk pipes get STALLed when the GetMaxLUN request is
	 * processed.   This is, in theory, harmless to all other devices
	 * (regardless of if they stall or not).
	 */
	USB_ClearHalt(dev->usb_fd, dev->ep_in);
	USB_ClearHalt(dev->usb_fd, dev->ep_out);

	dev->buffer = USB_Alloc(MAX_TRANSFER_SIZE);
	
	if(dev->buffer == NULL) retval = -ENOMEM;
	else retval = USBSTORAGE_OK;

free_and_return:
	if(max_lun!=NULL) USB_Free(max_lun);
	if(retval < 0)
	{
		if(dev->buffer != NULL)
			USB_Free(dev->buffer);
		memset(dev, 0, sizeof(*dev));
		return retval;
	}
	return 0;
}