1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13/** 14 * @brief Prolific PL2303 USB to Serial adaptor 15 * @see http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=232&pcid=41 16 */ 17#include <stdio.h> 18#include <string.h> 19 20#include <usb/drivers/pl2303.h> 21#include "../services.h" 22 23#define PL2303_VENDOR_REQ 0x01 24#define PL2303_READ_TYPE (USB_DIR_IN | USB_TYPE_VEN | USB_RCPT_DEVICE) 25#define PL2303_WRITE_TYPE (USB_DIR_OUT | USB_TYPE_VEN | USB_RCPT_DEVICE) 26 27#define PL2303_SET_LINE_REQ 0x20 28#define PL2303_SET_CTRL_REQ 0x22 29#define PL2303_SET_REQ_TYPE 0x21 30 31#define PL2303_GET_LINE_REQ 0x21 32#define PL2303_GET_REQ_TYEP 0xA1 33 34#define PL2303_CTRL_DTR 0x01 35#define PL2303_CTRL_RTS 0x01 36 37/* PL2303 USB to Serial Converter */ 38struct pl2303_device { 39 struct usb_dev *udev; //The handle to the underlying USB device 40 uint8_t config; //Active configuration 41 struct endpoint *ep_int; //Interrupt endpoint 42 struct endpoint *ep_in; //BULK in endpoint 43 struct endpoint *ep_out; //BULK out endpoint 44 struct xact int_xact; //Interrupt xact 45}; 46 47static int 48pl2303_config_cb(void *token, int cfg, int iface, struct anon_desc *desc) 49{ 50 struct pl2303_device *dev; 51 struct config_desc *cdesc; 52 53 if (!desc) { 54 return 0; 55 } 56 57 dev = (struct pl2303_device*)token; 58 59 switch (desc->bDescriptorType) { 60 case CONFIGURATION: 61 cdesc = (struct config_desc*)desc; 62 dev->config = cdesc->bConfigurationValue; 63 break; 64 default: 65 break; 66 } 67 68 return 0; 69} 70 71static int 72pl2303_interrupt_cb(void* token, enum usb_xact_status stat, int rbytes) 73{ 74 int err; 75 struct pl2303_device *dev; 76 struct usb_dev *udev; 77 78 udev = (struct usb_dev*)token; 79 dev = (struct pl2303_device*)udev->dev_data; 80 81 /* Queue another request */ 82 err = usbdev_schedule_xact(udev, dev->ep_int, &dev->int_xact, 1, 83 pl2303_interrupt_cb, udev); 84 if (err) { 85 ZF_LOGF("Transaction error\n"); 86 } 87 88 return err; 89} 90 91static void 92pl2303_startup_magic(struct usb_dev *udev) 93{ 94 int err; 95 struct xact xact[2]; 96 struct usbreq *req; 97 98 if (!udev) { 99 ZF_LOGF("Invalid device\n"); 100 } 101 102 xact[0].len = sizeof(struct usbreq); 103 xact[1].len = 1; 104 err = usb_alloc_xact(udev->dman, xact, 2); 105 if (err) { 106 ZF_LOGF("Out of DMA memory\n"); 107 } 108 109 /* Fill in the request */ 110 xact[0].type = PID_SETUP; 111 xact[1].type = PID_IN; 112 req = xact_get_vaddr(&xact[0]); 113 114 /* 115 * Send Prolific private initial data. 116 * 117 * It is found by sniffing the official windows driver. 118 */ 119 req->bRequest = PL2303_VENDOR_REQ; 120 121#define magic_request(typ, idx, val) \ 122 req->bmRequestType = typ; \ 123 req->wIndex = idx; \ 124 req->wValue = val; \ 125 req->wLength = (typ == PL2303_READ_TYPE) ? 1 : 0; \ 126 err = usbdev_schedule_xact(udev, udev->ep_ctrl, xact, \ 127 req->wLength + 1, NULL, NULL); \ 128 129 magic_request(PL2303_READ_TYPE, 0, 0x8484); 130 magic_request(PL2303_WRITE_TYPE, 0, 0x0404); 131 magic_request(PL2303_READ_TYPE, 0, 0x8484); 132 magic_request(PL2303_READ_TYPE, 0, 0x8383); 133 magic_request(PL2303_READ_TYPE, 0, 0x8484); 134 magic_request(PL2303_WRITE_TYPE, 1, 0x0404); 135 magic_request(PL2303_READ_TYPE, 0, 0x8484); 136 magic_request(PL2303_READ_TYPE, 0, 0x8383); 137 magic_request(PL2303_WRITE_TYPE, 1, 0); 138 magic_request(PL2303_WRITE_TYPE, 0, 1); 139 magic_request(PL2303_WRITE_TYPE, 0x44, 2); 140 141 usb_destroy_xact(udev->dman, xact, 2); 142} 143 144int usb_pl2303_bind(usb_dev_t *udev) 145{ 146 int err; 147 struct pl2303_device *dev; 148 struct xact xact; 149 struct usbreq *req; 150 151 if (!udev) { 152 ZF_LOGF("Invalid device\n"); 153 } 154 155 dev = usb_malloc(sizeof(struct pl2303_device)); 156 if (!dev) { 157 ZF_LOGD("Not enough memory!\n"); 158 return -1; 159 } 160 161 dev->udev = udev; 162 udev->dev_data = (struct udev_priv*)dev; 163 164 /* Parse the descriptors */ 165 err = usbdev_parse_config(udev, pl2303_config_cb, dev); 166 if (err) { 167 ZF_LOGF("Invalid descriptors\n"); 168 } 169 170 /* Find endpoints */ 171 for (int i = 0; udev->ep[i] != NULL; i++) { 172 if (udev->ep[i]->type == EP_BULK) { 173 if (udev->ep[i]->dir == EP_DIR_OUT) { 174 dev->ep_out = udev->ep[i]; 175 } else { 176 dev->ep_in = udev->ep[i]; 177 } 178 } else if (udev->ep[i]->type == EP_INTERRUPT) { 179 dev->ep_int = udev->ep[i]; 180 } else { 181 continue; 182 } 183 } 184 185 if (udev->vend_id != 0x067b || udev->prod_id != 0x2303) { 186 ZF_LOGD("Not a PL2303 device(%u:%u)\n", 187 udev->vend_id, udev->prod_id); 188 return -1; 189 } 190 191 ZF_LOGD("Found PL2303 USB to serial converter!\n"); 192 193 /* Activate configuration */ 194 xact.len = sizeof(struct usbreq); 195 err = usb_alloc_xact(udev->dman, &xact, 1); 196 if (err) { 197 ZF_LOGF("Out of DMA memory\n"); 198 } 199 200 /* Fill in the request */ 201 xact.type = PID_SETUP; 202 req = xact_get_vaddr(&xact); 203 *req = __set_configuration_req(dev->config); 204 205 /* Send the request to the host */ 206 err = usbdev_schedule_xact(udev, udev->ep_ctrl, &xact, 1, NULL, NULL); 207 if (err) { 208 ZF_LOGF("Transaction error\n"); 209 } 210 usb_destroy_xact(udev->dman, &xact, 1); 211 212 pl2303_startup_magic(udev); 213 214 /* Allocate interrupt xact */ 215 dev->int_xact.type = PID_IN; 216 dev->int_xact.len = dev->ep_int->max_pkt; 217 err = usb_alloc_xact(udev->dman, &dev->int_xact, 1); 218 if (err) { 219 ZF_LOGF("Out of DMA memory\n"); 220 } 221 222 /* Schedule a interrupt request */ 223 err = usbdev_schedule_xact(udev, dev->ep_int, &dev->int_xact, 1, 224 pl2303_interrupt_cb, udev); 225 if (err) { 226 ZF_LOGF("Transaction error\n"); 227 } 228 229 return 0; 230} 231 232int usb_pl2303_configure(usb_dev_t *udev, uint32_t bps, uint8_t char_size, 233 enum serial_parity parity, uint8_t stop) 234{ 235 int err; 236 struct xact xact[2]; 237 struct usbreq *req; 238 char *buf; 239 240 xact[0].len = sizeof(struct usbreq); 241 xact[1].len = 7; 242 err = usb_alloc_xact(udev->dman, xact, 2); 243 if (err) { 244 ZF_LOGF("Out of DMA memory\n"); 245 } 246 247 xact[0].type = PID_SETUP; 248 xact[1].type = PID_OUT; 249 req = xact_get_vaddr(&xact[0]); 250 buf = xact_get_vaddr(&xact[1]); 251 252 /* Data bits */ 253 buf[6] = char_size; 254 255 /* 256 * Set parity 257 * 0 -- none, 1 -- odd, 2-- even, 3 -- mark, 4 -- space 258 */ 259 switch (parity) { 260 case PARITY_NONE: 261 buf[5] = 0; 262 break; 263 case PARITY_ODD: 264 buf[5] = 1; 265 break; 266 case PARITY_EVEN: 267 buf[5] = 2; 268 break; 269 default: 270 ZF_LOGD("Unsupported parity!\n"); 271 break; 272 } 273 274 /* 0 -- 1 stop bits, 1 -- 1.5 stop bits, 2 -- 2 stop bits */ 275 buf[4] = stop; 276 277 /* Set baudrate */ 278 buf[3] = bps & 0xFF; 279 buf[2] = (bps >> 16) & 0xFF; 280 buf[1] = (bps >> 8) & 0xFF; 281 buf[0] = bps & 0xFF000000; 282 283 /* Send configuration */ 284 req->bmRequestType = PL2303_SET_REQ_TYPE; 285 req->bRequest = PL2303_SET_LINE_REQ; 286 req->wIndex = 0; 287 req->wLength = 7; 288 req->wValue = 0; 289 290 err = usbdev_schedule_xact(udev, udev->ep_ctrl, xact, 2, NULL, NULL); 291 if (err) { 292 ZF_LOGF("Transaction error\n"); 293 } 294 295 /* Activate device */ 296 req->bmRequestType = PL2303_SET_REQ_TYPE; 297 req->bRequest = PL2303_SET_CTRL_REQ; 298 req->wIndex = 0; 299 req->wLength = 0; 300 req->wValue = PL2303_CTRL_DTR | PL2303_CTRL_RTS; 301 302 err = usbdev_schedule_xact(udev, udev->ep_ctrl, xact, 1, NULL, NULL); 303 if (err) { 304 ZF_LOGF("Transaction error\n"); 305 } 306 307 usb_destroy_xact(udev->dman, xact, 2); 308 309 return 0; 310} 311 312/* TODO: Remove the 20K limitation */ 313int usb_pl2303_write(usb_dev_t *udev, void *buf, int len) 314{ 315 int err; 316 struct pl2303_device *dev; 317 struct xact xact; 318 319 dev = (struct pl2303_device*)udev->dev_data; 320 321 xact.type = PID_OUT; 322 xact.len = len; 323 err = usb_alloc_xact(udev->dman, &xact, 1); 324 if (err) { 325 ZF_LOGF("Out of DMA memory\n"); 326 } 327 328 memcpy(xact_get_vaddr(&xact), buf, len); 329 330 err = usbdev_schedule_xact(udev, dev->ep_out, &xact, 1, NULL, NULL); 331 if (err) { 332 ZF_LOGF("Transaction error\n"); 333 } 334 335 usb_destroy_xact(udev->dman, &xact, 1); 336 337 return len - err; 338} 339 340/* TODO: Remove the 20K limitation and possible babble */ 341int usb_pl2303_read(usb_dev_t *udev, void *buf, int len) 342{ 343 int err; 344 struct pl2303_device *dev; 345 struct xact xact; 346 347 dev = (struct pl2303_device*)udev->dev_data; 348 349 xact.type = PID_IN; 350 xact.len = len; 351 err = usb_alloc_xact(udev->dman, &xact, 1); 352 if (err) { 353 ZF_LOGF("Out of DMA memory\n"); 354 } 355 356 err = usbdev_schedule_xact(udev, dev->ep_in, &xact, 1, NULL, NULL); 357 if (err) { 358 ZF_LOGF("Transaction error\n"); 359 } 360 361 memcpy(buf, xact_get_vaddr(&xact), len); 362 363 usb_destroy_xact(udev->dman, &xact, 1); 364 365 return len - err; 366} 367 368