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 "KLSI.h" 9 #include <ByteOrder.h> 10 11 KLSIDevice::KLSIDevice(usb_device device, uint16 vendorID, uint16 productID, 12 const char *description) 13 : SerialDevice(device, vendorID, productID, description) 14 { 15 } 16 17 18 status_t 19 KLSIDevice::AddDevice(const usb_configuration_info *config) 20 { 21 TRACE_FUNCALLS("> KLSIDevice::AddDevice(%08x, %08x)\n", this, config); 22 23 int32 pipesSet = 0; 24 status_t status = ENODEV; 25 if (config->interface_count > 0) { 26 usb_interface_info *interface = config->interface[0].active; 27 for (size_t i = 0; i < interface->endpoint_count; i++) { 28 usb_endpoint_info *endpoint = &interface->endpoint[i]; 29 if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_INTERRUPT) { 30 if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) { 31 SetControlPipe(endpoint->handle); 32 SetInterruptBufferSize(endpoint->descr->max_packet_size); 33 } 34 } else if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { 35 if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) { 36 SetReadBufferSize(ROUNDUP(endpoint->descr->max_packet_size, 16)); 37 SetReadPipe(endpoint->handle); 38 } else { 39 SetWriteBufferSize(ROUNDUP(endpoint->descr->max_packet_size, 16)); 40 SetWritePipe(endpoint->handle); 41 } 42 } 43 if (++pipesSet >= 3) 44 break; 45 } 46 } 47 48 if (pipesSet >= 3) 49 status = B_OK; 50 51 TRACE_FUNCRET("< KLSIDevice::AddDevice() returns: 0x%08x\n", status); 52 return status; 53 } 54 55 56 status_t 57 KLSIDevice::ResetDevice() 58 { 59 TRACE_FUNCALLS("> KLSIDevice::ResetDevice(%08x)\n", this); 60 61 size_t length = 0; 62 status_t status; 63 usb_cdc_line_coding lineCoding = { 9600, 1, 0, 8 }; 64 uint8 linestate[2]; 65 66 status = SetLineCoding(&lineCoding); 67 status = gUSBModule->send_request(Device(), 68 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 69 KLSI_CONF_REQUEST, 70 KLSI_CONF_REQUEST_READ_ON, 0, 0, NULL, &length); 71 TRACE("= KLSIDevice::ResetDevice(): set conf read_on returns: 0x%08x\n", 72 status); 73 74 linestate[0] = 0xff; 75 linestate[1] = 0xff; 76 length = 0; 77 status = gUSBModule->send_request(Device(), 78 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, 79 KLSI_POLL_REQUEST, 80 0, 0, 2, linestate, &length); 81 82 TRACE_FUNCRET("< KLSIDevice::ResetDevice() returns: 0x%08x\n", status); 83 return status; 84 } 85 86 87 status_t 88 KLSIDevice::SetLineCoding(usb_cdc_line_coding *lineCoding) 89 { 90 TRACE_FUNCALLS("> KLSIDevice::SetLineCoding(0x%08x, {%d, 0x%02x, 0x%02x, 0x%02x})\n", 91 this, lineCoding->speed, lineCoding->stopbits, lineCoding->parity, 92 lineCoding->databits); 93 94 uint8 rate; 95 switch (lineCoding->speed) { 96 case 300: rate = klsi_sio_b300; break; 97 case 600: rate = klsi_sio_b600; break; 98 case 1200: rate = klsi_sio_b1200; break; 99 case 2400: rate = klsi_sio_b2400; break; 100 case 4800: rate = klsi_sio_b4800; break; 101 case 9600: rate = klsi_sio_b9600; break; 102 case 19200: rate = klsi_sio_b19200; break; 103 case 38400: rate = klsi_sio_b38400; break; 104 case 57600: rate = klsi_sio_b57600; break; 105 case 115200: rate = klsi_sio_b115200; break; 106 default: 107 rate = klsi_sio_b19200; 108 TRACE_ALWAYS("= KLSIDevice::SetLineCoding(): Datarate: %d is not " 109 "supported by this hardware. Defaulted to %d\n", 110 lineCoding->speed, rate); 111 break; 112 } 113 114 uint8 codingPacket[5]; 115 codingPacket[0] = 5; /* size */ 116 codingPacket[1] = rate; 117 codingPacket[2] = lineCoding->databits; /* only 7,8 */ 118 codingPacket[3] = 0; /* unknown */ 119 codingPacket[4] = 1; /* unknown */ 120 121 size_t length = 0; 122 status_t status = gUSBModule->send_request(Device(), 123 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 124 KLSI_SET_REQUEST, 0, 0, 125 sizeof(codingPacket), codingPacket, &length); 126 127 if (status != B_OK) 128 TRACE_ALWAYS("= KLSIDevice::SetLineCoding(): datarate set request failed: 0x%08x\n", status); 129 130 TRACE_FUNCRET("< KLSIDevice::SetLineCoding() returns: 0x%08x\n", status); 131 return status; 132 } 133 134 135 void 136 KLSIDevice::OnRead(char **buffer, size_t *numBytes) 137 { 138 if (*numBytes <= 2) { 139 *numBytes = 0; 140 return; 141 } 142 143 size_t bytes = B_LENDIAN_TO_HOST_INT16(*(uint16 *)(*buffer)); 144 *numBytes = MIN(bytes, *numBytes - 2); 145 *buffer += 2; 146 } 147 148 149 void 150 KLSIDevice::OnWrite(const char *buffer, size_t *numBytes, size_t *packetBytes) 151 { 152 if (*numBytes > KLSI_BUFFER_SIZE) 153 *numBytes = *packetBytes = KLSI_BUFFER_SIZE; 154 155 if (*numBytes > WriteBufferSize() - 2) 156 *numBytes = *packetBytes = WriteBufferSize() - 2; 157 158 char *writeBuffer = WriteBuffer(); 159 *((uint16 *)writeBuffer) = B_HOST_TO_LENDIAN_INT16(*numBytes); 160 memcpy(writeBuffer + 2, buffer, *packetBytes); 161 *packetBytes += 2; 162 } 163 164 165 void 166 KLSIDevice::OnClose() 167 { 168 TRACE_FUNCALLS("> KLSIDevice::OnClose(%08x)\n", this); 169 170 size_t length = 0; 171 status_t status = gUSBModule->send_request(Device(), 172 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, 173 KLSI_CONF_REQUEST, 174 KLSI_CONF_REQUEST_READ_OFF, 0, 0, 175 NULL, &length); 176 177 TRACE_FUNCRET("< KLSIDevice::OnClose() returns: 0x%08x\n", status); 178 } 179