Modules/USB - Working on HID support (and fixed some little bugs)
[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   1
9 #include <acess.h>
10 #include "usb.h"
11 #include "usb_proto.h"
12 #include "usb_lowlevel.h"
13 #include <timers.h>
14
15 // === PROTOTYPES ===
16 void    *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
17  int    USB_int_SendSetupSetAddress(tUSBHost *Host, int Address);
18  int    USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest);
19 char    *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index);
20  int    _UTF16to8(Uint16 *Input, int InputLen, char *Dest);
21
22 // === CODE ===
23 void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data)
24 {
25         void    *hdl;
26         // TODO: Sanity check (and check that Type is valid)
27         struct sDeviceRequest   req;
28          int    dest = Addr * 16 + EndPt;       // TODO: Validate
29         req.ReqType = Type;
30         req.Request = Req;
31         req.Value = LittleEndian16( Val );
32         req.Index = LittleEndian16( Indx );
33         req.Length = LittleEndian16( Len );
34         
35         hdl = Host->HostDef->SendSETUP(Host->Ptr, dest, 0, NULL, NULL, &req, sizeof(req));
36
37         // TODO: Data toggle?
38         // TODO: Multi-packet transfers
39         if( Type & 0x80 )
40         {
41                 void    *hdl2;
42                 
43                 hdl = Host->HostDef->SendIN(Host->Ptr, dest, 0, NULL, NULL, Data, Len);
44
45                 hdl2 = Host->HostDef->SendOUT(Host->Ptr, dest, 0, NULL, NULL, NULL, 0);
46                 while( Host->HostDef->IsOpComplete(Host->Ptr, hdl2) == 0 )
47                         Time_Delay(1);
48         }
49         else
50         {
51                 void    *hdl2;
52                 
53                 if( Len > 0 )
54                         hdl = Host->HostDef->SendOUT(Host->Ptr, dest, 0, NULL, NULL, Data, Len);
55                 else
56                         hdl = NULL;
57                 
58                 // Status phase (DataToggle=1)
59                 hdl2 = Host->HostDef->SendIN(Host->Ptr, dest, 1, NULL, NULL, NULL, 0);
60                 while( Host->HostDef->IsOpComplete(Host->Ptr, hdl2) == 0 )
61                         Time_Delay(1);
62         }
63         return hdl;
64 }
65
66 int USB_int_SendSetupSetAddress(tUSBHost *Host, int Address)
67 {
68         USB_int_Request(Host, 0, 0, 0x00, 5, Address & 0x7F, 0, 0, NULL);
69         return 0;
70 }
71
72 int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest)
73 {
74         const int       ciMaxPacketSize = 0x400;
75         struct sDeviceRequest   req;
76          int    bToggle = 0;
77         void    *final;
78          int    dest = Dev->Address*16 + Endpoint;
79
80         req.ReqType = 0x80;
81         req.ReqType |= ((Type >> 8) & 0x3) << 5;        // Bits 5/6
82         req.ReqType |= (Type >> 12) & 3;        // Destination (Device, Interface, Endpoint, Other);
83
84         req.Request = 6;        // GET_DESCRIPTOR
85         req.Value = LittleEndian16( ((Type & 0xFF) << 8) | (Index & 0xFF) );
86         req.Index = LittleEndian16( 0 );        // TODO: Language ID / Interface
87         req.Length = LittleEndian16( Length );
88         
89         Dev->Host->HostDef->SendSETUP(
90                 Dev->Host->Ptr, dest,
91                 0, NULL, NULL,
92                 &req, sizeof(req)
93                 );
94         
95         bToggle = 1;
96         while( Length > ciMaxPacketSize )
97         {
98                 Dev->Host->HostDef->SendIN(
99                         Dev->Host->Ptr, dest,
100                         bToggle, NULL, NULL,
101                         Dest, ciMaxPacketSize
102                         );
103                 bToggle = !bToggle;
104                 Length -= ciMaxPacketSize;
105         }
106
107         final = Dev->Host->HostDef->SendIN(
108                 Dev->Host->Ptr, dest,
109                 bToggle, INVLPTR, NULL,
110                 Dest, Length
111                 );
112
113         while( Dev->Host->HostDef->IsOpComplete(Dev->Host->Ptr, final) == 0 )
114                 Threads_Yield();
115
116         return 0;
117 }
118
119 char *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index)
120 {
121         struct sDescriptor_String       str;
122          int    src_len, new_len;
123         char    *ret;
124
125         if(Index == 0)  return strdup("");
126         
127         USB_int_ReadDescriptor(Dev, Endpoint, 3, Index, sizeof(str), &str);
128         if(str.Length < 2) {
129                 Log_Error("USB", "String %p:%i:%i:%i descriptor is undersized (%i)",
130                         Dev->Host, Dev->Address, Endpoint, Index, str.Length);
131                 return NULL;
132         }
133 //      if(str.Length > sizeof(str)) {
134 //              // IMPOSSIBLE!
135 //              Log_Error("USB", "String is %i bytes, which is over prealloc size (%i)",
136 //                      str.Length, sizeof(str)
137 //                      );
138 //      }
139         src_len = (str.Length - 2) / sizeof(str.Data[0]);
140
141         LOG("&str = %p, src_len = %i", &str, src_len);
142
143         new_len = _UTF16to8(str.Data, src_len, NULL);   
144         ret = malloc( new_len + 1 );
145         _UTF16to8(str.Data, src_len, ret);
146         ret[new_len] = 0;
147         return ret;
148 }
149
150 int _UTF16to8(Uint16 *Input, int InputLen, char *Dest)
151 {
152          int    str_len, cp_len;
153         Uint32  saved_bits = 0;
154         str_len = 0;
155         for( int i = 0; i < InputLen; i ++)
156         {
157                 Uint32  cp;
158                 Uint16  val = Input[i];
159                 if( val >= 0xD800 && val <= 0xDBFF )
160                 {
161                         // Multibyte - Leading
162                         if(i + 1 > InputLen) {
163                                 cp = '?';
164                         }
165                         else {
166                                 saved_bits = (val - 0xD800) << 10;
167                                 saved_bits += 0x10000;
168                                 continue ;
169                         }
170                 }
171                 else if( val >= 0xDC00 && val <= 0xDFFF )
172                 {
173                         if( !saved_bits ) {
174                                 cp = '?';
175                         }
176                         else {
177                                 saved_bits |= (val - 0xDC00);
178                                 cp = saved_bits;
179                         }
180                 }
181                 else
182                         cp = val;
183
184                 cp_len = WriteUTF8((Uint8*)Dest, cp);
185                 if(Dest)
186                         Dest += cp_len;
187                 str_len += cp_len;
188
189                 saved_bits = 0;
190         }
191         
192         return str_len;
193 }
194

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