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