TODO
[tpg/acess2.git] / KernelLand / Modules / USB / Core / usb_io.c
1 /*
2  * Acess2 USB Stack
3  * - By John Hodge (thePowersGang)
4  *
5  * usb_io.c
6  * - High-level IO
7  */
8 #define DEBUG   0
9
10 #include <usb_core.h>
11 #include "usb.h"
12 #include "usb_lowlevel.h"
13 #include <workqueue.h>
14 #include <events.h>
15 #include "usb_async.h"
16
17 // === PROTOTYPES ===
18 void    USB_ReadDescriptor(tUSBInterface *Iface, int Type, int Index, int Length, void *Data);
19 void    USB_Request(tUSBInterface *Iface, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data);
20 void    USB_SendData(tUSBInterface *Dev, int Endpoint, size_t Length, const void *Data);
21 void    USB_WakeCallback(void *Ptr, void *Buf, size_t Length);
22 void    USB_AsyncCallback(void *Ptr, void *Buf, size_t Length);
23 void    USB_AsyncThread(void *unused);
24
25 // === GLOBALS ===
26 tWorkqueue      gUSB_AsyncQueue;
27
28 // === CODE ===
29 void USB_ReadDescriptor(tUSBInterface *Iface, int Type, int Index, int Length, void *Data)
30 {
31         USB_int_ReadDescriptor(Iface->Dev, 0, Type, Index, Length, Data);
32 }
33
34 void USB_Request(tUSBInterface *Iface, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data)
35 {
36          int    endpt;
37
38         // Sanity check
39         if(Endpoint < 0 || Endpoint >= Iface->nEndpoints)
40                 return ;        
41
42         // Get endpoint number
43         if(Endpoint)
44                 endpt = Iface->Endpoints[Endpoint-1].EndpointNum;
45         else
46                 endpt = 0;
47         
48         USB_int_Request(Iface->Dev->Host, Iface->Dev->Address, endpt, Type, Req, Value, Index, Len, Data);
49 }
50
51
52 void USB_SendData(tUSBInterface *Dev, int Endpoint, size_t Length, const void *Data)
53 {
54         tUSBHost *host;
55         tUSBEndpoint    *ep;
56         ENTER("pDev iEndpoint iLength pData", Dev, Endpoint, Length, Data);
57
58         ep = &Dev->Endpoints[Endpoint-1];
59         host = Dev->Dev->Host;
60
61         Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
62         for( size_t ofs = 0; ofs < Length; ofs += ep->MaxPacketSize )
63         {
64                 size_t  len = MIN(Length - ofs, ep->MaxPacketSize);
65                 
66                 host->HostDef->BulkOUT(
67                         host->Ptr, Dev->Dev->Address*16 + Dev->Endpoints[Endpoint-1].EndpointNum,
68                         0, (len == Length - ofs ? USB_WakeCallback : NULL), Proc_GetCurThread(),
69                         (char*)Data + ofs, len
70                         );
71         }
72         Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
73         
74         LEAVE('-');
75 }
76
77 void USB_RecvData(tUSBInterface *Dev, int Endpoint, size_t Length, void *Data)
78 {
79         tUSBHost *host;
80         tUSBEndpoint    *ep;
81         ENTER("pDev iEndpoint iLength pData", Dev, Endpoint, Length, Data);
82
83         ep = &Dev->Endpoints[Endpoint-1];
84         host = Dev->Dev->Host;
85
86         Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
87         for( size_t ofs = 0; ofs < Length; ofs += ep->MaxPacketSize )
88         {
89                 size_t  len = MIN(Length - ofs, ep->MaxPacketSize);
90                 
91                 host->HostDef->BulkIN(
92                         host->Ptr, Dev->Dev->Address*16 + Dev->Endpoints[Endpoint-1].EndpointNum,
93                         0, (len == Length - ofs ? USB_WakeCallback : NULL), Proc_GetCurThread(),
94                         (char*)Data + ofs, len
95                         );
96         }
97         Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
98         
99         LEAVE('-');
100 }
101
102 void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, size_t Length, void *DataBuf, tUSB_DataCallback Callback)
103 {
104         tAsyncOp *op;
105         tUSBHost *host;
106
107         ENTER("pDev iEndpoint iLength pDataBuf", Dev, Endpoint, Length, DataBuf); 
108
109         op = malloc(sizeof(*op));
110         op->Next = NULL;
111         op->Endpt = &Dev->Endpoints[Endpoint-1];
112         op->Length = Length;
113         op->Data = DataBuf;
114
115         // TODO: Handle transfers that are larger than one packet
116         // TODO: Data toggle
117
118         host = Dev->Dev->Host;
119         
120         LOG("IN from %p %i:%i", host->Ptr, Dev->Dev->Address, op->Endpt->EndpointNum);
121         for( size_t ofs = 0; ofs < Length; ofs += op->Endpt->MaxPacketSize )
122         {
123                 size_t  len = MIN(Length - ofs, op->Endpt->MaxPacketSize);
124                 
125                 host->HostDef->BulkIN(
126                         host->Ptr, Dev->Dev->Address*16 + op->Endpt->EndpointNum,
127                         0, (len == Length - ofs ? USB_AsyncCallback : NULL), op,
128                         (char*)DataBuf + ofs, len
129                         );
130         }
131         
132         LEAVE('-');
133
134 //      Log_Warning("USB", "TODO: Implement USB_RecvDataA");
135 }
136
137 void USB_WakeCallback(void *Ptr, void *Buf, size_t Length)
138 {
139         Threads_PostEvent(Ptr, THREAD_EVENT_SHORTWAIT);
140 }
141
142 void USB_AsyncCallback(void *Ptr, void *Buf, size_t Length)
143 {
144         tAsyncOp *op = Ptr;
145         op->Length = Length;
146         LOG("adding %p to work queue", op);
147         Workqueue_AddWork(&gUSB_AsyncQueue, op);
148 }
149
150 void USB_AsyncThread(void *Unused)
151 {
152         Threads_SetName("USB Async IO Thread");
153         for(;;)
154         {
155                 tAsyncOp *op = Workqueue_GetWork(&gUSB_AsyncQueue);
156                 tUSBInterface   *iface = op->Endpt->Interface;
157
158                 LOG("op = %p", op);     
159
160                 iface->Driver->Endpoints[op->Endpt->EndpointIdx].DataAvail(
161                         iface, op->Endpt->EndpointIdx,
162                         op->Length, op->Data);
163                 
164                 free(op);
165         }
166 }
167

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