├── .gitignore ├── LICENSE ├── README.md ├── linux ├── README.md └── driver │ ├── Makefile │ ├── ch341.c │ └── ch341.h ├── macos ├── CH34X_DRV_INSTAL_INSTRUCTIONS.pdf ├── CH34xVCPDriver.dmg └── CH34xVCPDriver.pkg └── windows ├── CH341M64.SYS ├── CH341PORTS.DLL ├── CH341PORTSA64.DLL ├── CH341PT.DLL ├── CH341PTA64.DLL ├── CH341S64.SYS ├── CH341S98.SYS ├── CH341SER.CAT ├── CH341SER.INF ├── CH341SER.SYS ├── CH341SER.VXD ├── DRVSETUP64 └── DRVSETUP64.exe ├── SETUP.EXE └── WIN 1X ├── CH341M64.sys ├── CH341PORTS.DLL ├── CH341PORTSA64.DLL ├── CH341PT.DLL ├── CH341PTA64.DLL ├── CH341S64.sys ├── CH341S98.SYS ├── CH341SER.CAT ├── CH341SER.INF ├── CH341SER.VXD └── CH341SER.sys /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arduino USB Drivers 2 | 3 | CH340 and CH341 USB controllers are commonly found on 3rd party Arduinos. To use them with the Arduino IDE or CLI you will need to install these drivers. The drivers in this repo are from the manufacturer (see [Sources](#Sources)). 4 | 5 | To install them, download the repository and follow the instructions in the appropriate folder. If you have any previously installed versions of these drivers, uninstall them before installing the new drivers. 6 | 7 | ## Sources 8 | 9 | | OS | Source URL | 10 | |---------|-----------------------------------------------------------| 11 | | Linux | https://www.wch-ic.com/downloads/CH341SER_LINUX_ZIP.html | 12 | | macOS | https://www.wch-ic.com/downloads/CH341SER_MAC_ZIP.html | 13 | | Windows | https://www.wch-ic.com/downloads/CH341SER_ZIP.html | -------------------------------------------------------------------------------- /linux/README.md: -------------------------------------------------------------------------------- 1 | # ch341 linux serial driver 2 | ## Description 3 | 4 | USB serial driver for USB to UART chip ch340, ch341, etc. In fact Linux mainline kernels have built-in ch341 serial driver since kernel version 2.6.24. The location is: drivers/usb/serial/ch341.c, it's a pity that the built-in driver cannot be kept up to date. We suggest our customers to use this driver. 5 | 6 | 1. Open "Terminal" 7 | 2. Switch to "driver" directory 8 | 3. Compile the driver using "make", you will see the module "ch341.ko" if successful 9 | 4. Type "sudo make load" or "sudo insmod ch341.ko" to load the driver dynamically 10 | 5. Type "sudo make unload" or "sudo rmmod ch341.ko" to unload the driver 11 | 6. Type "sudo make install" to make the driver work permanently 12 | 7. Type "sudo make uninstall" to remove the driver 13 | 8. You can refer to the link below to acquire uart application, you can use gcc or Cross-compile with cross-gcc 14 | https://github.com/WCHSoftGroup/tty_uart 15 | 16 | Before the driver works, you should make sure that the usb device has been plugged in and is working properly, you can use shell command "lsusb" or "dmesg" to confirm that, USB VID of these devices are [1a86], you can view all IDs from the id table which defined in "ch341.c". 17 | 18 | If the device works well, the driver will created tty devices named "ttyCH341USBx" in /dev directory. 19 | 20 | ## Note 21 | 22 | Any question, you can send feedback to mail: tech@wch.cn 23 | -------------------------------------------------------------------------------- /linux/driver/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(KERNELRELEASE), ) 2 | KERNELDIR := /lib/modules/$(shell uname -r)/build 3 | PWD :=$(shell pwd) 4 | default: 5 | $(MAKE) -C $(KERNELDIR) M=$(PWD) 6 | clean: 7 | rm -rf *.mk .tmp_versions Module.symvers *.mod.c *.o *.ko .*.cmd Module.markers modules.order *.a *.mod 8 | load: 9 | insmod ch341.ko 10 | unload: 11 | rmmod ch341 12 | install: default 13 | rmmod ch341 || true 14 | insmod ch341.ko || true 15 | mkdir -p /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ || true 16 | cp -f ./ch341.ko /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ || true 17 | depmod -a 18 | uninstall: 19 | rmmod ch341 || true 20 | rm -rf /lib/modules/$(shell uname -r)/kernel/drivers/usb/serial/ch341.ko || true 21 | depmod -a 22 | else 23 | obj-m := ch341.o 24 | endif 25 | -------------------------------------------------------------------------------- /linux/driver/ch341.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CH340/CH341 USB to serial port driver 3 | * 4 | * Copyright (C) 2023 Nanjing Qinheng Microelectronics Co., Ltd. 5 | * Web: http://wch.cn 6 | * Author: WCH 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * System require: Kernel version beyond 3.4.x 14 | * 15 | * Update Log: 16 | * V1.0 - initial version 17 | * V1.1 - add support high baudrates, modem signal, flow control, etc. 18 | * V1.2 - fixe baud rate 0 bugs and add some debug messages 19 | * V1.3 - special setting on usb packet upload timeout 20 | * V1.4 - change read urb length to ep size 21 | * V1.5 - fix hardware flowcontrol bugs 22 | * V1.6 - add support for application to get uart state 23 | * - remove tty throttle methods 24 | * - submit urbs when uart open while not probe 25 | * - fix tty kref errors in dtr_rts 26 | * - add support for kernel version beyond 5.14.x 27 | * - fix data analysis in status ep callback 28 | * V1.7 - add support for kernel version beyond 6.3.x 29 | */ 30 | 31 | #define DEBUG 32 | #define VERBOSE_DEBUG 33 | 34 | #undef DEBUG 35 | #undef VERBOSE_DEBUG 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) 57 | #include 58 | #endif 59 | 60 | #include "ch341.h" 61 | 62 | #define DRIVER_AUTHOR "WCH" 63 | #define DRIVER_DESC "USB serial driver for ch340, ch341, etc." 64 | #define VERSION_DESC "V1.7 On 2023.07" 65 | 66 | static struct usb_driver ch341_driver; 67 | static struct tty_driver *ch341_tty_driver; 68 | 69 | static DEFINE_IDR(ch341_minors); 70 | static DEFINE_MUTEX(ch341_minors_lock); 71 | 72 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) 73 | static void ch341_tty_set_termios(struct tty_struct *tty, const struct ktermios *termios_old); 74 | #else 75 | static void ch341_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old); 76 | #endif 77 | 78 | /* 79 | * Look up an ch341 structure by minor. If found and not disconnected, increment 80 | * its refcount and return it with its mutex held. 81 | */ 82 | static struct ch341 *ch341_get_by_minor(unsigned int minor) 83 | { 84 | struct ch341 *ch341; 85 | 86 | mutex_lock(&ch341_minors_lock); 87 | ch341 = idr_find(&ch341_minors, minor); 88 | if (ch341) { 89 | mutex_lock(&ch341->mutex); 90 | if (ch341->disconnected) { 91 | mutex_unlock(&ch341->mutex); 92 | ch341 = NULL; 93 | } else { 94 | tty_port_get(&ch341->port); 95 | mutex_unlock(&ch341->mutex); 96 | } 97 | } 98 | mutex_unlock(&ch341_minors_lock); 99 | return ch341; 100 | } 101 | 102 | /* 103 | * Try to find an available minor number and if found, associate it with 'ch341'. 104 | */ 105 | static int ch341_alloc_minor(struct ch341 *ch341) 106 | { 107 | int minor; 108 | 109 | mutex_lock(&ch341_minors_lock); 110 | minor = idr_alloc(&ch341_minors, ch341, 0, CH341_TTY_MINORS, GFP_KERNEL); 111 | mutex_unlock(&ch341_minors_lock); 112 | 113 | return minor; 114 | } 115 | 116 | /* Release the minor number associated with 'ch341'. */ 117 | static void ch341_release_minor(struct ch341 *ch341) 118 | { 119 | mutex_lock(&ch341_minors_lock); 120 | idr_remove(&ch341_minors, ch341->minor); 121 | mutex_unlock(&ch341_minors_lock); 122 | } 123 | 124 | /* 125 | * Functions for CH341 control messages. 126 | */ 127 | static int ch341_control_out(struct ch341 *ch341, u8 request, u16 value, u16 index) 128 | { 129 | int retval; 130 | 131 | retval = usb_autopm_get_interface(ch341->data); 132 | if (retval) 133 | return retval; 134 | 135 | retval = usb_control_msg(ch341->dev, usb_sndctrlpipe(ch341->dev, 0), request, 136 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, value, index, NULL, 0, 137 | DEFAULT_TIMEOUT); 138 | 139 | usb_autopm_put_interface(ch341->data); 140 | 141 | return retval < 0 ? retval : 0; 142 | } 143 | 144 | static int ch341_control_in(struct ch341 *ch341, u8 request, u16 value, u16 index, char *buf, unsigned bufsize) 145 | { 146 | int retval; 147 | 148 | retval = usb_autopm_get_interface(ch341->data); 149 | if (retval) 150 | return retval; 151 | 152 | retval = usb_control_msg(ch341->dev, usb_rcvctrlpipe(ch341->dev, 0), request, 153 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, value, index, buf, bufsize, 154 | DEFAULT_TIMEOUT); 155 | 156 | usb_autopm_put_interface(ch341->data); 157 | 158 | return retval; 159 | } 160 | 161 | static inline int ch341_set_control(struct ch341 *ch341, int control) 162 | { 163 | u16 value = 0; 164 | 165 | value |= (u8)~control; 166 | 167 | return ch341_control_out(ch341, CMD_C2, value, 0x0000); 168 | } 169 | 170 | static inline int ch341_set_line(struct ch341 *ch341, struct usb_ch341_line_coding *line) 171 | { 172 | return 0; 173 | } 174 | 175 | static int ch341_get_status(struct ch341 *ch341) 176 | { 177 | char *buffer; 178 | int retval; 179 | const unsigned size = 2; 180 | unsigned long flags; 181 | 182 | buffer = kmalloc(size, GFP_KERNEL); 183 | if (!buffer) 184 | return -ENOMEM; 185 | 186 | retval = ch341_control_in(ch341, CMD_R, 0x0706, 0, buffer, size); 187 | if (retval < 0) 188 | goto out; 189 | 190 | if (retval > 0) { 191 | spin_lock_irqsave(&ch341->read_lock, flags); 192 | ch341->ctrlin = (~(*buffer)) & CH341_CTI_ST; 193 | spin_unlock_irqrestore(&ch341->read_lock, flags); 194 | } else 195 | retval = -EPROTO; 196 | 197 | out: 198 | kfree(buffer); 199 | return retval; 200 | } 201 | 202 | static int ch341_configure(struct ch341 *ch341) 203 | { 204 | char *buffer; 205 | int r; 206 | const unsigned size = 2; 207 | 208 | buffer = kmalloc(size, GFP_KERNEL); 209 | if (!buffer) 210 | return -ENOMEM; 211 | 212 | r = ch341_control_in(ch341, CMD_C3, 0, 0, buffer, size); 213 | if (r < 0) 214 | goto out; 215 | r = ch341_control_out(ch341, CMD_C1, 0, 0); 216 | if (r < 0) 217 | goto out; 218 | r = ch341_control_out(ch341, CMD_W, 0x1312, 0xd982); 219 | if (r < 0) 220 | goto out; 221 | r = ch341_control_out(ch341, CMD_W, 0x0f2c, 0x0007); 222 | if (r < 0) 223 | goto out; 224 | r = ch341_control_in(ch341, CMD_R, 0x2518, 0, buffer, size); 225 | if (r < 0) 226 | goto out; 227 | r = ch341_get_status(ch341); 228 | if (r < 0) 229 | goto out; 230 | r = ch341_control_out(ch341, CMD_W, 0x2727, 0); 231 | if (r < 0) 232 | goto out; 233 | 234 | out: 235 | kfree(buffer); 236 | return r; 237 | } 238 | 239 | /* 240 | * Write buffer management. 241 | * All of these assume proper locks taken by the caller. 242 | */ 243 | static int ch341_wb_alloc(struct ch341 *ch341) 244 | { 245 | int i, wbn; 246 | struct ch341_wb *wb; 247 | 248 | wbn = 0; 249 | i = 0; 250 | for (;;) { 251 | wb = &ch341->wb[wbn]; 252 | if (!wb->use) { 253 | wb->use = 1; 254 | return wbn; 255 | } 256 | wbn = (wbn + 1) % CH341_NW; 257 | if (++i >= CH341_NW) 258 | return -1; 259 | } 260 | } 261 | 262 | static int ch341_wb_is_avail(struct ch341 *ch341) 263 | { 264 | int i, n; 265 | unsigned long flags; 266 | 267 | n = CH341_NW; 268 | spin_lock_irqsave(&ch341->write_lock, flags); 269 | for (i = 0; i < CH341_NW; i++) 270 | n -= ch341->wb[i].use; 271 | spin_unlock_irqrestore(&ch341->write_lock, flags); 272 | return n; 273 | } 274 | 275 | static void ch341_write_done(struct ch341 *ch341, struct ch341_wb *wb) 276 | { 277 | wb->use = 0; 278 | ch341->transmitting--; 279 | usb_autopm_put_interface_async(ch341->data); 280 | } 281 | 282 | static int ch341_start_wb(struct ch341 *ch341, struct ch341_wb *wb) 283 | { 284 | int rc; 285 | 286 | ch341->transmitting++; 287 | 288 | wb->urb->transfer_buffer = wb->buf; 289 | wb->urb->transfer_dma = wb->dmah; 290 | wb->urb->transfer_buffer_length = wb->len; 291 | wb->urb->dev = ch341->dev; 292 | 293 | rc = usb_submit_urb(wb->urb, GFP_ATOMIC); 294 | if (rc < 0) { 295 | dev_err(&ch341->data->dev, "%s - usb_submit_urb(write bulk) failed: %d\n", __func__, rc); 296 | ch341_write_done(ch341, wb); 297 | } 298 | return rc; 299 | } 300 | 301 | static void ch341_update_status(struct ch341 *ch341, unsigned char *data, size_t len) 302 | { 303 | unsigned long flags; 304 | u8 status; 305 | u8 difference; 306 | u8 type = data[0]; 307 | u8 handled = 0; 308 | 309 | if (len < 4) 310 | return; 311 | 312 | if (type & CH341_CTT_M) { 313 | status = ~data[2] & CH341_CTI_ST; 314 | 315 | if (!ch341->clocal && (ch341->ctrlin & status & CH341_CTI_DC)) { 316 | tty_port_tty_hangup(&ch341->port, false); 317 | } 318 | 319 | spin_lock_irqsave(&ch341->read_lock, flags); 320 | difference = status ^ ch341->ctrlin; 321 | ch341->ctrlin = status; 322 | ch341->oldcount = ch341->iocount; 323 | if (difference) { 324 | if (difference & CH341_CTI_C) { 325 | ch341->iocount.cts++; 326 | } 327 | if (difference & CH341_CTI_DS) { 328 | ch341->iocount.dsr++; 329 | } 330 | if (difference & CH341_CTRL_RI) { 331 | ch341->iocount.rng++; 332 | } 333 | if (difference & CH341_CTI_DC) { 334 | ch341->iocount.dcd++; 335 | } 336 | spin_unlock_irqrestore(&ch341->read_lock, flags); 337 | wake_up_interruptible(&ch341->wioctl); 338 | } else 339 | spin_unlock_irqrestore(&ch341->read_lock, flags); 340 | handled = 1; 341 | } 342 | if (type & CH341_CTT_O) { 343 | spin_lock_irqsave(&ch341->read_lock, flags); 344 | ch341->oldcount = ch341->iocount; 345 | ch341->iocount.overrun++; 346 | spin_unlock_irqrestore(&ch341->read_lock, flags); 347 | handled = 1; 348 | } 349 | if ((type & CH341_CTT_F) == CH341_CTT_F) { 350 | spin_lock_irqsave(&ch341->read_lock, flags); 351 | ch341->oldcount = ch341->iocount; 352 | ch341->iocount.frame++; 353 | spin_unlock_irqrestore(&ch341->read_lock, flags); 354 | handled = 1; 355 | } else if (type & CH341_CTT_P) { 356 | spin_lock_irqsave(&ch341->read_lock, flags); 357 | ch341->oldcount = ch341->iocount; 358 | ch341->iocount.parity++; 359 | spin_unlock_irqrestore(&ch341->read_lock, flags); 360 | handled = 1; 361 | } 362 | if (!handled) 363 | dev_dbg(&ch341->data->dev, 364 | "%s - unknown status received:" 365 | "len:%d, data0:0x%x, data1:0x%x\n", 366 | __func__, (int)len, data[0], data[1]); 367 | } 368 | 369 | static void ch341_ctrl_irq(struct urb *urb) 370 | { 371 | struct ch341 *ch341 = urb->context; 372 | unsigned char *data = urb->transfer_buffer; 373 | unsigned int len = urb->actual_length; 374 | int status = urb->status; 375 | int retval; 376 | 377 | switch (status) { 378 | case 0: 379 | /* success */ 380 | break; 381 | case -ECONNRESET: 382 | case -ENOENT: 383 | case -ESHUTDOWN: 384 | /* this urb is terminated, clean up */ 385 | dev_dbg(&ch341->data->dev, "%s - urb shutting down with status: %d\n", __func__, status); 386 | return; 387 | default: 388 | dev_dbg(&ch341->data->dev, "%s - nonzero urb status received: %d\n", __func__, status); 389 | goto exit; 390 | } 391 | 392 | usb_mark_last_busy(ch341->dev); 393 | ch341_update_status(ch341, data, len); 394 | exit: 395 | retval = usb_submit_urb(urb, GFP_ATOMIC); 396 | if (retval && retval != -EPERM) 397 | dev_err(&ch341->data->dev, "%s - usb_submit_urb failed: %d\n", __func__, retval); 398 | } 399 | 400 | static int ch341_submit_read_urb(struct ch341 *ch341, int index, gfp_t mem_flags) 401 | { 402 | int res; 403 | 404 | if (!test_and_clear_bit(index, &ch341->read_urbs_free)) 405 | return 0; 406 | 407 | res = usb_submit_urb(ch341->read_urbs[index], mem_flags); 408 | if (res) { 409 | if (res != -EPERM) { 410 | dev_err(&ch341->data->dev, "%s - usb_submit_urb failed: %d\n", __func__, res); 411 | } 412 | set_bit(index, &ch341->read_urbs_free); 413 | return res; 414 | } 415 | return 0; 416 | } 417 | 418 | static int ch341_submit_read_urbs(struct ch341 *ch341, gfp_t mem_flags) 419 | { 420 | int res; 421 | int i; 422 | 423 | for (i = 0; i < ch341->rx_buflimit; ++i) { 424 | res = ch341_submit_read_urb(ch341, i, mem_flags); 425 | if (res) 426 | return res; 427 | } 428 | return 0; 429 | } 430 | 431 | static void ch341_process_read_urb(struct ch341 *ch341, struct urb *urb) 432 | { 433 | if (!urb->actual_length) 434 | return; 435 | 436 | ch341->iocount.rx += urb->actual_length; 437 | tty_insert_flip_string(&ch341->port, urb->transfer_buffer, urb->actual_length); 438 | tty_flip_buffer_push(&ch341->port); 439 | } 440 | 441 | static void ch341_read_bulk_callback(struct urb *urb) 442 | { 443 | struct ch341_rb *rb = urb->context; 444 | struct ch341 *ch341 = rb->instance; 445 | int status = urb->status; 446 | 447 | if (!ch341->dev) { 448 | set_bit(rb->index, &ch341->read_urbs_free); 449 | dev_dbg(&ch341->data->dev, "%s - disconnected\n", __func__); 450 | return; 451 | } 452 | if (status) { 453 | set_bit(rb->index, &ch341->read_urbs_free); 454 | dev_dbg(&ch341->data->dev, "%s - non-zero urb status: %d\n", __func__, status); 455 | return; 456 | } 457 | usb_mark_last_busy(ch341->dev); 458 | ch341_process_read_urb(ch341, urb); 459 | set_bit(rb->index, &ch341->read_urbs_free); 460 | ch341_submit_read_urb(ch341, rb->index, GFP_ATOMIC); 461 | } 462 | 463 | /* data interface wrote those outgoing bytes */ 464 | static void ch341_write_bulk(struct urb *urb) 465 | { 466 | struct ch341_wb *wb = urb->context; 467 | struct ch341 *ch341 = wb->instance; 468 | unsigned long flags; 469 | int status = urb->status; 470 | 471 | if (status || (urb->actual_length != urb->transfer_buffer_length)) 472 | dev_vdbg(&ch341->data->dev, "%s - len %d/%d, status %d\n", __func__, urb->actual_length, 473 | urb->transfer_buffer_length, status); 474 | 475 | ch341->iocount.tx += urb->actual_length; 476 | spin_lock_irqsave(&ch341->write_lock, flags); 477 | ch341_write_done(ch341, wb); 478 | spin_unlock_irqrestore(&ch341->write_lock, flags); 479 | schedule_work(&ch341->work); 480 | } 481 | 482 | static void ch341_softint(struct work_struct *work) 483 | { 484 | struct ch341 *ch341 = container_of(work, struct ch341, work); 485 | 486 | tty_port_tty_wakeup(&ch341->port); 487 | } 488 | 489 | static int ch341_tty_install(struct tty_driver *driver, struct tty_struct *tty) 490 | { 491 | struct ch341 *ch341; 492 | int retval; 493 | 494 | ch341 = ch341_get_by_minor(tty->index); 495 | if (!ch341) 496 | return -ENODEV; 497 | 498 | retval = tty_standard_install(driver, tty); 499 | if (retval) 500 | goto error_init_termios; 501 | 502 | tty->driver_data = ch341; 503 | return 0; 504 | 505 | error_init_termios: 506 | tty_port_put(&ch341->port); 507 | return retval; 508 | } 509 | 510 | static int ch341_tty_open(struct tty_struct *tty, struct file *filp) 511 | { 512 | struct ch341 *ch341 = tty->driver_data; 513 | 514 | return tty_port_open(&ch341->port, tty, filp); 515 | } 516 | 517 | 518 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) 519 | static void ch341_port_dtr_rts(struct tty_port *port, bool raise) 520 | #else 521 | static void ch341_port_dtr_rts(struct tty_port *port, int raise) 522 | #endif 523 | { 524 | struct ch341 *ch341 = container_of(port, struct ch341, port); 525 | int res; 526 | 527 | if (raise) 528 | ch341->ctrlout |= CH341_CTO_D | CH341_CTO_R; 529 | else 530 | ch341->ctrlout &= ~(CH341_CTO_D | CH341_CTO_R); 531 | if (ch341->hardflow) 532 | ch341->ctrlout |= CH341_CTO_R; 533 | res = ch341_set_control(ch341, ch341->ctrlout); 534 | if (res) 535 | dev_err(&ch341->data->dev, "failed to set dtr/rts\n"); 536 | } 537 | 538 | static int ch341_port_activate(struct tty_port *port, struct tty_struct *tty) 539 | { 540 | struct ch341 *ch341 = container_of(port, struct ch341, port); 541 | int retval = -ENODEV; 542 | int i; 543 | 544 | mutex_lock(&ch341->mutex); 545 | if (ch341->disconnected) 546 | goto disconnected; 547 | 548 | retval = usb_autopm_get_interface(ch341->data); 549 | if (retval) 550 | goto error_get_interface; 551 | 552 | set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); 553 | ch341->data->needs_remote_wakeup = 1; 554 | retval = ch341_configure(ch341); 555 | if (retval) 556 | goto error_configure; 557 | 558 | ch341_tty_set_termios(tty, NULL); 559 | 560 | retval = usb_submit_urb(ch341->ctrlurb, GFP_KERNEL); 561 | if (retval) { 562 | dev_err(&ch341->data->dev, "%s - usb_submit_urb(ctrl cmd) failed\n", __func__); 563 | goto error_submit_urb; 564 | } 565 | 566 | retval = ch341_submit_read_urbs(ch341, GFP_KERNEL); 567 | if (retval) 568 | goto error_submit_read_urbs; 569 | usb_autopm_put_interface(ch341->data); 570 | 571 | mutex_unlock(&ch341->mutex); 572 | 573 | return 0; 574 | 575 | error_submit_read_urbs: 576 | for (i = 0; i < ch341->rx_buflimit; i++) 577 | usb_kill_urb(ch341->read_urbs[i]); 578 | error_submit_urb: 579 | usb_kill_urb(ch341->ctrlurb); 580 | error_configure: 581 | usb_autopm_put_interface(ch341->data); 582 | error_get_interface: 583 | disconnected: 584 | mutex_unlock(&ch341->mutex); 585 | 586 | return usb_translate_errors(retval); 587 | } 588 | 589 | static void ch341_port_destruct(struct tty_port *port) 590 | { 591 | struct ch341 *ch341 = container_of(port, struct ch341, port); 592 | 593 | ch341_release_minor(ch341); 594 | usb_put_intf(ch341->data); 595 | kfree(ch341); 596 | } 597 | 598 | static void ch341_port_shutdown(struct tty_port *port) 599 | { 600 | struct ch341 *ch341 = container_of(port, struct ch341, port); 601 | struct urb *urb; 602 | struct ch341_wb *wb; 603 | int i; 604 | 605 | usb_autopm_get_interface_no_resume(ch341->data); 606 | ch341->data->needs_remote_wakeup = 0; 607 | usb_autopm_put_interface(ch341->data); 608 | 609 | for (;;) { 610 | urb = usb_get_from_anchor(&ch341->delayed); 611 | if (!urb) 612 | break; 613 | wb = urb->context; 614 | wb->use = 0; 615 | usb_autopm_put_interface_async(ch341->data); 616 | } 617 | 618 | usb_kill_urb(ch341->ctrlurb); 619 | for (i = 0; i < CH341_NW; i++) 620 | usb_kill_urb(ch341->wb[i].urb); 621 | for (i = 0; i < ch341->rx_buflimit; i++) 622 | usb_kill_urb(ch341->read_urbs[i]); 623 | } 624 | 625 | static void ch341_tty_cleanup(struct tty_struct *tty) 626 | { 627 | struct ch341 *ch341 = tty->driver_data; 628 | 629 | tty_port_put(&ch341->port); 630 | } 631 | 632 | static void ch341_tty_hangup(struct tty_struct *tty) 633 | { 634 | struct ch341 *ch341 = tty->driver_data; 635 | 636 | tty_port_hangup(&ch341->port); 637 | } 638 | 639 | static void ch341_tty_close(struct tty_struct *tty, struct file *filp) 640 | { 641 | struct ch341 *ch341 = tty->driver_data; 642 | 643 | tty_port_close(&ch341->port, tty, filp); 644 | } 645 | 646 | static int ch341_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) 647 | { 648 | struct ch341 *ch341 = tty->driver_data; 649 | int stat; 650 | unsigned long flags; 651 | int wbn; 652 | struct ch341_wb *wb; 653 | 654 | if (!count) 655 | return 0; 656 | 657 | spin_lock_irqsave(&ch341->write_lock, flags); 658 | wbn = ch341_wb_alloc(ch341); 659 | if (wbn < 0) { 660 | spin_unlock_irqrestore(&ch341->write_lock, flags); 661 | return 0; 662 | } 663 | wb = &ch341->wb[wbn]; 664 | 665 | if (!ch341->dev) { 666 | wb->use = 0; 667 | spin_unlock_irqrestore(&ch341->write_lock, flags); 668 | return -ENODEV; 669 | } 670 | 671 | count = (count > ch341->writesize) ? ch341->writesize : count; 672 | memcpy(wb->buf, buf, count); 673 | wb->len = count; 674 | 675 | stat = usb_autopm_get_interface_async(ch341->data); 676 | if (stat) { 677 | wb->use = 0; 678 | spin_unlock_irqrestore(&ch341->write_lock, flags); 679 | return stat; 680 | } 681 | 682 | if (ch341->susp_count) { 683 | usb_anchor_urb(wb->urb, &ch341->delayed); 684 | spin_unlock_irqrestore(&ch341->write_lock, flags); 685 | return count; 686 | } 687 | 688 | stat = ch341_start_wb(ch341, wb); 689 | spin_unlock_irqrestore(&ch341->write_lock, flags); 690 | 691 | if (stat < 0) 692 | return stat; 693 | return count; 694 | } 695 | 696 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)) 697 | static unsigned int ch341_tty_write_room(struct tty_struct *tty) 698 | #else 699 | static int ch341_tty_write_room(struct tty_struct *tty) 700 | #endif 701 | { 702 | struct ch341 *ch341 = tty->driver_data; 703 | 704 | return ch341_wb_is_avail(ch341) ? ch341->writesize : 0; 705 | } 706 | 707 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0)) 708 | static unsigned int ch341_tty_chars_in_buffer(struct tty_struct *tty) 709 | #else 710 | static int ch341_tty_chars_in_buffer(struct tty_struct *tty) 711 | #endif 712 | { 713 | struct ch341 *ch341 = tty->driver_data; 714 | 715 | if (ch341->disconnected) 716 | return 0; 717 | 718 | return (CH341_NW - ch341_wb_is_avail(ch341)) * ch341->writesize; 719 | } 720 | 721 | static int ch341_tty_break_ctl(struct tty_struct *tty, int state) 722 | { 723 | struct ch341 *ch341 = tty->driver_data; 724 | int retval; 725 | uint16_t reg_contents; 726 | uint8_t *regbuf; 727 | const u16 regval = ((u16)CH341_RL << 8) | CH341_RB; 728 | 729 | regbuf = kmalloc(2, GFP_KERNEL); 730 | if (!regbuf) 731 | return -1; 732 | 733 | retval = ch341_control_in(ch341, CMD_R, regval, 0, regbuf, 2); 734 | if (retval < 0) { 735 | dev_err(&ch341->data->dev, "%s - ch341_control_in error (%d)\n", __func__, retval); 736 | goto out; 737 | } 738 | if (state != 0) { 739 | regbuf[0] &= ~CH341_NB; 740 | regbuf[1] &= ~CH341_L_ET; 741 | } else { 742 | regbuf[0] |= CH341_NB; 743 | regbuf[1] |= CH341_L_ET; 744 | } 745 | reg_contents = get_unaligned_le16(regbuf); 746 | 747 | retval = ch341_control_out(ch341, CMD_W, regval, reg_contents); 748 | if (retval < 0) 749 | dev_err(&ch341->data->dev, "%s - ch341_control_in error (%d)\n", __func__, retval); 750 | out: 751 | kfree(regbuf); 752 | return retval; 753 | } 754 | 755 | static int ch341_tty_tiocmget(struct tty_struct *tty) 756 | { 757 | struct ch341 *ch341 = tty->driver_data; 758 | unsigned long flags; 759 | unsigned int result; 760 | 761 | spin_lock_irqsave(&ch341->read_lock, flags); 762 | result = (ch341->ctrlout & CH341_CTO_D ? TIOCM_DTR : 0) | (ch341->ctrlout & CH341_CTO_R ? TIOCM_RTS : 0) | 763 | (ch341->ctrlin & CH341_CTI_C ? TIOCM_CTS : 0) | (ch341->ctrlin & CH341_CTI_DS ? TIOCM_DSR : 0) | 764 | (ch341->ctrlin & CH341_CTRL_RI ? TIOCM_RI : 0) | (ch341->ctrlin & CH341_CTI_DC ? TIOCM_CD : 0); 765 | spin_unlock_irqrestore(&ch341->read_lock, flags); 766 | 767 | return result; 768 | } 769 | 770 | static int ch341_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) 771 | { 772 | struct ch341 *ch341 = tty->driver_data; 773 | unsigned int newctrl; 774 | 775 | newctrl = ch341->ctrlout; 776 | set = (set & TIOCM_DTR ? CH341_CTO_D : 0) | (set & TIOCM_RTS ? CH341_CTO_R : 0); 777 | clear = (clear & TIOCM_DTR ? CH341_CTO_D : 0) | (clear & TIOCM_RTS ? CH341_CTO_R : 0); 778 | newctrl = (newctrl & ~clear) | set; 779 | if (C_CRTSCTS(tty)) 780 | newctrl |= CH341_CTO_R; 781 | if (ch341->ctrlout == newctrl) 782 | return 0; 783 | 784 | return ch341_set_control(ch341, ch341->ctrlout = newctrl); 785 | } 786 | 787 | static int ch341_get_icount(struct tty_struct *tty, struct serial_icounter_struct *icount) 788 | { 789 | struct ch341 *ch341 = tty->driver_data; 790 | struct async_icount cnow; 791 | unsigned long flags; 792 | 793 | spin_lock_irqsave(&ch341->read_lock, flags); 794 | cnow = ch341->iocount; 795 | spin_unlock_irqrestore(&ch341->read_lock, flags); 796 | 797 | icount->cts = cnow.cts; 798 | icount->dsr = cnow.dsr; 799 | icount->rng = cnow.rng; 800 | icount->dcd = cnow.dcd; 801 | icount->tx = cnow.tx; 802 | icount->rx = cnow.rx; 803 | icount->frame = cnow.frame; 804 | icount->parity = cnow.parity; 805 | icount->overrun = cnow.overrun; 806 | icount->brk = cnow.brk; 807 | icount->buf_overrun = cnow.buf_overrun; 808 | 809 | return 0; 810 | } 811 | 812 | static int get_serial_info(struct ch341 *ch341, struct serial_struct __user *info) 813 | { 814 | struct serial_struct tmp; 815 | 816 | if (!info) 817 | return -EINVAL; 818 | 819 | memset(&tmp, 0, sizeof(tmp)); 820 | tmp.flags = ASYNC_LOW_LATENCY; 821 | tmp.xmit_fifo_size = ch341->writesize; 822 | tmp.baud_base = le32_to_cpu(ch341->line.dwDTERate); 823 | tmp.close_delay = ch341->port.close_delay / 10; 824 | tmp.closing_wait = ch341->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : 825 | ch341->port.closing_wait / 10; 826 | if (copy_to_user(info, &tmp, sizeof(tmp))) 827 | return -EFAULT; 828 | else 829 | return 0; 830 | } 831 | 832 | static int set_serial_info(struct ch341 *ch341, struct serial_struct __user *newinfo) 833 | { 834 | struct serial_struct new_serial; 835 | unsigned int closing_wait, close_delay; 836 | int retval = 0; 837 | 838 | if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) 839 | return -EFAULT; 840 | 841 | close_delay = new_serial.close_delay * 10; 842 | closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : 843 | new_serial.closing_wait * 10; 844 | 845 | mutex_lock(&ch341->port.mutex); 846 | if (!capable(CAP_SYS_ADMIN)) { 847 | if ((close_delay != ch341->port.close_delay) || (closing_wait != ch341->port.closing_wait)) 848 | retval = -EPERM; 849 | else 850 | retval = -EOPNOTSUPP; 851 | } else { 852 | ch341->port.close_delay = close_delay; 853 | ch341->port.closing_wait = closing_wait; 854 | } 855 | mutex_unlock(&ch341->port.mutex); 856 | 857 | return retval; 858 | } 859 | 860 | static int wait_serial_change(struct ch341 *ch341, unsigned long arg) 861 | { 862 | int rv = 0; 863 | DECLARE_WAITQUEUE(wait, current); 864 | struct async_icount old, new; 865 | 866 | do { 867 | spin_lock_irq(&ch341->read_lock); 868 | old = ch341->oldcount; 869 | new = ch341->iocount; 870 | ch341->oldcount = new; 871 | spin_unlock_irq(&ch341->read_lock); 872 | 873 | if ((arg & TIOCM_CTS) && old.cts != new.cts) 874 | break; 875 | if ((arg & TIOCM_DSR) && old.dsr != new.dsr) 876 | break; 877 | if ((arg & TIOCM_RI) && old.rng != new.rng) 878 | break; 879 | if ((arg & TIOCM_CD) && old.dcd != new.dcd) 880 | break; 881 | 882 | add_wait_queue(&ch341->wioctl, &wait); 883 | set_current_state(TASK_INTERRUPTIBLE); 884 | schedule(); 885 | remove_wait_queue(&ch341->wioctl, &wait); 886 | if (ch341->disconnected) { 887 | rv = -ENODEV; 888 | } else { 889 | if (signal_pending(current)) 890 | rv = -ERESTARTSYS; 891 | } 892 | } while (!rv); 893 | 894 | return rv; 895 | } 896 | 897 | static int get_serial_usage(struct ch341 *ch341, struct serial_icounter_struct __user *count) 898 | { 899 | struct serial_icounter_struct icount; 900 | int rv = 0; 901 | 902 | memset(&icount, 0, sizeof(icount)); 903 | icount.cts = ch341->iocount.cts; 904 | icount.dsr = ch341->iocount.dsr; 905 | icount.rng = ch341->iocount.rng; 906 | icount.dcd = ch341->iocount.dcd; 907 | icount.tx = ch341->iocount.tx; 908 | icount.rx = ch341->iocount.rx; 909 | icount.frame = ch341->iocount.frame; 910 | icount.overrun = ch341->iocount.overrun; 911 | icount.parity = ch341->iocount.parity; 912 | icount.brk = ch341->iocount.brk; 913 | icount.buf_overrun = ch341->iocount.buf_overrun; 914 | 915 | if (copy_to_user(count, &icount, sizeof(icount)) > 0) 916 | rv = -EFAULT; 917 | 918 | return rv; 919 | } 920 | 921 | static int ch341_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) 922 | { 923 | struct ch341 *ch341 = tty->driver_data; 924 | int rv = -ENOIOCTLCMD; 925 | 926 | switch (cmd) { 927 | case TIOCGSERIAL: /* gets serial port data */ 928 | rv = get_serial_info(ch341, (struct serial_struct __user *)arg); 929 | break; 930 | case TIOCSSERIAL: 931 | rv = set_serial_info(ch341, (struct serial_struct __user *)arg); 932 | break; 933 | case TIOCMIWAIT: 934 | rv = usb_autopm_get_interface(ch341->data); 935 | if (rv < 0) { 936 | rv = -EIO; 937 | break; 938 | } 939 | rv = wait_serial_change(ch341, arg); 940 | usb_autopm_put_interface(ch341->data); 941 | break; 942 | case TIOCGICOUNT: 943 | rv = get_serial_usage(ch341, (struct serial_icounter_struct __user *)arg); 944 | break; 945 | } 946 | 947 | return rv; 948 | } 949 | 950 | static int ch341_get(unsigned int baval, unsigned char *factor, unsigned char *divisor) 951 | { 952 | unsigned char a; 953 | unsigned char b; 954 | unsigned long c; 955 | 956 | switch (baval) { 957 | case 921600: 958 | a = 0xf3; 959 | b = 7; 960 | break; 961 | case 307200: 962 | a = 0xd9; 963 | b = 7; 964 | break; 965 | default: 966 | if (baval > 6000000 / 255) { 967 | b = 3; 968 | c = 6000000; 969 | } else if (baval > 750000 / 255) { 970 | b = 2; 971 | c = 750000; 972 | } else if (baval > 93750 / 255) { 973 | b = 1; 974 | c = 93750; 975 | } else { 976 | b = 0; 977 | c = 11719; 978 | } 979 | a = (unsigned char)(c / baval); 980 | if (a == 0 || a == 0xFF) 981 | return -EINVAL; 982 | if ((c / a - baval) > (baval - c / (a + 1))) 983 | a++; 984 | a = 256 - a; 985 | break; 986 | } 987 | *factor = a; 988 | *divisor = b; 989 | 990 | return 0; 991 | } 992 | 993 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) 994 | static void ch341_tty_set_termios(struct tty_struct *tty, const struct ktermios *termios_old) 995 | #else 996 | static void ch341_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) 997 | #endif 998 | { 999 | struct ch341 *ch341 = tty->driver_data; 1000 | struct ktermios *termios = &tty->termios; 1001 | struct usb_ch341_line_coding newline; 1002 | int newctrl = ch341->ctrlout; 1003 | 1004 | unsigned char divisor = 0; 1005 | unsigned char reg_count = 0; 1006 | unsigned char factor = 0; 1007 | unsigned char reg_value = 0; 1008 | unsigned short value = 0; 1009 | unsigned short index = 0; 1010 | 1011 | if (termios_old && !tty_termios_hw_change(&tty->termios, termios_old)) { 1012 | return; 1013 | } 1014 | 1015 | newline.dwDTERate = tty_get_baud_rate(tty); 1016 | 1017 | if (newline.dwDTERate == 0) 1018 | newline.dwDTERate = 9600; 1019 | ch341_get(newline.dwDTERate, &factor, &divisor); 1020 | 1021 | newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 1; 1022 | if (newline.bCharFormat == 2) 1023 | reg_value |= CH341_L_SB; 1024 | 1025 | newline.bParityType = termios->c_cflag & PARENB ? 1026 | (termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 1027 | 0; 1028 | 1029 | switch (newline.bParityType) { 1030 | case 0x01: 1031 | reg_value |= CH341_L_PO; 1032 | break; 1033 | case 0x02: 1034 | reg_value |= CH341_L_PE; 1035 | break; 1036 | case 0x03: 1037 | reg_value |= CH341_L_PM; 1038 | break; 1039 | case 0x04: 1040 | reg_value |= CH341_L_PS; 1041 | break; 1042 | default: 1043 | break; 1044 | } 1045 | 1046 | switch (termios->c_cflag & CSIZE) { 1047 | case CS5: 1048 | newline.bDataBits = 5; 1049 | reg_value |= CH341_L_D5; 1050 | break; 1051 | case CS6: 1052 | newline.bDataBits = 6; 1053 | reg_value |= CH341_L_D6; 1054 | break; 1055 | case CS7: 1056 | newline.bDataBits = 7; 1057 | reg_value |= CH341_L_D7; 1058 | break; 1059 | case CS8: 1060 | default: 1061 | newline.bDataBits = 8; 1062 | reg_value |= CH341_L_D8; 1063 | break; 1064 | } 1065 | 1066 | ch341->clocal = ((termios->c_cflag & CLOCAL) != 0); 1067 | 1068 | if (C_BAUD(tty) == B0) { 1069 | newline.dwDTERate = ch341->line.dwDTERate; 1070 | newctrl &= ~CH341_CTO_D; 1071 | } else if (termios_old && (termios_old->c_cflag & CBAUD) == B0) { 1072 | newctrl |= CH341_CTO_D; 1073 | } 1074 | 1075 | reg_value |= 0xc0; 1076 | reg_count |= 0x9c; 1077 | 1078 | value |= reg_count; 1079 | value |= (unsigned short)reg_value << 8; 1080 | index |= 0x80 | divisor; 1081 | index |= (unsigned short)factor << 8; 1082 | ch341_control_out(ch341, CMD_C1, value, index); 1083 | 1084 | if (newctrl != ch341->ctrlout) 1085 | ch341_set_control(ch341, ch341->ctrlout = newctrl); 1086 | 1087 | if (memcmp(&ch341->line, &newline, sizeof newline)) 1088 | memcpy(&ch341->line, &newline, sizeof newline); 1089 | if (C_CRTSCTS(tty)) { 1090 | ch341_control_out(ch341, CMD_W, 0x2727, 0x0101); 1091 | newctrl |= CH341_CTO_R; 1092 | ch341_set_control(ch341, ch341->ctrlout = newctrl); 1093 | ch341->hardflow = true; 1094 | } else { 1095 | ch341_control_out(ch341, CMD_W, 0x2727, 0x0000); 1096 | ch341->hardflow = false; 1097 | } 1098 | } 1099 | 1100 | static const struct tty_port_operations ch341_port_ops = { 1101 | .dtr_rts = ch341_port_dtr_rts, 1102 | .shutdown = ch341_port_shutdown, 1103 | .activate = ch341_port_activate, 1104 | .destruct = ch341_port_destruct, 1105 | }; 1106 | 1107 | /* 1108 | * USB probe and disconnect routines. 1109 | */ 1110 | static void ch341_write_buffers_free(struct ch341 *ch341) 1111 | { 1112 | int i; 1113 | struct ch341_wb *wb; 1114 | struct usb_device *usb_dev = interface_to_usbdev(ch341->data); 1115 | 1116 | for (wb = &ch341->wb[0], i = 0; i < CH341_NW; i++, wb++) 1117 | usb_free_coherent(usb_dev, ch341->writesize, wb->buf, wb->dmah); 1118 | } 1119 | 1120 | static void ch341_read_buffers_free(struct ch341 *ch341) 1121 | { 1122 | struct usb_device *usb_dev = interface_to_usbdev(ch341->data); 1123 | int i; 1124 | 1125 | for (i = 0; i < ch341->rx_buflimit; i++) 1126 | usb_free_coherent(usb_dev, ch341->readsize, ch341->read_buffers[i].base, ch341->read_buffers[i].dma); 1127 | } 1128 | 1129 | static int ch341_write_buffers_alloc(struct ch341 *ch341) 1130 | { 1131 | int i; 1132 | struct ch341_wb *wb; 1133 | 1134 | for (wb = &ch341->wb[0], i = 0; i < CH341_NW; i++, wb++) { 1135 | wb->buf = usb_alloc_coherent(ch341->dev, ch341->writesize, GFP_KERNEL, &wb->dmah); 1136 | if (!wb->buf) { 1137 | while (i != 0) { 1138 | --i; 1139 | --wb; 1140 | usb_free_coherent(ch341->dev, ch341->writesize, wb->buf, wb->dmah); 1141 | } 1142 | return -ENOMEM; 1143 | } 1144 | } 1145 | return 0; 1146 | } 1147 | 1148 | static int ch341_probe(struct usb_interface *intf, const struct usb_device_id *id) 1149 | { 1150 | struct usb_interface *data_interface; 1151 | struct usb_endpoint_descriptor *epctrl = NULL; 1152 | struct usb_endpoint_descriptor *epread = NULL; 1153 | struct usb_endpoint_descriptor *epwrite = NULL; 1154 | struct usb_device *usb_dev = interface_to_usbdev(intf); 1155 | struct ch341 *ch341; 1156 | int minor; 1157 | int ctrlsize, readsize; 1158 | u8 *buf; 1159 | unsigned long quirks; 1160 | int num_rx_buf = CH341_NR; 1161 | int i; 1162 | struct device *tty_dev; 1163 | int rv = -ENOMEM; 1164 | 1165 | /* normal quirks */ 1166 | quirks = (unsigned long)id->driver_info; 1167 | 1168 | data_interface = usb_ifnum_to_if(usb_dev, 0); 1169 | 1170 | if (intf != data_interface) 1171 | return -ENODEV; 1172 | 1173 | if (data_interface->cur_altsetting->desc.bNumEndpoints < 2 || 1174 | data_interface->cur_altsetting->desc.bNumEndpoints == 0) 1175 | return -EINVAL; 1176 | 1177 | epread = &data_interface->cur_altsetting->endpoint[0].desc; 1178 | epwrite = &data_interface->cur_altsetting->endpoint[1].desc; 1179 | epctrl = &data_interface->cur_altsetting->endpoint[2].desc; 1180 | 1181 | if (!usb_endpoint_dir_in(epread)) { 1182 | swap(epread, epwrite); 1183 | } 1184 | 1185 | ch341 = kzalloc(sizeof(struct ch341), GFP_KERNEL); 1186 | if (ch341 == NULL) 1187 | goto alloc_fail; 1188 | 1189 | minor = ch341_alloc_minor(ch341); 1190 | if (minor < 0) { 1191 | dev_err(&intf->dev, "no more free ch341 devices\n"); 1192 | kfree(ch341); 1193 | return -ENODEV; 1194 | } 1195 | 1196 | ctrlsize = usb_endpoint_maxp(epctrl); 1197 | readsize = usb_endpoint_maxp(epread) * (quirks == SINGLE_RX_URB ? 1 : 1); 1198 | ch341->writesize = usb_endpoint_maxp(epwrite) * 20; 1199 | ch341->data = data_interface; 1200 | ch341->minor = minor; 1201 | ch341->dev = usb_dev; 1202 | ch341->ctrlsize = ctrlsize; 1203 | ch341->readsize = readsize; 1204 | ch341->rx_buflimit = num_rx_buf; 1205 | 1206 | INIT_WORK(&ch341->work, ch341_softint); 1207 | init_waitqueue_head(&ch341->wioctl); 1208 | spin_lock_init(&ch341->write_lock); 1209 | spin_lock_init(&ch341->read_lock); 1210 | mutex_init(&ch341->mutex); 1211 | ch341->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); 1212 | tty_port_init(&ch341->port); 1213 | ch341->port.ops = &ch341_port_ops; 1214 | init_usb_anchor(&ch341->delayed); 1215 | ch341->quirks = quirks; 1216 | 1217 | buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &ch341->ctrl_dma); 1218 | if (!buf) 1219 | goto alloc_fail2; 1220 | ch341->ctrl_buffer = buf; 1221 | 1222 | if (ch341_write_buffers_alloc(ch341) < 0) 1223 | goto alloc_fail4; 1224 | 1225 | ch341->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); 1226 | if (!ch341->ctrlurb) 1227 | goto alloc_fail5; 1228 | 1229 | for (i = 0; i < num_rx_buf; i++) { 1230 | struct ch341_rb *rb = &(ch341->read_buffers[i]); 1231 | struct urb *urb; 1232 | 1233 | rb->base = usb_alloc_coherent(ch341->dev, readsize, GFP_KERNEL, &rb->dma); 1234 | if (!rb->base) 1235 | goto alloc_fail6; 1236 | rb->index = i; 1237 | rb->instance = ch341; 1238 | 1239 | urb = usb_alloc_urb(0, GFP_KERNEL); 1240 | if (!urb) 1241 | goto alloc_fail6; 1242 | 1243 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1244 | urb->transfer_dma = rb->dma; 1245 | usb_fill_bulk_urb(urb, ch341->dev, ch341->rx_endpoint, rb->base, ch341->readsize, 1246 | ch341_read_bulk_callback, rb); 1247 | 1248 | ch341->read_urbs[i] = urb; 1249 | __set_bit(i, &ch341->read_urbs_free); 1250 | } 1251 | for (i = 0; i < CH341_NW; i++) { 1252 | struct ch341_wb *snd = &(ch341->wb[i]); 1253 | 1254 | snd->urb = usb_alloc_urb(0, GFP_KERNEL); 1255 | if (snd->urb == NULL) 1256 | goto alloc_fail7; 1257 | 1258 | usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), NULL, 1259 | ch341->writesize, ch341_write_bulk, snd); 1260 | snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1261 | snd->instance = ch341; 1262 | } 1263 | 1264 | usb_set_intfdata(intf, ch341); 1265 | 1266 | usb_fill_int_urb(ch341->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), ch341->ctrl_buffer, 1267 | ctrlsize, ch341_ctrl_irq, ch341, epctrl->bInterval ? epctrl->bInterval : 16); 1268 | ch341->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1269 | ch341->ctrlurb->transfer_dma = ch341->ctrl_dma; 1270 | 1271 | dev_info(&intf->dev, "ttyCH341USB%d: ch341 USB device\n", minor); 1272 | 1273 | usb_driver_claim_interface(&ch341_driver, data_interface, ch341); 1274 | usb_set_intfdata(data_interface, ch341); 1275 | 1276 | usb_get_intf(data_interface); 1277 | tty_dev = tty_port_register_device(&ch341->port, ch341_tty_driver, minor, &data_interface->dev); 1278 | if (IS_ERR(tty_dev)) { 1279 | rv = PTR_ERR(tty_dev); 1280 | goto alloc_fail7; 1281 | } 1282 | return 0; 1283 | 1284 | alloc_fail7: 1285 | usb_set_intfdata(intf, NULL); 1286 | for (i = 0; i < CH341_NW; i++) 1287 | usb_free_urb(ch341->wb[i].urb); 1288 | alloc_fail6: 1289 | for (i = 0; i < num_rx_buf; i++) 1290 | usb_free_urb(ch341->read_urbs[i]); 1291 | ch341_read_buffers_free(ch341); 1292 | usb_free_urb(ch341->ctrlurb); 1293 | alloc_fail5: 1294 | ch341_write_buffers_free(ch341); 1295 | alloc_fail4: 1296 | usb_free_coherent(usb_dev, ctrlsize, ch341->ctrl_buffer, ch341->ctrl_dma); 1297 | alloc_fail2: 1298 | ch341_release_minor(ch341); 1299 | kfree(ch341); 1300 | alloc_fail: 1301 | return rv; 1302 | } 1303 | 1304 | static void stop_data_traffic(struct ch341 *ch341) 1305 | { 1306 | int i; 1307 | 1308 | usb_kill_urb(ch341->ctrlurb); 1309 | for (i = 0; i < CH341_NW; i++) 1310 | usb_kill_urb(ch341->wb[i].urb); 1311 | for (i = 0; i < ch341->rx_buflimit; i++) 1312 | usb_kill_urb(ch341->read_urbs[i]); 1313 | 1314 | cancel_work_sync(&ch341->work); 1315 | } 1316 | 1317 | static void ch341_disconnect(struct usb_interface *intf) 1318 | { 1319 | struct ch341 *ch341 = usb_get_intfdata(intf); 1320 | struct usb_device *usb_dev = interface_to_usbdev(intf); 1321 | struct tty_struct *tty; 1322 | int i; 1323 | 1324 | if (!ch341) 1325 | return; 1326 | mutex_lock(&ch341->mutex); 1327 | ch341->disconnected = true; 1328 | wake_up_all(&ch341->wioctl); 1329 | usb_set_intfdata(ch341->data, NULL); 1330 | mutex_unlock(&ch341->mutex); 1331 | 1332 | tty = tty_port_tty_get(&ch341->port); 1333 | if (tty) { 1334 | tty_vhangup(tty); 1335 | tty_kref_put(tty); 1336 | } 1337 | stop_data_traffic(ch341); 1338 | tty_unregister_device(ch341_tty_driver, ch341->minor); 1339 | 1340 | usb_free_urb(ch341->ctrlurb); 1341 | for (i = 0; i < CH341_NW; i++) 1342 | usb_free_urb(ch341->wb[i].urb); 1343 | for (i = 0; i < ch341->rx_buflimit; i++) 1344 | usb_free_urb(ch341->read_urbs[i]); 1345 | ch341_write_buffers_free(ch341); 1346 | usb_free_coherent(usb_dev, ch341->ctrlsize, ch341->ctrl_buffer, ch341->ctrl_dma); 1347 | ch341_read_buffers_free(ch341); 1348 | usb_driver_release_interface(&ch341_driver, ch341->data); 1349 | tty_port_put(&ch341->port); 1350 | dev_info(&intf->dev, "%s\n", "ch341 usb device disconnect."); 1351 | } 1352 | 1353 | #ifdef CONFIG_PM 1354 | static int ch341_suspend(struct usb_interface *intf, pm_message_t message) 1355 | { 1356 | struct ch341 *ch341 = usb_get_intfdata(intf); 1357 | int cnt; 1358 | 1359 | spin_lock_irq(&ch341->write_lock); 1360 | if (PMSG_IS_AUTO(message)) { 1361 | if (ch341->transmitting) { 1362 | spin_unlock_irq(&ch341->write_lock); 1363 | return -EBUSY; 1364 | } 1365 | } 1366 | cnt = ch341->susp_count++; 1367 | spin_unlock_irq(&ch341->write_lock); 1368 | if (cnt) 1369 | return 0; 1370 | 1371 | stop_data_traffic(ch341); 1372 | 1373 | return 0; 1374 | } 1375 | 1376 | static int ch341_resume(struct usb_interface *intf) 1377 | { 1378 | struct ch341 *ch341 = usb_get_intfdata(intf); 1379 | struct urb *urb; 1380 | int rv = 0; 1381 | 1382 | spin_lock_irq(&ch341->write_lock); 1383 | if (--ch341->susp_count) 1384 | goto out; 1385 | 1386 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) 1387 | if (tty_port_initialized(&ch341->port)) { 1388 | #else 1389 | if (test_bit(ASYNCB_INITIALIZED, &ch341->port.flags)) { 1390 | #endif 1391 | rv = usb_submit_urb(ch341->ctrlurb, GFP_ATOMIC); 1392 | for (;;) { 1393 | urb = usb_get_from_anchor(&ch341->delayed); 1394 | if (!urb) 1395 | break; 1396 | 1397 | ch341_start_wb(ch341, urb->context); 1398 | } 1399 | if (rv < 0) 1400 | goto out; 1401 | rv = ch341_submit_read_urbs(ch341, GFP_ATOMIC); 1402 | } 1403 | out: 1404 | spin_unlock_irq(&ch341->write_lock); 1405 | return rv; 1406 | } 1407 | 1408 | static int ch341_reset_resume(struct usb_interface *intf) 1409 | { 1410 | struct ch341 *ch341 = usb_get_intfdata(intf); 1411 | 1412 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) 1413 | if (tty_port_initialized(&ch341->port)) 1414 | #else 1415 | if (test_bit(ASYNCB_INITIALIZED, &ch341->port.flags)) 1416 | #endif 1417 | tty_port_tty_hangup(&ch341->port, false); 1418 | 1419 | return ch341_resume(intf); 1420 | } 1421 | #endif /* CONFIG_PM */ 1422 | 1423 | /* 1424 | * USB driver structure. 1425 | */ 1426 | static const struct usb_device_id ch341_ids[] = { { USB_DEVICE(0x1a86, 0x7523) }, /* ch340 chip */ 1427 | { USB_DEVICE(0x1a86, 0x7522) }, /* ch340k chip */ 1428 | { USB_DEVICE(0x1a86, 0x5523) }, /* ch341 chip */ 1429 | { USB_DEVICE(0x1a86, 0xe523) }, /* ch330 chip */ 1430 | { USB_DEVICE(0x4348, 0x5523) }, /* ch340 custom chip */ 1431 | {} }; 1432 | 1433 | MODULE_DEVICE_TABLE(usb, ch341_ids); 1434 | 1435 | static struct usb_driver ch341_driver = { 1436 | .name = "usb_ch341", 1437 | .probe = ch341_probe, 1438 | .disconnect = ch341_disconnect, 1439 | #ifdef CONFIG_PM 1440 | .suspend = ch341_suspend, 1441 | .resume = ch341_resume, 1442 | .reset_resume = ch341_reset_resume, 1443 | #endif 1444 | .id_table = ch341_ids, 1445 | #ifdef CONFIG_PM 1446 | .supports_autosuspend = 1, 1447 | #endif 1448 | .disable_hub_initiated_lpm = 1, 1449 | }; 1450 | 1451 | /* 1452 | * TTY driver structures. 1453 | */ 1454 | static const struct tty_operations ch341_ops = { 1455 | .install = ch341_tty_install, 1456 | .open = ch341_tty_open, 1457 | .close = ch341_tty_close, 1458 | .cleanup = ch341_tty_cleanup, 1459 | .hangup = ch341_tty_hangup, 1460 | .write = ch341_tty_write, 1461 | .write_room = ch341_tty_write_room, 1462 | .ioctl = ch341_tty_ioctl, 1463 | .chars_in_buffer = ch341_tty_chars_in_buffer, 1464 | .break_ctl = ch341_tty_break_ctl, 1465 | .set_termios = ch341_tty_set_termios, 1466 | .tiocmget = ch341_tty_tiocmget, 1467 | .tiocmset = ch341_tty_tiocmset, 1468 | .get_icount = ch341_get_icount, 1469 | }; 1470 | 1471 | static int __init ch341_init(void) 1472 | { 1473 | int retval; 1474 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) 1475 | ch341_tty_driver = tty_alloc_driver(CH341_TTY_MINORS, TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); 1476 | if (IS_ERR(ch341_tty_driver)) 1477 | return PTR_ERR(ch341_tty_driver); 1478 | #else 1479 | ch341_tty_driver = alloc_tty_driver(CH341_TTY_MINORS); 1480 | if (!ch341_tty_driver) 1481 | return -ENOMEM; 1482 | #endif 1483 | ch341_tty_driver->driver_name = "ch341_uart", ch341_tty_driver->name = "ttyCH341USB", 1484 | ch341_tty_driver->major = CH341_TTY_MAJOR, ch341_tty_driver->minor_start = 0, 1485 | ch341_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, ch341_tty_driver->subtype = SERIAL_TYPE_NORMAL, 1486 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) 1487 | ch341_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 1488 | #endif 1489 | ch341_tty_driver->init_termios = tty_std_termios; 1490 | ch341_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; 1491 | tty_set_operations(ch341_tty_driver, &ch341_ops); 1492 | 1493 | retval = tty_register_driver(ch341_tty_driver); 1494 | if (retval) { 1495 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) 1496 | tty_driver_kref_put(ch341_tty_driver); 1497 | #else 1498 | put_tty_driver(ch341_tty_driver); 1499 | #endif 1500 | return retval; 1501 | } 1502 | 1503 | retval = usb_register(&ch341_driver); 1504 | if (retval) { 1505 | tty_unregister_driver(ch341_tty_driver); 1506 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) 1507 | tty_driver_kref_put(ch341_tty_driver); 1508 | #else 1509 | put_tty_driver(ch341_tty_driver); 1510 | #endif 1511 | return retval; 1512 | } 1513 | 1514 | printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); 1515 | printk(KERN_INFO KBUILD_MODNAME ": " VERSION_DESC "\n"); 1516 | 1517 | return 0; 1518 | } 1519 | 1520 | static void __exit ch341_exit(void) 1521 | { 1522 | usb_deregister(&ch341_driver); 1523 | tty_unregister_driver(ch341_tty_driver); 1524 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) 1525 | tty_driver_kref_put(ch341_tty_driver); 1526 | #else 1527 | put_tty_driver(ch341_tty_driver); 1528 | #endif 1529 | idr_destroy(&ch341_minors); 1530 | printk(KERN_INFO KBUILD_MODNAME ": " 1531 | "ch341 driver exit.\n"); 1532 | } 1533 | 1534 | module_init(ch341_init); 1535 | module_exit(ch341_exit); 1536 | 1537 | MODULE_AUTHOR(DRIVER_AUTHOR); 1538 | MODULE_DESCRIPTION(DRIVER_DESC); 1539 | MODULE_VERSION(VERSION_DESC); 1540 | MODULE_LICENSE("GPL"); 1541 | MODULE_ALIAS_CHARDEV_MAJOR(CH341_TTY_MAJOR); 1542 | -------------------------------------------------------------------------------- /linux/driver/ch341.h: -------------------------------------------------------------------------------- 1 | #ifndef _CH341_H 2 | #define _CH341_H 3 | 4 | /* 5 | * Baud rate and default timeout 6 | */ 7 | #define DEFAULT_BAUD_RATE 9600 8 | #define DEFAULT_TIMEOUT 2000 9 | 10 | /* 11 | * CMSPAR, some architectures can't have space and mark parity. 12 | */ 13 | #ifndef CMSPAR 14 | #define CMSPAR 0 15 | #endif 16 | 17 | /* 18 | * Major and minor numbers. 19 | */ 20 | #define CH341_TTY_MAJOR 169 21 | #define CH341_TTY_MINORS 256 22 | 23 | /* 24 | * Requests. 25 | */ 26 | #define USB_RT_CH341 (USB_TYPE_CLASS | USB_RECIP_INTERFACE) 27 | 28 | #define CMD_R 0x95 29 | #define CMD_W 0x9A 30 | #define CMD_C1 0xA1 31 | #define CMD_C2 0xA4 32 | #define CMD_C3 0x5F 33 | 34 | #define CH341_CTO_O 0x10 35 | #define CH341_CTO_D 0x20 36 | #define CH341_CTO_R 0x40 37 | #define CH341_CTI_C 0x01 38 | #define CH341_CTI_DS 0x02 39 | #define CH341_CTRL_RI 0x04 40 | #define CH341_CTI_DC 0x08 41 | #define CH341_CTI_ST 0x0f 42 | 43 | #define CH341_CTT_M BIT(3) 44 | #define CH341_CTT_F (BIT(2) | BIT(6)) 45 | #define CH341_CTT_P BIT(2) 46 | #define CH341_CTT_O BIT(1) 47 | 48 | #define CH341_L_ER 0x80 49 | #define CH341_L_ET 0x40 50 | #define CH341_L_PS 0x38 51 | #define CH341_L_PM 0x28 52 | #define CH341_L_PE 0x18 53 | #define CH341_L_PO 0x08 54 | #define CH341_L_SB 0x04 55 | #define CH341_L_D8 0x03 56 | #define CH341_L_D7 0x02 57 | #define CH341_L_D6 0x01 58 | #define CH341_L_D5 0x00 59 | 60 | #define CH341_RB 0x05 61 | #define CH341_RL 0x18 62 | #define CH341_NB 0x01 63 | 64 | #define CH341_NW 2 65 | #define CH341_NR 2 66 | 67 | struct ch341_wb { 68 | unsigned char *buf; 69 | dma_addr_t dmah; 70 | int len; 71 | int use; 72 | struct urb *urb; 73 | struct ch341 *instance; 74 | }; 75 | 76 | struct ch341_rb { 77 | int size; 78 | unsigned char *base; 79 | dma_addr_t dma; 80 | int index; 81 | struct ch341 *instance; 82 | }; 83 | 84 | struct usb_ch341_line_coding { 85 | __le32 dwDTERate; 86 | __u8 bCharFormat; 87 | #define USB_CH341_1_STOP_BITS 0 88 | #define USB_CH341_1_5_STOP_BITS 1 89 | #define USB_CH341_2_STOP_BITS 2 90 | 91 | __u8 bParityType; 92 | #define USB_CH341_NO_PARITY 0 93 | #define USB_CH341_ODD_PARITY 1 94 | #define USB_CH341_EVEN_PARITY 2 95 | #define USB_CH341_MARK_PARITY 3 96 | #define USB_CH341_SPACE_PARITY 4 97 | 98 | __u8 bDataBits; 99 | } __attribute__((packed)); 100 | 101 | struct ch341 { 102 | struct usb_device *dev; /* the corresponding usb device */ 103 | struct usb_interface *data; /* data interface */ 104 | struct tty_port port; /* our tty port data */ 105 | struct urb *ctrlurb; /* urbs */ 106 | u8 *ctrl_buffer; /* buffers of urbs */ 107 | dma_addr_t ctrl_dma; /* dma handles of buffers */ 108 | struct ch341_wb wb[CH341_NW]; 109 | unsigned long read_urbs_free; 110 | struct urb *read_urbs[CH341_NR]; 111 | struct ch341_rb read_buffers[CH341_NR]; 112 | int rx_buflimit; 113 | int rx_endpoint; 114 | spinlock_t read_lock; 115 | int write_used; /* number of non-empty write buffers */ 116 | int transmitting; 117 | spinlock_t write_lock; 118 | struct mutex mutex; 119 | bool disconnected; 120 | struct usb_ch341_line_coding line; /* bits, stop, parity */ 121 | struct work_struct work; /* work queue entry for line discipline waking up */ 122 | unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ 123 | unsigned int ctrlout; /* output control lines (DTR, RTS) */ 124 | struct async_icount iocount; /* counters for control line changes */ 125 | struct async_icount oldcount; /* for comparison of counter */ 126 | wait_queue_head_t wioctl; /* for ioctl */ 127 | unsigned int writesize; /* max packet size for the output bulk endpoint */ 128 | unsigned int readsize, ctrlsize; /* buffer sizes for freeing */ 129 | unsigned int minor; /* ch341 minor number */ 130 | unsigned char clocal; /* termios CLOCAL */ 131 | unsigned int susp_count; /* number of suspended interfaces */ 132 | u8 bInterval; 133 | struct usb_anchor delayed; /* writes queued for a device about to be woken */ 134 | unsigned long quirks; 135 | bool hardflow; 136 | }; 137 | 138 | /* constants describing various quirks and errors */ 139 | #define NO_UNION_NORMAL BIT(0) 140 | #define SINGLE_RX_URB BIT(1) 141 | #define NO_CAP_LINE BIT(2) 142 | #define NO_DATA_INTERFACE BIT(4) 143 | #define IGNORE_DEVICE BIT(5) 144 | #define QUIRK_CONTROL_LINE_STATE BIT(6) 145 | #define CLEAR_HALT_CONDITIONS BIT(7) 146 | #endif 147 | -------------------------------------------------------------------------------- /macos/CH34X_DRV_INSTAL_INSTRUCTIONS.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/macos/CH34X_DRV_INSTAL_INSTRUCTIONS.pdf -------------------------------------------------------------------------------- /macos/CH34xVCPDriver.dmg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/macos/CH34xVCPDriver.dmg -------------------------------------------------------------------------------- /macos/CH34xVCPDriver.pkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/macos/CH34xVCPDriver.pkg -------------------------------------------------------------------------------- /windows/CH341M64.SYS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/CH341M64.SYS -------------------------------------------------------------------------------- /windows/CH341PORTS.DLL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/CH341PORTS.DLL -------------------------------------------------------------------------------- /windows/CH341PORTSA64.DLL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/CH341PORTSA64.DLL -------------------------------------------------------------------------------- /windows/CH341PT.DLL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/CH341PT.DLL -------------------------------------------------------------------------------- /windows/CH341PTA64.DLL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/CH341PTA64.DLL -------------------------------------------------------------------------------- /windows/CH341S64.SYS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/CH341S64.SYS -------------------------------------------------------------------------------- /windows/CH341S98.SYS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/CH341S98.SYS -------------------------------------------------------------------------------- /windows/CH341SER.CAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/CH341SER.CAT -------------------------------------------------------------------------------- /windows/CH341SER.INF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/CH341SER.INF -------------------------------------------------------------------------------- /windows/CH341SER.SYS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/CH341SER.SYS -------------------------------------------------------------------------------- /windows/CH341SER.VXD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/CH341SER.VXD -------------------------------------------------------------------------------- /windows/DRVSETUP64/DRVSETUP64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/DRVSETUP64/DRVSETUP64.exe -------------------------------------------------------------------------------- /windows/SETUP.EXE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/SETUP.EXE -------------------------------------------------------------------------------- /windows/WIN 1X/CH341M64.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/WIN 1X/CH341M64.sys -------------------------------------------------------------------------------- /windows/WIN 1X/CH341PORTS.DLL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/WIN 1X/CH341PORTS.DLL -------------------------------------------------------------------------------- /windows/WIN 1X/CH341PORTSA64.DLL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/WIN 1X/CH341PORTSA64.DLL -------------------------------------------------------------------------------- /windows/WIN 1X/CH341PT.DLL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/WIN 1X/CH341PT.DLL -------------------------------------------------------------------------------- /windows/WIN 1X/CH341PTA64.DLL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/WIN 1X/CH341PTA64.DLL -------------------------------------------------------------------------------- /windows/WIN 1X/CH341S64.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/WIN 1X/CH341S64.sys -------------------------------------------------------------------------------- /windows/WIN 1X/CH341S98.SYS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/WIN 1X/CH341S98.SYS -------------------------------------------------------------------------------- /windows/WIN 1X/CH341SER.CAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/WIN 1X/CH341SER.CAT -------------------------------------------------------------------------------- /windows/WIN 1X/CH341SER.INF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/WIN 1X/CH341SER.INF -------------------------------------------------------------------------------- /windows/WIN 1X/CH341SER.VXD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/WIN 1X/CH341SER.VXD -------------------------------------------------------------------------------- /windows/WIN 1X/CH341SER.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himalayanelixir/arduino-usb-drivers/1414f785eed6554a17d555a8fb7d5752e3f1a8e6/windows/WIN 1X/CH341SER.sys --------------------------------------------------------------------------------