2/* $NetBSD: ugensa.c,v 1.9.2.1 2007/03/24 14:55:50 yamt Exp $ */ 3 4/* 5 * Copyright (c) 2004, 2005 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Roland C. Dowdeswell <elric@netbsd.org>. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40/* 41 * NOTE: all function names beginning like "ugensa_cfg_" can only 42 * be called from within the config thread function ! 43 */ 44 45#include <dev/usb2/include/usb2_devid.h> 46#include <dev/usb2/include/usb2_standard.h> 47#include <dev/usb2/include/usb2_mfunc.h> 48#include <dev/usb2/include/usb2_error.h> 49#include <dev/usb2/include/usb2_cdc.h> 50#include <dev/usb2/include/usb2_defs.h> 51 52#define USB_DEBUG_VAR usb2_debug 53 54#include <dev/usb2/core/usb2_core.h> 55#include <dev/usb2/core/usb2_debug.h> 56#include <dev/usb2/core/usb2_process.h>
| 2/* $NetBSD: ugensa.c,v 1.9.2.1 2007/03/24 14:55:50 yamt Exp $ */ 3 4/* 5 * Copyright (c) 2004, 2005 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Roland C. Dowdeswell <elric@netbsd.org>. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40/* 41 * NOTE: all function names beginning like "ugensa_cfg_" can only 42 * be called from within the config thread function ! 43 */ 44 45#include <dev/usb2/include/usb2_devid.h> 46#include <dev/usb2/include/usb2_standard.h> 47#include <dev/usb2/include/usb2_mfunc.h> 48#include <dev/usb2/include/usb2_error.h> 49#include <dev/usb2/include/usb2_cdc.h> 50#include <dev/usb2/include/usb2_defs.h> 51 52#define USB_DEBUG_VAR usb2_debug 53 54#include <dev/usb2/core/usb2_core.h> 55#include <dev/usb2/core/usb2_debug.h> 56#include <dev/usb2/core/usb2_process.h>
|
58#include <dev/usb2/core/usb2_request.h> 59#include <dev/usb2/core/usb2_lookup.h> 60#include <dev/usb2/core/usb2_util.h> 61#include <dev/usb2/core/usb2_device.h> 62 63#include <dev/usb2/serial/usb2_serial.h> 64 65#define UGENSA_BUF_SIZE 2048 /* bytes */ 66#define UGENSA_N_TRANSFER 4 /* units */ 67#define UGENSA_CONFIG_INDEX 0 68#define UGENSA_IFACE_INDEX 0 69#define UGENSA_IFACE_MAX 8 /* exclusivly */ 70 71struct ugensa_sub_softc { 72 struct usb2_com_softc *sc_usb2_com_ptr; 73 struct usb2_xfer *sc_xfer[UGENSA_N_TRANSFER]; 74 75 uint8_t sc_flags; 76#define UGENSA_FLAG_BULK_READ_STALL 0x01 77#define UGENSA_FLAG_BULK_WRITE_STALL 0x02 78}; 79 80struct ugensa_softc { 81 struct usb2_com_super_softc sc_super_ucom; 82 struct usb2_com_softc sc_ucom[UGENSA_IFACE_MAX]; 83 struct ugensa_sub_softc sc_sub[UGENSA_IFACE_MAX]; 84 85 struct mtx sc_mtx; 86 uint8_t sc_niface; 87}; 88 89/* prototypes */ 90 91static device_probe_t ugensa_probe; 92static device_attach_t ugensa_attach; 93static device_detach_t ugensa_detach; 94 95static usb2_callback_t ugensa_bulk_write_callback; 96static usb2_callback_t ugensa_bulk_write_clear_stall_callback; 97static usb2_callback_t ugensa_bulk_read_callback; 98static usb2_callback_t ugensa_bulk_read_clear_stall_callback; 99 100static void ugensa_start_read(struct usb2_com_softc *); 101static void ugensa_stop_read(struct usb2_com_softc *); 102static void ugensa_start_write(struct usb2_com_softc *); 103static void ugensa_stop_write(struct usb2_com_softc *); 104 105static const struct usb2_config 106 ugensa_xfer_config[UGENSA_N_TRANSFER] = { 107 108 [0] = { 109 .type = UE_BULK, 110 .endpoint = UE_ADDR_ANY, 111 .direction = UE_DIR_OUT, 112 .mh.bufsize = UGENSA_BUF_SIZE, 113 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 114 .mh.callback = &ugensa_bulk_write_callback, 115 }, 116 117 [1] = { 118 .type = UE_BULK, 119 .endpoint = UE_ADDR_ANY, 120 .direction = UE_DIR_IN, 121 .mh.bufsize = UGENSA_BUF_SIZE, 122 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 123 .mh.callback = &ugensa_bulk_read_callback, 124 }, 125 126 [2] = { 127 .type = UE_CONTROL, 128 .endpoint = 0x00, /* Control pipe */ 129 .direction = UE_DIR_ANY, 130 .mh.bufsize = sizeof(struct usb2_device_request), 131 .mh.flags = {}, 132 .mh.callback = &ugensa_bulk_write_clear_stall_callback, 133 .mh.timeout = 1000, /* 1 second */ 134 .mh.interval = 50, /* 50ms */ 135 }, 136 137 [3] = { 138 .type = UE_CONTROL, 139 .endpoint = 0x00, /* Control pipe */ 140 .direction = UE_DIR_ANY, 141 .mh.bufsize = sizeof(struct usb2_device_request), 142 .mh.flags = {}, 143 .mh.callback = &ugensa_bulk_read_clear_stall_callback, 144 .mh.timeout = 1000, /* 1 second */ 145 .mh.interval = 50, /* 50ms */ 146 }, 147}; 148 149static const struct usb2_com_callback ugensa_callback = { 150 .usb2_com_start_read = &ugensa_start_read, 151 .usb2_com_stop_read = &ugensa_stop_read, 152 .usb2_com_start_write = &ugensa_start_write, 153 .usb2_com_stop_write = &ugensa_stop_write, 154}; 155 156static device_method_t ugensa_methods[] = { 157 /* Device methods */ 158 DEVMETHOD(device_probe, ugensa_probe), 159 DEVMETHOD(device_attach, ugensa_attach), 160 DEVMETHOD(device_detach, ugensa_detach), 161 {0, 0} 162}; 163 164static devclass_t ugensa_devclass; 165 166static driver_t ugensa_driver = { 167 .name = "ugensa", 168 .methods = ugensa_methods, 169 .size = sizeof(struct ugensa_softc), 170}; 171 172DRIVER_MODULE(ugensa, ushub, ugensa_driver, ugensa_devclass, NULL, 0); 173MODULE_DEPEND(ugensa, usb2_serial, 1, 1, 1); 174MODULE_DEPEND(ugensa, usb2_core, 1, 1, 1); 175 176static const struct usb2_device_id ugensa_devs[] = { 177 {USB_VPI(USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220, 0)}, 178 {USB_VPI(USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CDMA_MODEM1, 0)}, 179 {USB_VPI(USB_VENDOR_KYOCERA2, USB_PRODUCT_KYOCERA2_CDMA_MSM_K, 0)}, 180 {USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_49GPLUS, 0)}, 181/* {USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E270, 0)}, */ 182 {USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE, 0)}, 183 {USB_VPI(USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620, 0)}, 184 {USB_VPI(USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_FLEXPACKGPS, 0)}, 185}; 186 187static int 188ugensa_probe(device_t dev) 189{ 190 struct usb2_attach_arg *uaa = device_get_ivars(dev); 191 192 if (uaa->usb2_mode != USB_MODE_HOST) { 193 return (ENXIO); 194 } 195 if (uaa->info.bConfigIndex != UGENSA_CONFIG_INDEX) { 196 return (ENXIO); 197 } 198 if (uaa->info.bIfaceIndex != 0) { 199 return (ENXIO); 200 } 201 return (usb2_lookup_id_by_uaa(ugensa_devs, sizeof(ugensa_devs), uaa)); 202} 203 204static int 205ugensa_attach(device_t dev) 206{ 207 struct usb2_attach_arg *uaa = device_get_ivars(dev); 208 struct ugensa_softc *sc = device_get_softc(dev); 209 struct ugensa_sub_softc *ssc; 210 struct usb2_interface *iface; 211 int32_t error; 212 uint8_t iface_index; 213 int x, cnt; 214 215 if (sc == NULL) 216 return (ENOMEM); 217 218 device_set_usb2_desc(dev); 219 mtx_init(&sc->sc_mtx, "ugensa", NULL, MTX_DEF); 220 221 /* Figure out how many interfaces this device has got */ 222 for (cnt = 0; cnt < UGENSA_IFACE_MAX; cnt++) { 223 if ((usb2_get_pipe(uaa->device, cnt, ugensa_xfer_config + 0) == NULL) || 224 (usb2_get_pipe(uaa->device, cnt, ugensa_xfer_config + 1) == NULL)) { 225 /* we have reached the end */ 226 break; 227 } 228 } 229 230 if (cnt == 0) { 231 device_printf(dev, "No interfaces!\n"); 232 goto detach; 233 } 234 for (x = 0; x < cnt; x++) { 235 iface = usb2_get_iface(uaa->device, x); 236 if (iface->idesc->bInterfaceClass != UICLASS_VENDOR) 237 /* Not a serial port, most likely a SD reader */ 238 continue; 239 240 ssc = sc->sc_sub + sc->sc_niface; 241 ssc->sc_usb2_com_ptr = sc->sc_ucom + sc->sc_niface; 242 243 iface_index = (UGENSA_IFACE_INDEX + x); 244 error = usb2_transfer_setup(uaa->device, 245 &iface_index, ssc->sc_xfer, ugensa_xfer_config, 246 UGENSA_N_TRANSFER, ssc, &sc->sc_mtx); 247 248 if (error) { 249 device_printf(dev, "allocating USB " 250 "transfers failed!\n"); 251 goto detach; 252 } 253 /* clear stall at first run */ 254 ssc->sc_flags |= (UGENSA_FLAG_BULK_WRITE_STALL | 255 UGENSA_FLAG_BULK_READ_STALL); 256 257 /* initialize port number */ 258 ssc->sc_usb2_com_ptr->sc_portno = sc->sc_niface; 259 sc->sc_niface++; 260 if (x != uaa->info.bIfaceIndex) 261 usb2_set_parent_iface(uaa->device, x, 262 uaa->info.bIfaceIndex); 263 } 264 device_printf(dev, "Found %d interfaces.\n", sc->sc_niface); 265 266 error = usb2_com_attach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_niface, sc, 267 &ugensa_callback, &sc->sc_mtx); 268 if (error) { 269 DPRINTF("attach failed\n"); 270 goto detach; 271 } 272 return (0); /* success */ 273 274detach: 275 ugensa_detach(dev); 276 return (ENXIO); /* failure */ 277} 278 279static int 280ugensa_detach(device_t dev) 281{ 282 struct ugensa_softc *sc = device_get_softc(dev); 283 uint8_t x; 284 285 usb2_com_detach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_niface); 286 287 for (x = 0; x < sc->sc_niface; x++) { 288 usb2_transfer_unsetup(sc->sc_sub[x].sc_xfer, UGENSA_N_TRANSFER); 289 } 290 mtx_destroy(&sc->sc_mtx); 291 292 return (0); 293} 294 295static void 296ugensa_bulk_write_callback(struct usb2_xfer *xfer) 297{ 298 struct ugensa_sub_softc *ssc = xfer->priv_sc; 299 uint32_t actlen; 300 301 switch (USB_GET_STATE(xfer)) { 302 case USB_ST_SETUP: 303 case USB_ST_TRANSFERRED: 304 if (ssc->sc_flags & UGENSA_FLAG_BULK_WRITE_STALL) { 305 usb2_transfer_start(ssc->sc_xfer[2]); 306 return; 307 } 308 if (usb2_com_get_data(ssc->sc_usb2_com_ptr, xfer->frbuffers, 0, 309 UGENSA_BUF_SIZE, &actlen)) { 310 xfer->frlengths[0] = actlen; 311 usb2_start_hardware(xfer); 312 } 313 return; 314 315 default: /* Error */ 316 if (xfer->error != USB_ERR_CANCELLED) { 317 ssc->sc_flags |= UGENSA_FLAG_BULK_WRITE_STALL; 318 usb2_transfer_start(ssc->sc_xfer[2]); 319 } 320 return; 321 322 } 323} 324 325static void 326ugensa_bulk_write_clear_stall_callback(struct usb2_xfer *xfer) 327{ 328 struct ugensa_sub_softc *ssc = xfer->priv_sc; 329 struct usb2_xfer *xfer_other = ssc->sc_xfer[0]; 330 331 if (usb2_clear_stall_callback(xfer, xfer_other)) { 332 DPRINTF("stall cleared\n"); 333 ssc->sc_flags &= ~UGENSA_FLAG_BULK_WRITE_STALL; 334 usb2_transfer_start(xfer_other); 335 } 336} 337 338static void 339ugensa_bulk_read_callback(struct usb2_xfer *xfer) 340{ 341 struct ugensa_sub_softc *ssc = xfer->priv_sc; 342 343 switch (USB_GET_STATE(xfer)) { 344 case USB_ST_TRANSFERRED: 345 usb2_com_put_data(ssc->sc_usb2_com_ptr, xfer->frbuffers, 0, 346 xfer->actlen); 347 348 case USB_ST_SETUP: 349 if (ssc->sc_flags & UGENSA_FLAG_BULK_READ_STALL) { 350 usb2_transfer_start(ssc->sc_xfer[3]); 351 } else { 352 xfer->frlengths[0] = xfer->max_data_length; 353 usb2_start_hardware(xfer); 354 } 355 return; 356 357 default: /* Error */ 358 if (xfer->error != USB_ERR_CANCELLED) { 359 ssc->sc_flags |= UGENSA_FLAG_BULK_READ_STALL; 360 usb2_transfer_start(ssc->sc_xfer[3]); 361 } 362 return; 363 364 } 365} 366 367static void 368ugensa_bulk_read_clear_stall_callback(struct usb2_xfer *xfer) 369{ 370 struct ugensa_sub_softc *ssc = xfer->priv_sc; 371 struct usb2_xfer *xfer_other = ssc->sc_xfer[1]; 372 373 if (usb2_clear_stall_callback(xfer, xfer_other)) { 374 DPRINTF("stall cleared\n"); 375 ssc->sc_flags &= ~UGENSA_FLAG_BULK_READ_STALL; 376 usb2_transfer_start(xfer_other); 377 } 378} 379 380static void 381ugensa_start_read(struct usb2_com_softc *ucom) 382{ 383 struct ugensa_softc *sc = ucom->sc_parent; 384 struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno; 385 386 usb2_transfer_start(ssc->sc_xfer[1]); 387} 388 389static void 390ugensa_stop_read(struct usb2_com_softc *ucom) 391{ 392 struct ugensa_softc *sc = ucom->sc_parent; 393 struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno; 394 395 usb2_transfer_stop(ssc->sc_xfer[3]); 396 usb2_transfer_stop(ssc->sc_xfer[1]); 397} 398 399static void 400ugensa_start_write(struct usb2_com_softc *ucom) 401{ 402 struct ugensa_softc *sc = ucom->sc_parent; 403 struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno; 404 405 usb2_transfer_start(ssc->sc_xfer[0]); 406} 407 408static void 409ugensa_stop_write(struct usb2_com_softc *ucom) 410{ 411 struct ugensa_softc *sc = ucom->sc_parent; 412 struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno; 413 414 usb2_transfer_stop(ssc->sc_xfer[2]); 415 usb2_transfer_stop(ssc->sc_xfer[0]); 416}
| 57#include <dev/usb2/core/usb2_request.h> 58#include <dev/usb2/core/usb2_lookup.h> 59#include <dev/usb2/core/usb2_util.h> 60#include <dev/usb2/core/usb2_device.h> 61 62#include <dev/usb2/serial/usb2_serial.h> 63 64#define UGENSA_BUF_SIZE 2048 /* bytes */ 65#define UGENSA_N_TRANSFER 4 /* units */ 66#define UGENSA_CONFIG_INDEX 0 67#define UGENSA_IFACE_INDEX 0 68#define UGENSA_IFACE_MAX 8 /* exclusivly */ 69 70struct ugensa_sub_softc { 71 struct usb2_com_softc *sc_usb2_com_ptr; 72 struct usb2_xfer *sc_xfer[UGENSA_N_TRANSFER]; 73 74 uint8_t sc_flags; 75#define UGENSA_FLAG_BULK_READ_STALL 0x01 76#define UGENSA_FLAG_BULK_WRITE_STALL 0x02 77}; 78 79struct ugensa_softc { 80 struct usb2_com_super_softc sc_super_ucom; 81 struct usb2_com_softc sc_ucom[UGENSA_IFACE_MAX]; 82 struct ugensa_sub_softc sc_sub[UGENSA_IFACE_MAX]; 83 84 struct mtx sc_mtx; 85 uint8_t sc_niface; 86}; 87 88/* prototypes */ 89 90static device_probe_t ugensa_probe; 91static device_attach_t ugensa_attach; 92static device_detach_t ugensa_detach; 93 94static usb2_callback_t ugensa_bulk_write_callback; 95static usb2_callback_t ugensa_bulk_write_clear_stall_callback; 96static usb2_callback_t ugensa_bulk_read_callback; 97static usb2_callback_t ugensa_bulk_read_clear_stall_callback; 98 99static void ugensa_start_read(struct usb2_com_softc *); 100static void ugensa_stop_read(struct usb2_com_softc *); 101static void ugensa_start_write(struct usb2_com_softc *); 102static void ugensa_stop_write(struct usb2_com_softc *); 103 104static const struct usb2_config 105 ugensa_xfer_config[UGENSA_N_TRANSFER] = { 106 107 [0] = { 108 .type = UE_BULK, 109 .endpoint = UE_ADDR_ANY, 110 .direction = UE_DIR_OUT, 111 .mh.bufsize = UGENSA_BUF_SIZE, 112 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 113 .mh.callback = &ugensa_bulk_write_callback, 114 }, 115 116 [1] = { 117 .type = UE_BULK, 118 .endpoint = UE_ADDR_ANY, 119 .direction = UE_DIR_IN, 120 .mh.bufsize = UGENSA_BUF_SIZE, 121 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 122 .mh.callback = &ugensa_bulk_read_callback, 123 }, 124 125 [2] = { 126 .type = UE_CONTROL, 127 .endpoint = 0x00, /* Control pipe */ 128 .direction = UE_DIR_ANY, 129 .mh.bufsize = sizeof(struct usb2_device_request), 130 .mh.flags = {}, 131 .mh.callback = &ugensa_bulk_write_clear_stall_callback, 132 .mh.timeout = 1000, /* 1 second */ 133 .mh.interval = 50, /* 50ms */ 134 }, 135 136 [3] = { 137 .type = UE_CONTROL, 138 .endpoint = 0x00, /* Control pipe */ 139 .direction = UE_DIR_ANY, 140 .mh.bufsize = sizeof(struct usb2_device_request), 141 .mh.flags = {}, 142 .mh.callback = &ugensa_bulk_read_clear_stall_callback, 143 .mh.timeout = 1000, /* 1 second */ 144 .mh.interval = 50, /* 50ms */ 145 }, 146}; 147 148static const struct usb2_com_callback ugensa_callback = { 149 .usb2_com_start_read = &ugensa_start_read, 150 .usb2_com_stop_read = &ugensa_stop_read, 151 .usb2_com_start_write = &ugensa_start_write, 152 .usb2_com_stop_write = &ugensa_stop_write, 153}; 154 155static device_method_t ugensa_methods[] = { 156 /* Device methods */ 157 DEVMETHOD(device_probe, ugensa_probe), 158 DEVMETHOD(device_attach, ugensa_attach), 159 DEVMETHOD(device_detach, ugensa_detach), 160 {0, 0} 161}; 162 163static devclass_t ugensa_devclass; 164 165static driver_t ugensa_driver = { 166 .name = "ugensa", 167 .methods = ugensa_methods, 168 .size = sizeof(struct ugensa_softc), 169}; 170 171DRIVER_MODULE(ugensa, ushub, ugensa_driver, ugensa_devclass, NULL, 0); 172MODULE_DEPEND(ugensa, usb2_serial, 1, 1, 1); 173MODULE_DEPEND(ugensa, usb2_core, 1, 1, 1); 174 175static const struct usb2_device_id ugensa_devs[] = { 176 {USB_VPI(USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220, 0)}, 177 {USB_VPI(USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CDMA_MODEM1, 0)}, 178 {USB_VPI(USB_VENDOR_KYOCERA2, USB_PRODUCT_KYOCERA2_CDMA_MSM_K, 0)}, 179 {USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_49GPLUS, 0)}, 180/* {USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E270, 0)}, */ 181 {USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE, 0)}, 182 {USB_VPI(USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620, 0)}, 183 {USB_VPI(USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_FLEXPACKGPS, 0)}, 184}; 185 186static int 187ugensa_probe(device_t dev) 188{ 189 struct usb2_attach_arg *uaa = device_get_ivars(dev); 190 191 if (uaa->usb2_mode != USB_MODE_HOST) { 192 return (ENXIO); 193 } 194 if (uaa->info.bConfigIndex != UGENSA_CONFIG_INDEX) { 195 return (ENXIO); 196 } 197 if (uaa->info.bIfaceIndex != 0) { 198 return (ENXIO); 199 } 200 return (usb2_lookup_id_by_uaa(ugensa_devs, sizeof(ugensa_devs), uaa)); 201} 202 203static int 204ugensa_attach(device_t dev) 205{ 206 struct usb2_attach_arg *uaa = device_get_ivars(dev); 207 struct ugensa_softc *sc = device_get_softc(dev); 208 struct ugensa_sub_softc *ssc; 209 struct usb2_interface *iface; 210 int32_t error; 211 uint8_t iface_index; 212 int x, cnt; 213 214 if (sc == NULL) 215 return (ENOMEM); 216 217 device_set_usb2_desc(dev); 218 mtx_init(&sc->sc_mtx, "ugensa", NULL, MTX_DEF); 219 220 /* Figure out how many interfaces this device has got */ 221 for (cnt = 0; cnt < UGENSA_IFACE_MAX; cnt++) { 222 if ((usb2_get_pipe(uaa->device, cnt, ugensa_xfer_config + 0) == NULL) || 223 (usb2_get_pipe(uaa->device, cnt, ugensa_xfer_config + 1) == NULL)) { 224 /* we have reached the end */ 225 break; 226 } 227 } 228 229 if (cnt == 0) { 230 device_printf(dev, "No interfaces!\n"); 231 goto detach; 232 } 233 for (x = 0; x < cnt; x++) { 234 iface = usb2_get_iface(uaa->device, x); 235 if (iface->idesc->bInterfaceClass != UICLASS_VENDOR) 236 /* Not a serial port, most likely a SD reader */ 237 continue; 238 239 ssc = sc->sc_sub + sc->sc_niface; 240 ssc->sc_usb2_com_ptr = sc->sc_ucom + sc->sc_niface; 241 242 iface_index = (UGENSA_IFACE_INDEX + x); 243 error = usb2_transfer_setup(uaa->device, 244 &iface_index, ssc->sc_xfer, ugensa_xfer_config, 245 UGENSA_N_TRANSFER, ssc, &sc->sc_mtx); 246 247 if (error) { 248 device_printf(dev, "allocating USB " 249 "transfers failed!\n"); 250 goto detach; 251 } 252 /* clear stall at first run */ 253 ssc->sc_flags |= (UGENSA_FLAG_BULK_WRITE_STALL | 254 UGENSA_FLAG_BULK_READ_STALL); 255 256 /* initialize port number */ 257 ssc->sc_usb2_com_ptr->sc_portno = sc->sc_niface; 258 sc->sc_niface++; 259 if (x != uaa->info.bIfaceIndex) 260 usb2_set_parent_iface(uaa->device, x, 261 uaa->info.bIfaceIndex); 262 } 263 device_printf(dev, "Found %d interfaces.\n", sc->sc_niface); 264 265 error = usb2_com_attach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_niface, sc, 266 &ugensa_callback, &sc->sc_mtx); 267 if (error) { 268 DPRINTF("attach failed\n"); 269 goto detach; 270 } 271 return (0); /* success */ 272 273detach: 274 ugensa_detach(dev); 275 return (ENXIO); /* failure */ 276} 277 278static int 279ugensa_detach(device_t dev) 280{ 281 struct ugensa_softc *sc = device_get_softc(dev); 282 uint8_t x; 283 284 usb2_com_detach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_niface); 285 286 for (x = 0; x < sc->sc_niface; x++) { 287 usb2_transfer_unsetup(sc->sc_sub[x].sc_xfer, UGENSA_N_TRANSFER); 288 } 289 mtx_destroy(&sc->sc_mtx); 290 291 return (0); 292} 293 294static void 295ugensa_bulk_write_callback(struct usb2_xfer *xfer) 296{ 297 struct ugensa_sub_softc *ssc = xfer->priv_sc; 298 uint32_t actlen; 299 300 switch (USB_GET_STATE(xfer)) { 301 case USB_ST_SETUP: 302 case USB_ST_TRANSFERRED: 303 if (ssc->sc_flags & UGENSA_FLAG_BULK_WRITE_STALL) { 304 usb2_transfer_start(ssc->sc_xfer[2]); 305 return; 306 } 307 if (usb2_com_get_data(ssc->sc_usb2_com_ptr, xfer->frbuffers, 0, 308 UGENSA_BUF_SIZE, &actlen)) { 309 xfer->frlengths[0] = actlen; 310 usb2_start_hardware(xfer); 311 } 312 return; 313 314 default: /* Error */ 315 if (xfer->error != USB_ERR_CANCELLED) { 316 ssc->sc_flags |= UGENSA_FLAG_BULK_WRITE_STALL; 317 usb2_transfer_start(ssc->sc_xfer[2]); 318 } 319 return; 320 321 } 322} 323 324static void 325ugensa_bulk_write_clear_stall_callback(struct usb2_xfer *xfer) 326{ 327 struct ugensa_sub_softc *ssc = xfer->priv_sc; 328 struct usb2_xfer *xfer_other = ssc->sc_xfer[0]; 329 330 if (usb2_clear_stall_callback(xfer, xfer_other)) { 331 DPRINTF("stall cleared\n"); 332 ssc->sc_flags &= ~UGENSA_FLAG_BULK_WRITE_STALL; 333 usb2_transfer_start(xfer_other); 334 } 335} 336 337static void 338ugensa_bulk_read_callback(struct usb2_xfer *xfer) 339{ 340 struct ugensa_sub_softc *ssc = xfer->priv_sc; 341 342 switch (USB_GET_STATE(xfer)) { 343 case USB_ST_TRANSFERRED: 344 usb2_com_put_data(ssc->sc_usb2_com_ptr, xfer->frbuffers, 0, 345 xfer->actlen); 346 347 case USB_ST_SETUP: 348 if (ssc->sc_flags & UGENSA_FLAG_BULK_READ_STALL) { 349 usb2_transfer_start(ssc->sc_xfer[3]); 350 } else { 351 xfer->frlengths[0] = xfer->max_data_length; 352 usb2_start_hardware(xfer); 353 } 354 return; 355 356 default: /* Error */ 357 if (xfer->error != USB_ERR_CANCELLED) { 358 ssc->sc_flags |= UGENSA_FLAG_BULK_READ_STALL; 359 usb2_transfer_start(ssc->sc_xfer[3]); 360 } 361 return; 362 363 } 364} 365 366static void 367ugensa_bulk_read_clear_stall_callback(struct usb2_xfer *xfer) 368{ 369 struct ugensa_sub_softc *ssc = xfer->priv_sc; 370 struct usb2_xfer *xfer_other = ssc->sc_xfer[1]; 371 372 if (usb2_clear_stall_callback(xfer, xfer_other)) { 373 DPRINTF("stall cleared\n"); 374 ssc->sc_flags &= ~UGENSA_FLAG_BULK_READ_STALL; 375 usb2_transfer_start(xfer_other); 376 } 377} 378 379static void 380ugensa_start_read(struct usb2_com_softc *ucom) 381{ 382 struct ugensa_softc *sc = ucom->sc_parent; 383 struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno; 384 385 usb2_transfer_start(ssc->sc_xfer[1]); 386} 387 388static void 389ugensa_stop_read(struct usb2_com_softc *ucom) 390{ 391 struct ugensa_softc *sc = ucom->sc_parent; 392 struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno; 393 394 usb2_transfer_stop(ssc->sc_xfer[3]); 395 usb2_transfer_stop(ssc->sc_xfer[1]); 396} 397 398static void 399ugensa_start_write(struct usb2_com_softc *ucom) 400{ 401 struct ugensa_softc *sc = ucom->sc_parent; 402 struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno; 403 404 usb2_transfer_start(ssc->sc_xfer[0]); 405} 406 407static void 408ugensa_stop_write(struct usb2_com_softc *ucom) 409{ 410 struct ugensa_softc *sc = ucom->sc_parent; 411 struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno; 412 413 usb2_transfer_stop(ssc->sc_xfer[2]); 414 usb2_transfer_stop(ssc->sc_xfer[0]); 415}
|