1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13/**
14 * @brief USB hub driver
15 * @see USB 2.0 spec, Chapter 11
16 */
17#include "usbhub.h"
18
19#include <stdio.h>
20#include <string.h>
21
22#include <utils/util.h>
23
24#include "../services.h"
25
26#define HUBINT_RATE_MS 100
27
28#define HUB_ENABLE_IRQS
29
30/*** USB spec chapter 11 page 262 ***/
31
32struct hub_desc {
33/// Number of bytes in this descriptor, including this byte.
34	uint8_t bDescLength;
35/// Descriptor Type, value: 0x29 for Hub Descriptor.
36#define DESCRIPTOR_TYPE_HUB 0x29
37	uint8_t bDescriptorType;
38/// Number of downstream ports that this hub supports.
39	uint8_t bNbrPorts;
40/// Hub characteristics.
41#define HUBCHAR_POWER_SWITCH_SINGLE BIT(0)
42#define HUBCHAR_POWER_SWITCH_NONE   BIT(1)
43#define HUBCHAR_COMPOUND_DEVICE     BIT(2)
44#define HUBCHAR_OVER_CURRENT_SINGLE BIT(3)
45#define HUBCHAR_OVER_CURRENT_NONE   BIT(4)
46	uint16_t wHubCharacteristics;
47/// Time (in 2ms intervals) until power is stable after child port power on
48	uint8_t bPwrOn2PwrGood;
49/// Maximum current requirements of the hub controller
50	uint8_t bHubContrCurrent;
51	/* The size of the remaining fields depends on the number of ports
52	 * Bit x will correspond to port x
53	 * DeviceRemovable bitmap: 1-not removable.
54	 * PortPwrCtrlMask bitmap: 1-requires manual power on (not ganged).
55	 */
56	uint8_t portcfg[64];
57} __attribute__ ((packed));
58
59/****************
60 *** FEATURES ***
61 ****************/
62static inline struct usbreq
63__clear_port_feature_req(uint16_t port, uint16_t feature)
64{
65	struct usbreq r = {
66		.bmRequestType = (USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_OTHER),
67		.bRequest = CLR_FEATURE,
68		.wValue = feature,
69		.wIndex = port,
70		.wLength = 0
71	};
72	return r;
73}
74
75static inline struct usbreq __clear_hub_feature_req(uint16_t feature)
76{
77	struct usbreq r = {
78		.bmRequestType = (USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_DEVICE),
79		.bRequest = CLR_FEATURE,
80		.wValue = feature,
81		.wIndex = 0,
82		.wLength = 0
83	};
84	return r;
85}
86
87static inline struct usbreq
88__set_port_feature_req(uint16_t port, uint16_t feature)
89{
90	struct usbreq r = {
91		.bmRequestType = (USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_OTHER),
92		.bRequest = SET_FEATURE,
93		.wValue = feature,
94		.wIndex = port,
95		.wLength = 0
96	};
97	return r;
98}
99
100static inline struct usbreq __set_hub_feature_req(uint16_t feature)
101{
102	struct usbreq r = {
103		.bmRequestType = (USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_DEVICE),
104		.bRequest = SET_FEATURE,
105		.wValue = feature,
106		.wIndex = 0,
107		.wLength = 0
108	};
109	return r;
110}
111
112static inline struct usbreq __get_port_status_req(uint16_t port)
113{
114	struct usbreq r = {
115		.bmRequestType = (USB_DIR_IN | USB_TYPE_CLS | USB_RCPT_OTHER),
116		.bRequest = GET_STATUS,
117		.wValue = 0,
118		.wIndex = port,
119		.wLength = 4
120	};
121	return r;
122}
123
124static inline struct usbreq __get_hub_status_req(void)
125{
126	struct usbreq r = {
127		.bmRequestType = (USB_DIR_IN | USB_TYPE_CLS | USB_RCPT_DEVICE),
128		.bRequest = GET_STATUS,
129		.wValue = 0,
130		.wIndex = 0,
131		.wLength = 4
132	};
133	return r;
134}
135
136static inline struct usbreq __get_hub_descriptor_req(void)
137{
138	struct usbreq r = {
139		.bmRequestType = (USB_DIR_IN | USB_TYPE_CLS | USB_RCPT_DEVICE),
140		.bRequest = GET_DESCRIPTOR,
141		.wValue = DESCRIPTOR_TYPE_HUB << 8,
142		.wIndex = 0,
143		.wLength = sizeof(struct hub_desc)
144	};
145	return r;
146}
147
148static inline struct usbreq __set_hub_descriptor_req(void)
149{
150	struct usbreq r = {
151		.bmRequestType = (USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_DEVICE),
152		.bRequest = SET_DESCRIPTOR,
153		.wValue = DESCRIPTOR_TYPE_HUB << 8,
154		.wIndex = 0,
155		.wLength = sizeof(struct hub_desc)
156	};
157	return r;
158}
159
160struct usb_hubem {
161	int hubem_nports;
162	int pwr_delay_ms;
163	int (*set_pf) (void *token, int port, enum port_feature feature);
164	int (*clr_pf) (void *token, int port, enum port_feature feature);
165	int (*get_pstat) (void *token, int port, struct port_status *ps);
166	void *token;
167};
168
169static void _handle_port_change(usb_hub_t h, int port)
170{
171	struct xact xact[2];
172	struct usbreq *req;
173	struct port_status *sts;
174	uint16_t change, status;
175	int ret;
176
177	if (!h) {
178		ZF_LOGF("Invalid HUB\n");
179	}
180
181	if (!port) {
182		ZF_LOGD("Error: check hub status!\n");
183		return;
184	}
185
186	ZF_LOGD("Handle status change of port %d\n", port);
187
188	/* Get port status change */
189	xact[0].type = PID_SETUP;
190	xact[0].len = sizeof(struct usbreq);
191	xact[1].type = PID_IN;
192	xact[1].len = sizeof(struct port_status);
193
194	ret = usb_alloc_xact(h->udev->dman, xact, 2);
195	if (ret) {
196		ZF_LOGF("Out of DMA memory\n");
197	}
198	req = xact_get_vaddr(&xact[0]);
199	sts = xact_get_vaddr(&xact[1]);
200
201	*req = __get_port_status_req(port);
202	ret = usbdev_schedule_xact(h->udev, h->udev->ep_ctrl,
203				   xact, 2, NULL, NULL);
204	if (ret < 0) {
205		ZF_LOGF("Transaction error\n");
206	}
207
208	/* Cache the port status, because we need to clear it right away. */
209	change = sts->wPortChange;
210	status = sts->wPortStatus;
211
212	ZF_LOGD("Status change (0x%x:0x%x) on port %d.\n",
213		change, status, port);
214
215	/* Attach and detach detect event */
216	if (change & BIT(PORT_CONNECTION)) {
217		/* Clear the port connection status */
218		*req = __clear_port_feature_req(port, C_PORT_CONNECTION);
219		ret = usbdev_schedule_xact(h->udev, h->udev->ep_ctrl,
220					   xact, 1, NULL, NULL);
221		if (ret < 0) {
222			ZF_LOGF("Transaction error\n");
223		}
224
225		if (status & BIT(PORT_CONNECTION)) {
226			ZF_LOGD("Port %d connected\n", port);
227			/* Wait for the device to stabilize, USB spec 9.1.2 */
228			ps_mdelay(100);
229
230			/* Enable the connection by resetting the port */
231			*req = __set_port_feature_req(port, PORT_RESET);
232			ret = usbdev_schedule_xact(h->udev, h->udev->ep_ctrl,
233						   xact, 1, NULL, NULL);
234			if (ret < 0) {
235				ZF_LOGF("Transaction error\n");
236			}
237
238			/*
239			 * Wait for the hub to exit the resetting state, refer
240			 * to USB spec 11.5.1.5
241			 * We also need to re-read the port status, it's updated
242			 * by the reset.
243			 */
244			*req = __get_port_status_req(port);
245			do {
246				ps_mdelay(10);
247				ret =
248				    usbdev_schedule_xact(h->udev,
249							 h->udev->ep_ctrl, xact,
250							 2, NULL, NULL);
251				if (ret < 0) {
252					ZF_LOGF("Transaction error\n");
253				}
254
255				status = sts->wPortStatus;
256			} while (status & BIT(PORT_RESET));
257
258			/* Reset finished, clear reset status */
259			*req = __clear_port_feature_req(port, C_PORT_RESET);
260			ret = usbdev_schedule_xact(h->udev, h->udev->ep_ctrl,
261						   xact, 1, NULL, NULL);
262			if (ret < 0) {
263				ZF_LOGF("Transaction error\n");
264			}
265
266			/* Create the new device */
267			enum usb_speed speed;
268			struct usb_dev *new_dev = NULL;
269			usb_hub_t new_hub = NULL;
270
271			if (status & BIT(PORT_HIGH_SPEED)) {
272				speed = USBSPEED_HIGH;
273			} else if (status & BIT(PORT_LOW_SPEED)) {
274				speed = USBSPEED_LOW;
275			} else {
276				speed = USBSPEED_FULL;
277			}
278
279			ret = usb_new_device(h->udev, port, speed, &new_dev);
280			if (ret < 0) {
281				*req = __set_port_feature_req(port, PORT_RESET);
282				ret =
283				    usbdev_schedule_xact(h->udev,
284							 h->udev->ep_ctrl, xact,
285							 1, NULL, NULL);
286				if (ret < 0) {
287					ZF_LOGF("Transaction error\n");
288				}
289				if (new_dev) {
290					usbdev_disconnect(new_dev);
291				}
292			} else {
293				h->port[port - 1].udev = new_dev;
294				usb_hub_driver_bind(new_dev, &new_hub);
295			}
296		} else {
297			ZF_LOGD("Port %d disconnected\n", port);
298			*req = __set_port_feature_req(port, PORT_SUSPEND);
299			ret = usbdev_schedule_xact(h->udev, h->udev->ep_ctrl,
300						   xact, 1, NULL, NULL);
301			if (ret < 0) {
302				ZF_LOGF("Transaction error\n");
303			}
304			if (h->port[port - 1].udev) {
305				usbdev_disconnect(h->port[port - 1].udev);
306				h->port[port - 1].udev = NULL;
307			}
308		}
309	}
310
311	/* Port enable */
312	if (change & BIT(PORT_ENABLE)) {
313		ZF_LOGD("Port %d enabled\n", port);
314		/* Clear the port connection status */
315		*req = __clear_port_feature_req(port, C_PORT_CONNECTION);
316		ret = usbdev_schedule_xact(h->udev, h->udev->ep_ctrl,
317					   xact, 1, NULL, NULL);
318		if (ret < 0) {
319			ZF_LOGF("Transaction error\n");
320		}
321	}
322
323	/* Port suspend */
324	if (change & BIT(PORT_SUSPEND)) {
325		ZF_LOGD("Port %d suspended\n", port);
326		/* Clear suspend status */
327		*req = __clear_port_feature_req(port, C_PORT_SUSPEND);
328		ret = usbdev_schedule_xact(h->udev, h->udev->ep_ctrl,
329					   xact, 1, NULL, NULL);
330		if (ret < 0) {
331			ZF_LOGF("Transaction error\n");
332		}
333	}
334
335	/* Port over-current */
336	if (change & BIT(PORT_OVER_CURRENT)) {
337		ZF_LOGD("Port %d over-current\n", port);
338		/* Clear over-current status */
339		*req = __clear_port_feature_req(port, C_PORT_OVER_CURRENT);
340		ret = usbdev_schedule_xact(h->udev, h->udev->ep_ctrl,
341					   xact, 1, NULL, NULL);
342		if (ret < 0) {
343			ZF_LOGF("Transaction error\n");
344		}
345	}
346
347	/* Port reset */
348	if (change & BIT(PORT_RESET)) {
349		ZF_LOGD("Port %d reset\n", port);
350		/* Clear reset status */
351		*req = __clear_port_feature_req(port, C_PORT_RESET);
352		ret = usbdev_schedule_xact(h->udev, h->udev->ep_ctrl,
353					   xact, 1, NULL, NULL);
354		if (ret < 0) {
355			ZF_LOGF("Transaction error\n");
356		}
357	}
358
359	usb_destroy_xact(h->udev->dman, xact, 2);
360}
361
362static int
363hub_irq_handler(void *token, enum usb_xact_status stat, int bytes_remaining)
364{
365	usb_hub_t h = (usb_hub_t) token;
366	int i, j;
367	int handled = 0;
368	uint8_t *intbm;
369	int len = h->int_xact.len - bytes_remaining;
370
371	/* Check the status */
372	if (stat != XACTSTAT_SUCCESS) {
373		ZF_LOGD("Received unsuccessful IRQ\n");
374		return 1;
375	}
376
377	ZF_LOGD("Handling IRQ\n");
378
379	intbm = h->intbm;
380	if (intbm != xact_get_vaddr(&h->int_xact)) {
381		ZF_LOGF("Invalid bitmap\n");
382	}
383	for (i = 0; i < len; i++) {
384		/* Check if any bits have changed */
385		if (intbm[i] == 0) {
386			continue;
387		}
388		/* Scan bitfield */
389		for (j = 0; j < 8; j++) {
390			if ((1 << j) & intbm[i]) {
391				int port = i * 8 + j;
392				_handle_port_change(h, port);
393				handled++;
394			}
395		}
396		intbm[i] = 0;
397	}
398	if (!handled) {
399		ZF_LOGD("Spurious IRQ\n");
400	}
401
402	usbdev_schedule_xact(h->udev, h->udev->ep[0],
403			     &h->int_xact, 1, &hub_irq_handler, h);
404	return 0;
405}
406
407static int hub_config_cb(void *token, int cfg, int iface, struct anon_desc *d)
408{
409	struct endpoint_desc *e;
410	usb_hub_t hub = (usb_hub_t)token;
411
412	if (!hub) {
413		ZF_LOGF("Invalid token\n");
414	}
415	if (d) {
416		switch (d->bDescriptorType) {
417		case ENDPOINT:
418			e = (struct endpoint_desc*)d;
419			/* We just take the first endpoint */
420			hub->int_ep = e->bEndpointAddress & 0xf;
421			hub->int_max_pkt = e->wMaxPacketSize;
422			hub->int_rate_ms = e->bInterval * 2;
423			hub->ifno = iface;
424			hub->cfgno = cfg;
425			break;
426		default:
427			/* Don't care */
428			break;
429		}
430		return 0;
431	} else {
432		return 0;
433	}
434}
435
436int usb_hub_driver_bind(usb_dev_t *udev, usb_hub_t *hub)
437{
438	usb_hub_t h;
439	struct usbreq *req;
440	struct hub_desc *hdesc;
441	struct xact xact[2];
442	int err;
443	int i;
444
445	/* Check the class */
446	if (usbdev_get_class(udev) != USB_CLASS_HUB) {
447		return -1;
448	}
449
450	/* Allocate memory */
451	h = (usb_hub_t) usb_malloc(sizeof(*h));
452	if (h == NULL) {
453		return -2;
454	}
455	memset(h, 0, sizeof(*h));
456	h->udev = udev;
457	udev->dev_data = (struct udev_priv *)h;
458
459	/* Get hub descriptor for nports and power delay */
460	ZF_LOGD("Get hub descriptor\n");
461	xact[0].type = PID_SETUP;
462	xact[0].len = sizeof(*req);
463	xact[1].type = PID_IN;
464	xact[1].len = sizeof(*hdesc);
465	err = usb_alloc_xact(udev->dman, xact, 2);
466	if (err) {
467		ZF_LOGF("Out of DMA memory\n");
468	}
469	req = xact_get_vaddr(&xact[0]);
470	*req = __get_hub_descriptor_req();
471	err = usbdev_schedule_xact(udev, h->udev->ep_ctrl, xact, 2, NULL, NULL);
472	if (err < 0) {
473		usb_destroy_xact(udev->dman, xact, 2);
474		usb_free(h);
475		h = NULL;
476		return -1;
477	}
478	hdesc = xact_get_vaddr(&xact[1]);
479	h->nports = hdesc->bNbrPorts;
480	h->power_good_delay_ms = hdesc->bPwrOn2PwrGood * 2;
481	usb_destroy_xact(udev->dman, xact, 2);
482	h->port = (struct usb_hub_port *)usb_malloc(sizeof(*h->port) * h->nports);
483	if (!h->port) {
484		ZF_LOGF("Out of memory\n");
485	}
486	memset(h->port, 0, sizeof(*h->port) * h->nports);
487	ZF_LOGD("Parsing config\n");
488	h->int_ep = -1;
489	err = usbdev_parse_config(h->udev, &hub_config_cb, h);
490	if (err || h->int_ep == -1) {
491		usb_free(h);
492		h = NULL;
493		return -1;
494	}
495	ZF_LOGD("Configure HUB\n");
496	xact[0].type = PID_SETUP;
497	xact[0].len = sizeof(*req);
498
499	err = usb_alloc_xact(h->udev->dman, xact, 1);
500	if (err) {
501		ZF_LOGE("Out of DMA memory\n");
502		return -1;
503	}
504	req = xact_get_vaddr(&xact[0]);
505	*req = __set_configuration_req(h->cfgno);
506
507	err = usbdev_schedule_xact(udev, h->udev->ep_ctrl, xact, 1, NULL, NULL);
508	if (err < 0) {
509		usb_destroy_xact(udev->dman, xact, 1);
510		usb_free(h);
511		h = NULL;
512		return -1;
513	}
514	usb_destroy_xact(udev->dman, xact, 1);
515
516	/* Power up ports */
517	xact[0].type = PID_SETUP;
518	xact[0].len = sizeof(*req);
519
520	usb_alloc_xact(h->udev->dman, xact, 1);
521	req = xact_get_vaddr(&xact[0]);
522	for (i = 1; i <= h->nports; i++) {
523		ZF_LOGD("Power on port %d\n", i);
524		*req = __set_port_feature_req(i, PORT_POWER);
525		err = usbdev_schedule_xact(h->udev, h->udev->ep_ctrl,
526					   xact, 1, NULL, NULL);
527		if (err < 0) {
528			ZF_LOGF("Transaction error\n");
529		}
530	}
531	ps_mdelay(h->power_good_delay_ms);
532	usb_destroy_xact(udev->dman, xact, 1);
533#if !defined(HUB_ENABLE_IRQS)
534	/* Setup ports */
535	for (i = 1; i <= h->nports; i++) {
536		_handle_port_change(h, i);
537	}
538#endif
539#if defined(HUB_ENABLE_IRQS)
540	h->int_xact.type = PID_IN;
541	/*
542	 * USB 2.0 spec[11.12.4] says the packet size should be (nport + 7)/8, but
543	 * some hubs are known to send more data, which would cause a "babble". So
544	 * we use maximum packet size instead, short packet does no harm.
545	 */
546	h->int_xact.len = h->int_max_pkt;
547	err = usb_alloc_xact(udev->dman, &h->int_xact, 1);
548	if (err) {
549		ZF_LOGF("Out of DMA memory\n");
550	}
551	h->intbm = xact_get_vaddr(&h->int_xact);
552	ZF_LOGD("Registering for INT\n");
553	/* FIXME: Search for the right ep */
554	usbdev_schedule_xact(udev, udev->ep[0],
555			     &h->int_xact, 1, &hub_irq_handler, h);
556#else
557	h->intbm = NULL;
558	h->int_xact.vaddr = NULL;
559	h->int_xact.paddr = 0;
560	h->int_xact.len = 0;
561	(void)hub_irq_handler;
562#endif
563	*hub = h;
564
565	return 0;
566}
567
568/*********************
569 *** Hub emulation ***
570 *********************/
571
572static struct device_desc _hub_device_desc = {
573	.bLength = sizeof(struct device_desc),
574	.bDescriptorType = DEVICE,
575	.bcdUSB = 0x200,
576	.bDeviceClass = USB_CLASS_HUB,
577	.bDeviceSubClass = 0,
578	.bDeviceProtocol = 2,
579	.bMaxPacketSize0 = 64,
580	.idVendor = 0xFEED,
581	.idProduct = 0xBEEF,
582	.bcdDevice = 1234,
583	.iManufacturer = 0,
584	.iProduct = 0,
585	.iSerialNumber = 0,
586	.bNumConfigurations = 1
587};
588
589static struct iface_desc _hub_iface_desc = {
590	.bLength = sizeof(_hub_iface_desc),
591	.bDescriptorType = INTERFACE,
592	.bInterfaceNumber = 0,
593	.bAlternateSetting = 0,
594	.bNumEndpoints = 1,
595	.bInterfaceClass = 9,
596	.bInterfaceSubClass = 0,
597	.bInterfaceProtocol = 1,
598	.iInterface = 0
599};
600
601static struct endpoint_desc _hub_endpoint_desc = {
602	.bLength = sizeof(_hub_endpoint_desc),
603	.bDescriptorType = ENDPOINT,
604	.bEndpointAddress = 0x81,
605	.bmAttributes = 0x3,
606	.wMaxPacketSize = 0x1,
607	.bInterval = 0xc
608};
609
610static struct config_desc _hub_config_desc = {
611	.bLength = sizeof(_hub_config_desc),
612	.bDescriptorType = CONFIGURATION,
613	.wTotalLength = sizeof(_hub_config_desc) +
614	    sizeof(_hub_iface_desc) + sizeof(_hub_endpoint_desc),
615	.bNumInterfaces = 1,
616	.bConfigurationValue = 1,
617	.iConfigurationIndex = 0,
618	.bmAttributes = (1 << 7),
619	.bMaxPower = 100 /*mA */  / 2
620};
621
622static struct hub_desc _hub_hub_desc = {
623	.bDescLength = 0x8,
624	.bDescriptorType = DESCRIPTOR_TYPE_HUB,
625	.bNbrPorts = 2,
626	.wHubCharacteristics = 0,
627	.bPwrOn2PwrGood = 0xff,
628	.bHubContrCurrent = 0,
629	.portcfg = {0}
630};
631
632static int
633hubem_get_descriptor(usb_hubem_t dev, struct usbreq *req, void *buf, int len)
634{
635	int act_len = 0;
636	int dtype = req->wValue >> 8;
637	switch (dtype) {
638	case DEVICE:{
639		struct device_desc *ret = (struct device_desc *)buf;
640		ZF_LOGD("Get device descriptor\n");
641		act_len = MIN(len, sizeof(*ret));
642		memcpy(ret, &_hub_device_desc, act_len);
643		return act_len;}
644	case DESCRIPTOR_TYPE_HUB:{
645		struct hub_desc *ret = (struct hub_desc *)buf;
646		int nregs = (dev->hubem_nports + 7) / 8;
647		int i;
648		ZF_LOGD("Get hub type descriptor\n");
649		_hub_hub_desc.bNbrPorts = dev->hubem_nports;
650		_hub_hub_desc.bPwrOn2PwrGood = dev->pwr_delay_ms / 2;
651		_hub_hub_desc.bDescLength = 7 + nregs * 2;
652		for (i = 0; i < nregs; i++) {
653			_hub_hub_desc.portcfg[i] = 0;
654			_hub_hub_desc.portcfg[i + nregs] = 0;
655		}
656		act_len = MIN(_hub_hub_desc.bDescLength, len);
657		memcpy(ret, &_hub_hub_desc, act_len);
658		return act_len;}
659	case CONFIGURATION:{
660		int cp_len;
661		int pos = 0;
662		int act_len;
663		ZF_LOGD("Get configuration descriptor\n");
664		act_len = MIN(_hub_config_desc.wTotalLength, len);
665		/* Copy the config */
666		cp_len = MIN(act_len - pos, _hub_config_desc.bLength);
667		memcpy(buf + pos, &_hub_config_desc, cp_len);
668		pos += cp_len;
669		/* Copy the iface */
670		cp_len = MIN(act_len - pos, _hub_iface_desc.bLength);
671		memcpy(buf + pos, &_hub_iface_desc, cp_len);
672		pos += cp_len;
673		/* copy the endpoint */
674		_hub_endpoint_desc.wMaxPacketSize =
675		    (dev->hubem_nports + 7) / 8;
676		cp_len = MIN(act_len - pos, _hub_endpoint_desc.bLength);
677		memcpy(buf + pos, &_hub_endpoint_desc, cp_len);
678		pos += cp_len;
679		if (pos != act_len) {
680			ZF_LOGF("Invalid descriptor\n");
681		}
682		return act_len;}
683	case INTERFACE:{
684		int act_len;
685		ZF_LOGD("Get interface descriptor\n");
686		act_len = MIN(_hub_iface_desc.bLength, len);
687		memcpy(buf, &_hub_iface_desc, act_len);
688		return act_len;}
689	case ENDPOINT:{
690		int act_len;
691		ZF_LOGD("Get endpoint descriptor\n");
692		act_len = MIN(_hub_endpoint_desc.bLength, len);
693		memcpy(buf, &_hub_endpoint_desc, act_len);
694		return act_len;}
695	case STRING:
696	case DEVICE_QUALIFIER:
697	case OTHER_SPEED_CONFIGURATION:
698	case INTERFACE_POWER:
699	default:
700		ZF_LOGD("Descriptor 0x%x not supported\n", dtype);
701		return -1;
702	}
703}
704
705static int hubem_feature(usb_hubem_t dev, struct usbreq *req)
706{
707	int f = req->wValue;
708	int p = req->wIndex;
709	void *t = dev->token;
710	int ret;
711	switch (req->bRequest) {
712	case SET_FEATURE:
713		ZF_LOGD("Set feature %d -> port %d\n", f, p);
714		return dev->set_pf(t, p, f);
715	case CLR_FEATURE:
716		ZF_LOGD("Clear feature %d -> port %d\n", f, p);
717		return dev->clr_pf(t, p, f);
718	default:
719		printf("Unsupported feature: %d\n", f);
720		return -1;
721	}
722	return ret;
723}
724
725static int
726hubem_get_status(usb_hubem_t dev, struct usbreq *req, void *buf, int len)
727{
728	int port = req->wIndex;
729	if (port == 0) {
730		/* Device status: self powered | remote wakeup */
731		uint16_t stat = 0;
732		int act_len;
733		ZF_LOGD("Get Status: Device status\n");
734		act_len = MIN(len, sizeof(stat));
735		memcpy(buf, &stat, act_len);
736		return act_len;
737	} else if (port <= dev->hubem_nports) {
738		/* Port status */
739		struct port_status *psts = (struct port_status *)buf;
740		int act_len = MIN(len, sizeof(*psts));
741		if (len < sizeof(*psts)) {
742			ZF_LOGF("Invalid port status\n");
743		}
744		if (dev->get_pstat(dev->token, port, psts)) {
745			ZF_LOGD
746			    ("Get Status: Failed to read status for port %d\n",
747			     port);
748			return -1;
749		} else {
750			ZF_LOGD("Get Status: Success s0x%x c0x%0x on port %d\n",
751			       psts->wPortStatus, psts->wPortChange, port);
752			return act_len;
753		}
754	} else {
755		ZF_LOGD("Get Status: Invalid port (%d/%d)\n", port,
756		       dev->hubem_nports);
757		return -1;
758	}
759}
760
761int
762hubem_process_xact(usb_hubem_t dev, struct xact *xact, int nxact,
763		   usb_cb_t cb, void *t)
764{
765	struct usbreq *req;
766	void *buf;
767	int buf_len;
768	int i;
769	int err;
770
771	for (err = 0, i = 0; !err && i < nxact; i++) {
772		if (xact[i].type != PID_SETUP) {
773			continue;
774		}
775		req = xact_get_vaddr(&xact[i]);
776		if (xact[i].len < sizeof(*req)) {
777			ZF_LOGF("Buffer too small\n");
778		}
779
780		if (i + 1 < nxact && xact[i + 1].type != PID_SETUP) {
781			buf = xact_get_vaddr(&xact[i + 1]);
782			buf_len = xact[i + 1].len;
783		} else {
784			buf = NULL;
785			buf_len = 0;
786		}
787		switch (req->bRequest) {
788		case GET_STATUS:
789			return hubem_get_status(dev, req, buf, buf_len);
790		case GET_DESCRIPTOR:
791			return hubem_get_descriptor(dev, req, buf, buf_len);
792		case SET_CONFIGURATION:
793			ZF_LOGD("Unhandled transaction: SET_CONFIGURATION\n");
794			break;
795		case SET_INTERFACE:
796			ZF_LOGD("Unhandled transaction: SET_INTERFACE\n");
797			break;
798		case SET_ADDRESS:
799			ZF_LOGD("Unhandled transaction: SET_ADDRESS\n");
800			break;
801		case CLR_FEATURE:
802		case SET_FEATURE:
803			err = hubem_feature(dev, req);
804			break;
805		default:
806			ZF_LOGE("Request code %d not supported\n",
807			       req->bRequest);
808		}
809	}
810	if (cb) {
811		if (err >= 0) {
812			cb(t, XACTSTAT_SUCCESS, err);
813		} else {
814			cb(t, XACTSTAT_ERROR, err);
815		}
816	}
817	return err;
818}
819
820int
821usb_hubem_driver_init(void *token, int nports, int pwr_delay_ms,
822		      int (*set_pf) (void *token, int port,
823				     enum port_feature feature),
824		      int (*clr_pf) (void *token, int port,
825				     enum port_feature feature),
826		      int (*get_pstat) (void *token, int port,
827					struct port_status *ps),
828		      usb_hubem_t *hub)
829{
830
831	usb_hubem_t h;
832	h = (usb_hubem_t) usb_malloc(sizeof(*h));
833	if (h == NULL) {
834		ZF_LOGE("Out of memory\n");
835		return -1;
836	}
837
838	h->token = token;
839	h->hubem_nports = nports;
840	h->pwr_delay_ms = pwr_delay_ms;
841	h->set_pf = set_pf;
842	h->clr_pf = clr_pf;
843	h->get_pstat = get_pstat;
844	*hub = h;
845	return 0;
846}
847