1 /* $OpenBSD: umsm.c,v 1.33 2008/07/30 15:40:39 canacar Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Yojiro UO <yuo@nui.org> 5 * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org> 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 USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Driver for Qualcomm MSM EVDO and UMTS communication devices */ 21 22 #include <sys/param.h> 23 #include <sys/systm.h> 24 #include <sys/kernel.h> 25 #include <sys/malloc.h> 26 #include <sys/device.h> 27 #include <sys/conf.h> 28 #include <sys/tty.h> 29 30 #include <dev/usb/usb.h> 31 #include <dev/usb/usbdi.h> 32 #include <dev/usb/usbdi_util.h> 33 #include <dev/usb/usbdevs.h> 34 #include <dev/usb/ucomvar.h> 35 #include <dev/usb/usbcdc.h> 36 #include <dev/usb/umassvar.h> 37 #undef DPRINTF /* undef DPRINTF for umass */ 38 39 #ifdef USB_DEBUG 40 #define UMSM_DEBUG 41 #endif 42 43 #ifdef UMSM_DEBUG 44 int umsmdebug = 1; 45 #define DPRINTFN(n, x) do { if (umsmdebug > (n)) printf x; } while (0) 46 #else 47 #define DPRINTFN(n, x) 48 #endif 49 50 #define DPRINTF(x) DPRINTFN(0, x) 51 52 #define UMSMBUFSZ 4096 53 #define UMSM_INTR_INTERVAL 100 /* ms */ 54 #define E220_MODE_CHANGE_REQUEST 0x2 55 56 int umsm_match(struct device *, void *, void *); 57 void umsm_attach(struct device *, struct device *, void *); 58 int umsm_detach(struct device *, int); 59 int umsm_activate(struct device *, enum devact); 60 61 int umsm_open(void *, int); 62 void umsm_close(void *, int); 63 void umsm_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); 64 void umsm_get_status(void *, int, u_char *, u_char *); 65 void umsm_set(void *, int, int, int); 66 67 struct umsm_softc { 68 struct device sc_dev; 69 usbd_device_handle sc_udev; 70 usbd_interface_handle sc_iface; 71 int sc_iface_no; 72 struct device *sc_subdev; 73 u_char sc_dying; 74 uint16_t sc_flag; 75 76 /* interrupt ep */ 77 int sc_intr_number; 78 usbd_pipe_handle sc_intr_pipe; 79 u_char *sc_intr_buf; 80 int sc_isize; 81 82 u_char sc_lsr; /* Local status register */ 83 u_char sc_msr; /* status register */ 84 u_char sc_dtr; /* current DTR state */ 85 u_char sc_rts; /* current RTS state */ 86 }; 87 88 usbd_status umsm_huawei_changemode(usbd_device_handle); 89 usbd_status umsm_umass_changemode(struct umsm_softc *); 90 91 struct ucom_methods umsm_methods = { 92 umsm_get_status, 93 umsm_set, 94 NULL, 95 NULL, 96 umsm_open, 97 umsm_close, 98 NULL, 99 NULL, 100 }; 101 102 struct umsm_type { 103 struct usb_devno umsm_dev; 104 uint16_t umsm_flag; 105 /* device type */ 106 #define DEV_NORMAL 0x0000 107 #define DEV_HUAWEI 0x0001 108 #define DEV_UMASS1 0x0010 109 #define DEV_UMASS2 0x0020 110 #define DEV_UMASS (DEV_UMASS1 | DEV_UMASS2) 111 }; 112 113 static const struct umsm_type umsm_devs[] = { 114 {{ USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220 }, 0}, 115 {{ USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_A2502 }, 0}, 116 {{ USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_500A }, 0}, 117 {{ USB_VENDOR_DELL, USB_PRODUCT_DELL_W5500 }, 0}, 118 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 }, DEV_HUAWEI}, 119 {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E618 }, 0}, 120 {{ USB_VENDOR_KYOCERA2, USB_PRODUCT_KYOCERA2_KPC650 }, 0}, 121 {{ USB_VENDOR_NOVATEL1, USB_PRODUCT_NOVATEL1_FLEXPACKGPS }, 0}, 122 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_EXPRESSCARD }, 0}, 123 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MERLINV620 }, 0}, 124 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_S720 }, 0}, 125 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720 }, 0}, 126 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870 }, 0}, 127 {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620 }, 0}, 128 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS }, 0}, 129 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GSICON72 }, DEV_UMASS1}, 130 {{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTHSDPA225 }, DEV_UMASS2}, 131 {{ USB_VENDOR_QUALCOMM, USB_PRODUCT_QUALCOMM_MSM_DRIVER }, DEV_UMASS1}, 132 {{ USB_VENDOR_QUALCOMM, USB_PRODUCT_QUALCOMM_MSM_HSDPA }, 0}, 133 {{ USB_VENDOR_QUALCOMM, USB_PRODUCT_QUALCOMM_MSM_HSDPA2 }, 0}, 134 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 }, 0}, 135 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD_580 }, 0}, 136 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD_595 }, 0}, 137 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD_875 }, 0}, 138 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 }, 0}, 139 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 }, 0}, 140 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725_2 }, 0}, 141 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 }, 0}, 142 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 }, 0}, 143 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 }, 0}, 144 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 }, 0}, 145 {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775 }, 0}, 146 }; 147 148 #define umsm_lookup(v, p) ((const struct umsm_type *)usb_lookup(umsm_devs, v, p)) 149 150 struct cfdriver umsm_cd = { 151 NULL, "umsm", DV_DULL 152 }; 153 154 const struct cfattach umsm_ca = { 155 sizeof(struct umsm_softc), 156 umsm_match, 157 umsm_attach, 158 umsm_detach, 159 umsm_activate, 160 }; 161 162 int 163 umsm_match(struct device *parent, void *match, void *aux) 164 { 165 struct usb_attach_arg *uaa = aux; 166 usb_interface_descriptor_t *id; 167 uint16_t flag; 168 169 if (uaa->iface == NULL) 170 return UMATCH_NONE; 171 172 /* 173 * Some devices (eg Huawei E220) have multiple interfaces and some 174 * of them are of class umass. Don't claim ownership in such case. 175 */ 176 if (umsm_lookup(uaa->vendor, uaa->product) != NULL) { 177 id = usbd_get_interface_descriptor(uaa->iface); 178 flag = umsm_lookup(uaa->vendor, uaa->product)->umsm_flag; 179 180 if (id == NULL || id->bInterfaceClass == UICLASS_MASS) { 181 /* 182 * Some high-speed modem requre special care. 183 */ 184 if (flag & DEV_HUAWEI) { 185 if (uaa->ifaceno != 2) 186 return UMATCH_VENDOR_IFACESUBCLASS; 187 else 188 return UMATCH_NONE; 189 } else if (flag & DEV_UMASS) 190 return UMATCH_VENDOR_IFACESUBCLASS; 191 else 192 return UMATCH_NONE; 193 } else 194 return UMATCH_VENDOR_IFACESUBCLASS; 195 } 196 197 return UMATCH_NONE; 198 } 199 200 void 201 umsm_attach(struct device *parent, struct device *self, void *aux) 202 { 203 struct umsm_softc *sc = (struct umsm_softc *)self; 204 struct usb_attach_arg *uaa = aux; 205 struct ucom_attach_args uca; 206 usb_interface_descriptor_t *id; 207 usb_endpoint_descriptor_t *ed; 208 int i; 209 210 bzero(&uca, sizeof(uca)); 211 sc->sc_udev = uaa->device; 212 sc->sc_iface = uaa->iface; 213 sc->sc_flag = umsm_lookup(uaa->vendor, uaa->product)->umsm_flag; 214 215 id = usbd_get_interface_descriptor(sc->sc_iface); 216 217 /* 218 * Some 3G modem devices have multiple interface and some 219 * of them are umass class. Don't claim ownership in such case. 220 */ 221 if (id == NULL || id->bInterfaceClass == UICLASS_MASS) { 222 /* 223 * Some 3G modems require special request to 224 * enable it's modem function. 225 */ 226 if ((sc->sc_flag & DEV_HUAWEI) && uaa->ifaceno == 0) { 227 umsm_huawei_changemode(uaa->device); 228 printf("%s: umass only mode. need to reattach\n", 229 sc->sc_dev.dv_xname); 230 } else if ((sc->sc_flag & DEV_UMASS) && uaa->ifaceno == 0) { 231 umsm_umass_changemode(sc); 232 } 233 234 /* 235 * The device will reset its own bus from the device side 236 * when its mode was changed, so just return. 237 */ 238 return; 239 } 240 241 sc->sc_iface_no = id->bInterfaceNumber; 242 uca.bulkin = uca.bulkout = -1; 243 sc->sc_intr_number = sc->sc_isize = -1; 244 for (i = 0; i < id->bNumEndpoints; i++) { 245 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 246 if (ed == NULL) { 247 printf("%s: no endpoint descriptor found for %d\n", 248 sc->sc_dev.dv_xname, i); 249 sc->sc_dying = 1; 250 return; 251 } 252 253 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 254 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 255 sc->sc_intr_number = ed->bEndpointAddress; 256 sc->sc_isize = UGETW(ed->wMaxPacketSize); 257 DPRINTF(("%s: find interrupt endpoint for %s\n", 258 __func__, sc->sc_dev.dv_xname)); 259 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 260 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 261 uca.bulkin = ed->bEndpointAddress; 262 else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 263 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 264 uca.bulkout = ed->bEndpointAddress; 265 } 266 if (uca.bulkin == -1 || uca.bulkout == -1) { 267 printf("%s: missing endpoint\n", sc->sc_dev.dv_xname); 268 sc->sc_dying = 1; 269 return; 270 } 271 272 sc->sc_dtr = sc->sc_rts = -1; 273 274 /* We need to force size as some devices lie */ 275 uca.ibufsize = UMSMBUFSZ; 276 uca.obufsize = UMSMBUFSZ; 277 uca.ibufsizepad = UMSMBUFSZ; 278 uca.opkthdrlen = 0; 279 uca.device = sc->sc_udev; 280 uca.iface = sc->sc_iface; 281 uca.methods = &umsm_methods; 282 uca.arg = sc; 283 uca.info = NULL; 284 uca.portno = UCOM_UNK_PORTNO; 285 286 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 287 &sc->sc_dev); 288 289 sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); 290 } 291 292 int 293 umsm_detach(struct device *self, int flags) 294 { 295 struct umsm_softc *sc = (struct umsm_softc *)self; 296 int rv = 0; 297 298 /* close the interrupt endpoint if that is opened */ 299 if (sc->sc_intr_pipe != NULL) { 300 usbd_abort_pipe(sc->sc_intr_pipe); 301 usbd_close_pipe(sc->sc_intr_pipe); 302 free(sc->sc_intr_buf, M_USBDEV); 303 sc->sc_intr_pipe = NULL; 304 } 305 306 sc->sc_dying = 1; 307 if (sc->sc_subdev != NULL) { 308 rv = config_detach(sc->sc_subdev, flags); 309 sc->sc_subdev = NULL; 310 } 311 312 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, 313 &sc->sc_dev); 314 315 return (rv); 316 } 317 318 int 319 umsm_activate(struct device *self, enum devact act) 320 { 321 struct umsm_softc *sc = (struct umsm_softc *)self; 322 int rv = 0; 323 324 switch (act) { 325 case DVACT_ACTIVATE: 326 break; 327 328 case DVACT_DEACTIVATE: 329 if (sc->sc_subdev != NULL) 330 rv = config_deactivate(sc->sc_subdev); 331 sc->sc_dying = 1; 332 break; 333 } 334 return (rv); 335 } 336 337 int 338 umsm_open(void *addr, int portno) 339 { 340 struct umsm_softc *sc = addr; 341 int err; 342 343 if (sc->sc_dying) 344 return (ENXIO); 345 346 if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { 347 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 348 err = usbd_open_pipe_intr(sc->sc_iface, 349 sc->sc_intr_number, 350 USBD_SHORT_XFER_OK, 351 &sc->sc_intr_pipe, 352 sc, 353 sc->sc_intr_buf, 354 sc->sc_isize, 355 umsm_intr, 356 UMSM_INTR_INTERVAL); 357 if (err) { 358 printf("%s: cannot open interrupt pipe (addr %d)\n", 359 sc->sc_dev.dv_xname, 360 sc->sc_intr_number); 361 return (EIO); 362 } 363 } 364 365 return (0); 366 } 367 368 void 369 umsm_close(void *addr, int portno) 370 { 371 struct umsm_softc *sc = addr; 372 int err; 373 374 if (sc->sc_dying) 375 return; 376 377 if (sc->sc_intr_pipe != NULL) { 378 err = usbd_abort_pipe(sc->sc_intr_pipe); 379 if (err) 380 printf("%s: abort interrupt pipe failed: %s\n", 381 sc->sc_dev.dv_xname, 382 usbd_errstr(err)); 383 err = usbd_close_pipe(sc->sc_intr_pipe); 384 if (err) 385 printf("%s: close interrupt pipe failed: %s\n", 386 sc->sc_dev.dv_xname, 387 usbd_errstr(err)); 388 free(sc->sc_intr_buf, M_USBDEV); 389 sc->sc_intr_pipe = NULL; 390 } 391 } 392 393 void 394 umsm_intr(usbd_xfer_handle xfer, usbd_private_handle priv, 395 usbd_status status) 396 { 397 struct umsm_softc *sc = priv; 398 usb_cdc_notification_t *buf; 399 u_char mstatus; 400 401 buf = (usb_cdc_notification_t *)sc->sc_intr_buf; 402 if (sc->sc_dying) 403 return; 404 405 if (status != USBD_NORMAL_COMPLETION) { 406 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 407 return; 408 409 DPRINTF(("%s: umsm_intr: abnormal status: %s\n", 410 sc->sc_dev.dv_xname, usbd_errstr(status))); 411 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 412 return; 413 } 414 415 if (buf->bmRequestType != UCDC_NOTIFICATION) { 416 #if 1 /* test */ 417 printf("%s: this device is not using CDC notify message in intr pipe.\n" 418 "Please send your dmesg to <bugs@openbsd.org>, thanks.\n", 419 sc->sc_dev.dv_xname); 420 printf("%s: intr buffer 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", 421 sc->sc_dev.dv_xname, 422 sc->sc_intr_buf[0], sc->sc_intr_buf[1], 423 sc->sc_intr_buf[2], sc->sc_intr_buf[3], 424 sc->sc_intr_buf[4], sc->sc_intr_buf[5], 425 sc->sc_intr_buf[6]); 426 #else 427 DPRINTF(("%s: umsm_intr: unknown message type(0x%02x)\n", 428 sc->sc_dev.dv_xname, buf->bmRequestType)); 429 #endif 430 return; 431 } 432 433 if (buf->bNotification == UCDC_N_SERIAL_STATE) { 434 /* invalid message length, discard it */ 435 if (UGETW(buf->wLength) != 2) 436 return; 437 /* XXX: sc_lsr is always 0 */ 438 sc->sc_lsr = sc->sc_msr = 0; 439 mstatus = buf->data[0]; 440 if (ISSET(mstatus, UCDC_N_SERIAL_RI)) 441 sc->sc_msr |= UMSR_RI; 442 if (ISSET(mstatus, UCDC_N_SERIAL_DSR)) 443 sc->sc_msr |= UMSR_DSR; 444 if (ISSET(mstatus, UCDC_N_SERIAL_DCD)) 445 sc->sc_msr |= UMSR_DCD; 446 } else if (buf->bNotification != UCDC_N_CONNECTION_SPEED_CHANGE) { 447 DPRINTF(("%s: umsm_intr: unknown notify message (0x%02x)\n", 448 sc->sc_dev.dv_xname, buf->bNotification)); 449 return; 450 } 451 452 ucom_status_change((struct ucom_softc *)sc->sc_subdev); 453 } 454 455 void 456 umsm_get_status(void *addr, int portno, u_char *lsr, u_char *msr) 457 { 458 struct umsm_softc *sc = addr; 459 460 if (lsr != NULL) 461 *lsr = sc->sc_lsr; 462 if (msr != NULL) 463 *msr = sc->sc_msr; 464 } 465 466 void 467 umsm_set(void *addr, int portno, int reg, int onoff) 468 { 469 struct umsm_softc *sc = addr; 470 usb_device_request_t req; 471 int ls; 472 473 switch (reg) { 474 case UCOM_SET_DTR: 475 if (sc->sc_dtr == onoff) 476 return; 477 sc->sc_dtr = onoff; 478 break; 479 case UCOM_SET_RTS: 480 if (sc->sc_rts == onoff) 481 return; 482 sc->sc_rts = onoff; 483 break; 484 default: 485 return; 486 } 487 488 /* build a usb request */ 489 ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) | 490 (sc->sc_rts ? UCDC_LINE_RTS : 0); 491 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 492 req.bRequest = UCDC_SET_CONTROL_LINE_STATE; 493 USETW(req.wValue, ls); 494 USETW(req.wIndex, sc->sc_iface_no); 495 USETW(req.wLength, 0); 496 497 (void)usbd_do_request(sc->sc_udev, &req, 0); 498 } 499 500 usbd_status 501 umsm_huawei_changemode(usbd_device_handle dev) 502 { 503 usb_device_request_t req; 504 usbd_status err; 505 506 req.bmRequestType = UT_WRITE_DEVICE; 507 req.bRequest = UR_SET_FEATURE; 508 USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP); 509 USETW(req.wIndex, E220_MODE_CHANGE_REQUEST); 510 USETW(req.wLength, 0); 511 512 err = usbd_do_request(dev, &req, 0); 513 if (err) 514 return (EIO); 515 516 return (0); 517 } 518 519 usbd_status 520 umsm_umass_changemode(struct umsm_softc *sc) 521 { 522 #define UMASS_CMD_REZERO_UNIT 0x01 523 usb_interface_descriptor_t *id; 524 usb_endpoint_descriptor_t *ed; 525 usbd_xfer_handle xfer; 526 usbd_pipe_handle cmdpipe; 527 usbd_status err; 528 u_int32_t n; 529 void *bufp; 530 int target_ep, i; 531 532 umass_bbb_cbw_t cbw; 533 static int dCBWTag = 0x12345678; 534 535 USETDW(cbw.dCBWSignature, CBWSIGNATURE); 536 USETDW(cbw.dCBWTag, dCBWTag); 537 cbw.bCBWLUN = 0; 538 cbw.bCDBLength= 6; 539 bzero(cbw.CBWCDB, sizeof(cbw.CBWCDB)); 540 cbw.CBWCDB[0] = UMASS_CMD_REZERO_UNIT; 541 cbw.CBWCDB[1] = 0x0; /* target LUN: 0 */ 542 543 switch (sc->sc_flag) { 544 case DEV_UMASS1: 545 USETDW(cbw.dCBWDataTransferLength, 0x0); 546 cbw.bCBWFlags = CBWFLAGS_OUT; 547 break; 548 case DEV_UMASS2: 549 USETDW(cbw.dCBWDataTransferLength, 0x1); 550 cbw.bCBWFlags = CBWFLAGS_IN; 551 break; 552 default: 553 DPRINTF(("%s: unknown device type.\n", sc->sc_dev.dv_xname)); 554 break; 555 } 556 557 /* get command endpoint address */ 558 id = usbd_get_interface_descriptor(sc->sc_iface); 559 for (i = 0; i < id->bNumEndpoints; i++) { 560 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 561 if (ed == NULL) { 562 return (USBD_IOERROR); 563 } 564 565 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 566 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 567 target_ep = ed->bEndpointAddress; 568 } 569 570 /* open command endppoint */ 571 err = usbd_open_pipe(sc->sc_iface, target_ep, 572 USBD_EXCLUSIVE_USE, &cmdpipe); 573 if (err) { 574 DPRINTF(("%s: open pipe for modem change cmd failed: %s\n", 575 sc->sc_dev.dv_xname, usbd_errstr(err))); 576 return (err); 577 } 578 579 xfer = usbd_alloc_xfer(sc->sc_udev); 580 if (xfer == NULL) { 581 usbd_close_pipe(cmdpipe); 582 return (USBD_NOMEM); 583 } else { 584 bufp = usbd_alloc_buffer(xfer, UMASS_BBB_CBW_SIZE); 585 if (bufp == NULL) 586 err = USBD_NOMEM; 587 else { 588 n = UMASS_BBB_CBW_SIZE; 589 memcpy(bufp, &cbw, UMASS_BBB_CBW_SIZE); 590 err = usbd_bulk_transfer(xfer, cmdpipe, USBD_NO_COPY, 591 USBD_NO_TIMEOUT, bufp, &n, "umsm"); 592 if (err) 593 DPRINTF(("%s: send error:%s", __func__, 594 usbd_errstr(err))); 595 } 596 usbd_close_pipe(cmdpipe); 597 usbd_free_buffer(xfer); 598 usbd_free_xfer(xfer); 599 } 600 601 return (err); 602 } 603