summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2014-03-25 03:29:24 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2014-03-25 03:29:24 +0000
commit1191fcbd26db3675f1291fd568d5043416fa279c (patch)
treecced08be07e021d15fdbbb9628ae37fe3c933729 /sys
parent64f66602d9a159107c73599bb7591a8c561ffbe2 (diff)
Add a driver for simple usb serial devices, it attaches
ucom but doesn't set any custom callbacks. John Long has a HPx9G+ device that requires this.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/files.usb7
-rw-r--r--sys/dev/usb/uscom.c184
2 files changed, 190 insertions, 1 deletions
diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb
index 2043f88a1a2..06729e6784e 100644
--- a/sys/dev/usb/files.usb
+++ b/sys/dev/usb/files.usb
@@ -1,4 +1,4 @@
-# $OpenBSD: files.usb,v 1.113 2014/03/17 18:40:46 andre Exp $
+# $OpenBSD: files.usb,v 1.114 2014/03/25 03:29:23 jsg Exp $
# $NetBSD: files.usb,v 1.16 2000/02/14 20:29:54 augustss Exp $
#
# Config file and device description for machine-independent USB code.
@@ -319,6 +319,11 @@ device moscom: ucombus
attach moscom at uhub
file dev/usb/moscom.c moscom
+# simple serial
+device uscom: ucombus
+attach uscom at uhub
+file dev/usb/uscom.c uscom
+
# iPAQ PDAs
# Generic ipaq support
device uipaq: ucombus
diff --git a/sys/dev/usb/uscom.c b/sys/dev/usb/uscom.c
new file mode 100644
index 00000000000..9e4cf5bde23
--- /dev/null
+++ b/sys/dev/usb/uscom.c
@@ -0,0 +1,184 @@
+/* $OpenBSD: uscom.c,v 1.1 2014/03/25 03:29:23 jsg Exp $ */
+
+/*
+ * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/tty.h>
+#include <sys/device.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdevs.h>
+
+#include <dev/usb/usbdevs.h>
+#include <dev/usb/ucomvar.h>
+
+#define USCOMBUFSZ 256
+#define USCOM_CONFIG_NO 0
+#define USCOM_IFACE_NO 0
+
+struct uscom_softc {
+ struct device sc_dev;
+ struct usbd_device *sc_udev;
+ struct usbd_interface *sc_iface;
+ struct device *sc_subdev;
+};
+
+struct ucom_methods uscom_methods = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static const struct usb_devno uscom_devs[] = {
+ { USB_VENDOR_HP, USB_PRODUCT_HP_HPX9GP }
+};
+
+int uscom_match(struct device *, void *, void *);
+void uscom_attach(struct device *, struct device *, void *);
+int uscom_detach(struct device *, int);
+int uscom_activate(struct device *, int);
+
+struct cfdriver uscom_cd = {
+ NULL, "uscom", DV_DULL
+};
+
+const struct cfattach uscom_ca = {
+ sizeof(struct uscom_softc),
+ uscom_match,
+ uscom_attach,
+ uscom_detach,
+ uscom_activate,
+};
+
+int
+uscom_match(struct device *parent, void *match, void *aux)
+{
+ struct usb_attach_arg *uaa = aux;
+
+ if (uaa->iface != NULL)
+ return UMATCH_NONE;
+
+ return (usb_lookup(uscom_devs, uaa->vendor, uaa->product) != NULL) ?
+ UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
+}
+
+void
+uscom_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct uscom_softc *sc = (struct uscom_softc *)self;
+ struct usb_attach_arg *uaa = aux;
+ struct ucom_attach_args uca;
+ usb_interface_descriptor_t *id;
+ usb_endpoint_descriptor_t *ed;
+ usbd_status error;
+ int i;
+
+ bzero(&uca, sizeof(uca));
+ sc->sc_udev = uaa->device;
+
+ if (usbd_set_config_index(sc->sc_udev, USCOM_CONFIG_NO, 1) != 0) {
+ printf("%s: could not set configuration no\n",
+ sc->sc_dev.dv_xname);
+ usbd_deactivate(sc->sc_udev);
+ return;
+ }
+
+ /* get the first interface handle */
+ error = usbd_device2interface_handle(sc->sc_udev, USCOM_IFACE_NO,
+ &sc->sc_iface);
+ if (error != 0) {
+ printf("%s: could not get interface handle\n",
+ sc->sc_dev.dv_xname);
+ usbd_deactivate(sc->sc_udev);
+ return;
+ }
+
+ id = usbd_get_interface_descriptor(sc->sc_iface);
+
+ uca.bulkin = uca.bulkout = -1;
+ for (i = 0; i < id->bNumEndpoints; i++) {
+ ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
+ if (ed == NULL) {
+ printf("%s: no endpoint descriptor found for %d\n",
+ sc->sc_dev.dv_xname, i);
+ usbd_deactivate(sc->sc_udev);
+ 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 || uca.bulkout == -1) {
+ printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
+ usbd_deactivate(sc->sc_udev);
+ return;
+ }
+
+ uca.ibufsize = USCOMBUFSZ;
+ uca.obufsize = USCOMBUFSZ;
+ uca.ibufsizepad = USCOMBUFSZ;
+ uca.opkthdrlen = 0;
+ uca.device = sc->sc_udev;
+ uca.iface = sc->sc_iface;
+ uca.methods = &uscom_methods;
+ uca.arg = sc;
+ uca.info = NULL;
+
+ sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
+}
+
+int
+uscom_detach(struct device *self, int flags)
+{
+ struct uscom_softc *sc = (struct uscom_softc *)self;
+ int rv = 0;
+
+ if (sc->sc_subdev != NULL) {
+ rv = config_detach(sc->sc_subdev, flags);
+ sc->sc_subdev = NULL;
+ }
+
+ return (rv);
+}
+
+int
+uscom_activate(struct device *self, int act)
+{
+ struct uscom_softc *sc = (struct uscom_softc *)self;
+
+ switch (act) {
+ case DVACT_DEACTIVATE:
+ usbd_deactivate(sc->sc_udev);
+ break;
+ }
+ return (0);
+}