xref: /minix3/minix/drivers/usb/usb_hub/usb_hub.c (revision 2d64210c1dbcd340904718f2d4e9e81adeab3c7d)
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