diff options
| author | augustss <augustss@NetBSD.org> | 2005-05-11 20:25:01 +0000 |
|---|---|---|
| committer | augustss <augustss@NetBSD.org> | 2005-05-11 20:25:01 +0000 |
| commit | bf68872cdbbdd9e0028fc2491be5f487d318e271 (patch) | |
| tree | cea1df2b7102391ba202c3e0c678063271ae8a8c /sys/dev | |
| parent | a83267e9a2aefcc22bf9cff343bb8820096b176e (diff) | |
Support for the HX version of the chip.
Contributed by a donor that wishes to remain anonymous.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/usb/uplcom.c | 74 |
1 files changed, 68 insertions, 6 deletions
diff --git a/sys/dev/usb/uplcom.c b/sys/dev/usb/uplcom.c index 282510d66b8..1f2b61af19e 100644 --- a/sys/dev/usb/uplcom.c +++ b/sys/dev/usb/uplcom.c @@ -1,4 +1,4 @@ -/* $NetBSD: uplcom.c,v 1.42 2005/05/11 10:02:28 augustss Exp $ */ +/* $NetBSD: uplcom.c,v 1.43 2005/05/11 20:25:01 augustss Exp $ */ /* * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. @@ -41,7 +41,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uplcom.c,v 1.42 2005/05/11 10:02:28 augustss Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uplcom.c,v 1.43 2005/05/11 20:25:01 augustss Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -80,7 +80,8 @@ int uplcomdebug = 0; #define UPLCOM_SECOND_IFACE_INDEX 1 #define UPLCOM_SET_REQUEST 0x01 -#define UPLCOM_SET_CRTSCTS 0x41 +#define UPLCOM_SET_CRTSCTS_0 0x41 +#define UPLCOM_SET_CRTSCTS_HX 0x61 #define RSAQ_STATUS_DSR 0x02 #define RSAQ_STATUS_DCD 0x01 @@ -93,6 +94,11 @@ int uplcomdebug = 0; #define UPLCOM_FLOW_OUT_XON 0x0080 #define UPLCOM_FLOW_IN_XON 0x0100 +enum pl2303_type { + UPLCOM_TYPE_0, + UPLCOM_TYPE_HX, +}; + struct uplcom_softc { USBBASEDEVICE sc_dev; /* base device */ usbd_device_handle sc_udev; /* USB device */ @@ -115,6 +121,8 @@ struct uplcom_softc { u_char sc_lsr; /* Local status register */ u_char sc_msr; /* uplcom status register */ + + enum pl2303_type sc_type; /* PL2303 chip type */ }; /* @@ -142,6 +150,7 @@ Static int uplcom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr ); Static int uplcom_param(void *, int, struct termios *); Static int uplcom_open(void *, int); Static void uplcom_close(void *, int); +Static usbd_status uplcom_vendor_control_write(usbd_device_handle, u_int16_t, u_int16_t); struct ucom_methods uplcom_methods = { uplcom_get_status, @@ -206,6 +215,7 @@ USB_ATTACH(uplcom) { USB_ATTACH_START(uplcom, sc, uaa); usbd_device_handle dev = uaa->device; + usb_device_descriptor_t *ddesc; usb_config_descriptor_t *cdesc; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; @@ -238,6 +248,28 @@ USB_ATTACH(uplcom) USB_ATTACH_ERROR_RETURN; } + /* get the device descriptor */ + ddesc = usbd_get_device_descriptor(sc->sc_udev); + if (ddesc == NULL) { + printf("%s: failed to get device descriptor\n", + USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } + + /* + * NOTE: The Linux driver distinguishes between UPLCOM_TYPE_0 + * and UPLCOM_TYPE_1 type chips by testing other fields in the + * device descriptor. As far as the uplcom driver is + * concerned, both types are identical. + * The bcdDevice field should also distinguish these versions, + * but who knows. + */ + if (UGETW(ddesc->bcdDevice) == 0x0300) + sc->sc_type = UPLCOM_TYPE_HX; + else + sc->sc_type = UPLCOM_TYPE_0; + /* get the config descriptor */ cdesc = usbd_get_config_descriptor(sc->sc_udev); @@ -468,7 +500,6 @@ uplcom_set_line_state(struct uplcom_softc *sc) USETW(req.wLength, 0); (void)usbd_do_request(sc->sc_udev, &req, 0); - } void @@ -545,7 +576,10 @@ uplcom_set_crtscts(struct uplcom_softc *sc) req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = UPLCOM_SET_REQUEST; USETW(req.wValue, 0); - USETW(req.wIndex, UPLCOM_SET_CRTSCTS); + if (sc->sc_type == UPLCOM_TYPE_HX) + USETW(req.wIndex, UPLCOM_SET_CRTSCTS_HX); + else + USETW(req.wIndex, UPLCOM_SET_CRTSCTS_0); USETW(req.wLength, 0); err = usbd_do_request(sc->sc_udev, &req, 0); @@ -647,17 +681,45 @@ uplcom_param(void *addr, int portno, struct termios *t) return (0); } +Static usbd_status +uplcom_vendor_control_write(usbd_device_handle dev, u_int16_t value, u_int16_t index) +{ + usb_device_request_t req; + usbd_status err; + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = UPLCOM_SET_REQUEST; + USETW(req.wValue, value); + USETW(req.wIndex, index); + USETW(req.wLength, 0); + + err = usbd_do_request(dev, &req, NULL); + + if (err) { + DPRINTF(("uplcom_open: vendor write failed, err=%s (%d)\n", + usbd_errstr(err), err)); + } + + return err; +} + int uplcom_open(void *addr, int portno) { struct uplcom_softc *sc = addr; - int err; + usbd_status err; if (sc->sc_dying) return (EIO); DPRINTF(("uplcom_open: sc=%p\n", sc)); + /* Some unknown device frobbing. */ + if (sc->sc_type == UPLCOM_TYPE_HX) + uplcom_vendor_control_write(sc->sc_udev, 2, 0x44); + else + uplcom_vendor_control_write(sc->sc_udev, 2, 0x24); + if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number, |
