140804Ssemenu/* 240804Ssemenu * Copyright (c) 2007-2008 by Michael Lotz 340804Ssemenu * Heavily based on the original usb_serial driver which is: 440804Ssemenu * 540804Ssemenu * Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li> 640804Ssemenu * Distributed under the terms of the MIT License. 740804Ssemenu */ 840804Ssemenu#include "Prolific.h" 940804Ssemenu 1040804SsemenuProlificDevice::ProlificDevice(usb_device device, uint16 vendorID, 1140804Ssemenu uint16 productID, const char *description) 1240804Ssemenu : ACMDevice(device, vendorID, productID, description), 1340804Ssemenu fIsHX(false) 1440804Ssemenu{ 1540804Ssemenu} 1640804Ssemenu 1740804Ssemenu 1840804Ssemenustatus_t 1940804SsemenuProlificDevice::AddDevice(const usb_configuration_info *config) 2040804Ssemenu{ 2140804Ssemenu TRACE_FUNCALLS("> ProlificDevice::AddDevice(%08x, %08x)\n", this, config); 2240804Ssemenu 2340804Ssemenu // check for device type. 2440804Ssemenu // Linux checks for type 0, 1 and HX, but handles 0 and 1 the same. 25105666Ssemenu // We'll just check for HX then. 26105666Ssemenu const usb_device_descriptor *deviceDescriptor = NULL; 2740804Ssemenu deviceDescriptor = gUSBModule->get_device_descriptor(Device()); 2840804Ssemenu if (deviceDescriptor) { 2940804Ssemenu fIsHX = (deviceDescriptor->device_class != 0x02 3040804Ssemenu && deviceDescriptor->max_packet_size_0 == 0x40); 3140804Ssemenu } 32105666Ssemenu 3359164Ssemenu int32 pipesSet = 0; 34105666Ssemenu status_t status = ENODEV; 3559164Ssemenu if (config->interface_count > 0) { 3640804Ssemenu usb_interface_info *interface = config->interface[0].active; 3740804Ssemenu for (size_t i = 0; i < interface->endpoint_count; i++) { 3840804Ssemenu usb_endpoint_info *endpoint = &interface->endpoint[i]; 3940804Ssemenu if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_INTERRUPT) { 4040804Ssemenu if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) { 4140804Ssemenu SetControlPipe(endpoint->handle); 4240804Ssemenu pipesSet++; 4340804Ssemenu } 4440804Ssemenu } 4540804Ssemenu } 4640804Ssemenu 4740804Ssemenu /* They say that USB-RSAQ1 has 2 interfaces */ 4840804Ssemenu if (config->interface_count >= 2) 4940804Ssemenu interface = config->interface[1].active; 5040804Ssemenu 51105966Ssam for (size_t i = 0; i < interface->endpoint_count; i++) { 5240804Ssemenu usb_endpoint_info *endpoint = &interface->endpoint[i]; 5340804Ssemenu if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { 5440804Ssemenu if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) 55113754Smux SetReadPipe(endpoint->handle); 56113754Smux else 5740804Ssemenu SetWritePipe(endpoint->handle); 5840804Ssemenu 5940804Ssemenu if (++pipesSet >= 3) 60113754Smux break; 61113754Smux } 6240804Ssemenu } 6340804Ssemenu 6472134Ssemenu if (pipesSet >= 3) 6572134Ssemenu status = B_OK; 6672134Ssemenu } 6772134Ssemenu 6872134Ssemenu TRACE_FUNCRET("< ProlificDevice::AddDevice() returns: 0x%08x\n", status); 6972134Ssemenu return status; 7072134Ssemenu} 7140804Ssemenu 7240804Ssemenu 73147256Sbrooksstruct request_item { 7459164Ssemenu bool out; 7559164Ssemenu uint16 value; 7659164Ssemenu uint16 index; 7759164Ssemenu}; 7861906Ssemenu 79179706Sjhb/* Linux sends all those, and it seems to work */ 80179706Sjhb/* see drivers/usb/serial/pl2303.c */ 81179706Sjhbstatic struct request_item prolific_reset_common[] = { 8259164Ssemenu { false, 0x8484, 0 }, 8340804Ssemenu { true, 0x0404, 0 }, 84113754Smux { false, 0x8484, 0 }, 85113754Smux { false, 0x8383, 0 }, 86113754Smux { false, 0x8484, 0 }, 87113754Smux { true, 0x0404, 1 }, 88113754Smux { false, 0x8484, 0 }, 89113754Smux { false, 0x8383, 0 }, 90113754Smux { true, 0x0000, 1 }, 91113754Smux { true, 0x0001, 0 } 9259164Ssemenu}; 9340804Ssemenu 9440804Ssemenustatic struct request_item prolific_reset_common_hx[] = { 9540804Ssemenu { true, 2, 0x44 }, 9640804Ssemenu { true, 8, 0 }, 9740804Ssemenu { true, 0, 0 } 9840804Ssemenu}; 9940804Ssemenu 10040804Ssemenustatic struct request_item prolific_reset_common_nhx[] = { 101113754Smux { true, 2, 0x24 } 102113754Smux}; 103113754Smux 10440804Ssemenu 10540804Ssemenustatus_t 10640804SsemenuProlificDevice::SendRequestList(request_item *list, size_t length) 10772134Ssemenu{ 10840804Ssemenu for (size_t i = 0; i < length; i++) { 10940804Ssemenu char buffer[10]; 11040804Ssemenu size_t bufferLength = 1; 11140804Ssemenu status_t status = gUSBModule->send_request(Device(), 11272134Ssemenu USB_REQTYPE_VENDOR | (list[i].out ? USB_REQTYPE_DEVICE_OUT : USB_REQTYPE_DEVICE_IN), 11372134Ssemenu PROLIFIC_SET_REQUEST, 11472134Ssemenu list[i].value, 11572134Ssemenu list[i].index, 11672134Ssemenu list[i].out ? 0 : bufferLength, 117105666Ssemenu list[i].out ? NULL : buffer, 11840804Ssemenu &bufferLength); 11940804Ssemenu TRACE(" ProlificDevice::SendRequestList(): request[%d]: 0x%08lx\n", i, status); 120179706Sjhb if (status != B_OK) { 121179706Sjhb TRACE_ALWAYS("sending request list failed:0x%08lx\n", status); 122179706Sjhb } 123179706Sjhb } 12459164Ssemenu 12559164Ssemenu return B_OK; 12659164Ssemenu} 12759164Ssemenu 12859164Ssemenu 12959164Ssemenustatus_t 130105666SsemenuProlificDevice::ResetDevice() 131179706Sjhb{ 132105666Ssemenu TRACE_FUNCALLS("> ProlificDevice::ResetDevice(%08x)\n", this); 133179706Sjhb 134105666Ssemenu SendRequestList(prolific_reset_common, B_COUNT_OF(prolific_reset_common)); 135179706Sjhb if (fIsHX) 136105666Ssemenu SendRequestList(prolific_reset_common_hx, B_COUNT_OF(prolific_reset_common_hx)); 137179706Sjhb else 138105666Ssemenu SendRequestList(prolific_reset_common_nhx, B_COUNT_OF(prolific_reset_common_nhx)); 139179706Sjhb 140105666Ssemenu status_t status = B_OK; /* discard */ 141179706Sjhb TRACE_FUNCRET("< ProlificDevice::ResetDevice() returns: 0x%08x\n", status); 14240804Ssemenu return status; 143105666Ssemenu} 144105666Ssemenu