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,
> 

Reply via email to