uplcom.c (PL2303X usb-to-serial) fix

看板DFBSD_submit作者時間21年前 (2005/03/28 13:01), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串1/1
This patch fixes the uplcom driver to work with newer PL2303X-based devices. It works for me. (Taken from FreeBSD) - Rahul --- sys/dev/usbmisc/uplcom/uplcom.c.orig 2005-03-21 19:04:18.000000000 +0530 +++ sys/dev/usbmisc/uplcom/uplcom.c 2005-03-27 19:11:14.000000000 +0530 @@ -67,13 +67,26 @@ */ /* - * Simple datasheet - * http://www.prolific.com.tw/download/DataSheet/pl2303_ds11.PDF - * http://www.nisseisg.co.jp/jyouhou/_cp/@gif/2303.pdf - * (english) + * This driver supports several USB-to-RS232 serial adapters driven by + * Prolific PL-2303, PL-2303X and probably PL-2303HX USB-to-RS232 + * bridge chip. The adapters are sold under many different brand + * names. * + * Datasheets are available at Prolific www site at + * http://www.prolific.com.tw. The datasheets don't contain full + * programming information for the chip. + * + * PL-2303HX is probably programmed the same as PL-2303X. + * + * There are several differences between PL-2303 and PL-2303(H)X. + * PL-2303(H)X can do higher bitrate in bulk mode, has _probably_ + * different command for controlling CRTSCTS and needs special + * sequence of commands for initialization which aren't also + * documented in the datasheet. */ +/* #include "opt_uplcom.h" */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -94,10 +107,13 @@ #include <sys/poll.h> #include <sys/sysctl.h> +#include <machine/bus.h> + #include <bus/usb/usb.h> #include <bus/usb/usbcdc.h> #include <bus/usb/usbdi.h> +#include <bus/usb/usbdivar.h> #include <bus/usb/usbdi_util.h> #include <bus/usb/usbdevs.h> #include <bus/usb/usb_quirks.h> @@ -131,9 +147,13 @@ #define UPLCOM_SET_REQUEST 0x01 #define UPLCOM_SET_CRTSCTS 0x41 +#define UPLCOM_SET_CRTSCTS_PL2303X 0x61 #define RSAQ_STATUS_DSR 0x02 #define RSAQ_STATUS_DCD 0x01 +#define TYPE_PL2303 0 +#define TYPE_PL2303X 1 + struct uplcom_softc { struct ucom_softc sc_ucom; @@ -152,6 +172,8 @@ u_char sc_lsr; /* Local status register */ u_char sc_msr; /* uplcom status register */ + + int sc_chiptype; /* Type of chip */ }; /* @@ -194,27 +216,40 @@ static const struct uplcom_product { uint16_t vendor; uint16_t product; + int32_t release; /* release is a 16bit entity, + * if -1 is specified we "don't care" + */ + char chiptype; } uplcom_products [] = { /* I/O DATA USB-RSAQ */ - { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ }, + { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ, -1, TYPE_PL2303 }, /* I/O DATA USB-RSAQ2 */ - { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 }, + { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2, -1, TYPE_PL2303 }, /* PLANEX USB-RS232 URS-03 */ - { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A }, - /* IOGEAR/ATEN UC-232A */ - { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 }, + { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A, -1, TYPE_PL2303 }, + /* ST Lab USB-SERIAL-4 */ + { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, + 0x300, TYPE_PL2303X }, + /* IOGEAR/ATEN UC-232A (also ST Lab USB-SERIAL-1) */ + { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, -1, TYPE_PL2303 }, /* TDK USB-PHS Adapter UHA6400 */ - { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 }, + { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400, -1, TYPE_PL2303 }, /* RATOC REX-USB60 */ - { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 }, + { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60, -1, TYPE_PL2303 }, /* ELECOM UC-SGT */ - { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT }, + { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT, -1, TYPE_PL2303 }, + { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0, -1, TYPE_PL2303 }, + /* Sony Ericsson USB Cable */ + { USB_VENDOR_SUSTEEN, USB_PRODUCT_SUSTEEN_DCU10, + -1,TYPE_PL2303 }, /* SOURCENEXT KeikaiDenwa 8 */ - { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 }, + { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8, + -1, TYPE_PL2303 }, /* SOURCENEXT KeikaiDenwa 8 with charger */ - { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG }, + { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG, + -1, TYPE_PL2303 }, /* HAL Corporation Crossam2+USB */ - { USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 }, + { USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001, -1, TYPE_PL2303 }, { 0, 0 } }; @@ -241,7 +276,7 @@ MODULE_DEPEND(uplcom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER); MODULE_VERSION(uplcom, UPLCOM_MODVER); -static int uplcominterval = UPLCOM_INTR_INTERVAL; +static int uplcominterval = UPLCOM_INTR_INTERVAL; static int sysctl_hw_usb_uplcom_interval(SYSCTL_HANDLER_ARGS) @@ -261,8 +296,8 @@ } SYSCTL_PROC(_hw_usb_uplcom, OID_AUTO, interval, CTLTYPE_INT | CTLFLAG_RW, - 0, sizeof(int), sysctl_hw_usb_uplcom_interval, - "I", "uplcom interrpt pipe interval"); + 0, sizeof(int), sysctl_hw_usb_uplcom_interval, + "I", "uplcom interrupt pipe interval"); USB_MATCH(uplcom) { @@ -274,7 +309,9 @@ for (i = 0; uplcom_products[i].vendor != 0; i++) { if (uplcom_products[i].vendor == uaa->vendor && - uplcom_products[i].product == uaa->product) { + uplcom_products[i].product == uaa->product && + (uplcom_products[i].release == uaa->release || + uplcom_products[i].release == -1)) { return (UMATCH_VENDOR_PRODUCT); } } @@ -294,7 +331,7 @@ usbd_status err; int i; - devinfo = malloc(1024, M_USBDEV, M_INTWAIT); + devinfo = malloc(1024, M_USBDEV, M_WAITOK); ucom = &sc->sc_ucom; bzero(sc, sizeof (struct uplcom_softc)); @@ -313,6 +350,36 @@ DPRINTF(("uplcom attach: sc = %p\n", sc)); + /* determine chip type */ + for (i = 0; uplcom_products[i].vendor != 0; i++) { + if (uplcom_products[i].vendor == uaa->vendor && + uplcom_products[i].product == uaa->product && + (uplcom_products[i].release == uaa->release || + uplcom_products[i].release == -1)) { + sc->sc_chiptype = uplcom_products[i].chiptype; + break; + } + } + + /* + * check we found the device - attach should have ensured we + * don't get here without matching device + */ + if (uplcom_products[i].vendor == 0) { + printf("%s: didn't match\n", devname); + ucom->sc_dying = 1; + goto error; + } + +#ifdef USB_DEBUG + /* print the chip type */ + if (sc->sc_chiptype == TYPE_PL2303X) { + DPRINTF(("uplcom_attach: chiptype 2303X\n")); + } else { + DPRINTF(("uplcom_attach: chiptype 2303\n")); + } +#endif + /* initialize endpoints */ ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1; sc->sc_intr_number = -1; @@ -514,6 +581,55 @@ return (0); } +struct pl2303x_init { + uint8_t req_type; + uint8_t request; + uint16_t value; + uint16_t index; + uint16_t length; +}; + +Static const struct pl2303x_init pl2303x[] = { + { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 0 }, + { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 0, 0 }, + { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 0 }, + { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 0 }, + { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 0 }, + { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 1, 0 }, + { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 0 }, + { UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 0 }, + { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0, 1, 0 }, + { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0, 0 }, + { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44, 0 } +}; +#define N_PL2302X_INIT (sizeof(pl2303x)/sizeof(pl2303x[0])) + +Static usbd_status +uplcom_pl2303x_init(struct uplcom_softc *sc) +{ + usb_device_request_t req; + usbd_status err; + int i; + + for (i = 0; i < N_PL2302X_INIT; i++) { + req.bmRequestType = pl2303x[i].req_type; + req.bRequest = pl2303x[i].request; + USETW(req.wValue, pl2303x[i].value); + USETW(req.wIndex, pl2303x[i].index); + USETW(req.wLength, pl2303x[i].length); + + err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0); + if (err) { + printf("%s: uplcom_pl2303x_init: %d: %s\n", + USBDEVNAME(sc->sc_ucom.sc_dev), i, + usbd_errstr(err)); + return (EIO); + } + } + + return (0); +} + Static void uplcom_set_line_state(struct uplcom_softc *sc) { @@ -610,7 +726,10 @@ req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = UPLCOM_SET_REQUEST; USETW(req.wValue, 0); - USETW(req.wIndex, UPLCOM_SET_CRTSCTS); + if (sc->sc_chiptype == TYPE_PL2303X) + USETW(req.wIndex, UPLCOM_SET_CRTSCTS_PL2303X); + else + USETW(req.wIndex, UPLCOM_SET_CRTSCTS); USETW(req.wLength, 0); err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0); @@ -657,15 +776,36 @@ return (USBD_NORMAL_COMPLETION); } +Static const int uplcom_rates[] = { + 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, + 19200, 28800, 38400, 57600, 115200, + /* + * Higher speeds are probably possible. PL2303X supports up to + * 6Mb and can set any rate + */ + 230400, 460800, 614400, 921600, 1228800 +}; +#define N_UPLCOM_RATES (sizeof(uplcom_rates)/sizeof(uplcom_rates[0])) + Static int uplcom_param(void *addr, int portno, struct termios *t) { struct uplcom_softc *sc = addr; usbd_status err; usb_cdc_line_state_t ls; + int i; DPRINTF(("uplcom_param: sc = %p\n", sc)); + /* Check requested baud rate */ + for (i = 0; i < N_UPLCOM_RATES; i++) + if (uplcom_rates[i] == t->c_ospeed) + break; + if (i == N_UPLCOM_RATES) { + DPRINTF(("uplcom_param: bad baud rate (%d)\n", t->c_ospeed)); + return (EIO); + } + USETDW(ls.dwDTERate, t->c_ospeed); if (ISSET(t->c_cflag, CSTOPB)) ls.bCharFormat = UCDC_STOP_BIT_2; @@ -737,6 +877,9 @@ } } + if (sc->sc_chiptype == TYPE_PL2303X) + return (uplcom_pl2303x_init(sc)); + return (0); }
文章代碼(AID): #12Hu-L00 (DFBSD_submit)