On Mon, Oct 26, 2020 at 09:12:17AM +0100, Stefan Huber wrote: > Hey all, > > I recently got hands on an USB-TTY converter that is not (yet) supported by > OpenBSD: > > > addr 03: 067b:23a3 Prolific Technology Inc., USB-Serial Controller > > Simply adding the device ID to usbdevs and the uplcom driver did not do the > trick, as apparently it is what the linux driver calls a "HXN" chip, which > is (as of now) not yet supported by the uplcom driver (also, not in NetBSD > where the uplcom driver seems to come from). Some hours (days) later, I have > produced the following diff, butchering both the uplcom and the linux > driver. I know it looks like shit, but it works (for now and for me). I will > try to "streamline" the driver, and am happy for any feedback (since you may > see watching the code I am not a good kernel hacker yet). > > I was also thinking of adding all the other IDs from the linux driver to > uplcom, but then I can't test them since I only have the two chips 067b:2303 > and 067b:23a3. So I'd rather not merge the other IDs to prevent the kernel > from doing nasty things to them (or was it the other way around?) > > The diff's below. Works for me. Not looking for okay or a merge, mostly > feedback and maybe a merge for a future version of this diff.
First of all, we need unified diffs. Usually you have a CVS checkout and then run cvs diff -u. Yours don't look like you used cvs, was that a diff -r? Well, even then you should add -u, otherwise diffs become unreadable. Second, only OpenBSD account holders can ask for OKs. :) So, please resend with diff -u, otherwise no one will have a look at it since the diff is hard to follow. Thanks, Patrick > Happy Hacking, > Stefan > > > Common subdirectories: /home/src_orig/sys/dev/usb/CVS and > /usr/src/sys/dev/usb/CVS > Common subdirectories: /home/src_orig/sys/dev/usb/dwc2 and > /usr/src/sys/dev/usb/dwc2 > diff /home/src_orig/sys/dev/usb/uplcom.c /usr/src/sys/dev/usb/uplcom.c > 66c66 > < #define DPRINTF(x) DPRINTFN(0, x) > --- > > #define DPRINTF(x) printf x; > 71a72,74 > > #define UPLCOM_SET_NREQUEST 0x80 > > #define UPLCOM_READ_REQUEST 0x01 > > #define UPLCOM_READ_NREQUEST 0x81 > 77a81,91 > > #define UPLCOM_READ_HX_STATUS 0x8080 > > #define UPLCOM_HXN_RESET_REG 0x07 > > #define UPLCOM_HXN_RESET_UPSTREAM_PIPE 0x02 > > #define UPLCOM_HXN_RESET_DOWNSTREAM_PIPE 0x01 > > > > #define UPLCOM_HXN_FLOWCTRL_REG 0x0a > > #define UPLCOM_HXN_FLOWCTRL_MASK 0x1c > > #define UPLCOM_HXN_FLOWCTRL_NONE 0x1c > > #define UPLCOM_HXN_FLOWCTRL_RTS_CTS 0x18 > > #define UPLCOM_HXN_FLOWCTRL_XON_XOFF 0x0c > > > 98a113 > > int sc_type_hxn; /* HXN variant */ > 108a124,127 > > usbd_status uplcom_update_reg(struct uplcom_softc *sc, char reg, char > > mask, char val); > > usbd_status uplcom_vendor_read(struct uplcom_softc *sc, char val, char > > buf[1]); > > usbd_status uplcom_vendor_write(struct uplcom_softc *sc, char val, char > > index); > > int uplcom_test_hxn(struct uplcom_softc *); > 153a173 > > { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL23a3 }, > 250c270,272 > < if (ddesc->bDeviceClass == 0x02) > --- > > printf("[DEBUG] DeviceClass: %x\n", ddesc->bDeviceClass); > > printf("[DEBUG] MaxPacketSize: %x\n", ddesc->bMaxPacketSize); > > if (ddesc->bDeviceClass == 0x02) { /* type 0 */ > 252c274,276 > < else if (ddesc->bMaxPacketSize == 0x40) > --- > > sc->sc_type_hxn = 0; > > } > > else if (ddesc->bMaxPacketSize == 0x40) { /* type hx */ > 254c278,280 > < else > --- > > sc->sc_type_hxn = 0; > > } > > else { /* probably type 1 */ > 255a282,283 > > sc->sc_type_hxn = 0; > > } > 256a285,298 > > /* > > * The Linux driver also distinguishes HXN variant... > > * Let's see if that is needed for the 23a3 variant. > > */ > > if (sc->sc_type_hx == 1) { > > printf("[DEBUG] seems to be HX type. Checking for HXN type.\n"); > > if (uplcom_test_hxn(sc)) { > > printf("[DEBUG] Probably HXN.\n"); > > sc->sc_type_hxn = 1; > > } else { > > printf("[DEBUG] Probably not HXN.\n"); > > } > > } > > > 259c301,303 > < if (sc->sc_type_hx) { > --- > > if (sc->sc_type_hxn) { > > DPRINTF(("uplcom_attach: chiptype 2303XN\n")); > > } else if (sc->sc_type_hx) { > 419a464,471 > > > > if (sc->sc_type_hxn) { > > DPRINTF(("[DEBUG] trying to reset hxn\n")); > > req.bmRequestType = UT_WRITE_VENDOR_DEVICE; > > req.bRequest = UPLCOM_SET_NREQUEST; > > USETW(req.wValue, 0x07); > > USETW(req.wIndex, UPLCOM_HXN_RESET_UPSTREAM_PIPE | > > UPLCOM_HXN_RESET_DOWNSTREAM_PIPE); > > USETW(req.wLength, 0); > 421,425c473,484 > < req.bmRequestType = UT_WRITE_VENDOR_DEVICE; > < req.bRequest = UPLCOM_SET_REQUEST; > < USETW(req.wValue, 0); > < USETW(req.wIndex, sc->sc_iface_number); > < USETW(req.wLength, 0); > --- > > err = usbd_do_request(sc->sc_udev, &req, 0); > > if (err) { > > DPRINTF(("[DEBUG] uplcom_reset_hxn err=%d\n", err)); > > return (err); > > } > > } else { > > DPRINTF(("[DEBUG] trying to reset non-hxn device\n")); > > req.bmRequestType = UT_WRITE_VENDOR_DEVICE; > > req.bRequest = UPLCOM_SET_REQUEST; > > USETW(req.wValue, 8); > > USETW(req.wIndex, 0); > > USETW(req.wLength, 0); > 427,429c486,495 > < err = usbd_do_request(sc->sc_udev, &req, 0); > < if (err) > < return (EIO); > --- > > err = usbd_do_request(sc->sc_udev, &req, 0); > > if (err) { > > DPRINTF(("[DEBUG] uplcom_reset_8 err=%s\n", > > usbd_errstr(err))); > > return (err); > > } > > req.bmRequestType = UT_WRITE_VENDOR_DEVICE; > > req.bRequest = UPLCOM_SET_REQUEST; > > USETW(req.wValue, 9); > > USETW(req.wIndex, 0); > > USETW(req.wLength, 0); > 430a497,503 > > err = usbd_do_request(sc->sc_udev, &req, 0); > > if (err) { > > DPRINTF(("[DEBUG] uplcom_reset_9 err=%s\n", > > usbd_errstr(err))); > > return (err); > > } > > } > > > 528a602,610 > > if (sc->sc_type_hxn) { > > uplcom_update_reg(sc, UPLCOM_HXN_FLOWCTRL_REG, > > UPLCOM_HXN_FLOWCTRL_MASK, UPLCOM_HXN_FLOWCTRL_XON_XOFF); > > } else { > > req.bmRequestType = UT_WRITE_VENDOR_DEVICE; > > req.bRequest = UPLCOM_SET_REQUEST; > > USETW(req.wValue, 0); > > USETW(req.wIndex, > > (sc->sc_type_hx ? UPLCOM_HX_SET_CRTSCTS : > > UPLCOM_SET_CRTSCTS)); > > USETW(req.wLength, 0); > 530,541c612,617 > < req.bmRequestType = UT_WRITE_VENDOR_DEVICE; > < req.bRequest = UPLCOM_SET_REQUEST; > < USETW(req.wValue, 0); > < USETW(req.wIndex, > < (sc->sc_type_hx ? UPLCOM_HX_SET_CRTSCTS : UPLCOM_SET_CRTSCTS)); > < USETW(req.wLength, 0); > < > < err = usbd_do_request(sc->sc_udev, &req, 0); > < if (err) { > < DPRINTF(("uplcom_set_crtscts: failed, err=%s\n", > < usbd_errstr(err))); > < return (err); > --- > > err = usbd_do_request(sc->sc_udev, &req, 0); > > if (err) { > > DPRINTF(("uplcom_set_crtscts: failed, err=%s\n", > > usbd_errstr(err))); > > return (err); > > } > 658c734,738 > < if (sc->sc_type_hx == 1) { > --- > > if (sc->sc_type_hxn) { > > uplcom_vendor_write(sc, UPLCOM_HXN_RESET_REG, > > UPLCOM_HXN_RESET_UPSTREAM_PIPE | > > UPLCOM_HXN_RESET_DOWNSTREAM_PIPE); > > } else if (sc->sc_type_hx == 1) { > 768a849,984 > > } > > > > /* > > * uplcom_test_hxn() > > * will return 1 if attached device is HXN device, > > * will return 0 else. > > */ > > int > > uplcom_test_hxn(struct uplcom_softc *sc) > > { > > /* > > * res = usb_control_msg(serial->dev, > > * usb_rcvctrlpipe(serial->dev, 0), > > * VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, > > * PL2303_READ_TYPE_HX_STATUS, 0, buf, 1, 100); > > * if (res != 1) > > * type = TYPE_HXN; > > * > > * int usb_control_msg( > > * struct usb_device * dev, > > * unsigned int pipe, > > * __u8 request, > > * __u8 requesttype, > > * __u16 value, > > * __u16 index, > > * void * data, > > * __u16 size, > > * int timeout); > > * > > * VENDOR_READ_REQUEST 0x01 > > * VENDOR_READ_REQUEST_TYPE 0xc0 > > * PL2303_READ_TYPE_HX_STATUS 0x8080 > > */ > > usb_device_request_t req; > > usbd_status err; > > > > req.bmRequestType = 0xc0; > > req.bRequest = 0x01; > > USETW(req.wValue, 0x8080); > > USETW(req.wIndex, 0); > > USETW(req.wLength, 1); > > > > void* buf = malloc(1, M_USBDEV, M_WAITOK); > > err = usbd_do_request(sc->sc_udev, &req, buf); > > DPRINTF(("uplcom_test_hxn buf: %02x\n", (*(uint8_t*) buf))); > > if (err) { > > /* If it stalls, it's HXN */ > > DPRINTF(("uplcom_test_hxn err=%s\n", usbd_errstr(err))); > > return (1); > > } > > > > return (0); > > } > > > > usbd_status > > uplcom_update_reg(struct uplcom_softc *sc, char reg, char mask, char > > val) > > { > > char* buf = malloc(1, M_USBDEV, M_WAITOK); > > usbd_status err; > > /* read value */ > > if (sc->sc_type_hxn) { > > err = uplcom_vendor_read(sc, reg, buf); > > if (err) { > > DPRINTF(("%s: err=%s\n", __func__, usbd_errstr(err))); > > return (err); > > } > > } else { > > err = uplcom_vendor_read(sc, reg | 0x80, buf); > > if (err) { > > DPRINTF(("%s: err=%s\n", __func__, usbd_errstr(err))); > > return (err); > > } > > } > > > > /* update value */ > > *buf &= ~mask; > > *buf |= val & mask; > > > > /* write new value */ > > err = uplcom_vendor_write(sc, reg, *buf); > > if (err) { > > DPRINTF(("%s: err=%s\n", __func__, usbd_errstr(err))); > > return (err); > > } > > > > return USBD_NORMAL_COMPLETION; > > } > > > > usbd_status > > uplcom_vendor_read(struct uplcom_softc *sc, char val, char buf[1]) > > { > > usbd_status err; > > usb_device_request_t req; > > req.bmRequestType = UT_READ_VENDOR_DEVICE; > > if (sc->sc_type_hxn) { > > req.bRequest = UPLCOM_READ_NREQUEST; > > } else { > > req.bRequest = UPLCOM_READ_REQUEST; > > } > > USETW(req.wValue, val); > > USETW(req.wIndex, 0); /* read: index is always zero */ > > USETW(req.wLength, 1); /* read: read always one byte */ > > > > err = usbd_do_request(sc->sc_udev, &req, &buf); > > if (err) { > > DPRINTF(("%s: failed to read: %s\n", > > __func__, usbd_errstr(err))); > > return (err); > > } > > > > return USBD_NORMAL_COMPLETION; /* should return 0 if everything worked > > */ > > } > > > > usbd_status > > uplcom_vendor_write(struct uplcom_softc *sc, char val, char index) > > { > > usbd_status err; > > usb_device_request_t req; > > req.bmRequestType = UT_READ_VENDOR_DEVICE; > > if (sc->sc_type_hxn) { > > req.bRequest = UPLCOM_SET_NREQUEST; > > } else { > > req.bRequest = UPLCOM_SET_REQUEST; > > } > > USETW(req.wValue, val); > > USETW(req.wIndex, index); > > USETW(req.wLength, 0); > > > > err = usbd_do_request(sc->sc_udev, &req, 0); > > if (err) { > > DPRINTF(("%s: failed to write: %s\n", > > __func__, usbd_errstr(err))); > > return (err); > > } > > > > return USBD_NORMAL_COMPLETION; /* should return 0 if everything worked > > */ > diff /home/src_orig/sys/dev/usb/usbdevs /usr/src/sys/dev/usb/usbdevs > 3552a3553 > > product PROLIFIC PL23a3 0x23a3 PL2303 Serial > diff /home/src_orig/sys/dev/usb/usbdevs.h /usr/src/sys/dev/usb/usbdevs.h > 1c1 > < /* $OpenBSD: usbdevs.h,v 1.732 2020/08/03 14:25:56 deraadt Exp $ */ > --- > > /* $OpenBSD$ */ > 3559a3560 > > #define USB_PRODUCT_PROLIFIC_PL23a3 0x23a3 /* PL2303 > > Serial */ > diff /home/src_orig/sys/dev/usb/usbdevs_data.h > /usr/src/sys/dev/usb/usbdevs_data.h > 1c1 > < /* $OpenBSD: usbdevs_data.h,v 1.726 2020/08/03 14:25:56 deraadt Exp $ > */ > --- > > /* $OpenBSD$ */ > 8777a8778,8781 > > "PL2303 Serial", > > }, > > { > > USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL23a3, >