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

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