1/*
2 * Copyright 2022, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
4 */
5
6#include <sys/condvar.h>
7
8extern "C" {
9#include <sys/mutex.h>
10#include <sys/systm.h>
11#include <sys/taskqueue.h>
12#include <sys/priority.h>
13
14#include <dev/usb/usb.h>
15#include <dev/usb/usbdi.h>
16#include <dev/usb/usb_device.h>
17
18#include "device.h"
19}
20
21// undo name remappings, so we can use both FreeBSD and Haiku ones in this file
22#undef usb_device
23#undef usb_interface
24#undef usb_endpoint_descriptor
25
26#include <USB3.h>
27
28
29struct mtx sUSBLock;
30usb_module_info* sUSB = NULL;
31struct taskqueue* sUSBTaskqueue = NULL;
32
33
34status_t
35init_usb()
36{
37	if (sUSB != NULL)
38		return B_OK;
39
40	if (get_module(B_USB_MODULE_NAME, (module_info**)&sUSB) != B_OK) {
41		dprintf("cannot get module \"%s\"\n", B_USB_MODULE_NAME);
42		return B_ERROR;
43	}
44
45	mtx_init(&sUSBLock, "fbsd usb", NULL, MTX_DEF);
46	return B_OK;
47}
48
49
50void
51uninit_usb()
52{
53	if (sUSB == NULL)
54		return;
55
56	put_module(B_USB_MODULE_NAME);
57	if (sUSBTaskqueue != NULL)
58		taskqueue_free(sUSBTaskqueue);
59
60	sUSB = NULL;
61	sUSBTaskqueue = NULL;
62	mtx_destroy(&sUSBLock);
63}
64
65
66status_t
67get_next_usb_device(uint32* cookie, freebsd_usb_device* result)
68{
69	// We cheat here: since USB IDs are sequential, instead of doing a
70	// complicated parent/child iteration dance, we simply request device
71	// descriptors and let the USB stack figure out the rest.
72	//
73	// It would be better if we used USB->register_driver, but that is not
74	// an option at present for a variety of reasons...
75	const usb_configuration_info* config;
76	usb_device current;
77	while (*cookie < 1024) {
78		current = *cookie;
79		*cookie = *cookie + 1;
80
81		config = sUSB->get_configuration(current);
82		if (config != NULL)
83			break;
84	}
85	if (config == NULL)
86		return ENODEV;
87
88	result->haiku_usb_device = current;
89	result->endpoints_max = 0;
90	for (size_t i = 0; i < config->interface_count; i++) {
91		usb_interface_info* iface = config->interface[i].active;
92		if (iface == NULL)
93			continue;
94
95		for (size_t j = 0; j < iface->endpoint_count; j++) {
96			if (iface->endpoint[j].descr == NULL)
97				continue;
98
99			const int rep = result->endpoints_max++;
100			result->endpoints[rep].iface_index = i;
101
102			static_assert(sizeof(freebsd_usb_endpoint_descriptor)
103				== sizeof(usb_endpoint_descriptor), "size mismatch");
104
105			if (result->endpoints[rep].edesc == NULL)
106				result->endpoints[rep].edesc = new freebsd_usb_endpoint_descriptor;
107
108			memcpy(result->endpoints[rep].edesc, iface->endpoint[j].descr,
109				sizeof(usb_endpoint_descriptor));
110		}
111	}
112
113	return B_OK;
114}
115
116
117status_t
118get_usb_device_attach_arg(struct freebsd_usb_device* device, struct usb_attach_arg* uaa)
119{
120	memset(uaa, 0, sizeof(struct usb_attach_arg));
121
122	const usb_device_descriptor* device_desc =
123		sUSB->get_device_descriptor(device->haiku_usb_device);
124	if (device_desc == NULL)
125		return B_BAD_VALUE;
126
127	uaa->info.idVendor = device_desc->vendor_id;
128	uaa->info.idProduct = device_desc->product_id;
129	uaa->info.bcdDevice = device_desc->device_version;
130	uaa->info.bDeviceClass = device_desc->device_class;
131	uaa->info.bDeviceSubClass = device_desc->device_subclass;
132	uaa->info.bDeviceProtocol = device_desc->device_protocol;
133
134	const usb_configuration_info* config = sUSB->get_configuration(device->haiku_usb_device);
135	if (device_desc == NULL)
136		return B_BAD_VALUE;
137
138	// TODO: represent more than just interface[0], but how?
139	usb_interface_info* iface = config->interface[0].active;
140	if (iface == NULL)
141		return B_NO_INIT;
142
143	uaa->info.bInterfaceClass = iface->descr->interface_class;
144	uaa->info.bInterfaceSubClass = iface->descr->interface_subclass;
145	uaa->info.bInterfaceProtocol = iface->descr->interface_protocol;
146
147	// TODO: bIface{Index,Num}, bConfig{Index,Num}
148
149	uaa->device = device;
150	uaa->iface = NULL;
151
152	// TODO: fetch values for these?
153	uaa->usb_mode = USB_MODE_HOST;
154	uaa->port = 1;
155	uaa->dev_state = UAA_DEV_READY;
156
157	return B_OK;
158}
159
160
161void
162usb_cleanup_device(freebsd_usb_device* udev)
163{
164	for (int i = 0; i < USB_MAX_EP_UNITS; i++) {
165		delete udev->endpoints[i].edesc;
166		udev->endpoints[i].edesc = NULL;
167	}
168}
169
170
171static usb_error_t
172map_usb_error(status_t err)
173{
174	switch (err) {
175	case B_OK:			return USB_ERR_NORMAL_COMPLETION;
176	case B_DEV_STALLED:	return USB_ERR_STALLED;
177	case B_CANCELED:	return USB_ERR_CANCELLED;
178	case B_TIMED_OUT:	return USB_ERR_TIMEOUT;
179	}
180	return USB_ERR_INVAL;
181}
182
183
184extern "C" usb_error_t
185usbd_do_request_flags(struct freebsd_usb_device* udev, struct mtx* mtx,
186	struct usb_device_request* req, void* data, uint16_t flags,
187	uint16_t* actlen, usb_timeout_t timeout)
188{
189	if (mtx != NULL)
190		mtx_unlock(mtx);
191
192	// FIXME: timeouts
193	// TODO: flags
194
195	size_t actualLen = 0;
196	status_t ret = sUSB->send_request((usb_device)udev->haiku_usb_device,
197		req->bmRequestType, req->bRequest,
198		UGETW(req->wValue), UGETW(req->wIndex), UGETW(req->wLength),
199		data, &actualLen);
200	if (actlen)
201		*actlen = actualLen;
202
203	if (mtx != NULL)
204		mtx_lock(mtx);
205
206	return map_usb_error(ret);
207}
208
209
210enum usb_dev_speed
211usbd_get_speed(struct freebsd_usb_device* udev)
212{
213	const usb_device_descriptor* descriptor = sUSB->get_device_descriptor(
214		(usb_device)udev->haiku_usb_device);
215	KASSERT(descriptor != NULL, ("no device"));
216
217	if (descriptor->usb_version >= 0x0300)
218		return USB_SPEED_SUPER;
219	else if (descriptor->usb_version >= 0x200)
220		return USB_SPEED_HIGH;
221	else if (descriptor->usb_version >= 0x110)
222		return USB_SPEED_FULL;
223	else if (descriptor->usb_version >= 0x100)
224		return USB_SPEED_LOW;
225
226	panic("unknown USB version!");
227	return (usb_dev_speed)-1;
228}
229
230
231struct usb_page_cache {
232	void* buffer;
233	size_t length;
234};
235
236struct usb_xfer {
237	struct mtx* mutex;
238	void* priv_sc, *priv;
239	usb_callback_t* callback;
240	usb_xfer_flags flags;
241	usb_frlength_t max_data_length;
242
243	usb_device device;
244	uint8 type;
245	usb_pipe pipe;
246
247	iovec* frames;
248	usb_page_cache* buffers;
249	int max_frame_count, nframes;
250
251	uint8 usb_state;
252	bool in_progress;
253	status_t result;
254	int transferred_length;
255
256	struct task invoker;
257	struct cv condition;
258};
259
260
261extern "C" usb_error_t
262usbd_transfer_setup(struct freebsd_usb_device* udev,
263	const uint8_t* ifaces, struct usb_xfer** ppxfer,
264	const struct usb_config* setup_start, uint16_t n_setup,
265	void* priv_sc, struct mtx* xfer_mtx)
266{
267	if (xfer_mtx == NULL)
268		xfer_mtx = &Giant;
269
270	// Make sure the taskqueue exists.
271	if (sUSBTaskqueue == NULL) {
272		mtx_lock(&sUSBLock);
273		if (sUSBTaskqueue == NULL) {
274			sUSBTaskqueue = taskqueue_create("usb taskq", 0,
275				taskqueue_thread_enqueue, &sUSBTaskqueue);
276			taskqueue_start_threads(&sUSBTaskqueue, 1, PZERO, "usb taskq");
277		}
278		mtx_unlock(&sUSBLock);
279	}
280
281	const usb_configuration_info* device_config = sUSB->get_configuration(
282		(usb_device)udev->haiku_usb_device);
283
284	for (const struct usb_config* setup = setup_start;
285			setup < (setup_start + n_setup); setup++) {
286		/* skip transfers w/o callbacks */
287		if (setup->callback == NULL)
288			continue;
289
290		struct usb_xfer* xfer = new usb_xfer;
291		xfer->mutex = xfer_mtx;
292		xfer->priv_sc = priv_sc;
293		xfer->priv = NULL;
294		xfer->callback = setup->callback;
295		xfer->flags = setup->flags;
296		xfer->max_data_length = setup->bufsize;
297
298		xfer->device = (usb_device)udev->haiku_usb_device;
299		xfer->type = setup->type;
300
301		xfer->pipe = -1;
302		uint8_t endpoint = setup->endpoint;
303		uint8_t iface_index = ifaces[setup->if_index];
304		if (endpoint == UE_ADDR_ANY) {
305			for (int i = 0; i < udev->endpoints_max; i++) {
306				if (UE_GET_XFERTYPE(udev->endpoints[i].edesc->bmAttributes) != xfer->type)
307					continue;
308
309				endpoint = udev->endpoints[i].edesc->bEndpointAddress;
310				break;
311			}
312		}
313		usb_interface_info* iface = device_config->interface[iface_index].active;
314		for (int i = 0; i < iface->endpoint_count; i++) {
315			if (iface->endpoint[i].descr->endpoint_address != endpoint)
316				continue;
317
318			xfer->pipe = iface->endpoint[i].handle;
319			break;
320		}
321		if (xfer->pipe == -1)
322			panic("failed to locate endpoint!");
323
324		xfer->nframes = setup->frames;
325		if (xfer->nframes == 0)
326			xfer->nframes = 1;
327		xfer->max_frame_count = xfer->nframes;
328		xfer->frames = (iovec*)calloc(xfer->max_frame_count, sizeof(iovec));
329		xfer->buffers = NULL;
330
331		xfer->usb_state = USB_ST_SETUP;
332		xfer->in_progress = false;
333		xfer->transferred_length = 0;
334		cv_init(&xfer->condition, "FreeBSD USB transfer");
335
336		if (xfer->flags.proxy_buffer)
337			panic("not yet supported");
338
339		ppxfer[setup - setup_start] = xfer;
340	}
341
342	return USB_ERR_NORMAL_COMPLETION;
343}
344
345
346extern "C" void
347usbd_transfer_unsetup(struct usb_xfer** pxfer, uint16_t n_setup)
348{
349	for (int i = 0; i < n_setup; i++) {
350		struct usb_xfer* xfer = pxfer[i];
351		usbd_transfer_drain(xfer);
352		cv_destroy(&xfer->condition);
353
354		if (xfer->buffers != NULL) {
355			for (int i = 0; i < xfer->max_frame_count; i++)
356				free(xfer->buffers[i].buffer);
357			free(xfer->buffers);
358		}
359		free(xfer->frames);
360		delete xfer;
361	}
362}
363
364
365extern "C" usb_frlength_t
366usbd_xfer_max_len(struct usb_xfer* xfer)
367{
368	return xfer->max_data_length;
369}
370
371
372extern "C" void*
373usbd_xfer_softc(struct usb_xfer* xfer)
374{
375	return xfer->priv_sc;
376}
377
378
379extern "C" void*
380usbd_xfer_get_priv(struct usb_xfer* xfer)
381{
382	return xfer->priv;
383}
384
385
386extern "C" void
387usbd_xfer_set_priv(struct usb_xfer* xfer, void* ptr)
388{
389	xfer->priv = ptr;
390}
391
392
393extern "C" uint8_t
394usbd_xfer_state(struct usb_xfer* xfer)
395{
396	return xfer->usb_state;
397}
398
399
400extern "C" void
401usbd_xfer_set_frames(struct usb_xfer* xfer, usb_frcount_t n)
402{
403	KASSERT(n <= uint32_t(xfer->max_frame_count), ("frame index overflow"));
404	xfer->nframes = n;
405}
406
407
408extern "C" void
409usbd_xfer_set_frame_data(struct usb_xfer* xfer,
410	usb_frcount_t frindex, void* ptr, usb_frlength_t len)
411{
412	KASSERT(frindex < uint32_t(xfer->nframes), ("frame index overflow"));
413
414	xfer->frames[frindex].iov_base = ptr;
415	xfer->frames[frindex].iov_len = len;
416}
417
418
419extern "C" void
420usbd_xfer_set_frame_len(struct usb_xfer* xfer,
421	usb_frcount_t frindex, usb_frlength_t len)
422{
423	KASSERT(frindex < uint32_t(xfer->nframes), ("frame index overflow"));
424	KASSERT(len <= uint32_t(xfer->max_data_length), ("length overflow"));
425
426	// Trigger buffer allocation if necessary.
427	if (xfer->frames[frindex].iov_base == NULL)
428		usbd_xfer_get_frame(xfer, frindex);
429
430	xfer->frames[frindex].iov_len = len;
431}
432
433
434extern "C" struct usb_page_cache*
435usbd_xfer_get_frame(struct usb_xfer* xfer, usb_frcount_t frindex)
436{
437	KASSERT(frindex < uint32_t(xfer->max_frame_count), ("frame index overflow"));
438	if (xfer->buffers == NULL)
439		xfer->buffers = (usb_page_cache*)calloc(xfer->max_frame_count, sizeof(usb_page_cache));
440
441	usb_page_cache* cache = &xfer->buffers[frindex];
442	if (cache->buffer == NULL) {
443		cache->buffer = malloc(xfer->max_data_length);
444		cache->length = xfer->max_data_length;
445	}
446
447	xfer->frames[frindex].iov_base = cache->buffer;
448	return cache;
449}
450
451
452extern "C" void
453usbd_frame_zero(struct usb_page_cache* cache,
454	usb_frlength_t offset, usb_frlength_t len)
455{
456	KASSERT((offset + len) < uint32_t(cache->length), ("buffer overflow"));
457	memset((uint8*)cache->buffer + offset, 0, len);
458}
459
460
461extern "C" void
462usbd_copy_in(struct usb_page_cache* cache, usb_frlength_t offset,
463	const void *ptr, usb_frlength_t len)
464{
465	KASSERT((offset + len) < uint32_t(cache->length), ("buffer overflow"));
466	memcpy((uint8*)cache->buffer + offset, ptr, len);
467}
468
469
470extern "C" void
471usbd_copy_out(struct usb_page_cache* cache, usb_frlength_t offset,
472	void *ptr, usb_frlength_t len)
473{
474	KASSERT((offset + len) < uint32_t(cache->length), ("buffer overflow"));
475	memcpy(ptr, (uint8*)cache->buffer + offset, len);
476}
477
478
479extern "C" void
480usbd_m_copy_in(struct usb_page_cache* cache, usb_frlength_t dst_offset,
481	struct mbuf *m, usb_size_t src_offset, usb_frlength_t src_len)
482{
483	m_copydata(m, src_offset, src_len, (caddr_t)((uint8*)cache->buffer + dst_offset));
484}
485
486
487extern "C" void
488usbd_xfer_set_stall(struct usb_xfer *xfer)
489{
490	// Not needed?
491}
492
493
494static void
495usbd_invoker(void* arg, int pending)
496{
497	struct usb_xfer* xfer = (struct usb_xfer*)arg;
498	mtx_lock(xfer->mutex);
499	xfer->in_progress = false;
500	xfer->usb_state = (xfer->result == B_OK) ? USB_ST_TRANSFERRED : USB_ST_ERROR;
501	xfer->callback(xfer, map_usb_error(xfer->result));
502	mtx_unlock(xfer->mutex);
503	cv_signal(&xfer->condition);
504}
505
506
507static void
508usbd_callback(void* arg, status_t status, void* data, size_t actualLength)
509{
510	struct usb_xfer* xfer = (struct usb_xfer*)arg;
511	xfer->result = status;
512	xfer->transferred_length = actualLength;
513
514	TASK_INIT(&xfer->invoker, 0, usbd_invoker, xfer);
515	taskqueue_enqueue(sUSBTaskqueue, &xfer->invoker);
516}
517
518
519extern "C" void
520usbd_transfer_start(struct usb_xfer* xfer)
521{
522	if (xfer->in_progress)
523		return;
524
525	xfer->usb_state = USB_ST_SETUP;
526	xfer->callback(xfer, USB_ERR_NOT_STARTED);
527}
528
529
530extern "C" void
531usbd_transfer_submit(struct usb_xfer* xfer)
532{
533	KASSERT(!xfer->in_progress, ("cannot submit in-progress transfer!"));
534
535	xfer->transferred_length = 0;
536	xfer->in_progress = true;
537	status_t status = B_NOT_SUPPORTED;
538	switch (xfer->type) {
539	case UE_BULK:
540		status = sUSB->queue_bulk_v(xfer->pipe, xfer->frames, xfer->nframes, usbd_callback, xfer);
541		break;
542
543	case UE_INTERRUPT:
544		KASSERT(xfer->nframes == 1, ("invalid frame count for interrupt transfer"));
545		status = sUSB->queue_interrupt(xfer->pipe,
546			xfer->frames[0].iov_base, xfer->frames[0].iov_len,
547			usbd_callback, xfer);
548		break;
549
550	default:
551		panic("unhandled pipe type %d", xfer->type);
552	}
553
554	if (status != B_OK)
555		usbd_callback(xfer, status, NULL, 0);
556}
557
558
559extern "C" void
560usbd_transfer_stop(struct usb_xfer* xfer)
561{
562	if (xfer == NULL)
563		return;
564	mtx_assert(xfer->mutex, MA_OWNED);
565
566	if (!xfer->in_progress)
567		return;
568
569	// Unfortunately we have no way of cancelling just one transfer.
570	sUSB->cancel_queued_transfers(xfer->pipe);
571}
572
573
574extern "C" void
575usbd_transfer_drain(struct usb_xfer* xfer)
576{
577	if (xfer == NULL)
578		return;
579
580	mtx_lock(xfer->mutex);
581	usbd_transfer_stop(xfer);
582	while (xfer->in_progress)
583		cv_wait(&xfer->condition, xfer->mutex);
584	mtx_unlock(xfer->mutex);
585}
586
587
588extern "C" void
589usbd_xfer_status(struct usb_xfer* xfer, int* actlen, int* sumlen, int* aframes, int* nframes)
590{
591	if (actlen)
592		*actlen = xfer->transferred_length;
593	if (sumlen) {
594		int sum = 0;
595		for (int i = 0; i < xfer->nframes; i++)
596			sum += xfer->frames[i].iov_len;
597		*sumlen = sum;
598	}
599	if (aframes) {
600		int length = xfer->transferred_length;
601		int frames = 0;
602		for (int i = 0; i < xfer->nframes && length > 0; i++) {
603			length -= xfer->frames[i].iov_len;
604			if (length >= 0)
605				frames++;
606		}
607		*aframes = frames;
608	}
609	if (nframes)
610		*nframes = xfer->nframes;
611}
612