Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb Connect to the interrupt endpoint on the control...



details:   https://anonhg.NetBSD.org/src/rev/fd4e22194bf4
branches:  trunk
changeset: 503866:fd4e22194bf4
user:      kenh <kenh%NetBSD.org@localhost>
date:      Fri Feb 16 20:15:57 2001 +0000

description:
Connect to the interrupt endpoint on the control interface to receive
notification messages.  This lets us properly pass line status changes
down to the ucom driver (specifically, DSR, DCD, and RI).

diffstat:

 sys/dev/usb/umodem.c |  154 +++++++++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/usb/usbcdc.h |   14 ++++-
 2 files changed, 161 insertions(+), 7 deletions(-)

diffs (239 lines):

diff -r f6b524cadcf4 -r fd4e22194bf4 sys/dev/usb/umodem.c
--- a/sys/dev/usb/umodem.c      Fri Feb 16 20:04:18 2001 +0000
+++ b/sys/dev/usb/umodem.c      Fri Feb 16 20:15:57 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: umodem.c,v 1.38 2001/01/23 21:56:17 augustss Exp $     */
+/*     $NetBSD: umodem.c,v 1.39 2001/02/16 20:15:57 kenh Exp $ */
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -113,6 +113,12 @@
 
        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);
@@ -131,14 +137,17 @@
 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,
 };
@@ -209,7 +218,6 @@
               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) {
@@ -276,6 +284,31 @@
                        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.  Interate 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;
@@ -303,6 +336,113 @@
        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)
+               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;
+               }
+       else
+               DPRINTF(("%s: unknown message type (%02x) on notify pipe\n",
+                        USBDEVNAME(sc->sc_dev),
+                        sc->sc_notify_buf.bmRequestType));
+
+       return;
+}
+
 void
 umodem_get_caps(usbd_device_handle dev, int *cm, int *acm)
 {
@@ -329,12 +469,14 @@
 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
diff -r f6b524cadcf4 -r fd4e22194bf4 sys/dev/usb/usbcdc.h
--- a/sys/dev/usb/usbcdc.h      Fri Feb 16 20:04:18 2001 +0000
+++ b/sys/dev/usb/usbcdc.h      Fri Feb 16 20:15:57 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: usbcdc.h,v 1.7 2000/05/30 10:10:18 augustss Exp $      */
+/*     $NetBSD: usbcdc.h,v 1.8 2001/02/16 20:15:57 kenh Exp $  */
 /*     $FreeBSD: src/sys/dev/usb/usbcdc.h,v 1.7 1999/11/17 22:33:48 n_hibma Exp $      */
 
 /*
@@ -146,4 +146,16 @@
 } UPACKED usb_cdc_notification_t;
 #define UCDC_NOTIFICATION_LENGTH 8
 
+/*
+ * Bits set in the SERIAL STATE notifcation (first byte of data)
+ */
+
+#define UCDC_N_SERIAL_OVERRUN          0x40
+#define UCDC_N_SERIAL_PARITY           0x20
+#define UCDC_N_SERIAL_FRAMING          0x10
+#define UCDC_N_SERIAL_RI               0x08
+#define UCDC_N_SERIAL_BREAK            0x04
+#define UCDC_N_SERIAL_DSR              0x02
+#define UCDC_N_SERIAL_DCD              0x01
+
 #endif /* _USBCDC_H_ */



Home | Main Index | Thread Index | Old Index