1 /* 2 * Copyright 2011, Adrien Destugues <pulkomandy@pulkomandy.ath.cx> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "Silicon.h" 8 9 10 static const int kBaudrateGeneratorFrequency = 0x384000; 11 12 13 SiliconDevice::SiliconDevice(usb_device device, uint16 vendorID, uint16 productID, 14 const char *description) 15 : SerialDevice(device, vendorID, productID, description) 16 { 17 } 18 19 20 // Called for each configuration of the device. Return B_OK if the given 21 // configuration sounds like it is the usb serial one. 22 status_t 23 SiliconDevice::AddDevice(const usb_configuration_info *config) 24 { 25 status_t status = ENODEV; 26 if (config->interface_count > 0) { 27 int32 pipesSet = 0; 28 usb_interface_info *interface = config->interface[0].active; 29 for (size_t i = 0; i < interface->endpoint_count; i++) { 30 usb_endpoint_info *endpoint = &interface->endpoint[i]; 31 if (endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { 32 if (endpoint->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) { 33 SetReadPipe(endpoint->handle); 34 if (++pipesSet >= 3) 35 break; 36 } else { 37 if (endpoint->descr->endpoint_address) { 38 SetControlPipe(endpoint->handle); 39 SetWritePipe(endpoint->handle); 40 pipesSet += 2; 41 if (pipesSet >= 3) 42 break; 43 } 44 } 45 } 46 } 47 48 if (pipesSet >= 3) { 49 status = B_OK; 50 } 51 } 52 return status; 53 } 54 55 56 // Called on opening the device - Good time to enable the UART ? 57 status_t 58 SiliconDevice::ResetDevice() 59 { 60 uint16_t enableUart = 1; 61 return WriteConfig(ENABLE_UART, &enableUart, 2); 62 } 63 64 65 status_t 66 SiliconDevice::SetLineCoding(usb_cdc_line_coding *lineCoding) 67 { 68 uint16_t divider = kBaudrateGeneratorFrequency / lineCoding->speed ; 69 status_t result = WriteConfig(SET_BAUDRATE_DIVIDER, ÷r, 2); 70 71 if (result != B_OK) return result; 72 73 uint16_t data = 0; 74 75 switch (lineCoding->stopbits) { 76 case USB_CDC_LINE_CODING_1_STOPBIT: data = 0; break; 77 case USB_CDC_LINE_CODING_2_STOPBITS: data = 2; break; 78 default: 79 TRACE_ALWAYS("= SiliconDevice::SetLineCoding(): Wrong stopbits param: %d\n", 80 lineCoding->stopbits); 81 break; 82 } 83 84 switch (lineCoding->parity) { 85 case USB_CDC_LINE_CODING_NO_PARITY: data |= 0 << 4; break; 86 case USB_CDC_LINE_CODING_EVEN_PARITY: data |= 2 << 4; break; 87 case USB_CDC_LINE_CODING_ODD_PARITY: data |= 1 << 4; break; 88 default: 89 TRACE_ALWAYS("= SiliconDevice::SetLineCoding(): Wrong parity param: %d\n", 90 lineCoding->parity); 91 break; 92 } 93 94 data |= lineCoding->databits << 8; 95 96 return WriteConfig(SET_LINE_FORMAT, &data, 2); 97 } 98 99 100 status_t 101 SiliconDevice::SetControlLineState(uint16 state) 102 { 103 uint16_t control = 0; 104 control |= 0x0300; // We are updating DTR and RTS 105 control |= (state & USB_CDC_CONTROL_SIGNAL_STATE_RTS) ? 2 : 0; 106 control |= (state & USB_CDC_CONTROL_SIGNAL_STATE_DTR) ? 1 : 0; 107 108 return WriteConfig(SET_STATUS, &control, 2); 109 } 110 111 112 status_t SiliconDevice::WriteConfig(CP210XRequest request, uint16_t* data, 113 size_t size) 114 { 115 size_t replyLength = 0; 116 status_t result; 117 // Small requests (16 bits and less) use the "value" field for their data. 118 // Bigger ones use the actual buffer. 119 if (size <= 2) { 120 result = gUSBModule->send_request(Device(), 121 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, request, data[0], 0, 0, 122 NULL, &replyLength); 123 } else { 124 result = gUSBModule->send_request(Device(), 125 USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, request, 0x0000, 0, 126 size, data, &replyLength); 127 } 128 129 if (result != B_OK) { 130 TRACE_ALWAYS("= SiliconDevice request failed: 0x%08x (%s)\n", 131 result, strerror(result)); 132 } 133 134 return result; 135 } 136