From owner-p4-projects@FreeBSD.ORG Fri Sep 1 18:03:28 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id C981216A4E0; Fri, 1 Sep 2006 18:03:28 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 8B90616A4DA for ; Fri, 1 Sep 2006 18:03:28 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 373E043D45 for ; Fri, 1 Sep 2006 18:03:28 +0000 (GMT) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k81I3SZO087143 for ; Fri, 1 Sep 2006 18:03:28 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k81I3RLU087140 for perforce@freebsd.org; Fri, 1 Sep 2006 18:03:27 GMT (envelope-from hselasky@FreeBSD.org) Date: Fri, 1 Sep 2006 18:03:27 GMT Message-Id: <200609011803.k81I3RLU087140@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 105471 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 01 Sep 2006 18:03:29 -0000 http://perforce.freebsd.org/chv.cgi?CH=105471 Change 105471 by hselasky@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 . + * 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@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 +#include +#include +#include +#include +#include +#include +#include + +#define usbd_config_td_cc ufoma_config_copy +#define usbd_config_td_softc ufoma_softc + +#include +#include +#include +#include +#include + +#include + +#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) <<<