diff options
author | Aaron Campbell <aaron@cvs.openbsd.org> | 2001-05-03 02:20:36 +0000 |
---|---|---|
committer | Aaron Campbell <aaron@cvs.openbsd.org> | 2001-05-03 02:20:36 +0000 |
commit | 5b92d7a741e1c34c9d68a85e4b9a47c24ea37b56 (patch) | |
tree | ac62c98e8633ce27c0186aaa2e0856e4093ade97 /sys/dev/usb/umodem.c | |
parent | c31dae3edb4a874106f38c4f1418182e49eda727 (diff) |
Sync with NetBSD. Tested with a USB keyboard, USB mouse, and three different
kue(4) Ethernet devices.
Diffstat (limited to 'sys/dev/usb/umodem.c')
-rw-r--r-- | sys/dev/usb/umodem.c | 161 |
1 files changed, 151 insertions, 10 deletions
diff --git a/sys/dev/usb/umodem.c b/sys/dev/usb/umodem.c index 3340bf3765a..df2c0ade0c2 100644 --- a/sys/dev/usb/umodem.c +++ b/sys/dev/usb/umodem.c @@ -1,5 +1,5 @@ -/* $OpenBSD: umodem.c,v 1.6 2001/01/28 09:43:42 aaron Exp $ */ -/* $NetBSD: umodem.c,v 1.31 2000/10/22 08:20:09 explorer Exp $ */ +/* $OpenBSD: umodem.c,v 1.7 2001/05/03 02:20:34 aaron Exp $ */ +/* $NetBSD: umodem.c,v 1.40 2001/03/25 23:02:34 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -114,6 +114,12 @@ struct umodem_softc { u_char sc_opening; /* lock during open */ u_char sc_dying; /* disconnecting */ + + int sc_ctl_notify; /* Notification endpoint */ + usbd_pipe_handle sc_notify_pipe; /* Notification pipe */ + usb_cdc_notification_t sc_notify_buf; /* Notification structure */ + u_char sc_lsr; /* Local status register */ + u_char sc_msr; /* Modem status register */ }; Static void *umodem_get_desc(usbd_device_handle dev, int type, int subtype); @@ -132,14 +138,17 @@ Static void umodem_break(struct umodem_softc *, int); Static void umodem_set_line_state(struct umodem_softc *); Static int umodem_param(void *, int, struct termios *); Static int umodem_ioctl(void *, int, u_long, caddr_t, int, struct proc *); +Static int umodem_open(void *, int portno); +Static void umodem_close(void *, int portno); +Static void umodem_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); Static struct ucom_methods umodem_methods = { umodem_get_status, umodem_set, umodem_param, umodem_ioctl, - NULL, - NULL, + umodem_open, + umodem_close, NULL, NULL, }; @@ -210,7 +219,6 @@ USB_ATTACH(umodem) sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ", sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no "); - /* Get the data interface too. */ for (i = 0; i < uaa->nifaces; i++) { if (uaa->ifaces[i] != NULL) { @@ -277,6 +285,31 @@ USB_ATTACH(umodem) sc->sc_cm_over_data = 1; } } + + /* + * The standard allows for notification messages (to indicate things + * like a modem hangup) to come in via an interrupt endpoint + * off of the control interface. Iterate over the endpoints on + * the control interface and see if there are any interrupt + * endpoints; if there are, then register it. + */ + + sc->sc_ctl_notify = -1; + sc->sc_notify_pipe = NULL; + + for (i = 0; i < id->bNumEndpoints; i++) { + ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i); + if (ed == NULL) + continue; + + if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && + (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { + printf("%s: status change notification available\n", + USBDEVNAME(sc->sc_dev)); + sc->sc_ctl_notify = ed->bEndpointAddress; + } + } + sc->sc_dtr = -1; uca.portno = UCOM_UNK_PORTNO; @@ -289,13 +322,14 @@ USB_ATTACH(umodem) uca.iface = sc->sc_data_iface; uca.methods = &umodem_methods; uca.arg = sc; - - DPRINTF(("umodem_attach: sc=%p\n", sc)); - sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); + uca.info = NULL; usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, USBDEV(sc->sc_dev)); + DPRINTF(("umodem_attach: sc=%p\n", sc)); + sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); + USB_ATTACH_SUCCESS_RETURN; bad: @@ -303,6 +337,111 @@ USB_ATTACH(umodem) USB_ATTACH_ERROR_RETURN; } +Static int +umodem_open(void *addr, int portno) +{ + struct umodem_softc *sc = addr; + int err; + + DPRINTF(("umodem_open: sc=%p\n", sc)); + + if (sc->sc_ctl_notify != -1 && sc->sc_notify_pipe == NULL) { + err = usbd_open_pipe_intr(sc->sc_ctl_iface, sc->sc_ctl_notify, + USBD_SHORT_XFER_OK, &sc->sc_notify_pipe, sc, + &sc->sc_notify_buf, sizeof(sc->sc_notify_buf), + umodem_intr, USBD_DEFAULT_INTERVAL); + + if (err) { + DPRINTF(("Failed to establish notify pipe: %s\n", + usbd_errstr(err))); + return EIO; + } + } + + return 0; +} + +Static void +umodem_close(void *addr, int portno) +{ + struct umodem_softc *sc = addr; + int err; + + DPRINTF(("umodem_close: sc=%p\n", sc)); + + if (sc->sc_notify_pipe != NULL) { + err = usbd_abort_pipe(sc->sc_notify_pipe); + if (err) + printf("%s: abort notify pipe failed: %s\n", + USBDEVNAME(sc->sc_dev), usbd_errstr(err)); + err = usbd_close_pipe(sc->sc_notify_pipe); + if (err) + printf("%s: close notify pipe failed: %s\n", + USBDEVNAME(sc->sc_dev), usbd_errstr(err)); + sc->sc_notify_pipe = NULL; + } +} + +Static void +umodem_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status) +{ + struct umodem_softc *sc = priv; + u_char mstatus; + + if (sc->sc_dying) + return; + + if (status != USBD_NORMAL_COMPLETION) { + if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) + return; + printf("%s: abnormal status: %s\n", USBDEVNAME(sc->sc_dev), + usbd_errstr(status)); + return; + } + + if (sc->sc_notify_buf.bmRequestType != UCDC_NOTIFICATION) { + DPRINTF(("%s: unknown message type (%02x) on notify pipe\n", + USBDEVNAME(sc->sc_dev), + sc->sc_notify_buf.bmRequestType)); + return; + } + + switch (sc->sc_notify_buf.bNotification) { + case UCDC_N_SERIAL_STATE: + /* + * Set the serial state in ucom driver based on + * the bits from the notify message + */ + if (UGETW(sc->sc_notify_buf.wLength) != 2) { + printf("%s: Invalid notification length! (%d)\n", + USBDEVNAME(sc->sc_dev), + UGETW(sc->sc_notify_buf.wLength)); + break; + } + DPRINTF(("%s: notify bytes = %02x%02x\n", + USBDEVNAME(sc->sc_dev), + sc->sc_notify_buf.data[0], + sc->sc_notify_buf.data[1])); + /* Currently, lsr is always zero. */ + sc->sc_lsr = sc->sc_msr = 0; + mstatus = sc->sc_notify_buf.data[0]; + + if (ISSET(mstatus, UCDC_N_SERIAL_RI)) + sc->sc_msr |= UMSR_RI; + if (ISSET(mstatus, UCDC_N_SERIAL_DSR)) + sc->sc_msr |= UMSR_DSR; + if (ISSET(mstatus, UCDC_N_SERIAL_DCD)) + sc->sc_msr |= UMSR_DCD; + ucom_status_change((struct ucom_softc *)sc->sc_subdev); + break; + default: + DPRINTF(("%s: unknown notify message: %02x\n", + USBDEVNAME(sc->sc_dev), + sc->sc_notify_buf.bNotification)); + break; + } +} + void umodem_get_caps(usbd_device_handle dev, int *cm, int *acm) { @@ -329,12 +468,14 @@ umodem_get_caps(usbd_device_handle dev, int *cm, int *acm) void umodem_get_status(void *addr, int portno, u_char *lsr, u_char *msr) { + struct umodem_softc *sc = addr; + DPRINTF(("umodem_get_status:\n")); if (lsr != NULL) - *lsr = 0; /* XXX */ + *lsr = sc->sc_lsr; if (msr != NULL) - *msr = 0; /* XXX */ + *msr = sc->sc_msr; } int |