xref: /haiku/src/add-ons/kernel/drivers/ports/usb_serial/Prolific.cpp (revision 1294543de9ac0eff000eaea1b18368c36435d08e)
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 
10 ProlificDevice::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 
18 status_t
19 ProlificDevice::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_EP_ATTR_INTERRUPT) {
40 				if (endpoint->descr->endpoint_address & USB_EP_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_EP_ATTR_BULK) {
54 				if (endpoint->descr->endpoint_address & USB_EP_ADDR_DIR_IN) {
55 					SetReadPipe(endpoint->handle);
56 					if (++pipesSet >= 3)
57 						break;
58 				} else {
59 					SetWritePipe(endpoint->handle);
60 					if (++pipesSet >= 3)
61 						break;
62 				}
63 			}
64 		}
65 
66 		if (pipesSet >= 3)
67 			status = B_OK;
68 	}
69 
70 	TRACE_FUNCRET("< ProlificDevice::AddDevice() returns: 0x%08x\n", status);
71 	return status;
72 }
73 
74 
75 struct request_item {
76 	bool out;
77 	uint16 value;
78 	uint16 index;
79 };
80 
81 /* Linux sends all those, and it seems to work */
82 /* see drivers/usb/serial/pl2303.c */
83 static struct request_item prolific_reset_common[] = {
84 	{ false, 0x8484, 0 },
85 	{ true, 0x0404, 0 },
86 	{ false, 0x8484, 0 },
87 	{ false, 0x8383, 0 },
88 	{ false, 0x8484, 0 },
89 	{ true, 0x0404, 1 },
90 	{ false, 0x8484, 0 },
91 	{ false, 0x8383, 0 },
92 	{ true, 0x0000, 1 },
93 	{ true, 0x0001, 0 }
94 };
95 
96 static struct request_item prolific_reset_common_hx[] = {
97 	{ true, 2, 0x44 },
98 	{ true, 8, 0 },
99 	{ true, 0, 0 }
100 };
101 
102 static struct request_item prolific_reset_common_nhx[] = {
103 	{ true, 2, 0x24 }
104 };
105 
106 
107 status_t
108 ProlificDevice::SendRequestList(request_item *list, size_t length)
109 {
110 	for (size_t i = 0; i < length; i++) {
111 		char buffer[10];
112 		size_t bufferLength = 1;
113 		status_t status = gUSBModule->send_request(Device(),
114 			USB_REQTYPE_VENDOR | (list[i].out ? USB_REQTYPE_DEVICE_OUT : USB_REQTYPE_DEVICE_IN),
115 			PROLIFIC_SET_REQUEST,
116 			list[i].value,
117 			list[i].index,
118 			list[i].out ? 0 : bufferLength,
119 			list[i].out ? NULL : buffer,
120 			&bufferLength);
121 		TRACE(" ProlificDevice::SendRequestList(): request[%d]: 0x%08lx\n", i, status);
122 	}
123 
124 	return B_OK;
125 }
126 
127 
128 status_t
129 ProlificDevice::ResetDevice()
130 {
131 	TRACE_FUNCALLS("> ProlificDevice::ResetDevice(%08x)\n", this);
132 
133 	SendRequestList(prolific_reset_common, SIZEOF(prolific_reset_common));
134 	if (fIsHX)
135 		SendRequestList(prolific_reset_common_hx, SIZEOF(prolific_reset_common_hx));
136 	else
137 		SendRequestList(prolific_reset_common_nhx, SIZEOF(prolific_reset_common_nhx));
138 
139 	status_t status = B_OK; /* discard */
140 	TRACE_FUNCRET("< ProlificDevice::ResetDevice() returns: 0x%08x\n", status);
141 	return status;
142 }
143