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