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

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