Modules/USB MSC - Silence, scum
[tpg/acess2.git] / KernelLand / Modules / USB / MSC / main.c
1 /*
2  * Acess2 USB Stack Mass Storage Driver
3  * - By John Hodge (thePowersGang)
4  *
5  * main.c
6  * - Driver Core
7  */
8 #define DEBUG   1
9 #define VERSION VER2(0,1)
10 #include <acess.h>
11 #include <modules.h>
12 #include "common.h"
13 #include "msc_proto.h"
14
15 // === PROTOTYPES ===
16  int    MSC_Initialise(char **Arguments);
17  int    MSC_Cleanup(void);
18 void    MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen);
19 void    MSC_DataIn(tUSBInterface *Dev, int EndPt, int Length, void *Data);
20 // --- Internal Helpers
21  int    MSC_int_CreateCBW(tMSC_CBW *Cbw, int bInput, size_t CmdLen, const void *CmdData, size_t DataLen);
22  int    MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data);
23  int    MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data);
24
25 // === GLOBALS ===
26 MODULE_DEFINE(0, VERSION, USB_MSC, MSC_Initialise, MSC_Cleanup, "USB_Core", NULL);
27 tUSBDriver      gMSC_Driver_BulkOnly = {
28         .Name = "MSC_BulkOnly",
29         .Match = {.Class = {0x080050, 0xFF00FF}},
30         .Connected = MSC_DeviceConnected,
31         .MaxEndpoints = 2,
32         .Endpoints = {
33                 {0x82, MSC_DataIn},
34                 {0x02, NULL},
35                 }
36         };
37 int giMSC_NextTag;
38
39 // === CODE ===
40 int MSC_Initialise(char **Arguments)
41 {
42         USB_RegisterDriver( &gMSC_Driver_BulkOnly );
43         return 0;
44 }
45
46 int MSC_Cleanup(void)
47 {
48         return 0;
49 }
50
51 void MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen)
52 {
53         tMSCInfo        *info;
54         tLVM_VolType    *vt;
55         
56         info = malloc( sizeof(*info) );
57         USB_SetDeviceDataPtr(Dev, info);
58         
59         // Get the class code (and hence what command set is in use)
60         Uint8   sc = (USB_GetInterfaceClass(Dev) & 0x00FF00) >> 8;
61         switch( sc )
62         {
63         // SCSI Transparent Command Set
64         case 0x06:
65                 info->BlockCount = MSC_SCSI_GetSize(Dev, &info->BlockSize);
66                 // HACK! Try twice if needed
67                 // Qemu Tegra2 appears to error with Sense=RESET on the first attempt
68                 if( !info->BlockCount )
69                         info->BlockCount = MSC_SCSI_GetSize(Dev, &info->BlockSize);
70                 vt = &gMSC_SCSI_VolType;
71                 break;
72         // Unknown, prepare to chuck sad
73         default:
74                 Log_Error("USB MSC", "Unknown sub-class 0x%02x", sc);
75                 USB_SetDeviceDataPtr(Dev, NULL);
76                 free(info);
77                 return ;
78         }
79         
80         // Zero size indicates some form of critical error
81         if( !info->BlockCount ) {
82                 Log_Error("USB MSC", "Device did not report a valid size");
83                 USB_SetDeviceDataPtr(Dev, NULL);
84                 free(info);
85                 return ;
86         }
87
88         // Create device name from Vendor ID, Device ID and Serial Number
89         Uint16  vendor, devid;
90         char    *serial_number;
91         USB_GetDeviceVendor(Dev, &vendor, &devid);
92         serial_number = USB_GetSerialNumber(Dev);
93         if( !serial_number ) {
94                 // No serial number - this breaks spec, but it's easy to handle
95                 Log_Warning("USB MSC", "Device does not have a serial number, using a random one");
96                 serial_number = malloc(4+8+1);
97                 sprintf(serial_number, "rand%08x", rand());
98         }
99         char    name[4 + 4 + 1 + 4 + 1 + strlen(serial_number) + 1];
100         sprintf(name, "usb-%04x:%04x-%s", vendor, devid, serial_number);
101         free(serial_number);
102
103         // Pass the buck to LVM
104         LOG("Device '%s' has 0x%llx blocks of 0x%x bytes", name, info->BlockCount, info->BlockSize);
105         LVM_AddVolume(vt, name, Dev, info->BlockSize, info->BlockCount);
106 }
107
108 void MSC_DataIn(tUSBInterface *Dev, int EndPt, int Length, void *Data)
109 {
110         // Will this ever be needed?
111 }
112
113 /**
114  * \brief Create a CBW structure
115  */
116 int MSC_int_CreateCBW(tMSC_CBW *Cbw, int bInput, size_t CmdLen, const void *CmdData, size_t DataLen)
117 {
118         if( CmdLen == 0 ) {
119                 Log_Error("MSC", "Zero length commands are invalid");
120                 return -1;
121         }
122         
123         if( CmdLen > 16 ) {
124                 Log_Error("MSC", "Command data >16 bytes (%i)", CmdLen);
125                 return -1;
126         }
127         
128         Cbw->dCBWSignature = LittleEndian32(0x43425355);
129         Cbw->dCBWTag    = giMSC_NextTag ++;
130         Cbw->dCBWDataTransferLength = LittleEndian32(DataLen);
131         Cbw->bmCBWFlags = (bInput ? 0x80 : 0x00);
132         Cbw->bCBWLUN    = 0;    // TODO: Logical Unit Number (param from proto)
133         Cbw->bCBWLength = CmdLen;
134         memcpy(Cbw->CBWCB, CmdData, CmdLen);
135         
136         return 0;
137 }
138
139 int MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data)
140 {
141         tMSC_CBW        cbw;
142         tMSC_CSW        csw;
143         const int       endpoint_out = 2;
144         const int       endpoint_in = 1;
145         
146         if( MSC_int_CreateCBW(&cbw, 0, CmdLen, CmdData, DataLen) )
147                 return 2;
148         
149         // Send CBW
150         USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw);
151         
152         // Send Data
153         USB_SendData(Dev, endpoint_out, DataLen, Data);
154         
155         // Read CSW
156         USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw);
157         // TODO: Validate CSW
158
159         return (csw.bCSWStatus != 0x00);
160 }
161
162 int MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data)
163 {
164         tMSC_CBW        cbw;
165         tMSC_CSW        csw;
166         const int       endpoint_out = 2;
167         const int       endpoint_in = 1;
168                 
169         if( MSC_int_CreateCBW(&cbw, 1, CmdLen, CmdData, DataLen) )
170                 return 2;
171         
172         // Send CBW
173         USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw);
174         
175         // Read Data
176         // TODO: use async version and wait for the transaction to complete
177         USB_RecvData(Dev, endpoint_in, DataLen, Data);
178         
179         // Read CSW
180         USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw);
181         
182         //Debug_HexDump("MSC RecvData, cbw=", &cbw, sizeof(cbw));
183         //Debug_HexDump("MSC RecvData, csw=", &csw, sizeof(csw));
184         //Debug_HexDump("MSC RecvData, Data=", Data, DataLen);
185         
186         // TODO: Validate CSW
187         if( LittleEndian32(csw.dCSWSignature) != MSC_CSW_SIGNATURE ) {
188                 Log_Warning("MSC", "CSW Signature invalid %x!=exp %x",
189                         LittleEndian32(csw.dCSWSignature), MSC_CSW_SIGNATURE);
190         }
191         if( csw.dCSWTag != cbw.dCBWTag ) {
192                 Log_Warning("MSC", "Recv - CSW tag (%x) doesn't match CBW tag (%x)",
193                         LittleEndian32(csw.dCSWTag), LittleEndian32(cbw.dCBWTag));
194         }
195         if( LittleEndian32(csw.dCSWDataResidue) > DataLen ) {
196                 Log_Warning("MSC", "Recv - CSW residue (0x%x) is larger than DatLen (0x%x)",
197                         LittleEndian32(csw.dCSWDataResidue), DataLen);
198         }
199         if( csw.bCSWStatus != 0x00 ) {
200                 Log_Warning("MWC", "Recv - CSW indicated error (Status=%02x, Residue=0x%x/0x%x)",
201                         csw.bCSWStatus, LittleEndian32(csw.dCSWDataResidue), DataLen);
202         }
203         
204         return (csw.bCSWStatus != 0x00);
205 }
206

UCC git Repository :: git.ucc.asn.au