Add some initialization magic from FreeBSD. This makes it work with

the more recent PL2303 revision 4.
This commit is contained in:
mlelstv 2008-02-12 22:29:54 +00:00
parent 6d51094880
commit 20eb004e2e
1 changed files with 131 additions and 56 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: uplcom.c,v 1.58 2007/08/18 20:23:04 sborrill Exp $ */
/* $NetBSD: uplcom.c,v 1.59 2008/02/12 22:29:54 mlelstv 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.58 2007/08/18 20:23:04 sborrill Exp $");
__KERNEL_RCSID(0, "$NetBSD: uplcom.c,v 1.59 2008/02/12 22:29:54 mlelstv Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -153,66 +153,83 @@ struct ucom_methods uplcom_methods = {
NULL,
};
static const struct usb_devno uplcom_devs[] = {
static const struct uplcom_type {
struct usb_devno uplcom_dev;
int32_t release;
enum pl2303_type chiptype;
} uplcom_devs[] = {
/* I/O DATA USB-RSAQ2 */
{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 },
{ { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 },
-1, UPLCOM_TYPE_0 },
/* I/O DATA USB-RSAQ3 */
{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3 },
{ { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3 },
-1, UPLCOM_TYPE_HX },
/* I/O DATA USB-RSAQ */
{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ },
{ { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ },
-1, UPLCOM_TYPE_0 },
/* I/O DATA USB-RSAQ5 */
{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ5 },
{ { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ5 },
-1, UPLCOM_TYPE_HX },
/* PLANEX USB-RS232 URS-03 */
{ USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A },
{ { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A },
-1, UPLCOM_TYPE_0 },
/* TrendNet TU-S9 */
{ { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
0x400, UPLCOM_TYPE_HX },
/* ST Lab USB-SERIAL-4 */
{ { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
0x300, UPLCOM_TYPE_HX },
/* IOGEAR/ATEN UC-232A */
{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
{ { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
-1, UPLCOM_TYPE_0 },
/* SMART Technologies USB to serial */
{ USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_PL2303 },
{ { USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_PL2303 },
-1, UPLCOM_TYPE_HX },
/* IOGEAR/ATENTRIPPLITE */
{ USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209 },
{ { USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209 },
-1, UPLCOM_TYPE_0 },
/* ELECOM UC-SGT */
{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT },
{ { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT },
-1, UPLCOM_TYPE_0 },
/* ELECOM UC-SGT0 */
{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0 },
{ { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0 },
-1, UPLCOM_TYPE_0 },
/* Panasonic 50" Touch Panel */
{ USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_TYTP50P6S },
{ { USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_TYTP50P6S },
-1, UPLCOM_TYPE_0 },
/* RATOC REX-USB60 */
{ USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 },
{ { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 },
-1, UPLCOM_TYPE_0 },
/* TDK USB-PHS Adapter UHA6400 */
{ USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 },
{ { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 },
-1, UPLCOM_TYPE_0 },
/* TDK USB-PDC Adapter UPA9664 */
{ USB_VENDOR_TDK, USB_PRODUCT_TDK_UPA9664 },
{ { USB_VENDOR_TDK, USB_PRODUCT_TDK_UPA9664 },
-1, UPLCOM_TYPE_0 },
/* Sony Ericsson USB Cable */
{ USB_VENDOR_SUSTEEN, USB_PRODUCT_SUSTEEN_DCU10 },
{ { USB_VENDOR_SUSTEEN, USB_PRODUCT_SUSTEEN_DCU10 },
-1, UPLCOM_TYPE_0 },
/* SOURCENEXT KeikaiDenwa 8 */
{ USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 },
{ { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 },
-1, UPLCOM_TYPE_0 },
/* SOURCENEXT KeikaiDenwa 8 with charger */
{ USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG },
{ { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG },
-1, UPLCOM_TYPE_0 },
/* HAL Corporation Crossam2+USB */
{ USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 },
{ { USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 },
-1, UPLCOM_TYPE_0 },
/* Sitecom USB to serial cable */
{ USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_CN104 },
{ { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_CN104 },
-1, UPLCOM_TYPE_0 },
/* Pharos USB GPS - Microsoft version */
{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X },
{ { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X },
-1, UPLCOM_TYPE_0 },
/* Willcom WS002IN (DD) */
{ USB_VENDOR_NETINDEX, USB_PRODUCT_NETINDEX_WS002IN },
{ { USB_VENDOR_NETINDEX, USB_PRODUCT_NETINDEX_WS002IN },
-1, UPLCOM_TYPE_HX },
};
#define uplcom_lookup(v, p) usb_lookup(uplcom_devs, v, p)
static const struct {
uint16_t vendor;
uint16_t product;
enum pl2303_type chiptype;
} uplcom_devs_ext[] = {
/* I/O DATA USB-RSAQ3 */
{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3, UPLCOM_TYPE_HX },
{ USB_VENDOR_NETINDEX, USB_PRODUCT_NETINDEX_WS002IN, UPLCOM_TYPE_HX },
/* I/O DATA USB-RSAQ5 */
{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ5, UPLCOM_TYPE_HX },
{0, 0, 0}
};
USB_DECLARE_DRIVER(uplcom);
USB_MATCH(uplcom)
@ -260,26 +277,33 @@ USB_ATTACH(uplcom)
}
/* determine chip type */
for (i = 0; uplcom_devs_ext[i].vendor != 0; i++) {
if (uplcom_devs_ext[i].vendor == uaa->vendor &&
uplcom_devs_ext[i].product == uaa->product) {
sc->sc_type = uplcom_devs_ext[i].chiptype;
goto chiptype_determined;
for (i = 0; uplcom_devs[i].uplcom_dev.ud_vendor != 0; i++) {
if (uplcom_devs[i].uplcom_dev.ud_vendor == uaa->vendor &&
uplcom_devs[i].uplcom_dev.ud_product == uaa->product &&
(uplcom_devs[i].release == uaa->release ||
uplcom_devs[i].release == 1)) {
sc->sc_type = uplcom_devs[i].chiptype;
break;
}
}
/*
* 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 (uaa->release == 0x0300)
sc->sc_type = UPLCOM_TYPE_HX;
else
sc->sc_type = UPLCOM_TYPE_0;
chiptype_determined:
#ifdef USB_DEBUG
/* print the chip type */
if (sc->sc_type == UPLCOM_TYPE_HX) {
DPRINTF(("uplcom_attach: chiptype HX\n"));
} else {
DPRINTF(("uplcom_attach: chiptype 0\n"));
}
#endif
/* Move the device into the configured state. */
err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1);
if (err) {
printf("%s: failed to set configuration: %s\n",
devname, usbd_errstr(err));
sc->sc_dying = 1;
USB_ATTACH_ERROR_RETURN;
}
/* get the config descriptor */
cdesc = usbd_get_config_descriptor(sc->sc_udev);
@ -489,6 +513,54 @@ uplcom_reset(struct uplcom_softc *sc)
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_udev, &req, 0);
if (err) {
printf("%s: uplcom_pl2303x_init failed: %s\n",
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
return (EIO);
}
}
return (0);
}
void
uplcom_set_line_state(struct uplcom_softc *sc)
{
@ -744,6 +816,9 @@ uplcom_open(void *addr, int portno)
}
}
if (sc->sc_type == UPLCOM_TYPE_HX)
return (uplcom_pl2303x_init(sc));
return (0);
}