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 Prolific PL2303 USB to Serial adaptor
15 * @see http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=232&pcid=41
16 */
17#include <stdio.h>
18#include <string.h>
19
20#include <usb/drivers/pl2303.h>
21#include "../services.h"
22
23#define PL2303_VENDOR_REQ  0x01
24#define PL2303_READ_TYPE   (USB_DIR_IN | USB_TYPE_VEN | USB_RCPT_DEVICE)
25#define PL2303_WRITE_TYPE  (USB_DIR_OUT | USB_TYPE_VEN | USB_RCPT_DEVICE)
26
27#define PL2303_SET_LINE_REQ 0x20
28#define PL2303_SET_CTRL_REQ 0x22
29#define PL2303_SET_REQ_TYPE 0x21
30
31#define PL2303_GET_LINE_REQ 0x21
32#define PL2303_GET_REQ_TYEP 0xA1
33
34#define PL2303_CTRL_DTR     0x01
35#define PL2303_CTRL_RTS     0x01
36
37/* PL2303 USB to Serial Converter */
38struct pl2303_device {
39	struct usb_dev *udev;	 //The handle to the underlying USB device
40	uint8_t config;          //Active configuration
41	struct endpoint *ep_int; //Interrupt endpoint
42	struct endpoint *ep_in;	 //BULK in endpoint
43	struct endpoint *ep_out; //BULK out endpoint
44	struct xact int_xact;    //Interrupt xact
45};
46
47static int
48pl2303_config_cb(void *token, int cfg, int iface, struct anon_desc *desc)
49{
50	struct pl2303_device *dev;
51	struct config_desc *cdesc;
52
53	if (!desc) {
54		return 0;
55	}
56
57	dev = (struct pl2303_device*)token;
58
59	switch (desc->bDescriptorType) {
60	case CONFIGURATION:
61		cdesc = (struct config_desc*)desc;
62		dev->config = cdesc->bConfigurationValue;
63		break;
64	default:
65		break;
66	}
67
68	return 0;
69}
70
71static int
72pl2303_interrupt_cb(void* token, enum usb_xact_status stat, int rbytes)
73{
74	int err;
75	struct pl2303_device *dev;
76	struct usb_dev *udev;
77
78	udev = (struct usb_dev*)token;
79	dev = (struct pl2303_device*)udev->dev_data;
80
81	/* Queue another request */
82	err = usbdev_schedule_xact(udev, dev->ep_int, &dev->int_xact, 1,
83			pl2303_interrupt_cb, udev);
84	if (err) {
85		ZF_LOGF("Transaction error\n");
86	}
87
88	return err;
89}
90
91static void
92pl2303_startup_magic(struct usb_dev *udev)
93{
94	int err;
95	struct xact xact[2];
96	struct usbreq *req;
97
98	if (!udev) {
99		ZF_LOGF("Invalid device\n");
100	}
101
102	xact[0].len = sizeof(struct usbreq);
103	xact[1].len = 1;
104	err = usb_alloc_xact(udev->dman, xact, 2);
105	if (err) {
106		ZF_LOGF("Out of DMA memory\n");
107	}
108
109	/* Fill in the request */
110	xact[0].type = PID_SETUP;
111	xact[1].type = PID_IN;
112	req = xact_get_vaddr(&xact[0]);
113
114	/*
115	 * Send Prolific private initial data.
116	 *
117	 * It is found by sniffing the official windows driver.
118	 */
119	req->bRequest = PL2303_VENDOR_REQ;
120
121#define magic_request(typ, idx, val) \
122	req->bmRequestType = typ; \
123	req->wIndex = idx; \
124	req->wValue = val; \
125	req->wLength = (typ == PL2303_READ_TYPE) ? 1 : 0; \
126	err = usbdev_schedule_xact(udev, udev->ep_ctrl, xact, \
127			req->wLength + 1, NULL, NULL); \
128
129	magic_request(PL2303_READ_TYPE, 0, 0x8484);
130	magic_request(PL2303_WRITE_TYPE, 0, 0x0404);
131	magic_request(PL2303_READ_TYPE, 0, 0x8484);
132	magic_request(PL2303_READ_TYPE, 0, 0x8383);
133	magic_request(PL2303_READ_TYPE, 0, 0x8484);
134	magic_request(PL2303_WRITE_TYPE, 1, 0x0404);
135	magic_request(PL2303_READ_TYPE, 0, 0x8484);
136	magic_request(PL2303_READ_TYPE, 0, 0x8383);
137	magic_request(PL2303_WRITE_TYPE, 1, 0);
138	magic_request(PL2303_WRITE_TYPE, 0, 1);
139	magic_request(PL2303_WRITE_TYPE, 0x44, 2);
140
141	usb_destroy_xact(udev->dman, xact, 2);
142}
143
144int usb_pl2303_bind(usb_dev_t *udev)
145{
146	int err;
147	struct pl2303_device *dev;
148	struct xact xact;
149	struct usbreq *req;
150
151	if (!udev) {
152		ZF_LOGF("Invalid device\n");
153	}
154
155	dev = usb_malloc(sizeof(struct pl2303_device));
156	if (!dev) {
157		ZF_LOGD("Not enough memory!\n");
158		return -1;
159	}
160
161	dev->udev = udev;
162	udev->dev_data = (struct udev_priv*)dev;
163
164	/* Parse the descriptors */
165	err = usbdev_parse_config(udev, pl2303_config_cb, dev);
166	if (err) {
167		ZF_LOGF("Invalid descriptors\n");
168	}
169
170	/* Find endpoints */
171	for (int i = 0; udev->ep[i] != NULL; i++) {
172		if (udev->ep[i]->type == EP_BULK) {
173			if (udev->ep[i]->dir == EP_DIR_OUT) {
174				dev->ep_out = udev->ep[i];
175			} else {
176				dev->ep_in = udev->ep[i];
177			}
178		} else if (udev->ep[i]->type == EP_INTERRUPT) {
179			dev->ep_int = udev->ep[i];
180		} else {
181			continue;
182		}
183	}
184
185	if (udev->vend_id != 0x067b || udev->prod_id != 0x2303) {
186		ZF_LOGD("Not a PL2303 device(%u:%u)\n",
187				udev->vend_id, udev->prod_id);
188		return -1;
189	}
190
191	ZF_LOGD("Found PL2303 USB to serial converter!\n");
192
193	/* Activate configuration */
194	xact.len = sizeof(struct usbreq);
195	err = usb_alloc_xact(udev->dman, &xact, 1);
196	if (err) {
197		ZF_LOGF("Out of DMA memory\n");
198	}
199
200	/* Fill in the request */
201	xact.type = PID_SETUP;
202	req = xact_get_vaddr(&xact);
203	*req = __set_configuration_req(dev->config);
204
205	/* Send the request to the host */
206	err = usbdev_schedule_xact(udev, udev->ep_ctrl, &xact, 1, NULL, NULL);
207	if (err) {
208		ZF_LOGF("Transaction error\n");
209	}
210	usb_destroy_xact(udev->dman, &xact, 1);
211
212	pl2303_startup_magic(udev);
213
214	/* Allocate interrupt xact */
215	dev->int_xact.type = PID_IN;
216	dev->int_xact.len = dev->ep_int->max_pkt;
217	err = usb_alloc_xact(udev->dman, &dev->int_xact, 1);
218	if (err) {
219		ZF_LOGF("Out of DMA memory\n");
220	}
221
222	/* Schedule a interrupt request */
223	err = usbdev_schedule_xact(udev, dev->ep_int, &dev->int_xact, 1,
224			pl2303_interrupt_cb, udev);
225	if (err) {
226		ZF_LOGF("Transaction error\n");
227	}
228
229	return 0;
230}
231
232int usb_pl2303_configure(usb_dev_t *udev, uint32_t bps, uint8_t char_size,
233		enum serial_parity parity, uint8_t stop)
234{
235	int err;
236	struct xact xact[2];
237	struct usbreq *req;
238	char *buf;
239
240	xact[0].len = sizeof(struct usbreq);
241	xact[1].len = 7;
242	err = usb_alloc_xact(udev->dman, xact, 2);
243	if (err) {
244		ZF_LOGF("Out of DMA memory\n");
245	}
246
247	xact[0].type = PID_SETUP;
248	xact[1].type = PID_OUT;
249	req = xact_get_vaddr(&xact[0]);
250	buf = xact_get_vaddr(&xact[1]);
251
252	/* Data bits */
253	buf[6] = char_size;
254
255	/*
256	 * Set parity
257	 * 0 -- none, 1 -- odd, 2-- even, 3 -- mark, 4 -- space
258	 */
259	switch (parity) {
260		case PARITY_NONE:
261			buf[5] = 0;
262			break;
263		case PARITY_ODD:
264			buf[5] = 1;
265			break;
266		case PARITY_EVEN:
267			buf[5] = 2;
268			break;
269		default:
270			ZF_LOGD("Unsupported parity!\n");
271			break;
272	}
273
274	/* 0 -- 1 stop bits, 1 -- 1.5 stop bits, 2 -- 2 stop bits */
275	buf[4] = stop;
276
277	/* Set baudrate */
278	buf[3] = bps & 0xFF;
279	buf[2] = (bps >> 16) & 0xFF;
280	buf[1] = (bps >> 8) & 0xFF;
281	buf[0] = bps & 0xFF000000;
282
283	/* Send configuration */
284	req->bmRequestType = PL2303_SET_REQ_TYPE;
285	req->bRequest = PL2303_SET_LINE_REQ;
286	req->wIndex = 0;
287	req->wLength = 7;
288	req->wValue = 0;
289
290	err = usbdev_schedule_xact(udev, udev->ep_ctrl, xact, 2, NULL, NULL);
291	if (err) {
292		ZF_LOGF("Transaction error\n");
293	}
294
295	/* Activate device */
296	req->bmRequestType = PL2303_SET_REQ_TYPE;
297	req->bRequest = PL2303_SET_CTRL_REQ;
298	req->wIndex = 0;
299	req->wLength = 0;
300	req->wValue = PL2303_CTRL_DTR | PL2303_CTRL_RTS;
301
302	err = usbdev_schedule_xact(udev, udev->ep_ctrl, xact, 1, NULL, NULL);
303	if (err) {
304		ZF_LOGF("Transaction error\n");
305	}
306
307	usb_destroy_xact(udev->dman, xact, 2);
308
309	return 0;
310}
311
312/* TODO: Remove the 20K limitation */
313int usb_pl2303_write(usb_dev_t *udev, void *buf, int len)
314{
315	int err;
316	struct pl2303_device *dev;
317	struct xact xact;
318
319	dev = (struct pl2303_device*)udev->dev_data;
320
321	xact.type = PID_OUT;
322	xact.len = len;
323	err = usb_alloc_xact(udev->dman, &xact, 1);
324	if (err) {
325		ZF_LOGF("Out of DMA memory\n");
326	}
327
328	memcpy(xact_get_vaddr(&xact), buf, len);
329
330	err = usbdev_schedule_xact(udev, dev->ep_out, &xact, 1, NULL, NULL);
331	if (err) {
332		ZF_LOGF("Transaction error\n");
333	}
334
335	usb_destroy_xact(udev->dman, &xact, 1);
336
337	return len - err;
338}
339
340/* TODO: Remove the 20K limitation and possible babble */
341int usb_pl2303_read(usb_dev_t *udev, void *buf, int len)
342{
343	int err;
344	struct pl2303_device *dev;
345	struct xact xact;
346
347	dev = (struct pl2303_device*)udev->dev_data;
348
349	xact.type = PID_IN;
350	xact.len = len;
351	err = usb_alloc_xact(udev->dman, &xact, 1);
352	if (err) {
353		ZF_LOGF("Out of DMA memory\n");
354	}
355
356	err = usbdev_schedule_xact(udev, dev->ep_in, &xact, 1, NULL, NULL);
357	if (err) {
358		ZF_LOGF("Transaction error\n");
359	}
360
361	memcpy(buf, xact_get_vaddr(&xact), len);
362
363	usb_destroy_xact(udev->dman, &xact, 1);
364
365	return len - err;
366}
367
368