7cea58aa56fff8019440acf25c6a72b6a3635c4d
[tpg/acess2.git] / KernelLand / Modules / USB / Core / usb_lowlevel.c
1 /*
2  * Acess 2 USB Stack
3  * - By John Hodge (thePowersGang)
4  * 
5  * usb_lowlevel.c
6  * - Low Level IO
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include "usb.h"
11 #include "usb_proto.h"
12 #include "usb_lowlevel.h"
13 #include <timers.h>
14 #include <events.h>
15
16 // === PROTOTYPES ===
17 void    *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
18 void    USB_int_WakeThread(void *Thread, void *Data, size_t Length);
19  int    USB_int_SendSetupSetAddress(tUSBHost *Host, int Address);
20  int    USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest);
21 char    *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index);
22  int    _UTF16to8(Uint16 *Input, int InputLen, char *Dest);
23
24 // === CODE ===
25 void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data)
26 {
27         void    *hdl;
28         // TODO: Sanity check (and check that Type is valid)
29         struct sDeviceRequest   req;
30          int    dest = Addr * 16 + EndPt;       // TODO: Validate
31         void    *dest_hdl = (void*)(dest+1);    // TODO: Get registered handle instead
32         tThread *thisthread = Proc_GetCurThread();
33         
34         ENTER("pHost xdest iType iReq iVal iIndx iLen pData",
35                 Host, dest, Type, Req, Val, Indx, Len, Data);
36         
37         req.ReqType = Type;
38         req.Request = Req;
39         req.Value = LittleEndian16( Val );
40         req.Index = LittleEndian16( Indx );
41         req.Length = LittleEndian16( Len );
42
43         Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
44
45         LOG("Send");
46         if( Type & 0x80 ) {
47                 // Inbound data
48                 hdl = Host->HostDef->SendControl(Host->Ptr, dest_hdl, USB_int_WakeThread, thisthread, 0,
49                         &req, sizeof(req),
50                         NULL, 0,
51                         Data, Len
52                         );
53         }
54         else {
55                 // Outbound data
56                 hdl = Host->HostDef->SendControl(Host->Ptr, dest_hdl, USB_int_WakeThread, thisthread, 1,
57                         &req, sizeof(req),
58                         Data, Len,
59                         NULL, 0
60                         );
61         }
62         LOG("Wait...");
63         Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
64
65         LEAVE('p', hdl);
66         return hdl;
67 }
68
69 void USB_int_WakeThread(void *Thread, void *Data, size_t Length)
70 {
71         Threads_PostEvent(Thread, THREAD_EVENT_SHORTWAIT);
72 }
73
74 int USB_int_SendSetupSetAddress(tUSBHost *Host, int Address)
75 {
76         USB_int_Request(Host, 0, 0, 0x00, 5, Address & 0x7F, 0, 0, NULL);
77         return 0;
78 }
79
80 int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest)
81 {
82         struct sDeviceRequest   req;
83          int    dest = Dev->Address*16 + Endpoint;
84         void    *dest_hdl = (void*)(dest+1);    // TODO: Get correct handle
85
86         ENTER("pDev xdest iType iIndex iLength pDest",
87                 Dev, dest, Type, Index, Length, Dest);
88
89         req.ReqType = 0x80;
90         req.ReqType |= ((Type >> 8) & 0x3) << 5;        // Bits 5/6
91         req.ReqType |= (Type >> 12) & 3;        // Destination (Device, Interface, Endpoint, Other);
92
93         req.Request = 6;        // GET_DESCRIPTOR
94         req.Value = LittleEndian16( ((Type & 0xFF) << 8) | (Index & 0xFF) );
95         req.Index = LittleEndian16( 0 );        // TODO: Language ID / Interface
96         req.Length = LittleEndian16( Length );
97
98         Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
99         
100         LOG("Send");
101         Dev->Host->HostDef->SendControl(Dev->Host->Ptr, dest_hdl, USB_int_WakeThread, Proc_GetCurThread(), 0,
102                 &req, sizeof(req),
103                 NULL, 0,
104                 Dest, Length
105                 );
106
107         LOG("Waiting");
108         // TODO: Detect errors?
109         Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
110         
111         LEAVE('i', 0);
112         return 0;
113 }
114
115 char *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index)
116 {
117         struct sDescriptor_String       str;
118          int    src_len, new_len;
119         char    *ret;
120
121         if(Index == 0)  return strdup("");
122         
123         str.Length = 0;
124         USB_int_ReadDescriptor(Dev, Endpoint, 3, Index, sizeof(str), &str);
125         if(str.Length == 0)     return NULL;
126         if(str.Length < 2) {
127                 Log_Error("USB", "String %p:%i:%i:%i descriptor is undersized (%i)",
128                         Dev->Host, Dev->Address, Endpoint, Index, str.Length);
129                 return NULL;
130         }
131 //      if(str.Length > sizeof(str)) {
132 //              // IMPOSSIBLE!
133 //              Log_Error("USB", "String is %i bytes, which is over prealloc size (%i)",
134 //                      str.Length, sizeof(str)
135 //                      );
136 //      }
137         src_len = (str.Length - 2) / sizeof(str.Data[0]);
138
139         LOG("&str = %p, src_len = %i", &str, src_len);
140
141         new_len = _UTF16to8(str.Data, src_len, NULL);   
142         ret = malloc( new_len + 1 );
143         _UTF16to8(str.Data, src_len, ret);
144         ret[new_len] = 0;
145         return ret;
146 }
147
148 int _UTF16to8(Uint16 *Input, int InputLen, char *Dest)
149 {
150          int    str_len, cp_len;
151         Uint32  saved_bits = 0;
152         str_len = 0;
153         for( int i = 0; i < InputLen; i ++)
154         {
155                 Uint32  cp;
156                 Uint16  val = Input[i];
157                 if( val >= 0xD800 && val <= 0xDBFF )
158                 {
159                         // Multibyte - Leading
160                         if(i + 1 > InputLen) {
161                                 cp = '?';
162                         }
163                         else {
164                                 saved_bits = (val - 0xD800) << 10;
165                                 saved_bits += 0x10000;
166                                 continue ;
167                         }
168                 }
169                 else if( val >= 0xDC00 && val <= 0xDFFF )
170                 {
171                         if( !saved_bits ) {
172                                 cp = '?';
173                         }
174                         else {
175                                 saved_bits |= (val - 0xDC00);
176                                 cp = saved_bits;
177                         }
178                 }
179                 else
180                         cp = val;
181
182                 cp_len = WriteUTF8((Uint8*)Dest, cp);
183                 if(Dest)
184                         Dest += cp_len;
185                 str_len += cp_len;
186
187                 saved_bits = 0;
188         }
189         
190         return str_len;
191 }
192

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