1 /* $NetBSD: uhmodem.c,v 1.6 2008/04/28 20:23:59 martin Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Yojiro UO <yuo@nui.org>. 5 * All rights reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 16 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 /*- 20 * Copyright (c) 2002, Alexander Kabaev <kan.FreeBSD.org>. 21 * All rights reserved. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 */ 44 /* 45 * Copyright (c) 2001 The NetBSD Foundation, Inc. 46 * All rights reserved. 47 * 48 * This code is derived from software contributed to The NetBSD Foundation 49 * by Ichiro FUKUHARA (ichiro@ichiro.org). 50 * 51 * Redistribution and use in source and binary forms, with or without 52 * modification, are permitted provided that the following conditions 53 * are met: 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 61 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 62 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 63 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 64 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 65 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 66 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 67 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 68 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 69 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 70 * POSSIBILITY OF SUCH DAMAGE. 71 */ 72 73 #include <sys/cdefs.h> 74 __KERNEL_RCSID(0, "$NetBSD: uhmodem.c,v 1.6 2008/04/28 20:23:59 martin Exp $"); 75 76 #include <sys/param.h> 77 #include <sys/systm.h> 78 #include <sys/kernel.h> 79 #include <sys/malloc.h> 80 #include <sys/ioccom.h> 81 #include <sys/fcntl.h> 82 #include <sys/conf.h> 83 #include <sys/tty.h> 84 #include <sys/file.h> 85 #include <sys/select.h> 86 #include <sys/proc.h> 87 #include <sys/device.h> 88 #include <sys/poll.h> 89 #include <sys/sysctl.h> 90 #include <sys/bus.h> 91 92 #include <dev/usb/usb.h> 93 #include <dev/usb/usbdi.h> 94 #include <dev/usb/usbdi_util.h> 95 #include <dev/usb/usbdivar.h> 96 97 #include <dev/usb/usbcdc.h> 98 #include <dev/usb/usbdevs.h> 99 #include <dev/usb/usb_quirks.h> 100 #include <dev/usb/ucomvar.h> 101 #include <dev/usb/ubsavar.h> 102 103 /* vendor specific bRequest */ 104 #define UHMODEM_REGWRITE 0x20 105 #define UHMODEM_REGREAD 0x21 106 #define UHMODEM_SETUP 0x22 107 108 #define UHMODEMIBUFSIZE 4096 109 #define UHMODEMOBUFSIZE 4096 110 111 #ifdef UHMODEM_DEBUG 112 Static int uhmodemdebug = 0; 113 #define DPRINTFN(n, x) do { \ 114 if (uhmodemdebug > (n)) \ 115 logprintf x; \ 116 } while (0) 117 #else 118 #define DPRINTFN(n, x) 119 #endif 120 #define DPRINTF(x) DPRINTFN(0, x) 121 122 Static int uhmodem_open(void *, int); 123 Static usbd_status e220_modechange_request(usbd_device_handle); 124 Static usbd_status uhmodem_endpointhalt(struct ubsa_softc *, int); 125 Static usbd_status uhmodem_regwrite(usbd_device_handle, uint8_t *, size_t); 126 Static usbd_status uhmodem_regread(usbd_device_handle, uint8_t *, size_t); 127 Static usbd_status a2502_init(usbd_device_handle); 128 #if 0 129 Static usbd_status uhmodem_regsetup(usbd_device_handle, uint16_t); 130 Static usbd_status e220_init(usbd_device_handle); 131 #endif 132 133 struct uhmodem_softc { 134 struct ubsa_softc sc_ubsa; 135 }; 136 137 struct ucom_methods uhmodem_methods = { 138 ubsa_get_status, 139 ubsa_set, 140 ubsa_param, 141 NULL, 142 uhmodem_open, 143 ubsa_close, 144 NULL, 145 NULL 146 }; 147 148 struct uhmodem_type { 149 struct usb_devno uhmodem_dev; 150 u_int16_t uhmodem_coms; /* number of serial interfaces on the device */ 151 u_int16_t uhmodem_flags; 152 #define E220 0x0001 153 #define A2502 0x0002 154 #define E620 0x0004 /* XXX */ 155 /* Whether or not it is a device different from E220 is not clear. */ 156 }; 157 158 Static const struct uhmodem_type uhmodem_devs[] = { 159 /* HUAWEI E220 / Emobile D0[12]HW */ 160 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 }, 2, E220}, 161 /* ANYDATA / NTT DoCoMo A2502 */ 162 {{ USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_A2502 }, 3, A2502}, 163 /* HUAWEI E620 */ 164 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE }, 3, E620}, 165 }; 166 #define uhmodem_lookup(v, p) ((const struct uhmodem_type *)usb_lookup(uhmodem_devs, v, p)) 167 168 int uhmodem_match(device_t, struct cfdata *, void *); 169 void uhmodem_attach(device_t, device_t, void *); 170 void uhmodem_childdet(device_t, device_t); 171 int uhmodem_detach(device_t, int); 172 int uhmodem_activate(device_t, enum devact); 173 extern struct cfdriver uhmodem_cd; 174 CFATTACH_DECL2(uhmodem, sizeof(struct uhmodem_softc), uhmodem_match, 175 uhmodem_attach, uhmodem_detach, uhmodem_activate, NULL, uhmodem_childdet); 176 177 USB_MATCH(uhmodem) 178 { 179 USB_IFMATCH_START(uhmodem, uaa); 180 181 if (uhmodem_lookup(uaa->vendor, uaa->product) != NULL) 182 /* XXX interface# 0,1 provide modem function, but this driver 183 handles all modem in single device. */ 184 if (uaa->ifaceno == 0) 185 return (UMATCH_VENDOR_PRODUCT); 186 return (UMATCH_NONE); 187 } 188 189 USB_ATTACH(uhmodem) 190 { 191 USB_IFATTACH_START(uhmodem, sc, uaa); 192 usbd_device_handle dev = uaa->device; 193 usb_config_descriptor_t *cdesc; 194 usb_interface_descriptor_t *id; 195 usb_endpoint_descriptor_t *ed; 196 char *devinfop; 197 const char *devname = USBDEVNAME(sc->sc_ubsa.sc_dev); 198 usbd_status err; 199 struct ucom_attach_args uca; 200 int i; 201 int j; 202 char comname[16]; 203 204 devinfop = usbd_devinfo_alloc(dev, 0); 205 USB_ATTACH_SETUP; 206 printf("%s: %s\n", devname, devinfop); 207 usbd_devinfo_free(devinfop); 208 209 sc->sc_ubsa.sc_udev = dev; 210 sc->sc_ubsa.sc_config_index = UBSA_DEFAULT_CONFIG_INDEX; 211 sc->sc_ubsa.sc_numif = 1; /* defaut device has one interface */ 212 213 /* Hauwei E220 need special request to change its mode to modem */ 214 if ((uaa->ifaceno == 0) && (uaa->class != 255)) { 215 err = e220_modechange_request(dev); 216 if (err) { 217 printf("%s: failed to change mode: %s\n", 218 devname, usbd_errstr(err)); 219 sc->sc_ubsa.sc_dying = 1; 220 goto error; 221 } 222 printf("%s: mass storage only mode, reattach to enable modem\n", 223 devname); 224 sc->sc_ubsa.sc_dying = 1; 225 goto error; 226 } 227 228 /* 229 * initialize rts, dtr variables to something 230 * different from boolean 0, 1 231 */ 232 sc->sc_ubsa.sc_dtr = -1; 233 sc->sc_ubsa.sc_rts = -1; 234 235 sc->sc_ubsa.sc_quadumts = 1; 236 sc->sc_ubsa.sc_config_index = 0; 237 sc->sc_ubsa.sc_numif = uhmodem_lookup(uaa->vendor, uaa->product)->uhmodem_coms; 238 sc->sc_ubsa.sc_devflags = uhmodem_lookup(uaa->vendor, uaa->product)->uhmodem_flags; 239 240 DPRINTF(("uhmodem attach: sc = %p\n", sc)); 241 242 /* Move the device into the configured state. */ 243 err = usbd_set_config_index(dev, sc->sc_ubsa.sc_config_index, 1); 244 if (err) { 245 printf("%s: failed to set configuration: %s\n", 246 devname, usbd_errstr(err)); 247 sc->sc_ubsa.sc_dying = 1; 248 goto error; 249 } 250 251 /* get the config descriptor */ 252 cdesc = usbd_get_config_descriptor(sc->sc_ubsa.sc_udev); 253 if (cdesc == NULL) { 254 printf("%s: failed to get configuration descriptor\n", 255 devname); 256 sc->sc_ubsa.sc_dying = 1; 257 goto error; 258 } 259 260 sc->sc_ubsa.sc_intr_number = -1; 261 sc->sc_ubsa.sc_intr_pipe = NULL; 262 263 /* get the interfaces */ 264 for (i = 0; i < sc->sc_ubsa.sc_numif; i++) { 265 err = usbd_device2interface_handle(dev, UBSA_IFACE_INDEX_OFFSET+i, 266 &sc->sc_ubsa.sc_iface[i]); 267 if (err) { 268 if (i == 0){ 269 /* can not get main interface */ 270 sc->sc_ubsa.sc_dying = 1; 271 goto error; 272 } else 273 break; 274 } 275 276 /* Find the endpoints */ 277 id = usbd_get_interface_descriptor(sc->sc_ubsa.sc_iface[i]); 278 sc->sc_ubsa.sc_iface_number[i] = id->bInterfaceNumber; 279 280 /* initialize endpoints */ 281 uca.bulkin = uca.bulkout = -1; 282 283 for (j = 0; j < id->bNumEndpoints; j++) { 284 ed = usbd_interface2endpoint_descriptor( 285 sc->sc_ubsa.sc_iface[i], j); 286 if (ed == NULL) { 287 printf("%s: no endpoint descriptor for %d (interface: %d)\n", 288 devname, j, i); 289 break; 290 } 291 292 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 293 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 294 sc->sc_ubsa.sc_intr_number = ed->bEndpointAddress; 295 sc->sc_ubsa.sc_isize = UGETW(ed->wMaxPacketSize); 296 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 297 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 298 uca.bulkin = ed->bEndpointAddress; 299 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 300 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 301 uca.bulkout = ed->bEndpointAddress; 302 } 303 } /* end of Endpoint loop */ 304 305 if (sc->sc_ubsa.sc_intr_number == -1) { 306 printf("%s: HUAWEI E220 need to re-attach to enable modem function\n", devname); 307 if (i == 0) { 308 /* could not get intr for main tty */ 309 sc->sc_ubsa.sc_dying = 1; 310 goto error; 311 } else 312 break; 313 } 314 if (uca.bulkin == -1) { 315 printf("%s: Could not find data bulk in\n", devname); 316 sc->sc_ubsa.sc_dying = 1; 317 goto error; 318 } 319 320 if (uca.bulkout == -1) { 321 printf("%s: Could not find data bulk out\n", devname); 322 sc->sc_ubsa.sc_dying = 1; 323 goto error; 324 } 325 326 switch (i) { 327 case 0: 328 snprintf(comname, sizeof(comname), "modem"); 329 break; 330 case 1: 331 snprintf(comname, sizeof(comname), "alt#1"); 332 break; 333 case 2: 334 snprintf(comname, sizeof(comname), "alt#2"); 335 break; 336 default: 337 snprintf(comname, sizeof(comname), "int#%d", i); 338 break; 339 } 340 341 uca.portno = i; 342 /* bulkin, bulkout set above */ 343 uca.ibufsize = UHMODEMIBUFSIZE; 344 uca.obufsize = UHMODEMOBUFSIZE; 345 uca.ibufsizepad = UHMODEMIBUFSIZE; 346 uca.opkthdrlen = 0; 347 uca.device = dev; 348 uca.iface = sc->sc_ubsa.sc_iface[i]; 349 uca.methods = &uhmodem_methods; 350 uca.arg = &sc->sc_ubsa; 351 uca.info = comname; 352 DPRINTF(("uhmodem: int#=%d, in = 0x%x, out = 0x%x, intr = 0x%x\n", 353 i, uca.bulkin, uca.bulkout, sc->sc_ubsa.sc_intr_number)); 354 sc->sc_ubsa.sc_subdevs[i] = config_found_sm_loc(self, "ucombus", NULL, 355 &uca, ucomprint, ucomsubmatch); 356 357 /* issue endpoint halt to each interface */ 358 err = uhmodem_endpointhalt(&sc->sc_ubsa, i); 359 if (err) 360 printf("%s: endpointhalt fail\n", __func__); 361 else 362 usbd_delay_ms(sc->sc_ubsa.sc_udev, 50); 363 } /* end of Interface loop */ 364 365 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_ubsa.sc_udev, 366 USBDEV(sc->sc_ubsa.sc_dev)); 367 368 USB_ATTACH_SUCCESS_RETURN; 369 370 error: 371 USB_ATTACH_ERROR_RETURN; 372 } 373 374 void 375 uhmodem_childdet(device_t self, device_t child) 376 { 377 int i; 378 struct uhmodem_softc *sc = device_private(self); 379 380 for (i = 0; i < sc->sc_ubsa.sc_numif; i++) { 381 if (sc->sc_ubsa.sc_subdevs[i] == child) 382 break; 383 } 384 KASSERT(i < sc->sc_ubsa.sc_numif); 385 sc->sc_ubsa.sc_subdevs[i] = NULL; 386 } 387 388 USB_DETACH(uhmodem) 389 { 390 USB_DETACH_START(uhmodem, sc); 391 int i; 392 int rv = 0; 393 394 DPRINTF(("uhmodem_detach: sc = %p\n", sc)); 395 396 if (sc->sc_ubsa.sc_intr_pipe != NULL) { 397 usbd_abort_pipe(sc->sc_ubsa.sc_intr_pipe); 398 usbd_close_pipe(sc->sc_ubsa.sc_intr_pipe); 399 free(sc->sc_ubsa.sc_intr_buf, M_USBDEV); 400 sc->sc_ubsa.sc_intr_pipe = NULL; 401 } 402 403 sc->sc_ubsa.sc_dying = 1; 404 for (i = 0; i < sc->sc_ubsa.sc_numif; i++) { 405 if (sc->sc_ubsa.sc_subdevs[i] != NULL) 406 rv |= config_detach(sc->sc_ubsa.sc_subdevs[i], flags); 407 } 408 409 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_ubsa.sc_udev, 410 USBDEV(sc->sc_ubsa.sc_dev)); 411 412 return (rv); 413 } 414 415 int 416 uhmodem_activate(device_t self, enum devact act) 417 { 418 struct uhmodem_softc *sc = device_private(self); 419 int rv = 0; 420 int i; 421 422 switch (act) { 423 case DVACT_ACTIVATE: 424 return (EOPNOTSUPP); 425 426 case DVACT_DEACTIVATE: 427 for (i = 0; i < sc->sc_ubsa.sc_numif; i++) { 428 if (sc->sc_ubsa.sc_subdevs[i] != NULL) 429 rv |= config_deactivate(sc->sc_ubsa.sc_subdevs[i]); 430 } 431 sc->sc_ubsa.sc_dying = 1; 432 break; 433 } 434 return (rv); 435 } 436 437 Static int 438 uhmodem_open(void *addr, int portno) 439 { 440 struct ubsa_softc *sc = addr; 441 usbd_status err; 442 443 if (sc->sc_dying) 444 return (ENXIO); 445 446 DPRINTF(("%s: sc = %p\n", __func__, sc)); 447 448 err = uhmodem_endpointhalt(sc, 0); 449 if (err) 450 printf("%s: endpointhalt fail\n", __func__); 451 else 452 usbd_delay_ms(sc->sc_udev, 50); 453 454 if (sc->sc_devflags & A2502) { 455 err = a2502_init(sc->sc_udev); 456 if (err) 457 printf("%s: a2502init fail\n", __func__); 458 else 459 usbd_delay_ms(sc->sc_udev, 50); 460 } 461 #if 0 /* currently disabled */ 462 if (sc->sc_devflags & E220) { 463 err = e220_init(sc->sc_udev); 464 if (err) 465 printf("%s: e220init fail\n", __func__); 466 else 467 usbd_delay_ms(sc->sc_udev, 50); 468 } 469 #endif 470 if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { 471 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 472 /* XXX only iface# = 0 has intr line */ 473 /* XXX E220 specific? need to check */ 474 err = usbd_open_pipe_intr(sc->sc_iface[0], 475 sc->sc_intr_number, 476 USBD_SHORT_XFER_OK, 477 &sc->sc_intr_pipe, 478 sc, 479 sc->sc_intr_buf, 480 sc->sc_isize, 481 ubsa_intr, 482 UBSA_INTR_INTERVAL); 483 if (err) { 484 printf("%s: cannot open interrupt pipe (addr %d)\n", 485 USBDEVNAME(sc->sc_dev), 486 sc->sc_intr_number); 487 return (EIO); 488 } 489 } 490 491 return (0); 492 } 493 494 /* 495 * Hauwei E220 needs special request to enable modem function. 496 * -- DEVICE_REMOTE_WAKEUP ruquest to endpoint 2. 497 */ 498 Static usbd_status 499 e220_modechange_request(usbd_device_handle dev) 500 { 501 #define E220_MODE_CHANGE_REQUEST 0x2 502 usb_device_request_t req; 503 usbd_status err; 504 505 req.bmRequestType = UT_WRITE_DEVICE; 506 req.bRequest = UR_SET_FEATURE; 507 USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP); 508 USETW(req.wIndex, E220_MODE_CHANGE_REQUEST); 509 USETW(req.wLength, 0); 510 511 DPRINTF(("%s: send e220 mode change request\n", __func__)); 512 err = usbd_do_request(dev, &req, 0); 513 if (err) { 514 DPRINTF(("%s: E220 mode change fail\n", __func__)); 515 return (EIO); 516 } 517 518 return (0); 519 #undef E220_MODE_CHANGE_REQUEST 520 } 521 522 Static usbd_status 523 uhmodem_endpointhalt(struct ubsa_softc *sc, int iface) 524 { 525 usb_device_request_t req; 526 usb_endpoint_descriptor_t *ed; 527 usb_interface_descriptor_t *id; 528 usbd_status err; 529 int i; 530 531 /* Find the endpoints */ 532 id = usbd_get_interface_descriptor(sc->sc_iface[iface]); 533 534 for (i = 0; i < id->bNumEndpoints; i++) { 535 ed = usbd_interface2endpoint_descriptor(sc->sc_iface[iface], i); 536 if (ed == NULL) 537 return (EIO); 538 539 if (UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 540 /* issue ENDPOINT_HALT request */ 541 req.bmRequestType = UT_WRITE_ENDPOINT; 542 req.bRequest = UR_CLEAR_FEATURE; 543 USETW(req.wValue, UF_ENDPOINT_HALT); 544 USETW(req.wIndex, ed->bEndpointAddress); 545 USETW(req.wLength, 0); 546 err = usbd_do_request(sc->sc_udev, &req, 0); 547 if (err) { 548 DPRINTF(("%s: ENDPOINT_HALT to EP:%d fail\n", 549 __func__, ed->bEndpointAddress)); 550 return (EIO); 551 } 552 553 } 554 } /* end of Endpoint loop */ 555 556 return (0); 557 } 558 559 Static usbd_status 560 uhmodem_regwrite(usbd_device_handle dev, uint8_t *data, size_t len) 561 { 562 usb_device_request_t req; 563 usbd_status err; 564 565 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 566 req.bRequest = UHMODEM_REGWRITE; 567 USETW(req.wValue, 0x0000); 568 USETW(req.wIndex, 0x0000); 569 USETW(req.wLength, len); 570 err = usbd_do_request(dev, &req, data); 571 if (err) 572 return err; 573 574 return 0; 575 } 576 577 Static usbd_status 578 uhmodem_regread(usbd_device_handle dev, uint8_t *data, size_t len) 579 { 580 usb_device_request_t req; 581 usbd_status err; 582 583 req.bmRequestType = UT_READ_CLASS_INTERFACE; 584 req.bRequest = UHMODEM_REGREAD; 585 USETW(req.wValue, 0x0000); 586 USETW(req.wIndex, 0x0000); 587 USETW(req.wLength, len); 588 err = usbd_do_request(dev, &req, data); 589 590 if (err) 591 return err; 592 593 return 0; 594 } 595 596 #if 0 597 Static usbd_status 598 uhmodem_regsetup(usbd_device_handle dev, uint16_t cmd) 599 { 600 usb_device_request_t req; 601 usbd_status err; 602 603 req.bmRequestType = UT_READ_CLASS_INTERFACE; 604 req.bRequest = UHMODEM_SETUP; 605 USETW(req.wValue, cmd); 606 USETW(req.wIndex, 0x0000); 607 USETW(req.wLength, 0); 608 err = usbd_do_request(dev, &req, 0); 609 610 if (err) 611 return err; 612 613 return 0; 614 } 615 #endif 616 617 Static usbd_status 618 a2502_init(usbd_device_handle dev) 619 { 620 uint8_t data[8]; 621 static uint8_t init_cmd[] = {0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x08}; 622 #ifdef UHMODEM_DEBUG 623 int i; 624 #endif 625 if (uhmodem_regread(dev, data, 7)) { 626 DPRINTF(("%s: read fail\n", __func__)); 627 return EIO; 628 } 629 #ifdef UHMODEM_DEBUG 630 printf("%s: readdata: ", __func__); 631 for (i = 0; i < 7; i++) 632 printf("0x%x ", data[i]); 633 #endif 634 if (uhmodem_regwrite(dev, init_cmd, sizeof(init_cmd)) ) { 635 DPRINTF(("%s: write fail\n", __func__)); 636 return EIO; 637 } 638 639 if (uhmodem_regread(dev, data, 7)) { 640 DPRINTF(("%s: read fail\n", __func__)); 641 return EIO; 642 } 643 #ifdef UHMODEM_DEBUG 644 printf("%s: readdata: ", __func__); 645 printf(" => "); 646 for (i = 0; i < 7; i++) 647 printf("0x%x ", data[i]); 648 printf("\n"); 649 #endif 650 return 0; 651 } 652 653 654 #if 0 655 /* 656 * Windows device driver send these sequens of USB requests. 657 * However currently I can't understand what the messege is, 658 * disable this code when I get more information about it. 659 */ 660 Static usbd_status 661 e220_init(usbd_device_handle dev) 662 { 663 uint8_t data[8]; 664 usb_device_request_t req; 665 int i; 666 667 /* vendor specific unknown request */ 668 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 669 req.bRequest = 0x02; 670 USETW(req.wValue, 0x0001); 671 USETW(req.wIndex, 0x0000); 672 USETW(req.wLength, 2); 673 data[0] = 0x0; 674 data[1] = 0x0; 675 if (usbd_do_request(dev, &req, data)) 676 goto error; 677 678 /* vendor specific unknown sequence */ 679 if(uhmodem_regsetup(dev, 0x1)) 680 goto error; 681 682 if (uhmodem_regread(dev, data, 7)) 683 goto error; 684 685 data[1] = 0x8; 686 data[2] = 0x7; 687 if (uhmodem_regwrite(dev, data, sizeof(data)) ) 688 goto error; 689 690 if (uhmodem_regread(dev, data, 7)) 691 goto error; 692 /* XXX should verify the read data ? */ 693 694 if (uhmodem_regsetup(dev, 0x3)) 695 goto error; 696 697 return (0); 698 error: 699 DPRINTF(("%s: E220 init request fail\n", __func__)); 700 return (EIO); 701 } 702 #endif 703 704