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 CDC ACM driver
15 * @see USB CDC specification and CDC PSTN subclass specification
16 */
17#include <stdio.h>
18#include <string.h>
19
20#include <utils/circular_buffer.h>
21#include <platsupport/sync/atomic.h>
22#include "../services.h"
23#include "cdc.h"
24
25/*
26 * XXX: In theory the maximum xact size can be up to 20K, however, our DMA
27 * allocator cannot handle that large allocation at the moment.
28 */
29#define CDC_READ_XACT_SIZE  128
30#define CDC_READ_BUFFER_SIZE 4096
31
32static const char *subclass_codes[] = {
33	"Reserved",
34	"Direct Line Control Model",
35	"Abstract Control Model",
36	"Telephone Control Model",
37	"Multi-Channel Control Model",
38	"CAPI Control Model",
39	"Ethernet Networking Control Model",
40	"ATM Networking Control Model",
41	"Wireless Handset Control Model",
42	"Device Management",
43	"Mobile Direct Line Model",
44	"OBEX",
45	"Ethernet Emulation Mode",
46	"Mobile Broadband Interface Model"
47};
48
49static const char *func_subtype_codes[] = {
50	"Header Functional",
51	"Call Management Functional",
52	"Abstract Control Management Functional",
53	"Direct Line Management Functional",
54	"Telephone Ringer Functional",
55	"Telephone Call and Line State Reporting Capabilities Functional",
56	"Union Functional",
57	"Country Selection Functional",
58	"Telephone Operational Modes Functional",
59	"USB Terminal Functional",
60	"Network Channel Terminal",
61	"Protocol Unit Functional",
62	"Extension Unit Functional",
63	"Multi-Channel Management Functional",
64	"CAPI Control Management Functional",
65	"Ethernet Networking Functional",
66	"ATM Networking Functional",
67	"Wireless Handset Control Model Functional",
68	"Mobile Direct Line Model Functional",
69	"MDLM Detail Functional",
70	"Device Management Model Functional",
71	"OBEX Functional",
72	"Command Set Functional",
73	"Command Set Detail Functional",
74	"Telephone Control Model Functional",
75	"OBEX Service Identifier Functional",
76	"NCM Functional",
77	"MBIM Functional",
78	"MBIM Extended Functional",
79	"RESERVED (future use)",
80	"RESERVED (vendor specific)"
81};
82
83/* CDC device interface class */
84enum usb_cdc_inf_class {
85	INF_COMM = 0x2,  //Communication Interface Class
86	INF_DATA = 0xA   //Data Interface Class
87};
88
89/* USB Communication Device */
90struct usb_cdc_device {
91	struct usb_dev *udev;	 //The handle to the underlying USB device
92	uint8_t subclass;        //Subclass code
93	uint8_t config;          //Active configuration
94	uint8_t comm;            //Communication interface index
95	uint8_t data;            //Data interface index
96	struct endpoint *ep_int; //Interrupt endpoint
97	struct endpoint *ep_in;	 //BULK in endpoint
98	struct endpoint *ep_out; //BULK out endpoint
99	struct xact read_xact;   //Current read request
100	circ_buf_t read_buf;     //Read buffer
101	int read_in_progress;
102};
103
104static int
105usb_cdc_config_cb(void *token, int cfg, int iface, struct anon_desc *desc)
106{
107	struct usb_cdc_device *cdc;
108	struct config_desc *cdesc;
109	struct iface_desc *idesc;
110	struct func_desc *fdesc;
111
112	if (!desc) {
113		return 0;
114	}
115
116	cdc = (struct usb_cdc_device *)token;
117
118	switch (desc->bDescriptorType) {
119	case CONFIGURATION:
120		cdesc = (struct config_desc*)desc;
121		cdc->config = cdesc->bConfigurationValue;
122		break;
123	case INTERFACE:
124		idesc = (struct iface_desc *)desc;
125		cdc->udev->class = idesc->bInterfaceClass;
126		cdc->subclass = idesc->bInterfaceSubClass;
127		if (cdc->udev->class == INF_COMM && cdc->subclass < 0xd) {
128			cdc->comm = idesc->bInterfaceNumber;
129			ZF_LOGD("Communication Interface\n");
130			if (cdc->subclass < 0xd) {
131				ZF_LOGD("  |-- %s\n", subclass_codes[cdc->subclass]);
132			}
133		} else if (cdc->udev->class == INF_DATA) {
134			cdc->data = idesc->bInterfaceNumber;
135			ZF_LOGD("Data Interface\n");
136		}
137		break;
138	case CS_INTERFACE:
139		fdesc = (struct func_desc *)desc;
140		if (fdesc->bDescriptorSubtype < 0x1d) {
141			ZF_LOGD("  %s\n",
142					func_subtype_codes[fdesc->bDescriptorSubtype]);
143		} else {
144			ZF_LOGD("  Function type reserved(%x)\n",
145					fdesc->bDescriptorSubtype);
146		}
147		break;
148	default:
149		break;
150	}
151
152	return 0;
153}
154
155static int usb_cdc_read_cb(void *token, enum usb_xact_status stat, int rbytes)
156{
157	struct usb_dev *udev;
158	struct usb_cdc_device *cdc;
159	char *buf;
160
161	udev = (struct usb_dev*)token;
162	cdc = (struct usb_cdc_device*)udev->dev_data;
163
164	if (stat == XACTSTAT_SUCCESS) {
165		buf = (char*)xact_get_vaddr(&cdc->read_xact);
166		for (int i = 0; i < CDC_READ_XACT_SIZE - rbytes; i++) {
167			if (!circ_buf_is_full(&cdc->read_buf)) {
168				circ_buf_put(&cdc->read_buf, buf[i]);
169			} else {
170				break;
171			}
172		}
173	}
174
175	sync_atomic_decrement(&cdc->read_in_progress, __ATOMIC_RELAXED);
176
177	return 0;
178}
179
180int usb_cdc_bind(usb_dev_t *udev)
181{
182	int err;
183	struct usb_cdc_device *cdc;
184	struct xact xact;
185	struct usbreq *req;
186	int class;
187
188	if (!udev) {
189		ZF_LOGF("Invalid device\n");
190	}
191
192	cdc = usb_malloc(sizeof(struct usb_cdc_device));
193	if (!cdc) {
194		ZF_LOGD("Not enough memory!\n");
195		return -1;
196	}
197
198	cdc->udev = udev;
199	udev->dev_data = (struct udev_priv*)cdc;
200
201	/* Parse the descriptors */
202	err = usbdev_parse_config(udev, usb_cdc_config_cb, cdc);
203	if (err) {
204		ZF_LOGF("Invalid descriptors\n");
205	}
206
207	/* Find endpoints */
208	for (int i = 0; udev->ep[i] != NULL; i++) {
209		if (udev->ep[i]->type == EP_BULK) {
210			if (udev->ep[i]->dir == EP_DIR_OUT) {
211				cdc->ep_out = udev->ep[i];
212			} else {
213				cdc->ep_in = udev->ep[i];
214			}
215		} else if (udev->ep[i]->type == EP_INTERRUPT) {
216			cdc->ep_int = udev->ep[i];
217		} else {
218			continue;
219		}
220	}
221
222	char *buf = usb_malloc(CDC_READ_BUFFER_SIZE);
223	if (!buf) {
224		ZF_LOGD("Failed to allocate circular buffer!\n");
225		usb_free(cdc);
226		return -1;
227	}
228
229	err = circ_buf_new(buf, CDC_READ_BUFFER_SIZE, &cdc->read_buf);
230	if (err) {
231		ZF_LOGD("Failed to allocate circular buffer!\n");
232		usb_free(buf);
233		usb_free(cdc);
234		return -1;
235	}
236
237	class = usbdev_get_class(udev);
238	if (class != USB_CLASS_CDCDATA && class != USB_CLASS_COMM) {
239		ZF_LOGD("Not a CDC device(%d)\n", class);
240		circ_buf_free(&cdc->read_buf);
241		usb_free(buf);
242		usb_free(cdc);
243		return -1;
244	}
245
246	ZF_LOGD("USB CDC found, subclass(%x)\n", cdc->subclass);
247
248	/* Allocate read request */
249	cdc->read_xact.type = PID_IN;
250	cdc->read_xact.len = CDC_READ_XACT_SIZE;
251	err = usb_alloc_xact(udev->dman, &cdc->read_xact, 1);
252	if (err) {
253		ZF_LOGF("Out of DMA memory\n");
254	}
255	cdc->read_in_progress = 0;
256
257	/* Activate configuration */
258	xact.len = sizeof(struct usbreq);
259	err = usb_alloc_xact(udev->dman, &xact, 1);
260	if (err) {
261		ZF_LOGF("Out of DMA memory\n");
262	}
263
264	/* Fill in the request */
265	xact.type = PID_SETUP;
266	req = xact_get_vaddr(&xact);
267	*req = __set_configuration_req(cdc->config);
268
269	/* Send the request to the host */
270	err = usbdev_schedule_xact(udev, udev->ep_ctrl, &xact, 1, NULL, NULL);
271	if (err) {
272		ZF_LOGF("Transaction error\n");
273	}
274	usb_destroy_xact(udev->dman, &xact, 1);
275
276	return 0;
277}
278
279int usb_cdc_read(usb_dev_t *udev, void *buf, int len)
280{
281	int err;
282	int cnt = 0;
283	struct usb_cdc_device *cdc;
284
285	cdc = (struct usb_cdc_device*)udev->dev_data;
286
287	if (!cdc->read_in_progress) {
288		err = usbdev_schedule_xact(udev, cdc->ep_in, &cdc->read_xact, 1,
289				usb_cdc_read_cb, udev);
290		if (err) {
291			ZF_LOGF("Transaction error\n");
292		}
293		sync_atomic_increment(&cdc->read_in_progress, __ATOMIC_RELAXED);
294	}
295
296	/* Get data from the read buffer */
297	while (len--) {
298		if (!circ_buf_is_empty(&cdc->read_buf)) {
299			*((char*)buf + cnt) = circ_buf_get(&cdc->read_buf);
300			cnt++;
301		} else {
302			break;
303		}
304	}
305
306	return cnt;
307}
308
309int usb_cdc_write(usb_dev_t *udev, const void *buf, int len)
310{
311	int err;
312	int cnt;
313	int offset;
314	struct usb_cdc_device *cdc;
315	struct xact *xact;
316
317	cdc = (struct usb_cdc_device*)udev->dev_data;
318
319	/* Xact needs to be virtually contiguous */
320	cnt = ROUND_UP(len, MAX_XACT_SIZE) / MAX_XACT_SIZE;
321
322	xact = usb_malloc(sizeof(struct xact) * cnt);
323	if (!xact) {
324		ZF_LOGF("Out of memory\n");
325	}
326
327	/* Fill in the length of each xact */
328	for (int i = 0; i < cnt; i++) {
329		xact[i].type = PID_OUT;
330		xact[i].len = len < MAX_XACT_SIZE ? len : MAX_XACT_SIZE;
331		len -= xact[i].len;
332	}
333
334	/* DMA allocation */
335	err = usb_alloc_xact(udev->dman, xact, cnt);
336	if (err) {
337		ZF_LOGF("Out of DMA memory\n");
338	}
339
340	/* Copy in */
341	offset = 0;
342	for (int i = 0; i < cnt; i++) {
343		memcpy(xact_get_vaddr(&xact[i]), (char*)buf + offset, xact[i].len);
344		offset += xact[i].len;
345	}
346
347	/* Send to the host */
348	err = usbdev_schedule_xact(udev, cdc->ep_out, xact, cnt, NULL, NULL);
349	if (err) {
350		ZF_LOGF("Transaction error\n");
351	}
352
353	/* Cleanup */
354	usb_destroy_xact(udev->dman, xact, cnt);
355
356	usb_free(xact);
357
358	return len;
359}
360
361static void
362usb_cdc_mgmt_msg(struct usb_cdc_device *cdc, uint8_t req_type,
363		enum cdc_req_code code, int value, void *buf, int len)
364{
365	int err;
366	struct usbreq *req;
367	struct xact msg[2];
368	int cnt;
369
370	/* Allocate xact */
371	msg[0].len = sizeof(struct usbreq);
372	msg[1].len = len;
373	err = usb_alloc_xact(cdc->udev->dman, msg, 2);
374	if (err) {
375		ZF_LOGF("Out of DMA memory\n");
376	}
377
378	/* Management element request */
379	msg[0].type = PID_SETUP;
380	req = xact_get_vaddr(&msg[0]);
381	req->bmRequestType = req_type;
382	req->bRequest = code;
383	req->wValue = value;
384	req->wIndex = cdc->comm;
385	req->wLength = len;
386	cnt = 1;
387
388	/* Data stage */
389	if (len > 0) {
390		if (req_type & USB_DIR_IN) {
391			msg[1].type = PID_IN;
392		} else {
393			msg[1].type = PID_OUT;
394		}
395		memcpy(xact_get_vaddr(&msg[1]), buf, len);
396		cnt++;
397	}
398
399	/* Send to the host */
400	err = usbdev_schedule_xact(cdc->udev, cdc->udev->ep_ctrl,
401			msg, cnt, NULL, NULL);
402
403	/* Copy out */
404	if (len > 0 && msg[1].type == PID_IN) {
405		memcpy(xact_get_vaddr(&msg[1]), buf, len);
406	}
407
408	/* Cleanup */
409	usb_destroy_xact(cdc->udev->dman, msg, 2);
410}
411
412/* Communication Device Class Requests */
413void cdc_send_encap_cmd(usb_dev_t *udev, const void *buf, int len)
414{
415	struct usb_cdc_device *cdc = (struct usb_cdc_device*)udev->dev_data;
416
417	usb_cdc_mgmt_msg(cdc, USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE,
418			SEND_ENCAPSULATED_COMMAND, 0, (void*)buf, len);
419}
420
421void cdc_get_encap_resp(usb_dev_t *udev, void *buf, int len)
422{
423	struct usb_cdc_device *cdc = (struct usb_cdc_device*)udev->dev_data;
424
425	usb_cdc_mgmt_msg(cdc, USB_DIR_IN | USB_TYPE_CLS | USB_RCPT_INTERFACE,
426			GET_ENCAPSULATED_RESPONSE, 0, buf, len);
427}
428
429/* PSTN - Abstract Control Model Requests */
430void acm_set_comm_feature(usb_dev_t *udev, enum acm_comm_feature f,
431		uint16_t state)
432{
433	struct usb_cdc_device *cdc = (struct usb_cdc_device*)udev->dev_data;
434
435	usb_cdc_mgmt_msg(cdc, USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE,
436			SET_COMM_FEATURE, f, &state, 2);
437}
438
439uint16_t acm_get_comm_feature(usb_dev_t *udev, enum acm_comm_feature f)
440{
441	uint16_t state;
442	struct usb_cdc_device *cdc = (struct usb_cdc_device*)udev->dev_data;
443
444	usb_cdc_mgmt_msg(cdc, USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE,
445			GET_COMM_FEATURE, f, &state, 2);
446	return state;
447}
448
449void acm_clear_comm_feature(usb_dev_t *udev, enum acm_comm_feature f)
450{
451	struct usb_cdc_device *cdc = (struct usb_cdc_device*)udev->dev_data;
452
453	usb_cdc_mgmt_msg(cdc, USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE,
454			CLEAR_COMM_FEATURE, f, NULL, 0);
455}
456
457void acm_set_line_coding(usb_dev_t *udev, const struct acm_line_coding *coding)
458{
459	struct usb_cdc_device *cdc = (struct usb_cdc_device*)udev->dev_data;
460
461	usb_cdc_mgmt_msg(cdc, USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE,
462			SET_LINE_CODING, 0, (struct acm_line_coding*)coding,
463			sizeof(*coding));
464}
465
466void acm_get_line_coding(usb_dev_t *udev, struct acm_line_coding *coding)
467{
468	struct usb_cdc_device *cdc = (struct usb_cdc_device*)udev->dev_data;
469
470	usb_cdc_mgmt_msg(cdc, USB_DIR_IN | USB_TYPE_CLS | USB_RCPT_INTERFACE,
471			GET_LINE_CODING, 0, coding, sizeof(*coding));
472}
473
474void acm_set_ctrl_line_state(usb_dev_t *udev, uint8_t ctrl)
475{
476	struct usb_cdc_device *cdc = (struct usb_cdc_device*)udev->dev_data;
477
478	usb_cdc_mgmt_msg(cdc, USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE,
479			SET_CONTROL_LINE_STATE, ctrl, NULL, 0);
480}
481
482void acm_send_break(usb_dev_t *udev, uint16_t us)
483{
484	struct usb_cdc_device *cdc = (struct usb_cdc_device*)udev->dev_data;
485
486	usb_cdc_mgmt_msg(cdc, USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE,
487			SEND_BREAK, us, NULL, 0);
488}
489
490