1/*
2 * Copyright (c) 2007-2008 by Michael Lotz
3 * Heavily based on the original usb_serial driver which is:
4 *
5 * Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
6 * Distributed under the terms of the MIT License.
7 */
8#include "Prolific.h"
9
10ProlificDevice::ProlificDevice(usb_device device, uint16 vendorID,
11	uint16 productID, const char *description)
12	:	ACMDevice(device, vendorID, productID, description),
13		fIsHX(false)
14{
15}
16
17
18status_t
19ProlificDevice::AddDevice(const usb_configuration_info *config)
20{
21	TRACE_FUNCALLS("> ProlificDevice::AddDevice(%08x, %08x)\n", this, config);
22
23	// check for device type.
24	// Linux checks for type 0, 1 and HX, but handles 0 and 1 the same.
25	// We'll just check for HX then.
26	const usb_device_descriptor *deviceDescriptor = NULL;
27	deviceDescriptor = gUSBModule->get_device_descriptor(Device());
28	if (deviceDescriptor) {
29		fIsHX = (deviceDescriptor->device_class != 0x02
30			&& deviceDescriptor->max_packet_size_0 == 0x40);
31	}
32
33	int32 pipesSet = 0;
34	status_t status = ENODEV;
35	if (config->interface_count > 0) {
36		usb_interface_info *interface = config->interface[0].active;
37		for (size_t i = 0; i < interface->endpoint_count; i++) {
38			usb_endpoint_info *endpoint = &interface->endpoint[i];
39			if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_INTERRUPT) {
40				if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) {
41					SetControlPipe(endpoint->handle);
42					pipesSet++;
43				}
44			}
45		}
46
47		/* They say that USB-RSAQ1 has 2 interfaces */
48		if (config->interface_count >= 2)
49			interface = config->interface[1].active;
50
51		for (size_t i = 0; i < interface->endpoint_count; i++) {
52			usb_endpoint_info *endpoint = &interface->endpoint[i];
53			if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) {
54				if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
55					SetReadPipe(endpoint->handle);
56				else
57					SetWritePipe(endpoint->handle);
58
59				if (++pipesSet >= 3)
60					break;
61			}
62		}
63
64		if (pipesSet >= 3)
65			status = B_OK;
66	}
67
68	TRACE_FUNCRET("< ProlificDevice::AddDevice() returns: 0x%08x\n", status);
69	return status;
70}
71
72
73struct request_item {
74	bool out;
75	uint16 value;
76	uint16 index;
77};
78
79/* Linux sends all those, and it seems to work */
80/* see drivers/usb/serial/pl2303.c */
81static struct request_item prolific_reset_common[] = {
82	{ false, 0x8484, 0 },
83	{ true, 0x0404, 0 },
84	{ false, 0x8484, 0 },
85	{ false, 0x8383, 0 },
86	{ false, 0x8484, 0 },
87	{ true, 0x0404, 1 },
88	{ false, 0x8484, 0 },
89	{ false, 0x8383, 0 },
90	{ true, 0x0000, 1 },
91	{ true, 0x0001, 0 }
92};
93
94static struct request_item prolific_reset_common_hx[] = {
95	{ true, 2, 0x44 },
96	{ true, 8, 0 },
97	{ true, 0, 0 }
98};
99
100static struct request_item prolific_reset_common_nhx[] = {
101	{ true, 2, 0x24 }
102};
103
104
105status_t
106ProlificDevice::SendRequestList(request_item *list, size_t length)
107{
108	for (size_t i = 0; i < length; i++) {
109		char buffer[10];
110		size_t bufferLength = 1;
111		status_t status = gUSBModule->send_request(Device(),
112			USB_REQTYPE_VENDOR | (list[i].out ? USB_REQTYPE_DEVICE_OUT : USB_REQTYPE_DEVICE_IN),
113			PROLIFIC_SET_REQUEST,
114			list[i].value,
115			list[i].index,
116			list[i].out ? 0 : bufferLength,
117			list[i].out ? NULL : buffer,
118			&bufferLength);
119		TRACE(" ProlificDevice::SendRequestList(): request[%d]: 0x%08lx\n", i, status);
120		if (status != B_OK) {
121			TRACE_ALWAYS("sending request list failed:0x%08lx\n", status);
122		}
123	}
124
125	return B_OK;
126}
127
128
129status_t
130ProlificDevice::ResetDevice()
131{
132	TRACE_FUNCALLS("> ProlificDevice::ResetDevice(%08x)\n", this);
133
134	SendRequestList(prolific_reset_common, B_COUNT_OF(prolific_reset_common));
135	if (fIsHX)
136		SendRequestList(prolific_reset_common_hx, B_COUNT_OF(prolific_reset_common_hx));
137	else
138		SendRequestList(prolific_reset_common_nhx, B_COUNT_OF(prolific_reset_common_nhx));
139
140	status_t status = B_OK; /* discard */
141	TRACE_FUNCRET("< ProlificDevice::ResetDevice() returns: 0x%08x\n", status);
142	return status;
143}
144