PERFORCE change 105471 for review

Hans Petter Selasky hselasky at FreeBSD.org
Fri Sep 1 18:03:29 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=105471

Change 105471 by hselasky at hselasky_mini_itx on 2006/09/01 18:02:55

	Finished reworking "ufoma". Please test!

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/ufoma.c#4 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/ufoma.c#4 (text+ko) ====

@@ -1,0 +1,1386 @@
+/*	$NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $	*/
+
+/*-
+ * Copyright (c) 2005, Takanori Watanabe
+ * Copyright (c) 2003, M. Warner Losh <imp at freebsd.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart at augustsson.net) at
+ * Carlstedt Research & Technology.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Comm Class spec:  http://www.usb.org/developers/devclass_docs/usbccs10.pdf
+ *                   http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
+ */
+
+/*
+ * TODO:
+ * - Implement a Call Device for modems without multiplexed commands.
+ */
+
+/*
+ * NOTE: all function names beginning like "ufoma_cfg_" can only
+ * be called from within the config thread function !
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/termios.h>
+#include <sys/serial.h>
+#include <sys/taskqueue.h>
+#include <sys/malloc.h>
+
+#define usbd_config_td_cc ufoma_config_copy
+#define usbd_config_td_softc ufoma_softc
+
+#include <dev/usb/usb_port.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usb_subr.h>
+#include <dev/usb/usb_quirks.h>
+#include <dev/usb/usb_cdc.h>
+
+#include <dev/usb/ucomvar.h>
+
+#include "usbdevs.h"
+
+__FBSDID("$FreeBSD: src/sys/dev/usb/ufoma.c,v 1.1 2006/01/09 17:46:36 takawata Exp $");
+
+typedef struct ufoma_mobile_acm_descriptor{
+	u_int8_t bFunctionLength;
+	u_int8_t bDescriptorType;
+	u_int8_t bDescriptorSubtype;
+	u_int8_t bType;
+	u_int8_t bMode[1];
+} UPACKED usb_mcpc_acm_descriptor;
+
+#define UISUBCLASS_MCPC 0x88
+
+#define UDESC_VS_INTERFACE 0x44
+#define UDESCSUB_MCPC_ACM  0x11
+
+#define UMCPC_ACM_TYPE_AB1 0x1
+#define UMCPC_ACM_TYPE_AB2 0x2
+#define UMCPC_ACM_TYPE_AB5 0x5
+#define UMCPC_ACM_TYPE_AB6 0x6
+
+#define UMCPC_ACM_MODE_DEACTIVATED 0x0
+#define UMCPC_ACM_MODE_MODEM 0x1
+#define UMCPC_ACM_MODE_ATCOMMAND 0x2
+#define UMCPC_ACM_MODE_OBEX 0x60
+#define UMCPC_ACM_MODE_VENDOR1 0xc0
+#define UMCPC_ACM_MODE_VENDOR2 0xfe
+#define UMCPC_ACM_MODE_UNLINKED 0xff
+
+#define UMCPC_CM_MOBILE_ACM 0x0
+
+#define UMCPC_ACTIVATE_MODE 0x60
+#define UMCPC_GET_MODETABLE 0x61
+#define UMCPC_SET_LINK 0x62
+#define UMCPC_CLEAR_LINK 0x63
+
+#define UMCPC_REQUEST_ACKNOWLEDGE 0x31
+
+#define UFOMA_MAX_TIMEOUT 15 /* standard says 10 seconds */
+#define UFOMA_CMD_BUF_SIZE 64 /* bytes */
+
+#define UFOMA_BULK_IBUFSIZE 64 /* bytes */
+#define UFOMA_BULK_OBUFSIZE 256 /* bytes */
+
+#define UFOMA_CTRL_ENDPT_MAX 4 /* units */
+#define UFOMA_BULK_ENDPT_MAX 4 /* units */
+
+#define DPRINTF(...)
+
+struct ufoma_softc {
+
+	struct ucom_softc	sc_ucom;
+	struct usbd_config_td	sc_config_td;
+	struct usbd_memory_wait sc_mem_wait;
+	usb_cdc_line_state_t	sc_line_state; /* current line state */
+
+	struct usbd_xfer *	sc_ctrl_xfer[UFOMA_CTRL_ENDPT_MAX];
+	struct usbd_xfer *	sc_bulk_xfer[UFOMA_BULK_ENDPT_MAX];
+	u_int8_t *		sc_modetable;
+	device_t		sc_dev;
+	struct usbd_device *	sc_udev;
+
+	u_int32_t sc_unit;
+
+	u_int8_t sc_num_msg;
+	u_int8_t sc_is_pseudo;
+	u_int8_t sc_ctrl_iface_no;
+	u_int8_t sc_ctrl_iface_index;
+	u_int8_t sc_data_iface_no;
+	u_int8_t sc_data_iface_index;
+	u_int8_t sc_cm_cap;
+	u_int8_t sc_acm_cap;
+	u_int8_t sc_dtr; /* current DTR state */
+	u_int8_t sc_rts; /* current RTS state */
+	u_int8_t sc_lsr;
+	u_int8_t sc_msr;
+	u_int8_t sc_break;
+	u_int8_t sc_modetoactivate;
+	u_int8_t sc_currentmode;
+	u_int8_t sc_flags;
+#define UFOMA_FLAG_INTR_STALL        0x01
+#define UFOMA_FLAG_BULK_WRITE_STALL  0x02
+#define UFOMA_FLAG_BULK_READ_STALL   0x04
+
+	u_int8_t sc_name[16];
+};
+
+struct ufoma_config_copy {
+
+	usb_cdc_line_state_t line_state;
+
+	u_int8_t break_onoff;
+	u_int8_t dtr_onoff;
+	u_int8_t rts_onoff;
+};
+
+/* prototypes */
+
+static device_probe_t ufoma_probe;
+static device_attach_t ufoma_attach;
+static device_detach_t ufoma_detach;
+
+static void
+ufoma_cfg_do_request(struct ufoma_softc *sc, usb_device_request_t *req, 
+		     void *data);
+static void *
+ufoma_get_intconf(usb_config_descriptor_t *cd, usb_interface_descriptor_t *id, 
+		  u_int8_t type, u_int8_t subtype);
+static void
+ufoma_cfg_link_state(struct ufoma_softc *sc);
+
+static void
+ufoma_cfg_activate_state(struct ufoma_softc *sc, u_int16_t state);
+
+static void
+ufoma_ctrl_read_callback(struct usbd_xfer *xfer);
+
+static void
+ufoma_ctrl_write_callback(struct usbd_xfer *xfer);
+
+static void
+ufoma_intr_clear_stall_callback(struct usbd_xfer *xfer);
+
+static void
+ufoma_intr_callback(struct usbd_xfer *xfer);
+
+static void
+ufoma_bulk_write_callback(struct usbd_xfer *xfer);
+
+static void
+ufoma_bulk_write_clear_stall_callback(struct usbd_xfer *xfer);
+
+static void
+ufoma_bulk_read_callback(struct usbd_xfer *xfer);
+
+static void
+ufoma_bulk_read_clear_stall_callback(struct usbd_xfer *xfer);
+
+static void
+ufoma_config_copy(struct ufoma_softc *sc,
+		  struct ufoma_config_copy *cc, u_int16_t refcount);
+static int
+ufoma_open(struct ucom_softc *ucom);
+
+static void
+ufoma_cfg_open(struct ufoma_softc *sc,
+	       struct ufoma_config_copy *cc, u_int16_t refcount);
+static void
+ufoma_close(struct ucom_softc *ucom);
+
+static void
+ufoma_cfg_close(struct ufoma_softc *sc,
+		struct ufoma_config_copy *cc, u_int16_t refcount);
+static void
+ufoma_set_break(struct ucom_softc *ucom, u_int8_t onoff);
+
+static void
+ufoma_cfg_set_break(struct ufoma_softc *sc,
+		    struct ufoma_config_copy *cc, u_int16_t refcount);
+static void
+ufoma_get_status(struct ucom_softc *ucom, u_int8_t *lsr, u_int8_t *msr);
+
+static void
+ufoma_cfg_set_line_state(struct ufoma_softc *sc, 
+			 struct ufoma_config_copy *cc, u_int16_t refcount);
+static void
+ufoma_set_dtr(struct ucom_softc *ucom, u_int8_t onoff);
+
+static void
+ufoma_set_rts(struct ucom_softc *ucom, u_int8_t onoff);
+
+static void
+ufoma_cfg_set_line_coding(struct ufoma_softc *sc, 
+			  struct ufoma_config_copy *cc, u_int16_t refcount);
+static int
+ufoma_param(struct ucom_softc *ucom, struct termios *t);
+
+static int
+ufoma_modem_setup(device_t dev, struct ufoma_softc *sc, 
+		  struct usb_attach_arg *uaa);
+static void
+ufoma_start_read(struct ucom_softc *ucom);
+
+static void
+ufoma_stop_read(struct ucom_softc *ucom);
+
+static void
+ufoma_start_write(struct ucom_softc *ucom);
+
+static void
+ufoma_stop_write(struct ucom_softc *ucom);
+
+static const struct usbd_config 
+ufoma_ctrl_config[UFOMA_CTRL_ENDPT_MAX] = {
+
+   [0] = {
+      .type      = UE_INTERRUPT,
+      .endpoint  = -1, /* any */
+      .direction = UE_DIR_IN,
+      .flags     = USBD_SHORT_XFER_OK,
+      .bufsize   = sizeof(usb_cdc_notification_t),
+      .callback  = &ufoma_intr_callback,
+    },
+
+    [1] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .flags     = USBD_USE_DMA,
+      .callback  = &ufoma_intr_clear_stall_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [2] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = (sizeof(usb_device_request_t) + UFOMA_CMD_BUF_SIZE),
+      .flags     = USBD_SHORT_XFER_OK,
+      .callback  = &ufoma_ctrl_read_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [3] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = (sizeof(usb_device_request_t) + 1),
+      .flags     = 0,
+      .callback  = &ufoma_ctrl_write_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+};
+
+static const struct usbd_config 
+ufoma_bulk_config[UFOMA_BULK_ENDPT_MAX] = {
+
+    [0] = {
+      .type      = UE_BULK,
+      .endpoint  = -1, /* any */
+      .direction = UE_DIR_OUT,
+      .bufsize   = UFOMA_BULK_OBUFSIZE,
+      .flags     = 0,
+      .callback  = &ufoma_bulk_write_callback,
+    },
+
+    [1] = {
+      .type      = UE_BULK,
+      .endpoint  = -1, /* any */
+      .direction = UE_DIR_IN,
+      .bufsize   = UFOMA_BULK_IBUFSIZE,
+      .flags     = USBD_SHORT_XFER_OK,
+      .callback  = &ufoma_bulk_read_callback,
+    },
+
+    [2] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .flags     = (USBD_USE_DMA),
+      .callback  = &ufoma_bulk_write_clear_stall_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+
+    [3] = {
+      .type      = UE_CONTROL,
+      .endpoint  = 0x00, /* Control pipe */
+      .direction = -1,
+      .bufsize   = sizeof(usb_device_request_t),
+      .flags     = (USBD_USE_DMA),
+      .callback  = &ufoma_bulk_read_clear_stall_callback,
+      .timeout   = 1000, /* 1 second */
+    },
+};
+
+static const struct ucom_callback ufoma_callback = {
+    .ucom_get_status  = &ufoma_get_status,
+    .ucom_set_dtr     = &ufoma_set_dtr,
+    .ucom_set_rts     = &ufoma_set_rts,
+    .ucom_set_break   = &ufoma_set_break,
+    .ucom_param       = &ufoma_param,
+    .ucom_open        = &ufoma_open,
+    .ucom_close       = &ufoma_close,
+    .ucom_start_read  = &ufoma_start_read,
+    .ucom_stop_read   = &ufoma_stop_read,
+    .ucom_start_write = &ufoma_start_write,
+    .ucom_stop_write  = &ufoma_stop_write,
+};
+
+static device_method_t ufoma_methods[] = { 
+    /* Device methods */
+    DEVMETHOD(device_probe, ufoma_probe),
+    DEVMETHOD(device_attach, ufoma_attach),
+    DEVMETHOD(device_detach, ufoma_detach),
+    { 0, 0 }
+};
+
+static driver_t ufoma_driver = {
+    "ucom",
+    ufoma_methods,
+    sizeof(struct ufoma_softc)
+};
+
+static devclass_t ucom_devclass;
+
+DRIVER_MODULE(ufoma, uhub, ufoma_driver, ucom_devclass, usbd_driver_load, 0);
+MODULE_DEPEND(ufoma, usb, 1, 1, 1);
+MODULE_DEPEND(ufoma, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
+
+static int
+ufoma_probe(device_t dev)
+{
+	struct usb_attach_arg *uaa = device_get_ivars(dev);
+	usb_interface_descriptor_t *id;
+	usb_config_descriptor_t *cd;
+	usb_mcpc_acm_descriptor *mad;
+
+	if(uaa->iface == NULL) {
+	    return UMATCH_NONE;
+	}
+
+	id = usbd_get_interface_descriptor(uaa->iface);
+	cd = usbd_get_config_descriptor(uaa->device);
+
+	if ((id == NULL) || 
+	    (cd == NULL) ||
+	    (id->bInterfaceClass != UICLASS_CDC) ||
+	    (id->bInterfaceSubClass != UISUBCLASS_MCPC)){
+	    return UMATCH_NONE;
+	}
+
+	mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
+	if(mad == NULL){
+	    return UMATCH_NONE;
+	}
+#if 0
+	if(mad->bType != UMCPC_ACM_TYPE_AB5){
+	    return UMATCH_NONE;
+	}
+#endif
+	return UMATCH_IFACECLASS_IFACESUBCLASS;
+}
+
+static int
+ufoma_attach(device_t dev)
+{
+	struct usb_attach_arg *uaa = device_get_ivars(dev);
+	struct ufoma_softc *sc = device_get_softc(dev);
+	usb_config_descriptor_t *cd;
+	usb_interface_descriptor_t *id;
+	usb_mcpc_acm_descriptor *mad;
+	u_int8_t elements;
+	int32_t error;
+
+	if (sc == NULL) {
+	    return ENOMEM;
+	}
+
+	sc->sc_udev = uaa->device;
+	sc->sc_dev = dev;
+	sc->sc_unit = device_get_unit(dev);
+
+	usbd_set_desc(dev, uaa->device);
+
+	snprintf(sc->sc_name, sizeof(sc->sc_name),
+		 "%s", device_get_nameunit(dev));
+
+	DPRINTF(sc, 0, "\n");
+
+	/* setup control transfers */
+
+	cd = usbd_get_config_descriptor(uaa->device);
+	id = usbd_get_interface_descriptor(uaa->iface);
+	sc->sc_ctrl_iface_no = id->bInterfaceNumber;
+	sc->sc_ctrl_iface_index = uaa->iface_index;
+
+	error = usbd_transfer_setup
+	  (uaa->device, sc->sc_ctrl_iface_index, 
+	   sc->sc_ctrl_xfer, ufoma_ctrl_config, UFOMA_CTRL_ENDPT_MAX,
+	   sc, &Giant, &(sc->sc_mem_wait));
+
+	if (error) {
+	    device_printf(dev, "allocating control USB "
+			  "transfers failed!\n");
+	    goto detach;
+	}
+
+	mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
+	if (mad == NULL){
+	    goto detach;
+	}
+
+	if (mad->bFunctionLength < sizeof(*mad)) {
+	    device_printf(dev, "invalid MAD descriptor\n");
+	    goto detach;
+	}
+
+	if(mad->bType == UMCPC_ACM_TYPE_AB5) {
+	    sc->sc_is_pseudo = 1;
+	} else {
+	    sc->sc_is_pseudo = 0;
+	    if (ufoma_modem_setup(dev, sc, uaa)) {
+	        goto detach;
+	    }
+	}
+
+	elements = (mad->bFunctionLength - sizeof(*mad) + 1);
+
+	/* initialize mode variables */
+
+	sc->sc_modetable = malloc(elements + 1, M_USBDEV, M_WAITOK);
+
+	if (sc->sc_modetable == NULL) {
+	    goto detach;
+	}
+
+	sc->sc_modetable[0] = (elements + 1);
+	bcopy(mad->bMode, &(sc->sc_modetable[1]), elements);
+
+	sc->sc_currentmode = UMCPC_ACM_MODE_UNLINKED;
+	sc->sc_modetoactivate = mad->bMode[0];
+
+	/* setup UCOM */
+
+        sc->sc_ucom.sc_parent = sc;
+        sc->sc_ucom.sc_portno = 0;
+        sc->sc_ucom.sc_callback = &ufoma_callback;
+
+        error = ucom_attach(&(sc->sc_ucom), dev);
+
+        if (error) {
+            DPRINTF(0, "ucom_attach failed\n");
+            goto detach;
+        }
+
+	/* setup config thread */
+
+	error = usbd_config_td_setup(&(sc->sc_config_td), sc, &Giant,
+				     &ufoma_config_copy, NULL,
+				     sizeof(struct ufoma_config_copy), 16);
+	if (error) {
+	    device_printf(dev, "could not setup config "
+			  "thread!\n");
+	    goto detach;
+	}
+
+	return 0; /* success */
+
+ detach:
+	ufoma_detach(dev);
+	return ENXIO; /* failure */
+}
+
+static int
+ufoma_detach(device_t dev)
+{
+	struct ufoma_softc *sc = device_get_softc(dev);
+
+        mtx_lock(&Giant);
+
+        usbd_config_td_stop(&(sc->sc_config_td));
+
+        mtx_unlock(&Giant);
+
+        ucom_detach(&(sc->sc_ucom));
+
+        usbd_transfer_unsetup(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX);
+
+        usbd_transfer_unsetup(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX);
+
+        usbd_transfer_drain(&(sc->sc_mem_wait), &Giant);
+
+        usbd_config_td_unsetup(&(sc->sc_config_td));
+
+	if (sc->sc_modetable) {
+	    free(sc->sc_modetable, M_USBDEV);
+	}
+	return 0;
+}
+
+static void
+ufoma_cfg_do_request(struct ufoma_softc *sc, usb_device_request_t *req, 
+		     void *data)
+{
+	u_int16_t length;
+	usbd_status err;
+
+	if (usbd_config_td_is_gone(&(sc->sc_config_td))) {
+	    goto error;
+	}
+
+	err = usbd_do_request_flags_mtx(sc->sc_udev, &Giant, req, 
+					data, 0, NULL, 1000);
+
+	if (err) {
+
+	    DPRINTF(sc, 0, "device request failed, err=%s "
+		    "(ignored)\n", usbd_errstr(err));
+
+	error:
+	    length = UGETW(req->wLength);
+
+	    if ((req->bmRequestType & UT_READ) && length) {
+		bzero(data, length);
+	    }
+	}
+	return;
+}
+
+static void *
+ufoma_get_intconf(usb_config_descriptor_t *cd, usb_interface_descriptor_t *id, 
+		  u_int8_t type, u_int8_t subtype)
+{
+	usb_descriptor_t *desc = (void *)id;
+
+	while ((desc = usbd_desc_foreach(cd,desc))) {
+
+	    if(desc->bDescriptorType == UDESC_INTERFACE){
+	        return NULL;
+	    }
+
+	    if((desc->bDescriptorType == type) &&
+	       (desc->bDescriptorSubtype == subtype)) {
+	        break;
+	    }
+	}
+	return desc;
+}
+
+static void
+ufoma_cfg_link_state(struct ufoma_softc *sc)
+{
+	usb_device_request_t req;
+	int32_t error;
+
+	req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
+	req.bRequest = UMCPC_SET_LINK;
+	USETW(req.wValue, UMCPC_CM_MOBILE_ACM);
+	USETW(req.wIndex, sc->sc_ctrl_iface_no);
+	USETW(req.wLength, sc->sc_modetable[0]);
+
+	ufoma_cfg_do_request(sc, &req, sc->sc_modetable);
+
+	error = msleep(&(sc->sc_currentmode), &Giant, PZERO, "ufoma_link", hz);
+
+	if(error){
+		DPRINTF(sc, 0, "NO response\n");
+	}
+	return;
+}
+
+static void
+ufoma_cfg_activate_state(struct ufoma_softc *sc, u_int16_t state)
+{
+	usb_device_request_t req;
+	int32_t error;
+
+	req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
+	req.bRequest = UMCPC_ACTIVATE_MODE;
+	USETW(req.wValue, state);
+	USETW(req.wIndex, sc->sc_ctrl_iface_no);
+	USETW(req.wLength, 0);	
+
+	ufoma_cfg_do_request(sc, &req, NULL);
+	
+	error = msleep(&(sc->sc_currentmode), &Giant, PZERO, "fmaact", (UFOMA_MAX_TIMEOUT*hz));
+	if(error){
+		DPRINTF(sc, 0, "No response\n");
+	}
+	return;
+}
+
+static void
+ufoma_ctrl_read_callback(struct usbd_xfer *xfer)
+{
+	struct ufoma_softc *sc = xfer->priv_sc;
+	usb_device_request_t *req = xfer->buffer;
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_error:
+	DPRINTF(sc, 0, "error = %s\n",
+		usbd_errstr(xfer->error));
+
+	if (xfer->error == USBD_CANCELLED) {
+	    return;
+	} else {
+	    goto tr_setup;
+	}
+
+ tr_transferred:
+	if (xfer->actlen < sizeof(*req)) {
+	    goto tr_setup;
+	}
+
+	xfer->actlen -= sizeof(*req);
+
+	if (xfer->actlen) {
+	    ucom_put_data(&(sc->sc_ucom), req->bData, xfer->actlen);
+	}
+
+ tr_setup:
+	if (sc->sc_num_msg) {
+	    sc->sc_num_msg--;
+
+	    req->bmRequestType = UT_READ_CLASS_INTERFACE;
+	    req->bRequest = UCDC_GET_ENCAPSULATED_RESPONSE;
+	    USETW(req->wIndex, sc->sc_ctrl_iface_no);
+	    USETW(req->wValue, 0);
+	    USETW(req->wLength, UFOMA_CMD_BUF_SIZE);
+
+	    usbd_start_hardware(xfer);
+	}
+	return;
+}
+
+static void
+ufoma_ctrl_write_callback(struct usbd_xfer *xfer)
+{
+	struct ufoma_softc *sc = xfer->priv_sc;
+	usb_device_request_t *req = xfer->buffer;
+	u_int32_t actlen;
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_error:
+	DPRINTF(sc, 0, "error = %s\n",
+		usbd_errstr(xfer->error));
+
+	if (xfer->error == USBD_CANCELLED) {
+	    return;
+	} else {
+	    goto tr_setup;
+	}
+
+ tr_transferred:
+ tr_setup:
+	if (ucom_get_data(&(sc->sc_ucom), req->bData, 1, &actlen)) {
+
+	    req->bmRequestType = UT_WRITE_CLASS_INTERFACE;
+	    req->bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
+	    USETW(req->wIndex, sc->sc_ctrl_iface_no);
+	    USETW(req->wValue, 0);
+	    USETW(req->wLength, 1);
+
+	    xfer->length = (sizeof(*req) + 1);
+
+	    usbd_start_hardware(xfer);
+	}
+	return;
+}
+
+static void
+ufoma_intr_clear_stall_callback(struct usbd_xfer *xfer)
+{
+	struct ufoma_softc *sc = xfer->priv_sc;
+	struct usbd_xfer *xfer_other = sc->sc_ctrl_xfer[0];
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_setup:
+	/* start clear stall */
+	usbd_clear_stall_tr_setup(xfer, xfer_other);
+	return;
+
+ tr_transferred:
+	usbd_clear_stall_tr_transferred(xfer, xfer_other);
+
+	sc->sc_flags &= ~UFOMA_FLAG_INTR_STALL;
+	usbd_transfer_start(xfer_other);
+	return;
+
+ tr_error:
+	/* bomb out */
+	sc->sc_flags &= ~UFOMA_FLAG_INTR_STALL;
+	DPRINTF(sc, 0, "interrupt read pipe stopped\n");
+	return;
+}
+
+static void
+ufoma_intr_callback(struct usbd_xfer *xfer)
+{
+	struct ufoma_softc *sc = xfer->priv_sc;
+	usb_cdc_notification_t *n = xfer->buffer;
+	u_int16_t wLen;
+	u_int16_t temp;
+	u_int8_t mstatus;
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_error:
+	if (xfer->error != USBD_CANCELLED) {
+	    /* start clear stall */
+	    sc->sc_flags |= UFOMA_FLAG_INTR_STALL;
+	    usbd_transfer_start(sc->sc_ctrl_xfer[1]);
+	}
+	return;
+
+ tr_transferred:
+	if (xfer->actlen < 8) {
+	    DPRINTF(sc, 0, "too short message\n");
+	    goto tr_setup;
+	}
+
+	xfer->actlen -= 8;
+
+	wLen = UGETW(n->wLength);
+	xfer->actlen = min(wLen, xfer->actlen);
+
+	if((n->bmRequestType == UT_READ_VENDOR_INTERFACE) &&
+	   (n->bNotification == UMCPC_REQUEST_ACKNOWLEDGE)) {
+	    temp =  UGETW(n->wValue);
+	    sc->sc_currentmode = (temp >> 8);
+	    if(!(temp & 0xff)){
+	        DPRINTF(sc, 0, "Mode change failed!\n");
+	    }
+	    wakeup(&(sc->sc_currentmode));
+	}
+
+	if(n->bmRequestType != UCDC_NOTIFICATION){
+	    goto tr_setup;
+	}
+
+	switch(n->bNotification){
+	case UCDC_N_RESPONSE_AVAILABLE:
+	    if(!(sc->sc_is_pseudo)){
+	        DPRINTF(sc, 0, "Wrong serial state!\n");
+		break;
+	    }
+
+	    if (sc->sc_num_msg != 0xFF) {
+	        sc->sc_num_msg ++;
+	    }
+
+	    usbd_transfer_start(sc->sc_ctrl_xfer[3]);
+	    break;
+
+	case UCDC_N_SERIAL_STATE:
+	    if(sc->sc_is_pseudo){
+	        DPRINTF(sc, 0, "Wrong serial state!\n");
+		break;
+	    }
+
+	    /*
+	     * Set the serial state in ucom driver based on
+	     * the bits from the notify message
+	     */
+	    if (xfer->actlen < 2) {
+	        DPRINTF(sc, 0, "invalid notification "
+			"length, %d bytes!\n", xfer->actlen);
+		break;
+	    }
+
+	    DPRINTF(sc, 0, "notify bytes = 0x%02x, 0x%02x\n",
+		    n->data[0], n->data[1]);
+
+	    /* currently, lsr is always zero. */
+	    sc->sc_lsr = 0;
+	    sc->sc_msr = 0;
+
+	    mstatus = n->data[0];
+
+	    if (mstatus & UCDC_N_SERIAL_RI) {
+	        sc->sc_msr |= SER_RI;
+	    }
+
+	    if (mstatus & UCDC_N_SERIAL_DSR) {
+	        sc->sc_msr |= SER_DSR;
+	    }
+
+	    if (mstatus & UCDC_N_SERIAL_DCD) {
+	        sc->sc_msr |= SER_DCD;
+	    }
+
+	    ucom_status_change(&(sc->sc_ucom));
+	    break;
+
+	default:
+	    break;
+	}
+
+ tr_setup:
+	if (sc->sc_flags & UFOMA_FLAG_INTR_STALL) {
+	    usbd_transfer_start(sc->sc_ctrl_xfer[1]);
+	} else {
+	    usbd_start_hardware(xfer);
+	}
+	return;
+}
+
+static void
+ufoma_bulk_write_callback(struct usbd_xfer *xfer)
+{
+	struct ufoma_softc *sc = xfer->priv_sc;
+	u_int32_t actlen;
+
+	USBD_CHECK_STATUS(xfer);
+
+tr_error:
+	if (xfer->error != USBD_CANCELLED) {
+	    sc->sc_flags |= UFOMA_FLAG_BULK_WRITE_STALL;
+	    usbd_transfer_start(sc->sc_bulk_xfer[2]);
+	}
+	return;
+
+tr_setup:
+tr_transferred:
+	if (sc->sc_flags & UFOMA_FLAG_BULK_WRITE_STALL) {
+	    usbd_transfer_start(sc->sc_bulk_xfer[2]);
+	    return;
+	}
+
+	if (ucom_get_data(&(sc->sc_ucom), xfer->buffer, 
+			  UFOMA_BULK_OBUFSIZE, &actlen)) {
+	    xfer->length = actlen;
+	    usbd_start_hardware(xfer);
+	}
+	return;
+}
+
+static void
+ufoma_bulk_write_clear_stall_callback(struct usbd_xfer *xfer)
+{
+	struct ufoma_softc *sc = xfer->priv_sc;
+	struct usbd_xfer *xfer_other = sc->sc_bulk_xfer[0];
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_setup:
+	/* start clear stall */
+	usbd_clear_stall_tr_setup(xfer, xfer_other);
+	return;
+
+ tr_transferred:
+	usbd_clear_stall_tr_transferred(xfer, xfer_other);
+	sc->sc_flags &= ~UFOMA_FLAG_BULK_WRITE_STALL;
+	usbd_transfer_start(xfer_other);
+	return;
+
+ tr_error:
+	sc->sc_flags &= ~UFOMA_FLAG_BULK_WRITE_STALL;
+	DPRINTF(sc, 0, "clear stall failed, error=%s\n",
+		usbd_errstr(xfer->error));
+	return;
+}
+
+static void
+ufoma_bulk_read_callback(struct usbd_xfer *xfer)
+{
+	struct ufoma_softc *sc = xfer->priv_sc;
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_error:
+	if (xfer->error != USBD_CANCELLED) {
+	    sc->sc_flags |= UFOMA_FLAG_BULK_READ_STALL;
+	    usbd_transfer_start(sc->sc_bulk_xfer[3]);
+	}
+	return;
+
+ tr_transferred:
+	ucom_put_data(&(sc->sc_ucom), xfer->buffer, 
+		      xfer->actlen);
+
+ tr_setup:
+	if (sc->sc_flags & UFOMA_FLAG_BULK_READ_STALL) {
+	    usbd_transfer_start(sc->sc_bulk_xfer[3]);
+	} else {
+	    usbd_start_hardware(xfer);
+	}
+	return;
+}
+
+static void
+ufoma_bulk_read_clear_stall_callback(struct usbd_xfer *xfer)
+{
+	struct ufoma_softc *sc = xfer->priv_sc;
+	struct usbd_xfer *xfer_other = sc->sc_bulk_xfer[1];
+
+	USBD_CHECK_STATUS(xfer);
+
+ tr_setup:
+	/* start clear stall */

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list