NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/39075: uhmodem(4) fix
>Number: 39075
>Category: kern
>Synopsis: uhmodem(4) fix
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Wed Jul 02 02:05:00 +0000 2008
>Originator: Yojiro UO
>Release: 4.99.67
>Organization:
>Environment:
all which has uhmodem(4).
>Description:
current uhmodem(4) assumes that the devices are compatible with ubsa(4).
however, uhmodem(4) device is not compatible with that. This patch fix
following problems.
- notify message in interrupt pipe processing
- unsolicited close of interrupt pipe when multiple coms on same device opened
and closed
(it depend on sequence of open/close).
>How-To-Repeat:
always
>Fix:
apply the patch
Index: share/man/man4/uhmodem.4
===================================================================
RCS file: /cvsroot/src/share/man/man4/uhmodem.4,v
retrieving revision 1.3
diff -u -p -r1.3 uhmodem.4
--- share/man/man4/uhmodem.4 30 Apr 2008 13:10:54 -0000 1.3
+++ share/man/man4/uhmodem.4 2 Jul 2008 01:14:32 -0000
@@ -43,6 +43,7 @@ driver supports the following adapters:
.Pp
.Bl -tag -width Dv -offset indent -compact
.It Huawei E220
+.It Huawei E620
.It E-mobile D01HW
.It E-mobile D02HW
.It NTT DoCoMo a2502
@@ -69,7 +70,6 @@ driver which makes it behave like a
.Xr tty 4 .
.Sh SEE ALSO
.Xr tty 4 ,
-.Xr ubsa 4 ,
.Xr ucom 4 ,
.Xr usb 4
.Sh HISTORY
@@ -77,5 +77,4 @@ The
.Nm
driver first appeared in
.Nx 5.0 .
-Separate from ubsa driver.
Index: sys/dev/usb/uhmodem.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/uhmodem.c,v
retrieving revision 1.7
diff -u -p -r1.7 uhmodem.c
--- sys/dev/usb/uhmodem.c 24 May 2008 16:40:58 -0000 1.7
+++ sys/dev/usb/uhmodem.c 2 Jul 2008 01:14:32 -0000
@@ -98,18 +98,14 @@ __KERNEL_RCSID(0, "$NetBSD: uhmodem.c,v
#include <dev/usb/usbdevs.h>
#include <dev/usb/usb_quirks.h>
#include <dev/usb/ucomvar.h>
-#include <dev/usb/ubsavar.h>
-
-/* vendor specific bRequest */
-#define UHMODEM_REGWRITE 0x20
-#define UHMODEM_REGREAD 0x21
-#define UHMODEM_SETUP 0x22
+#define UHMODEM_INTR_INTERVAL 100 /* ms */
#define UHMODEMIBUFSIZE 4096
#define UHMODEMOBUFSIZE 4096
+#define UHMODEM_DEBUG
#ifdef UHMODEM_DEBUG
-Static int uhmodemdebug = 0;
+Static int uhmodemdebug = 1;
#define DPRINTFN(n, x) do { \
if (uhmodemdebug > (n)) \
logprintf x; \
@@ -119,28 +115,72 @@ Static int uhmodemdebug = 0;
#endif
#define DPRINTF(x) DPRINTFN(0, x)
-Static int uhmodem_open(void *, int);
-Static usbd_status e220_modechange_request(usbd_device_handle);
-Static usbd_status uhmodem_endpointhalt(struct ubsa_softc *, int);
-Static usbd_status uhmodem_regwrite(usbd_device_handle, uint8_t *, size_t);
-Static usbd_status uhmodem_regread(usbd_device_handle, uint8_t *, size_t);
-Static usbd_status a2502_init(usbd_device_handle);
-#if 0
-Static usbd_status uhmodem_regsetup(usbd_device_handle, uint16_t);
-Static usbd_status e220_init(usbd_device_handle);
-#endif
+#define UHMODEM_MAXCONN 4
+
+#define E220_MODE_CHANGE_REQUEST 0x2
+
+struct uhmodem_iface {
+ struct uhmodem_softc *parent;
+ usbd_interface_handle sc_ifaceh;
+ int sc_iface_number;
+
+ /* intrrupt endpoint */
+ int sc_intr_number;
+ usbd_pipe_handle sc_intr_pipe;
+ u_char *sc_intr_buf;
+ int sc_isize;
+
+ u_char sc_dtr; /* current DTR state */
+ u_char sc_rts; /* current RTS state */
+ u_char sc_lsr; /* local status register */
+ u_char sc_msr; /* status register */
+
+ device_ptr_t sc_subdev; /* ucom device */
+};
struct uhmodem_softc {
- struct ubsa_softc sc_ubsa;
+ USBBASEDEVICE sc_dev;
+ usbd_device_handle sc_udev;
+ int sc_config_index;
+ int sc_numif;
+ u_char sc_dying; /* disconnecting */
+ u_int16_t sc_devflags;
+
+ struct uhmodem_iface sc_iface[UHMODEM_MAXCONN];
};
+int uhmodem_open(void *, int);
+void uhmodem_close(void*, int);
+void uhmodem_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
+void uhmodem_get_status(void *, int, u_char *, u_char *);
+void uhmodem_set(void *, int, int, int);
+int uhmodem_param(void *, int, struct termios *);
+
+int uhmodem_match(device_t, cfdata_t, void *);
+void uhmodem_attach(device_t, device_t, void *);
+void uhmodem_childdet(device_t, device_t);
+int uhmodem_detach(device_t, int);
+int uhmodem_activate(device_t, enum devact);
+
+Static usbd_status e220_modechange_request(usbd_device_handle);
+Static usbd_status uhmodem_endpointhalt(struct uhmodem_softc *, int);
+Static usbd_status uhmodem_set_line_coding(struct uhmodem_softc *,
+ int, usb_cdc_line_state_t *);
+Static usbd_status uhmodem_get_line_coding(struct uhmodem_softc *,
+ int, usb_cdc_line_state_t *);
+Static usbd_status uhmodem_set_ctrl_line_state(struct uhmodem_softc *,
+ int, uint16_t);
+Static usbd_status uhmodem_set_comm_feature(struct uhmodem_softc *,
+ int, usb_cdc_abstract_state_t *);
+Static usbd_status e220_init(struct uhmodem_softc *, int);
+
struct ucom_methods uhmodem_methods = {
- ubsa_get_status,
- ubsa_set,
- ubsa_param,
+ uhmodem_get_status,
+ uhmodem_set,
+ uhmodem_param,
NULL,
uhmodem_open,
- ubsa_close,
+ uhmodem_close,
NULL,
NULL
};
@@ -149,27 +189,20 @@ struct uhmodem_type {
struct usb_devno uhmodem_dev;
u_int16_t uhmodem_coms; /* number of serial interfaces
on the device */
u_int16_t uhmodem_flags;
-#define E220 0x0001
-#define A2502 0x0002
-#define E620 0x0004 /* XXX */
- /* Whether or not it is a device different from
E220 is not clear. */
+#define DEV_DEFAULT 0x0000
+#define DEV_E220 0x0001
};
Static const struct uhmodem_type uhmodem_devs[] = {
/* HUAWEI E220 / Emobile D0[12]HW */
- {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 }, 2, E220},
+ {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 }, 2, DEV_E220},
/* ANYDATA / NTT DoCoMo A2502 */
- {{ USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_A2502 }, 3, A2502},
+ {{ USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_A2502 }, 3, 0},
/* HUAWEI E620 */
- {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE }, 3, E620},
+ {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE }, 3, 0},
};
#define uhmodem_lookup(v, p) ((const struct uhmodem_type
*)usb_lookup(uhmodem_devs, v, p))
-int uhmodem_match(device_t, cfdata_t, void *);
-void uhmodem_attach(device_t, device_t, void *);
-void uhmodem_childdet(device_t, device_t);
-int uhmodem_detach(device_t, int);
-int uhmodem_activate(device_t, enum devact);
extern struct cfdriver uhmodem_cd;
CFATTACH_DECL2_NEW(uhmodem, sizeof(struct uhmodem_softc), uhmodem_match,
uhmodem_attach, uhmodem_detach, uhmodem_activate, NULL, uhmodem_childdet);
@@ -195,6 +228,7 @@ USB_ATTACH(uhmodem)
usb_endpoint_descriptor_t *ed;
char *devinfop;
usbd_status err;
+ struct uhmodem_iface *iface;
struct ucom_attach_args uca;
int i;
int j;
@@ -205,23 +239,25 @@ USB_ATTACH(uhmodem)
aprint_normal_dev(self, "%s\n", devinfop);
usbd_devinfo_free(devinfop);
- sc->sc_ubsa.sc_dev = self;
- sc->sc_ubsa.sc_udev = dev;
- sc->sc_ubsa.sc_config_index = UBSA_DEFAULT_CONFIG_INDEX;
- sc->sc_ubsa.sc_numif = 1; /* defaut device has one interface */
+ sc->sc_dev = self;
+ sc->sc_udev = dev;
+ sc->sc_config_index = 0;
+ sc->sc_numif = 1; /* defaut device has one interface */
/* Hauwei E220 need special request to change its mode to modem */
if ((uaa->ifaceno == 0) && (uaa->class != 255)) {
+ aprint_error_dev(self, "HUAWEI E220 need to re-attach "
+ "to enable modem function\n");
err = e220_modechange_request(dev);
if (err) {
aprint_error_dev(self, "failed to change mode: %s\n",
usbd_errstr(err));
- sc->sc_ubsa.sc_dying = 1;
+ sc->sc_dying = 1;
goto error;
}
aprint_error_dev(self,
"mass storage only mode, reattach to enable modem\n");
- sc->sc_ubsa.sc_dying = 1;
+ sc->sc_dying = 1;
goto error;
}
@@ -229,60 +265,62 @@ USB_ATTACH(uhmodem)
* initialize rts, dtr variables to something
* different from boolean 0, 1
*/
- sc->sc_ubsa.sc_dtr = -1;
- sc->sc_ubsa.sc_rts = -1;
+ sc->sc_numif = uhmodem_lookup(uaa->vendor, uaa->product)->uhmodem_coms;
+ sc->sc_devflags = uhmodem_lookup(uaa->vendor,
uaa->product)->uhmodem_flags;
- sc->sc_ubsa.sc_quadumts = 1;
- sc->sc_ubsa.sc_config_index = 0;
- sc->sc_ubsa.sc_numif = uhmodem_lookup(uaa->vendor,
uaa->product)->uhmodem_coms;
- sc->sc_ubsa.sc_devflags = uhmodem_lookup(uaa->vendor,
uaa->product)->uhmodem_flags;
-
- DPRINTF(("uhmodem attach: sc = %p\n", sc));
+ DPRINTF(("uhmodem attach: sc = %p, sc_dying = %d\n", sc, sc->sc_dying));
/* Move the device into the configured state. */
- err = usbd_set_config_index(dev, sc->sc_ubsa.sc_config_index, 1);
+ err = usbd_set_config_index(dev, sc->sc_config_index, 1);
if (err) {
aprint_error_dev(self, "failed to set configuration: %s\n",
usbd_errstr(err));
- sc->sc_ubsa.sc_dying = 1;
+ sc->sc_dying = 1;
goto error;
}
/* get the config descriptor */
- cdesc = usbd_get_config_descriptor(sc->sc_ubsa.sc_udev);
+ cdesc = usbd_get_config_descriptor(sc->sc_udev);
if (cdesc == NULL) {
aprint_error_dev(self,
"failed to get configuration descriptor\n");
- sc->sc_ubsa.sc_dying = 1;
+ sc->sc_dying = 1;
goto error;
}
- sc->sc_ubsa.sc_intr_number = -1;
- sc->sc_ubsa.sc_intr_pipe = NULL;
-
/* get the interfaces */
- for (i = 0; i < sc->sc_ubsa.sc_numif; i++) {
- err = usbd_device2interface_handle(dev,
UBSA_IFACE_INDEX_OFFSET+i,
- &sc->sc_ubsa.sc_iface[i]);
+ for (i = 0; i < sc->sc_numif; i++) {
+ iface = &sc->sc_iface[i];
+
+ /* initialize */
+ memset(iface, 0, sizeof(iface));
+ iface->sc_iface_number = -1;
+ iface->sc_intr_number = -1;
+ iface->sc_intr_pipe = NULL;
+ iface->sc_intr_buf = NULL;
+ iface->sc_dtr = iface->sc_rts = -1;
+ iface->parent = sc;
+
+ err = usbd_device2interface_handle(dev, i, &iface->sc_ifaceh);
if (err) {
if (i == 0){
/* can not get main interface */
- sc->sc_ubsa.sc_dying = 1;
+ sc->sc_dying = 1;
goto error;
} else
break;
}
/* Find the endpoints */
- id = usbd_get_interface_descriptor(sc->sc_ubsa.sc_iface[i]);
- sc->sc_ubsa.sc_iface_number[i] = id->bInterfaceNumber;
+ id = usbd_get_interface_descriptor(iface->sc_ifaceh);
+ iface->sc_iface_number = id->bInterfaceNumber;
/* initialize endpoints */
uca.bulkin = uca.bulkout = -1;
for (j = 0; j < id->bNumEndpoints; j++) {
ed = usbd_interface2endpoint_descriptor(
- sc->sc_ubsa.sc_iface[i], j);
+ iface->sc_ifaceh, j);
if (ed == NULL) {
aprint_error_dev(self,
"no endpoint descriptor for %d "
@@ -292,8 +330,10 @@ USB_ATTACH(uhmodem)
if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
- sc->sc_ubsa.sc_intr_number =
ed->bEndpointAddress;
- sc->sc_ubsa.sc_isize =
UGETW(ed->wMaxPacketSize);
+ iface->sc_intr_number = ed->bEndpointAddress;
+ iface->sc_isize = UGETW(ed->wMaxPacketSize);
+ aprint_normal_dev(self, "find interrupt
endpoint "
+ "for if#%d\n", iface->sc_iface_number);
} else if (UE_GET_DIR(ed->bEndpointAddress) ==
UE_DIR_IN &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
uca.bulkin = ed->bEndpointAddress;
@@ -303,27 +343,23 @@ USB_ATTACH(uhmodem)
}
} /* end of Endpoint loop */
- if (sc->sc_ubsa.sc_intr_number == -1) {
- aprint_error_dev(self, "HUAWEI E220 need to re-attach "
- "to enable modem function\n");
- if (i == 0) {
- /* could not get intr for main tty */
- sc->sc_ubsa.sc_dying = 1;
- goto error;
- } else
- break;
+ if (iface->sc_iface_number == 0 && iface->sc_intr_number == -1)
{
+ /* could not get intr for main tty */
+ aprint_error_dev(self, "could not find intr ep. for
main tty\n");
+ sc->sc_dying = 1;
+ goto error;
}
if (uca.bulkin == -1) {
aprint_error_dev(self,
"Could not find data bulk in\n");
- sc->sc_ubsa.sc_dying = 1;
+ sc->sc_dying = 1;
goto error;
}
if (uca.bulkout == -1) {
aprint_error_dev(self,
"Could not find data bulk out\n");
- sc->sc_ubsa.sc_dying = 1;
+ sc->sc_dying = 1;
goto error;
}
@@ -342,32 +378,32 @@ USB_ATTACH(uhmodem)
break;
}
+ /* build uca information , bulkin, bulkout set above */
uca.portno = i;
- /* bulkin, bulkout set above */
uca.ibufsize = UHMODEMIBUFSIZE;
uca.obufsize = UHMODEMOBUFSIZE;
uca.ibufsizepad = UHMODEMIBUFSIZE;
uca.opkthdrlen = 0;
uca.device = dev;
- uca.iface = sc->sc_ubsa.sc_iface[i];
+ uca.iface = iface->sc_ifaceh;
uca.methods = &uhmodem_methods;
- uca.arg = &sc->sc_ubsa;
+ uca.arg = sc;
uca.info = comname;
- DPRINTF(("uhmodem: int#=%d, in = 0x%x, out = 0x%x, intr =
0x%x\n",
- i, uca.bulkin, uca.bulkout,
sc->sc_ubsa.sc_intr_number));
- sc->sc_ubsa.sc_subdevs[i] = config_found_sm_loc(self,
"ucombus", NULL,
+ DPRINTF(("uhmodem: int#=%d, in=0x%x, out=0x%x, intr=0x%x\n",
+ i, uca.bulkin, uca.bulkout, iface->sc_intr_number));
+ iface->sc_subdev = config_found_sm_loc(self, "ucombus", NULL,
&uca, ucomprint, ucomsubmatch);
/* issue endpoint halt to each interface */
- err = uhmodem_endpointhalt(&sc->sc_ubsa, i);
+ err = uhmodem_endpointhalt(sc, i);
if (err)
aprint_error("%s: endpointhalt fail\n", __func__);
else
- usbd_delay_ms(sc->sc_ubsa.sc_udev, 50);
+ usbd_delay_ms(sc->sc_udev, 50);
} /* end of Interface loop */
- usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_ubsa.sc_udev,
- USBDEV(sc->sc_ubsa.sc_dev));
+ usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
USB_ATTACH_SUCCESS_RETURN;
@@ -378,40 +414,50 @@ error:
void
uhmodem_childdet(device_t self, device_t child)
{
- int i;
struct uhmodem_softc *sc = device_private(self);
+ struct uhmodem_iface *iface;
+ int i;
- for (i = 0; i < sc->sc_ubsa.sc_numif; i++) {
- if (sc->sc_ubsa.sc_subdevs[i] == child)
+ iface = &sc->sc_iface[0];
+ for (i = 0; i < sc->sc_numif; i++) {
+ iface = &sc->sc_iface[i];
+ if (iface->sc_subdev == child)
break;
}
- KASSERT(i < sc->sc_ubsa.sc_numif);
- sc->sc_ubsa.sc_subdevs[i] = NULL;
+ KASSERT(i < sc->sc_numif);
+ iface->sc_subdev = NULL;
}
USB_DETACH(uhmodem)
{
USB_DETACH_START(uhmodem, sc);
+ struct uhmodem_iface *iface;
int i;
int rv = 0;
DPRINTF(("uhmodem_detach: sc = %p\n", sc));
- if (sc->sc_ubsa.sc_intr_pipe != NULL) {
- usbd_abort_pipe(sc->sc_ubsa.sc_intr_pipe);
- usbd_close_pipe(sc->sc_ubsa.sc_intr_pipe);
- free(sc->sc_ubsa.sc_intr_buf, M_USBDEV);
- sc->sc_ubsa.sc_intr_pipe = NULL;
+ /* close all interrupt endpoints */
+ for (i = 0; i < sc->sc_numif; i++) {
+ iface = &sc->sc_iface[i];
+ if (iface->sc_intr_pipe != NULL) {
+ usbd_abort_pipe(iface->sc_intr_pipe);
+ usbd_close_pipe(iface->sc_intr_pipe);
+ free(iface->sc_intr_buf, M_USBDEV);
+ iface->sc_intr_pipe = NULL;
+ }
}
- sc->sc_ubsa.sc_dying = 1;
- for (i = 0; i < sc->sc_ubsa.sc_numif; i++) {
- if (sc->sc_ubsa.sc_subdevs[i] != NULL)
- rv |= config_detach(sc->sc_ubsa.sc_subdevs[i], flags);
+ sc->sc_dying = 1;
+ /* detach all sub devices */
+ for (i = 0; i < sc->sc_numif; i++) {
+ iface = &sc->sc_iface[i];
+ if (iface->sc_subdev != NULL)
+ rv |= config_detach(iface->sc_subdev, flags);
}
- usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_ubsa.sc_udev,
- USBDEV(sc->sc_ubsa.sc_dev));
+ usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
return (rv);
}
@@ -420,6 +466,7 @@ int
uhmodem_activate(device_t self, enum devact act)
{
struct uhmodem_softc *sc = device_private(self);
+ struct uhmodem_iface *iface;
int rv = 0;
int i;
@@ -428,66 +475,145 @@ uhmodem_activate(device_t self, enum dev
return (EOPNOTSUPP);
case DVACT_DEACTIVATE:
- for (i = 0; i < sc->sc_ubsa.sc_numif; i++) {
- if (sc->sc_ubsa.sc_subdevs[i] != NULL)
- rv |=
config_deactivate(sc->sc_ubsa.sc_subdevs[i]);
+ for (i = 0; i < sc->sc_numif; i++) {
+ iface = &sc->sc_iface[i];
+ if (iface->sc_subdev != NULL)
+ rv |= config_deactivate(iface->sc_subdev);
}
- sc->sc_ubsa.sc_dying = 1;
+ sc->sc_dying = 1;
break;
}
return (rv);
}
-Static int
+void
+uhmodem_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
+{
+ struct uhmodem_softc *sc = addr;
+ struct uhmodem_iface *iface = &sc->sc_iface[portno];
+
+ if (lsr != NULL)
+ *lsr = iface->sc_lsr;
+ if (msr != NULL)
+ *msr = iface->sc_msr;
+}
+
+int
+uhmodem_param(void *addr, int portno, struct termios *t)
+{
+ struct uhmodem_softc *sc = addr;
+ usbd_status err;
+ usb_cdc_line_state_t ls;
+
+ DPRINTF(("%s: called with speed:%d, flag:0x%02x\n", __func__,
+ t->c_ospeed, t->c_cflag));
+
+ 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 = uhmodem_set_line_coding(sc, portno, &ls);
+ if (err) {
+ DPRINTF(("%s: err=%s\n", __func__, usbd_errstr(err)));
+ return (EPASSTHROUGH);
+ }
+
+ return (0);
+}
+
+void
+uhmodem_set(void *addr, int portno, int reg, int onoff)
+{
+ struct uhmodem_softc *sc = addr;
+ struct uhmodem_iface *iface = &sc->sc_iface[portno];
+ usb_device_request_t req;
+ int ls;
+
+ switch (reg) {
+ case UCOM_SET_DTR:
+ if (iface->sc_dtr == onoff)
+ return;
+ iface->sc_dtr = onoff;
+ break;
+ case UCOM_SET_RTS:
+ if (iface->sc_rts == onoff)
+ return;
+ iface->sc_rts = onoff;
+ break;
+ default:
+ return;
+ }
+
+ /* build a usb request */
+ ls = (iface->sc_dtr ? UCDC_LINE_DTR : 0) |
+ (iface->sc_rts ? UCDC_LINE_RTS : 0);
+ req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
+ req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
+ USETW(req.wValue, ls);
+ USETW(req.wIndex, iface->sc_iface_number);
+ USETW(req.wLength, 0);
+
+ (void)usbd_do_request(sc->sc_udev, &req, 0);
+}
+
+int
uhmodem_open(void *addr, int portno)
{
- struct ubsa_softc *sc = addr;
+ struct uhmodem_softc *sc = addr;
+ struct uhmodem_iface *iface = &sc->sc_iface[portno];
usbd_status err;
if (sc->sc_dying)
return (ENXIO);
- DPRINTF(("%s: sc = %p\n", __func__, sc));
-
- err = uhmodem_endpointhalt(sc, 0);
- if (err)
- aprint_error("%s: endpointhalt fail\n", __func__);
- else
- usbd_delay_ms(sc->sc_udev, 50);
-
- if (sc->sc_devflags & A2502) {
- err = a2502_init(sc->sc_udev);
+#if 0 /* XXX: windows driver issues following request but currently disabled */
+ if (sc->sc_devflags & DEV_E220) {
+ err = e220_init(sc, portno);
if (err)
- aprint_error("%s: a2502init fail\n", __func__);
+ aprint_error("%s: e220 init fail\n", __func__);
else
- usbd_delay_ms(sc->sc_udev, 50);
- }
-#if 0 /* currently disabled */
- if (sc->sc_devflags & E220) {
- err = e220_init(sc->sc_udev);
- if (err)
- aprint_error("%s: e220init fail\n", __func__);
- else
- usbd_delay_ms(sc->sc_udev, 50);
+ usbd_delay_ms(sc->sc_udev, 100);
}
#endif
- if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
- sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
- /* XXX only iface# = 0 has intr line */
- /* XXX E220 specific? need to check */
- err = usbd_open_pipe_intr(sc->sc_iface[0],
- sc->sc_intr_number,
+
+ if (iface->sc_intr_number != -1 && iface->sc_intr_pipe == NULL) {
+ iface->sc_intr_buf = malloc(iface->sc_isize, M_USBDEV,
M_WAITOK);
+ err = usbd_open_pipe_intr(iface->sc_ifaceh,
+ iface->sc_intr_number,
USBD_SHORT_XFER_OK,
- &sc->sc_intr_pipe,
- sc,
- sc->sc_intr_buf,
- sc->sc_isize,
- ubsa_intr,
- UBSA_INTR_INTERVAL);
+ &iface->sc_intr_pipe,
+ iface,
+ iface->sc_intr_buf,
+ iface->sc_isize,
+ uhmodem_intr,
+ UHMODEM_INTR_INTERVAL);
if (err) {
aprint_error_dev(sc->sc_dev,
"cannot open interrupt pipe (addr %d)\n",
- sc->sc_intr_number);
+ iface->sc_intr_number);
return (EIO);
}
}
@@ -495,6 +621,85 @@ uhmodem_open(void *addr, int portno)
return (0);
}
+void
+uhmodem_close(void *addr, int portno)
+{
+ struct uhmodem_softc *sc = addr;
+ struct uhmodem_iface *iface = &sc->sc_iface[portno];
+ int err;
+
+ if (sc->sc_dying)
+ return;
+
+ if (iface->sc_intr_pipe != NULL) {
+ err = usbd_abort_pipe(iface->sc_intr_pipe);
+ if (err)
+ aprint_error_dev(sc->sc_dev,
+ "abort interrupt pipe failed: %s\n",
+ usbd_errstr(err));
+ err = usbd_close_pipe(iface->sc_intr_pipe);
+ if (err)
+ aprint_error_dev(sc->sc_dev,
+ "close interrupt pipe failed: %s\n",
+ usbd_errstr(err));
+ free(iface->sc_intr_buf, M_USBDEV);
+ iface->sc_intr_pipe = NULL;
+ }
+}
+
+void
+uhmodem_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
+ usbd_status status)
+{
+ struct uhmodem_iface *iface = priv;
+ struct uhmodem_softc *sc = iface->parent;
+ usb_cdc_notification_t *buf;
+ u_char mstatus;
+
+
+ buf = (usb_cdc_notification_t *)iface->sc_intr_buf;
+ if (sc->sc_dying)
+ return;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
+ return;
+ aprint_error_dev(sc->sc_dev,
+ "uhmodem interrupt abnormal status: %s\n",
+ usbd_errstr(status));
+ usbd_clear_endpoint_stall_async(iface->sc_intr_pipe);
+ return;
+ }
+
+ if (buf->bmRequestType != UCDC_NOTIFICATION) {
+ aprint_error_dev(sc->sc_dev,
+ "uhmodem_intr: unknown message type(0x%02x)\n",
+ buf->bmRequestType);
+ return;
+ }
+ if (buf->bNotification == UCDC_N_SERIAL_STATE) {
+ /* invalid message length, discard it */
+ if (UGETW(buf->wLength) != 2)
+ return;
+ /* XXX: sc_lsr is always 0 */
+ iface->sc_lsr = iface->sc_msr = 0;
+ mstatus = buf->data[0];
+ if (ISSET(mstatus, UCDC_N_SERIAL_RI))
+ iface->sc_msr |= UMSR_RI;
+ if (ISSET(mstatus, UCDC_N_SERIAL_DSR))
+ iface->sc_msr |= UMSR_DSR;
+ if (ISSET(mstatus, UCDC_N_SERIAL_DCD))
+ iface->sc_msr |= UMSR_DCD;
+ } else if (buf->bNotification != UCDC_N_CONNECTION_SPEED_CHANGE) {
+ aprint_error_dev(sc->sc_dev,
+ "uhmodem_intr: unknown notify message (0x%02x)\n",
+ buf->bNotification);
+ return;
+ }
+
+ ucom_status_change(device_private(iface->sc_subdev));
+}
+
/*
* Hauwei E220 needs special request to enable modem function.
* -- DEVICE_REMOTE_WAKEUP ruquest to endpoint 2.
@@ -502,7 +707,6 @@ uhmodem_open(void *addr, int portno)
Static usbd_status
e220_modechange_request(usbd_device_handle dev)
{
-#define E220_MODE_CHANGE_REQUEST 0x2
usb_device_request_t req;
usbd_status err;
@@ -520,28 +724,30 @@ e220_modechange_request(usbd_device_hand
}
return (0);
-#undef E220_MODE_CHANGE_REQUEST
}
Static usbd_status
-uhmodem_endpointhalt(struct ubsa_softc *sc, int iface)
+uhmodem_endpointhalt(struct uhmodem_softc *sc, int port)
{
usb_device_request_t req;
usb_endpoint_descriptor_t *ed;
usb_interface_descriptor_t *id;
+ struct uhmodem_iface *iface;
usbd_status err;
int i;
- /* Find the endpoints */
- id = usbd_get_interface_descriptor(sc->sc_iface[iface]);
+ iface = &sc->sc_iface[port];
+ id = usbd_get_interface_descriptor(iface->sc_ifaceh);
for (i = 0; i < id->bNumEndpoints; i++) {
- ed = usbd_interface2endpoint_descriptor(sc->sc_iface[iface], i);
+ ed = usbd_interface2endpoint_descriptor(iface->sc_ifaceh, i);
if (ed == NULL)
return (EIO);
if (UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
/* issue ENDPOINT_HALT request */
+ DPRINTF(("%s: endpoint halt to EP:0x%.2x\n",
+ __func__, ed->bEndpointAddress));
req.bmRequestType = UT_WRITE_ENDPOINT;
req.bRequest = UR_CLEAR_FEATURE;
USETW(req.wValue, UF_ENDPOINT_HALT);
@@ -553,7 +759,6 @@ uhmodem_endpointhalt(struct ubsa_softc *
__func__, ed->bEndpointAddress));
return (EIO);
}
-
}
} /* end of Endpoint loop */
@@ -561,147 +766,105 @@ uhmodem_endpointhalt(struct ubsa_softc *
}
Static usbd_status
-uhmodem_regwrite(usbd_device_handle dev, uint8_t *data, size_t len)
+uhmodem_set_line_coding(struct uhmodem_softc *sc, int portno,
+ usb_cdc_line_state_t *state)
{
usb_device_request_t req;
usbd_status err;
+ int iface = sc->sc_iface[portno].sc_iface_number;
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
- req.bRequest = UHMODEM_REGWRITE;
- USETW(req.wValue, 0x0000);
- USETW(req.wIndex, 0x0000);
- USETW(req.wLength, len);
- err = usbd_do_request(dev, &req, data);
+ req.bRequest = UCDC_SET_LINE_CODING;
+ USETW(req.wValue, 0); /* zero */
+ USETW(req.wIndex, iface); /* iface */
+ USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
+ err = usbd_do_request(sc->sc_udev, &req, state);
if (err)
return err;
- return 0;
+ return (USBD_NORMAL_COMPLETION);
}
Static usbd_status
-uhmodem_regread(usbd_device_handle dev, uint8_t *data, size_t len)
+uhmodem_get_line_coding(struct uhmodem_softc *sc, int portno,
+ usb_cdc_line_state_t *state)
{
usb_device_request_t req;
usbd_status err;
+ int iface = sc->sc_iface[portno].sc_iface_number;
req.bmRequestType = UT_READ_CLASS_INTERFACE;
- req.bRequest = UHMODEM_REGREAD;
- USETW(req.wValue, 0x0000);
- USETW(req.wIndex, 0x0000);
- USETW(req.wLength, len);
- err = usbd_do_request(dev, &req, data);
+ req.bRequest = UCDC_GET_LINE_CODING;
+ USETW(req.wValue, 0); /* zero */
+ USETW(req.wIndex, iface); /* iface */
+ USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
+ err = usbd_do_request(sc->sc_udev, &req, state);
if (err)
return err;
- return 0;
+ return (USBD_NORMAL_COMPLETION);
}
-#if 0
Static usbd_status
-uhmodem_regsetup(usbd_device_handle dev, uint16_t cmd)
+uhmodem_set_ctrl_line_state(struct uhmodem_softc *sc, int portno, uint16_t cmd)
{
usb_device_request_t req;
usbd_status err;
+ int iface = sc->sc_iface[portno].sc_iface_number;
req.bmRequestType = UT_READ_CLASS_INTERFACE;
- req.bRequest = UHMODEM_SETUP;
- USETW(req.wValue, cmd);
- USETW(req.wIndex, 0x0000);
- USETW(req.wLength, 0);
- err = usbd_do_request(dev, &req, 0);
+ req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
+ USETW(req.wValue, cmd); /* control signal bitmap */
+ USETW(req.wIndex, iface); /* iface */
+ USETW(req.wLength, 0); /* zero */
+ err = usbd_do_request(sc->sc_udev, &req, 0);
if (err)
return err;
- return 0;
+ return (USBD_NORMAL_COMPLETION);
}
-#endif
-Static usbd_status
-a2502_init(usbd_device_handle dev)
-{
- uint8_t data[8];
- static uint8_t init_cmd[] = {0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x08};
-#ifdef UHMODEM_DEBUG
- int i;
-#endif
- if (uhmodem_regread(dev, data, 7)) {
- DPRINTF(("%s: read fail\n", __func__));
- return EIO;
- }
-#ifdef UHMODEM_DEBUG
- printf("%s: readdata: ", __func__);
- for (i = 0; i < 7; i++)
- printf("0x%x ", data[i]);
-#endif
- if (uhmodem_regwrite(dev, init_cmd, sizeof(init_cmd)) ) {
- DPRINTF(("%s: write fail\n", __func__));
- return EIO;
- }
-
- if (uhmodem_regread(dev, data, 7)) {
- DPRINTF(("%s: read fail\n", __func__));
- return EIO;
- }
-#ifdef UHMODEM_DEBUG
- printf("%s: readdata: ", __func__);
- printf(" => ");
- for (i = 0; i < 7; i++)
- printf("0x%x ", data[i]);
- printf("\n");
-#endif
- return 0;
-}
-
-
-#if 0
-/*
- * Windows device driver send these sequens of USB requests.
- * However currently I can't understand what the messege is,
- * disable this code when I get more information about it.
- */
-Static usbd_status
-e220_init(usbd_device_handle dev)
+Static usbd_status
+uhmodem_set_comm_feature(struct uhmodem_softc *sc, int portno,
+ usb_cdc_abstract_state_t *as)
{
- uint8_t data[8];
usb_device_request_t req;
- int i;
+ usbd_status err;
+ int iface = sc->sc_iface[portno].sc_iface_number;
- /* vendor specific unknown request */
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
- req.bRequest = 0x02;
- USETW(req.wValue, 0x0001);
- USETW(req.wIndex, 0x0000);
- USETW(req.wLength, 2);
- data[0] = 0x0;
- data[1] = 0x0;
- if (usbd_do_request(dev, &req, data))
- goto error;
+ req.bRequest = UCDC_SET_COMM_FEATURE;
+ USETW(req.wValue, UCDC_ABSTRACT_STATE); /* feature selector */
+ USETW(req.wIndex, iface); /* iface */
+ USETW(req.wLength, UCDC_ABSTRACT_STATE_LENGTH);
- /* vendor specific unknown sequence */
- if(uhmodem_regsetup(dev, 0x1))
- goto error;
+ err = usbd_do_request(sc->sc_udev, &req, as);
+ if (err)
+ return err;
- if (uhmodem_regread(dev, data, 7))
- goto error;
+ return (USBD_NORMAL_COMPLETION);
+}
- data[1] = 0x8;
- data[2] = 0x7;
- if (uhmodem_regwrite(dev, data, sizeof(data)) )
- goto error;
+#if 0
+Static usbd_status
+e220_init(struct uhmodem_softc *sc, int portno)
+{
+ usb_cdc_abstract_state_t as;
- if (uhmodem_regread(dev, data, 7))
+ USETW(as.wState, 0); /* state no multiplex, no idle */
+ if (uhmodem_set_comm_feature(sc, portno, &as))
goto error;
- /* XXX should verify the read data ? */
- if (uhmodem_regsetup(dev, 0x3))
+ if (uhmodem_set_ctrl_line_state(sc, portno,
+ UCDC_LINE_DTR | UCDC_LINE_RTS))
goto error;
return (0);
error:
DPRINTF(("%s: E220 init request fail\n", __func__));
- return (EIO);
+ return (USBD_IOERROR);
}
#endif
Index: sys/dev/usb/files.usb
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/files.usb,v
retrieving revision 1.84
diff -u -p -r1.84 files.usb
--- sys/dev/usb/files.usb 26 May 2008 00:23:05 -0000 1.84
+++ sys/dev/usb/files.usb 2 Jul 2008 01:14:32 -0000
@@ -242,7 +242,7 @@ attach ubsa at usbifif
file dev/usb/ubsa.c ubsa
# Huawei E220 3G/HSDPA modem (ubsa)
-device uhmodem: ucombus, ubsa_common
+device uhmodem: ucombus
attach uhmodem at usbifif
file dev/usb/uhmodem.c uhmodem
Home |
Main Index |
Thread Index |
Old Index