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