Modules/USB MSC - Forgot a TODO
[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   0
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 void    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 void    MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data);
23 void    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 void MSC_Cleanup(void)
47 {
48 }
49
50 void MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen)
51 {
52         tMSCInfo        *info;
53         // TODO: Get the class code (and hence what command set is in use)
54         // TODO: Get the maximum packet size too
55
56         info = malloc( sizeof(*info) );
57         USB_SetDeviceDataPtr(Dev, info);        
58
59         info->BlockCount = MSC_SCSI_GetSize(Dev, &info->BlockSize);
60
61         LOG("Device has 0x%llx blocks of 0x%x bytes",
62                 info->BlockCount, info->BlockSize);
63         // TODO: Get serial number
64         LVM_AddVolume(&gMSC_SCSI_VolType, "usb0", Dev, info->BlockSize, info->BlockCount);
65 }
66
67 void MSC_DataIn(tUSBInterface *Dev, int EndPt, int Length, void *Data)
68 {
69         // Will this ever be needed?
70 }
71
72 int MSC_int_CreateCBW(tMSC_CBW *Cbw, int bInput, size_t CmdLen, const void *CmdData, size_t DataLen)
73 {
74         if( CmdLen == 0 ) {
75                 Log_Error("MSC", "Zero length commands are invalid");
76                 return -1;
77         }
78         
79         if( CmdLen > 16 ) {
80                 Log_Error("MSC", "Command data >16 bytes (%i)", CmdLen);
81                 return -1;
82         }
83         
84         Cbw->dCBWSignature = LittleEndian32(0x43425355);
85         Cbw->dCBWTag    = giMSC_NextTag ++;
86         Cbw->dCBWDataTransferLength = LittleEndian32(DataLen);
87         Cbw->bmCBWFlags = (bInput ? 0x80 : 0x00);
88         Cbw->bCBWLUN    = 0;    // TODO: Logical Unit Number (param from proto)
89         Cbw->bCBWLength = CmdLen;
90         memcpy(Cbw->CBWCB, CmdData, CmdLen);
91         
92         return 0;
93 }
94
95 void MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data)
96 {
97         tMSC_CBW        cbw;
98         tMSC_CSW        csw;
99         const int       endpoint_out = 2;
100         const int       endpoint_in = 1;
101         const int       max_packet_size = 64;
102         
103         if( MSC_int_CreateCBW(&cbw, 0, CmdLen, CmdData, DataLen) )
104                 return ;
105         
106         // Send CBW
107         USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw);
108         
109         // Send Data
110         for( size_t ofs = 0; ofs < DataLen; ofs += max_packet_size )
111         {
112                 USB_SendData(Dev, endpoint_out, MIN(max_packet_size, DataLen - ofs), Data + ofs);
113         }
114         
115         // Read CSW
116         USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw);
117         // TODO: Validate CSW
118 }
119
120 void MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data)
121 {
122         tMSC_CBW        cbw;
123         tMSC_CSW        csw;
124         const int       endpoint_out = 2;
125         const int       endpoint_in = 1;
126         const int       max_packet_size = 64;
127                 
128         if( MSC_int_CreateCBW(&cbw, 1, CmdLen, CmdData, DataLen) )
129                 return ;
130         
131         // Send CBW
132         LOG("Send CBW");
133         USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw);
134         
135         // Read Data
136         for( size_t ofs = 0; ofs < DataLen; ofs += max_packet_size )
137         {
138                 LOG("Read bytes 0x%x+0x%x", ofs, MIN(max_packet_size, DataLen - ofs));
139                 // TODO: use async version and wait for the transaction to complete
140                 USB_RecvData(Dev, endpoint_in, MIN(max_packet_size, DataLen - ofs), Data + ofs);
141         }
142         
143         // Read CSW
144         LOG("Read CSW");
145         USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw);
146         // TODO: Validate CSW
147 }
148

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