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