Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
/* $NetBSD: uplcom.c,v 1.54 2007/03/13 13:51:56 drochner Exp $ */
|
2001-01-23 04:24:10 +03:00
|
|
|
/*
|
2001-01-23 05:36:17 +03:00
|
|
|
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
2001-01-23 04:24:10 +03:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
2001-03-14 18:53:01 +03:00
|
|
|
* by Ichiro FUKUHARA (ichiro@ichiro.org).
|
2001-01-23 04:24:10 +03:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the NetBSD
|
|
|
|
* Foundation, Inc. and its contributors.
|
|
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2003-11-10 12:02:08 +03:00
|
|
|
* General information: http://www.prolific.com.tw/fr_pl2303.htm
|
|
|
|
* http://www.hitachi-hitec.com/jyouhou/prolific/2303.pdf
|
2001-01-23 04:24:10 +03:00
|
|
|
*/
|
|
|
|
|
2001-11-13 09:24:53 +03:00
|
|
|
#include <sys/cdefs.h>
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: uplcom.c,v 1.54 2007/03/13 13:51:56 drochner Exp $");
|
2001-11-13 09:24:53 +03:00
|
|
|
|
2001-01-23 04:24:10 +03:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
2001-03-14 18:53:01 +03:00
|
|
|
#include <sys/malloc.h>
|
2001-01-23 04:24:10 +03:00
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/conf.h>
|
|
|
|
#include <sys/tty.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/select.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/device.h>
|
|
|
|
#include <sys/poll.h>
|
|
|
|
|
|
|
|
#include <dev/usb/usb.h>
|
|
|
|
#include <dev/usb/usbcdc.h>
|
|
|
|
|
|
|
|
#include <dev/usb/usbdi.h>
|
|
|
|
#include <dev/usb/usbdi_util.h>
|
|
|
|
#include <dev/usb/usbdevs.h>
|
|
|
|
#include <dev/usb/usb_quirks.h>
|
|
|
|
|
|
|
|
#include <dev/usb/ucomvar.h>
|
|
|
|
|
|
|
|
#ifdef UPLCOM_DEBUG
|
|
|
|
#define DPRINTFN(n, x) if (uplcomdebug > (n)) logprintf x
|
2001-03-14 18:53:01 +03:00
|
|
|
int uplcomdebug = 0;
|
2001-01-23 04:24:10 +03:00
|
|
|
#else
|
|
|
|
#define DPRINTFN(n, x)
|
|
|
|
#endif
|
|
|
|
#define DPRINTF(x) DPRINTFN(0, x)
|
|
|
|
|
|
|
|
#define UPLCOM_CONFIG_INDEX 0
|
2001-01-28 06:44:46 +03:00
|
|
|
#define UPLCOM_IFACE_INDEX 0
|
|
|
|
#define UPLCOM_SECOND_IFACE_INDEX 1
|
2001-01-23 04:24:10 +03:00
|
|
|
|
2001-07-21 01:03:41 +04:00
|
|
|
#define UPLCOM_SET_REQUEST 0x01
|
2005-05-12 00:25:01 +04:00
|
|
|
#define UPLCOM_SET_CRTSCTS_0 0x41
|
|
|
|
#define UPLCOM_SET_CRTSCTS_HX 0x61
|
2001-03-14 18:53:01 +03:00
|
|
|
#define RSAQ_STATUS_DSR 0x02
|
|
|
|
#define RSAQ_STATUS_DCD 0x01
|
|
|
|
|
2005-05-12 00:25:01 +04:00
|
|
|
enum pl2303_type {
|
|
|
|
UPLCOM_TYPE_0,
|
|
|
|
UPLCOM_TYPE_HX,
|
|
|
|
};
|
|
|
|
|
2001-01-23 04:24:10 +03:00
|
|
|
struct uplcom_softc {
|
|
|
|
USBBASEDEVICE sc_dev; /* base device */
|
|
|
|
usbd_device_handle sc_udev; /* USB device */
|
2001-03-26 16:58:44 +04:00
|
|
|
usbd_interface_handle sc_iface; /* interface */
|
2001-01-23 04:24:10 +03:00
|
|
|
int sc_iface_number; /* interface number */
|
|
|
|
|
2001-07-31 16:33:11 +04:00
|
|
|
usbd_interface_handle sc_intr_iface; /* interrupt interface */
|
2001-03-14 18:53:01 +03:00
|
|
|
int sc_intr_number; /* interrupt number */
|
|
|
|
usbd_pipe_handle sc_intr_pipe; /* interrupt pipe */
|
|
|
|
u_char *sc_intr_buf; /* interrupt buffer */
|
|
|
|
int sc_isize;
|
|
|
|
|
2001-01-23 04:24:10 +03:00
|
|
|
usb_cdc_line_state_t sc_line_state; /* current line state */
|
2004-05-20 13:23:33 +04:00
|
|
|
int sc_dtr; /* current DTR state */
|
|
|
|
int sc_rts; /* current RTS state */
|
2001-01-23 04:24:10 +03:00
|
|
|
|
2001-03-14 18:53:01 +03:00
|
|
|
device_ptr_t sc_subdev; /* ucom device */
|
2001-01-23 04:24:10 +03:00
|
|
|
|
2001-03-26 16:49:39 +04:00
|
|
|
u_char sc_dying; /* disconnecting */
|
2001-03-14 18:53:01 +03:00
|
|
|
|
|
|
|
u_char sc_lsr; /* Local status register */
|
|
|
|
u_char sc_msr; /* uplcom status register */
|
2005-05-12 00:25:01 +04:00
|
|
|
|
|
|
|
enum pl2303_type sc_type; /* PL2303 chip type */
|
2001-01-23 04:24:10 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* These are the maximum number of bytes transferred per frame.
|
|
|
|
* The output buffer size cannot be increased due to the size encoding.
|
|
|
|
*/
|
2001-01-23 16:48:06 +03:00
|
|
|
#define UPLCOMIBUFSIZE 256
|
|
|
|
#define UPLCOMOBUFSIZE 256
|
2001-01-23 04:24:10 +03:00
|
|
|
|
2001-01-30 16:17:43 +03:00
|
|
|
Static usbd_status uplcom_reset(struct uplcom_softc *);
|
2001-01-23 04:24:10 +03:00
|
|
|
Static usbd_status uplcom_set_line_coding(struct uplcom_softc *sc,
|
2001-01-23 16:48:06 +03:00
|
|
|
usb_cdc_line_state_t *state);
|
2001-07-21 01:03:41 +04:00
|
|
|
Static usbd_status uplcom_set_crtscts(struct uplcom_softc *);
|
2001-03-14 18:53:01 +03:00
|
|
|
Static void uplcom_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
|
|
|
|
|
|
|
|
Static void uplcom_set(void *, int, int, int);
|
|
|
|
Static void uplcom_dtr(struct uplcom_softc *, int);
|
|
|
|
Static void uplcom_rts(struct uplcom_softc *, int);
|
|
|
|
Static void uplcom_break(struct uplcom_softc *, int);
|
|
|
|
Static void uplcom_set_line_state(struct uplcom_softc *);
|
|
|
|
Static void uplcom_get_status(void *, int portno, u_char *lsr, u_char *msr);
|
|
|
|
#if TODO
|
2007-03-04 08:59:00 +03:00
|
|
|
Static int uplcom_ioctl(void *, int, u_long, void *, int, usb_proc_ptr );
|
2001-03-14 18:53:01 +03:00
|
|
|
#endif
|
|
|
|
Static int uplcom_param(void *, int, struct termios *);
|
|
|
|
Static int uplcom_open(void *, int);
|
|
|
|
Static void uplcom_close(void *, int);
|
2005-05-12 00:25:01 +04:00
|
|
|
Static usbd_status uplcom_vendor_control_write(usbd_device_handle, u_int16_t, u_int16_t);
|
2001-01-23 04:24:10 +03:00
|
|
|
|
|
|
|
struct ucom_methods uplcom_methods = {
|
2001-03-14 18:53:01 +03:00
|
|
|
uplcom_get_status,
|
2001-01-23 04:24:10 +03:00
|
|
|
uplcom_set,
|
|
|
|
uplcom_param,
|
2001-03-14 18:53:01 +03:00
|
|
|
NULL, /* uplcom_ioctl, TODO */
|
2001-01-30 16:17:43 +03:00
|
|
|
uplcom_open,
|
|
|
|
uplcom_close,
|
2001-01-23 04:24:10 +03:00
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2001-12-03 04:47:12 +03:00
|
|
|
static const struct usb_devno uplcom_devs[] = {
|
2001-01-23 04:24:10 +03:00
|
|
|
/* I/O DATA USB-RSAQ2 */
|
2001-05-22 04:18:03 +04:00
|
|
|
{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 },
|
2006-09-04 19:39:39 +04:00
|
|
|
/* I/O DATA USB-RSAQ3 */
|
|
|
|
{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3 },
|
2001-03-26 16:49:39 +04:00
|
|
|
/* I/O DATA USB-RSAQ */
|
2001-01-28 06:44:46 +03:00
|
|
|
{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ },
|
2001-04-02 17:38:14 +04:00
|
|
|
/* PLANEX USB-RS232 URS-03 */
|
|
|
|
{ USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A },
|
2001-05-22 04:18:03 +04:00
|
|
|
/* IOGEAR/ATEN UC-232A */
|
2001-05-22 04:43:12 +04:00
|
|
|
{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
|
2004-02-19 04:12:05 +03:00
|
|
|
/* IOGEAR/ATENTRIPPLITE */
|
|
|
|
{ USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209 },
|
2001-11-30 16:41:00 +03:00
|
|
|
/* ELECOM UC-SGT */
|
|
|
|
{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT },
|
2005-10-09 06:16:35 +04:00
|
|
|
/* ELECOM UC-SGT0 */
|
|
|
|
{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0 },
|
2005-07-07 13:59:37 +04:00
|
|
|
/* Panasonic 50" Touch Panel */
|
|
|
|
{ USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_TYTP50P6S },
|
2002-01-22 06:13:28 +03:00
|
|
|
/* RATOC REX-USB60 */
|
|
|
|
{ USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 },
|
2002-03-09 09:06:11 +03:00
|
|
|
/* TDK USB-PHS Adapter UHA6400 */
|
|
|
|
{ USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 },
|
2002-03-16 19:10:19 +03:00
|
|
|
/* TDK USB-PDC Adapter UPA9664 */
|
|
|
|
{ USB_VENDOR_TDK, USB_PRODUCT_TDK_UPA9664 },
|
2003-08-11 12:16:34 +04:00
|
|
|
/* Sony Ericsson USB Cable */
|
2004-10-22 13:34:55 +04:00
|
|
|
{ USB_VENDOR_SUSTEEN, USB_PRODUCT_SUSTEEN_DCU10 },
|
2003-11-23 15:22:51 +03:00
|
|
|
/* SOURCENEXT KeikaiDenwa 8 */
|
|
|
|
{ USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 },
|
|
|
|
/* SOURCENEXT KeikaiDenwa 8 with charger */
|
|
|
|
{ USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG },
|
|
|
|
/* HAL Corporation Crossam2+USB */
|
|
|
|
{ USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 },
|
2004-06-05 12:41:43 +04:00
|
|
|
/* Sitecom USB to serial cable */
|
2004-10-22 13:34:55 +04:00
|
|
|
{ USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_CN104 },
|
2004-10-23 18:20:50 +04:00
|
|
|
/* Pharos USB GPS - Microsoft version */
|
|
|
|
{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X },
|
2007-01-31 13:11:50 +03:00
|
|
|
/* Willcom WS002IN (DD) */
|
|
|
|
{ USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_PL2303X },
|
2001-01-23 04:24:10 +03:00
|
|
|
};
|
2001-12-03 04:47:12 +03:00
|
|
|
#define uplcom_lookup(v, p) usb_lookup(uplcom_devs, v, p)
|
2001-01-23 04:24:10 +03:00
|
|
|
|
2006-09-04 19:39:39 +04:00
|
|
|
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 },
|
2007-01-31 13:11:50 +03:00
|
|
|
{ USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_PL2303X, UPLCOM_TYPE_HX },
|
2006-09-04 19:39:39 +04:00
|
|
|
{0, 0, 0}
|
|
|
|
};
|
|
|
|
|
2003-11-23 15:22:51 +03:00
|
|
|
|
2001-01-23 04:24:10 +03:00
|
|
|
USB_DECLARE_DRIVER(uplcom);
|
|
|
|
|
|
|
|
USB_MATCH(uplcom)
|
|
|
|
{
|
|
|
|
USB_MATCH_START(uplcom, uaa);
|
|
|
|
|
2001-12-03 04:47:12 +03:00
|
|
|
return (uplcom_lookup(uaa->vendor, uaa->product) != NULL ?
|
|
|
|
UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
|
2001-01-23 04:24:10 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
USB_ATTACH(uplcom)
|
|
|
|
{
|
|
|
|
USB_ATTACH_START(uplcom, sc, uaa);
|
|
|
|
usbd_device_handle dev = uaa->device;
|
2001-01-28 06:44:46 +03:00
|
|
|
usb_config_descriptor_t *cdesc;
|
2001-01-23 04:24:10 +03:00
|
|
|
usb_interface_descriptor_t *id;
|
|
|
|
usb_endpoint_descriptor_t *ed;
|
2005-05-11 14:02:28 +04:00
|
|
|
char *devinfop;
|
2001-01-23 04:24:10 +03:00
|
|
|
char *devname = USBDEVNAME(sc->sc_dev);
|
|
|
|
usbd_status err;
|
|
|
|
int i;
|
|
|
|
struct ucom_attach_args uca;
|
|
|
|
|
2005-05-11 14:02:28 +04:00
|
|
|
devinfop = usbd_devinfo_alloc(dev, 0);
|
|
|
|
USB_ATTACH_SETUP;
|
|
|
|
printf("%s: %s\n", devname, devinfop);
|
|
|
|
usbd_devinfo_free(devinfop);
|
2001-01-28 06:44:46 +03:00
|
|
|
|
|
|
|
sc->sc_udev = dev;
|
|
|
|
|
2001-01-23 04:24:10 +03:00
|
|
|
DPRINTF(("\n\nuplcom attach: sc=%p\n", sc));
|
|
|
|
|
2002-07-12 01:14:24 +04:00
|
|
|
/* initialize endpoints */
|
2001-03-26 16:49:39 +04:00
|
|
|
uca.bulkin = uca.bulkout = -1;
|
|
|
|
sc->sc_intr_number = -1;
|
|
|
|
sc->sc_intr_pipe = NULL;
|
|
|
|
|
2001-01-23 16:48:06 +03:00
|
|
|
/* Move the device into the configured state. */
|
2001-01-23 04:24:10 +03:00
|
|
|
err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1);
|
|
|
|
if (err) {
|
|
|
|
printf("\n%s: failed to set configuration, err=%s\n",
|
|
|
|
devname, usbd_errstr(err));
|
2001-03-26 16:49:39 +04:00
|
|
|
sc->sc_dying = 1;
|
2001-01-23 04:24:10 +03:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
2006-09-04 19:39:39 +04:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
}
|
2005-05-12 00:25:01 +04:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
if (uaa->release == 0x0300)
|
2005-05-12 00:25:01 +04:00
|
|
|
sc->sc_type = UPLCOM_TYPE_HX;
|
|
|
|
else
|
|
|
|
sc->sc_type = UPLCOM_TYPE_0;
|
2006-09-04 19:39:39 +04:00
|
|
|
chiptype_determined:
|
2005-05-12 00:25:01 +04:00
|
|
|
|
2001-01-28 06:44:46 +03:00
|
|
|
/* get the config descriptor */
|
|
|
|
cdesc = usbd_get_config_descriptor(sc->sc_udev);
|
|
|
|
|
|
|
|
if (cdesc == NULL) {
|
|
|
|
printf("%s: failed to get configuration descriptor\n",
|
|
|
|
USBDEVNAME(sc->sc_dev));
|
2001-03-26 16:49:39 +04:00
|
|
|
sc->sc_dying = 1;
|
2001-01-28 06:44:46 +03:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
2001-03-26 16:49:39 +04:00
|
|
|
/* get the (first/common) interface */
|
2002-07-12 01:14:24 +04:00
|
|
|
err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX,
|
2001-01-28 06:44:46 +03:00
|
|
|
&sc->sc_iface);
|
2001-01-23 04:24:10 +03:00
|
|
|
if (err) {
|
|
|
|
printf("\n%s: failed to get interface, err=%s\n",
|
|
|
|
devname, usbd_errstr(err));
|
2001-03-26 16:49:39 +04:00
|
|
|
sc->sc_dying = 1;
|
2001-01-23 04:24:10 +03:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
2001-03-26 16:49:39 +04:00
|
|
|
|
|
|
|
/* Find the interrupt endpoints */
|
|
|
|
|
|
|
|
id = usbd_get_interface_descriptor(sc->sc_iface);
|
|
|
|
sc->sc_iface_number = id->bInterfaceNumber;
|
|
|
|
|
|
|
|
for (i = 0; i < id->bNumEndpoints; i++) {
|
|
|
|
ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
|
|
|
|
if (ed == NULL) {
|
|
|
|
printf("%s: no endpoint descriptor for %d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), i);
|
|
|
|
sc->sc_dying = 1;
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
|
|
|
|
UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
|
|
|
|
sc->sc_intr_number = ed->bEndpointAddress;
|
|
|
|
sc->sc_isize = UGETW(ed->wMaxPacketSize);
|
2002-07-12 01:14:24 +04:00
|
|
|
}
|
2001-03-26 16:49:39 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->sc_intr_number== -1) {
|
|
|
|
printf("%s: Could not find interrupt in\n",
|
|
|
|
USBDEVNAME(sc->sc_dev));
|
|
|
|
sc->sc_dying = 1;
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
2001-07-31 16:33:11 +04:00
|
|
|
/* keep interface for interrupt */
|
|
|
|
sc->sc_intr_iface = sc->sc_iface;
|
|
|
|
|
2001-01-28 06:44:46 +03:00
|
|
|
/*
|
2001-03-26 16:49:39 +04:00
|
|
|
* USB-RSAQ1 has two interface
|
|
|
|
*
|
|
|
|
* USB-RSAQ1 | USB-RSAQ2
|
|
|
|
* -----------------+-----------------
|
2001-03-26 16:58:44 +04:00
|
|
|
* Interface 0 |Interface 0
|
|
|
|
* Interrupt(0x81) | Interrupt(0x81)
|
2001-03-26 16:49:39 +04:00
|
|
|
* -----------------+ BulkIN(0x02)
|
2001-03-26 16:58:44 +04:00
|
|
|
* Interface 1 | BulkOUT(0x83)
|
2002-07-12 01:14:24 +04:00
|
|
|
* BulkIN(0x02) |
|
2001-03-26 16:49:39 +04:00
|
|
|
* BulkOUT(0x83) |
|
2001-01-28 06:44:46 +03:00
|
|
|
*/
|
|
|
|
if (cdesc->bNumInterface == 2) {
|
2002-07-12 01:14:24 +04:00
|
|
|
err = usbd_device2interface_handle(dev,
|
2001-03-26 16:49:39 +04:00
|
|
|
UPLCOM_SECOND_IFACE_INDEX, &sc->sc_iface);
|
2001-01-28 06:44:46 +03:00
|
|
|
if (err) {
|
|
|
|
printf("\n%s: failed to get second interface, err=%s\n",
|
|
|
|
devname, usbd_errstr(err));
|
2001-03-26 16:49:39 +04:00
|
|
|
sc->sc_dying = 1;
|
2001-01-28 06:44:46 +03:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
2002-07-12 01:14:24 +04:00
|
|
|
}
|
2001-01-23 04:24:10 +03:00
|
|
|
|
2001-03-26 16:49:39 +04:00
|
|
|
/* Find the bulk{in,out} endpoints */
|
2001-01-23 04:24:10 +03:00
|
|
|
|
2001-03-14 18:53:01 +03:00
|
|
|
id = usbd_get_interface_descriptor(sc->sc_iface);
|
2001-01-23 04:24:10 +03:00
|
|
|
sc->sc_iface_number = id->bInterfaceNumber;
|
|
|
|
|
|
|
|
for (i = 0; i < id->bNumEndpoints; i++) {
|
2001-03-14 18:53:01 +03:00
|
|
|
ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
|
2001-01-23 04:24:10 +03:00
|
|
|
if (ed == NULL) {
|
|
|
|
printf("%s: no endpoint descriptor for %d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), i);
|
2001-03-26 16:49:39 +04:00
|
|
|
sc->sc_dying = 1;
|
2001-01-23 04:24:10 +03:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
|
|
|
|
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
|
|
|
|
uca.bulkin = ed->bEndpointAddress;
|
|
|
|
} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
|
|
|
|
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
|
|
|
|
uca.bulkout = ed->bEndpointAddress;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uca.bulkin == -1) {
|
|
|
|
printf("%s: Could not find data bulk in\n",
|
|
|
|
USBDEVNAME(sc->sc_dev));
|
2001-03-26 16:49:39 +04:00
|
|
|
sc->sc_dying = 1;
|
2001-01-23 04:24:10 +03:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uca.bulkout == -1) {
|
|
|
|
printf("%s: Could not find data bulk out\n",
|
|
|
|
USBDEVNAME(sc->sc_dev));
|
2001-03-26 16:49:39 +04:00
|
|
|
sc->sc_dying = 1;
|
2001-03-14 18:53:01 +03:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
2004-05-20 13:23:33 +04:00
|
|
|
sc->sc_dtr = sc->sc_rts = -1;
|
2001-01-23 04:24:10 +03:00
|
|
|
uca.portno = UCOM_UNK_PORTNO;
|
|
|
|
/* bulkin, bulkout set above */
|
|
|
|
uca.ibufsize = UPLCOMIBUFSIZE;
|
|
|
|
uca.obufsize = UPLCOMOBUFSIZE;
|
|
|
|
uca.ibufsizepad = UPLCOMIBUFSIZE;
|
2001-01-23 11:15:58 +03:00
|
|
|
uca.opkthdrlen = 0;
|
2001-01-23 04:24:10 +03:00
|
|
|
uca.device = dev;
|
2001-03-14 18:53:01 +03:00
|
|
|
uca.iface = sc->sc_iface;
|
2001-01-23 04:24:10 +03:00
|
|
|
uca.methods = &uplcom_methods;
|
|
|
|
uca.arg = sc;
|
2001-01-24 00:56:17 +03:00
|
|
|
uca.info = NULL;
|
2001-01-23 04:24:10 +03:00
|
|
|
|
2001-01-30 16:17:43 +03:00
|
|
|
err = uplcom_reset(sc);
|
|
|
|
|
2001-01-23 04:24:10 +03:00
|
|
|
if (err) {
|
2001-01-30 16:17:43 +03:00
|
|
|
printf("%s: reset failed, %s\n", USBDEVNAME(sc->sc_dev),
|
2001-01-23 04:24:10 +03:00
|
|
|
usbd_errstr(err));
|
2001-03-26 16:49:39 +04:00
|
|
|
sc->sc_dying = 1;
|
2001-01-23 04:24:10 +03:00
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
2001-01-23 17:04:13 +03:00
|
|
|
usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
|
|
|
|
USBDEV(sc->sc_dev));
|
|
|
|
|
2001-03-14 18:53:01 +03:00
|
|
|
DPRINTF(("uplcom: in=0x%x out=0x%x intr=0x%x\n",
|
|
|
|
uca.bulkin, uca.bulkout, sc->sc_intr_number ));
|
2004-09-13 16:55:47 +04:00
|
|
|
sc->sc_subdev = config_found_sm_loc(self, "ucombus", NULL, &uca,
|
|
|
|
ucomprint, ucomsubmatch);
|
2001-01-23 04:24:10 +03:00
|
|
|
|
|
|
|
USB_ATTACH_SUCCESS_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
USB_DETACH(uplcom)
|
|
|
|
{
|
|
|
|
USB_DETACH_START(uplcom, sc);
|
|
|
|
int rv = 0;
|
|
|
|
|
|
|
|
DPRINTF(("uplcom_detach: sc=%p flags=%d\n", sc, flags));
|
2001-03-14 18:53:01 +03:00
|
|
|
|
|
|
|
if (sc->sc_intr_pipe != NULL) {
|
|
|
|
usbd_abort_pipe(sc->sc_intr_pipe);
|
|
|
|
usbd_close_pipe(sc->sc_intr_pipe);
|
|
|
|
free(sc->sc_intr_buf, M_USBDEV);
|
|
|
|
sc->sc_intr_pipe = NULL;
|
|
|
|
}
|
|
|
|
|
2001-01-23 04:24:10 +03:00
|
|
|
sc->sc_dying = 1;
|
2001-01-23 16:48:06 +03:00
|
|
|
if (sc->sc_subdev != NULL) {
|
2001-01-23 04:24:10 +03:00
|
|
|
rv = config_detach(sc->sc_subdev, flags);
|
2001-01-23 16:48:06 +03:00
|
|
|
sc->sc_subdev = NULL;
|
|
|
|
}
|
2001-01-23 04:24:10 +03:00
|
|
|
|
2001-01-23 17:04:13 +03:00
|
|
|
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
|
|
|
|
USBDEV(sc->sc_dev));
|
|
|
|
|
2001-01-23 04:24:10 +03:00
|
|
|
return (rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
uplcom_activate(device_ptr_t self, enum devact act)
|
|
|
|
{
|
|
|
|
struct uplcom_softc *sc = (struct uplcom_softc *)self;
|
|
|
|
int rv = 0;
|
|
|
|
|
|
|
|
switch (act) {
|
|
|
|
case DVACT_ACTIVATE:
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
|
|
|
|
case DVACT_DEACTIVATE:
|
|
|
|
if (sc->sc_subdev != NULL)
|
|
|
|
rv = config_deactivate(sc->sc_subdev);
|
|
|
|
sc->sc_dying = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
2001-01-30 16:17:43 +03:00
|
|
|
uplcom_reset(struct uplcom_softc *sc)
|
2001-01-23 04:24:10 +03:00
|
|
|
{
|
|
|
|
usb_device_request_t req;
|
|
|
|
usbd_status err;
|
|
|
|
|
2001-07-21 01:03:41 +04:00
|
|
|
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
|
|
|
|
req.bRequest = UPLCOM_SET_REQUEST;
|
|
|
|
USETW(req.wValue, 0);
|
2001-01-23 04:24:10 +03:00
|
|
|
USETW(req.wIndex, sc->sc_iface_number);
|
2002-07-12 01:14:24 +04:00
|
|
|
USETW(req.wLength, 0);
|
|
|
|
|
|
|
|
err = usbd_do_request(sc->sc_udev, &req, 0);
|
2001-01-23 04:24:10 +03:00
|
|
|
if (err)
|
|
|
|
return (EIO);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
uplcom_set_line_state(struct uplcom_softc *sc)
|
|
|
|
{
|
|
|
|
usb_device_request_t req;
|
|
|
|
int ls;
|
|
|
|
|
2004-05-20 13:23:33 +04:00
|
|
|
/* make sure we have initialized state for sc_dtr and sc_rts */
|
|
|
|
if (sc->sc_dtr == -1)
|
|
|
|
sc->sc_dtr = 0;
|
|
|
|
if (sc->sc_rts == -1)
|
|
|
|
sc->sc_rts = 0;
|
|
|
|
|
2005-08-14 01:50:45 +04:00
|
|
|
ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) |
|
|
|
|
(sc->sc_rts ? UCDC_LINE_RTS : 0);
|
2004-05-20 13:23:33 +04:00
|
|
|
|
2001-01-23 04:24:10 +03:00
|
|
|
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
|
|
|
|
req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
|
|
|
|
USETW(req.wValue, ls);
|
|
|
|
USETW(req.wIndex, sc->sc_iface_number);
|
|
|
|
USETW(req.wLength, 0);
|
|
|
|
|
|
|
|
(void)usbd_do_request(sc->sc_udev, &req, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
uplcom_set(void *addr, int portno, int reg, int onoff)
|
2001-01-23 04:24:10 +03:00
|
|
|
{
|
|
|
|
struct uplcom_softc *sc = addr;
|
|
|
|
|
|
|
|
switch (reg) {
|
|
|
|
case UCOM_SET_DTR:
|
|
|
|
uplcom_dtr(sc, onoff);
|
|
|
|
break;
|
|
|
|
case UCOM_SET_RTS:
|
|
|
|
uplcom_rts(sc, onoff);
|
|
|
|
break;
|
|
|
|
case UCOM_SET_BREAK:
|
|
|
|
uplcom_break(sc, onoff);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
uplcom_dtr(struct uplcom_softc *sc, int onoff)
|
|
|
|
{
|
|
|
|
|
2001-01-30 16:17:43 +03:00
|
|
|
DPRINTF(("uplcom_dtr: onoff=%d\n", onoff));
|
2001-01-23 04:24:10 +03:00
|
|
|
|
2004-05-20 13:23:33 +04:00
|
|
|
if (sc->sc_dtr != -1 && !sc->sc_dtr == !onoff)
|
2001-01-23 04:24:10 +03:00
|
|
|
return;
|
2004-05-20 13:23:33 +04:00
|
|
|
|
|
|
|
sc->sc_dtr = !!onoff;
|
2001-01-23 04:24:10 +03:00
|
|
|
|
|
|
|
uplcom_set_line_state(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
uplcom_rts(struct uplcom_softc *sc, int onoff)
|
|
|
|
{
|
|
|
|
DPRINTF(("uplcom_rts: onoff=%d\n", onoff));
|
|
|
|
|
2004-05-20 13:23:33 +04:00
|
|
|
if (sc->sc_rts != -1 && !sc->sc_rts == !onoff)
|
2001-01-23 04:24:10 +03:00
|
|
|
return;
|
2004-05-20 13:23:33 +04:00
|
|
|
|
|
|
|
sc->sc_rts = !!onoff;
|
2001-01-23 04:24:10 +03:00
|
|
|
|
|
|
|
uplcom_set_line_state(sc);
|
|
|
|
}
|
|
|
|
|
2001-01-23 11:15:58 +03:00
|
|
|
void
|
|
|
|
uplcom_break(struct uplcom_softc *sc, int onoff)
|
|
|
|
{
|
|
|
|
usb_device_request_t req;
|
|
|
|
|
|
|
|
DPRINTF(("uplcom_break: onoff=%d\n", onoff));
|
|
|
|
|
|
|
|
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
|
|
|
|
req.bRequest = UCDC_SEND_BREAK;
|
|
|
|
USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
|
|
|
|
USETW(req.wIndex, sc->sc_iface_number);
|
|
|
|
USETW(req.wLength, 0);
|
|
|
|
|
|
|
|
(void)usbd_do_request(sc->sc_udev, &req, 0);
|
|
|
|
}
|
|
|
|
|
2001-07-21 01:03:41 +04:00
|
|
|
usbd_status
|
|
|
|
uplcom_set_crtscts(struct uplcom_softc *sc)
|
|
|
|
{
|
|
|
|
usb_device_request_t req;
|
|
|
|
usbd_status err;
|
|
|
|
|
|
|
|
DPRINTF(("uplcom_set_crtscts: on\n"));
|
|
|
|
|
|
|
|
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
|
|
|
|
req.bRequest = UPLCOM_SET_REQUEST;
|
|
|
|
USETW(req.wValue, 0);
|
2005-05-12 00:25:01 +04:00
|
|
|
if (sc->sc_type == UPLCOM_TYPE_HX)
|
|
|
|
USETW(req.wIndex, UPLCOM_SET_CRTSCTS_HX);
|
|
|
|
else
|
|
|
|
USETW(req.wIndex, UPLCOM_SET_CRTSCTS_0);
|
2001-07-21 01:03:41 +04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (USBD_NORMAL_COMPLETION);
|
|
|
|
}
|
|
|
|
|
2001-01-23 04:24:10 +03:00
|
|
|
usbd_status
|
|
|
|
uplcom_set_line_coding(struct uplcom_softc *sc, usb_cdc_line_state_t *state)
|
|
|
|
{
|
|
|
|
usb_device_request_t req;
|
|
|
|
usbd_status err;
|
|
|
|
|
|
|
|
DPRINTF(("uplcom_set_line_coding: rate=%d fmt=%d parity=%d bits=%d\n",
|
|
|
|
UGETDW(state->dwDTERate), state->bCharFormat,
|
|
|
|
state->bParityType, state->bDataBits));
|
|
|
|
|
|
|
|
if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) {
|
|
|
|
DPRINTF(("uplcom_set_line_coding: already set\n"));
|
|
|
|
return (USBD_NORMAL_COMPLETION);
|
|
|
|
}
|
|
|
|
|
|
|
|
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
|
|
|
|
req.bRequest = UCDC_SET_LINE_CODING;
|
|
|
|
USETW(req.wValue, 0);
|
|
|
|
USETW(req.wIndex, sc->sc_iface_number);
|
|
|
|
USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
|
|
|
|
|
|
|
|
err = usbd_do_request(sc->sc_udev, &req, state);
|
|
|
|
if (err) {
|
|
|
|
DPRINTF(("uplcom_set_line_coding: failed, err=%s\n",
|
|
|
|
usbd_errstr(err)));
|
|
|
|
return (err);
|
|
|
|
}
|
|
|
|
|
|
|
|
sc->sc_line_state = *state;
|
|
|
|
|
|
|
|
return (USBD_NORMAL_COMPLETION);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
uplcom_param(void *addr, int portno, struct termios *t)
|
2001-01-23 04:24:10 +03:00
|
|
|
{
|
|
|
|
struct uplcom_softc *sc = addr;
|
|
|
|
usbd_status err;
|
|
|
|
usb_cdc_line_state_t ls;
|
|
|
|
|
|
|
|
DPRINTF(("uplcom_param: sc=%p\n", sc));
|
|
|
|
|
|
|
|
USETDW(ls.dwDTERate, t->c_ospeed);
|
|
|
|
if (ISSET(t->c_cflag, CSTOPB))
|
|
|
|
ls.bCharFormat = UCDC_STOP_BIT_2;
|
|
|
|
else
|
|
|
|
ls.bCharFormat = UCDC_STOP_BIT_1;
|
|
|
|
if (ISSET(t->c_cflag, PARENB)) {
|
|
|
|
if (ISSET(t->c_cflag, PARODD))
|
|
|
|
ls.bParityType = UCDC_PARITY_ODD;
|
|
|
|
else
|
|
|
|
ls.bParityType = UCDC_PARITY_EVEN;
|
|
|
|
} else
|
|
|
|
ls.bParityType = UCDC_PARITY_NONE;
|
|
|
|
switch (ISSET(t->c_cflag, CSIZE)) {
|
|
|
|
case CS5:
|
|
|
|
ls.bDataBits = 5;
|
|
|
|
break;
|
|
|
|
case CS6:
|
|
|
|
ls.bDataBits = 6;
|
|
|
|
break;
|
|
|
|
case CS7:
|
|
|
|
ls.bDataBits = 7;
|
|
|
|
break;
|
|
|
|
case CS8:
|
|
|
|
ls.bDataBits = 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = uplcom_set_line_coding(sc, &ls);
|
|
|
|
if (err) {
|
|
|
|
DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err)));
|
|
|
|
return (EIO);
|
|
|
|
}
|
2001-07-21 01:03:41 +04:00
|
|
|
|
|
|
|
if (ISSET(t->c_cflag, CRTSCTS))
|
|
|
|
uplcom_set_crtscts(sc);
|
|
|
|
|
2004-05-20 13:23:33 +04:00
|
|
|
if (sc->sc_rts == -1 || sc->sc_dtr == -1)
|
|
|
|
uplcom_set_line_state(sc);
|
|
|
|
|
2001-07-21 01:03:41 +04:00
|
|
|
if (err) {
|
|
|
|
DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err)));
|
|
|
|
return (EIO);
|
|
|
|
}
|
|
|
|
|
2001-01-23 04:24:10 +03:00
|
|
|
return (0);
|
|
|
|
}
|
2001-01-30 16:17:43 +03:00
|
|
|
|
2005-05-12 00:25:01 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2001-01-30 16:17:43 +03:00
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
uplcom_open(void *addr, int portno)
|
2001-01-30 16:17:43 +03:00
|
|
|
{
|
|
|
|
struct uplcom_softc *sc = addr;
|
2005-05-12 00:25:01 +04:00
|
|
|
usbd_status err;
|
2002-07-12 01:14:24 +04:00
|
|
|
|
2001-01-30 16:17:43 +03:00
|
|
|
if (sc->sc_dying)
|
|
|
|
return (EIO);
|
|
|
|
|
2001-03-14 18:53:01 +03:00
|
|
|
DPRINTF(("uplcom_open: sc=%p\n", sc));
|
2001-01-30 16:17:43 +03:00
|
|
|
|
2005-05-12 00:25:01 +04:00
|
|
|
/* 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);
|
|
|
|
|
2001-03-14 18:53:01 +03:00
|
|
|
if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
|
|
|
|
sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
|
2001-07-31 16:33:11 +04:00
|
|
|
err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number,
|
2001-03-14 18:53:01 +03:00
|
|
|
USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc,
|
|
|
|
sc->sc_intr_buf, sc->sc_isize,
|
|
|
|
uplcom_intr, USBD_DEFAULT_INTERVAL);
|
|
|
|
if (err) {
|
|
|
|
DPRINTF(("%s: cannot open interrupt pipe (addr %d)\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), sc->sc_intr_number));
|
|
|
|
return (EIO);
|
|
|
|
}
|
|
|
|
}
|
2001-01-30 16:17:43 +03:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
uplcom_close(void *addr, int portno)
|
2001-01-30 16:17:43 +03:00
|
|
|
{
|
|
|
|
struct uplcom_softc *sc = addr;
|
2001-03-14 18:53:01 +03:00
|
|
|
int err;
|
2001-01-30 16:17:43 +03:00
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return;
|
|
|
|
|
2001-03-14 18:53:01 +03:00
|
|
|
DPRINTF(("uplcom_close: close\n"));
|
|
|
|
|
|
|
|
if (sc->sc_intr_pipe != NULL) {
|
|
|
|
err = usbd_abort_pipe(sc->sc_intr_pipe);
|
|
|
|
if (err)
|
|
|
|
printf("%s: abort interrupt pipe failed: %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
|
|
|
|
err = usbd_close_pipe(sc->sc_intr_pipe);
|
|
|
|
if (err)
|
|
|
|
printf("%s: close interrupt pipe failed: %s\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), usbd_errstr(err));
|
|
|
|
free(sc->sc_intr_buf, M_USBDEV);
|
|
|
|
sc->sc_intr_pipe = NULL;
|
2001-01-30 16:17:43 +03:00
|
|
|
}
|
2001-03-14 18:53:01 +03:00
|
|
|
}
|
2001-01-30 16:17:43 +03:00
|
|
|
|
2001-03-14 18:53:01 +03:00
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
uplcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
|
2006-10-12 05:30:41 +04:00
|
|
|
usbd_status status)
|
2001-03-14 18:53:01 +03:00
|
|
|
{
|
|
|
|
struct uplcom_softc *sc = priv;
|
|
|
|
u_char *buf = sc->sc_intr_buf;
|
|
|
|
u_char pstatus;
|
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (status != USBD_NORMAL_COMPLETION) {
|
|
|
|
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
|
|
|
|
return;
|
|
|
|
|
|
|
|
DPRINTF(("%s: abnormal status: %s\n", USBDEVNAME(sc->sc_dev),
|
|
|
|
usbd_errstr(status)));
|
|
|
|
usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DPRINTF(("%s: uplcom status = %02x\n", USBDEVNAME(sc->sc_dev), buf[8]));
|
|
|
|
|
2001-04-01 07:28:11 +04:00
|
|
|
sc->sc_lsr = sc->sc_msr = 0;
|
|
|
|
pstatus = buf[8];
|
|
|
|
if (ISSET(pstatus, RSAQ_STATUS_DSR))
|
|
|
|
sc->sc_msr |= UMSR_DSR;
|
|
|
|
if (ISSET(pstatus, RSAQ_STATUS_DCD))
|
|
|
|
sc->sc_msr |= UMSR_DCD;
|
|
|
|
ucom_status_change((struct ucom_softc *) sc->sc_subdev);
|
2001-03-14 18:53:01 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-11-16 04:32:37 +03:00
|
|
|
uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
|
2001-03-14 18:53:01 +03:00
|
|
|
{
|
|
|
|
struct uplcom_softc *sc = addr;
|
|
|
|
|
|
|
|
DPRINTF(("uplcom_get_status:\n"));
|
|
|
|
|
|
|
|
if (lsr != NULL)
|
|
|
|
*lsr = sc->sc_lsr;
|
|
|
|
if (msr != NULL)
|
|
|
|
*msr = sc->sc_msr;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if TODO
|
|
|
|
int
|
2007-03-04 08:59:00 +03:00
|
|
|
uplcom_ioctl(void *addr, int portno, u_long cmd, void *data, int flag,
|
2001-12-31 15:15:21 +03:00
|
|
|
usb_proc_ptr p)
|
2001-03-14 18:53:01 +03:00
|
|
|
{
|
|
|
|
struct uplcom_softc *sc = addr;
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return (EIO);
|
|
|
|
|
|
|
|
DPRINTF(("uplcom_ioctl: cmd=0x%08lx\n", cmd));
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case TIOCNOTTY:
|
|
|
|
case TIOCMGET:
|
|
|
|
case TIOCMSET:
|
|
|
|
case USB_GET_CM_OVER_DATA:
|
|
|
|
case USB_SET_CM_OVER_DATA:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
DPRINTF(("uplcom_ioctl: unknown\n"));
|
|
|
|
error = ENOTTY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (error);
|
2001-01-30 16:17:43 +03:00
|
|
|
}
|
2001-03-14 18:53:01 +03:00
|
|
|
#endif
|