1*2d64210cSWojciech Zajac /*
2*2d64210cSWojciech Zajac * Minix3 USB hub driver implementation
3*2d64210cSWojciech Zajac */
4*2d64210cSWojciech Zajac
5*2d64210cSWojciech Zajac #include <string.h> /* memset */
6*2d64210cSWojciech Zajac #include <stdint.h>
7*2d64210cSWojciech Zajac #include <time.h> /* nanosleep */
8*2d64210cSWojciech Zajac
9*2d64210cSWojciech Zajac #include <ddekit/thread.h>
10*2d64210cSWojciech Zajac #include <minix/sef.h>
11*2d64210cSWojciech Zajac #include <minix/sysutil.h> /* panic */
12*2d64210cSWojciech Zajac #include <minix/usb.h> /* usb_ctrlrequest TODO: remove me */
13*2d64210cSWojciech Zajac
14*2d64210cSWojciech Zajac #include "common.h"
15*2d64210cSWojciech Zajac #include "urb_helper.h"
16*2d64210cSWojciech Zajac
17*2d64210cSWojciech Zajac
18*2d64210cSWojciech Zajac /*---------------------------*
19*2d64210cSWojciech Zajac * declared functions *
20*2d64210cSWojciech Zajac *---------------------------*/
21*2d64210cSWojciech Zajac /* TODO: these are missing from DDE header files */
22*2d64210cSWojciech Zajac extern void ddekit_minix_wait_exit(void);
23*2d64210cSWojciech Zajac extern void ddekit_shutdown(void);
24*2d64210cSWojciech Zajac
25*2d64210cSWojciech Zajac /* SEF related functions */
26*2d64210cSWojciech Zajac static int hub_sef_hdlr(int, sef_init_info_t *);
27*2d64210cSWojciech Zajac static void hub_signal_handler(int);
28*2d64210cSWojciech Zajac
29*2d64210cSWojciech Zajac /* DDEKit IPC related */
30*2d64210cSWojciech Zajac static void ddekit_usb_task(void *);
31*2d64210cSWojciech Zajac
32*2d64210cSWojciech Zajac /* DDEKit's USB driver callbacks */
33*2d64210cSWojciech Zajac static void usb_driver_completion(void *);
34*2d64210cSWojciech Zajac static void usb_driver_connect(struct ddekit_usb_dev *, unsigned int);
35*2d64210cSWojciech Zajac static void usb_driver_disconnect(struct ddekit_usb_dev *);
36*2d64210cSWojciech Zajac
37*2d64210cSWojciech Zajac /* Hub driver main task */
38*2d64210cSWojciech Zajac static void hub_task(void *);
39*2d64210cSWojciech Zajac
40*2d64210cSWojciech Zajac
41*2d64210cSWojciech Zajac /*---------------------------*
42*2d64210cSWojciech Zajac * class specific stuff *
43*2d64210cSWojciech Zajac *---------------------------*/
44*2d64210cSWojciech Zajac #define HUB_PACKED __attribute__((__packed__))
45*2d64210cSWojciech Zajac
46*2d64210cSWojciech Zajac /* How often to check for changes */
47*2d64210cSWojciech Zajac #define USB_HUB_POLLING_INTERVAL 1000
48*2d64210cSWojciech Zajac
49*2d64210cSWojciech Zajac /* Max number of hub ports */
50*2d64210cSWojciech Zajac #define USB_HUB_PORT_LIMIT 8
51*2d64210cSWojciech Zajac
52*2d64210cSWojciech Zajac /* Limits number of communication retries (when needed) */
53*2d64210cSWojciech Zajac #define USB_HUB_MAX_TRIES 3
54*2d64210cSWojciech Zajac
55*2d64210cSWojciech Zajac /* How long to wait between retries, in case of reset error (in nanoseconds) */
56*2d64210cSWojciech Zajac #define USB_HUB_RESET_DELAY 200000000 /* 200ms */
57*2d64210cSWojciech Zajac
58*2d64210cSWojciech Zajac /* Hub descriptor type */
59*2d64210cSWojciech Zajac #define USB_HUB_DESCRIPTOR_TYPE 0x29
60*2d64210cSWojciech Zajac
61*2d64210cSWojciech Zajac /* Hub descriptor structure */
62*2d64210cSWojciech Zajac typedef struct HUB_PACKED hub_descriptor {
63*2d64210cSWojciech Zajac
64*2d64210cSWojciech Zajac uint8_t bDescLength;
65*2d64210cSWojciech Zajac uint8_t bDescriptorType;
66*2d64210cSWojciech Zajac uint8_t bNbrPorts;
67*2d64210cSWojciech Zajac uint16_t wHubCharacteristics;
68*2d64210cSWojciech Zajac uint8_t bPwrOn2PwrGood;
69*2d64210cSWojciech Zajac uint8_t bHubContrCurrent;
70*2d64210cSWojciech Zajac /* Remaining variable length fields are ignored for now */
71*2d64210cSWojciech Zajac }
72*2d64210cSWojciech Zajac hub_descriptor;
73*2d64210cSWojciech Zajac
74*2d64210cSWojciech Zajac /* Hub port status structure, as defined in USB 2.0 document */
75*2d64210cSWojciech Zajac typedef struct HUB_PACKED hub_port_status {
76*2d64210cSWojciech Zajac
77*2d64210cSWojciech Zajac uint32_t PORT_CONNECTION : 1;
78*2d64210cSWojciech Zajac uint32_t PORT_ENABLE : 1;
79*2d64210cSWojciech Zajac uint32_t PORT_SUSPEND : 1;
80*2d64210cSWojciech Zajac uint32_t PORT_OVER_CURRENT : 1;
81*2d64210cSWojciech Zajac uint32_t PORT_RESET : 1;
82*2d64210cSWojciech Zajac uint32_t RESERVED1 : 3;
83*2d64210cSWojciech Zajac
84*2d64210cSWojciech Zajac uint32_t PORT_POWER : 1;
85*2d64210cSWojciech Zajac uint32_t PORT_LOW_SPEED : 1;
86*2d64210cSWojciech Zajac uint32_t PORT_HIGH_SPEED : 1;
87*2d64210cSWojciech Zajac uint32_t PORT_TEST : 1;
88*2d64210cSWojciech Zajac uint32_t PORT_INDICATOR : 1;
89*2d64210cSWojciech Zajac uint32_t RESERVED2 : 3;
90*2d64210cSWojciech Zajac
91*2d64210cSWojciech Zajac uint32_t C_PORT_CONNECTION : 1;
92*2d64210cSWojciech Zajac uint32_t C_PORT_ENABLE : 1;
93*2d64210cSWojciech Zajac uint32_t C_PORT_SUSPEND : 1;
94*2d64210cSWojciech Zajac uint32_t C_PORT_OVER_CURRENT : 1;
95*2d64210cSWojciech Zajac uint32_t C_PORT_RESET : 1;
96*2d64210cSWojciech Zajac uint32_t RESERVED3 : 11;
97*2d64210cSWojciech Zajac }
98*2d64210cSWojciech Zajac hub_port_status;
99*2d64210cSWojciech Zajac
100*2d64210cSWojciech Zajac /* Hub Class Feature Selectors */
101*2d64210cSWojciech Zajac typedef enum {
102*2d64210cSWojciech Zajac
103*2d64210cSWojciech Zajac C_HUB_LOCAL_POWER = 0 ,
104*2d64210cSWojciech Zajac C_HUB_OVER_CURRENT = 1 ,
105*2d64210cSWojciech Zajac PORT_CONNECTION = 0 ,
106*2d64210cSWojciech Zajac PORT_ENABLE = 1 ,
107*2d64210cSWojciech Zajac PORT_SUSPEND = 2 ,
108*2d64210cSWojciech Zajac PORT_OVER_CURRENT = 3 ,
109*2d64210cSWojciech Zajac PORT_RESET = 4 ,
110*2d64210cSWojciech Zajac PORT_POWER = 8 ,
111*2d64210cSWojciech Zajac PORT_LOW_SPEED = 9 ,
112*2d64210cSWojciech Zajac C_PORT_CONNECTION = 16,
113*2d64210cSWojciech Zajac C_PORT_ENABLE = 17,
114*2d64210cSWojciech Zajac C_PORT_SUSPEND = 18,
115*2d64210cSWojciech Zajac C_PORT_OVER_CURRENT = 19,
116*2d64210cSWojciech Zajac C_PORT_RESET = 20,
117*2d64210cSWojciech Zajac PORT_TEST = 21,
118*2d64210cSWojciech Zajac PORT_INDICATOR = 22
119*2d64210cSWojciech Zajac }
120*2d64210cSWojciech Zajac class_feature;
121*2d64210cSWojciech Zajac
122*2d64210cSWojciech Zajac /* Hub Class Request Codes */
123*2d64210cSWojciech Zajac typedef enum {
124*2d64210cSWojciech Zajac
125*2d64210cSWojciech Zajac GET_STATUS = 0 ,
126*2d64210cSWojciech Zajac CLEAR_FEATURE = 1 ,
127*2d64210cSWojciech Zajac RESERVED1 = 2 ,
128*2d64210cSWojciech Zajac SET_FEATURE = 3 ,
129*2d64210cSWojciech Zajac RESERVED2 = 4 ,
130*2d64210cSWojciech Zajac RESERVED3 = 5 ,
131*2d64210cSWojciech Zajac GET_DESCRIPTOR = 6 ,
132*2d64210cSWojciech Zajac SET_DESCRIPTOR = 7 ,
133*2d64210cSWojciech Zajac CLEAR_TT_BUFFER = 8 ,
134*2d64210cSWojciech Zajac RESET_TT = 9 ,
135*2d64210cSWojciech Zajac GET_TT_STATE = 10,
136*2d64210cSWojciech Zajac STOP_TT = 11
137*2d64210cSWojciech Zajac }
138*2d64210cSWojciech Zajac class_code;
139*2d64210cSWojciech Zajac
140*2d64210cSWojciech Zajac /* Hub port connection state */
141*2d64210cSWojciech Zajac typedef enum {
142*2d64210cSWojciech Zajac
143*2d64210cSWojciech Zajac HUB_PORT_DISCONN = 0,
144*2d64210cSWojciech Zajac HUB_PORT_CONN = 1,
145*2d64210cSWojciech Zajac HUB_PORT_ERROR = 2
146*2d64210cSWojciech Zajac }
147*2d64210cSWojciech Zajac port_conn;
148*2d64210cSWojciech Zajac
149*2d64210cSWojciech Zajac /* Hub port connection changes */
150*2d64210cSWojciech Zajac typedef enum {
151*2d64210cSWojciech Zajac
152*2d64210cSWojciech Zajac HUB_CHANGE_NONE = 0, /* Nothing changed since last poll */
153*2d64210cSWojciech Zajac HUB_CHANGE_CONN = 1, /* Device was just connected */
154*2d64210cSWojciech Zajac HUB_CHANGE_DISCONN= 2, /* Device was just disconnected */
155*2d64210cSWojciech Zajac HUB_CHANGE_STATUS_ERR = 3, /* Port status mismatch */
156*2d64210cSWojciech Zajac HUB_CHANGE_COM_ERR = 4 /* Something wrong happened to driver */
157*2d64210cSWojciech Zajac }
158*2d64210cSWojciech Zajac port_change;
159*2d64210cSWojciech Zajac
160*2d64210cSWojciech Zajac /* Hub get class specific descriptor call */
161*2d64210cSWojciech Zajac static int hub_get_descriptor(hub_descriptor *);
162*2d64210cSWojciech Zajac
163*2d64210cSWojciech Zajac /* Hub Set/ClearPortFeature call */
164*2d64210cSWojciech Zajac static int hub_port_feature(int, class_code, class_feature);
165*2d64210cSWojciech Zajac
166*2d64210cSWojciech Zajac /* Hub GetPortStatus call */
167*2d64210cSWojciech Zajac static int hub_get_port_status(int, hub_port_status *);
168*2d64210cSWojciech Zajac
169*2d64210cSWojciech Zajac /* Handle port status change */
170*2d64210cSWojciech Zajac static port_change hub_handle_change(int, hub_port_status *);
171*2d64210cSWojciech Zajac
172*2d64210cSWojciech Zajac /* Handle port connection */
173*2d64210cSWojciech Zajac static int hub_handle_connection(int, hub_port_status *);
174*2d64210cSWojciech Zajac
175*2d64210cSWojciech Zajac /* Handle port disconnection */
176*2d64210cSWojciech Zajac static int hub_handle_disconnection(int);
177*2d64210cSWojciech Zajac
178*2d64210cSWojciech Zajac
179*2d64210cSWojciech Zajac /*---------------------------*
180*2d64210cSWojciech Zajac * defined variables *
181*2d64210cSWojciech Zajac *---------------------------*/
182*2d64210cSWojciech Zajac /* USB hub driver state */
183*2d64210cSWojciech Zajac typedef struct hub_state {
184*2d64210cSWojciech Zajac
185*2d64210cSWojciech Zajac hub_descriptor descriptor; /* Class specific descriptor */
186*2d64210cSWojciech Zajac struct ddekit_usb_dev * dev; /* DDEKit device */
187*2d64210cSWojciech Zajac int num_ports; /* Number of hub ports */
188*2d64210cSWojciech Zajac port_conn conn[USB_HUB_PORT_LIMIT]; /* Map of connected ports */
189*2d64210cSWojciech Zajac }
190*2d64210cSWojciech Zajac hub_state;
191*2d64210cSWojciech Zajac
192*2d64210cSWojciech Zajac /* Current hub driver state */
193*2d64210cSWojciech Zajac static hub_state driver_state;
194*2d64210cSWojciech Zajac
195*2d64210cSWojciech Zajac /* USB callback structure */
196*2d64210cSWojciech Zajac static struct ddekit_usb_driver usb_driver = {
197*2d64210cSWojciech Zajac .completion = usb_driver_completion,
198*2d64210cSWojciech Zajac .connect = usb_driver_connect,
199*2d64210cSWojciech Zajac .disconnect = usb_driver_disconnect
200*2d64210cSWojciech Zajac };
201*2d64210cSWojciech Zajac
202*2d64210cSWojciech Zajac /* Semaphore used to block hub thread to
203*2d64210cSWojciech Zajac * allow DDE dispatcher operation */
204*2d64210cSWojciech Zajac static ddekit_sem_t * hub_sem = NULL;
205*2d64210cSWojciech Zajac
206*2d64210cSWojciech Zajac /* USB hub thread */
207*2d64210cSWojciech Zajac ddekit_thread_t * hub_thread = NULL;
208*2d64210cSWojciech Zajac
209*2d64210cSWojciech Zajac /* DDEKit USB message handling thread */
210*2d64210cSWojciech Zajac ddekit_thread_t * ddekit_usb_thread = NULL;
211*2d64210cSWojciech Zajac
212*2d64210cSWojciech Zajac
213*2d64210cSWojciech Zajac /*---------------------------*
214*2d64210cSWojciech Zajac * defined functions *
215*2d64210cSWojciech Zajac *---------------------------*/
216*2d64210cSWojciech Zajac /*===========================================================================*
217*2d64210cSWojciech Zajac * main *
218*2d64210cSWojciech Zajac *===========================================================================*/
219*2d64210cSWojciech Zajac int
main(int argc,char * argv[])220*2d64210cSWojciech Zajac main(int argc, char * argv[])
221*2d64210cSWojciech Zajac {
222*2d64210cSWojciech Zajac HUB_MSG("Starting driver... (built: %s %s)", __DATE__, __TIME__);
223*2d64210cSWojciech Zajac
224*2d64210cSWojciech Zajac /* Store arguments for future parsing */
225*2d64210cSWojciech Zajac env_setargs(argc, argv);
226*2d64210cSWojciech Zajac
227*2d64210cSWojciech Zajac /* Clear current state */
228*2d64210cSWojciech Zajac memset(&driver_state, 0, sizeof(driver_state));
229*2d64210cSWojciech Zajac
230*2d64210cSWojciech Zajac /* Initialize SEF related callbacks */
231*2d64210cSWojciech Zajac sef_setcb_init_fresh(hub_sef_hdlr);
232*2d64210cSWojciech Zajac sef_setcb_init_lu(hub_sef_hdlr);
233*2d64210cSWojciech Zajac sef_setcb_init_restart(hub_sef_hdlr);
234*2d64210cSWojciech Zajac sef_setcb_signal_handler(hub_signal_handler);
235*2d64210cSWojciech Zajac
236*2d64210cSWojciech Zajac /* Initialize DDEkit (involves sef_startup()) */
237*2d64210cSWojciech Zajac ddekit_init();
238*2d64210cSWojciech Zajac HUB_DEBUG_MSG("DDEkit ready...");
239*2d64210cSWojciech Zajac
240*2d64210cSWojciech Zajac /* Semaphore initialization */
241*2d64210cSWojciech Zajac hub_sem = ddekit_sem_init(0);
242*2d64210cSWojciech Zajac if (NULL == hub_sem)
243*2d64210cSWojciech Zajac panic("Initializing USB hub semaphore, failed!");
244*2d64210cSWojciech Zajac
245*2d64210cSWojciech Zajac /* Starting hub thread */
246*2d64210cSWojciech Zajac hub_thread = ddekit_thread_create(hub_task, NULL, "hub_task");
247*2d64210cSWojciech Zajac if (NULL == hub_thread)
248*2d64210cSWojciech Zajac panic("Initializing USB hub thread failed!");
249*2d64210cSWojciech Zajac
250*2d64210cSWojciech Zajac HUB_DEBUG_MSG("USB HUB task ready...");
251*2d64210cSWojciech Zajac
252*2d64210cSWojciech Zajac /* Run USB IPC task to collect messages */
253*2d64210cSWojciech Zajac ddekit_usb_thread = ddekit_thread_create(ddekit_usb_task, NULL,
254*2d64210cSWojciech Zajac "ddekit_task" );
255*2d64210cSWojciech Zajac if (NULL == ddekit_usb_thread)
256*2d64210cSWojciech Zajac panic("Initializing ddekit_usb_thread failed!");
257*2d64210cSWojciech Zajac
258*2d64210cSWojciech Zajac HUB_DEBUG_MSG("USB IPC task ready...");
259*2d64210cSWojciech Zajac
260*2d64210cSWojciech Zajac /* Block and wait until exit signal is received */
261*2d64210cSWojciech Zajac ddekit_minix_wait_exit();
262*2d64210cSWojciech Zajac HUB_DEBUG_MSG("Exiting...");
263*2d64210cSWojciech Zajac
264*2d64210cSWojciech Zajac /* Release objects that were explicitly allocated above */
265*2d64210cSWojciech Zajac ddekit_thread_terminate(ddekit_usb_thread);
266*2d64210cSWojciech Zajac ddekit_thread_terminate(hub_thread);
267*2d64210cSWojciech Zajac ddekit_sem_deinit(hub_sem);
268*2d64210cSWojciech Zajac
269*2d64210cSWojciech Zajac /* TODO: No ddekit_deinit for proper cleanup? */
270*2d64210cSWojciech Zajac
271*2d64210cSWojciech Zajac HUB_DEBUG_MSG("Cleanup completed...");
272*2d64210cSWojciech Zajac
273*2d64210cSWojciech Zajac return EXIT_SUCCESS;
274*2d64210cSWojciech Zajac }
275*2d64210cSWojciech Zajac
276*2d64210cSWojciech Zajac
277*2d64210cSWojciech Zajac /*===========================================================================*
278*2d64210cSWojciech Zajac * hub_sef_hdlr *
279*2d64210cSWojciech Zajac *===========================================================================*/
280*2d64210cSWojciech Zajac static int
hub_sef_hdlr(int type,sef_init_info_t * UNUSED (info))281*2d64210cSWojciech Zajac hub_sef_hdlr(int type, sef_init_info_t * UNUSED(info))
282*2d64210cSWojciech Zajac {
283*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
284*2d64210cSWojciech Zajac
285*2d64210cSWojciech Zajac switch (type) {
286*2d64210cSWojciech Zajac case SEF_INIT_FRESH:
287*2d64210cSWojciech Zajac return EXIT_SUCCESS;
288*2d64210cSWojciech Zajac case SEF_INIT_LU:
289*2d64210cSWojciech Zajac case SEF_INIT_RESTART:
290*2d64210cSWojciech Zajac HUB_MSG("Only 'fresh' SEF initialization supported");
291*2d64210cSWojciech Zajac break;
292*2d64210cSWojciech Zajac default:
293*2d64210cSWojciech Zajac HUB_MSG("Illegal SEF type");
294*2d64210cSWojciech Zajac break;
295*2d64210cSWojciech Zajac }
296*2d64210cSWojciech Zajac
297*2d64210cSWojciech Zajac return EXIT_FAILURE;
298*2d64210cSWojciech Zajac }
299*2d64210cSWojciech Zajac
300*2d64210cSWojciech Zajac
301*2d64210cSWojciech Zajac /*===========================================================================*
302*2d64210cSWojciech Zajac * hub_signal_handler *
303*2d64210cSWojciech Zajac *===========================================================================*/
304*2d64210cSWojciech Zajac static void
hub_signal_handler(int this_signal)305*2d64210cSWojciech Zajac hub_signal_handler(int this_signal)
306*2d64210cSWojciech Zajac {
307*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
308*2d64210cSWojciech Zajac
309*2d64210cSWojciech Zajac HUB_MSG("Handling signal 0x%X", this_signal);
310*2d64210cSWojciech Zajac
311*2d64210cSWojciech Zajac /* TODO: Any signal means shutdown for now (it may be OK anyway) */
312*2d64210cSWojciech Zajac /* Try graceful DDEKit exit */
313*2d64210cSWojciech Zajac ddekit_shutdown();
314*2d64210cSWojciech Zajac
315*2d64210cSWojciech Zajac /* Unreachable, when ddekit_shutdown works correctly */
316*2d64210cSWojciech Zajac panic("Calling ddekit_shutdown failed!");
317*2d64210cSWojciech Zajac }
318*2d64210cSWojciech Zajac
319*2d64210cSWojciech Zajac
320*2d64210cSWojciech Zajac /*===========================================================================*
321*2d64210cSWojciech Zajac * ddekit_usb_task *
322*2d64210cSWojciech Zajac *===========================================================================*/
323*2d64210cSWojciech Zajac static void
ddekit_usb_task(void * UNUSED (arg))324*2d64210cSWojciech Zajac ddekit_usb_task(void * UNUSED(arg))
325*2d64210cSWojciech Zajac {
326*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
327*2d64210cSWojciech Zajac
328*2d64210cSWojciech Zajac /* TODO: This call was meant to return 'int' but loops forever instead,
329*2d64210cSWojciech Zajac * so no return value is checked */
330*2d64210cSWojciech Zajac ddekit_usb_init(&usb_driver, NULL, NULL);
331*2d64210cSWojciech Zajac }
332*2d64210cSWojciech Zajac
333*2d64210cSWojciech Zajac
334*2d64210cSWojciech Zajac /*===========================================================================*
335*2d64210cSWojciech Zajac * usb_driver_completion *
336*2d64210cSWojciech Zajac *===========================================================================*/
337*2d64210cSWojciech Zajac static void
usb_driver_completion(void * UNUSED (priv))338*2d64210cSWojciech Zajac usb_driver_completion(void * UNUSED(priv))
339*2d64210cSWojciech Zajac {
340*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
341*2d64210cSWojciech Zajac
342*2d64210cSWojciech Zajac /* Last request was completed so allow continuing
343*2d64210cSWojciech Zajac * execution from place where semaphore was downed */
344*2d64210cSWojciech Zajac ddekit_sem_up(hub_sem);
345*2d64210cSWojciech Zajac }
346*2d64210cSWojciech Zajac
347*2d64210cSWojciech Zajac
348*2d64210cSWojciech Zajac /*===========================================================================*
349*2d64210cSWojciech Zajac * usb_driver_connect *
350*2d64210cSWojciech Zajac *===========================================================================*/
351*2d64210cSWojciech Zajac static void
usb_driver_connect(struct ddekit_usb_dev * dev,unsigned int interfaces)352*2d64210cSWojciech Zajac usb_driver_connect(struct ddekit_usb_dev * dev, unsigned int interfaces)
353*2d64210cSWojciech Zajac {
354*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
355*2d64210cSWojciech Zajac
356*2d64210cSWojciech Zajac if (NULL != driver_state.dev)
357*2d64210cSWojciech Zajac panic("HUB device driver can be connected only once!");
358*2d64210cSWojciech Zajac
359*2d64210cSWojciech Zajac /* Clear current state */
360*2d64210cSWojciech Zajac memset(&driver_state, 0, sizeof(driver_state));
361*2d64210cSWojciech Zajac
362*2d64210cSWojciech Zajac /* Hold host information for future use */
363*2d64210cSWojciech Zajac driver_state.dev = dev;
364*2d64210cSWojciech Zajac
365*2d64210cSWojciech Zajac /* Let driver logic work */
366*2d64210cSWojciech Zajac ddekit_sem_up(hub_sem);
367*2d64210cSWojciech Zajac }
368*2d64210cSWojciech Zajac
369*2d64210cSWojciech Zajac
370*2d64210cSWojciech Zajac /*===========================================================================*
371*2d64210cSWojciech Zajac * usb_driver_disconnect *
372*2d64210cSWojciech Zajac *===========================================================================*/
373*2d64210cSWojciech Zajac static void
usb_driver_disconnect(struct ddekit_usb_dev * UNUSED (dev))374*2d64210cSWojciech Zajac usb_driver_disconnect(struct ddekit_usb_dev * UNUSED(dev))
375*2d64210cSWojciech Zajac {
376*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
377*2d64210cSWojciech Zajac
378*2d64210cSWojciech Zajac if (NULL == driver_state.dev)
379*2d64210cSWojciech Zajac panic("HUB device driver was never connected!");
380*2d64210cSWojciech Zajac
381*2d64210cSWojciech Zajac /* Discard connected device information */
382*2d64210cSWojciech Zajac driver_state.dev = NULL;
383*2d64210cSWojciech Zajac }
384*2d64210cSWojciech Zajac
385*2d64210cSWojciech Zajac
386*2d64210cSWojciech Zajac /*===========================================================================*
387*2d64210cSWojciech Zajac * hub_task *
388*2d64210cSWojciech Zajac *===========================================================================*/
389*2d64210cSWojciech Zajac static void
hub_task(void * UNUSED (arg))390*2d64210cSWojciech Zajac hub_task(void * UNUSED(arg))
391*2d64210cSWojciech Zajac {
392*2d64210cSWojciech Zajac hub_port_status port_status;
393*2d64210cSWojciech Zajac hub_state * s;
394*2d64210cSWojciech Zajac hub_descriptor * d;
395*2d64210cSWojciech Zajac int port;
396*2d64210cSWojciech Zajac
397*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
398*2d64210cSWojciech Zajac
399*2d64210cSWojciech Zajac /* For short */
400*2d64210cSWojciech Zajac s = &(driver_state);
401*2d64210cSWojciech Zajac d = &(s->descriptor);
402*2d64210cSWojciech Zajac
403*2d64210cSWojciech Zajac /* Wait for connection */
404*2d64210cSWojciech Zajac ddekit_sem_down(hub_sem);
405*2d64210cSWojciech Zajac
406*2d64210cSWojciech Zajac if (hub_get_descriptor(d)) {
407*2d64210cSWojciech Zajac HUB_MSG("Getting hub descriptor failed");
408*2d64210cSWojciech Zajac goto HUB_ERROR;
409*2d64210cSWojciech Zajac }
410*2d64210cSWojciech Zajac
411*2d64210cSWojciech Zajac /* Output hub descriptor in debug mode */
412*2d64210cSWojciech Zajac HUB_DEBUG_MSG("bDescLength %4X", d->bDescLength);
413*2d64210cSWojciech Zajac HUB_DEBUG_MSG("bDescriptorType %4X", d->bDescriptorType);
414*2d64210cSWojciech Zajac HUB_DEBUG_MSG("bNbrPorts %4X", d->bNbrPorts);
415*2d64210cSWojciech Zajac HUB_DEBUG_MSG("wHubCharacteristics %4X", d->wHubCharacteristics);
416*2d64210cSWojciech Zajac HUB_DEBUG_MSG("bPwrOn2PwrGood %4X", d->bPwrOn2PwrGood);
417*2d64210cSWojciech Zajac HUB_DEBUG_MSG("bHubContrCurrent %4X", d->bHubContrCurrent);
418*2d64210cSWojciech Zajac
419*2d64210cSWojciech Zajac /* Check for sane number of ports... */
420*2d64210cSWojciech Zajac if (d->bNbrPorts > USB_HUB_PORT_LIMIT) {
421*2d64210cSWojciech Zajac HUB_MSG("Too many hub ports declared: %d", d->bNbrPorts);
422*2d64210cSWojciech Zajac goto HUB_ERROR;
423*2d64210cSWojciech Zajac }
424*2d64210cSWojciech Zajac
425*2d64210cSWojciech Zajac /* ...and reassign */
426*2d64210cSWojciech Zajac s->num_ports = (int)d->bNbrPorts;
427*2d64210cSWojciech Zajac
428*2d64210cSWojciech Zajac /* Initialize all available ports starting
429*2d64210cSWojciech Zajac * from 1, as defined by USB 2.0 document */
430*2d64210cSWojciech Zajac for (port = 1; port <= s->num_ports; port++) {
431*2d64210cSWojciech Zajac if (hub_port_feature(port, SET_FEATURE, PORT_POWER)) {
432*2d64210cSWojciech Zajac HUB_MSG("Powering port%d failed", port);
433*2d64210cSWojciech Zajac goto HUB_ERROR;
434*2d64210cSWojciech Zajac }
435*2d64210cSWojciech Zajac }
436*2d64210cSWojciech Zajac
437*2d64210cSWojciech Zajac /*
438*2d64210cSWojciech Zajac * Connection polling loop
439*2d64210cSWojciech Zajac */
440*2d64210cSWojciech Zajac for (;;) {
441*2d64210cSWojciech Zajac for (port = 1; port <= s->num_ports; port++) {
442*2d64210cSWojciech Zajac
443*2d64210cSWojciech Zajac /* Ignore previously blocked ports */
444*2d64210cSWojciech Zajac if (HUB_PORT_ERROR == s->conn[port]) {
445*2d64210cSWojciech Zajac HUB_DEBUG_MSG("Blocked hub port ignored");
446*2d64210cSWojciech Zajac continue;
447*2d64210cSWojciech Zajac }
448*2d64210cSWojciech Zajac
449*2d64210cSWojciech Zajac /* Get port status */
450*2d64210cSWojciech Zajac if (hub_get_port_status(port, &port_status)) {
451*2d64210cSWojciech Zajac HUB_MSG("Reading port%d status failed", port);
452*2d64210cSWojciech Zajac goto HUB_ERROR;
453*2d64210cSWojciech Zajac }
454*2d64210cSWojciech Zajac
455*2d64210cSWojciech Zajac /* Resolve port changes */
456*2d64210cSWojciech Zajac switch (hub_handle_change(port, &port_status)) {
457*2d64210cSWojciech Zajac
458*2d64210cSWojciech Zajac case HUB_CHANGE_NONE:
459*2d64210cSWojciech Zajac break;
460*2d64210cSWojciech Zajac
461*2d64210cSWojciech Zajac case HUB_CHANGE_CONN:
462*2d64210cSWojciech Zajac s->conn[port] = HUB_PORT_CONN;
463*2d64210cSWojciech Zajac break;
464*2d64210cSWojciech Zajac
465*2d64210cSWojciech Zajac case HUB_CHANGE_DISCONN:
466*2d64210cSWojciech Zajac s->conn[port] = HUB_PORT_DISCONN;
467*2d64210cSWojciech Zajac break;
468*2d64210cSWojciech Zajac
469*2d64210cSWojciech Zajac case HUB_CHANGE_STATUS_ERR:
470*2d64210cSWojciech Zajac /* Turn off port */
471*2d64210cSWojciech Zajac if (hub_port_feature(port,
472*2d64210cSWojciech Zajac CLEAR_FEATURE,
473*2d64210cSWojciech Zajac PORT_POWER)) {
474*2d64210cSWojciech Zajac HUB_MSG("Halting port%d "
475*2d64210cSWojciech Zajac "failed", port);
476*2d64210cSWojciech Zajac goto HUB_ERROR;
477*2d64210cSWojciech Zajac }
478*2d64210cSWojciech Zajac /* Block this port forever */
479*2d64210cSWojciech Zajac s->conn[port] = HUB_PORT_ERROR;
480*2d64210cSWojciech Zajac
481*2d64210cSWojciech Zajac HUB_MSG("Port%d status ERROR", port);
482*2d64210cSWojciech Zajac HUB_MSG("Port%d will be blocked, until "
483*2d64210cSWojciech Zajac "hub is detached", port);
484*2d64210cSWojciech Zajac
485*2d64210cSWojciech Zajac break;
486*2d64210cSWojciech Zajac
487*2d64210cSWojciech Zajac case HUB_CHANGE_COM_ERR:
488*2d64210cSWojciech Zajac /* Serious error, hang */
489*2d64210cSWojciech Zajac HUB_MSG("Handling port%d "
490*2d64210cSWojciech Zajac "change failed", port);
491*2d64210cSWojciech Zajac goto HUB_ERROR;
492*2d64210cSWojciech Zajac }
493*2d64210cSWojciech Zajac }
494*2d64210cSWojciech Zajac
495*2d64210cSWojciech Zajac ddekit_thread_msleep(USB_HUB_POLLING_INTERVAL);
496*2d64210cSWojciech Zajac HUB_DEBUG_MSG("Polling USB hub for status change");
497*2d64210cSWojciech Zajac }
498*2d64210cSWojciech Zajac
499*2d64210cSWojciech Zajac return;
500*2d64210cSWojciech Zajac
501*2d64210cSWojciech Zajac HUB_ERROR:
502*2d64210cSWojciech Zajac for (;;) {
503*2d64210cSWojciech Zajac /* Hang till removed by devmand */
504*2d64210cSWojciech Zajac HUB_MSG("Hub driver error occurred, hanging up");
505*2d64210cSWojciech Zajac ddekit_sem_down(hub_sem);
506*2d64210cSWojciech Zajac }
507*2d64210cSWojciech Zajac }
508*2d64210cSWojciech Zajac
509*2d64210cSWojciech Zajac
510*2d64210cSWojciech Zajac /*===========================================================================*
511*2d64210cSWojciech Zajac * hub_get_descriptor *
512*2d64210cSWojciech Zajac *===========================================================================*/
513*2d64210cSWojciech Zajac static int
hub_get_descriptor(hub_descriptor * descriptor)514*2d64210cSWojciech Zajac hub_get_descriptor(hub_descriptor * descriptor)
515*2d64210cSWojciech Zajac {
516*2d64210cSWojciech Zajac /* URB to be send */
517*2d64210cSWojciech Zajac struct ddekit_usb_urb urb;
518*2d64210cSWojciech Zajac
519*2d64210cSWojciech Zajac /* Setup buffer to be attached */
520*2d64210cSWojciech Zajac struct usb_ctrlrequest setup_buf;
521*2d64210cSWojciech Zajac
522*2d64210cSWojciech Zajac /* Control EP configuration */
523*2d64210cSWojciech Zajac urb_ep_config ep_conf;
524*2d64210cSWojciech Zajac
525*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
526*2d64210cSWojciech Zajac
527*2d64210cSWojciech Zajac /* Initialize EP configuration */
528*2d64210cSWojciech Zajac ep_conf.ep_num = 0;
529*2d64210cSWojciech Zajac ep_conf.direction = DDEKIT_USB_IN;
530*2d64210cSWojciech Zajac ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
531*2d64210cSWojciech Zajac ep_conf.max_packet_size = 0;
532*2d64210cSWojciech Zajac ep_conf.interval = 0;
533*2d64210cSWojciech Zajac
534*2d64210cSWojciech Zajac /* Reset URB and assign given values */
535*2d64210cSWojciech Zajac init_urb(&urb, driver_state.dev, &ep_conf);
536*2d64210cSWojciech Zajac
537*2d64210cSWojciech Zajac /* Clear setup data */
538*2d64210cSWojciech Zajac memset(&setup_buf, 0, sizeof(setup_buf));
539*2d64210cSWojciech Zajac
540*2d64210cSWojciech Zajac /* Class get hub descriptor request */
541*2d64210cSWojciech Zajac setup_buf.bRequestType = 0xA0;
542*2d64210cSWojciech Zajac setup_buf.bRequest = 0x06;
543*2d64210cSWojciech Zajac setup_buf.wValue = USB_HUB_DESCRIPTOR_TYPE << 8;
544*2d64210cSWojciech Zajac setup_buf.wIndex = 0x00;
545*2d64210cSWojciech Zajac setup_buf.wLength = sizeof(*descriptor);
546*2d64210cSWojciech Zajac
547*2d64210cSWojciech Zajac /* Attach buffers to URB */
548*2d64210cSWojciech Zajac attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
549*2d64210cSWojciech Zajac &setup_buf, sizeof(setup_buf));
550*2d64210cSWojciech Zajac attach_urb_data(&urb, URB_BUF_TYPE_DATA,
551*2d64210cSWojciech Zajac descriptor, sizeof(*descriptor));
552*2d64210cSWojciech Zajac
553*2d64210cSWojciech Zajac /* Send and wait for response */
554*2d64210cSWojciech Zajac if (blocking_urb_submit(&urb, hub_sem, URB_SUBMIT_CHECK_LEN)) {
555*2d64210cSWojciech Zajac HUB_MSG("Submitting HUB URB failed");
556*2d64210cSWojciech Zajac return EXIT_FAILURE;
557*2d64210cSWojciech Zajac } else {
558*2d64210cSWojciech Zajac HUB_DEBUG_MSG("HUB descriptor received");
559*2d64210cSWojciech Zajac return EXIT_SUCCESS;
560*2d64210cSWojciech Zajac }
561*2d64210cSWojciech Zajac }
562*2d64210cSWojciech Zajac
563*2d64210cSWojciech Zajac
564*2d64210cSWojciech Zajac /*===========================================================================*
565*2d64210cSWojciech Zajac * hub_port_feature *
566*2d64210cSWojciech Zajac *===========================================================================*/
567*2d64210cSWojciech Zajac static int
hub_port_feature(int port_num,class_code code,class_feature feature)568*2d64210cSWojciech Zajac hub_port_feature(int port_num, class_code code, class_feature feature)
569*2d64210cSWojciech Zajac {
570*2d64210cSWojciech Zajac /* URB to be send */
571*2d64210cSWojciech Zajac struct ddekit_usb_urb urb;
572*2d64210cSWojciech Zajac
573*2d64210cSWojciech Zajac /* Setup buffer to be attached */
574*2d64210cSWojciech Zajac struct usb_ctrlrequest setup_buf;
575*2d64210cSWojciech Zajac
576*2d64210cSWojciech Zajac /* Control EP configuration */
577*2d64210cSWojciech Zajac urb_ep_config ep_conf;
578*2d64210cSWojciech Zajac
579*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
580*2d64210cSWojciech Zajac
581*2d64210cSWojciech Zajac /* TODO: Add more checks when needed */
582*2d64210cSWojciech Zajac if (!((port_num <= driver_state.num_ports) && (port_num > 0)))
583*2d64210cSWojciech Zajac return EXIT_FAILURE;
584*2d64210cSWojciech Zajac
585*2d64210cSWojciech Zajac if (!((code == SET_FEATURE) || (code == CLEAR_FEATURE)))
586*2d64210cSWojciech Zajac return EXIT_FAILURE;
587*2d64210cSWojciech Zajac
588*2d64210cSWojciech Zajac if (!((feature == PORT_RESET) || (feature == PORT_POWER) ||
589*2d64210cSWojciech Zajac (feature == C_PORT_CONNECTION) || (feature == C_PORT_RESET)))
590*2d64210cSWojciech Zajac return EXIT_FAILURE;
591*2d64210cSWojciech Zajac
592*2d64210cSWojciech Zajac /* Initialize EP configuration */
593*2d64210cSWojciech Zajac ep_conf.ep_num = 0;
594*2d64210cSWojciech Zajac ep_conf.direction = DDEKIT_USB_OUT;
595*2d64210cSWojciech Zajac ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
596*2d64210cSWojciech Zajac ep_conf.max_packet_size = 0;
597*2d64210cSWojciech Zajac ep_conf.interval = 0;
598*2d64210cSWojciech Zajac
599*2d64210cSWojciech Zajac /* Reset URB and assign given values */
600*2d64210cSWojciech Zajac init_urb(&urb, driver_state.dev, &ep_conf);
601*2d64210cSWojciech Zajac
602*2d64210cSWojciech Zajac /* Clear setup data */
603*2d64210cSWojciech Zajac memset(&setup_buf, 0, sizeof(setup_buf));
604*2d64210cSWojciech Zajac
605*2d64210cSWojciech Zajac /* Standard get endpoint request */
606*2d64210cSWojciech Zajac setup_buf.bRequestType = 0x23;
607*2d64210cSWojciech Zajac setup_buf.bRequest = (u8_t)code;
608*2d64210cSWojciech Zajac setup_buf.wValue = (u16_t)feature;
609*2d64210cSWojciech Zajac setup_buf.wIndex = (u16_t)port_num;
610*2d64210cSWojciech Zajac setup_buf.wLength = 0;
611*2d64210cSWojciech Zajac
612*2d64210cSWojciech Zajac /* Attach buffers to URB */
613*2d64210cSWojciech Zajac attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
614*2d64210cSWojciech Zajac &setup_buf, sizeof(setup_buf));
615*2d64210cSWojciech Zajac
616*2d64210cSWojciech Zajac /* Send and wait for response */
617*2d64210cSWojciech Zajac if (blocking_urb_submit(&urb, hub_sem, URB_SUBMIT_CHECK_LEN)) {
618*2d64210cSWojciech Zajac HUB_MSG("Submitting HUB URB failed");
619*2d64210cSWojciech Zajac return EXIT_FAILURE;
620*2d64210cSWojciech Zajac } else {
621*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PortFeature operation completed");
622*2d64210cSWojciech Zajac return EXIT_SUCCESS;
623*2d64210cSWojciech Zajac }
624*2d64210cSWojciech Zajac }
625*2d64210cSWojciech Zajac
626*2d64210cSWojciech Zajac
627*2d64210cSWojciech Zajac /*===========================================================================*
628*2d64210cSWojciech Zajac * hub_get_port_status *
629*2d64210cSWojciech Zajac *===========================================================================*/
630*2d64210cSWojciech Zajac static int
hub_get_port_status(int port_num,hub_port_status * p)631*2d64210cSWojciech Zajac hub_get_port_status(int port_num, hub_port_status * p)
632*2d64210cSWojciech Zajac {
633*2d64210cSWojciech Zajac /* URB to be send */
634*2d64210cSWojciech Zajac struct ddekit_usb_urb urb;
635*2d64210cSWojciech Zajac
636*2d64210cSWojciech Zajac /* Setup buffer to be attached */
637*2d64210cSWojciech Zajac struct usb_ctrlrequest setup_buf;
638*2d64210cSWojciech Zajac
639*2d64210cSWojciech Zajac /* Control EP configuration */
640*2d64210cSWojciech Zajac urb_ep_config ep_conf;
641*2d64210cSWojciech Zajac
642*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
643*2d64210cSWojciech Zajac
644*2d64210cSWojciech Zajac if (!((port_num <= driver_state.num_ports) && (port_num > 0)))
645*2d64210cSWojciech Zajac return EXIT_FAILURE;
646*2d64210cSWojciech Zajac
647*2d64210cSWojciech Zajac /* Initialize EP configuration */
648*2d64210cSWojciech Zajac ep_conf.ep_num = 0;
649*2d64210cSWojciech Zajac ep_conf.direction = DDEKIT_USB_IN;
650*2d64210cSWojciech Zajac ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
651*2d64210cSWojciech Zajac ep_conf.max_packet_size = 0;
652*2d64210cSWojciech Zajac ep_conf.interval = 0;
653*2d64210cSWojciech Zajac
654*2d64210cSWojciech Zajac /* Reset URB and assign given values */
655*2d64210cSWojciech Zajac init_urb(&urb, driver_state.dev, &ep_conf);
656*2d64210cSWojciech Zajac
657*2d64210cSWojciech Zajac /* Clear setup data */
658*2d64210cSWojciech Zajac memset(&setup_buf, 0, sizeof(setup_buf));
659*2d64210cSWojciech Zajac
660*2d64210cSWojciech Zajac /* Standard get endpoint request */
661*2d64210cSWojciech Zajac setup_buf.bRequestType = 0xA3;
662*2d64210cSWojciech Zajac setup_buf.bRequest = (u8_t)GET_STATUS;
663*2d64210cSWojciech Zajac setup_buf.wValue = 0x00;
664*2d64210cSWojciech Zajac setup_buf.wIndex = (u16_t)port_num;
665*2d64210cSWojciech Zajac setup_buf.wLength = sizeof(*p);
666*2d64210cSWojciech Zajac
667*2d64210cSWojciech Zajac /* Attach buffers to URB */
668*2d64210cSWojciech Zajac attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
669*2d64210cSWojciech Zajac &setup_buf, sizeof(setup_buf));
670*2d64210cSWojciech Zajac attach_urb_data(&urb, URB_BUF_TYPE_DATA,
671*2d64210cSWojciech Zajac p, sizeof(*p));
672*2d64210cSWojciech Zajac
673*2d64210cSWojciech Zajac /* Send and wait for response */
674*2d64210cSWojciech Zajac if (blocking_urb_submit(&urb, hub_sem, URB_SUBMIT_CHECK_LEN)) {
675*2d64210cSWojciech Zajac HUB_MSG("Submitting HUB URB failed");
676*2d64210cSWojciech Zajac return EXIT_FAILURE;
677*2d64210cSWojciech Zajac } else {
678*2d64210cSWojciech Zajac HUB_DEBUG_MSG("Port%d status: ", port_num);
679*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_CONNECTION %01X", p->PORT_CONNECTION);
680*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_ENABLE %01X", p->PORT_ENABLE);
681*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_POWER %01X", p->PORT_POWER);
682*2d64210cSWojciech Zajac HUB_DEBUG_MSG("C_PORT_CONNECTION %01X", p->C_PORT_CONNECTION);
683*2d64210cSWojciech Zajac HUB_DEBUG_MSG("C_PORT_ENABLE %01X", p->C_PORT_ENABLE);
684*2d64210cSWojciech Zajac return EXIT_SUCCESS;
685*2d64210cSWojciech Zajac }
686*2d64210cSWojciech Zajac }
687*2d64210cSWojciech Zajac
688*2d64210cSWojciech Zajac
689*2d64210cSWojciech Zajac /*===========================================================================*
690*2d64210cSWojciech Zajac * hub_handle_change *
691*2d64210cSWojciech Zajac *===========================================================================*/
692*2d64210cSWojciech Zajac static port_change
hub_handle_change(int port_num,hub_port_status * status)693*2d64210cSWojciech Zajac hub_handle_change(int port_num, hub_port_status * status)
694*2d64210cSWojciech Zajac {
695*2d64210cSWojciech Zajac port_conn * c;
696*2d64210cSWojciech Zajac
697*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
698*2d64210cSWojciech Zajac
699*2d64210cSWojciech Zajac /* Possible combinations: */
700*2d64210cSWojciech Zajac /* Change = status->C_PORT_CONNECTION (hub connection change bit)
701*2d64210cSWojciech Zajac * Local = driver_state.conn[port_num] (local connection status)
702*2d64210cSWojciech Zajac * Remote = status->PORT_CONNECTION (hub connection status) */
703*2d64210cSWojciech Zajac /*
704*2d64210cSWojciech Zajac Case Change Local Remote Description
705*2d64210cSWojciech Zajac 1. 1 1 1 Polling mismatch (quick disconn-conn)
706*2d64210cSWojciech Zajac 2. 1 1 0 Just disconnected
707*2d64210cSWojciech Zajac 3. 1 0 1 Just connected
708*2d64210cSWojciech Zajac 4. 1 0 0 Polling mismatch (quick conn-disconn)
709*2d64210cSWojciech Zajac 5. 0 1 1 Still connected
710*2d64210cSWojciech Zajac 6. 0 1 0 Serious ERROR
711*2d64210cSWojciech Zajac 7. 0 0 1 Serious ERROR
712*2d64210cSWojciech Zajac 8. 0 0 0 Still disconnected
713*2d64210cSWojciech Zajac */
714*2d64210cSWojciech Zajac
715*2d64210cSWojciech Zajac /* Reassign for code cleanliness */
716*2d64210cSWojciech Zajac c = driver_state.conn;
717*2d64210cSWojciech Zajac
718*2d64210cSWojciech Zajac /* Resolve combination */
719*2d64210cSWojciech Zajac if (status->C_PORT_CONNECTION) {
720*2d64210cSWojciech Zajac
721*2d64210cSWojciech Zajac /* C_PORT_CONNECTION was set, so clear change bit
722*2d64210cSWojciech Zajac * to allow further polling */
723*2d64210cSWojciech Zajac if (hub_port_feature(port_num, CLEAR_FEATURE,
724*2d64210cSWojciech Zajac C_PORT_CONNECTION)) {
725*2d64210cSWojciech Zajac HUB_MSG("Clearing port%d change bit failed", port_num);
726*2d64210cSWojciech Zajac return HUB_CHANGE_COM_ERR;
727*2d64210cSWojciech Zajac }
728*2d64210cSWojciech Zajac
729*2d64210cSWojciech Zajac if (HUB_PORT_CONN == c[port_num]) {
730*2d64210cSWojciech Zajac if (status->PORT_CONNECTION) {
731*2d64210cSWojciech Zajac
732*2d64210cSWojciech Zajac /*
733*2d64210cSWojciech Zajac * 1
734*2d64210cSWojciech Zajac */
735*2d64210cSWojciech Zajac /* Make hub disconnect and connect again */
736*2d64210cSWojciech Zajac if (hub_handle_disconnection(port_num) ||
737*2d64210cSWojciech Zajac hub_handle_connection(port_num, status))
738*2d64210cSWojciech Zajac return HUB_CHANGE_STATUS_ERR;
739*2d64210cSWojciech Zajac else
740*2d64210cSWojciech Zajac return HUB_CHANGE_CONN;
741*2d64210cSWojciech Zajac
742*2d64210cSWojciech Zajac } else {
743*2d64210cSWojciech Zajac
744*2d64210cSWojciech Zajac /*
745*2d64210cSWojciech Zajac * 2
746*2d64210cSWojciech Zajac */
747*2d64210cSWojciech Zajac /* Handle disconnection */
748*2d64210cSWojciech Zajac if (hub_handle_disconnection(port_num))
749*2d64210cSWojciech Zajac return HUB_CHANGE_STATUS_ERR;
750*2d64210cSWojciech Zajac else
751*2d64210cSWojciech Zajac return HUB_CHANGE_DISCONN;
752*2d64210cSWojciech Zajac
753*2d64210cSWojciech Zajac }
754*2d64210cSWojciech Zajac } else if (HUB_PORT_DISCONN == c[port_num]) {
755*2d64210cSWojciech Zajac if (status->PORT_CONNECTION) {
756*2d64210cSWojciech Zajac
757*2d64210cSWojciech Zajac /*
758*2d64210cSWojciech Zajac * 3
759*2d64210cSWojciech Zajac */
760*2d64210cSWojciech Zajac /* Handle connection */
761*2d64210cSWojciech Zajac if (hub_handle_connection(port_num, status))
762*2d64210cSWojciech Zajac return HUB_CHANGE_STATUS_ERR;
763*2d64210cSWojciech Zajac else
764*2d64210cSWojciech Zajac return HUB_CHANGE_CONN;
765*2d64210cSWojciech Zajac
766*2d64210cSWojciech Zajac } else {
767*2d64210cSWojciech Zajac
768*2d64210cSWojciech Zajac /*
769*2d64210cSWojciech Zajac * 4
770*2d64210cSWojciech Zajac */
771*2d64210cSWojciech Zajac /* Since we were disconnected before and
772*2d64210cSWojciech Zajac * are disconnected now, additional handling
773*2d64210cSWojciech Zajac * may be ignored */
774*2d64210cSWojciech Zajac return HUB_CHANGE_NONE;
775*2d64210cSWojciech Zajac
776*2d64210cSWojciech Zajac }
777*2d64210cSWojciech Zajac }
778*2d64210cSWojciech Zajac } else {
779*2d64210cSWojciech Zajac if (HUB_PORT_CONN == c[port_num]) {
780*2d64210cSWojciech Zajac if (status->PORT_CONNECTION) {
781*2d64210cSWojciech Zajac
782*2d64210cSWojciech Zajac /*
783*2d64210cSWojciech Zajac * 5
784*2d64210cSWojciech Zajac */
785*2d64210cSWojciech Zajac /* Connected (nothing changed) */
786*2d64210cSWojciech Zajac return HUB_CHANGE_NONE;
787*2d64210cSWojciech Zajac
788*2d64210cSWojciech Zajac } else {
789*2d64210cSWojciech Zajac
790*2d64210cSWojciech Zajac /*
791*2d64210cSWojciech Zajac * 6
792*2d64210cSWojciech Zajac */
793*2d64210cSWojciech Zajac /* Serious status error */
794*2d64210cSWojciech Zajac return HUB_CHANGE_STATUS_ERR;
795*2d64210cSWojciech Zajac
796*2d64210cSWojciech Zajac }
797*2d64210cSWojciech Zajac } else if (HUB_PORT_DISCONN == c[port_num]) {
798*2d64210cSWojciech Zajac if (status->PORT_CONNECTION) {
799*2d64210cSWojciech Zajac
800*2d64210cSWojciech Zajac /*
801*2d64210cSWojciech Zajac * 7
802*2d64210cSWojciech Zajac */
803*2d64210cSWojciech Zajac /* Serious status error */
804*2d64210cSWojciech Zajac return HUB_CHANGE_STATUS_ERR;
805*2d64210cSWojciech Zajac
806*2d64210cSWojciech Zajac } else {
807*2d64210cSWojciech Zajac
808*2d64210cSWojciech Zajac /*
809*2d64210cSWojciech Zajac * 8
810*2d64210cSWojciech Zajac */
811*2d64210cSWojciech Zajac /* Disconnected (nothing changed) */
812*2d64210cSWojciech Zajac return HUB_CHANGE_NONE;
813*2d64210cSWojciech Zajac
814*2d64210cSWojciech Zajac }
815*2d64210cSWojciech Zajac }
816*2d64210cSWojciech Zajac }
817*2d64210cSWojciech Zajac
818*2d64210cSWojciech Zajac return HUB_CHANGE_COM_ERR;
819*2d64210cSWojciech Zajac }
820*2d64210cSWojciech Zajac
821*2d64210cSWojciech Zajac
822*2d64210cSWojciech Zajac /*===========================================================================*
823*2d64210cSWojciech Zajac * hub_handle_connection *
824*2d64210cSWojciech Zajac *===========================================================================*/
825*2d64210cSWojciech Zajac static int
hub_handle_connection(int port_num,hub_port_status * status)826*2d64210cSWojciech Zajac hub_handle_connection(int port_num, hub_port_status * status)
827*2d64210cSWojciech Zajac {
828*2d64210cSWojciech Zajac struct timespec wait_time;
829*2d64210cSWojciech Zajac int reset_tries;
830*2d64210cSWojciech Zajac long port_speed;
831*2d64210cSWojciech Zajac
832*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
833*2d64210cSWojciech Zajac
834*2d64210cSWojciech Zajac HUB_MSG("Device connected to port%d", port_num);
835*2d64210cSWojciech Zajac
836*2d64210cSWojciech Zajac /* This should never happen if power-off works as intended */
837*2d64210cSWojciech Zajac if (status->C_PORT_RESET) {
838*2d64210cSWojciech Zajac HUB_MSG("Unexpected reset state for port%d", port_num);
839*2d64210cSWojciech Zajac return EXIT_FAILURE;
840*2d64210cSWojciech Zajac }
841*2d64210cSWojciech Zajac
842*2d64210cSWojciech Zajac /* Start reset signaling for this port */
843*2d64210cSWojciech Zajac if (hub_port_feature(port_num, SET_FEATURE, PORT_RESET)) {
844*2d64210cSWojciech Zajac HUB_MSG("Resetting port%d failed", port_num);
845*2d64210cSWojciech Zajac return EXIT_FAILURE;
846*2d64210cSWojciech Zajac }
847*2d64210cSWojciech Zajac
848*2d64210cSWojciech Zajac reset_tries = 0;
849*2d64210cSWojciech Zajac wait_time.tv_sec = 0;
850*2d64210cSWojciech Zajac wait_time.tv_nsec = USB_HUB_RESET_DELAY;
851*2d64210cSWojciech Zajac
852*2d64210cSWojciech Zajac /* Wait for reset completion */
853*2d64210cSWojciech Zajac while (!status->C_PORT_RESET) {
854*2d64210cSWojciech Zajac /* To avoid endless loop */
855*2d64210cSWojciech Zajac if (reset_tries >= USB_HUB_MAX_TRIES) {
856*2d64210cSWojciech Zajac HUB_MSG("Port%d reset took too long", port_num);
857*2d64210cSWojciech Zajac return EXIT_FAILURE;
858*2d64210cSWojciech Zajac }
859*2d64210cSWojciech Zajac
860*2d64210cSWojciech Zajac /* Get port status again */
861*2d64210cSWojciech Zajac if (hub_get_port_status(port_num, status)) {
862*2d64210cSWojciech Zajac HUB_MSG("Reading port%d status failed", port_num);
863*2d64210cSWojciech Zajac return EXIT_FAILURE;
864*2d64210cSWojciech Zajac }
865*2d64210cSWojciech Zajac
866*2d64210cSWojciech Zajac reset_tries++;
867*2d64210cSWojciech Zajac
868*2d64210cSWojciech Zajac /* Ignore potential signal interruption (no return value check),
869*2d64210cSWojciech Zajac * since it causes driver termination anyway */
870*2d64210cSWojciech Zajac if (nanosleep(&wait_time, NULL))
871*2d64210cSWojciech Zajac HUB_MSG("Calling nanosleep() failed");
872*2d64210cSWojciech Zajac }
873*2d64210cSWojciech Zajac
874*2d64210cSWojciech Zajac /* Reset completed */
875*2d64210cSWojciech Zajac HUB_DEBUG_MSG("Port%d reset complete", port_num);
876*2d64210cSWojciech Zajac
877*2d64210cSWojciech Zajac /* Dump full status for analysis (high-speed, ...) */
878*2d64210cSWojciech Zajac HUB_DEBUG_MSG("C_PORT_CONNECTION %1X", status->C_PORT_CONNECTION );
879*2d64210cSWojciech Zajac HUB_DEBUG_MSG("C_PORT_ENABLE %1X", status->C_PORT_ENABLE );
880*2d64210cSWojciech Zajac HUB_DEBUG_MSG("C_PORT_OVER_CURRENT %1X", status->C_PORT_OVER_CURRENT);
881*2d64210cSWojciech Zajac HUB_DEBUG_MSG("C_PORT_RESET %1X", status->C_PORT_RESET );
882*2d64210cSWojciech Zajac HUB_DEBUG_MSG("C_PORT_SUSPEND %1X", status->C_PORT_SUSPEND );
883*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_CONNECTION %1X", status->PORT_CONNECTION );
884*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_ENABLE %1X", status->PORT_ENABLE );
885*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_HIGH_SPEED %1X", status->PORT_HIGH_SPEED );
886*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_INDICATOR %1X", status->PORT_INDICATOR );
887*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_LOW_SPEED %1X", status->PORT_LOW_SPEED );
888*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_OVER_CURRENT %1X", status->PORT_OVER_CURRENT );
889*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_POWER %1X", status->PORT_POWER );
890*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_RESET %1X", status->PORT_RESET );
891*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_SUSPEND %1X", status->PORT_SUSPEND );
892*2d64210cSWojciech Zajac HUB_DEBUG_MSG("PORT_TEST %1X", status->PORT_TEST );
893*2d64210cSWojciech Zajac
894*2d64210cSWojciech Zajac /* Clear reset change bit for further devices */
895*2d64210cSWojciech Zajac if (hub_port_feature(port_num, CLEAR_FEATURE, C_PORT_RESET)) {
896*2d64210cSWojciech Zajac HUB_MSG("Clearing port%d reset bit failed", port_num);
897*2d64210cSWojciech Zajac return EXIT_FAILURE;
898*2d64210cSWojciech Zajac }
899*2d64210cSWojciech Zajac
900*2d64210cSWojciech Zajac /* Should never happen */
901*2d64210cSWojciech Zajac if (!status->PORT_CONNECTION || !status->PORT_ENABLE) {
902*2d64210cSWojciech Zajac HUB_MSG("Port%d unexpectedly unavailable", port_num);
903*2d64210cSWojciech Zajac return EXIT_FAILURE;
904*2d64210cSWojciech Zajac }
905*2d64210cSWojciech Zajac
906*2d64210cSWojciech Zajac /* Determine port speed from status bits */
907*2d64210cSWojciech Zajac if (status->PORT_LOW_SPEED) {
908*2d64210cSWojciech Zajac if (status->PORT_HIGH_SPEED) {
909*2d64210cSWojciech Zajac HUB_MSG("Port%d has invalid speed flags", port_num);
910*2d64210cSWojciech Zajac return EXIT_FAILURE;
911*2d64210cSWojciech Zajac } else
912*2d64210cSWojciech Zajac port_speed = (long)DDEKIT_HUB_PORT_LS_CONN;
913*2d64210cSWojciech Zajac } else {
914*2d64210cSWojciech Zajac if (status->PORT_HIGH_SPEED)
915*2d64210cSWojciech Zajac port_speed = (long)DDEKIT_HUB_PORT_HS_CONN;
916*2d64210cSWojciech Zajac else
917*2d64210cSWojciech Zajac port_speed = (long)DDEKIT_HUB_PORT_FS_CONN;
918*2d64210cSWojciech Zajac }
919*2d64210cSWojciech Zajac
920*2d64210cSWojciech Zajac /* Signal to HCD that port has device connected at given speed */
921*2d64210cSWojciech Zajac return ddekit_usb_info(driver_state.dev, port_speed, (long)port_num);
922*2d64210cSWojciech Zajac }
923*2d64210cSWojciech Zajac
924*2d64210cSWojciech Zajac
925*2d64210cSWojciech Zajac /*===========================================================================*
926*2d64210cSWojciech Zajac * hub_handle_disconnection *
927*2d64210cSWojciech Zajac *===========================================================================*/
928*2d64210cSWojciech Zajac static int
hub_handle_disconnection(int port_num)929*2d64210cSWojciech Zajac hub_handle_disconnection(int port_num)
930*2d64210cSWojciech Zajac {
931*2d64210cSWojciech Zajac HUB_DEBUG_DUMP;
932*2d64210cSWojciech Zajac
933*2d64210cSWojciech Zajac HUB_MSG("Device disconnected from port%d", port_num);
934*2d64210cSWojciech Zajac
935*2d64210cSWojciech Zajac return ddekit_usb_info(driver_state.dev, (long)DDEKIT_HUB_PORT_DISCONN,
936*2d64210cSWojciech Zajac (long)port_num);
937*2d64210cSWojciech Zajac }
938