xref: /haiku/src/add-ons/kernel/drivers/ports/usb_serial/ACM.cpp (revision 89755088d790ff4fe36f8aa77dacb2bd15507108)
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 "ACM.h"
9 #include "Driver.h"
10 
11 ACMDevice::ACMDevice(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 ACMDevice::AddDevice(const usb_configuration_info *config)
20 {
21 	TRACE_FUNCALLS("> ACMDevice::AddDevice(0x%08x, 0x%08x)\n", this, config);
22 
23 	status_t status = ENODEV;
24 	uint8 masterIndex = 0;
25 	uint8 slaveIndex = 0;
26 	for (size_t i = 0; i < config->interface_count && status < B_OK; i++) {
27 		usb_interface_info *interface = config->interface[i].active;
28 		usb_interface_descriptor *descriptor = interface->descr;
29 		if (descriptor->interface_class == USB_INT_CLASS_CDC
30 			&& descriptor->interface_subclass == USB_INT_SUBCLASS_ACM
31 			&& interface->generic_count > 0) {
32 			// try to find and interpret the union functional descriptor
33 			for (size_t j = 0; j < interface->generic_count; j++) {
34 				usb_generic_descriptor *generic = &interface->generic[j]->generic;
35 				if (generic->length >= 5
36 					&& generic->data[0] == FUNCTIONAL_SUBTYPE_UNION) {
37 					masterIndex = generic->data[1];
38 					slaveIndex = generic->data[2];
39 					status = B_OK;
40 					break;
41 				}
42 			}
43 		}
44 	}
45 
46 	if (status == B_OK && masterIndex < config->interface_count) {
47 		// check that the indicated master interface fits our need
48 		usb_interface_info *interface = config->interface[masterIndex].active;
49 		usb_interface_descriptor *descriptor = interface->descr;
50 		if ((descriptor->interface_class == USB_INT_CLASS_CDC
51 			|| descriptor->interface_class == USB_INT_CLASS_CDC_DATA)
52 			&& interface->endpoint_count >= 1) {
53 			SetControlPipe(interface->endpoint[0].handle);
54 		} else
55 			status = ENODEV;
56 	}
57 
58 	if (status == B_OK && slaveIndex < config->interface_count) {
59 		// check that the indicated slave interface fits our need
60 		usb_interface_info *interface = config->interface[slaveIndex].active;
61 		usb_interface_descriptor *descriptor = interface->descr;
62 		if (descriptor->interface_class == USB_INT_CLASS_CDC_DATA
63 			&& interface->endpoint_count >= 2) {
64 			if (!(interface->endpoint[0].descr->endpoint_address & USB_EP_ADDR_DIR_IN))
65 				SetWritePipe(interface->endpoint[0].handle);
66 			else
67 				SetReadPipe(interface->endpoint[0].handle);
68 
69 			if (interface->endpoint[1].descr->endpoint_address & USB_EP_ADDR_DIR_IN)
70 				SetReadPipe(interface->endpoint[1].handle);
71 			else
72 				SetWritePipe(interface->endpoint[1].handle);
73 		} else
74 			status = ENODEV;
75 	}
76 
77 	TRACE_FUNCRET("< ACMDevice::AddDevice() returns: 0x%08x\n", status);
78 	return status;
79 }
80 
81 
82 status_t
83 ACMDevice::SetLineCoding(usb_serial_line_coding *lineCoding)
84 {
85 	TRACE_FUNCALLS("> ACMDevice::SetLineCoding(0x%08x, {%d, 0x%02x, 0x%02x, 0x%02x})\n",
86 		this, lineCoding->speed, lineCoding->stopbits, lineCoding->parity,
87 		lineCoding->databits);
88 
89 	size_t length = 0;
90 	status_t status = gUSBModule->send_request(Device(),
91 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT,
92 		SET_LINE_CODING, 0, 0,
93 		sizeof(usb_serial_line_coding),
94 		lineCoding, &length);
95 
96 	TRACE_FUNCRET("< ACMDevice::SetLineCoding() returns: 0x%08x\n", status);
97 	return status;
98 }
99 
100 
101 status_t
102 ACMDevice::SetControlLineState(uint16 state)
103 {
104 	TRACE_FUNCALLS("> ACMDevice::SetControlLineState(0x%08x, 0x%04x)\n", this, state);
105 
106 	size_t length = 0;
107 	status_t status = gUSBModule->send_request(Device(),
108 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT,
109 		SET_CONTROL_LINE_STATE, state, 0, 0, NULL, &length);
110 
111 	TRACE_FUNCRET("< ACMDevice::SetControlLineState() returns: 0x%08x\n", status);
112 	return status;
113 }
114 
115 
116 void
117 ACMDevice::OnWrite(const char *buffer, size_t *numBytes)
118 {
119 	memcpy(WriteBuffer(), buffer, *numBytes);
120 }
121