Usermode/libc - Fix strchr and strrchr behavior
[tpg/acess2.git] / KernelLand / Modules / USB / Core / hub.c
1 /*
2  * Acess2 USB Stack
3  * - By John Hodge (thePowersGang)
4  *
5  * hub.c
6  * - Basic hub driver
7  */
8 #define DEBUG   0
9 #include <usb_hub.h>
10 #include <timers.h>
11
12 #define MAX_PORTS       32      // Not actually a max, but used for DeviceRemovable
13
14
15 #define GET_STATUS      0
16 #define CLEAR_FEATURE   1
17 // resvd
18 #define SET_FEATURE     3
19
20 struct sHubDescriptor
21 {
22         Uint8   DescLength;
23         Uint8   DescType;       // = 0x29
24         Uint8   NbrPorts;
25         Uint16  HubCharacteristics;
26         Uint8   PwrOn2PwrGood;  // 2 ms intervals
27         Uint8   HubContrCurrent;        // Max internal current (mA)
28         Uint8   DeviceRemovable[MAX_PORTS];
29 };
30
31 struct sHubInfo
32 {
33         tUSBHub *HubPtr;
34          int    PowerOnDelay;   // in ms
35          int    nPorts;
36         Uint8   DeviceRemovable[];
37 };
38
39 // === PROTOTYPES ===
40 void    Hub_Connected(tUSBInterface *Dev, void *Descriptors, size_t Length);
41 void    Hub_Disconnected(tUSBInterface *Dev);
42 void    Hub_PortStatusChange(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
43 void    Hub_int_HandleChange(tUSBInterface *Dev, int Port);
44 void    Hub_SetPortFeature(tUSBInterface *Dev, int Port, int Feat);
45 void    Hub_ClearPortFeature(tUSBInterface *HubDev, int Port, int Feat);
46 int     Hub_GetPortStatus(tUSBInterface *HubDev, int Port, int Flag);
47
48 // === GLOBALS ===
49 tUSBDriver      gUSBHub_Driver = {
50         .Name = "Hub",
51         .Match = {.Class = {0x090000, 0xFF0000}},
52         .Connected = Hub_Connected,
53         .Disconnected = Hub_Disconnected,
54         .MaxEndpoints = 1,
55         .Endpoints = {
56                 {0x83, Hub_PortStatusChange}
57         }
58 };
59
60 // === CODE ===
61 #if 0
62 int Hub_DriverInitialise(char **Arguments)
63 {
64         USB_RegisterDriver( &gUSBHub_Driver );
65         return 0;
66 }
67 #endif
68
69 void Hub_Connected(tUSBInterface *Dev, void *Descriptors, size_t Length)
70 {
71         struct sHubDescriptor   hub_desc;
72         struct sHubInfo *info;  
73
74         // Read hub descriptor (Class descriptor 0x9, destined for device)
75         USB_ReadDescriptor(Dev, 0x0129, 0, sizeof(hub_desc), &hub_desc);
76
77         LOG("%i Ports", hub_desc.NbrPorts);
78         LOG("Takes %i ms for power to stabilise", hub_desc.PwrOn2PwrGood*2);
79
80         // Allocate infomation structure
81         info = malloc(sizeof(*info) + (hub_desc.NbrPorts+7)/8);
82         if(!info) {
83                 Log_Error("USBHub", "malloc() failed");
84                 return ;
85         }
86         USB_SetDeviceDataPtr(Dev, info);
87
88         // Fill data
89         info->nPorts = hub_desc.NbrPorts;
90         info->PowerOnDelay = hub_desc.PwrOn2PwrGood * 2;
91         memcpy(info->DeviceRemovable, hub_desc.DeviceRemovable, (hub_desc.NbrPorts+7)/8);
92         // Register
93         info->HubPtr = USB_RegisterHub(Dev, info->nPorts);
94
95         // Register poll on endpoint
96         USB_StartPollingEndpoint(Dev, 1);
97 }
98
99 void Hub_Disconnected(tUSBInterface *Dev)
100 {
101         struct sHubInfo *info = USB_GetDeviceDataPtr(Dev);
102         USB_RemoveHub(info->HubPtr);
103         free(info);
104 }
105
106 void Hub_PortStatusChange(tUSBInterface *Dev, int Endpoint, int Length, void *Data)
107 {
108         Uint8   *status = Data;
109         struct sHubInfo *info = USB_GetDeviceDataPtr(Dev);
110          int    i;
111         for( i = 0; i < info->nPorts; i += 8, status ++ )
112         {
113                 if( i/8 >= Length )     break;
114                 LOG("status[%i] = %x", i/8, *status);
115                 if( *status == 0 )      continue;       
116
117                 for( int j = 0; j < 8; j ++ )
118                         if( *status & (1 << j) )
119                                 Hub_int_HandleChange(Dev, i+j);
120         }
121 }
122
123 void Hub_int_HandleChange(tUSBInterface *Dev, int Port)
124 {
125         struct sHubInfo *info = USB_GetDeviceDataPtr(Dev);
126         Uint16  status[2];      // Status, Change
127         
128         // Get port status
129         USB_Request(Dev, 0, 0xA3, GET_STATUS, 0, Port, 4, status);
130
131         LOG("Port %i: status = {0b%b, 0b%b}", Port, status[0], status[1]);
132         
133         // Handle connections / disconnections
134         if( status[1] & 0x0001 )
135         {
136                 if( status[0] & 0x0001 ) {
137                         // Connected
138                         // - Power on port
139                         USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_POWER, Port, 0, NULL);
140                         Time_Delay(info->PowerOnDelay);
141                         // - Start reset process
142                         USB_PortCtl_BeginReset(info->HubPtr, Port);
143                 }
144                 else {
145                         // Disconnected
146                         USB_DeviceDisconnected(info->HubPtr, Port);
147                 }
148                 
149                 USB_Request(Dev, 0, 0x23, CLEAR_FEATURE, C_PORT_CONNECTION, Port, 0, NULL);
150         }
151         
152         // Reset change
153         if( status[1] & 0x0010 )
154         {
155                 if( status[0] & 0x0010 ) {
156                         // Reset complete
157                 }
158                 else {
159                         // Useful?
160                 }
161                 // ACK
162                 USB_Request(Dev, 0, 0x23, CLEAR_FEATURE, C_PORT_RESET, Port, 0, NULL);
163         }
164 }
165
166 void Hub_SetPortFeature(tUSBInterface *Dev, int Port, int Feat)
167 {
168         USB_Request(Dev, 0, 0x23, SET_FEATURE, Feat, Port, 0, NULL);
169 }
170
171 void Hub_ClearPortFeature(tUSBInterface *Dev, int Port, int Feat)
172 {
173         USB_Request(Dev, 0, 0x23, CLEAR_FEATURE, Feat, Port, 0, NULL);
174 }
175
176 int Hub_GetPortStatus(tUSBInterface *Dev, int Port, int Flag)
177 {
178         Uint16  status[2];      // Status, Change
179         USB_Request(Dev, 0, 0xA3, GET_STATUS, 0, Port, 4, status);
180         return !!(status[0] & (1 << Flag));
181 }

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