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
KLSIDevice(usb_device device,uint16 vendorID,uint16 productID,const char * description)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
AddDevice(const usb_configuration_info * config)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
ResetDevice()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
SetLineCoding(usb_cdc_line_coding * lineCoding)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
OnRead(char ** buffer,size_t * numBytes)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
OnWrite(const char * buffer,size_t * numBytes,size_t * packetBytes)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
OnClose()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