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

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