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

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