usbBulkDevLib.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:89k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* usbBulkDevLib.c - USB Bulk Only Mass Storage class driver */
  2. /* Copyright 2000-2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01h,06nov01,wef  remove automatic buffer creations and repalce with OSS_xALLOC
  7.  remove more warnings
  8. 01g,08aug01,dat  Removing warnings
  9. 01f,25jul01,wef  fixed spr #69285
  10. 01e,01may01,wef  fixed incorrect declaration of usbBulkDevDestroy
  11. 01d,12apr01,wef  added logic to do READ/WRITE 6 or 10 based on configlette
  12.  parameter - added a paramter to usbBulBlkDevCreate () 
  13.  for this purpose.  added support for drives with partition 
  14.  tables.
  15. 01c,02sep00,bri  added support for multiple devices.
  16. 01b,04aug00,bri  updated as per review.
  17. 01a,22may00,bri  written.
  18. */
  19. /*
  20. DESCRIPTION
  21. This module implements the USB Mass Storage class driver for the vxWorks 
  22. operating system.  This module presents an interface which is a superset 
  23. of the vxWorks Block Device driver model.  This driver implements external 
  24. APIs which would be expected of a standard block device driver. 
  25. This class driver restricts to Mass Storage class devices that follow bulk-only
  26. transport.  For bulk-only devices transport of command, data and status occurs 
  27. solely via bulk endpoints.  The default control pipe is only used to set 
  28. configuration, clear STALL condition on endpoints and to issue class-specific 
  29. requests. 
  30. The class driver is a client of the Universal Serial Bus Driver (USBD).  All
  31. interaction with the USB buses and devices is handled through the USBD.
  32. INITIALIZATION
  33. The class driver must be initialized with usbBulkDevInit().  It is assumed that
  34. USBD is already initialized and attached to atleast one USB Host Controller.  
  35. usbBulkDevInit() registers the class driver as a client module with USBD.  It 
  36. also registers a callback routine to get notified whenever a USB MSC/SCSI/
  37. BULK-ONLY device is attached or removed from the system.  The callback routine
  38. creates a USB_BULK_DEV structure to represent the USB device attached.  It 
  39. also sets device configuration, interface settings and creates pipes for 
  40. BULK_IN and BULK_OUT transfers. 
  41. OTHER FUNCTIONS
  42. usbBulkBlkDevCreate() is the entry point to define a logical block device.
  43. This routine initializes the fields with in the vxWorks block device structure 
  44. BLK_DEV.  This BLK_DEV structure is part of the USB_BULK_DEV structure.  
  45. Memory is allocated for USB_BULK_DEV by the dynamic attach notification 
  46. callback routine.  So, this create routine just initializes the BLK_DEV 
  47. structure and returns a pointer to it, which is used during file system 
  48. initializtion call.
  49. usbBulkDevIoctl() implements functions which are beyond basic file handling. 
  50. Class-specific requests, Descriptor show, are some of the functions.  Function
  51. code parameter identifies the IO operation requested. 
  52. DATA FLOW
  53. For each USB MSC/SCSI/BULK-ONLY device detected, usbBulkPhysDevCreate() will
  54. create pipes to BULK_IN and a BULK_OUT endpoints of the device.  A pipe is a
  55. channel between USBD client i,e usbBulkDevLib and a specific endpoint.  All 
  56. SCSI commands are encapsulated with in a Command Block Wrapper (CBW) and 
  57. transferred across the BULK_OUT endpoint through the out pipe created.  
  58. This is followed by a data transfer phase.  Depending on the SCSI command 
  59. sent to the device, the direction bit in the CBW will indicate whether data 
  60. is transferred to or from the device.  This bit has no significance if no
  61. data transfer is expected.  Data is transferred to the device through BULK_OUT
  62. endpoint and if the device is required to transfer data, it does through
  63. the BULK_IN endpoint.  The device shall send Command Status Wrapper (CSW) via 
  64. BULK_IN endpoint.  This will indicate the success or failure of the CBW.  The
  65. data to be transferred to device will be pointed by the file system launched 
  66. on the device. 
  67. INCLUDE FILES: usbBulkDevLib.h, blkIo.h
  68. SEE ALSO:
  69. .I "USB Mass Storage Class - Bulk Only Transport Specification Version 1.0,"
  70. .I "SCSI-2 Standard specification 10L - Direct Access device commands"
  71. */
  72. /* includes */
  73. #include "vxWorks.h"
  74. #include "string.h"
  75. #include "errno.h"
  76. #include "errnoLib.h"
  77. #include "ioLib.h"
  78. #include "blkIo.h"
  79. #include "stdio.h"
  80. #include "logLib.h"
  81. #include "dosFsLib.h"
  82. #include "usb/usbPlatform.h"
  83. #include "usb/ossLib.h"             /* operations system srvcs */
  84. #include "usb/usb.h"             /* general USB definitions */
  85. #include "usb/usbListLib.h"         /* linked list functions   */
  86. #include "usb/usbdLib.h"            /* USBD interface          */
  87. #include "usb/usbLib.h"             /* USB utility functions   */
  88. #include "drv/usb/usbBulkDevLib.h"
  89. /* defines */
  90. #define USB_DEBUG_MSG        0x01
  91. #define USB_DEBUG_ERR        0x02
  92. #define USB_BULK_DEBUG                  
  93.         if (usbBulkDebug & USB_DEBUG_MSG)   
  94.             logMsg
  95. #define USB_BULK_ERR                    
  96.         if (usbBulkDebug & USB_DEBUG_ERR)   
  97.             logMsg
  98. #define USB_BULK_OFFS  1000
  99. /* typedefs */
  100. /* USB_BULK_DEV Structure - used to describe USB MSC/SCSI/BULK-ONLY device */
  101. typedef struct usbBulkDev
  102.     {
  103.     BLK_DEV           blkDev;         /* Vxworks block device structure */
  104.                                       /* Must be the first one          */
  105.     USBD_NODE_ID      bulkDevId;      /* USBD node ID of the device     */  
  106.     UINT16            configuration;  /* Configuration value         */    
  107.     UINT16            interface;      /* Interface number               */
  108.     UINT16            altSetting;     /* Alternate setting of interface */ 
  109.     UINT16            outEpAddress;   /* Bulk out EP address            */   
  110.     UINT16            inEpAddress;    /* Bulk in EP address             */
  111.     USBD_PIPE_HANDLE  outPipeHandle;  /* Pipe handle for Bulk out EP    */
  112.     USBD_PIPE_HANDLE  inPipeHandle;   /* Pipe handle for Bulk in EP     */
  113.     USB_IRP           inIrp;          /* IRP used for bulk-in data      */
  114.     USB_IRP           outIrp;         /* IRP used for bulk-out data     */
  115.     USB_IRP           statusIrp;      /* IRP used for reading status    */ 
  116.     UINT8             maxLun;         /* Max. number of LUN supported   */
  117.     USB_BULK_CBW      bulkCbw;        /* Structure for Command block    */
  118.     USB_BULK_CSW      bulkCsw;        /* Structure for Command status   */
  119.     UINT8 *           bulkInData;     /* Pointer for bulk-in data       */
  120.     UINT8 *           bulkOutData;    /* Pointer for bulk-out data      */   
  121.     UINT32            numBlks;       /* Number of blocks on device     */  
  122.     UINT32            blkOffset;      /* Offset of the starting block   */
  123.     UINT16            lockCount;      /* Count of times structure locked*/
  124.     BOOL              connected;      /* TRUE if USB_BULK device connected */    
  125.     LINK              bulkDevLink;    /* Link to other USB_BULK devices    */  
  126.     BOOL              read10Able;     /* Which read/write command the device  */
  127.       /* supports.  If TRUE, the device uses  */
  128.       /* READ10/WRITE10, if FALSE uses READ6 / */
  129.       /* WRITE6 */
  130.     } USB_BULK_DEV, *pUSB_BULK_DEV;    
  131. /* Attach request for user callback */
  132. typedef struct attach_request
  133.     {
  134.     LINK reqLink;                       /* linked list of requests */
  135.     USB_BULK_ATTACH_CALLBACK callback;  /* client callback routine */
  136.     pVOID callbackArg;                  /* client callback argument*/
  137.     } ATTACH_REQUEST, *pATTACH_REQUEST;
  138. /* globals */
  139. BOOL usbBulkDebug =  0;
  140. /* locals */
  141. LOCAL UINT16 initCount = 0;           /* Count for Bulk device initialisation */
  142. LOCAL USBD_CLIENT_HANDLE usbdHandle;  /* Handle for this class driver */
  143. LOCAL LIST_HEAD bulkDevList;          /* linked list of USB_BULK_DEV */
  144. LOCAL LIST_HEAD    reqList;           /* Attach callback request list */
  145.  MUTEX_HANDLE bulkDevMutex;      /* mutex used to protect internal structs */
  146. SEM_HANDLE   bulkIrpSem;        /* Semaphore for IRP Synchronisation */
  147. LOCAL UINT32 usbBulkIrpTimeOut = USB_BULK_IRP_TIME_OUT; /* Time out for IRP */
  148. /* forward declarations */
  149. LOCAL  STATUS usbBulkDescShow (USBD_NODE_ID nodeId);
  150. LOCAL  STATUS usbBulkConfigDescShow  (USBD_NODE_ID nodeId, UINT8 index);
  151. LOCAL  STATUS usbBulkPhysDevCreate (USBD_NODE_ID nodeId, UINT16 config, 
  152.                                     UINT16 interface);
  153. LOCAL  pUSB_BULK_DEV usbBulkDevFind (USBD_NODE_ID nodeId);
  154. LOCAL  STATUS usbBulkDevBlkRd (BLK_DEV *blkDev, int offset, int num, 
  155.        char * buf);
  156. LOCAL  STATUS usbBulkDevBlkWrt (BLK_DEV *blkDev, int offset, int num, 
  157. char * buf);
  158. LOCAL  STATUS usbBulkDevStatusChk (BLK_DEV *blkDev);
  159. LOCAL  STATUS usbBulkDevReset (BLK_DEV *blkDev);
  160. LOCAL  void   usbBulkIrpCallback (pVOID p);
  161. LOCAL  STATUS usbBulkFormScsiCmd (pUSB_BULK_DEV pBulkDev, 
  162.   UINT16 scsiCmd, 
  163.   UINT32 cmdParam1, 
  164.   UINT32 cmdParam2);
  165.                                    
  166. LOCAL  USB_COMMAND_STATUS usbBulkCmdExecute (pUSB_BULK_DEV pBulkDev);
  167. LOCAL  void   usbBulkDevDestroy (pUSB_BULK_DEV pBulkDev);
  168. LOCAL  STATUS usbBulkDevResetRecovery (pUSB_BULK_DEV  pBulkDev);
  169. LOCAL  VOID notifyAttach (USBD_NODE_ID nodeId, UINT16 attachCode);
  170. /***************************************************************************
  171. *
  172. * usbBulkDevAttachCallback - called when BULK-ONLY/SCSI device is attached/
  173. * removed
  174. *
  175. * This routine is called by USBD when a mass storage device with SCSI command 
  176. * set as interface sub-class and with bulk-only as interface protocol, is 
  177. * attached/detached.
  178. *
  179. * <nodeId> is the USBD_NODE_ID of the node being attached or removed.
  180. * <attachAction> is USBD_DYNA_ATTACH or USBD_DYNA_REMOVE.
  181. * <configuration> and <interface> indicate the configuration/interface
  182. * that reports itself as a MSC/SCSI/BULK-ONLY device.  
  183. * <deviceClass>, <deviceSubClass>, and <deviceProtocol> will identify a 
  184. * MSC/SCSI/BULK-ONLY device.
  185. *
  186. * NOTE: The USBD will invoke this function once for each configuration/
  187. * interface which reports itself as a MSC/SCSI/BULK-ONLY.  So, it is possible 
  188. * that a single device insertion/removal may trigger multiple callbacks. 
  189. *
  190. *
  191. * RETURNS: N/A
  192. */
  193. LOCAL VOID usbBulkDevAttachCallback
  194.     (
  195.     USBD_NODE_ID nodeId,         /* USBD Node ID of the device attached */
  196.     UINT16       attachAction,   /* Whether device attached / detached */
  197.     UINT16       configuration,  /* Configur'n value for  MSC/SCSI/BULK-ONLY */
  198.     UINT16       interface,      /* Interface number for  MSC/SCSI/BULK-ONLY */
  199.     UINT16       deviceClass,    /* Interface class   - 0x8  for MSC */
  200.     UINT16       deviceSubClass, /* Device sub-class  - 0x6  for SCSI 
  201.   * command 
  202.   */ 
  203.     UINT16       deviceProtocol  /* Interfaceprotocol - 0x50 for Bulk only */ 
  204.     )
  205.     {
  206.     pUSB_BULK_DEV  pBulkDev;     /* Pointer to bulk device,in case of 
  207.   * removal 
  208.   */
  209.     OSS_MUTEX_TAKE (bulkDevMutex, OSS_BLOCK);
  210.  
  211.     switch (attachAction)
  212.         { 
  213.         case USBD_DYNA_ATTACH: 
  214.             /* MSC/SCSI/BULK-ONLY Device attached */
  215.             /* Check out whether we already have a structure for this device */
  216.             if (usbBulkDevFind (nodeId) != NULL)
  217.                 break;
  218.             USB_BULK_DEBUG ("usbBulkDevAttachCallback : New Bulk-only device "
  219.                             "attachedn", 0, 0, 0, 0, 0, 0);
  220.             USB_BULK_DEBUG ("usbBulkDevAttachCallback: Configuration = %d, " 
  221.                             "Interface = %d, Node Id = %d n", configuration,
  222.                             interface, (UINT)nodeId, 0, 0, 0); 
  223.             /* create a USB_BULK_DEV structure for the device attached */
  224.            
  225.             if ( usbBulkPhysDevCreate (nodeId, configuration,interface) != OK )
  226.                 {
  227.                 USB_BULK_ERR ("usbBulkDevAttachCallback : Error creating Bulk"
  228.                               "devicen", 0, 0, 0, 0, 0, 0);
  229.                 break; 
  230.                 } 
  231.             /* Notify registered callers that a USB_BULK_DEV has been added */
  232.     notifyAttach (nodeId, USB_BULK_ATTACH); 
  233.  
  234.             break;
  235.         case USBD_DYNA_REMOVE:
  236.             /* MSC/SCSI/BULK-ONLY Device detached */
  237.             if ((pBulkDev = usbBulkDevFind (nodeId)) == NULL)
  238.                 break;
  239.             /* Check the connected flag  */
  240.             if (pBulkDev->connected == FALSE)
  241.                 break;
  242.             
  243.             pBulkDev->connected = FALSE;
  244.     /* Notify registered callers that the SCSI/BULK-ONLY device has 
  245.              * been removed 
  246.      *
  247.      * NOTE: We temporarily increment the device's lock count
  248.      * to prevent usbBulkDevUnlock() from destroying the
  249.      * structure while we're still using it.
  250.      */
  251.             pBulkDev->lockCount++; 
  252.             notifyAttach (pBulkDev->bulkDevId, USB_BULK_REMOVE); 
  253.             pBulkDev->lockCount--; 
  254.            
  255.             if (pBulkDev->lockCount == 0) 
  256.                 usbBulkDevDestroy (pBulkDev); 
  257.             USB_BULK_DEBUG ("usbBulkDevAttachCallback : Bulk only Mass 
  258.      storage device detachedn", 0, 0, 0, 0, 0, 0);
  259.             break;
  260.         default :
  261.             break; 
  262.         }
  263.     OSS_MUTEX_RELEASE (bulkDevMutex);  
  264.     }
  265. /***************************************************************************
  266. *
  267. * usbBulkDevShutDown - shuts down the USB bulk-only class driver.
  268. *
  269. * This routine unregisters the driver from USBD and releases any resources 
  270. * allocated for the devices.
  271. *
  272. * RETURNS: OK or ERROR.
  273. */
  274. STATUS usbBulkDevShutDown 
  275.     (
  276.     int   errCode                /* Error code - reason for shutdown */
  277.     )
  278.     {
  279.     pUSB_BULK_DEV pBulkDev;      /* Pointer to bulk device */
  280.     pATTACH_REQUEST  pRequest;
  281.     if (initCount == 0)
  282.         return ossStatus (S_usbBulkDevLib_NOT_INITIALIZED);
  283.     /* release any bulk devices */
  284.     while ((pBulkDev = usbListFirst (&bulkDevList)) != NULL)
  285.         usbBulkDevDestroy (pBulkDev); 
  286.     /* Dispose of any outstanding notification requests */
  287.     while ((pRequest = usbListFirst (&reqList)) != NULL)
  288.         {
  289.        usbListUnlink (&pRequest->reqLink);
  290.         OSS_FREE (pRequest); 
  291.         }
  292.     /* 
  293.      * Unregister with the USBD. USBD will automatically release any pending
  294.      * IRPs or attach requests.
  295.      */
  296.     if (usbdHandle != NULL)
  297.         {
  298.         usbdClientUnregister (usbdHandle);
  299.         usbdHandle = NULL;
  300.         USB_BULK_DEBUG ("usbBulkDevShutDown : Bulk Only class driver "
  301.                         "unregistered n", 0, 0, 0, 0, 0, 0);
  302.         }
  303.     /* release resources */
  304.     if (bulkDevMutex != NULL)
  305.         {
  306.         OSS_MUTEX_DESTROY (bulkDevMutex);
  307.         bulkDevMutex = NULL;
  308.         }
  309.     if (bulkIrpSem != NULL)
  310.         {
  311.         OSS_SEM_DESTROY (bulkIrpSem);
  312.         bulkIrpSem = NULL;
  313.         }
  314.     initCount--; 
  315.    
  316.     return ossStatus (errCode); 
  317.     }
  318. /***************************************************************************
  319. *
  320. * usbBulkDevInit - registers USB Bulk only mass storage class driver.
  321. *
  322. * This routine registers the mass storage class driver with USB driver.  It
  323. * also registers attach callback routine to get notified of the USB/MSC/BULK
  324. * ONLY devices.  
  325. *
  326. * RETURNS: OK, or ERROR if unable to register with USBD.
  327. *
  328. * ERRNO:
  329. *   S_usbbulkDevLib_OUT_OF_RESOURCES
  330. *   S_usbbulkDevLib_USBD_FAULT
  331. */
  332. STATUS usbBulkDevInit (void)
  333.     {
  334.     /* 
  335.      * Check whether already initilized. If not, then initialise the required
  336.      * structures and register the class driver with USBD.
  337.      */
  338.     if (initCount == 0)
  339.         {
  340.         memset (&bulkDevList, 0, sizeof (bulkDevList));
  341.         memset (&reqList, 0, sizeof (reqList));
  342.         bulkDevMutex = NULL;
  343.         bulkIrpSem   = NULL;
  344.         usbdHandle   = NULL;
  345.         if (OSS_MUTEX_CREATE (&bulkDevMutex) != OK)
  346.             return (usbBulkDevShutDown (S_usbBulkDevLib_OUT_OF_RESOURCES));
  347.         if (OSS_SEM_CREATE (1, 1 , &bulkIrpSem) != OK)
  348.             return (usbBulkDevShutDown (S_usbBulkDevLib_OUT_OF_RESOURCES));
  349.         /* Establish connection to USBD and register for attach callback */
  350.         if (usbdClientRegister ("BULK_CLASS", &usbdHandle) != OK ||
  351.             usbdDynamicAttachRegister (usbdHandle, USB_CLASS_MASS_STORAGE,
  352.                                        USB_SUBCLASS_SCSI_COMMAND_SET, 
  353.                                        USB_INTERFACE_PROTOCOL_BULK_ONLY,
  354.                                        usbBulkDevAttachCallback) != OK)
  355.             {
  356.             USB_BULK_ERR ("usbBulkDevInit: Client Registration Failed n",
  357.                           0, 0, 0, 0, 0, 0); 
  358.             return usbBulkDevShutDown (S_usbBulkDevLib_USBD_FAULT);
  359.             }
  360.         }
  361.     initCount++;
  362.     return (OK);
  363.     }
  364. /***************************************************************************
  365. *
  366. * usbBulkDevIoctl - perform a device-specific control.
  367. *
  368. * Typically called to invoke device-specific functions which are not needed
  369. * by a file system.  
  370. *
  371. * RETURNS: The status of the request, or ERROR if the request is unsupported.
  372. */
  373. STATUS usbBulkDevIoctl
  374.     (
  375.     BLK_DEV * pBlkDev,           /* pointer to bulk device       */
  376.     int request,                 /* request type                 */
  377.     int someArg                  /* arguments related to request */
  378.     )
  379.     {
  380.     UINT16 actLen= 0xffff;       
  381.     /* get a pointer to the bulk device */
  382.     pUSB_BULK_DEV  pBulkDev = (USB_BULK_DEV *)pBlkDev;   
  383.     if ( pBulkDev == (pUSB_BULK_DEV)NULL )
  384.         return (ERROR);
  385.     /* Check whether the device exists or not */
  386.     if (usbBulkDevFind (pBulkDev->bulkDevId) != pBulkDev)
  387.         {
  388.         USB_BULK_ERR ("usbBulkDevIoctl: Bulk Device not foundn", 
  389.                         0, 0, 0, 0, 0, 0);
  390.         return (ERROR);
  391.         }
  392.     switch (request)
  393.         {
  394.         case FIODISKFORMAT: 
  395.             /*  
  396.              * This is the IO control function supported by file system,
  397.              * but supplied by the device driver. Other IO control functions 
  398.              * are directly handled by file system with out the use of this 
  399.      * routine.
  400.              */
  401.             if ( usbBulkFormScsiCmd (pBulkDev, 
  402.      USB_SCSI_FORMAT_UNIT, 
  403.      0, 
  404.      0) 
  405.    != OK )
  406.                 return (ERROR); 
  407.             if ( usbBulkCmdExecute (pBulkDev) != USB_COMMAND_SUCCESS )
  408.                 {
  409.                 USB_BULK_ERR ("usbBulkDevIoctl: FORMAT UNIT Command failedn", 
  410.                               0, 0, 0, 0, 0, 0);  
  411.                 return (ERROR); 
  412.                 }   
  413.                 
  414.             return (OK);
  415.         case USB_BULK_DESCRIPTOR_GET:
  416.             /* invoke routine to display all descriptors */
  417.             return (usbBulkDescShow (pBulkDev->bulkDevId));
  418.         case USB_BULK_DEV_RESET:
  419.             /* send a class-specific mass storage reset command */
  420.              
  421.             return (usbBulkDevResetRecovery (pBulkDev));
  422.         case USB_BULK_EJECT_MEDIA:
  423.             /* Only applicable if media is removable */
  424.             if ( pBulkDev->blkDev.bd_removable  != TRUE )
  425.                 return (ERROR);  
  426.             else
  427.                 {
  428.                 if ( usbBulkFormScsiCmd (pBulkDev, 
  429.  USB_SCSI_START_STOP_START, 
  430.  USB_SCSI_START_STOP_LOEJ, 
  431.  0) 
  432. != OK )
  433.                     return (ERROR); 
  434.                 if ( usbBulkCmdExecute (pBulkDev) != USB_COMMAND_SUCCESS )
  435.                     {
  436.                     USB_BULK_ERR ("usbBulkDevIoctl: EJECT Command " 
  437.                                   "failedn", 0, 0, 0, 0, 0, 0);  
  438.                     return (ERROR); 
  439.                     }
  440.                 }
  441.             return (OK); 
  442.         
  443.         case USB_BULK_MAX_LUN:
  444.             /* May not be supported by devices having single LUN */
  445.         
  446.             if (usbdVendorSpecific (usbdHandle, pBulkDev->bulkDevId,
  447.                 USB_RT_DEV_TO_HOST | USB_RT_CLASS | USB_RT_INTERFACE,
  448.                 USB_BULK_GET_MAX_LUN, 0, pBulkDev->interface, 1, 
  449.                 &(pBulkDev->maxLun), &actLen) != OK )
  450.                 {
  451.                 USB_BULK_ERR ("usbBulkDevIoctl: Failed to acquire max lun n", 
  452.                               0, 0, 0, 0, 0, 0);  
  453.                 }
  454.             else 
  455.                 { 
  456.                  USB_BULK_DEBUG ("usbBulkDevIoctl: Max Lun = %c n", 
  457.                                  pBulkDev->maxLun, 0, 0, 0, 0, 0);
  458.                 }   
  459.       
  460.             return (OK); 
  461.                  
  462.         default:
  463.             errnoSet (S_ioLib_UNKNOWN_REQUEST);
  464.             USB_BULK_DEBUG ("usbBulkDevIoctl: Unknown Requestn", 
  465.                             0, 0, 0, 0, 0, 0);
  466.             return (ERROR);
  467.         }
  468.     }
  469. /***************************************************************************
  470. *
  471. * usbBulkDevResetRecovery - Performs reset recovery on the specified device.
  472. *
  473. * Reset recovery shall be done when device returns a phase error status 
  474. * while executing a CBW.  It is also done, when a stall condition is detected
  475. * on bulk-out endpoint during CBW transport.  The following sequence is 
  476. * performed on the device 
  477. *
  478. * - BulkOnly Mass Storage Reset 
  479. * - Clear HALT feature on the Bulk-in Endpoint
  480. * - Clear HALT feature on the Bulk-out Endpoint
  481. *
  482. * RETURNS: OK, if reset sequence successful otherwise ERROR.
  483. */
  484. LOCAL STATUS usbBulkDevResetRecovery
  485.     (
  486.     pUSB_BULK_DEV  pBulkDev           /* pointer to bulk device */
  487.     )
  488.     {
  489.     OSS_MUTEX_TAKE (bulkDevMutex, OSS_BLOCK);
  490.       
  491.     /* issue bulk-only mass storage reset request on control End point */
  492.     if ((usbdVendorSpecific (usbdHandle, 
  493.      pBulkDev->bulkDevId,
  494.      USB_RT_HOST_TO_DEV | USB_RT_CLASS | USB_RT_INTERFACE,
  495.      USB_BULK_RESET, 
  496.      0, 
  497.      pBulkDev->interface, 
  498.      0, 
  499.      NULL, 
  500.      NULL)) 
  501.    != OK )
  502.         {
  503.         USB_BULK_ERR ("usbBulkDevResetRecovery: Failed to reset %xn", 
  504.                       0, 0, 0, 0, 0, 0);  
  505.         
  506.         OSS_MUTEX_RELEASE (bulkDevMutex);
  507.         return (ERROR); 
  508.         }
  509.     else 
  510.        { 
  511.        USB_BULK_DEBUG ("usbBulkDevResetRecovery: Reset...donen", 
  512.                        0, 0, 0, 0, 0, 0);
  513.        }
  514.     /* clear HALT feature on bulk in and bulk out end points */
  515.     if ((usbdFeatureClear (usbdHandle, 
  516.    pBulkDev->bulkDevId, 
  517.    USB_RT_ENDPOINT, 
  518.    USB_FSEL_DEV_ENDPOINT_HALT, 
  519.    (pBulkDev->inEpAddress & 0x0F))) 
  520.  != OK)
  521.         {
  522.         USB_BULK_ERR ("usbBulkDevResetRecovery: Failed to clear HALT feauture"
  523.                       " on bulk in Endpoint %xn", 0, 0, 0, 0, 0, 0);
  524.         }  
  525.     if ((usbdFeatureClear (usbdHandle, 
  526.    pBulkDev->bulkDevId, 
  527.    USB_RT_ENDPOINT,                            
  528.    USB_FSEL_DEV_ENDPOINT_HALT, 
  529.    (pBulkDev->outEpAddress & 0x0F))) 
  530.  != OK)
  531.         {
  532.         USB_BULK_ERR ("usbBulkDevResetRecovery: Failed to clear HALT feauture"
  533.                       " on bulk out Endpoint %xn", 0, 0, 0, 0, 0, 0);
  534.         } 
  535.     OSS_MUTEX_RELEASE (bulkDevMutex);
  536.     return (OK);
  537.   
  538.     }
  539. /***************************************************************************
  540. *
  541. * usbBulkFormScsiCmd - forms command block wrapper(CBW) for requested SCSI command
  542. *
  543. * This routine forms SCSI command blocks as per the Bulk-only command   
  544. * specifications and SCSI protocol.
  545. *
  546. * The following are the input parameters 
  547. *
  548. * .IP <pBulkDev>
  549. * pointer to USB/BULK-ONLY/SCSI device for which the command has to be formed.
  550. *
  551. * .IP <scsiCmd>
  552. * identifies the SCSI command to be formed.
  553. * .IP <cmdParam1>
  554. * parameter required to form a SCSI comamnd, if any.
  555. *
  556. * .IP <cmdParam2>
  557. * parameter required to form a SCSI comamnd, if any.
  558. *
  559. * RETURNS: OK, or ERROR if the command is unsupported.
  560. */
  561. LOCAL STATUS usbBulkFormScsiCmd 
  562.     (
  563.     pUSB_BULK_DEV pBulkDev,      /* pointer to bulk device     */
  564.     UINT16 scsiCmd,                /* SCSI command               */ 
  565.     UINT32 cmdParam1,              /* command parameter          */
  566.     UINT32 cmdParam2               /* command parameter          */
  567.     )
  568.     {
  569.     BOOL status = OK;
  570.     /* TODO : how to support a LUN other than 0. Also support for more than
  571.      * one scsi device on the usb-scsi bus. how can we get SCSI ID
  572.      */ 
  573.     pBulkDev->bulkCbw.signature = USB_BULK_SWAP_32 (USB_CBW_SIGNATURE);  
  574.     pBulkDev->bulkCbw.tag       = USB_BULK_SWAP_32 (USB_CBW_TAG);
  575.     pBulkDev->bulkCbw.lun       = 0x00;       
  576.     switch (scsiCmd)
  577.         {
  578.         case USB_SCSI_WRITE10:    /* 6-byte SCSI WRITE command  */
  579.              cmdParam1 += pBulkDev->blkOffset;  /* add offset to blk number */
  580.             /* 
  581.              * For WRITE10 command, cmdParam1 refers to the block number from
  582.              * which cmdParam2 number of blocks are to be written. Calculate
  583.              * the transfer length based on the block size and num. of blocks
  584.              */
  585.             pBulkDev->bulkCbw.dataXferLength = USB_BULK_SWAP_32(((cmdParam2) * 
  586.                                                (pBulkDev->blkDev.bd_bytesPerBlk))); 
  587.             pBulkDev->bulkCbw.direction  = USB_CBW_DIR_OUT;
  588.             pBulkDev->bulkCbw.length = 0x0A;
  589.     /* op code */
  590.             pBulkDev->bulkCbw.CBD[0] = 0x2A;
  591.     
  592.     /* DPU, FOA,  and RELADR bits*/
  593.             pBulkDev->bulkCbw.CBD[1] = 0x0;
  594.     /* lba is bytes 2-5  MSB first, LSB .last */
  595.     pBulkDev->bulkCbw.CBD[2] = 0x0;
  596.             pBulkDev->bulkCbw.CBD[3] = 0x0;
  597.     pBulkDev->bulkCbw.CBD[4] = (UINT8)((cmdParam1 & 0xFF00) >>8);
  598.             pBulkDev->bulkCbw.CBD[5] = (UINT8)(cmdParam1 & 0xFF);
  599.     /* Reserved */
  600.             pBulkDev->bulkCbw.CBD[6] = 0x0;
  601.     /* transfer length */
  602.             pBulkDev->bulkCbw.CBD[7] = (UINT8)((cmdParam2 & 0xFF00) >>8);
  603.             pBulkDev->bulkCbw.CBD[8] = (UINT8)(cmdParam2 & 0xFF);
  604.     /* Control */
  605.             pBulkDev->bulkCbw.CBD[9] = 0x0;
  606.             break;
  607.         case USB_SCSI_WRITE6:    /* 6-byte SCSI WRITE command  */
  608.              cmdParam1 += pBulkDev->blkOffset;  /* add offset to blk number */
  609.             /* 
  610.              * For WRITE6 command, cmdParam1 refers to the block number from
  611.              * which cmdParam2 number of blocks are to be written. Calculate
  612.              * the transfer length based on the block size and num. of blocks
  613.              */
  614.             pBulkDev->bulkCbw.dataXferLength = USB_BULK_SWAP_32(((cmdParam2) * 
  615.                                                (pBulkDev->blkDev.bd_bytesPerBlk))); 
  616.             pBulkDev->bulkCbw.direction  = USB_CBW_DIR_OUT;
  617.             
  618.             pBulkDev->bulkCbw.length = 0x06;
  619.             pBulkDev->bulkCbw.CBD[0] = USB_SCSI_WRITE6;
  620.             pBulkDev->bulkCbw.CBD[1] = 0x0;
  621.             pBulkDev->bulkCbw.CBD[2] = (UINT8)((cmdParam1 & 0xFF00) >>8) ;
  622.             pBulkDev->bulkCbw.CBD[3] = (UINT8)(cmdParam1 & 0xFF);
  623.             pBulkDev->bulkCbw.CBD[4] = (UINT8)cmdParam2;
  624.             pBulkDev->bulkCbw.CBD[5] = 0x0; 
  625.     
  626.             break;
  627.         case USB_SCSI_READ10:     /* 10-byte SCSI READ command */
  628.     cmdParam1 += pBulkDev->blkOffset; 
  629.             /* 
  630.              * For READ10 command, cmdParam1 refers to the block number from
  631.              * which cmdParam2 number of blocks are to be read. Calculate
  632.              * the transfer length based on the block size and num. of blocks
  633.              */ 
  634.   
  635.             pBulkDev->bulkCbw.dataXferLength = USB_BULK_SWAP_32(((cmdParam2) * 
  636.                                               (pBulkDev->blkDev.bd_bytesPerBlk))); 
  637.             pBulkDev->bulkCbw.direction      = USB_CBW_DIR_IN;
  638.             pBulkDev->bulkCbw.length = 0x0A;
  639.             pBulkDev->bulkCbw.CBD[0] = 0x28; /* op code */
  640.             pBulkDev->bulkCbw.CBD[1] = 0x0; /* DPU, FOA,  and RELADR bits*/
  641.             pBulkDev->bulkCbw.CBD[2] = 0x0; /* lba is bytes 2-5 MSB */
  642.             pBulkDev->bulkCbw.CBD[3] = 0x0; /* lba is bytes 2-5 */
  643.             pBulkDev->bulkCbw.CBD[4] = (UINT8)((cmdParam1 & 0xFF00) >>8); /* lba is bytes 2-5 */
  644.             pBulkDev->bulkCbw.CBD[5] = (UINT8)(cmdParam1 & 0xFF); /* lba is bytes 2-5  LSB*/
  645.             pBulkDev->bulkCbw.CBD[6] = 0x0; /* Reserved */
  646.             pBulkDev->bulkCbw.CBD[7] = (UINT8)((cmdParam2 & 0xFF00) >>8); /* transfer length MSB */
  647.             pBulkDev->bulkCbw.CBD[8] = (UINT8)(cmdParam2 & 0xFF); /* transfer length LSB */
  648.             pBulkDev->bulkCbw.CBD[9] = 0x0; /* Control */
  649.             break;
  650.         case USB_SCSI_READ6:     /* 6-byte SCSI READ command */
  651.     cmdParam1 += pBulkDev->blkOffset; 
  652.             /* 
  653.              * For READ6 command, cmdParam1 refers to the block number from
  654.              * which cmdParam2 number of blocks are to be read. Calculate
  655.              * the transfer length based on the block size and num. of blocks
  656.              */ 
  657.   
  658.             pBulkDev->bulkCbw.dataXferLength = USB_BULK_SWAP_32(((cmdParam2) * 
  659.                                               (pBulkDev->blkDev.bd_bytesPerBlk))); 
  660.             pBulkDev->bulkCbw.direction      = USB_CBW_DIR_IN;
  661.             pBulkDev->bulkCbw.length = 0x06;
  662.             pBulkDev->bulkCbw.CBD[0] = USB_SCSI_READ6;
  663.             pBulkDev->bulkCbw.CBD[1] = 0x0;
  664.             pBulkDev->bulkCbw.CBD[2] = (UINT8)((cmdParam1 & 0xFF00) >>8) ;
  665.             pBulkDev->bulkCbw.CBD[3] = (UINT8)(cmdParam1 & 0xFF);
  666.             pBulkDev->bulkCbw.CBD[4] = (UINT8)cmdParam2;
  667.             pBulkDev->bulkCbw.CBD[5] = 0x0; 
  668.             break;
  669. case USB_SCSI_INQUIRY:   /* Standard 36-byte INQUIRY command */
  670.             pBulkDev->bulkCbw.dataXferLength = USB_BULK_SWAP_32 (USB_SCSI_STD_INQUIRY_LEN); 
  671.             pBulkDev->bulkCbw.direction      = USB_CBW_DIR_IN;
  672.             pBulkDev->bulkCbw.length  = 0x06;
  673.             pBulkDev->bulkCbw.CBD[0]  = USB_SCSI_INQUIRY;
  674.             pBulkDev->bulkCbw.CBD[1]  = 0x0;
  675.             pBulkDev->bulkCbw.CBD[2]  = 0x0;
  676.             pBulkDev->bulkCbw.CBD[3]  = 0x0;
  677.             pBulkDev->bulkCbw.CBD[4]  = USB_SCSI_STD_INQUIRY_LEN;
  678.             pBulkDev->bulkCbw.CBD[5]  = 0x0; 
  679.             break;
  680.         case USB_SCSI_START_STOP_UNIT:      /* for Eject/start media command */
  681.             /* Eject applicable only for removable media */
  682.              if ((cmdParam1 == USB_SCSI_START_STOP_LOEJ) &
  683.                 (pBulkDev->blkDev.bd_removable != TRUE)) 
  684.                 {
  685.                 status = ERROR;
  686.                 break;
  687.                 }
  688.             pBulkDev->bulkCbw.dataXferLength = 0; 
  689.             pBulkDev->bulkCbw.direction  = USB_CBW_DIR_NONE;
  690.             pBulkDev->bulkCbw.length = 0x06;
  691.             pBulkDev->bulkCbw.CBD[0] = USB_SCSI_START_STOP_UNIT;
  692.             pBulkDev->bulkCbw.CBD[1] = 0x0;
  693.             pBulkDev->bulkCbw.CBD[2] = 0x0;
  694.             pBulkDev->bulkCbw.CBD[3] = 0x0;
  695.             pBulkDev->bulkCbw.CBD[4] = (UINT8)cmdParam1;
  696.             pBulkDev->bulkCbw.CBD[5] = 0x0; 
  697.             break;
  698.         case USB_SCSI_TEST_UNIT_READY: /* Test unit ready command */ 
  699.             pBulkDev->bulkCbw.dataXferLength = 0; 
  700.             pBulkDev->bulkCbw.direction  = USB_CBW_DIR_NONE;
  701.             pBulkDev->bulkCbw.length = 0x06;
  702.             pBulkDev->bulkCbw.CBD[0] = USB_SCSI_TEST_UNIT_READY;
  703.             pBulkDev->bulkCbw.CBD[1] = 0x0;
  704.             pBulkDev->bulkCbw.CBD[2] = 0x0;
  705.             pBulkDev->bulkCbw.CBD[3] = 0x0;
  706.             pBulkDev->bulkCbw.CBD[4] = 0x0;
  707.             pBulkDev->bulkCbw.CBD[5] = 0x0; 
  708.             break;
  709.  
  710.         case USB_SCSI_REQ_SENSE:      /* Request sense command */ 
  711.             pBulkDev->bulkCbw.dataXferLength = 
  712.                                     USB_BULK_SWAP_32(USB_SCSI_REQ_SENSE_LEN); 
  713.             pBulkDev->bulkCbw.direction  = USB_CBW_DIR_IN;
  714.             pBulkDev->bulkCbw.length = 0x06;
  715.             pBulkDev->bulkCbw.CBD[0] = USB_SCSI_REQ_SENSE;
  716.             pBulkDev->bulkCbw.CBD[1] = 0x0;
  717.             pBulkDev->bulkCbw.CBD[2] = 0x0;
  718.             pBulkDev->bulkCbw.CBD[3] = 0x0;
  719.             pBulkDev->bulkCbw.CBD[4] = USB_SCSI_REQ_SENSE_LEN;
  720.             pBulkDev->bulkCbw.CBD[5] = 0x0; 
  721.             break;
  722.         case USB_SCSI_FORMAT_UNIT:    /* Format Unit command */ 
  723.             /* issue a FORMAT UNIT command with default parameters */
  724.             pBulkDev->bulkCbw.dataXferLength = 0; 
  725.             pBulkDev->bulkCbw.direction  = USB_CBW_DIR_NONE;
  726.             pBulkDev->bulkCbw.length = 0x06;
  727.             pBulkDev->bulkCbw.CBD[0] = USB_SCSI_FORMAT_UNIT;
  728.             pBulkDev->bulkCbw.CBD[1] = 0x0;
  729.             pBulkDev->bulkCbw.CBD[2] = 0x0;
  730.             pBulkDev->bulkCbw.CBD[3] = 0x0;
  731.             pBulkDev->bulkCbw.CBD[4] = 0x0;
  732.             pBulkDev->bulkCbw.CBD[5] = 0x0; 
  733.             break;
  734.     
  735.         case USB_SCSI_READ_CAPACITY:  /* Read capacity command */
  736.             /* 
  737.              * Provides a means to request information regarding the capacity 
  738.              * of the logical unit. The response will consists of number of 
  739.              * logical blocks present and the size of the block.
  740.              */
  741.             pBulkDev->bulkCbw.dataXferLength = 
  742.                                       USB_BULK_SWAP_32(USB_SCSI_READ_CAP_LEN); 
  743.             pBulkDev->bulkCbw.direction  = USB_CBW_DIR_IN;
  744.             pBulkDev->bulkCbw.length = 0x0A;
  745.             pBulkDev->bulkCbw.CBD[0] = USB_SCSI_READ_CAPACITY;
  746.             pBulkDev->bulkCbw.CBD[1] = 0x0;
  747.             pBulkDev->bulkCbw.CBD[2] = 0x0;
  748.             pBulkDev->bulkCbw.CBD[3] = 0x0;
  749.             pBulkDev->bulkCbw.CBD[4] = 0x0;
  750.             pBulkDev->bulkCbw.CBD[5] = 0x0; 
  751.             pBulkDev->bulkCbw.CBD[6] = 0x0; 
  752.             pBulkDev->bulkCbw.CBD[7] = 0x0; 
  753.             pBulkDev->bulkCbw.CBD[8] = 0x0; 
  754.             pBulkDev->bulkCbw.CBD[9] = 0x0; 
  755.             break;
  756.         case USB_SCSI_PREVENT_REMOVAL: /* Prevent media removal command */
  757.             /* Applicable only for removable media. Disables removal of media */    
  758.             if (pBulkDev->blkDev.bd_removable  != TRUE) 
  759.                 {
  760.                 status = ERROR;
  761.                 break;
  762.                 }
  763.             pBulkDev->bulkCbw.dataXferLength = 0; 
  764.             pBulkDev->bulkCbw.direction  = USB_CBW_DIR_NONE;
  765.             pBulkDev->bulkCbw.length = 0x06;
  766.             pBulkDev->bulkCbw.CBD[0] = USB_SCSI_PREVENT_REMOVAL;
  767.             pBulkDev->bulkCbw.CBD[1] = 0x0;
  768.             pBulkDev->bulkCbw.CBD[2] = 0x0;
  769.             pBulkDev->bulkCbw.CBD[3] = 0x0;
  770.             pBulkDev->bulkCbw.CBD[4] = 0x0;
  771.             pBulkDev->bulkCbw.CBD[5] = 0x0; 
  772.             break; 
  773.          
  774.         default: 
  775.             status= ERROR;
  776.         }
  777.  
  778.     return (status);
  779.  
  780.     } 
  781. /***************************************************************************
  782. *
  783. * usbBulkCmdExecute - Executes a previously formed command block. 
  784. *
  785. * This routine transports the CBW across the BULK_OUT endpoint followed by
  786. * a data transfer phase(if required) to/from the device depending on the 
  787. * direction bit.  After data transfer, CSW is received from the device.
  788. * All transactions to the device are done by forming IRP's initilized with  
  789. * command dependent values.
  790. *
  791. * RETURNS: OK on success, or ERROR if failed to execute
  792. */
  793. LOCAL USB_COMMAND_STATUS usbBulkCmdExecute
  794.     ( 
  795.     pUSB_BULK_DEV pBulkDev       /* pointer to bulk device */ 
  796.     )
  797.     {
  798.     pUSB_BULK_CSW pCsw ;
  799. if ( pBulkDev->connected == FALSE )
  800. return (USB_INTERNAL_ERROR);
  801.     if ( OSS_SEM_TAKE (bulkIrpSem, usbBulkIrpTimeOut + 1000) == ERROR )
  802.         {
  803.         USB_BULK_DEBUG ("usbBulkCmdExecute: Irp in Use n", 0, 0, 0, 0, 0, 0);
  804.         return (USB_INTERNAL_ERROR);
  805.         }
  806.     /* Form an IRP to submit the command block on BULK OUT pipe */
  807.     memset (&(pBulkDev->outIrp), 0, sizeof (USB_IRP));
  808.     
  809.     pBulkDev->outIrp.irpLen            = sizeof (USB_IRP);
  810.     pBulkDev->outIrp.userCallback      = usbBulkIrpCallback; 
  811.     pBulkDev->outIrp.timeout           = usbBulkIrpTimeOut;
  812.     pBulkDev->outIrp.transferLen       = USB_CBW_LENGTH;
  813.     pBulkDev->outIrp.bfrCount          = 0x01;  
  814.     pBulkDev->outIrp.bfrList[0].pid    = USB_PID_OUT;
  815.     pBulkDev->outIrp.bfrList[0].pBfr   = (UINT8 *)&(pBulkDev->bulkCbw);
  816.     pBulkDev->outIrp.bfrList[0].bfrLen = USB_CBW_LENGTH;
  817.     pBulkDev->outIrp.userPtr           = pBulkDev;            
  818.     /* Submit IRP */
  819.  
  820.     if (usbdTransfer (usbdHandle, 
  821.       pBulkDev->outPipeHandle, 
  822.       &(pBulkDev->outIrp)) 
  823.     != OK)
  824.         {
  825.         USB_BULK_ERR ("usbBulkCmdExecute: Unable to submit CBW IRP for transfern",
  826.                       0, 0, 0, 0, 0, 0);
  827.         return (USB_INTERNAL_ERROR);
  828.         }
  829.     /* Wait till the transfer of IRP completes or time out */
  830.  
  831.     if ( OSS_SEM_TAKE (bulkIrpSem, 
  832.                        usbBulkIrpTimeOut + USB_BULK_OFFS) 
  833.      == ERROR )
  834.         {
  835.         USB_BULK_DEBUG ("usbBulkCmdExecute: Irp Time out n", 0, 0, 0, 0, 0, 0);
  836.         OSS_SEM_GIVE (bulkIrpSem);
  837.         return (USB_INTERNAL_ERROR);
  838.         }
  839.     if (pBulkDev->outIrp.result == S_usbHcdLib_STALLED)
  840.         {
  841.         usbBulkDevResetRecovery (pBulkDev); 
  842.         OSS_SEM_GIVE (bulkIrpSem);
  843.         return (USB_BULK_IO_ERROR); 
  844.         }
  845.     /* 
  846.      * Check whether any data is to be transferred to/from the device.
  847.      * If yes, form an IRP and submit it.
  848.      */
  849.     if (pBulkDev->bulkCbw.dataXferLength > 0)
  850.         {
  851.         if (pBulkDev->bulkCbw.direction == USB_CBW_DIR_IN)
  852.             {
  853.          
  854.             /* data is expected from the device. read from BULK_IN pipe */
  855.             memset (&(pBulkDev->inIrp), 0, sizeof (USB_IRP));   
  856.             /* form an IRP to read from BULK_IN pipe */ 
  857.             pBulkDev->inIrp.irpLen            = sizeof(USB_IRP);
  858.             pBulkDev->inIrp.userCallback      = usbBulkIrpCallback; 
  859.             pBulkDev->inIrp.timeout           = usbBulkIrpTimeOut;
  860.             pBulkDev->inIrp.transferLen       = USB_BULK_SWAP_32(
  861.                                                 pBulkDev->bulkCbw.dataXferLength);
  862.             pBulkDev->inIrp.bfrCount          = 0x01;  
  863.             pBulkDev->inIrp.bfrList[0].pid    = USB_PID_IN;
  864.             pBulkDev->inIrp.bfrList[0].pBfr   = pBulkDev->bulkInData;
  865.             pBulkDev->inIrp.bfrList[0].bfrLen = USB_BULK_SWAP_32( 
  866.                                                 pBulkDev->bulkCbw.dataXferLength);
  867.             pBulkDev->inIrp.userPtr           = pBulkDev;            
  868.  
  869.             /* Submit IRP */
  870.  
  871.             if (usbdTransfer (usbdHandle, 
  872.       pBulkDev->inPipeHandle, 
  873.       &(pBulkDev->inIrp)) 
  874.     != OK)
  875.                 {
  876.                 USB_BULK_ERR ("usbBulkCmdExecute: Unable to submit IRP for "
  877.                               "BULK_IN data transfern", 0, 0, 0, 0, 0, 0);
  878.                 OSS_SEM_GIVE (bulkIrpSem); 
  879.                 return (USB_INTERNAL_ERROR);
  880.                 }
  881.             /* 
  882.              * wait till the data transfer ends on the bulk in pipe, before 
  883.              * reading the command status
  884.              */
  885.            
  886.             if ( OSS_SEM_TAKE (bulkIrpSem, 
  887.                                usbBulkIrpTimeOut + USB_BULK_OFFS)  == ERROR )
  888.                 {
  889.                 USB_BULK_DEBUG ("usbBulkCmdExecute: Irp time out n", 
  890.                                 0, 0, 0, 0, 0, 0);
  891.                 OSS_SEM_GIVE (bulkIrpSem);
  892.                 return (USB_INTERNAL_ERROR);
  893.                 }
  894.             }
  895.         else
  896.             {  
  897.             /* device is expecting data over BULK_OUT pipe. send it */
  898.         
  899.             memset (&pBulkDev->outIrp, 0, sizeof (USB_IRP));
  900.             /* form an IRP to write to BULK_OUT pipe */ 
  901.             pBulkDev->outIrp.irpLen            = sizeof(USB_IRP);
  902.             pBulkDev->outIrp.userCallback      = usbBulkIrpCallback; 
  903.             pBulkDev->outIrp.timeout           = usbBulkIrpTimeOut;
  904.             pBulkDev->outIrp.transferLen       = USB_BULK_SWAP_32(
  905.                                                  pBulkDev->bulkCbw.dataXferLength);
  906.             pBulkDev->outIrp.bfrCount          = 0x01;  
  907.             pBulkDev->outIrp.bfrList[0].pid    = USB_PID_OUT;
  908.             pBulkDev->outIrp.bfrList[0].pBfr   = pBulkDev->bulkOutData;
  909.             pBulkDev->outIrp.bfrList[0].bfrLen = USB_BULK_SWAP_32(
  910.                                                  pBulkDev->bulkCbw.dataXferLength);
  911.             pBulkDev->outIrp.userPtr           = pBulkDev;
  912.             /* Submit IRP */
  913.  
  914.             if (usbdTransfer (usbdHandle, pBulkDev->outPipeHandle, 
  915.                               &(pBulkDev->outIrp)) != OK)
  916.                 {
  917.                 USB_BULK_ERR ("usbBulkCmdExecute: Unable to submit IRP for "
  918.                               "BULK_OUT data transfern", 0, 0, 0, 0, 0, 0);
  919.                 OSS_SEM_GIVE (bulkIrpSem);  
  920.                 return (USB_INTERNAL_ERROR);
  921.                 }
  922.        
  923.             /* 
  924.              * wait till the data transfer ends on bulk out pipe before reading
  925.              * the command status 
  926.              */
  927.             if ( OSS_SEM_TAKE (bulkIrpSem, 
  928.                                usbBulkIrpTimeOut + USB_BULK_OFFS) == ERROR )
  929.                 {
  930.                 USB_BULK_DEBUG ("usbBulkCmdExecute: Irp time out n", 
  931.                                 0, 0, 0, 0, 0, 0);
  932.                 OSS_SEM_GIVE (bulkIrpSem);
  933.                 return (USB_INTERNAL_ERROR);
  934.                 }
  935.             }  
  936.         }
  937.     /* read the command status from the device. */
  938.     memset (&pBulkDev->statusIrp, 0, sizeof (USB_IRP));
  939.     /* Form an IRP to read the CSW from the BULK_IN pipe */
  940.     pBulkDev->statusIrp.irpLen            = sizeof( USB_IRP );
  941.     pBulkDev->statusIrp.userCallback      = usbBulkIrpCallback;
  942.     pBulkDev->statusIrp.timeout           = usbBulkIrpTimeOut;
  943.     pBulkDev->statusIrp.transferLen       = USB_CSW_LENGTH;
  944.     pBulkDev->statusIrp.bfrCount          = 0x01;  
  945.     pBulkDev->statusIrp.bfrList[0].pid    = USB_PID_IN;
  946.     pBulkDev->statusIrp.bfrList[0].pBfr   = (UINT8 *)(&pBulkDev->bulkCsw);
  947.     pBulkDev->statusIrp.bfrList[0].bfrLen = USB_CSW_LENGTH;
  948.     pBulkDev->statusIrp.userPtr           = pBulkDev;
  949.     /* Submit IRP */
  950.     if (usbdTransfer (usbdHandle, 
  951.       pBulkDev->inPipeHandle, 
  952.       &pBulkDev->statusIrp) 
  953.     != OK)
  954.         {
  955.         USB_BULK_ERR ("usbBulkCmdExecute: Unable to submit Status IRPn",
  956.                       0, 0, 0, 0, 0, 0);
  957.         OSS_SEM_GIVE (bulkIrpSem);
  958.         return (USB_INTERNAL_ERROR);
  959.         }
  960.     if ( OSS_SEM_TAKE (bulkIrpSem, 
  961.                        usbBulkIrpTimeOut + USB_BULK_OFFS) 
  962.      == ERROR )
  963.         {
  964.         USB_BULK_DEBUG ("usbBulkCmdExecute: Irp time out n", 
  965.                         0, 0, 0, 0, 0, 0);
  966.         OSS_SEM_GIVE (bulkIrpSem);
  967.         return (USB_INTERNAL_ERROR);
  968.         }
  969.     /* Check whether status IRP was transferred */
  970.         
  971.     if (pBulkDev->statusIrp.result == S_usbHcdLib_STALLED)  /* if stalled */
  972.         { 
  973.  
  974.         /* Clear STALL on the BULK IN endpoint */
  975.         if ((usbdFeatureClear (usbdHandle, 
  976.        pBulkDev->bulkDevId, 
  977.        USB_RT_ENDPOINT, 
  978.        USB_FSEL_DEV_ENDPOINT_HALT, 
  979.        (pBulkDev->inEpAddress & 0x7F))) 
  980.       != OK)
  981.             {
  982.             USB_BULK_ERR ("usbBulkCmdExecute: Failed to clear HALT feauture "
  983.                           "on bulk in Endpoint %xn", 0, 0, 0, 0, 0, 0);
  984.             }  
  985.         /* Try to read the CSW once again */
  986.         if (usbdTransfer (usbdHandle, 
  987.   pBulkDev->inPipeHandle, 
  988.   &pBulkDev->statusIrp) 
  989. != OK)
  990.             {
  991.             USB_BULK_ERR ("usbBulkCmdExecute: Unable to submit Status IRPn",
  992.                           0, 0, 0, 0, 0, 0);
  993.             OSS_SEM_GIVE (bulkIrpSem);
  994.             return (USB_INTERNAL_ERROR);
  995.             } 
  996.         if ( OSS_SEM_TAKE (bulkIrpSem, 
  997.                            usbBulkIrpTimeOut + USB_BULK_OFFS) 
  998.  == ERROR )
  999.             {
  1000.             USB_BULK_DEBUG ("usbBulkCmdExecute: Irp time out n", 
  1001.                             0, 0, 0, 0, 0, 0);
  1002.             OSS_SEM_GIVE (bulkIrpSem);
  1003.             return (USB_INTERNAL_ERROR);
  1004.             }
  1005.         /* how about the status this time */
  1006.         if (pBulkDev->statusIrp.result == S_usbHcdLib_STALLED)
  1007.             {
  1008.             /* Failed to read CSW again. Do reset recovery */
  1009.             
  1010.             OSS_SEM_GIVE (bulkIrpSem);
  1011.             usbBulkDevResetRecovery (pBulkDev); 
  1012.             return (USB_BULK_IO_ERROR);
  1013.             }
  1014.         }
  1015.     OSS_SEM_GIVE (bulkIrpSem);    
  1016.     /* If any error other than STALL on Endpoint. */ 
  1017.     if ( pBulkDev->statusIrp.result != OK )
  1018.         {
  1019.         return (USB_IRP_FAILED);
  1020.         }
  1021.     /* If successful in transferring the CSW IRP, check the buffer */
  1022.     pCsw = (pUSB_BULK_CSW)(pBulkDev->statusIrp.bfrList[0].pBfr);
  1023.     /* Check the length of CSW received. If not USB_CSW_LENGTH, invalid CSW. */
  1024.     if ( pBulkDev->statusIrp.bfrList[0].actLen != USB_CSW_LENGTH)
  1025.         {
  1026.         USB_BULK_ERR ("usbBulkCmdExecute: Invalid CSWn", 0, 0, 0, 0, 0, 0);
  1027.         usbBulkDevResetRecovery (pBulkDev);   
  1028.         return (USB_INVALID_CSW);
  1029.         }
  1030.     /* check the signature/tag/status in command status block */
  1031.     if ( (pCsw->signature != USB_BULK_SWAP_32 (USB_CSW_SIGNATURE)) 
  1032.          || (pCsw->tag != USB_BULK_SWAP_32 (USB_CBW_TAG))
  1033.          || (pCsw->status > USB_CSW_PHASE_ERROR))
  1034.         {
  1035.         USB_BULK_ERR ("usbBulkCmdExecute: Logical Error in status blockn", 
  1036.                       0, 0, 0, 0, 0, 0);   
  1037.         usbBulkDevResetRecovery (pBulkDev);
  1038.         return (USB_INVALID_CSW);
  1039.         }
  1040.  
  1041.     /* check for Data residue. */ 
  1042.         
  1043.     if (pCsw->dataResidue > 0) 
  1044.         { 
  1045.         USB_BULK_ERR ("usbBulkCmdExecute: Data transfer incompleten", 
  1046.                       0, 0, 0, 0, 0, 0);   
  1047.         return (USB_DATA_INCOMPLETE); 
  1048.         }
  1049.     /* It is a valid CSW. Check for the status of the CBW executed */
  1050.     if ( pCsw->status == USB_CSW_STATUS_FAIL )  /* Command failed */
  1051.         {
  1052.         USB_BULK_ERR ("usbBulkCmdExecute: CBW Failed n", 0, 0, 0, 0, 0, 0);
  1053.         return (USB_COMMAND_FAILED); 
  1054.         } 
  1055.     else if (pCsw->status == USB_CSW_PHASE_ERROR) 
  1056.         {
  1057.         /* Phase error while executing the command in CBW. Reset recovery */ 
  1058.         USB_BULK_ERR ("usbBulkCmdExecute: Phase Errorn", 0, 0, 0, 0, 0, 0);
  1059.            
  1060.         /* fatal error. do a reset recovery */        
  1061.         usbBulkDevResetRecovery (pBulkDev);
  1062.         return (USB_PHASE_ERROR);
  1063.         }    
  1064.     return (USB_COMMAND_SUCCESS);
  1065.     }
  1066. /***************************************************************************
  1067. *
  1068. * usbBulkDevDestroy - release USB_BULK_DEV structure and its links
  1069. *
  1070. * Unlinks the indicated USB_BULK_DEV structure and de-allocates
  1071. * resources associated with the device.
  1072. *
  1073. * RETURNS: N/A
  1074. */
  1075. LOCAL void usbBulkDevDestroy
  1076.     (
  1077.     pUSB_BULK_DEV pBlkDev       /* pointer to bulk device   */
  1078.     )
  1079.     {
  1080.     pUSB_BULK_DEV pBulkDev = (pUSB_BULK_DEV) pBlkDev;
  1081.     if (pBulkDev != NULL)
  1082.         {
  1083.         /* Unlink the structure. */
  1084.         usbListUnlink (&pBulkDev->bulkDevLink);
  1085.         /* Release pipes and wait for IRPs. */
  1086.         if (pBulkDev->outPipeHandle != NULL)
  1087.             usbdPipeDestroy (usbdHandle, pBulkDev->outPipeHandle);
  1088.         if (pBulkDev->inPipeHandle != NULL)
  1089.             usbdPipeDestroy (usbdHandle, pBulkDev->inPipeHandle);
  1090.         /* wait for any IRP to complete */
  1091.         OSS_SEM_TAKE (bulkIrpSem, OSS_BLOCK); 
  1092.         OSS_SEM_GIVE (bulkIrpSem);
  1093.         /* Release structure. */
  1094.         OSS_FREE (pBulkDev);
  1095.         }
  1096.     }
  1097. /***************************************************************************
  1098. *
  1099. * usbBulkDevFind - Searches for a USB_BULK_DEV for indicated node ID
  1100. *
  1101. * RETURNS: pointer to matching USB_BULK_DEV or NULL if not found
  1102. */
  1103. LOCAL pUSB_BULK_DEV usbBulkDevFind
  1104.     (
  1105.     USBD_NODE_ID nodeId          /* node ID to be looked for */
  1106.     )
  1107.     {
  1108.     pUSB_BULK_DEV pBulkDev = usbListFirst (&bulkDevList);
  1109.     /* browse through the list */
  1110.     while (pBulkDev != NULL)
  1111.         {
  1112.         if (pBulkDev->bulkDevId == nodeId)
  1113.         break;
  1114.         pBulkDev = usbListNext (&pBulkDev->bulkDevLink);
  1115.         }
  1116.     return (pBulkDev);
  1117.     }
  1118. /***************************************************************************
  1119. *
  1120. * findEndpoint - Searches for a BULK endpoint of the indicated direction.
  1121. *
  1122. * RETURNS: pointer to matching endpoint descriptor or NULL if not found
  1123. */
  1124. LOCAL pUSB_ENDPOINT_DESCR findEndpoint
  1125.     (
  1126.     pUINT8 pBfr,
  1127.     UINT16 bfrLen,
  1128.     UINT16 direction
  1129.     )
  1130.     {
  1131.     pUSB_ENDPOINT_DESCR pEp;
  1132.     while ((pEp = usbDescrParseSkip (&pBfr, &bfrLen, USB_DESCR_ENDPOINT)) 
  1133.           != NULL)
  1134.         {
  1135.         if ((pEp->attributes & USB_ATTR_EPTYPE_MASK) == USB_ATTR_BULK &&
  1136.             (pEp->endpointAddress & USB_ENDPOINT_DIR_MASK) == direction)
  1137.             break;
  1138.         }
  1139.     return pEp;
  1140.     }
  1141. /***************************************************************************
  1142. *
  1143. * usbBulkPhysDevCreate - create a USB_BULK_DEV Structure for the device attached
  1144. *
  1145. * This function is invoked from the dynamic attach callback routine whenever 
  1146. * a USB_BULK_DEV device is attached.  It allocates memory for the structure,
  1147. * sets device configuration, and creates pipe for bulk-in and bulk-out endpoints.
  1148. * RETURNS: OK on success, ERROR if failed to create pipes, set configuration
  1149. */
  1150. LOCAL STATUS usbBulkPhysDevCreate
  1151.     (
  1152.     USBD_NODE_ID nodeId,         /* USBD Node Id ofthe device */     
  1153.     UINT16       configuration,  /* Configuration value       */ 
  1154.     UINT16       interface       /* Interface Number          */ 
  1155.     )
  1156.     {
  1157.     UINT16   actLength;
  1158.     UINT8  *  pBfr;           /* pointer to descriptor store */ 
  1159.     UINT8  * pScratchBfr;       /* another pointer to the above store */ 
  1160.     UINT     ifNo;
  1161.     UINT16   maxPacketSize;  
  1162.     USB_BULK_DEV * pBulkDev;
  1163.     USB_CONFIG_DESCR * pCfgDescr;
  1164.     USB_INTERFACE_DESCR * pIfDescr;
  1165.     USB_ENDPOINT_DESCR * pOutEp;
  1166.     USB_ENDPOINT_DESCR * pInEp;
  1167.     /*
  1168.      * A new device is being attached. Check if we already 
  1169.      * have a structure for this device.
  1170.      */
  1171.     if (usbBulkDevFind (nodeId) != NULL)
  1172.         return (OK);
  1173.     /* Allocate a non-cacheable buffer for the descriptor's */
  1174.     if ((pBfr = OSS_MALLOC (USB_MAX_DESCR_LEN)) == NULL)
  1175. {        
  1176. USB_BULK_ERR ("usbBulkPhysDevCreate: Unable to allocate memory:pBfrn",
  1177.                         0, 0, 0, 0, 0, 0);
  1178.         return ERROR;
  1179.         }
  1180.     /* Allocate memory for a new structure to represent this device */
  1181.     if ((pBulkDev = OSS_CALLOC (sizeof (*pBulkDev))) == NULL)
  1182.         {
  1183.         USB_BULK_ERR ("usbBulkPhysDevCreate: Unable to allocate 
  1184. memory:pBulkDevn", 0, 0, 0, 0, 0, 0);
  1185.         goto errorExit;
  1186.         }
  1187.     pBulkDev->bulkDevId     = nodeId; 
  1188.     pBulkDev->configuration = configuration;
  1189.     pBulkDev->interface     = interface;
  1190.     pBulkDev->connected     = TRUE;
  1191.     /* Check out the device configuration */
  1192.     /* Configuration index is assumed to be one less than config'n value */
  1193.     if (usbdDescriptorGet (usbdHandle, 
  1194.    pBulkDev->bulkDevId, 
  1195.    USB_RT_STANDARD | USB_RT_DEVICE, 
  1196.    USB_DESCR_CONFIGURATION, 
  1197.    (configuration - 1), 
  1198.    0, 
  1199.    USB_MAX_DESCR_LEN, 
  1200.    pBfr, 
  1201.    &actLength) 
  1202.   != OK)  
  1203.         {
  1204.         USB_BULK_ERR ("usbBulkPhysDevCreate: Unable to read configuration "
  1205.                       "descriptorn", 0, 0, 0, 0, 0, 0);
  1206.         goto errorExit;
  1207.         }
  1208.     if ((pCfgDescr = usbDescrParse (pBfr, 
  1209.     actLength, 
  1210.     USB_DESCR_CONFIGURATION)) 
  1211.  == NULL)
  1212.         {
  1213.         USB_BULK_ERR ("usbBulkPhysDevCreate: Unable to find configuration "
  1214.                       "descriptorn", 0, 0, 0, 0, 0, 0);
  1215.         goto errorExit;
  1216.         }
  1217.     /* Look for the interface representing the MSC/SCSI/BULK_ONLY. */
  1218.     ifNo = 0;
  1219.     /*
  1220.      * usbDescrParseSkip() modifies the value of the pointer it recieves
  1221.      * so we pass it a copy of our buffer pointer
  1222.      */
  1223.     pScratchBfr = pBfr;
  1224.     while ((pIfDescr = usbDescrParseSkip (&pScratchBfr, 
  1225.   &actLength, 
  1226.   USB_DESCR_INTERFACE)) 
  1227. != NULL)
  1228.         {
  1229.         if (ifNo == pBulkDev->interface)
  1230.             break;
  1231.         ifNo++;
  1232.         }
  1233.     if (pIfDescr == NULL)
  1234.         goto errorExit;
  1235.     pBulkDev->altSetting = pIfDescr->alternateSetting;
  1236.     /* 
  1237.      * Retrieve the endpoint descriptor(s) following the identified interface
  1238.      * descriptor.
  1239.      */
  1240.     if ((pOutEp = findEndpoint (pScratchBfr, 
  1241. actLength, 
  1242. USB_ENDPOINT_OUT)) 
  1243.    == NULL)
  1244.         goto errorExit;
  1245.     if ((pInEp = findEndpoint (pScratchBfr, 
  1246.        actLength, 
  1247.        USB_ENDPOINT_IN)) 
  1248.      == NULL)
  1249.         goto errorExit;
  1250.     pBulkDev->outEpAddress = pOutEp->endpointAddress;
  1251.     pBulkDev->inEpAddress  = pInEp->endpointAddress;
  1252.     /* Set the device configuration corresponding to MSC/SCSI/BULK-ONLY */
  1253.     if ((usbdConfigurationSet (usbdHandle, 
  1254.        pBulkDev->bulkDevId, 
  1255.        pBulkDev->configuration, 
  1256.        pCfgDescr->maxPower * USB_POWER_MA_PER_UNIT)) 
  1257.      != OK )
  1258.         {
  1259.         USB_BULK_ERR ("usbBulkPhysDevCreate: Unable to set device "
  1260.                       "configuration n", 0, 0, 0, 0, 0, 0);
  1261.         goto errorExit;
  1262.         }
  1263.     else
  1264.         {
  1265.         USB_BULK_DEBUG ("usbBulkPhysDevCreate: Configuration set to 0x%x n",
  1266.                         pBulkDev->configuration, 0, 0, 0, 0, 0);
  1267.         }
  1268.     
  1269.    /* Select interface 
  1270.     * 
  1271.     * NOTE: Some devices may reject this command, and this does not represent
  1272.     * a fatal error.  Therefore, we ignore the return status.
  1273.     */
  1274.     usbdInterfaceSet (usbdHandle, 
  1275.       pBulkDev->bulkDevId,
  1276.       pBulkDev->interface, 
  1277.       pBulkDev->altSetting);
  1278.     maxPacketSize = *((pUINT8) &pOutEp->maxPacketSize) |
  1279.                     (*(((pUINT8) &pOutEp->maxPacketSize) + 1) << 8);
  1280.     /* Create a Bulk-out pipe for the MSC/SCSI/BULK-ONLY device */
  1281.     if (usbdPipeCreate (usbdHandle, 
  1282. pBulkDev->bulkDevId, 
  1283. pOutEp->endpointAddress, 
  1284. pBulkDev->configuration, 
  1285. pBulkDev->interface, 
  1286. USB_XFRTYPE_BULK, 
  1287. USB_DIR_OUT, 
  1288. maxPacketSize, 
  1289. 0, 
  1290. 0, 
  1291. &(pBulkDev->outPipeHandle)) 
  1292.       != OK)
  1293.         {
  1294.         USB_BULK_ERR ("usbBulkPhysDevCreate: Error creating bulk out pipen",
  1295.                         0, 0, 0, 0, 0, 0);
  1296.         goto errorExit;
  1297.         } 
  1298.     maxPacketSize = *((pUINT8) &pInEp->maxPacketSize) |
  1299.     (*(((pUINT8) &pInEp->maxPacketSize) + 1) << 8);
  1300.     /* Create a Bulk-in pipe for the MSC/SCSI/BULK-ONLY device */
  1301.        
  1302.     if (usbdPipeCreate (usbdHandle, 
  1303. pBulkDev->bulkDevId, 
  1304. pInEp->endpointAddress, 
  1305. pBulkDev->configuration, 
  1306. pBulkDev->interface, 
  1307. USB_XFRTYPE_BULK, 
  1308. USB_DIR_IN, 
  1309. maxPacketSize, 
  1310. 0, 
  1311. 0, 
  1312. &(pBulkDev->inPipeHandle)) 
  1313.       != OK)
  1314.         {
  1315.         USB_BULK_ERR ("usbBulkPhysDevCreate: Error creating bulk in pipen",
  1316.                         0, 0, 0, 0, 0, 0);
  1317.         goto errorExit;
  1318.         } 
  1319.     /* Clear HALT feauture on the endpoints */
  1320.     if ((usbdFeatureClear (usbdHandle, 
  1321.    pBulkDev->bulkDevId, 
  1322.    USB_RT_ENDPOINT, 
  1323.    USB_FSEL_DEV_ENDPOINT_HALT, 
  1324.    (pOutEp->endpointAddress & 0x0F))) 
  1325.  != OK)
  1326.         {
  1327.         USB_BULK_ERR ("usbBulkPhysDevCreate: Failed to clear HALT feauture "
  1328.                       "on bulk out Endpoint %xn", 0, 0, 0, 0, 0, 0);
  1329.         }  
  1330.     if ((usbdFeatureClear (usbdHandle, 
  1331.    pBulkDev->bulkDevId, 
  1332.    USB_RT_ENDPOINT, 
  1333.    USB_FSEL_DEV_ENDPOINT_HALT, 
  1334.    (pOutEp->endpointAddress & 0x0F))) 
  1335.  != OK)
  1336.         {
  1337.         USB_BULK_ERR ("usbBulkPhysDevCreate: Failed to clear HALT feauture "
  1338.                       "on bulk in Endpoint %xn", 0, 0, 0, 0, 0, 0);
  1339.         } 
  1340.     /* Link the newly created structure. */
  1341.     usbListLink (&bulkDevList, pBulkDev, &pBulkDev->bulkDevLink, LINK_TAIL);
  1342.     
  1343.     OSS_FREE (pBfr);
  1344.     return (OK);
  1345. errorExit:
  1346.     /* Error in creating a bulk device ..destroy */
  1347.     OSS_FREE (pBfr);
  1348.     usbBulkDevDestroy (pBulkDev);
  1349.     return (ERROR);
  1350.     }
  1351. /***************************************************************************
  1352. *
  1353. * usbBulkBlkDevCreate - create a block device.
  1354. *
  1355. * This routine  initializes a BLK_DEV structure, which describes a 
  1356. * logical partition on a USB_BULK_DEV device.  A logical partition is an array 
  1357. * of contiguously addressed blocks; it can be completely described by the number
  1358. * of blocks and the address of the first block in the partition.  
  1359. *
  1360. * NOTE:
  1361. * If `numBlocks' is 0, the rest of device is used.
  1362. * This routine supplies an additional parameter called <flags>.  This bitfield 
  1363. * currently only uses bit 1.  This bit determines whether the driver will use a
  1364. * SCSI READ6 or SCSI READ10 for read access.
  1365. *
  1366. * RETURNS: A pointer to the BLK_DEV, or NULL if parameters exceed
  1367. * physical device boundaries, or if no bulk device exists.
  1368. */
  1369. BLK_DEV * usbBulkBlkDevCreate
  1370.     (
  1371.     USBD_NODE_ID nodeId,        /* nodeId of the bulk-only device     */ 
  1372.     UINT32       numBlks,       /* number of logical blocks on device */
  1373.     UINT32       blkOffset,     /* offset of the starting block       */ 
  1374.     UINT32       flags /* optional flags       */ 
  1375.     )
  1376.     {
  1377.     UINT8 * pInquiry;         /* store for INQUIRY data  */
  1378.     pUSB_BULK_DEV pBulkDev  = usbBulkDevFind (nodeId);
  1379.     OSS_MUTEX_TAKE (bulkDevMutex, OSS_BLOCK); 
  1380.     if ((pInquiry = OSS_MALLOC (USB_SCSI_STD_INQUIRY_LEN)) == NULL)
  1381. {
  1382.         USB_BULK_ERR ("usbBulkBlkDevCreate: Error allocating memoryn",
  1383.                         0, 0, 0, 0, 0, 0);
  1384.         OSS_MUTEX_RELEASE (bulkDevMutex);
  1385.         return (NULL);
  1386.         }
  1387.     if (pBulkDev == NULL)
  1388.         {
  1389.         USB_BULK_ERR ("usbBulkBlkDevCreate: No MSC/SCSI/BULK-ONLY foundn",
  1390.                         0, 0, 0, 0, 0, 0);
  1391. OSS_FREE (pInquiry);
  1392.         OSS_MUTEX_RELEASE (bulkDevMutex);
  1393.         return (NULL);
  1394.         }
  1395.     /* 
  1396.      * Initialize the standard block device structure for use with file 
  1397.      * systems.
  1398.      */
  1399.     pBulkDev->blkDev.bd_blkRd        = (FUNCPTR) usbBulkDevBlkRd;
  1400.     pBulkDev->blkDev.bd_blkWrt       = (FUNCPTR) usbBulkDevBlkWrt;
  1401.     pBulkDev->blkDev.bd_ioctl        = (FUNCPTR) usbBulkDevIoctl;
  1402.     pBulkDev->blkDev.bd_reset        = (FUNCPTR) usbBulkDevReset; 
  1403.     pBulkDev->blkDev.bd_statusChk    = (FUNCPTR) usbBulkDevStatusChk;
  1404.     pBulkDev->blkDev.bd_retry        = 1;
  1405.     pBulkDev->blkDev.bd_mode         = O_RDWR;
  1406.     pBulkDev->blkDev.bd_readyChanged = TRUE;
  1407.     /* 
  1408.      * Read out the standard INQUIRY information from the device, mainly to
  1409.      * check whether the media is removable or not.
  1410.      */
  1411.     pBulkDev->bulkInData  = pInquiry;
  1412.  
  1413.     if ( usbBulkFormScsiCmd (pBulkDev, USB_SCSI_INQUIRY, 0, 0) != OK )
  1414.         {
  1415.         USB_BULK_ERR ("usbBulkBlkDevCreate: Error forming commandn",
  1416.                         0, 0, 0, 0, 0, 0);
  1417. OSS_FREE (pInquiry);
  1418.         OSS_MUTEX_RELEASE (bulkDevMutex);
  1419.         return (NULL); 
  1420.         } 
  1421.     if ( usbBulkCmdExecute (pBulkDev) != USB_COMMAND_SUCCESS )
  1422.         {
  1423.         USB_BULK_ERR ("usbBulkBlkDevCreate: Error executing USB_SCSI_INQUIRY "
  1424.                       "commandn", 0, 0, 0, 0, 0, 0);        
  1425. OSS_FREE (pInquiry);
  1426.         OSS_MUTEX_RELEASE (bulkDevMutex);
  1427.         return (NULL);  
  1428.         }
  1429.  
  1430.     /* Check the media type bit  */
  1431.     if (*(pInquiry+1) & USB_SCSI_INQUIRY_RMB_BIT)
  1432.         {
  1433.         pBulkDev->blkDev.bd_removable = TRUE;
  1434.         }
  1435.     else
  1436.         {
  1437.         pBulkDev->blkDev.bd_removable = FALSE;      
  1438.         }
  1439.     /* read the block size and capacity of device (in terms of blocks) */
  1440.     if ( usbBulkFormScsiCmd (pBulkDev, 
  1441.      USB_SCSI_READ_CAPACITY, 
  1442.      0, 
  1443.      0) 
  1444.    != OK )
  1445.         {
  1446. OSS_FREE (pInquiry);
  1447.         OSS_MUTEX_RELEASE (bulkDevMutex); 
  1448.         return (NULL); 
  1449.         } 
  1450.     /* 
  1451.      * Read Capacity command will usually return CHECK CONDITION status
  1452.      * very first time, just try again.
  1453.      */
  1454.     if ( usbBulkCmdExecute (pBulkDev) != USB_COMMAND_SUCCESS )
  1455.         {
  1456.         if ( usbBulkCmdExecute (pBulkDev) != USB_COMMAND_SUCCESS )  
  1457.             {
  1458.             USB_BULK_ERR ("usbBulkBlkDevCreate: Read Capacity command failedn",
  1459.                           0, 0, 0, 0, 0, 0);
  1460.     OSS_FREE (pInquiry);
  1461.             OSS_MUTEX_RELEASE (bulkDevMutex);
  1462.             return (NULL);  
  1463.             } 
  1464.         } 
  1465.     
  1466.     /*
  1467.      * Response is in BIG endian format. Swap it to get correct value.
  1468.      * Also, READ_CAPACITY returns the address of the last logical block,
  1469.      * NOT the number of blocks.  Since the blkDev structure wants the
  1470.      * number of blocks, we add 1 (numBlocks = last address + 1).
  1471.      */
  1472.     pBulkDev->numBlks   = USB_SCSI_SWAP_32(*((UINT32 *) pInquiry)) + 1;
  1473.     pBulkDev->blkOffset = blkOffset;
  1474.     if ( numBlks == 0 )
  1475.         pBulkDev->blkDev.bd_nBlocks = (pBulkDev->numBlks - blkOffset); 
  1476.     else 
  1477.         pBulkDev->blkDev.bd_nBlocks = numBlks;
  1478.  
  1479.     pBulkDev->blkDev.bd_bytesPerBlk = 
  1480. USB_SCSI_SWAP_32(*((UINT32 *)(pInquiry+4))); 
  1481.     /* determine which type of SCSI read command is implemnted */
  1482.     if ( (flags & USB_SCSI_FLAG_READ_WRITE10) == 1 )
  1483. pBulkDev->read10Able = TRUE;
  1484.     else
  1485. pBulkDev->read10Able = FALSE;
  1486.     OSS_FREE (pInquiry);
  1487.     OSS_MUTEX_RELEASE (bulkDevMutex);
  1488.     return (&pBulkDev->blkDev);
  1489.        
  1490.     }        
  1491. /***************************************************************************
  1492. *
  1493. * usbBulkDevBlkRd - routine to read one or more blocks from the device.
  1494. *
  1495. * This routine reads the specified physical sector(s) from a specified
  1496. * physical device.  Typically called by file system when data is to be
  1497. * read from a particular device.
  1498. *
  1499. * RETURNS: OK on success, or ERROR if failed to read from device
  1500. */
  1501. LOCAL STATUS usbBulkDevBlkRd
  1502.     (
  1503.     BLK_DEV * pBlkDev,           /* pointer to bulk device   */ 
  1504.     int       blkNum,            /* logical block number     */
  1505.     int       numBlks,           /* number of blocks to read */
  1506.     char *    pBuf               /* store for data           */ 
  1507.     )
  1508.     {
  1509.     pUSB_BULK_DEV  pBulkDev = (USB_BULK_DEV *)pBlkDev;   
  1510.     UINT readType;
  1511.     /*  Ensure that the device has not been removed during a transfer */
  1512.     if ( pBulkDev->connected == FALSE ) 
  1513. return ERROR;
  1514.     USB_BULK_DEBUG ("usbBulkDevBlkRd: Number of blocks = %d, Starting blk = %dn",
  1515.                     numBlks, blkNum, 0, 0, 0, 0); 
  1516.     OSS_MUTEX_TAKE (bulkDevMutex, OSS_BLOCK);
  1517.     /* intialise the pointer to store bulk in data */ 
  1518.     pBulkDev->bulkInData = (UINT8 *)pBuf ; 
  1519.     if (pBulkDev->read10Able)
  1520. readType = USB_SCSI_READ10;
  1521.     else 
  1522. readType = USB_SCSI_READ6;
  1523.     if ( usbBulkFormScsiCmd (pBulkDev, 
  1524.      readType, 
  1525.      blkNum, 
  1526.      numBlks) 
  1527.    != OK )
  1528.         {
  1529.         OSS_MUTEX_RELEASE (bulkDevMutex);
  1530.         return (ERROR);  
  1531.         }
  1532.     if ( usbBulkCmdExecute (pBulkDev) != USB_COMMAND_SUCCESS )
  1533.         {
  1534.         OSS_MUTEX_RELEASE (bulkDevMutex);
  1535.         return (ERROR); 
  1536.         }
  1537.     OSS_MUTEX_RELEASE (bulkDevMutex);
  1538.     return (OK);
  1539.   
  1540.     }
  1541. /***************************************************************************
  1542. *
  1543. * usbBulkDevBlkWrt - routine to write one or more blocks to the device.
  1544. *
  1545. * This routine writes the specified physical sector(s) to a specified physical
  1546. * device.
  1547. *
  1548. * RETURNS: OK on success, or ERROR if failed to write to device
  1549. */
  1550. LOCAL STATUS usbBulkDevBlkWrt
  1551.     (
  1552.     BLK_DEV * pBlkDev,           /* pointer to bulk device    */  
  1553.     int       blkNum,            /* logical block number      */
  1554.     int       numBlks,           /* number of blocks to write */ 
  1555.     char *    pBuf               /* data to be written        */ 
  1556.     )
  1557.     {
  1558.     pUSB_BULK_DEV  pBulkDev = (USB_BULK_DEV *)pBlkDev;   
  1559.     UINT writeType;
  1560.     /*  Ensure that the device has not been removed during a transfer */
  1561.     if ( pBulkDev->connected == FALSE ) 
  1562. return ERROR;
  1563.     USB_BULK_DEBUG ("usbBulkDevBlkWrt: Number of blocks = %d, Starting blk = %dn",
  1564.                     numBlks, blkNum, 0, 0, 0, 0);
  1565.     OSS_MUTEX_TAKE (bulkDevMutex, OSS_BLOCK); 
  1566.     /* initialise the pointer to fetch bulk out data */
  1567.     pBulkDev->bulkOutData = (UINT8 *)pBuf;
  1568.     if (pBulkDev->read10Able)
  1569. writeType = USB_SCSI_WRITE10;
  1570.     else 
  1571. writeType = USB_SCSI_WRITE6;
  1572.     if ( usbBulkFormScsiCmd (pBulkDev, 
  1573.      writeType, 
  1574.      blkNum, 
  1575.                              numBlks) 
  1576.    != OK )
  1577.         {
  1578.         OSS_MUTEX_RELEASE (bulkDevMutex);
  1579.         return (ERROR); 
  1580.         }
  1581.     if ( usbBulkCmdExecute (pBulkDev) != USB_COMMAND_SUCCESS )
  1582.         {
  1583.         OSS_MUTEX_RELEASE (bulkDevMutex);
  1584.         return (ERROR); 
  1585.         }
  1586.     OSS_MUTEX_RELEASE (bulkDevMutex);
  1587.     return (OK);
  1588.     }
  1589. /***************************************************************************
  1590. *
  1591. * usbBulkIrpCallback - Invoked upon IRP completion
  1592. *
  1593. * Examines the status of the IRP submitted.  
  1594. *
  1595. * RETURNS: N/A
  1596. */
  1597. LOCAL void usbBulkIrpCallback
  1598.     (
  1599.     pVOID p                      /* pointer to the IRP submitted */
  1600.     )
  1601.     {
  1602.     pUSB_IRP      pIrp     = (pUSB_IRP) p;
  1603.     pUSB_BULK_DEV pBulkDev = pIrp->userPtr;
  1604.     /* check whether the IRP was for bulk out/ bulk in / status transport */
  1605.     if (pIrp == &(pBulkDev->outIrp))
  1606.         {  
  1607.         if (pIrp->result == OK)     /* check the result of IRP */
  1608.             {
  1609.             USB_BULK_DEBUG ("usbBulkIrpCallback: Num of Bytes transferred on "
  1610.                             "out pipe %dn", pIrp->bfrList[0].actLen, 
  1611.                             0, 0, 0, 0, 0); 
  1612.             }
  1613.         else
  1614.             {
  1615.             USB_BULK_ERR ("usbBulkIrpCallback: Irp failed on Bulk Out %x n",
  1616.                             pIrp->result, 0, 0, 0, 0, 0); 
  1617.             /* Clear HALT Feature on Bulk out Endpoint */ 
  1618.             if ((usbdFeatureClear (usbdHandle, 
  1619.    pBulkDev->bulkDevId, 
  1620.    USB_RT_ENDPOINT, 
  1621.    USB_FSEL_DEV_ENDPOINT_HALT, 
  1622.    (pBulkDev->outEpAddress & 0x0F))) 
  1623.  != OK)
  1624.                 {
  1625.                 USB_BULK_ERR ("usbBulkIrpCallback: Failed to clear HALT "
  1626.                               "feauture on bulk out Endpoint %xn", 0, 0, 0, 
  1627.                               0, 0, 0);
  1628.                 }
  1629.             }
  1630.       
  1631.         } 
  1632.     else if (pIrp == &(pBulkDev->statusIrp))    /* if status block IRP */
  1633.         {
  1634.         if (pIrp->result == OK)     /* check the result of the IRP */
  1635.             {
  1636.             USB_BULK_DEBUG ("usbBulkIrpCallback : Num of Status Bytes 
  1637.                             read  =%d n", pIrp->bfrList[0].actLen, 0, 0, 0, 0, 0);
  1638.             }
  1639.         else     /* status IRP failed */
  1640.             {
  1641.             USB_BULK_ERR ("usbBulkIrpCallback: Status Irp failed on Bulk in "
  1642.                           "%xn", pIrp->result, 0, 0, 0, 0, 0);
  1643.             } 
  1644.         }
  1645.     else     /* IRP for bulk_in data */
  1646.         {
  1647.         if (pIrp->result == OK)
  1648.             {
  1649.             USB_BULK_DEBUG ("usbBulkIrpCallback: Num of Bytes read from Bulk "
  1650.                             "In =%dn", pIrp->bfrList[0].actLen, 0, 0, 0, 0, 0); 
  1651.             }
  1652.         else   /* IRP on BULK IN failed */
  1653.             {
  1654.             USB_BULK_ERR ("usbBulkIrpCallback : Irp failed on Bulk in ,%xn", 
  1655.                             pIrp->result, 0, 0, 0, 0, 0);
  1656.             /* Clear HALT Feature on Bulk in Endpoint */
  1657.             if ((usbdFeatureClear (usbdHandle, pBulkDev->bulkDevId, USB_RT_ENDPOINT, 
  1658.                                    USB_FSEL_DEV_ENDPOINT_HALT, 
  1659.                                    (pBulkDev->inEpAddress & 0x0F))) != OK)
  1660.                 {
  1661.                 USB_BULK_ERR ("usbBulkIrpCallback: Failed to clear HALT "
  1662.                               "feature on bulk in Endpoint %xn", 0, 0, 0, 0, 0, 0);
  1663.                 }
  1664.             }
  1665.         }
  1666.     OSS_SEM_GIVE (bulkIrpSem);
  1667.    
  1668.     }   
  1669.   
  1670. /***************************************************************************
  1671. *
  1672. * usbBulkDevStatusChk - routine to check device status
  1673. *
  1674. * Typically called by the file system before doing a read/write to the device.
  1675. * The routine issues a TEST_UNIT_READY command.  Also, if the device is not
  1676. * ready, then the sense data is read from the device to check for presence/
  1677. * change of media.  For removable devices, the ready change flag is set to 
  1678. * indicate media change.  File system checks this flag, and remounts the device
  1679. *
  1680. * RETURNS: OK if the device is ready for IO, or ERROR if device is busy. 
  1681. */
  1682. LOCAL STATUS usbBulkDevStatusChk
  1683.     (
  1684.     BLK_DEV *pBlkDev             /* pointer to bulk device */
  1685.     )
  1686.     {
  1687.      
  1688.     USB_COMMAND_STATUS status;
  1689.     UINT8   requestSense[20];         /* store for REQUEST SENSE data  */                 
  1690.     /* 
  1691.      * requestSense can be a automatic buffer because it is not 
  1692.      * passed to the hardware.  Instead it is a place holder for 
  1693.      * data read from the hardware.
  1694.      */
  1695.     pUSB_BULK_DEV  pBulkDev = (USB_BULK_DEV *)pBlkDev;    
  1696.  
  1697.     OSS_MUTEX_TAKE (bulkDevMutex, OSS_BLOCK);
  1698.     /* 
  1699.      * The device might take long time to respond when the disk is
  1700.      * changed. So the time out for this IRP is increased.
  1701.      */
  1702.     usbBulkIrpTimeOut = (USB_BULK_IRP_TIME_OUT * 4);
  1703.     /* Form a SCSI Test Unit Ready command and send it */ 
  1704.  
  1705.     if ( usbBulkFormScsiCmd (pBulkDev, 
  1706.      USB_SCSI_TEST_UNIT_READY, 
  1707.      0, 
  1708.      0) 
  1709.    != OK )
  1710.         {
  1711.         OSS_MUTEX_RELEASE (bulkDevMutex);
  1712.         return (ERROR); 
  1713.         } 
  1714.     status = usbBulkCmdExecute (pBulkDev);
  1715.     usbBulkIrpTimeOut = USB_BULK_IRP_TIME_OUT;
  1716.     if (status == USB_COMMAND_FAILED )
  1717.         {
  1718.         /* TEST_UNIT_READY command failed.  Get request sense data.*/
  1719.         pBulkDev->bulkInData = requestSense;
  1720.         if ( usbBulkFormScsiCmd (pBulkDev, 
  1721.  USB_SCSI_REQ_SENSE, 
  1722.  0, 
  1723.  0) 
  1724. != OK )
  1725.             {
  1726.             USB_BULK_ERR ("usbBulkDevStatusChk: Error forming commandn",
  1727.                           0, 0, 0, 0, 0, 0);
  1728.             OSS_MUTEX_RELEASE (bulkDevMutex);
  1729.             return (ERROR); 
  1730.             } 
  1731.         if ( usbBulkCmdExecute (pBulkDev) != USB_COMMAND_SUCCESS )
  1732.             {
  1733.             USB_BULK_ERR ("usbBulkDevStatusChk: Error executing USB_SCSI_REQ_SENSE" 
  1734.                           "commandn", 0, 0, 0, 0, 0, 0);        
  1735.             OSS_MUTEX_RELEASE (bulkDevMutex);
  1736.             return (ERROR);  
  1737.             }
  1738.         /* Check the sense data for possible reasons of CHECK_CONDITION */
  1739.         /* This is really needed for removable media to declare media change or
  1740.          * or media not present. Once request sense is read, the device shall be
  1741.          * ready for further commands.
  1742.          */       
  1743.         /* check for media change */
  1744.         if (((requestSense [USB_SCSI_SENSE_KEY_OFFSET]) & 
  1745.             (USB_SCSI_SENSE_KEY_MASK)) == USB_SCSI_KEY_UNIT_ATTN)
  1746.             {
  1747.             if (requestSense [USB_SCSI_SENSE_ASC] == USB_SCSI_ASC_RESET) 
  1748.                 {
  1749.                 USB_BULK_ERR ("usbBulkDevStatusChk: Bus reset or media "
  1750.                               "change n", 0, 0, 0, 0, 0, 0);
  1751.                 /* declare that device has to be mounted on next IO operation */
  1752.                 if (pBulkDev->blkDev.bd_removable == TRUE)
  1753.                     pBulkDev->blkDev.bd_readyChanged = TRUE;
  1754.                 OSS_MUTEX_RELEASE (bulkDevMutex);
  1755.                 return (OK);
  1756.                 }
  1757.             }
  1758.         /* check for media present */
  1759.         if (((requestSense [USB_SCSI_SENSE_KEY_OFFSET]) & 
  1760.             (USB_SCSI_SENSE_KEY_MASK)) == USB_SCSI_KEY_NOT_READY)
  1761.             {
  1762.             if (requestSense [USB_SCSI_SENSE_ASC] == USB_SCSI_ASC_NO_MEDIA) 
  1763.                 {
  1764.                 USB_BULK_ERR ("usbBulkDevStatusChk: Media not presentn",
  1765.                               0, 0, 0, 0, 0, 0);
  1766.                 /* declare that device has to be mounted on next IO operation */
  1767.                 if (pBulkDev->blkDev.bd_removable == TRUE)
  1768.                     pBulkDev->blkDev.bd_readyChanged = TRUE;
  1769.                 }
  1770.                 /* return ERROR */
  1771.             }  
  1772.         /* For all other conditions, return error */ 
  1773.         OSS_MUTEX_RELEASE (bulkDevMutex);  
  1774.         return (ERROR);
  1775.         
  1776.         } 
  1777.     else if (status != USB_COMMAND_SUCCESS) /* other than COMMAND_FAILED error */
  1778.         {
  1779.         OSS_MUTEX_RELEASE (bulkDevMutex);
  1780.         return (ERROR);
  1781.         }   
  1782.     /* if we are here, then TEST UNIT READY command returned device is READY */
  1783.     OSS_MUTEX_RELEASE (bulkDevMutex);
  1784.     return (OK);
  1785.     }
  1786. /***************************************************************************
  1787. *
  1788. * usbBulkDevReset -  routine to reset the MSC/SCSI/BULK-only device.
  1789. *
  1790. * Typically called by file system when it mounts the device first time or when a 
  1791. * read/write fails even after specified number of retries.  It issues a mass 
  1792. * storage reset class-specific request, which prepares the device ready to 
  1793. * receive the next CBW from the host. 
  1794. * RETURNS: OK if reset succcssful, or ERROR
  1795. */
  1796. LOCAL STATUS usbBulkDevReset
  1797.     (
  1798.     BLK_DEV * pBlkDev            /* pointer to bulk device */
  1799.     )
  1800.     {
  1801.     STATUS s;
  1802.     pUSB_BULK_DEV  pBulkDev = (USB_BULK_DEV *)pBlkDev;    
  1803.     /*  Ensure that the device has not been removed during a transfer */
  1804.     if ( pBulkDev->connected == FALSE ) 
  1805. return ERROR;
  1806.     OSS_MUTEX_TAKE (bulkDevMutex, OSS_BLOCK);
  1807.       
  1808.     /* issue bulk-only mass storage reset request on control End point */
  1809.     if ((s = usbdVendorSpecific (usbdHandle, 
  1810.  pBulkDev->bulkDevId,
  1811.  USB_RT_HOST_TO_DEV | USB_RT_CLASS | USB_RT_INTERFACE,
  1812.  USB_BULK_RESET, 
  1813.  0, 
  1814.  pBulkDev->interface, 
  1815.  0, 
  1816.  NULL, 
  1817.  NULL)) 
  1818. != OK )
  1819.         {
  1820.         USB_BULK_ERR ("usbBulkDevReset: Failed to reset %xn", 
  1821.                         0, 0, 0, 0, 0, 0);  
  1822.         }
  1823.     else 
  1824.        { 
  1825.        USB_BULK_DEBUG ("usbBulkDevReset: Reset...donen", 0, 0, 0, 0, 0, 0);
  1826.        }
  1827.     OSS_MUTEX_RELEASE (bulkDevMutex);
  1828.     return (s);
  1829.     }
  1830. /***************************************************************************
  1831. *
  1832. * notifyAttach - Notifies registered callers of attachment/removal
  1833. *
  1834. * RETURNS: N/A
  1835. */
  1836. LOCAL VOID notifyAttach
  1837.     (
  1838.     USBD_NODE_ID bulkDevId,
  1839.     UINT16 attachCode
  1840.     )
  1841.     {
  1842.     pATTACH_REQUEST pRequest = usbListFirst (&reqList);
  1843.     while (pRequest != NULL)
  1844.     {
  1845.     (*pRequest->callback) (pRequest->callbackArg, 
  1846.    bulkDevId, attachCode);
  1847.     pRequest = usbListNext (&pRequest->reqLink);
  1848.     }
  1849.     }
  1850. /***************************************************************************
  1851. *
  1852. * usbBulkDynamicAttachRegister - Register SCSI/BULK-ONLY device attach callback.
  1853. *
  1854. * <callback> is a caller-supplied function of the form:
  1855. *
  1856. * .CS
  1857. * typedef (*USB_BULK_ATTACH_CALLBACK) 
  1858. *     (
  1859. *     pVOID arg,
  1860. *     USBD_NODE_ID bulkDevId,
  1861. *     UINT16 attachCode
  1862. *     );
  1863. * .CE
  1864. *
  1865. * usbBulkDevLib will invoke <callback> each time a  MSC/SCSI/BULK-ONLY device
  1866. * is attached to or removed from the system.  <arg> is a caller-defined
  1867. * parameter which will be passed to the <callback> each time it is
  1868. * invoked.  The <callback> will also be passed the nodeID of the device 
  1869. * being created/destroyed and an attach code of USB_BULK_ATTACH or 
  1870. * USB_BULK_REMOVE.
  1871. *
  1872. * NOTE: The user callback routine should not invoke any driver function that
  1873. * submits IRPs.  Further processing must be done from a different task context.
  1874. * As the driver routines wait for IRP completion, they cannot be invoked from
  1875. * USBD client task's context created for this driver.
  1876. *
  1877. *
  1878. * RETURNS: OK, or ERROR if unable to register callback
  1879. *
  1880. * ERRNO:
  1881. *   S_usbBulkDevLib_BAD_PARAM
  1882. *   S_usbBulkDevLib_OUT_OF_MEMORY
  1883. */
  1884. STATUS usbBulkDynamicAttachRegister
  1885.     (
  1886.     USB_BULK_ATTACH_CALLBACK callback, /* new callback to be registered */
  1887.     pVOID arg                           /* user-defined arg to callback  */
  1888.     )
  1889.     {
  1890.     pATTACH_REQUEST   pRequest;
  1891.     pUSB_BULK_DEV     pBulkDev;
  1892.     int status = OK;
  1893.     /* Validate parameters */
  1894.     if (callback == NULL)
  1895.         return (ossStatus (S_usbBulkDevLib_BAD_PARAM));
  1896.     OSS_MUTEX_TAKE (bulkDevMutex, OSS_BLOCK);
  1897.     /* Create a new request structure to track this callback request. */
  1898.     if ((pRequest = OSS_CALLOC (sizeof (*pRequest))) == NULL)
  1899.         {
  1900.         status = S_usbBulkDevLib_OUT_OF_MEMORY;
  1901.         }
  1902.     else
  1903.         {
  1904.         pRequest->callback    = callback;
  1905.         pRequest->callbackArg = arg;
  1906.         usbListLink (&reqList, pRequest, &pRequest->reqLink, LINK_TAIL) ;
  1907.     
  1908.        /* 
  1909.         * Perform an initial notification of all currrently attached
  1910.         * SCSI/BULK-ONLY devices.
  1911.         */
  1912.         pBulkDev = usbListFirst (&bulkDevList);
  1913.         while (pBulkDev != NULL)
  1914.     {
  1915.             if (pBulkDev->connected)
  1916.                 (*callback) (arg, pBulkDev->bulkDevId, USB_BULK_ATTACH);
  1917.     pBulkDev = usbListNext (&pBulkDev->bulkDevLink);
  1918.     }
  1919.         }
  1920.     OSS_MUTEX_RELEASE (bulkDevMutex);
  1921.     return (ossStatus (status));
  1922.     }
  1923. /***************************************************************************
  1924. *
  1925. * usbBulkDynamicAttachUnregister - Unregisters SCSI/BULK-ONLY attach callback.
  1926. *
  1927. * This function cancels a previous request to be dynamically notified for
  1928. * SCSI/BULK-ONLY device attachment and removal.  The <callback> and <arg> 
  1929. * paramters must exactly match those passed in a previous call to 
  1930. * usbBulkDynamicAttachRegister().
  1931. *
  1932. * RETURNS: OK, or ERROR if unable to unregister callback
  1933. *
  1934. * ERRNO:
  1935. *   S_usbBulkDevLib_NOT_REGISTERED
  1936. */
  1937. STATUS usbBulkDynamicAttachUnregister
  1938.     (
  1939.     USB_BULK_ATTACH_CALLBACK callback,  /* callback to be unregistered  */
  1940.     pVOID arg                           /* user-defined arg to callback */
  1941.     )
  1942.     {
  1943.     pATTACH_REQUEST pRequest;
  1944.     int status = S_usbBulkDevLib_NOT_REGISTERED;
  1945.     OSS_MUTEX_TAKE (bulkDevMutex, OSS_BLOCK);
  1946.     pRequest = usbListFirst (&reqList);
  1947.     while (pRequest != NULL)
  1948.         {
  1949.         if ((callback == pRequest->callback) && (arg == pRequest->callbackArg))
  1950.     {
  1951.     /* We found a matching notification request. */
  1952.     usbListUnlink (&pRequest->reqLink);
  1953.             /* Dispose of structure */
  1954.             OSS_FREE (pRequest);
  1955.     status = OK;
  1956.     break;
  1957.     }
  1958.         pRequest = usbListNext (&pRequest->reqLink);
  1959.         }
  1960.     OSS_MUTEX_RELEASE (bulkDevMutex);
  1961.     return (ossStatus (status));
  1962.     }
  1963. /***************************************************************************
  1964. *
  1965. * usbBulkDevLock - Marks USB_BULK_DEV structure as in use.
  1966. *
  1967. * A caller uses usbBulkDevLock() to notify usbBulkDevLib that it is using 
  1968. * the indicated USB_BULK_DEV structure.  usbBulkDevLib maintains
  1969. * a count of callers using a particular USB_BULK_DEV structure so that it 
  1970. * knows when it is safe to dispose of a structure when the underlying
  1971. * USB_BULK_DEV is removed from the system.  So long as the "lock count"
  1972. * is greater than zero, usbBulkDevLib will not dispose of an USB_BULK_DEV
  1973. * structure.
  1974. *
  1975. * RETURNS: OK, or ERROR if unable to mark USB_BULK_DEV structure in use.
  1976. */
  1977. STATUS usbBulkDevLock
  1978.     (
  1979.     USBD_NODE_ID nodeId    /* NodeId of the BLK_DEV to be marked as in use */
  1980.     )
  1981.     {
  1982.     pUSB_BULK_DEV pBulkDev = usbBulkDevFind (nodeId);
  1983.     if ( pBulkDev == NULL)
  1984.         return (ERROR);
  1985.     pBulkDev->lockCount++;
  1986.     return (OK);
  1987.     }
  1988. /***************************************************************************
  1989. *
  1990. * usbBulkDevUnlock - Marks USB_BULK_DEV structure as unused.
  1991. *
  1992. * This function releases a lock placed on an USB_BULK_DEV structure.  When a
  1993. * caller no longer needs an USB_BULK_DEV structure for which it has previously
  1994. * called usbBulkDevLock(), then it should call this function to
  1995. * release the lock.
  1996. *
  1997. * NOTE: If the underlying SCSI/BULK-ONLY device has already been removed
  1998. * from the system, then this function will automatically dispose of the
  1999. * USB_BULK_DEV structure if this call removes the last lock on the structure.
  2000. * Therefore, a caller must not reference the USB_BULK_DEV structure after
  2001. * making this call.
  2002. *
  2003. * RETURNS: OK, or ERROR if unable to mark USB_BULK_DEV structure unused
  2004. *
  2005. * ERRNO:
  2006. *   S_usbBulkDevLib_NOT_LOCKED
  2007. */
  2008. STATUS usbBulkDevUnlock
  2009.     (
  2010.     USBD_NODE_ID nodeId    /* NodeId of the BLK_DEV to be marked as unused */
  2011.     )
  2012.     {
  2013.     int status = OK;
  2014.     pUSB_BULK_DEV pBulkDev = usbBulkDevFind (nodeId);
  2015.  
  2016.     if ( pBulkDev == NULL)
  2017.         return (ERROR);
  2018.     OSS_MUTEX_TAKE (bulkDevMutex, OSS_BLOCK);
  2019.     if (pBulkDev->lockCount == 0)
  2020.         {
  2021.         status = S_usbBulkDevLib_NOT_LOCKED;
  2022.         }
  2023.     else
  2024.     {
  2025.     /* If this is the last lock and the underlying USB_BULK device is
  2026.      * no longer connected, then dispose of the device.
  2027.      */
  2028.     if ((--pBulkDev->lockCount == 0) && (!pBulkDev->connected))
  2029. usbBulkDevDestroy (pBulkDev);
  2030.     }
  2031.     OSS_MUTEX_RELEASE (bulkDevMutex);
  2032.     return (ossStatus (status));
  2033.     }
  2034. /***************************************************************************
  2035. *
  2036. * usbBulkDescShow - Show routine for displaying all descriptors
  2037. *
  2038. * RETURNS: OK on success or ERROR if unable to read descriptors.
  2039. */
  2040. LOCAL STATUS usbBulkDescShow 
  2041.     (
  2042.     USBD_NODE_ID nodeId           /* nodeId of bulk device         */
  2043.     )
  2044.     {
  2045.     UINT8    bfr[255];            /* store for descriptors         */
  2046.     UINT8    index;               
  2047.     UINT8    numCfg;              /* number of configuration       */
  2048.     UINT8    mfcIndex;            /* index for manufacturer string */
  2049.     UINT8    productIndex;        /* index for product string      */
  2050.     UINT16   actLength;           /* actual length of descriptor   */
  2051.     pUSB_DEVICE_DESCR  pDevDescr; /* pointer to device descriptor  */
  2052.     pUSB_STRING_DESCR  pStrDescr; /* pointer to string descriptor  */   
  2053.     /* Get the Device descriptor first */
  2054.     if (usbdDescriptorGet (usbdHandle, nodeId, 
  2055.                            USB_RT_STANDARD | USB_RT_DEVICE,
  2056.                            USB_DESCR_DEVICE, 0, 0, 20, bfr, &actLength) != OK)
  2057.         {
  2058.         USB_BULK_ERR ("usbBulkDevDescShow: Failed to read Device descriptorn",
  2059.                         0, 0, 0, 0, 0, 0);
  2060.         return (ERROR);
  2061.         }
  2062.     if ((pDevDescr = usbDescrParse (bfr, actLength, USB_DESCR_DEVICE)) == NULL)
  2063.         {
  2064.         USB_BULK_ERR ("usbBulkDevDescShow: No Device descriptor was found "
  2065.                        "in the buffer n", 0, 0, 0, 0, 0, 0);
  2066.         return (ERROR);
  2067.         }
  2068.     /* store the num. of configurations, string indices locally */
  2069.     numCfg       = pDevDescr->numConfigurations;
  2070.     mfcIndex     = pDevDescr->manufacturerIndex;
  2071.     productIndex = pDevDescr->productIndex;
  2072.     printf ("DEVICE DESCRIPTOR:n");
  2073.     printf ("------------------n");
  2074.     printf (" Length                    = 0x%xn", pDevDescr->length);
  2075.     printf (" Descriptor Type           = 0x%xn", pDevDescr->descriptorType);
  2076.     printf (" USB release in BCD        = 0x%xn", pDevDescr->bcdUsb);
  2077.     printf (" Device Class              = 0x%xn", pDevDescr->deviceClass);
  2078.     printf (" Device Sub-Class          = 0x%xn", pDevDescr->deviceSubClass);
  2079.     printf (" Device Protocol           = 0x%xn", pDevDescr->deviceProtocol);
  2080.     printf (" Max Packet Size           = 0x%xn", pDevDescr->maxPacketSize0);
  2081.     printf (" Vendor ID                 = 0x%xn", pDevDescr->vendor);
  2082.     printf (" Product ID                = 0x%xn", pDevDescr->product);
  2083.     printf (" Dev release in BCD        = 0x%xn", pDevDescr->bcdDevice);
  2084.     printf (" Manufacturer              = 0x%xn", pDevDescr->manufacturerIndex);
  2085.     printf (" Product                   = 0x%xn", pDevDescr->productIndex);
  2086.     printf (" Serial Number             = 0x%xn", 
  2087.             pDevDescr->serialNumberIndex);
  2088.     printf (" Number of Configurations  = 0x%xnn", 
  2089.             pDevDescr->numConfigurations);
  2090.     /* get the manufacturer string descriptor  */     
  2091.     if (usbdDescriptorGet (usbdHandle, nodeId, 
  2092.                            USB_RT_STANDARD | USB_RT_DEVICE,
  2093.                            USB_DESCR_STRING , mfcIndex,
  2094.                            0x0409, 100, bfr, &actLength) != OK)
  2095.         {
  2096.         USB_BULK_ERR ("usbBulkDevDescShow: Failed to read String descriptorn",
  2097.                         0, 0, 0, 0, 0, 0);
  2098.         }
  2099.     else
  2100.         {
  2101.         if ((pStrDescr = usbDescrParse (bfr, actLength, 
  2102.                                         USB_DESCR_STRING)) == NULL)
  2103.             {
  2104.             USB_BULK_ERR ("usbBulkDevDescShow: No String descriptor was "
  2105.                           "found in the buffer n", 0, 0, 0, 0, 0, 0);
  2106.             }
  2107.         else
  2108.             {
  2109.             printf ("STRING DESCRIPTOR : %dn",1);
  2110.             printf ("----------------------n");
  2111.             printf (" Length              = 0x%xn", pStrDescr->length);
  2112.             printf (" Descriptor Type     = 0x%xn", pStrDescr->descriptorType); 
  2113.             printf (" Manufacturer String = ");  
  2114.             for (index = 0; index < (pStrDescr->length -2) ; index++)
  2115.                 printf("%c", pStrDescr->string [index]);
  2116.             printf("nn");
  2117.             }
  2118.         }  
  2119.     /* get the product string descriptor  */
  2120.     if (usbdDescriptorGet (usbdHandle, nodeId, 
  2121.                            USB_RT_STANDARD | USB_RT_DEVICE,
  2122.                            USB_DESCR_STRING , productIndex,
  2123.                            0x0409, 100, bfr, &actLength) != OK)
  2124.         {
  2125.         USB_BULK_ERR ("usbBulkDevDescShow: Failed to read String descriptorn", 
  2126.                         0, 0, 0, 0, 0, 0);
  2127.         }
  2128.     else
  2129.         {
  2130.         if ((pStrDescr = usbDescrParse (bfr, actLength, 
  2131.                                         USB_DESCR_STRING)) == NULL)
  2132.             {
  2133.             USB_BULK_ERR ("usbBulkDevDescShow: No String descriptor was "
  2134.                           "found in the buffer n", 0, 0, 0, 0, 0, 0);
  2135.             }
  2136.         else
  2137.             {
  2138.             printf ("STRING DESCRIPTOR : %dn",2);
  2139.             printf ("----------------------n");
  2140.             printf (" Length              = 0x%xn", pStrDescr->length);
  2141.             printf (" Descriptor Type     = 0x%xn", pStrDescr->descriptorType); 
  2142.             printf (" Product String      = ");  
  2143.             for (index = 0; index < (pStrDescr->length -2) ; index++)
  2144.                 printf("%c", pStrDescr->string [index]);
  2145.             printf("nn");
  2146.             }
  2147.         }
  2148.     /* get the configuration descriptors one by one for each configuration */
  2149.     for (index = 0; index < numCfg; index++) 
  2150.        if (usbBulkConfigDescShow ( nodeId, index ) == ERROR)
  2151.           return (ERROR);
  2152.     return  (OK);
  2153.     }
  2154. /***************************************************************************
  2155. *
  2156. * usbBulkConfigDescShow - shows routine for displaying configuration descriptors.
  2157. *
  2158. * RETURNS: OK on success or ERROR if unable to read descriptors. 
  2159. */
  2160. LOCAL STATUS usbBulkConfigDescShow 
  2161.     (
  2162.     USBD_NODE_ID nodeId,         /* nodeId of bulk device       */
  2163.     UINT8 cfgIndex               /* index of configuration      */
  2164.     )
  2165.     {
  2166.     UINT8    bfr[255];           /* store for config descriptor */
  2167.     UINT8  * pBfr = bfr;         /* pointer to the above store  */
  2168.     UINT8    ifIndex;            /* index for interfaces        */
  2169.     UINT8    epIndex;            /* index for endpoints         */
  2170.     UINT16   actLength;          /* actual length of descriptor */
  2171.     pUSB_CONFIG_DESCR pCfgDescr;    /* pointer to config'n descriptor   */
  2172.     pUSB_INTERFACE_DESCR pIntDescr; /* pointer to interface descriptor  */ 
  2173.     pUSB_ENDPOINT_DESCR pEndptDescr;/* pointer to endpointer descriptor */ 
  2174.  
  2175.     /* get the configuration descriptor */
  2176.     if (usbdDescriptorGet (usbdHandle, nodeId, 
  2177.                            USB_RT_STANDARD | USB_RT_DEVICE,
  2178.                            USB_DESCR_CONFIGURATION, cfgIndex, 0, 
  2179.                            255, bfr, &actLength) != OK)
  2180.         {
  2181.         USB_BULK_ERR ("usbBulkConfigDescShow: Failed to read Config'n "
  2182.                       "descriptorn", 0, 0, 0, 0, 0, 0);
  2183.         return (ERROR);
  2184.         }
  2185.         
  2186.     if ((pCfgDescr = usbDescrParseSkip (&pBfr, &actLength, 
  2187.                                         USB_DESCR_CONFIGURATION)) == NULL)
  2188.         {
  2189.         USB_BULK_ERR ("usbBulkConfigDescShow: No Config'n descriptor was found "
  2190.                       "in the buffer n", 0, 0, 0, 0, 0, 0);
  2191.         return (ERROR);
  2192.         }
  2193.     printf ("CONFIGURATION DESCRIPTOR: %dn", cfgIndex);
  2194.     printf ("----------------------------n");
  2195.     printf (" Length                    = 0x%xn", pCfgDescr->length);
  2196.     printf (" Descriptor Type           = 0x%xn", pCfgDescr->descriptorType);
  2197.     printf (" Total Length              = 0x%xn", pCfgDescr->totalLength);
  2198.     printf (" Number of Interfaces      = 0x%xn", pCfgDescr->numInterfaces);
  2199.     printf (" Configuration Value       = 0x%xn", pCfgDescr->configurationValue);
  2200.     printf (" Configuration Index       = 0x%xn", pCfgDescr->configurationIndex);
  2201.     printf (" Attributes                = 0x%xn", pCfgDescr->attributes);
  2202.     printf (" Maximum Power             = 0x%xnn", pCfgDescr->maxPower);
  2203.     /* Parse for the interface and its related endpoint descriptors */   
  2204.     for (ifIndex = 0; ifIndex < pCfgDescr->numInterfaces; ifIndex++)
  2205.         {
  2206.         if ((pIntDescr = usbDescrParseSkip (&pBfr, &actLength, 
  2207.                                             USB_DESCR_INTERFACE)) == NULL)
  2208.             {
  2209.             USB_BULK_ERR ("usbBulkInterfaceDescShow: No Interface descriptor "
  2210.                           "was found n", 0, 0, 0, 0, 0, 0);
  2211.             return (ERROR);
  2212.             }
  2213.         printf ("INTERFACE DESCRIPTOR: %dn", ifIndex);
  2214.         printf ("-----------------------n");
  2215.         printf (" Length                    = 0x%xn", pIntDescr->length);
  2216.         printf (" Descriptor Type           = 0x%xn", pIntDescr->descriptorType);
  2217.         printf (" Interface Number          = 0x%xn", pIntDescr->interfaceNumber);
  2218.         printf (" Alternate setting         = 0x%xn", 
  2219.                 pIntDescr->alternateSetting);
  2220.         printf (" Number of Endpoints       = 0x%xn", pIntDescr->numEndpoints) ;
  2221.         printf (" Interface Class           = 0x%xn", 
  2222.                 pIntDescr->interfaceClass);
  2223.         printf (" Interface Sub-Class       = 0x%xn", 
  2224.                 pIntDescr->interfaceSubClass);
  2225.         printf (" Interface Protocol        = 0x%xn", 
  2226.                 pIntDescr->interfaceProtocol);
  2227.         printf (" Interface Index           = 0x%xnn", pIntDescr->interfaceIndex); 
  2228.         
  2229.         for ( epIndex = 0; epIndex < pIntDescr->numEndpoints; epIndex++)
  2230.             { 
  2231.             if ((pEndptDescr = usbDescrParseSkip (&pBfr, &actLength, 
  2232.                                                   USB_DESCR_ENDPOINT)) == NULL)
  2233.                 {
  2234.                 USB_BULK_ERR ("usbBulkInterfaceDescShow: No Endpoint descriptor" 
  2235.                               "was found n", 0, 0, 0, 0, 0, 0);
  2236.                 return (ERROR);
  2237.                 }
  2238.             printf ("ENDPOINT DESCRIPTOR: %dn", epIndex);
  2239.             printf ("-----------------------n");
  2240.             printf (" Length                    = 0x%xn", pEndptDescr->length);
  2241.             printf (" Descriptor Type           = 0x%xn", 
  2242.                     pEndptDescr->descriptorType);
  2243.             printf (" Endpoint Address          = 0x%xn", 
  2244.                     pEndptDescr->endpointAddress);
  2245.             printf (" Attributes                = 0x%xn", 
  2246.                     pEndptDescr->attributes);
  2247.             printf (" Max Packet Size           = 0x%xn", 
  2248.                     pEndptDescr->maxPacketSize);
  2249.             printf (" Interval                  = 0x%xnn", 
  2250.                     pEndptDescr->interval);
  2251.             }
  2252.         }
  2253.   
  2254.     return (OK);
  2255.     }