xref: /haiku/src/add-ons/kernel/drivers/ports/usb_serial/Prolific.cpp (revision 57bc65034a7781d7bb53a48f94d692346b641da1)
17aa661d4SMichael Lotz /*
27aa661d4SMichael Lotz  * Copyright (c) 2007-2008 by Michael Lotz
37aa661d4SMichael Lotz  * Heavily based on the original usb_serial driver which is:
47aa661d4SMichael Lotz  *
57aa661d4SMichael Lotz  * Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li>
67aa661d4SMichael Lotz  * Distributed under the terms of the MIT License.
77aa661d4SMichael Lotz  */
87aa661d4SMichael Lotz #include "Prolific.h"
97aa661d4SMichael Lotz 
ProlificDevice(usb_device device,uint16 vendorID,uint16 productID,const char * description)107aa661d4SMichael Lotz ProlificDevice::ProlificDevice(usb_device device, uint16 vendorID,
117aa661d4SMichael Lotz 	uint16 productID, const char *description)
127aa661d4SMichael Lotz 	:	ACMDevice(device, vendorID, productID, description),
137aa661d4SMichael Lotz 		fIsHX(false)
147aa661d4SMichael Lotz {
157aa661d4SMichael Lotz }
167aa661d4SMichael Lotz 
177aa661d4SMichael Lotz 
187aa661d4SMichael Lotz status_t
AddDevice(const usb_configuration_info * config)197aa661d4SMichael Lotz ProlificDevice::AddDevice(const usb_configuration_info *config)
207aa661d4SMichael Lotz {
217aa661d4SMichael Lotz 	TRACE_FUNCALLS("> ProlificDevice::AddDevice(%08x, %08x)\n", this, config);
227aa661d4SMichael Lotz 
237aa661d4SMichael Lotz 	// check for device type.
247aa661d4SMichael Lotz 	// Linux checks for type 0, 1 and HX, but handles 0 and 1 the same.
257aa661d4SMichael Lotz 	// We'll just check for HX then.
267aa661d4SMichael Lotz 	const usb_device_descriptor *deviceDescriptor = NULL;
277aa661d4SMichael Lotz 	deviceDescriptor = gUSBModule->get_device_descriptor(Device());
287aa661d4SMichael Lotz 	if (deviceDescriptor) {
297aa661d4SMichael Lotz 		fIsHX = (deviceDescriptor->device_class != 0x02
307aa661d4SMichael Lotz 			&& deviceDescriptor->max_packet_size_0 == 0x40);
317aa661d4SMichael Lotz 	}
327aa661d4SMichael Lotz 
337aa661d4SMichael Lotz 	int32 pipesSet = 0;
347aa661d4SMichael Lotz 	status_t status = ENODEV;
357aa661d4SMichael Lotz 	if (config->interface_count > 0) {
367aa661d4SMichael Lotz 		usb_interface_info *interface = config->interface[0].active;
377aa661d4SMichael Lotz 		for (size_t i = 0; i < interface->endpoint_count; i++) {
387aa661d4SMichael Lotz 			usb_endpoint_info *endpoint = &interface->endpoint[i];
39c5f2df28SPhilippe Houdoin 			if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_INTERRUPT) {
40c5f2df28SPhilippe Houdoin 				if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) {
417aa661d4SMichael Lotz 					SetControlPipe(endpoint->handle);
427aa661d4SMichael Lotz 					pipesSet++;
437aa661d4SMichael Lotz 				}
447aa661d4SMichael Lotz 			}
457aa661d4SMichael Lotz 		}
467aa661d4SMichael Lotz 
477aa661d4SMichael Lotz 		/* They say that USB-RSAQ1 has 2 interfaces */
487aa661d4SMichael Lotz 		if (config->interface_count >= 2)
497aa661d4SMichael Lotz 			interface = config->interface[1].active;
507aa661d4SMichael Lotz 
517aa661d4SMichael Lotz 		for (size_t i = 0; i < interface->endpoint_count; i++) {
527aa661d4SMichael Lotz 			usb_endpoint_info *endpoint = &interface->endpoint[i];
53c5f2df28SPhilippe Houdoin 			if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) {
54c5f2df28SPhilippe Houdoin 				if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
557aa661d4SMichael Lotz 					SetReadPipe(endpoint->handle);
56c5f2df28SPhilippe Houdoin 				else
577aa661d4SMichael Lotz 					SetWritePipe(endpoint->handle);
58c5f2df28SPhilippe Houdoin 
597aa661d4SMichael Lotz 				if (++pipesSet >= 3)
607aa661d4SMichael Lotz 					break;
617aa661d4SMichael Lotz 			}
627aa661d4SMichael Lotz 		}
637aa661d4SMichael Lotz 
647aa661d4SMichael Lotz 		if (pipesSet >= 3)
657aa661d4SMichael Lotz 			status = B_OK;
667aa661d4SMichael Lotz 	}
677aa661d4SMichael Lotz 
687aa661d4SMichael Lotz 	TRACE_FUNCRET("< ProlificDevice::AddDevice() returns: 0x%08x\n", status);
697aa661d4SMichael Lotz 	return status;
707aa661d4SMichael Lotz }
717aa661d4SMichael Lotz 
727aa661d4SMichael Lotz 
737aa661d4SMichael Lotz struct request_item {
747aa661d4SMichael Lotz 	bool out;
757aa661d4SMichael Lotz 	uint16 value;
767aa661d4SMichael Lotz 	uint16 index;
777aa661d4SMichael Lotz };
787aa661d4SMichael Lotz 
797aa661d4SMichael Lotz /* Linux sends all those, and it seems to work */
807aa661d4SMichael Lotz /* see drivers/usb/serial/pl2303.c */
817aa661d4SMichael Lotz static struct request_item prolific_reset_common[] = {
827aa661d4SMichael Lotz 	{ false, 0x8484, 0 },
837aa661d4SMichael Lotz 	{ true, 0x0404, 0 },
847aa661d4SMichael Lotz 	{ false, 0x8484, 0 },
857aa661d4SMichael Lotz 	{ false, 0x8383, 0 },
867aa661d4SMichael Lotz 	{ false, 0x8484, 0 },
877aa661d4SMichael Lotz 	{ true, 0x0404, 1 },
887aa661d4SMichael Lotz 	{ false, 0x8484, 0 },
897aa661d4SMichael Lotz 	{ false, 0x8383, 0 },
907aa661d4SMichael Lotz 	{ true, 0x0000, 1 },
917aa661d4SMichael Lotz 	{ true, 0x0001, 0 }
927aa661d4SMichael Lotz };
937aa661d4SMichael Lotz 
947aa661d4SMichael Lotz static struct request_item prolific_reset_common_hx[] = {
957aa661d4SMichael Lotz 	{ true, 2, 0x44 },
967aa661d4SMichael Lotz 	{ true, 8, 0 },
977aa661d4SMichael Lotz 	{ true, 0, 0 }
987aa661d4SMichael Lotz };
997aa661d4SMichael Lotz 
1007aa661d4SMichael Lotz static struct request_item prolific_reset_common_nhx[] = {
1017aa661d4SMichael Lotz 	{ true, 2, 0x24 }
1027aa661d4SMichael Lotz };
1037aa661d4SMichael Lotz 
1047aa661d4SMichael Lotz 
1057aa661d4SMichael Lotz status_t
SendRequestList(request_item * list,size_t length)1067aa661d4SMichael Lotz ProlificDevice::SendRequestList(request_item *list, size_t length)
1077aa661d4SMichael Lotz {
1087aa661d4SMichael Lotz 	for (size_t i = 0; i < length; i++) {
1097aa661d4SMichael Lotz 		char buffer[10];
1107aa661d4SMichael Lotz 		size_t bufferLength = 1;
1117aa661d4SMichael Lotz 		status_t status = gUSBModule->send_request(Device(),
1127aa661d4SMichael Lotz 			USB_REQTYPE_VENDOR | (list[i].out ? USB_REQTYPE_DEVICE_OUT : USB_REQTYPE_DEVICE_IN),
1137aa661d4SMichael Lotz 			PROLIFIC_SET_REQUEST,
1147aa661d4SMichael Lotz 			list[i].value,
1157aa661d4SMichael Lotz 			list[i].index,
1167aa661d4SMichael Lotz 			list[i].out ? 0 : bufferLength,
1177aa661d4SMichael Lotz 			list[i].out ? NULL : buffer,
1187aa661d4SMichael Lotz 			&bufferLength);
1197aa661d4SMichael Lotz 		TRACE(" ProlificDevice::SendRequestList(): request[%d]: 0x%08lx\n", i, status);
120f7868b8fSMichael Lotz 		if (status != B_OK) {
121f7868b8fSMichael Lotz 			TRACE_ALWAYS("sending request list failed:0x%08lx\n", status);
122f7868b8fSMichael Lotz 		}
1237aa661d4SMichael Lotz 	}
1247aa661d4SMichael Lotz 
1257aa661d4SMichael Lotz 	return B_OK;
1267aa661d4SMichael Lotz }
1277aa661d4SMichael Lotz 
1287aa661d4SMichael Lotz 
1297aa661d4SMichael Lotz status_t
ResetDevice()1307aa661d4SMichael Lotz ProlificDevice::ResetDevice()
1317aa661d4SMichael Lotz {
1327aa661d4SMichael Lotz 	TRACE_FUNCALLS("> ProlificDevice::ResetDevice(%08x)\n", this);
1337aa661d4SMichael Lotz 
134*57bc6503SAlexander von Gluck IV 	SendRequestList(prolific_reset_common, B_COUNT_OF(prolific_reset_common));
1357aa661d4SMichael Lotz 	if (fIsHX)
136*57bc6503SAlexander von Gluck IV 		SendRequestList(prolific_reset_common_hx, B_COUNT_OF(prolific_reset_common_hx));
1377aa661d4SMichael Lotz 	else
138*57bc6503SAlexander von Gluck IV 		SendRequestList(prolific_reset_common_nhx, B_COUNT_OF(prolific_reset_common_nhx));
1397aa661d4SMichael Lotz 
1407aa661d4SMichael Lotz 	status_t status = B_OK; /* discard */
1417aa661d4SMichael Lotz 	TRACE_FUNCRET("< ProlificDevice::ResetDevice() returns: 0x%08x\n", status);
1427aa661d4SMichael Lotz 	return status;
1437aa661d4SMichael Lotz }
144