USB - Slight host API change
[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         switch( Type & 0xF00 )
82         {
83         case 0x000:     req.ReqType |= (0 << 5);        break;  // Standard
84         case 0x100:     req.ReqType |= (1 << 5);        break;  // Class
85         case 0x200:     req.ReqType |= (2 << 5);        break;  // Vendor
86         }
87
88         req.Request = 6;        // GET_DESCRIPTOR
89         req.Value = LittleEndian16( ((Type & 0xFF) << 8) | (Index & 0xFF) );
90         req.Index = LittleEndian16( 0 );        // TODO: Language ID
91         req.Length = LittleEndian16( Length );
92         
93         Dev->Host->HostDef->SendSETUP(
94                 Dev->Host->Ptr, dest,
95                 0, NULL, NULL,
96                 &req, sizeof(req)
97                 );
98         
99         bToggle = 1;
100         while( Length > ciMaxPacketSize )
101         {
102                 Dev->Host->HostDef->SendIN(
103                         Dev->Host->Ptr, dest,
104                         bToggle, NULL, NULL,
105                         Dest, ciMaxPacketSize
106                         );
107                 bToggle = !bToggle;
108                 Length -= ciMaxPacketSize;
109         }
110
111         final = Dev->Host->HostDef->SendIN(
112                 Dev->Host->Ptr, dest,
113                 bToggle, INVLPTR, NULL,
114                 Dest, Length
115                 );
116
117         while( Dev->Host->HostDef->IsOpComplete(Dev->Host->Ptr, final) == 0 )
118                 Threads_Yield();
119
120         return 0;
121 }
122
123 char *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index)
124 {
125         struct sDescriptor_String       str;
126          int    src_len, new_len;
127         char    *ret;
128
129         if(Index == 0)  return strdup("");
130         
131         USB_int_ReadDescriptor(Dev, Endpoint, 3, Index, sizeof(str), &str);
132         if(str.Length < 2) {
133                 Log_Error("USB", "String %p:%i:%i:%i descriptor is undersized (%i)",
134                         Dev->Host, Dev->Address, Endpoint, Index, str.Length);
135                 return NULL;
136         }
137 //      if(str.Length > sizeof(str)) {
138 //              // IMPOSSIBLE!
139 //              Log_Error("USB", "String is %i bytes, which is over prealloc size (%i)",
140 //                      str.Length, sizeof(str)
141 //                      );
142 //      }
143         src_len = (str.Length - 2) / sizeof(str.Data[0]);
144
145         LOG("&str = %p, src_len = %i", &str, src_len);
146
147         new_len = _UTF16to8(str.Data, src_len, NULL);   
148         ret = malloc( new_len + 1 );
149         _UTF16to8(str.Data, src_len, ret);
150         ret[new_len] = 0;
151         return ret;
152 }
153
154 int _UTF16to8(Uint16 *Input, int InputLen, char *Dest)
155 {
156          int    str_len, cp_len;
157         Uint32  saved_bits = 0;
158         str_len = 0;
159         for( int i = 0; i < InputLen; i ++)
160         {
161                 Uint32  cp;
162                 Uint16  val = Input[i];
163                 if( val >= 0xD800 && val <= 0xDBFF )
164                 {
165                         // Multibyte - Leading
166                         if(i + 1 > InputLen) {
167                                 cp = '?';
168                         }
169                         else {
170                                 saved_bits = (val - 0xD800) << 10;
171                                 saved_bits += 0x10000;
172                                 continue ;
173                         }
174                 }
175                 else if( val >= 0xDC00 && val <= 0xDFFF )
176                 {
177                         if( !saved_bits ) {
178                                 cp = '?';
179                         }
180                         else {
181                                 saved_bits |= (val - 0xDC00);
182                                 cp = saved_bits;
183                         }
184                 }
185                 else
186                         cp = val;
187
188                 cp_len = WriteUTF8((Uint8*)Dest, cp);
189                 if(Dest)
190                         Dest += cp_len;
191                 str_len += cp_len;
192
193                 saved_bits = 0;
194         }
195         
196         return str_len;
197 }
198

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