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