1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * USB Serial CDC ACM driver 29 * 30 * 1. General Concepts 31 * ------------------- 32 * 33 * 1.1 Overview 34 * ------------ 35 * This driver supports devices that comply with the USB Communication 36 * Device Class Abstract Control Model (USB CDC ACM) specification, 37 * which is available at http://www.usb.org. Given the broad nature 38 * of communication equipment, this driver supports the following 39 * types of devices: 40 * + Telecommunications devices: analog modems, mobile phones; 41 * + Networking devices: cable modems; 42 * Except the above mentioned acm devices, this driver also supports 43 * some devices which provide modem-like function and have pairs of 44 * bulk in/out pipes. 45 * 46 * There are three classes that make up the definition for communication 47 * devices: the Communication Device Class, the Communication Interface 48 * Class and the Data Interface Class. The Communication Device Class 49 * is a device level definition and is used by the host to properly 50 * identify a communication device that may present several different 51 * types of interfaces. The Communication Interface Class defines a 52 * general-purpose mechanism that can be used to enable all types of 53 * communication services on the Universal Serial Bus (USB). The Data 54 * Interface Class defines a general-purpose mechanism to enable bulk 55 * transfer on the USB when the data does not meet the requirements 56 * for any other class. 57 * 58 * 1.2 Interface Definitions 59 * ------------------------- 60 * Communication Class Interface is used for device management and, 61 * optionally, call management. Device management includes the requests 62 * that manage the operational state of a device, the device responses, 63 * and event notifications. In Abstract Control Model, the device can 64 * provide an internal implementation of call management over the Data 65 * Class interface or the Communication Class interface. 66 * 67 * The Data Class defines a data interface as an interface with a class 68 * type of Data Class. Data transmission on a communication device is 69 * not restricted to interfaces using the Data Class. Rather, a data 70 * interface is used to transmit and/or receive data that is not 71 * defined by any other class. The data could be: 72 * + Some form of raw data from a communication line. 73 * + Legacy modem data. 74 * + Data using a proprietary format. 75 * 76 * 1.3 Endpoint Requirements 77 * ------------------------- 78 * The Communication Class interface requires one endpoint, the management 79 * element. Optionally, it can have an additional endpoint, the notification 80 * element. The management element uses the default endpoint for all 81 * standard and Communication Class-specific requests. The notification 82 * element normally uses an interrupt endpoint. 83 * 84 * The type of endpoints belonging to a Data Class interface are restricted 85 * to bulk, and are expected to exist in pairs of the same type (one In and 86 * one Out). 87 * 88 * 1.4 ACM Function Characteristics 89 * -------------------------------- 90 * With Abstract Control Model, the USB device understands standard 91 * V.25ter (AT) commands. The device contains a Datapump and micro- 92 * controller that handles the AT commands and relay controls. The 93 * device uses both a Data Class interface and a Communication Class. 94 * interface. 95 * 96 * A Communication Class interface of type Abstract Control Model will 97 * consist of a minimum of two pipes; one is used to implement the 98 * management element and the other to implement a notification element. 99 * In addition, the device can use two pipes to implement channels over 100 * which to carry unspecified data, typically over a Data Class interface. 101 * 102 * 1.5 ACM Serial Emulation 103 * ------------------------ 104 * The Abstract Control Model can bridge the gap between legacy modem 105 * devices and USB devices. To support certain types of legacy applications, 106 * two problems need to be addressed. The first is supporting specific 107 * legacy control signals and state variables which are addressed 108 * directly by the various carrier modulation standards. To support these 109 * requirement, additional requests and notifications have been created. 110 * Please refer to macro, beginning with USB_CDC_REQ_* and 111 * USB_CDC_NOTIFICATION_*. 112 * 113 * The second significant item which is needed to bridge the gap between 114 * legacy modem designs and the Abstract Control Model is a means to 115 * multiplex call control (AT commands) on the Data Class interface. 116 * Legacy modem designs are limited by only supporting one channel for 117 * both "AT" commands and the actual data. To allow this type of 118 * functionality, the device must have a means to specify this limitation 119 * to the host. 120 * 121 * When describing this type of device, the Communication Class interface 122 * would still specify a Abstract Control Model, but call control would 123 * actually occur over the Data Class interface. To describe this 124 * particular characteristic, the Call Management Functional Descriptor 125 * would have bit D1 of bmCapabilities set. 126 * 127 * 1.6 Other Bulk In/Out Devices 128 * ----------------------------- 129 * Some devices don't conform to USB CDC specification, but they provide 130 * modem-like function and have pairs of bulk in/out pipes. This driver 131 * supports this kind of device and exports term nodes by their pipes. 132 * 133 * 2. Implementation 134 * ----------------- 135 * 136 * 2.1 Overview 137 * ------------ 138 * It is a device-specific driver (DSD) working with USB generic serial 139 * driver (GSD). It implements the USB-to-serial device-specific driver 140 * interface (DSDI) which is offered by GSD. The interface is defined 141 * by ds_ops_t structure. 142 * 143 * 2.2 Port States 144 * --------------- 145 * For USB CDC ACM devices, this driver is attached to its interface, 146 * and exports one port for each interface. For other modem-like devices, 147 * this driver can dynamically find the ports in the current device, 148 * and export one port for each pair bulk in/out pipes. Each port can 149 * be operated independently. 150 * 151 * port_state: 152 * 153 * attach_ports 154 * | 155 * | 156 * | 157 * v 158 * USBSACM_PORT_CLOSED 159 * | ^ 160 * | | 161 * V | 162 * open_port close_port 163 * | ^ 164 * | | 165 * V | 166 * USBSACM_PORT_OPEN 167 * 168 * 169 * 2.3 Pipe States 170 * --------------- 171 * Each port has its own bulk in/out pipes and some ports could also have 172 * its own interrupt pipes (traced by usbsacm_port structure), which are 173 * opened during attach. The pipe status is as following: 174 * 175 * pipe_state: 176 * 177 * usbsacm_init_alloc_ports usbsacm_free_ports 178 * | ^ 179 * v | 180 * |---->------ USBSACM_PORT_CLOSED ------>------+ 181 * ^ | 182 * | reconnect/resume/open_port 183 * | | 184 * disconnect/suspend/close_port | 185 * | v 186 * +------<------ USBSACM_PIPE_IDLE ------<------| 187 * | | 188 * V ^ 189 * | | 190 * +-----------------+ +-----------+ 191 * | | 192 * V ^ 193 * | | 194 * rx_start/tx_start----->------failed------->---------| 195 * | | 196 * | bulkin_cb/bulkout_cb 197 * V | 198 * | ^ 199 * | | 200 * +----->----- USBSACM_PIPE_BUSY ---->------+ 201 * 202 * 203 * To get its status in a timely way, acm driver can get the status 204 * of the device by polling the interrupt pipe. 205 * 206 */ 207 208 #include <sys/types.h> 209 #include <sys/param.h> 210 #include <sys/conf.h> 211 #include <sys/stream.h> 212 #include <sys/strsun.h> 213 #include <sys/termio.h> 214 #include <sys/termiox.h> 215 #include <sys/ddi.h> 216 #include <sys/sunddi.h> 217 #include <sys/byteorder.h> 218 #define USBDRV_MAJOR_VER 2 219 #define USBDRV_MINOR_VER 0 220 #include <sys/usb/usba.h> 221 #include <sys/usb/usba/usba_types.h> 222 #include <sys/usb/clients/usbser/usbser.h> 223 #include <sys/usb/clients/usbser/usbser_dsdi.h> 224 #include <sys/usb/clients/usbcdc/usb_cdc.h> 225 #include <sys/usb/clients/usbser/usbsacm/usbsacm.h> 226 227 /* devops entry points */ 228 static int usbsacm_attach(dev_info_t *, ddi_attach_cmd_t); 229 static int usbsacm_detach(dev_info_t *, ddi_detach_cmd_t); 230 static int usbsacm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, 231 void **); 232 static int usbsacm_open(queue_t *, dev_t *, int, int, cred_t *); 233 234 /* DSD operations */ 235 static int usbsacm_ds_attach(ds_attach_info_t *); 236 static void usbsacm_ds_detach(ds_hdl_t); 237 static int usbsacm_ds_register_cb(ds_hdl_t, uint_t, ds_cb_t *); 238 static void usbsacm_ds_unregister_cb(ds_hdl_t, uint_t); 239 static int usbsacm_ds_open_port(ds_hdl_t, uint_t); 240 static int usbsacm_ds_close_port(ds_hdl_t, uint_t); 241 242 /* standard UART operations */ 243 static int usbsacm_ds_set_port_params(ds_hdl_t, uint_t, 244 ds_port_params_t *); 245 static int usbsacm_ds_set_modem_ctl(ds_hdl_t, uint_t, int, int); 246 static int usbsacm_ds_get_modem_ctl(ds_hdl_t, uint_t, int, int *); 247 static int usbsacm_ds_break_ctl(ds_hdl_t, uint_t, int); 248 249 /* data xfer */ 250 static int usbsacm_ds_tx(ds_hdl_t, uint_t, mblk_t *); 251 static mblk_t *usbsacm_ds_rx(ds_hdl_t, uint_t); 252 static void usbsacm_ds_stop(ds_hdl_t, uint_t, int); 253 static void usbsacm_ds_start(ds_hdl_t, uint_t, int); 254 255 /* fifo operations */ 256 static int usbsacm_ds_fifo_flush(ds_hdl_t, uint_t, int); 257 static int usbsacm_ds_fifo_drain(ds_hdl_t, uint_t, int); 258 static int usbsacm_wait_tx_drain(usbsacm_port_t *, int); 259 static int usbsacm_fifo_flush_locked(usbsacm_state_t *, uint_t, int); 260 261 /* power management and CPR */ 262 static int usbsacm_ds_suspend(ds_hdl_t); 263 static int usbsacm_ds_resume(ds_hdl_t); 264 static int usbsacm_ds_disconnect(ds_hdl_t); 265 static int usbsacm_ds_reconnect(ds_hdl_t); 266 static int usbsacm_ds_usb_power(ds_hdl_t, int, int, int *); 267 static int usbsacm_create_pm_components(usbsacm_state_t *); 268 static void usbsacm_destroy_pm_components(usbsacm_state_t *); 269 static void usbsacm_pm_set_busy(usbsacm_state_t *); 270 static void usbsacm_pm_set_idle(usbsacm_state_t *); 271 static int usbsacm_pwrlvl0(usbsacm_state_t *); 272 static int usbsacm_pwrlvl1(usbsacm_state_t *); 273 static int usbsacm_pwrlvl2(usbsacm_state_t *); 274 static int usbsacm_pwrlvl3(usbsacm_state_t *); 275 276 /* event handling */ 277 /* pipe callbacks */ 278 static void usbsacm_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *); 279 static void usbsacm_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *); 280 281 /* interrupt pipe */ 282 static void usbsacm_pipe_start_polling(usbsacm_port_t *acmp); 283 static void usbsacm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req); 284 static void usbsacm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req); 285 static void usbsacm_parse_intr_data(usbsacm_port_t *acmp, mblk_t *data); 286 287 /* Utility functions */ 288 /* data transfer routines */ 289 static int usbsacm_rx_start(usbsacm_port_t *); 290 static void usbsacm_tx_start(usbsacm_port_t *); 291 static int usbsacm_send_data(usbsacm_port_t *, mblk_t *); 292 293 /* Initialize or release resources */ 294 static int usbsacm_init_alloc_ports(usbsacm_state_t *); 295 static void usbsacm_free_ports(usbsacm_state_t *); 296 static void usbsacm_cleanup(usbsacm_state_t *); 297 298 /* analysis functional descriptors */ 299 static int usbsacm_get_descriptors(usbsacm_state_t *); 300 301 /* hotplug */ 302 static int usbsacm_restore_device_state(usbsacm_state_t *); 303 static int usbsacm_restore_port_state(usbsacm_state_t *); 304 305 /* pipe operations */ 306 static int usbsacm_open_port_pipes(usbsacm_port_t *); 307 static void usbsacm_close_port_pipes(usbsacm_port_t *); 308 static void usbsacm_close_pipes(usbsacm_state_t *); 309 static void usbsacm_disconnect_pipes(usbsacm_state_t *); 310 static int usbsacm_reconnect_pipes(usbsacm_state_t *); 311 312 /* vendor-specific commands */ 313 static int usbsacm_req_write(usbsacm_port_t *, uchar_t, uint16_t, 314 mblk_t **); 315 static int usbsacm_set_line_coding(usbsacm_port_t *, 316 usb_cdc_line_coding_t *); 317 static void usbsacm_mctl2reg(int mask, int val, uint8_t *); 318 static int usbsacm_reg2mctl(uint8_t); 319 320 /* misc */ 321 static void usbsacm_put_tail(mblk_t **, mblk_t *); 322 static void usbsacm_put_head(mblk_t **, mblk_t *); 323 324 325 /* 326 * Standard STREAMS driver definitions 327 */ 328 struct module_info usbsacm_modinfo = { 329 0, /* module id */ 330 "usbsacm", /* module name */ 331 USBSER_MIN_PKTSZ, /* min pkt size */ 332 USBSER_MAX_PKTSZ, /* max pkt size */ 333 USBSER_HIWAT, /* hi watermark */ 334 USBSER_LOWAT /* low watermark */ 335 }; 336 337 static struct qinit usbsacm_rinit = { 338 NULL, 339 usbser_rsrv, 340 usbsacm_open, 341 usbser_close, 342 NULL, 343 &usbsacm_modinfo, 344 NULL 345 }; 346 347 static struct qinit usbsacm_winit = { 348 usbser_wput, 349 usbser_wsrv, 350 NULL, 351 NULL, 352 NULL, 353 &usbsacm_modinfo, 354 NULL 355 }; 356 357 358 struct streamtab usbsacm_str_info = { 359 &usbsacm_rinit, &usbsacm_winit, NULL, NULL 360 }; 361 362 /* cb_ops structure */ 363 static struct cb_ops usbsacm_cb_ops = { 364 nodev, /* cb_open */ 365 nodev, /* cb_close */ 366 nodev, /* cb_strategy */ 367 nodev, /* cb_print */ 368 nodev, /* cb_dump */ 369 nodev, /* cb_read */ 370 nodev, /* cb_write */ 371 nodev, /* cb_ioctl */ 372 nodev, /* cb_devmap */ 373 nodev, /* cb_mmap */ 374 nodev, /* cb_segmap */ 375 nochpoll, /* cb_chpoll */ 376 ddi_prop_op, /* cb_prop_op */ 377 &usbsacm_str_info, /* cb_stream */ 378 (int)(D_64BIT | D_NEW | D_MP | D_HOTPLUG) /* cb_flag */ 379 }; 380 381 /* dev_ops structure */ 382 struct dev_ops usbsacm_ops = { 383 DEVO_REV, /* devo_rev */ 384 0, /* devo_refcnt */ 385 usbsacm_getinfo, /* devo_getinfo */ 386 nulldev, /* devo_identify */ 387 nulldev, /* devo_probe */ 388 usbsacm_attach, /* devo_attach */ 389 usbsacm_detach, /* devo_detach */ 390 nodev, /* devo_reset */ 391 &usbsacm_cb_ops, /* devo_cb_ops */ 392 (struct bus_ops *)NULL, /* devo_bus_ops */ 393 usbser_power, /* devo_power */ 394 ddi_quiesce_not_needed, /* devo_quiesce */ 395 }; 396 397 extern struct mod_ops mod_driverops; 398 /* modldrv structure */ 399 static struct modldrv modldrv = { 400 &mod_driverops, /* type of module - driver */ 401 "USB Serial CDC ACM driver", 402 &usbsacm_ops, 403 }; 404 405 /* modlinkage structure */ 406 static struct modlinkage modlinkage = { 407 MODREV_1, 408 &modldrv, 409 NULL 410 }; 411 412 static void *usbsacm_statep; /* soft state */ 413 414 /* 415 * DSD definitions 416 */ 417 static ds_ops_t usbsacm_ds_ops = { 418 DS_OPS_VERSION, 419 usbsacm_ds_attach, 420 usbsacm_ds_detach, 421 usbsacm_ds_register_cb, 422 usbsacm_ds_unregister_cb, 423 usbsacm_ds_open_port, 424 usbsacm_ds_close_port, 425 usbsacm_ds_usb_power, 426 usbsacm_ds_suspend, 427 usbsacm_ds_resume, 428 usbsacm_ds_disconnect, 429 usbsacm_ds_reconnect, 430 usbsacm_ds_set_port_params, 431 usbsacm_ds_set_modem_ctl, 432 usbsacm_ds_get_modem_ctl, 433 usbsacm_ds_break_ctl, 434 NULL, /* NULL if h/w doesn't support loopback */ 435 usbsacm_ds_tx, 436 usbsacm_ds_rx, 437 usbsacm_ds_stop, 438 usbsacm_ds_start, 439 usbsacm_ds_fifo_flush, 440 usbsacm_ds_fifo_drain 441 }; 442 443 /* 444 * baud code -> baud rate (0 means unsupported rate) 445 */ 446 static int usbsacm_speedtab[] = { 447 0, /* B0 */ 448 50, /* B50 */ 449 75, /* B75 */ 450 110, /* B110 */ 451 134, /* B134 */ 452 150, /* B150 */ 453 200, /* B200 */ 454 300, /* B300 */ 455 600, /* B600 */ 456 1200, /* B1200 */ 457 1800, /* B1800 */ 458 2400, /* B2400 */ 459 4800, /* B4800 */ 460 9600, /* B9600 */ 461 19200, /* B19200 */ 462 38400, /* B38400 */ 463 57600, /* B57600 */ 464 76800, /* B76800 */ 465 115200, /* B115200 */ 466 153600, /* B153600 */ 467 230400, /* B230400 */ 468 307200, /* B307200 */ 469 460800, /* B460800 */ 470 921600 /* B921600 */ 471 }; 472 473 474 static uint_t usbsacm_errlevel = USB_LOG_L4; 475 static uint_t usbsacm_errmask = 0xffffffff; 476 static uint_t usbsacm_instance_debug = (uint_t)-1; 477 478 479 /* 480 * usbsacm driver's entry points 481 * ----------------------------- 482 */ 483 /* 484 * Module-wide initialization routine. 485 */ 486 int 487 _init(void) 488 { 489 int error; 490 491 if ((error = mod_install(&modlinkage)) == 0) { 492 493 error = ddi_soft_state_init(&usbsacm_statep, 494 usbser_soft_state_size(), 1); 495 } 496 497 return (error); 498 } 499 500 501 /* 502 * Module-wide tear-down routine. 503 */ 504 int 505 _fini(void) 506 { 507 int error; 508 509 if ((error = mod_remove(&modlinkage)) == 0) { 510 ddi_soft_state_fini(&usbsacm_statep); 511 } 512 513 return (error); 514 } 515 516 517 int 518 _info(struct modinfo *modinfop) 519 { 520 return (mod_info(&modlinkage, modinfop)); 521 } 522 523 524 /* 525 * Device configuration entry points 526 */ 527 static int 528 usbsacm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 529 { 530 return (usbser_attach(dip, cmd, usbsacm_statep, &usbsacm_ds_ops)); 531 } 532 533 534 static int 535 usbsacm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 536 { 537 return (usbser_detach(dip, cmd, usbsacm_statep)); 538 } 539 540 541 int 542 usbsacm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 543 void **result) 544 { 545 return (usbser_getinfo(dip, infocmd, arg, result, usbsacm_statep)); 546 } 547 548 549 static int 550 usbsacm_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) 551 { 552 return (usbser_open(rq, dev, flag, sflag, cr, usbsacm_statep)); 553 } 554 555 /* 556 * usbsacm_ds_detach: 557 * attach device instance, called from GSD attach 558 * initialize state and device, including: 559 * state variables, locks, device node 560 * device registration with system 561 * power management 562 */ 563 static int 564 usbsacm_ds_attach(ds_attach_info_t *aip) 565 { 566 usbsacm_state_t *acmp; 567 568 acmp = (usbsacm_state_t *)kmem_zalloc(sizeof (usbsacm_state_t), 569 KM_SLEEP); 570 acmp->acm_dip = aip->ai_dip; 571 acmp->acm_usb_events = aip->ai_usb_events; 572 acmp->acm_ports = NULL; 573 *aip->ai_hdl = (ds_hdl_t)acmp; 574 575 /* registers usbsacm with the USBA framework */ 576 if (usb_client_attach(acmp->acm_dip, USBDRV_VERSION, 577 0) != USB_SUCCESS) { 578 579 goto fail; 580 } 581 582 /* Get the configuration information of device */ 583 if (usb_get_dev_data(acmp->acm_dip, &acmp->acm_dev_data, 584 USB_PARSE_LVL_CFG, 0) != USB_SUCCESS) { 585 586 goto fail; 587 } 588 acmp->acm_def_ph = acmp->acm_dev_data->dev_default_ph; 589 acmp->acm_dev_state = USB_DEV_ONLINE; 590 mutex_init(&acmp->acm_mutex, NULL, MUTEX_DRIVER, 591 acmp->acm_dev_data->dev_iblock_cookie); 592 593 acmp->acm_lh = usb_alloc_log_hdl(acmp->acm_dip, "usbsacm", 594 &usbsacm_errlevel, &usbsacm_errmask, &usbsacm_instance_debug, 0); 595 596 /* Create power management components */ 597 if (usbsacm_create_pm_components(acmp) != USB_SUCCESS) { 598 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 599 "usbsacm_ds_attach: create pm components failed."); 600 601 goto fail; 602 } 603 604 /* Register to get callbacks for USB events */ 605 if (usb_register_event_cbs(acmp->acm_dip, acmp->acm_usb_events, 0) 606 != USB_SUCCESS) { 607 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 608 "usbsacm_ds_attach: register event callback failed."); 609 610 goto fail; 611 } 612 613 /* 614 * If devices conform to acm spec, driver will attach using class id; 615 * if not, using device id. 616 */ 617 if ((strcmp(DEVI(acmp->acm_dip)->devi_binding_name, 618 "usbif,class2.2") == 0) || 619 ((strcmp(DEVI(acmp->acm_dip)->devi_binding_name, 620 "usb,class2.2.0") == 0))) { 621 622 acmp->acm_compatibility = B_TRUE; 623 } else { 624 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 625 "usbsacm_ds_attach: A nonstandard device is attaching to " 626 "usbsacm driver. This device doesn't conform to " 627 "usb cdc spec."); 628 629 acmp->acm_compatibility = B_FALSE; 630 } 631 632 /* initialize state variables */ 633 if (usbsacm_init_alloc_ports(acmp) != USB_SUCCESS) { 634 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 635 "usbsacm_ds_attach: initialize port structure failed."); 636 637 goto fail; 638 } 639 *aip->ai_port_cnt = acmp->acm_port_cnt; 640 641 /* Get max data size of bulk transfer */ 642 if (usb_pipe_get_max_bulk_transfer_size(acmp->acm_dip, 643 &acmp->acm_xfer_sz) != USB_SUCCESS) { 644 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 645 "usbsacm_ds_attach: get max size of transfer failed."); 646 647 goto fail; 648 } 649 650 return (USB_SUCCESS); 651 fail: 652 usbsacm_cleanup(acmp); 653 654 return (USB_FAILURE); 655 } 656 657 658 /* 659 * usbsacm_ds_detach: 660 * detach device instance, called from GSD detach 661 */ 662 static void 663 usbsacm_ds_detach(ds_hdl_t hdl) 664 { 665 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 666 667 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 668 "usbsacm_ds_detach:"); 669 670 usbsacm_close_pipes(acmp); 671 usbsacm_cleanup(acmp); 672 } 673 674 675 /* 676 * usbsacm_ds_register_cb: 677 * GSD routine call ds_register_cb to register interrupt callbacks 678 * for the given port 679 */ 680 /*ARGSUSED*/ 681 static int 682 usbsacm_ds_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb) 683 { 684 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 685 usbsacm_port_t *acm_port; 686 687 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 688 "usbsacm_ds_register_cb: acmp = 0x%p port_num = %d", 689 (void *)acmp, port_num); 690 691 /* Check if port number is greater than actual port number. */ 692 if (port_num >= acmp->acm_port_cnt) { 693 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 694 "usbsacm_ds_register_cb: port number is wrong."); 695 696 return (USB_FAILURE); 697 } 698 acm_port = &acmp->acm_ports[port_num]; 699 acm_port->acm_cb = *cb; 700 701 return (USB_SUCCESS); 702 } 703 704 705 /* 706 * usbsacm_ds_unregister_cb: 707 * GSD routine call ds_unregister_cb to unregister 708 * interrupt callbacks for the given port 709 */ 710 /*ARGSUSED*/ 711 static void 712 usbsacm_ds_unregister_cb(ds_hdl_t hdl, uint_t port_num) 713 { 714 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 715 usbsacm_port_t *acm_port; 716 717 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 718 "usbsacm_ds_unregister_cb: "); 719 720 if (port_num < acmp->acm_port_cnt) { 721 /* Release callback function */ 722 acm_port = &acmp->acm_ports[port_num]; 723 bzero(&acm_port->acm_cb, sizeof (acm_port->acm_cb)); 724 } 725 } 726 727 728 /* 729 * usbsacm_ds_open_port: 730 * GSD routine call ds_open_port 731 * to open the given port 732 */ 733 /*ARGSUSED*/ 734 static int 735 usbsacm_ds_open_port(ds_hdl_t hdl, uint_t port_num) 736 { 737 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 738 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 739 740 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 741 "usbsacm_ds_open_port: port_num = %d", port_num); 742 743 mutex_enter(&acm_port->acm_port_mutex); 744 /* Check the status of the given port and device */ 745 if ((acmp->acm_dev_state == USB_DEV_DISCONNECTED) || 746 (acm_port->acm_port_state != USBSACM_PORT_CLOSED)) { 747 mutex_exit(&acm_port->acm_port_mutex); 748 749 return (USB_FAILURE); 750 } 751 mutex_exit(&acm_port->acm_port_mutex); 752 753 usbsacm_pm_set_busy(acmp); 754 755 /* open pipes of port */ 756 if (usbsacm_open_port_pipes(acm_port) != USB_SUCCESS) { 757 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 758 "usbsacm_ds_open_port: open pipes failed."); 759 760 return (USB_FAILURE); 761 } 762 763 mutex_enter(&acm_port->acm_port_mutex); 764 /* data receipt */ 765 if (usbsacm_rx_start(acm_port) != USB_SUCCESS) { 766 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 767 "usbsacm_ds_open_port: start receive data failed."); 768 mutex_exit(&acm_port->acm_port_mutex); 769 770 return (USB_FAILURE); 771 } 772 acm_port->acm_port_state = USBSACM_PORT_OPEN; 773 774 mutex_exit(&acm_port->acm_port_mutex); 775 776 return (USB_SUCCESS); 777 } 778 779 780 /* 781 * usbsacm_ds_close_port: 782 * GSD routine call ds_close_port 783 * to close the given port 784 */ 785 /*ARGSUSED*/ 786 static int 787 usbsacm_ds_close_port(ds_hdl_t hdl, uint_t port_num) 788 { 789 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 790 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 791 int rval = USB_SUCCESS; 792 793 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 794 "usbsacm_ds_close_port: acmp = 0x%p", (void *)acmp); 795 796 mutex_enter(&acm_port->acm_port_mutex); 797 acm_port->acm_port_state = USBSACM_PORT_CLOSED; 798 mutex_exit(&acm_port->acm_port_mutex); 799 800 usbsacm_close_port_pipes(acm_port); 801 802 mutex_enter(&acm_port->acm_port_mutex); 803 rval = usbsacm_fifo_flush_locked(acmp, port_num, DS_TX | DS_RX); 804 mutex_exit(&acm_port->acm_port_mutex); 805 806 usbsacm_pm_set_idle(acmp); 807 808 return (rval); 809 } 810 811 812 /* 813 * usbsacm_ds_usb_power: 814 * GSD routine call ds_usb_power 815 * to set power level of the component 816 */ 817 /*ARGSUSED*/ 818 static int 819 usbsacm_ds_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state) 820 { 821 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 822 usbsacm_pm_t *pm = acmp->acm_pm; 823 int rval = USB_SUCCESS; 824 825 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 826 "usbsacm_ds_usb_power: "); 827 828 /* check if pm is NULL */ 829 if (pm == NULL) { 830 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 831 "usbsacm_ds_usb_power: pm is NULL."); 832 833 return (USB_FAILURE); 834 } 835 836 mutex_enter(&acmp->acm_mutex); 837 /* 838 * check if we are transitioning to a legal power level 839 */ 840 if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) { 841 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 842 "usbsacm_ds_usb_power: " 843 "illegal power level %d, pwr_states=%x", 844 level, pm->pm_pwr_states); 845 mutex_exit(&acmp->acm_mutex); 846 847 return (USB_FAILURE); 848 } 849 850 /* 851 * if we are about to raise power and asked to lower power, fail 852 */ 853 if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) { 854 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 855 "usbsacm_ds_usb_power: wrong condition."); 856 mutex_exit(&acmp->acm_mutex); 857 858 return (USB_FAILURE); 859 } 860 861 /* 862 * Set the power status of device by request level. 863 */ 864 switch (level) { 865 case USB_DEV_OS_PWR_OFF: 866 rval = usbsacm_pwrlvl0(acmp); 867 868 break; 869 case USB_DEV_OS_PWR_1: 870 rval = usbsacm_pwrlvl1(acmp); 871 872 break; 873 case USB_DEV_OS_PWR_2: 874 rval = usbsacm_pwrlvl2(acmp); 875 876 break; 877 case USB_DEV_OS_FULL_PWR: 878 rval = usbsacm_pwrlvl3(acmp); 879 /* 880 * If usbser dev_state is DISCONNECTED or SUSPENDED, it shows 881 * that the usb serial device is disconnected/suspended while it 882 * is under power down state, now the device is powered up 883 * before it is reconnected/resumed. xxx_pwrlvl3() will set dev 884 * state to ONLINE, we need to set the dev state back to 885 * DISCONNECTED/SUSPENDED. 886 */ 887 if ((rval == USB_SUCCESS) && 888 ((*new_state == USB_DEV_DISCONNECTED) || 889 (*new_state == USB_DEV_SUSPENDED))) { 890 acmp->acm_dev_state = *new_state; 891 } 892 893 break; 894 } 895 896 *new_state = acmp->acm_dev_state; 897 mutex_exit(&acmp->acm_mutex); 898 899 return (rval); 900 } 901 902 903 /* 904 * usbsacm_ds_suspend: 905 * GSD routine call ds_suspend 906 * during CPR suspend 907 */ 908 static int 909 usbsacm_ds_suspend(ds_hdl_t hdl) 910 { 911 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 912 int state = USB_DEV_SUSPENDED; 913 914 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 915 "usbsacm_ds_suspend: "); 916 /* 917 * If the device is suspended while it is under PWRED_DOWN state, we 918 * need to keep the PWRED_DOWN state so that it could be powered up 919 * later. In the mean while, usbser dev state will be changed to 920 * SUSPENDED state. 921 */ 922 mutex_enter(&acmp->acm_mutex); 923 if (acmp->acm_dev_state != USB_DEV_PWRED_DOWN) { 924 /* set device status to suspend */ 925 acmp->acm_dev_state = USB_DEV_SUSPENDED; 926 } 927 mutex_exit(&acmp->acm_mutex); 928 929 usbsacm_disconnect_pipes(acmp); 930 931 return (state); 932 } 933 934 /* 935 * usbsacm_ds_resume: 936 * GSD routine call ds_resume 937 * during CPR resume 938 */ 939 /*ARGSUSED*/ 940 static int 941 usbsacm_ds_resume(ds_hdl_t hdl) 942 { 943 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 944 int current_state; 945 int ret; 946 947 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 948 "usbsacm_ds_resume: "); 949 950 mutex_enter(&acmp->acm_mutex); 951 current_state = acmp->acm_dev_state; 952 mutex_exit(&acmp->acm_mutex); 953 954 /* restore the status of device */ 955 if (current_state != USB_DEV_ONLINE) { 956 ret = usbsacm_restore_device_state(acmp); 957 } else { 958 ret = USB_DEV_ONLINE; 959 } 960 961 return (ret); 962 } 963 964 /* 965 * usbsacm_ds_disconnect: 966 * GSD routine call ds_disconnect 967 * to disconnect USB device 968 */ 969 static int 970 usbsacm_ds_disconnect(ds_hdl_t hdl) 971 { 972 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 973 int state = USB_DEV_DISCONNECTED; 974 975 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 976 "usbsacm_ds_disconnect: "); 977 978 /* 979 * If the device is disconnected while it is under PWRED_DOWN state, we 980 * need to keep the PWRED_DOWN state so that it could be powered up 981 * later. In the mean while, usbser dev state will be changed to 982 * DISCONNECTED state. 983 */ 984 mutex_enter(&acmp->acm_mutex); 985 if (acmp->acm_dev_state != USB_DEV_PWRED_DOWN) { 986 /* set device status to disconnected */ 987 acmp->acm_dev_state = USB_DEV_DISCONNECTED; 988 } 989 mutex_exit(&acmp->acm_mutex); 990 991 usbsacm_disconnect_pipes(acmp); 992 993 return (state); 994 } 995 996 997 /* 998 * usbsacm_ds_reconnect: 999 * GSD routine call ds_reconnect 1000 * to reconnect USB device 1001 */ 1002 /*ARGSUSED*/ 1003 static int 1004 usbsacm_ds_reconnect(ds_hdl_t hdl) 1005 { 1006 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1007 1008 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 1009 "usbsacm_ds_reconnect: "); 1010 1011 return (usbsacm_restore_device_state(acmp)); 1012 } 1013 1014 1015 /* 1016 * usbsacm_ds_set_port_params: 1017 * GSD routine call ds_set_port_params 1018 * to set one or more port parameters 1019 */ 1020 /*ARGSUSED*/ 1021 static int 1022 usbsacm_ds_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp) 1023 { 1024 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1025 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1026 int i; 1027 uint_t ui; 1028 ds_port_param_entry_t *pe; 1029 usb_cdc_line_coding_t lc; 1030 int ret; 1031 1032 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1033 "usbsacm_ds_set_port_params: acmp = 0x%p", (void *)acmp); 1034 1035 mutex_enter(&acm_port->acm_port_mutex); 1036 /* 1037 * If device conform to acm spec, check if it support to set port param. 1038 */ 1039 if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SERIAL_LINE) == 0 && 1040 acmp->acm_compatibility == B_TRUE) { 1041 1042 mutex_exit(&acm_port->acm_port_mutex); 1043 USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh, 1044 "usbsacm_ds_set_port_params: " 1045 "don't support Set_Line_Coding."); 1046 1047 return (USB_FAILURE); 1048 } 1049 1050 lc = acm_port->acm_line_coding; 1051 mutex_exit(&acm_port->acm_port_mutex); 1052 pe = tp->tp_entries; 1053 /* Get parameter information from ds_port_params_t */ 1054 for (i = 0; i < tp->tp_cnt; i++, pe++) { 1055 switch (pe->param) { 1056 case DS_PARAM_BAUD: 1057 /* Data terminal rate, in bits per second. */ 1058 ui = pe->val.ui; 1059 1060 /* if we don't support this speed, return USB_FAILURE */ 1061 if ((ui >= NELEM(usbsacm_speedtab)) || 1062 ((ui > 0) && (usbsacm_speedtab[ui] == 0))) { 1063 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 1064 "usbsacm_ds_set_port_params: " 1065 " error baud rate"); 1066 1067 return (USB_FAILURE); 1068 } 1069 lc.dwDTERate = LE_32(usbsacm_speedtab[ui]); 1070 1071 break; 1072 case DS_PARAM_PARITY: 1073 /* Parity Type */ 1074 if (pe->val.ui & PARENB) { 1075 if (pe->val.ui & PARODD) { 1076 lc.bParityType = USB_CDC_PARITY_ODD; 1077 } else { 1078 lc.bParityType = USB_CDC_PARITY_EVEN; 1079 } 1080 } else { 1081 lc.bParityType = USB_CDC_PARITY_NO; 1082 } 1083 1084 break; 1085 case DS_PARAM_STOPB: 1086 /* Stop bit */ 1087 if (pe->val.ui & CSTOPB) { 1088 lc.bCharFormat = USB_CDC_STOP_BITS_2; 1089 } else { 1090 lc.bCharFormat = USB_CDC_STOP_BITS_1; 1091 } 1092 1093 break; 1094 case DS_PARAM_CHARSZ: 1095 /* Data Bits */ 1096 switch (pe->val.ui) { 1097 case CS5: 1098 lc.bDataBits = 5; 1099 break; 1100 case CS6: 1101 lc.bDataBits = 6; 1102 break; 1103 case CS7: 1104 lc.bDataBits = 7; 1105 break; 1106 case CS8: 1107 default: 1108 lc.bDataBits = 8; 1109 break; 1110 } 1111 1112 break; 1113 default: 1114 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 1115 "usbsacm_ds_set_port_params: " 1116 "parameter 0x%x isn't supported", 1117 pe->param); 1118 1119 break; 1120 } 1121 } 1122 1123 if ((ret = usbsacm_set_line_coding(acm_port, &lc)) == USB_SUCCESS) { 1124 mutex_enter(&acm_port->acm_port_mutex); 1125 acm_port->acm_line_coding = lc; 1126 mutex_exit(&acm_port->acm_port_mutex); 1127 } 1128 1129 /* 1130 * If device don't conform to acm spec, return success directly. 1131 */ 1132 if (acmp->acm_compatibility != B_TRUE) { 1133 ret = USB_SUCCESS; 1134 } 1135 1136 return (ret); 1137 } 1138 1139 1140 /* 1141 * usbsacm_ds_set_modem_ctl: 1142 * GSD routine call ds_set_modem_ctl 1143 * to set modem control of the given port 1144 */ 1145 /*ARGSUSED*/ 1146 static int 1147 usbsacm_ds_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val) 1148 { 1149 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1150 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1151 uint8_t new_mctl; 1152 int ret; 1153 1154 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1155 "usbsacm_ds_set_modem_ctl: mask = 0x%x val = 0x%x", 1156 mask, val); 1157 1158 mutex_enter(&acm_port->acm_port_mutex); 1159 /* 1160 * If device conform to acm spec, check if it support to set modem 1161 * controls. 1162 */ 1163 if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SERIAL_LINE) == 0 && 1164 acmp->acm_compatibility == B_TRUE) { 1165 1166 mutex_exit(&acm_port->acm_port_mutex); 1167 USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh, 1168 "usbsacm_ds_set_modem_ctl: " 1169 "don't support Set_Control_Line_State."); 1170 1171 return (USB_FAILURE); 1172 } 1173 1174 new_mctl = acm_port->acm_mctlout; 1175 mutex_exit(&acm_port->acm_port_mutex); 1176 1177 usbsacm_mctl2reg(mask, val, &new_mctl); 1178 1179 if ((acmp->acm_compatibility == B_FALSE) || ((ret = 1180 usbsacm_req_write(acm_port, USB_CDC_REQ_SET_CONTROL_LINE_STATE, 1181 new_mctl, NULL)) == USB_SUCCESS)) { 1182 mutex_enter(&acm_port->acm_port_mutex); 1183 acm_port->acm_mctlout = new_mctl; 1184 mutex_exit(&acm_port->acm_port_mutex); 1185 } 1186 1187 /* 1188 * If device don't conform to acm spec, return success directly. 1189 */ 1190 if (acmp->acm_compatibility != B_TRUE) { 1191 ret = USB_SUCCESS; 1192 } 1193 1194 return (ret); 1195 } 1196 1197 1198 /* 1199 * usbsacm_ds_get_modem_ctl: 1200 * GSD routine call ds_get_modem_ctl 1201 * to get modem control/status of the given port 1202 */ 1203 /*ARGSUSED*/ 1204 static int 1205 usbsacm_ds_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp) 1206 { 1207 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1208 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1209 1210 mutex_enter(&acm_port->acm_port_mutex); 1211 *valp = usbsacm_reg2mctl(acm_port->acm_mctlout) & mask; 1212 /* 1213 * If device conform to acm spec, polling function can modify the value 1214 * of acm_mctlin; else set to default value. 1215 */ 1216 if (acmp->acm_compatibility) { 1217 *valp |= usbsacm_reg2mctl(acm_port->acm_mctlin) & mask; 1218 *valp |= (mask & (TIOCM_CD | TIOCM_CTS)); 1219 } else { 1220 *valp |= (mask & (TIOCM_CD | TIOCM_CTS | TIOCM_DSR | TIOCM_RI)); 1221 } 1222 mutex_exit(&acm_port->acm_port_mutex); 1223 1224 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1225 "usbsacm_ds_get_modem_ctl: val = 0x%x", *valp); 1226 1227 return (USB_SUCCESS); 1228 } 1229 1230 1231 /* 1232 * usbsacm_ds_tx: 1233 * GSD routine call ds_break_ctl 1234 * to set/clear break 1235 */ 1236 /*ARGSUSED*/ 1237 static int 1238 usbsacm_ds_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl) 1239 { 1240 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1241 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1242 1243 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1244 "usbsacm_ds_break_ctl: "); 1245 1246 mutex_enter(&acm_port->acm_port_mutex); 1247 /* 1248 * If device conform to acm spec, check if it support to send break. 1249 */ 1250 if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SEND_BREAK) == 0 && 1251 acmp->acm_compatibility == B_TRUE) { 1252 1253 mutex_exit(&acm_port->acm_port_mutex); 1254 USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh, 1255 "usbsacm_ds_break_ctl: don't support send break."); 1256 1257 return (USB_FAILURE); 1258 } 1259 mutex_exit(&acm_port->acm_port_mutex); 1260 1261 return (usbsacm_req_write(acm_port, USB_CDC_REQ_SEND_BREAK, 1262 ((ctl == DS_ON) ? 0xffff : 0), NULL)); 1263 } 1264 1265 1266 /* 1267 * usbsacm_ds_tx: 1268 * GSD routine call ds_tx 1269 * to data transmit 1270 */ 1271 /*ARGSUSED*/ 1272 static int 1273 usbsacm_ds_tx(ds_hdl_t hdl, uint_t port_num, mblk_t *mp) 1274 { 1275 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1276 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1277 1278 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1279 "usbsacm_ds_tx: mp = 0x%p acmp = 0x%p", (void *)mp, (void *)acmp); 1280 1281 /* sanity checks */ 1282 if (mp == NULL) { 1283 1284 return (USB_SUCCESS); 1285 } 1286 if (MBLKL(mp) < 1) { 1287 freemsg(mp); 1288 1289 return (USB_SUCCESS); 1290 } 1291 1292 mutex_enter(&acm_port->acm_port_mutex); 1293 /* put mblk to tail of mblk chain */ 1294 usbsacm_put_tail(&acm_port->acm_tx_mp, mp); 1295 usbsacm_tx_start(acm_port); 1296 mutex_exit(&acm_port->acm_port_mutex); 1297 1298 return (USB_SUCCESS); 1299 } 1300 1301 1302 /* 1303 * usbsacm_ds_rx: 1304 * GSD routine call ds_rx; 1305 * to data receipt 1306 */ 1307 /*ARGSUSED*/ 1308 static mblk_t * 1309 usbsacm_ds_rx(ds_hdl_t hdl, uint_t port_num) 1310 { 1311 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1312 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1313 mblk_t *mp; 1314 1315 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1316 "usbsacm_ds_rx: acmp = 0x%p", (void *)acmp); 1317 1318 mutex_enter(&acm_port->acm_port_mutex); 1319 1320 mp = acm_port->acm_rx_mp; 1321 acm_port->acm_rx_mp = NULL; 1322 mutex_exit(&acm_port->acm_port_mutex); 1323 1324 return (mp); 1325 } 1326 1327 1328 /* 1329 * usbsacm_ds_stop: 1330 * GSD routine call ds_stop; 1331 * but acm spec don't define this function 1332 */ 1333 /*ARGSUSED*/ 1334 static void 1335 usbsacm_ds_stop(ds_hdl_t hdl, uint_t port_num, int dir) 1336 { 1337 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1338 1339 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 1340 "usbsacm_ds_stop: don't support!"); 1341 } 1342 1343 1344 /* 1345 * usbsacm_ds_start: 1346 * GSD routine call ds_start; 1347 * but acm spec don't define this function 1348 */ 1349 /*ARGSUSED*/ 1350 static void 1351 usbsacm_ds_start(ds_hdl_t hdl, uint_t port_num, int dir) 1352 { 1353 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1354 1355 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 1356 "usbsacm_ds_start: don't support!"); 1357 } 1358 1359 1360 /* 1361 * usbsacm_ds_fifo_flush: 1362 * GSD routine call ds_fifo_flush 1363 * to flush FIFOs 1364 */ 1365 /*ARGSUSED*/ 1366 static int 1367 usbsacm_ds_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir) 1368 { 1369 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1370 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1371 int ret = USB_SUCCESS; 1372 1373 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1374 "usbsacm_ds_fifo_flush: "); 1375 1376 mutex_enter(&acm_port->acm_port_mutex); 1377 ret = usbsacm_fifo_flush_locked(acmp, port_num, dir); 1378 mutex_exit(&acm_port->acm_port_mutex); 1379 1380 return (ret); 1381 } 1382 1383 1384 /* 1385 * usbsacm_ds_fifo_drain: 1386 * GSD routine call ds_fifo_drain 1387 * to wait until empty output FIFO 1388 */ 1389 /*ARGSUSED*/ 1390 static int 1391 usbsacm_ds_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout) 1392 { 1393 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1394 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1395 int rval = USB_SUCCESS; 1396 1397 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 1398 "usbsacm_ds_fifo_drain: "); 1399 1400 mutex_enter(&acm_port->acm_port_mutex); 1401 ASSERT(acm_port->acm_port_state == USBSACM_PORT_OPEN); 1402 1403 if (usbsacm_wait_tx_drain(acm_port, timeout) != USB_SUCCESS) { 1404 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 1405 "usbsacm_ds_fifo_drain: fifo drain failed."); 1406 mutex_exit(&acm_port->acm_port_mutex); 1407 1408 return (USB_FAILURE); 1409 } 1410 1411 mutex_exit(&acm_port->acm_port_mutex); 1412 1413 return (rval); 1414 } 1415 1416 1417 /* 1418 * usbsacm_fifo_flush_locked: 1419 * flush FIFOs of the given ports 1420 */ 1421 /*ARGSUSED*/ 1422 static int 1423 usbsacm_fifo_flush_locked(usbsacm_state_t *acmp, uint_t port_num, int dir) 1424 { 1425 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1426 1427 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 1428 "usbsacm_fifo_flush_locked: "); 1429 1430 /* flush transmit FIFO if DS_TX is set */ 1431 if ((dir & DS_TX) && acm_port->acm_tx_mp) { 1432 freemsg(acm_port->acm_tx_mp); 1433 acm_port->acm_tx_mp = NULL; 1434 } 1435 /* flush received FIFO if DS_RX is set */ 1436 if ((dir & DS_RX) && acm_port->acm_rx_mp) { 1437 freemsg(acm_port->acm_rx_mp); 1438 acm_port->acm_rx_mp = NULL; 1439 } 1440 1441 return (USB_SUCCESS); 1442 } 1443 1444 1445 /* 1446 * usbsacm_get_bulk_pipe_number: 1447 * Calculate the number of bulk in or out pipes in current device. 1448 */ 1449 static int 1450 usbsacm_get_bulk_pipe_number(usbsacm_state_t *acmp, uint_t dir) 1451 { 1452 int count = 0; 1453 int i, skip; 1454 usb_if_data_t *cur_if; 1455 int ep_num; 1456 int if_num; 1457 int if_no; 1458 1459 USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh, 1460 "usbsacm_get_bulk_pipe_number: "); 1461 1462 cur_if = acmp->acm_dev_data->dev_curr_cfg->cfg_if; 1463 if_num = acmp->acm_dev_data->dev_curr_cfg->cfg_n_if; 1464 if_no = acmp->acm_dev_data->dev_curr_if; 1465 1466 /* search each interface which have bulk endpoint */ 1467 for (i = 0; i < if_num; i++) { 1468 ep_num = cur_if->if_alt->altif_n_ep; 1469 1470 /* 1471 * search endpoints in current interface, 1472 * which type is input parameter 'dir' 1473 */ 1474 for (skip = 0; skip < ep_num; skip++) { 1475 if (usb_lookup_ep_data(acmp->acm_dip, 1476 acmp->acm_dev_data, if_no + i, 0, skip, 1477 USB_EP_ATTR_BULK, dir) == NULL) { 1478 1479 /* 1480 * If not found, skip the internal loop 1481 * and search the next interface. 1482 */ 1483 break; 1484 } 1485 count++; 1486 } 1487 1488 cur_if++; 1489 } 1490 1491 return (count); 1492 } 1493 1494 1495 /* 1496 * port management 1497 * --------------- 1498 * initialize, release port. 1499 * 1500 * 1501 * usbsacm_init_ports_status: 1502 * Initialize the port status for the current device. 1503 */ 1504 static int 1505 usbsacm_init_ports_status(usbsacm_state_t *acmp) 1506 { 1507 usbsacm_port_t *cur_port; 1508 int i, skip; 1509 int if_num; 1510 int intr_if_no = 0; 1511 int ep_num; 1512 usb_if_data_t *cur_if; 1513 1514 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 1515 "usbsacm_init_ports_status: acmp = 0x%p", (void *)acmp); 1516 1517 /* Initialize the port status to default value */ 1518 for (i = 0; i < acmp->acm_port_cnt; i++) { 1519 cur_port = &acmp->acm_ports[i]; 1520 1521 cv_init(&cur_port->acm_tx_cv, NULL, CV_DRIVER, NULL); 1522 1523 cur_port->acm_port_state = USBSACM_PORT_CLOSED; 1524 1525 cur_port->acm_line_coding.dwDTERate = LE_32((uint32_t)9600); 1526 cur_port->acm_line_coding.bCharFormat = 0; 1527 cur_port->acm_line_coding.bParityType = USB_CDC_PARITY_NO; 1528 cur_port->acm_line_coding.bDataBits = 8; 1529 cur_port->acm_device = acmp; 1530 mutex_init(&cur_port->acm_port_mutex, NULL, MUTEX_DRIVER, 1531 acmp->acm_dev_data->dev_iblock_cookie); 1532 } 1533 1534 /* 1535 * If device conform to cdc acm spec, parse function descriptors. 1536 */ 1537 if (acmp->acm_compatibility == B_TRUE) { 1538 1539 if (usbsacm_get_descriptors(acmp) != USB_SUCCESS) { 1540 1541 return (USB_FAILURE); 1542 } 1543 1544 return (USB_SUCCESS); 1545 } 1546 1547 /* 1548 * If device don't conform to spec, search pairs of bulk in/out 1549 * endpoints and fill port structure. 1550 */ 1551 cur_if = acmp->acm_dev_data->dev_curr_cfg->cfg_if; 1552 if_num = acmp->acm_dev_data->dev_curr_cfg->cfg_n_if; 1553 cur_port = acmp->acm_ports; 1554 1555 /* search each interface which have bulk in and out */ 1556 for (i = 0; i < if_num; i++) { 1557 ep_num = cur_if->if_alt->altif_n_ep; 1558 1559 for (skip = 0; skip < ep_num; skip++) { 1560 1561 /* search interrupt pipe. */ 1562 if ((usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1563 i, 0, skip, USB_EP_ATTR_INTR, USB_EP_DIR_IN) != NULL)) { 1564 1565 intr_if_no = i; 1566 } 1567 1568 /* search pair of bulk in/out endpoints. */ 1569 if ((usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1570 i, 0, skip, USB_EP_ATTR_BULK, USB_EP_DIR_IN) == NULL) || 1571 (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1572 i, 0, skip, USB_EP_ATTR_BULK, USB_EP_DIR_OUT) == NULL)) { 1573 1574 continue; 1575 } 1576 1577 cur_port->acm_data_if_no = i; 1578 cur_port->acm_ctrl_if_no = intr_if_no; 1579 cur_port->acm_data_port_no = skip; 1580 cur_port++; 1581 intr_if_no = 0; 1582 } 1583 1584 cur_if++; 1585 } 1586 1587 return (USB_SUCCESS); 1588 } 1589 1590 1591 /* 1592 * usbsacm_init_alloc_ports: 1593 * Allocate memory and initialize the port state for the current device. 1594 */ 1595 static int 1596 usbsacm_init_alloc_ports(usbsacm_state_t *acmp) 1597 { 1598 int rval = USB_SUCCESS; 1599 int count_in = 0, count_out = 0; 1600 1601 if (acmp->acm_compatibility) { 1602 acmp->acm_port_cnt = 1; 1603 } else { 1604 /* Calculate the number of the bulk in/out endpoints */ 1605 count_in = usbsacm_get_bulk_pipe_number(acmp, USB_EP_DIR_IN); 1606 count_out = usbsacm_get_bulk_pipe_number(acmp, USB_EP_DIR_OUT); 1607 1608 USB_DPRINTF_L3(PRINT_MASK_OPEN, acmp->acm_lh, 1609 "usbsacm_init_alloc_ports: count_in = %d, count_out = %d", 1610 count_in, count_out); 1611 1612 acmp->acm_port_cnt = min(count_in, count_out); 1613 } 1614 1615 /* return if not found any pair of bulk in/out endpoint. */ 1616 if (acmp->acm_port_cnt == 0) { 1617 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 1618 "usbsacm_init_alloc_ports: port count is zero."); 1619 1620 return (USB_FAILURE); 1621 } 1622 1623 /* allocate memory for ports */ 1624 acmp->acm_ports = (usbsacm_port_t *)kmem_zalloc(acmp->acm_port_cnt * 1625 sizeof (usbsacm_port_t), KM_SLEEP); 1626 if (acmp->acm_ports == NULL) { 1627 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 1628 "usbsacm_init_alloc_ports: allocate memory failed."); 1629 1630 return (USB_FAILURE); 1631 } 1632 1633 /* fill the status of port structure. */ 1634 rval = usbsacm_init_ports_status(acmp); 1635 if (rval != USB_SUCCESS) { 1636 usbsacm_free_ports(acmp); 1637 } 1638 1639 return (rval); 1640 } 1641 1642 1643 /* 1644 * usbsacm_free_ports: 1645 * Release ports and deallocate memory. 1646 */ 1647 static void 1648 usbsacm_free_ports(usbsacm_state_t *acmp) 1649 { 1650 int i; 1651 1652 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 1653 "usbsacm_free_ports: "); 1654 1655 /* Release memory and data structure for each port */ 1656 for (i = 0; i < acmp->acm_port_cnt; i++) { 1657 cv_destroy(&acmp->acm_ports[i].acm_tx_cv); 1658 mutex_destroy(&acmp->acm_ports[i].acm_port_mutex); 1659 } 1660 kmem_free((caddr_t)acmp->acm_ports, sizeof (usbsacm_port_t) * 1661 acmp->acm_port_cnt); 1662 acmp->acm_ports = NULL; 1663 } 1664 1665 1666 /* 1667 * usbsacm_get_descriptors: 1668 * analysis functional descriptors of acm device 1669 */ 1670 static int 1671 usbsacm_get_descriptors(usbsacm_state_t *acmp) 1672 { 1673 int i; 1674 usb_cfg_data_t *cfg; 1675 usb_alt_if_data_t *altif; 1676 usb_cvs_data_t *cvs; 1677 int mgmt_cap = 0; 1678 int master_if = -1, slave_if = -1; 1679 usbsacm_port_t *acm_port = acmp->acm_ports; 1680 1681 USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh, 1682 "usbsacm_get_descriptors: "); 1683 1684 cfg = acmp->acm_dev_data->dev_curr_cfg; 1685 /* set default control and data interface */ 1686 acm_port->acm_ctrl_if_no = acm_port->acm_data_if_no = 0; 1687 1688 /* get current interfaces */ 1689 acm_port->acm_ctrl_if_no = acmp->acm_dev_data->dev_curr_if; 1690 if (cfg->cfg_if[acm_port->acm_ctrl_if_no].if_n_alt == 0) { 1691 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1692 "usbsacm_get_descriptors: elements in if_alt is %d", 1693 cfg->cfg_if[acm_port->acm_ctrl_if_no].if_n_alt); 1694 1695 return (USB_FAILURE); 1696 } 1697 1698 altif = &cfg->cfg_if[acm_port->acm_ctrl_if_no].if_alt[0]; 1699 1700 /* 1701 * Based on CDC specification, ACM devices usually include the 1702 * following function descriptors: Header, ACM, Union and Call 1703 * Management function descriptors. This loop search tree data 1704 * structure for each acm class descriptor. 1705 */ 1706 for (i = 0; i < altif->altif_n_cvs; i++) { 1707 1708 cvs = &altif->altif_cvs[i]; 1709 1710 if ((cvs->cvs_buf == NULL) || 1711 (cvs->cvs_buf[1] != USB_CDC_CS_INTERFACE)) { 1712 continue; 1713 } 1714 1715 switch (cvs->cvs_buf[2]) { 1716 case USB_CDC_DESCR_TYPE_CALL_MANAGEMENT: 1717 /* parse call management functional descriptor. */ 1718 if (cvs->cvs_buf_len >= 5) { 1719 mgmt_cap = cvs->cvs_buf[3]; 1720 acm_port->acm_data_if_no = cvs->cvs_buf[4]; 1721 } 1722 break; 1723 case USB_CDC_DESCR_TYPE_ACM: 1724 /* parse ACM functional descriptor. */ 1725 if (cvs->cvs_buf_len >= 4) { 1726 acm_port->acm_cap = cvs->cvs_buf[3]; 1727 } 1728 break; 1729 case USB_CDC_DESCR_TYPE_UNION: 1730 /* parse Union functional descriptor. */ 1731 if (cvs->cvs_buf_len >= 5) { 1732 master_if = cvs->cvs_buf[3]; 1733 slave_if = cvs->cvs_buf[4]; 1734 } 1735 break; 1736 default: 1737 break; 1738 } 1739 } 1740 1741 /* For usb acm devices, it must satisfy the following options. */ 1742 if (cfg->cfg_n_if < 2) { 1743 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1744 "usbsacm_get_descriptors: # of interfaces %d < 2", 1745 cfg->cfg_n_if); 1746 1747 return (USB_FAILURE); 1748 } 1749 1750 if (acm_port->acm_data_if_no == 0 && 1751 slave_if != acm_port->acm_data_if_no) { 1752 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1753 "usbsacm_get_descriptors: Device hasn't call management " 1754 "descriptor and use Union Descriptor."); 1755 1756 acm_port->acm_data_if_no = slave_if; 1757 } 1758 1759 if ((master_if != acm_port->acm_ctrl_if_no) || 1760 (slave_if != acm_port->acm_data_if_no)) { 1761 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1762 "usbsacm_get_descriptors: control interface or " 1763 "data interface don't match."); 1764 1765 return (USB_FAILURE); 1766 } 1767 1768 /* 1769 * We usually need both call and data capabilities, but 1770 * some devices, such as Nokia mobile phones, don't provide 1771 * call management descriptor, so we just give a warning 1772 * message. 1773 */ 1774 if (((mgmt_cap & USB_CDC_CALL_MGMT_CAP_CALL_MGMT) == 0) || 1775 ((mgmt_cap & USB_CDC_CALL_MGMT_CAP_DATA_INTERFACE) == 0)) { 1776 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1777 "usbsacm_get_descriptors: " 1778 "insufficient mgmt capabilities %x", 1779 mgmt_cap); 1780 } 1781 1782 if ((acm_port->acm_ctrl_if_no >= cfg->cfg_n_if) || 1783 (acm_port->acm_data_if_no >= cfg->cfg_n_if)) { 1784 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1785 "usbsacm_get_descriptors: control interface %d or " 1786 "data interface %d out of range.", 1787 acm_port->acm_ctrl_if_no, acm_port->acm_data_if_no); 1788 1789 return (USB_FAILURE); 1790 } 1791 1792 /* control interface must have interrupt endpoint */ 1793 if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1794 acm_port->acm_ctrl_if_no, 0, 0, USB_EP_ATTR_INTR, 1795 USB_EP_DIR_IN) == NULL) { 1796 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1797 "usbsacm_get_descriptors: " 1798 "ctrl interface %d has no interrupt endpoint", 1799 acm_port->acm_data_if_no); 1800 1801 return (USB_FAILURE); 1802 } 1803 1804 /* data interface must have bulk in and out */ 1805 if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1806 acm_port->acm_data_if_no, 0, 0, USB_EP_ATTR_BULK, 1807 USB_EP_DIR_IN) == NULL) { 1808 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1809 "usbsacm_get_descriptors: " 1810 "data interface %d has no bulk in endpoint", 1811 acm_port->acm_data_if_no); 1812 1813 return (USB_FAILURE); 1814 } 1815 if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1816 acm_port->acm_data_if_no, 0, 0, USB_EP_ATTR_BULK, 1817 USB_EP_DIR_OUT) == NULL) { 1818 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1819 "usbsacm_get_descriptors: " 1820 "data interface %d has no bulk out endpoint", 1821 acm_port->acm_data_if_no); 1822 1823 return (USB_FAILURE); 1824 } 1825 1826 return (USB_SUCCESS); 1827 } 1828 1829 1830 /* 1831 * usbsacm_cleanup: 1832 * Release resources of current device during detach. 1833 */ 1834 static void 1835 usbsacm_cleanup(usbsacm_state_t *acmp) 1836 { 1837 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 1838 "usbsacm_cleanup: "); 1839 1840 if (acmp != NULL) { 1841 /* free ports */ 1842 if (acmp->acm_ports != NULL) { 1843 usbsacm_free_ports(acmp); 1844 } 1845 1846 /* unregister callback function */ 1847 if (acmp->acm_usb_events != NULL) { 1848 usb_unregister_event_cbs(acmp->acm_dip, 1849 acmp->acm_usb_events); 1850 } 1851 1852 /* destroy power management components */ 1853 if (acmp->acm_pm != NULL) { 1854 usbsacm_destroy_pm_components(acmp); 1855 } 1856 1857 /* free description of device tree. */ 1858 if (acmp->acm_def_ph != NULL) { 1859 mutex_destroy(&acmp->acm_mutex); 1860 1861 usb_free_descr_tree(acmp->acm_dip, acmp->acm_dev_data); 1862 acmp->acm_def_ph = NULL; 1863 } 1864 1865 if (acmp->acm_lh != NULL) { 1866 usb_free_log_hdl(acmp->acm_lh); 1867 acmp->acm_lh = NULL; 1868 } 1869 1870 /* detach client device */ 1871 if (acmp->acm_dev_data != NULL) { 1872 usb_client_detach(acmp->acm_dip, acmp->acm_dev_data); 1873 } 1874 1875 kmem_free((caddr_t)acmp, sizeof (usbsacm_state_t)); 1876 } 1877 } 1878 1879 1880 /* 1881 * usbsacm_restore_device_state: 1882 * restore device state after CPR resume or reconnect 1883 */ 1884 static int 1885 usbsacm_restore_device_state(usbsacm_state_t *acmp) 1886 { 1887 int state; 1888 1889 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1890 "usbsacm_restore_device_state: "); 1891 1892 mutex_enter(&acmp->acm_mutex); 1893 state = acmp->acm_dev_state; 1894 mutex_exit(&acmp->acm_mutex); 1895 1896 /* Check device status */ 1897 if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) { 1898 1899 return (state); 1900 } 1901 1902 /* Check if we are talking to the same device */ 1903 if (usb_check_same_device(acmp->acm_dip, acmp->acm_lh, USB_LOG_L0, 1904 -1, USB_CHK_ALL, NULL) != USB_SUCCESS) { 1905 mutex_enter(&acmp->acm_mutex); 1906 state = acmp->acm_dev_state = USB_DEV_DISCONNECTED; 1907 mutex_exit(&acmp->acm_mutex); 1908 1909 return (state); 1910 } 1911 1912 if (state == USB_DEV_DISCONNECTED) { 1913 USB_DPRINTF_L1(PRINT_MASK_ALL, acmp->acm_lh, 1914 "usbsacm_restore_device_state: Device has been reconnected " 1915 "but data may have been lost"); 1916 } 1917 1918 /* reconnect pipes */ 1919 if (usbsacm_reconnect_pipes(acmp) != USB_SUCCESS) { 1920 1921 return (state); 1922 } 1923 1924 /* 1925 * init device state 1926 */ 1927 mutex_enter(&acmp->acm_mutex); 1928 state = acmp->acm_dev_state = USB_DEV_ONLINE; 1929 mutex_exit(&acmp->acm_mutex); 1930 1931 if ((usbsacm_restore_port_state(acmp) != USB_SUCCESS)) { 1932 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1933 "usbsacm_restore_device_state: failed"); 1934 } 1935 1936 return (state); 1937 } 1938 1939 1940 /* 1941 * usbsacm_restore_port_state: 1942 * restore ports state after CPR resume or reconnect 1943 */ 1944 static int 1945 usbsacm_restore_port_state(usbsacm_state_t *acmp) 1946 { 1947 int i, ret = USB_SUCCESS; 1948 usbsacm_port_t *cur_port; 1949 1950 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1951 "usbsacm_restore_port_state: "); 1952 1953 /* restore status of all ports */ 1954 for (i = 0; i < acmp->acm_port_cnt; i++) { 1955 cur_port = &acmp->acm_ports[i]; 1956 mutex_enter(&cur_port->acm_port_mutex); 1957 if (cur_port->acm_port_state != USBSACM_PORT_OPEN) { 1958 mutex_exit(&cur_port->acm_port_mutex); 1959 1960 continue; 1961 } 1962 mutex_exit(&cur_port->acm_port_mutex); 1963 1964 if ((ret = usbsacm_set_line_coding(cur_port, 1965 &cur_port->acm_line_coding)) != USB_SUCCESS) { 1966 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1967 "usbsacm_restore_port_state: failed."); 1968 } 1969 } 1970 1971 return (ret); 1972 } 1973 1974 1975 /* 1976 * pipe management 1977 * --------------- 1978 * 1979 * 1980 * usbsacm_open_port_pipes: 1981 * Open pipes of one port and set port structure; 1982 * Each port includes three pipes: bulk in, bulk out and interrupt. 1983 */ 1984 static int 1985 usbsacm_open_port_pipes(usbsacm_port_t *acm_port) 1986 { 1987 int rval = USB_SUCCESS; 1988 usbsacm_state_t *acmp = acm_port->acm_device; 1989 usb_ep_data_t *in_data, *out_data, *intr_pipe; 1990 usb_pipe_policy_t policy; 1991 1992 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 1993 "usbsacm_open_port_pipes: acmp = 0x%p", (void *)acmp); 1994 1995 /* Get bulk and interrupt endpoint data */ 1996 intr_pipe = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1997 acm_port->acm_ctrl_if_no, 0, 0, 1998 USB_EP_ATTR_INTR, USB_EP_DIR_IN); 1999 in_data = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 2000 acm_port->acm_data_if_no, 0, acm_port->acm_data_port_no, 2001 USB_EP_ATTR_BULK, USB_EP_DIR_IN); 2002 out_data = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 2003 acm_port->acm_data_if_no, 0, acm_port->acm_data_port_no, 2004 USB_EP_ATTR_BULK, USB_EP_DIR_OUT); 2005 2006 /* Bulk in and out must exist meanwhile. */ 2007 if ((in_data == NULL) || (out_data == NULL)) { 2008 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2009 "usbsacm_open_port_pipes: look up bulk pipe failed in " 2010 "interface %d port %d", 2011 acm_port->acm_data_if_no, acm_port->acm_data_port_no); 2012 2013 return (USB_FAILURE); 2014 } 2015 2016 /* 2017 * If device conform to acm spec, it must have an interrupt pipe 2018 * for this port. 2019 */ 2020 if (acmp->acm_compatibility == B_TRUE && intr_pipe == NULL) { 2021 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2022 "usbsacm_open_port_pipes: look up interrupt pipe failed in " 2023 "interface %d", acm_port->acm_ctrl_if_no); 2024 2025 return (USB_FAILURE); 2026 } 2027 2028 policy.pp_max_async_reqs = 2; 2029 2030 /* Open bulk in endpoint */ 2031 if (usb_pipe_open(acmp->acm_dip, &in_data->ep_descr, &policy, 2032 USB_FLAGS_SLEEP, &acm_port->acm_bulkin_ph) != USB_SUCCESS) { 2033 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2034 "usbsacm_open_port_pipes: open bulkin pipe failed!"); 2035 2036 return (USB_FAILURE); 2037 } 2038 2039 /* Open bulk out endpoint */ 2040 if (usb_pipe_open(acmp->acm_dip, &out_data->ep_descr, &policy, 2041 USB_FLAGS_SLEEP, &acm_port->acm_bulkout_ph) != USB_SUCCESS) { 2042 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2043 "usbsacm_open_port_pipes: open bulkout pipe failed!"); 2044 2045 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph, 2046 USB_FLAGS_SLEEP, NULL, NULL); 2047 2048 return (USB_FAILURE); 2049 } 2050 2051 /* Open interrupt endpoint if found. */ 2052 if (intr_pipe != NULL) { 2053 2054 if (usb_pipe_open(acmp->acm_dip, &intr_pipe->ep_descr, &policy, 2055 USB_FLAGS_SLEEP, &acm_port->acm_intr_ph) != USB_SUCCESS) { 2056 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2057 "usbsacm_open_port_pipes: " 2058 "open control pipe failed"); 2059 2060 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph, 2061 USB_FLAGS_SLEEP, NULL, NULL); 2062 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkout_ph, 2063 USB_FLAGS_SLEEP, NULL, NULL); 2064 2065 return (USB_FAILURE); 2066 } 2067 } 2068 2069 /* initialize the port structure. */ 2070 mutex_enter(&acm_port->acm_port_mutex); 2071 acm_port->acm_bulkin_size = in_data->ep_descr.wMaxPacketSize; 2072 acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE; 2073 acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE; 2074 if (acm_port->acm_intr_ph != NULL) { 2075 acm_port->acm_intr_state = USBSACM_PIPE_IDLE; 2076 acm_port->acm_intr_ep_descr = intr_pipe->ep_descr; 2077 } 2078 mutex_exit(&acm_port->acm_port_mutex); 2079 2080 if (acm_port->acm_intr_ph != NULL) { 2081 2082 usbsacm_pipe_start_polling(acm_port); 2083 } 2084 2085 return (rval); 2086 } 2087 2088 2089 /* 2090 * usbsacm_close_port_pipes: 2091 * Close pipes of one port and reset port structure to closed; 2092 * Each port includes three pipes: bulk in, bulk out and interrupt. 2093 */ 2094 static void 2095 usbsacm_close_port_pipes(usbsacm_port_t *acm_port) 2096 { 2097 usbsacm_state_t *acmp = acm_port->acm_device; 2098 2099 mutex_enter(&acm_port->acm_port_mutex); 2100 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 2101 "usbsacm_close_port_pipes: acm_bulkin_state = %d", 2102 acm_port->acm_bulkin_state); 2103 2104 /* 2105 * Check the status of the given port. If port is closing or closed, 2106 * return directly. 2107 */ 2108 if ((acm_port->acm_bulkin_state == USBSACM_PIPE_CLOSED) || 2109 (acm_port->acm_bulkin_state == USBSACM_PIPE_CLOSING)) { 2110 USB_DPRINTF_L2(PRINT_MASK_CLOSE, acmp->acm_lh, 2111 "usbsacm_close_port_pipes: port is closing or has closed"); 2112 mutex_exit(&acm_port->acm_port_mutex); 2113 2114 return; 2115 } 2116 2117 acm_port->acm_bulkin_state = USBSACM_PIPE_CLOSING; 2118 mutex_exit(&acm_port->acm_port_mutex); 2119 2120 /* Close pipes */ 2121 usb_pipe_reset(acmp->acm_dip, acm_port->acm_bulkin_ph, 2122 USB_FLAGS_SLEEP, 0, 0); 2123 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph, 2124 USB_FLAGS_SLEEP, 0, 0); 2125 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkout_ph, 2126 USB_FLAGS_SLEEP, 0, 0); 2127 if (acm_port->acm_intr_ph != NULL) { 2128 usb_pipe_stop_intr_polling(acm_port->acm_intr_ph, 2129 USB_FLAGS_SLEEP); 2130 usb_pipe_close(acmp->acm_dip, acm_port->acm_intr_ph, 2131 USB_FLAGS_SLEEP, 0, 0); 2132 } 2133 2134 mutex_enter(&acm_port->acm_port_mutex); 2135 /* Reset the status of pipes to closed */ 2136 acm_port->acm_bulkin_state = USBSACM_PIPE_CLOSED; 2137 acm_port->acm_bulkin_ph = NULL; 2138 acm_port->acm_bulkout_state = USBSACM_PIPE_CLOSED; 2139 acm_port->acm_bulkout_ph = NULL; 2140 if (acm_port->acm_intr_ph != NULL) { 2141 acm_port->acm_intr_state = USBSACM_PIPE_CLOSED; 2142 acm_port->acm_intr_ph = NULL; 2143 } 2144 2145 mutex_exit(&acm_port->acm_port_mutex); 2146 2147 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 2148 "usbsacm_close_port_pipes: port has been closed."); 2149 } 2150 2151 2152 /* 2153 * usbsacm_close_pipes: 2154 * close all opened pipes of current devices. 2155 */ 2156 static void 2157 usbsacm_close_pipes(usbsacm_state_t *acmp) 2158 { 2159 int i; 2160 2161 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 2162 "usbsacm_close_pipes: "); 2163 2164 /* Close all ports */ 2165 for (i = 0; i < acmp->acm_port_cnt; i++) { 2166 usbsacm_close_port_pipes(&acmp->acm_ports[i]); 2167 } 2168 } 2169 2170 2171 /* 2172 * usbsacm_disconnect_pipes: 2173 * this function just call usbsacm_close_pipes. 2174 */ 2175 static void 2176 usbsacm_disconnect_pipes(usbsacm_state_t *acmp) 2177 { 2178 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 2179 "usbsacm_disconnect_pipes: "); 2180 2181 usbsacm_close_pipes(acmp); 2182 } 2183 2184 2185 /* 2186 * usbsacm_reconnect_pipes: 2187 * reconnect pipes in CPR resume or reconnect 2188 */ 2189 static int 2190 usbsacm_reconnect_pipes(usbsacm_state_t *acmp) 2191 { 2192 usbsacm_port_t *cur_port = acmp->acm_ports; 2193 int i; 2194 2195 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 2196 "usbsacm_reconnect_pipes: "); 2197 2198 /* reopen all ports of current device. */ 2199 for (i = 0; i < acmp->acm_port_cnt; i++) { 2200 cur_port = &acmp->acm_ports[i]; 2201 2202 mutex_enter(&cur_port->acm_port_mutex); 2203 /* 2204 * If port status is open, reopen it; 2205 * else retain the current status. 2206 */ 2207 if (cur_port->acm_port_state == USBSACM_PORT_OPEN) { 2208 2209 mutex_exit(&cur_port->acm_port_mutex); 2210 if (usbsacm_open_port_pipes(cur_port) != USB_SUCCESS) { 2211 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 2212 "usbsacm_reconnect_pipes: " 2213 "open port %d failed.", i); 2214 2215 return (USB_FAILURE); 2216 } 2217 mutex_enter(&cur_port->acm_port_mutex); 2218 } 2219 mutex_exit(&cur_port->acm_port_mutex); 2220 } 2221 2222 return (USB_SUCCESS); 2223 } 2224 2225 /* 2226 * usbsacm_bulkin_cb: 2227 * Bulk In regular and exeception callback; 2228 * USBA framework will call this callback 2229 * after deal with bulkin request. 2230 */ 2231 /*ARGSUSED*/ 2232 static void 2233 usbsacm_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 2234 { 2235 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->bulk_client_private; 2236 usbsacm_state_t *acmp = acm_port->acm_device; 2237 mblk_t *data; 2238 int data_len; 2239 2240 data = req->bulk_data; 2241 data_len = (data) ? MBLKL(data) : 0; 2242 2243 mutex_enter(&acm_port->acm_port_mutex); 2244 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 2245 "usbsacm_bulkin_cb: " 2246 "acm_bulkin_state = %d acm_port_state = %d data_len = %d", 2247 acm_port->acm_bulkin_state, acm_port->acm_port_state, data_len); 2248 2249 if ((acm_port->acm_port_state == USBSACM_PORT_OPEN) && (data_len) && 2250 (req->bulk_completion_reason == USB_CR_OK)) { 2251 mutex_exit(&acm_port->acm_port_mutex); 2252 /* prevent USBA from freeing data along with the request */ 2253 req->bulk_data = NULL; 2254 2255 /* save data on the receive list */ 2256 usbsacm_put_tail(&acm_port->acm_rx_mp, data); 2257 2258 /* invoke GSD receive callback */ 2259 if (acm_port->acm_cb.cb_rx) { 2260 acm_port->acm_cb.cb_rx(acm_port->acm_cb.cb_arg); 2261 } 2262 mutex_enter(&acm_port->acm_port_mutex); 2263 } 2264 mutex_exit(&acm_port->acm_port_mutex); 2265 2266 usb_free_bulk_req(req); 2267 2268 /* receive more */ 2269 mutex_enter(&acm_port->acm_port_mutex); 2270 if (((acm_port->acm_bulkin_state == USBSACM_PIPE_BUSY) || 2271 (acm_port->acm_bulkin_state == USBSACM_PIPE_IDLE)) && 2272 (acm_port->acm_port_state == USBSACM_PORT_OPEN) && 2273 (acmp->acm_dev_state == USB_DEV_ONLINE)) { 2274 if (usbsacm_rx_start(acm_port) != USB_SUCCESS) { 2275 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2276 "usbsacm_bulkin_cb: restart rx fail " 2277 "acm_port_state = %d", acm_port->acm_port_state); 2278 } 2279 } else if (acm_port->acm_bulkin_state == USBSACM_PIPE_BUSY) { 2280 acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE; 2281 } 2282 mutex_exit(&acm_port->acm_port_mutex); 2283 } 2284 2285 2286 /* 2287 * usbsacm_bulkout_cb: 2288 * Bulk Out regular and exeception callback; 2289 * USBA framework will call this callback function 2290 * after deal with bulkout request. 2291 */ 2292 /*ARGSUSED*/ 2293 static void 2294 usbsacm_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 2295 { 2296 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->bulk_client_private; 2297 usbsacm_state_t *acmp = acm_port->acm_device; 2298 int data_len; 2299 mblk_t *data = req->bulk_data; 2300 2301 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 2302 "usbsacm_bulkout_cb: acmp = 0x%p", (void *)acmp); 2303 2304 data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0; 2305 2306 /* put untransferred residue back on the transfer list */ 2307 if (req->bulk_completion_reason && (data_len > 0)) { 2308 usbsacm_put_head(&acm_port->acm_tx_mp, data); 2309 req->bulk_data = NULL; 2310 } 2311 2312 usb_free_bulk_req(req); 2313 2314 /* invoke GSD transmit callback */ 2315 if (acm_port->acm_cb.cb_tx) { 2316 acm_port->acm_cb.cb_tx(acm_port->acm_cb.cb_arg); 2317 } 2318 2319 /* send more */ 2320 mutex_enter(&acm_port->acm_port_mutex); 2321 acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE; 2322 if (acm_port->acm_tx_mp == NULL) { 2323 cv_broadcast(&acm_port->acm_tx_cv); 2324 } else { 2325 usbsacm_tx_start(acm_port); 2326 } 2327 mutex_exit(&acm_port->acm_port_mutex); 2328 } 2329 2330 2331 /* 2332 * usbsacm_rx_start: 2333 * start data receipt 2334 */ 2335 static int 2336 usbsacm_rx_start(usbsacm_port_t *acm_port) 2337 { 2338 usbsacm_state_t *acmp = acm_port->acm_device; 2339 usb_bulk_req_t *br; 2340 int rval = USB_FAILURE; 2341 int data_len; 2342 2343 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 2344 "usbsacm_rx_start: acm_xfer_sz = 0x%lx acm_bulkin_size = 0x%lx", 2345 acmp->acm_xfer_sz, acm_port->acm_bulkin_size); 2346 2347 acm_port->acm_bulkin_state = USBSACM_PIPE_BUSY; 2348 /* 2349 * Qualcomm CDMA card won't response the first request, 2350 * if the following code don't multiply by 2. 2351 */ 2352 data_len = min(acmp->acm_xfer_sz, acm_port->acm_bulkin_size * 2); 2353 mutex_exit(&acm_port->acm_port_mutex); 2354 2355 br = usb_alloc_bulk_req(acmp->acm_dip, data_len, USB_FLAGS_SLEEP); 2356 if (br == NULL) { 2357 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2358 "usbsacm_rx_start: allocate bulk request failed"); 2359 2360 mutex_enter(&acm_port->acm_port_mutex); 2361 2362 return (USB_FAILURE); 2363 } 2364 /* initialize bulk in request. */ 2365 br->bulk_len = data_len; 2366 br->bulk_timeout = USBSACM_BULKIN_TIMEOUT; 2367 br->bulk_cb = usbsacm_bulkin_cb; 2368 br->bulk_exc_cb = usbsacm_bulkin_cb; 2369 br->bulk_client_private = (usb_opaque_t)acm_port; 2370 br->bulk_attributes = USB_ATTRS_AUTOCLEARING 2371 | USB_ATTRS_SHORT_XFER_OK; 2372 2373 rval = usb_pipe_bulk_xfer(acm_port->acm_bulkin_ph, br, 0); 2374 2375 mutex_enter(&acm_port->acm_port_mutex); 2376 if (rval != USB_SUCCESS) { 2377 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2378 "usbsacm_rx_start: bulk transfer failed %d", rval); 2379 usb_free_bulk_req(br); 2380 acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE; 2381 } 2382 2383 return (rval); 2384 } 2385 2386 2387 /* 2388 * usbsacm_tx_start: 2389 * start data transmit 2390 */ 2391 static void 2392 usbsacm_tx_start(usbsacm_port_t *acm_port) 2393 { 2394 int len; /* bytes we can transmit */ 2395 mblk_t *data; /* data to be transmitted */ 2396 int data_len; /* bytes in 'data' */ 2397 mblk_t *mp; /* current msgblk */ 2398 int copylen; /* bytes copy from 'mp' to 'data' */ 2399 int rval; 2400 usbsacm_state_t *acmp = acm_port->acm_device; 2401 2402 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 2403 "usbsacm_tx_start: "); 2404 2405 /* check the transmitted data. */ 2406 if (acm_port->acm_tx_mp == NULL) { 2407 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2408 "usbsacm_tx_start: acm_tx_mp is NULL"); 2409 2410 return; 2411 } 2412 2413 /* check pipe status */ 2414 if (acm_port->acm_bulkout_state != USBSACM_PIPE_IDLE) { 2415 2416 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2417 "usbsacm_tx_start: error state in bulkout endpoint"); 2418 2419 return; 2420 } 2421 ASSERT(MBLKL(acm_port->acm_tx_mp) > 0); 2422 2423 /* send as much data as port can receive */ 2424 len = min(msgdsize(acm_port->acm_tx_mp), acmp->acm_xfer_sz); 2425 2426 if (len == 0) { 2427 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2428 "usbsacm_tx_start: data len is 0"); 2429 2430 return; 2431 } 2432 2433 /* allocate memory for sending data. */ 2434 if ((data = allocb(len, BPRI_LO)) == NULL) { 2435 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2436 "usbsacm_tx_start: failure in allocate memory"); 2437 2438 return; 2439 } 2440 2441 /* 2442 * copy no more than 'len' bytes from mblk chain to transmit mblk 'data' 2443 */ 2444 data_len = 0; 2445 while ((data_len < len) && acm_port->acm_tx_mp) { 2446 /* Get the first mblk from chain. */ 2447 mp = acm_port->acm_tx_mp; 2448 copylen = min(MBLKL(mp), len - data_len); 2449 bcopy(mp->b_rptr, data->b_wptr, copylen); 2450 mp->b_rptr += copylen; 2451 data->b_wptr += copylen; 2452 data_len += copylen; 2453 2454 if (MBLKL(mp) < 1) { 2455 acm_port->acm_tx_mp = unlinkb(mp); 2456 freeb(mp); 2457 } else { 2458 ASSERT(data_len == len); 2459 } 2460 } 2461 2462 if (data_len <= 0) { 2463 freeb(data); 2464 2465 return; 2466 } 2467 2468 acm_port->acm_bulkout_state = USBSACM_PIPE_BUSY; 2469 2470 mutex_exit(&acm_port->acm_port_mutex); 2471 /* send request. */ 2472 rval = usbsacm_send_data(acm_port, data); 2473 mutex_enter(&acm_port->acm_port_mutex); 2474 2475 /* 2476 * If send failed, retransmit data when acm_tx_mp is null. 2477 */ 2478 if (rval != USB_SUCCESS) { 2479 acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE; 2480 if (acm_port->acm_tx_mp == NULL) { 2481 usbsacm_put_head(&acm_port->acm_tx_mp, data); 2482 } 2483 } 2484 } 2485 2486 2487 /* 2488 * usbsacm_send_data: 2489 * data transfer 2490 */ 2491 static int 2492 usbsacm_send_data(usbsacm_port_t *acm_port, mblk_t *data) 2493 { 2494 usbsacm_state_t *acmp = acm_port->acm_device; 2495 usb_bulk_req_t *br; 2496 int rval; 2497 int data_len = MBLKL(data); 2498 2499 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 2500 "usbsacm_send_data: data address is 0x%p, length = %d", 2501 (void *)data, data_len); 2502 2503 br = usb_alloc_bulk_req(acmp->acm_dip, 0, USB_FLAGS_SLEEP); 2504 if (br == NULL) { 2505 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2506 "usbsacm_send_data: alloc req failed."); 2507 2508 return (USB_FAILURE); 2509 } 2510 2511 /* initialize the bulk out request */ 2512 br->bulk_data = data; 2513 br->bulk_len = data_len; 2514 br->bulk_timeout = USBSACM_BULKOUT_TIMEOUT; 2515 br->bulk_cb = usbsacm_bulkout_cb; 2516 br->bulk_exc_cb = usbsacm_bulkout_cb; 2517 br->bulk_client_private = (usb_opaque_t)acm_port; 2518 br->bulk_attributes = USB_ATTRS_AUTOCLEARING; 2519 2520 rval = usb_pipe_bulk_xfer(acm_port->acm_bulkout_ph, br, 0); 2521 2522 if (rval != USB_SUCCESS) { 2523 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2524 "usbsacm_send_data: Send Data failed."); 2525 2526 /* 2527 * Don't free it in usb_free_bulk_req because it will 2528 * be linked in usbsacm_put_head 2529 */ 2530 br->bulk_data = NULL; 2531 2532 usb_free_bulk_req(br); 2533 } 2534 2535 return (rval); 2536 } 2537 2538 /* 2539 * usbsacm_wait_tx_drain: 2540 * wait until local tx buffer drains. 2541 * 'timeout' is in seconds, zero means wait forever 2542 */ 2543 static int 2544 usbsacm_wait_tx_drain(usbsacm_port_t *acm_port, int timeout) 2545 { 2546 clock_t until; 2547 int over = 0; 2548 2549 until = ddi_get_lbolt() + drv_usectohz(1000 * 1000 * timeout); 2550 2551 while (acm_port->acm_tx_mp && !over) { 2552 if (timeout > 0) { 2553 over = (cv_timedwait_sig(&acm_port->acm_tx_cv, 2554 &acm_port->acm_port_mutex, until) <= 0); 2555 } else { 2556 over = (cv_wait_sig(&acm_port->acm_tx_cv, 2557 &acm_port->acm_port_mutex) == 0); 2558 } 2559 } 2560 2561 return ((acm_port->acm_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE); 2562 } 2563 2564 2565 /* 2566 * usbsacm_req_write: 2567 * send command over control pipe 2568 */ 2569 static int 2570 usbsacm_req_write(usbsacm_port_t *acm_port, uchar_t request, uint16_t value, 2571 mblk_t **data) 2572 { 2573 usbsacm_state_t *acmp = acm_port->acm_device; 2574 usb_ctrl_setup_t setup; 2575 usb_cb_flags_t cb_flags; 2576 usb_cr_t cr; 2577 2578 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 2579 "usbsacm_req_write: "); 2580 2581 /* initialize the control request. */ 2582 setup.bmRequestType = USBSACM_REQ_WRITE_IF; 2583 setup.bRequest = request; 2584 setup.wValue = value; 2585 setup.wIndex = acm_port->acm_ctrl_if_no; 2586 setup.wLength = ((data != NULL) && (*data != NULL)) ? MBLKL(*data) : 0; 2587 setup.attrs = 0; 2588 2589 return (usb_pipe_ctrl_xfer_wait(acmp->acm_def_ph, &setup, data, 2590 &cr, &cb_flags, 0)); 2591 } 2592 2593 2594 /* 2595 * usbsacm_set_line_coding: 2596 * Send USB_CDC_REQ_SET_LINE_CODING request 2597 */ 2598 static int 2599 usbsacm_set_line_coding(usbsacm_port_t *acm_port, usb_cdc_line_coding_t *lc) 2600 { 2601 mblk_t *bp; 2602 int ret; 2603 2604 /* allocate mblk and copy supplied structure into it */ 2605 if ((bp = allocb(USB_CDC_LINE_CODING_LEN, BPRI_HI)) == NULL) { 2606 2607 return (USB_NO_RESOURCES); 2608 } 2609 2610 #ifndef __lock_lint /* warlock gets confused here */ 2611 /* LINTED E_BAD_PTR_CAST_ALIGN */ 2612 *((usb_cdc_line_coding_t *)bp->b_wptr) = *lc; 2613 bp->b_wptr += USB_CDC_LINE_CODING_LEN; 2614 #endif 2615 2616 ret = usbsacm_req_write(acm_port, USB_CDC_REQ_SET_LINE_CODING, 0, &bp); 2617 2618 if (bp != NULL) { 2619 freeb(bp); 2620 } 2621 2622 return (ret); 2623 } 2624 2625 2626 2627 /* 2628 * usbsacm_mctl2reg: 2629 * Set Modem control status 2630 */ 2631 static void 2632 usbsacm_mctl2reg(int mask, int val, uint8_t *line_ctl) 2633 { 2634 if (mask & TIOCM_RTS) { 2635 if (val & TIOCM_RTS) { 2636 *line_ctl |= USB_CDC_ACM_CONTROL_RTS; 2637 } else { 2638 *line_ctl &= ~USB_CDC_ACM_CONTROL_RTS; 2639 } 2640 } 2641 if (mask & TIOCM_DTR) { 2642 if (val & TIOCM_DTR) { 2643 *line_ctl |= USB_CDC_ACM_CONTROL_DTR; 2644 } else { 2645 *line_ctl &= ~USB_CDC_ACM_CONTROL_DTR; 2646 } 2647 } 2648 } 2649 2650 2651 /* 2652 * usbsacm_reg2mctl: 2653 * Get Modem control status 2654 */ 2655 static int 2656 usbsacm_reg2mctl(uint8_t line_ctl) 2657 { 2658 int val = 0; 2659 2660 if (line_ctl & USB_CDC_ACM_CONTROL_RTS) { 2661 val |= TIOCM_RTS; 2662 } 2663 if (line_ctl & USB_CDC_ACM_CONTROL_DTR) { 2664 val |= TIOCM_DTR; 2665 } 2666 if (line_ctl & USB_CDC_ACM_CONTROL_DSR) { 2667 val |= TIOCM_DSR; 2668 } 2669 if (line_ctl & USB_CDC_ACM_CONTROL_RNG) { 2670 val |= TIOCM_RI; 2671 } 2672 2673 return (val); 2674 } 2675 2676 2677 /* 2678 * misc routines 2679 * ------------- 2680 * 2681 */ 2682 2683 /* 2684 * usbsacm_put_tail: 2685 * link a message block to tail of message 2686 * account for the case when message is null 2687 */ 2688 static void 2689 usbsacm_put_tail(mblk_t **mpp, mblk_t *bp) 2690 { 2691 if (*mpp) { 2692 linkb(*mpp, bp); 2693 } else { 2694 *mpp = bp; 2695 } 2696 } 2697 2698 2699 /* 2700 * usbsacm_put_head: 2701 * put a message block at the head of the message 2702 * account for the case when message is null 2703 */ 2704 static void 2705 usbsacm_put_head(mblk_t **mpp, mblk_t *bp) 2706 { 2707 if (*mpp) { 2708 linkb(bp, *mpp); 2709 } 2710 *mpp = bp; 2711 } 2712 2713 2714 /* 2715 * power management 2716 * ---------------- 2717 * 2718 * usbsacm_create_pm_components: 2719 * create PM components 2720 */ 2721 static int 2722 usbsacm_create_pm_components(usbsacm_state_t *acmp) 2723 { 2724 dev_info_t *dip = acmp->acm_dip; 2725 usbsacm_pm_t *pm; 2726 uint_t pwr_states; 2727 usb_dev_descr_t *dev_descr; 2728 2729 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 2730 "usbsacm_create_pm_components: "); 2731 2732 if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) { 2733 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 2734 "usbsacm_create_pm_components: failed"); 2735 2736 return (USB_SUCCESS); 2737 } 2738 2739 pm = acmp->acm_pm = 2740 (usbsacm_pm_t *)kmem_zalloc(sizeof (usbsacm_pm_t), KM_SLEEP); 2741 2742 pm->pm_pwr_states = (uint8_t)pwr_states; 2743 pm->pm_cur_power = USB_DEV_OS_FULL_PWR; 2744 /* 2745 * Qualcomm CDMA card won't response the following control commands 2746 * after receive USB_REMOTE_WAKEUP_ENABLE. So we just set 2747 * pm_wakeup_enable to 0 for this specific device. 2748 */ 2749 dev_descr = acmp->acm_dev_data->dev_descr; 2750 if (dev_descr->idVendor == 0x5c6 && dev_descr->idProduct == 0x3100) { 2751 pm->pm_wakeup_enabled = 0; 2752 } else { 2753 pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip, 2754 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS); 2755 } 2756 2757 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2758 2759 return (USB_SUCCESS); 2760 } 2761 2762 2763 /* 2764 * usbsacm_destroy_pm_components: 2765 * destroy PM components 2766 */ 2767 static void 2768 usbsacm_destroy_pm_components(usbsacm_state_t *acmp) 2769 { 2770 usbsacm_pm_t *pm = acmp->acm_pm; 2771 dev_info_t *dip = acmp->acm_dip; 2772 int rval; 2773 2774 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 2775 "usbsacm_destroy_pm_components: "); 2776 2777 if (acmp->acm_dev_state != USB_DEV_DISCONNECTED) { 2778 if (pm->pm_wakeup_enabled) { 2779 rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2780 if (rval != DDI_SUCCESS) { 2781 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 2782 "usbsacm_destroy_pm_components: " 2783 "raising power failed (%d)", rval); 2784 } 2785 2786 rval = usb_handle_remote_wakeup(dip, 2787 USB_REMOTE_WAKEUP_DISABLE); 2788 if (rval != USB_SUCCESS) { 2789 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 2790 "usbsacm_destroy_pm_components: " 2791 "disable remote wakeup failed (%d)", rval); 2792 } 2793 } 2794 2795 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF); 2796 } 2797 kmem_free((caddr_t)pm, sizeof (usbsacm_pm_t)); 2798 acmp->acm_pm = NULL; 2799 } 2800 2801 2802 /* 2803 * usbsacm_pm_set_busy: 2804 * mark device busy and raise power 2805 */ 2806 static void 2807 usbsacm_pm_set_busy(usbsacm_state_t *acmp) 2808 { 2809 usbsacm_pm_t *pm = acmp->acm_pm; 2810 dev_info_t *dip = acmp->acm_dip; 2811 int rval; 2812 2813 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 2814 "usbsacm_pm_set_busy: pm = 0x%p", (void *)pm); 2815 2816 if (pm == NULL) { 2817 2818 return; 2819 } 2820 2821 mutex_enter(&acmp->acm_mutex); 2822 /* if already marked busy, just increment the counter */ 2823 if (pm->pm_busy_cnt++ > 0) { 2824 mutex_exit(&acmp->acm_mutex); 2825 2826 return; 2827 } 2828 2829 (void) pm_busy_component(dip, 0); 2830 2831 if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) { 2832 mutex_exit(&acmp->acm_mutex); 2833 2834 return; 2835 } 2836 2837 /* need to raise power */ 2838 pm->pm_raise_power = B_TRUE; 2839 mutex_exit(&acmp->acm_mutex); 2840 2841 rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2842 if (rval != DDI_SUCCESS) { 2843 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 2844 "usbsacm_pm_set_busy: raising power failed"); 2845 } 2846 2847 mutex_enter(&acmp->acm_mutex); 2848 pm->pm_raise_power = B_FALSE; 2849 mutex_exit(&acmp->acm_mutex); 2850 } 2851 2852 2853 /* 2854 * usbsacm_pm_set_idle: 2855 * mark device idle 2856 */ 2857 static void 2858 usbsacm_pm_set_idle(usbsacm_state_t *acmp) 2859 { 2860 usbsacm_pm_t *pm = acmp->acm_pm; 2861 dev_info_t *dip = acmp->acm_dip; 2862 2863 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 2864 "usbsacm_pm_set_idle: "); 2865 2866 if (pm == NULL) { 2867 2868 return; 2869 } 2870 2871 /* 2872 * if more ports use the device, do not mark as yet 2873 */ 2874 mutex_enter(&acmp->acm_mutex); 2875 if (--pm->pm_busy_cnt > 0) { 2876 mutex_exit(&acmp->acm_mutex); 2877 2878 return; 2879 } 2880 2881 if (pm) { 2882 (void) pm_idle_component(dip, 0); 2883 } 2884 mutex_exit(&acmp->acm_mutex); 2885 } 2886 2887 2888 /* 2889 * usbsacm_pwrlvl0: 2890 * Functions to handle power transition for OS levels 0 -> 3 2891 * The same level as OS state, different from USB state 2892 */ 2893 static int 2894 usbsacm_pwrlvl0(usbsacm_state_t *acmp) 2895 { 2896 int rval; 2897 int i; 2898 usbsacm_port_t *cur_port = acmp->acm_ports; 2899 2900 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 2901 "usbsacm_pwrlvl0: "); 2902 2903 switch (acmp->acm_dev_state) { 2904 case USB_DEV_ONLINE: 2905 /* issue USB D3 command to the device */ 2906 rval = usb_set_device_pwrlvl3(acmp->acm_dip); 2907 ASSERT(rval == USB_SUCCESS); 2908 2909 if (cur_port != NULL) { 2910 for (i = 0; i < acmp->acm_port_cnt; i++) { 2911 cur_port = &acmp->acm_ports[i]; 2912 if (cur_port->acm_intr_ph != NULL && 2913 cur_port->acm_port_state != 2914 USBSACM_PORT_CLOSED) { 2915 2916 mutex_exit(&acmp->acm_mutex); 2917 usb_pipe_stop_intr_polling( 2918 cur_port->acm_intr_ph, 2919 USB_FLAGS_SLEEP); 2920 mutex_enter(&acmp->acm_mutex); 2921 2922 mutex_enter(&cur_port->acm_port_mutex); 2923 cur_port->acm_intr_state = 2924 USBSACM_PIPE_IDLE; 2925 mutex_exit(&cur_port->acm_port_mutex); 2926 } 2927 } 2928 } 2929 2930 acmp->acm_dev_state = USB_DEV_PWRED_DOWN; 2931 acmp->acm_pm->pm_cur_power = USB_DEV_OS_PWR_OFF; 2932 2933 /* FALLTHRU */ 2934 case USB_DEV_DISCONNECTED: 2935 case USB_DEV_SUSPENDED: 2936 /* allow a disconnect/cpr'ed device to go to lower power */ 2937 2938 return (USB_SUCCESS); 2939 case USB_DEV_PWRED_DOWN: 2940 default: 2941 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 2942 "usbsacm_pwrlvl0: illegal device state"); 2943 2944 return (USB_FAILURE); 2945 } 2946 } 2947 2948 2949 /* 2950 * usbsacm_pwrlvl1: 2951 * Functions to handle power transition for OS levels 1 -> 2 2952 */ 2953 static int 2954 usbsacm_pwrlvl1(usbsacm_state_t *acmp) 2955 { 2956 /* issue USB D2 command to the device */ 2957 (void) usb_set_device_pwrlvl2(acmp->acm_dip); 2958 2959 return (USB_FAILURE); 2960 } 2961 2962 2963 /* 2964 * usbsacm_pwrlvl2: 2965 * Functions to handle power transition for OS levels 2 -> 1 2966 */ 2967 static int 2968 usbsacm_pwrlvl2(usbsacm_state_t *acmp) 2969 { 2970 /* issue USB D1 command to the device */ 2971 (void) usb_set_device_pwrlvl1(acmp->acm_dip); 2972 2973 return (USB_FAILURE); 2974 } 2975 2976 2977 /* 2978 * usbsacm_pwrlvl3: 2979 * Functions to handle power transition for OS levels 3 -> 0 2980 * The same level as OS state, different from USB state 2981 */ 2982 static int 2983 usbsacm_pwrlvl3(usbsacm_state_t *acmp) 2984 { 2985 int rval; 2986 int i; 2987 usbsacm_port_t *cur_port = acmp->acm_ports; 2988 2989 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 2990 "usbsacm_pwrlvl3: "); 2991 2992 switch (acmp->acm_dev_state) { 2993 case USB_DEV_PWRED_DOWN: 2994 /* Issue USB D0 command to the device here */ 2995 rval = usb_set_device_pwrlvl0(acmp->acm_dip); 2996 ASSERT(rval == USB_SUCCESS); 2997 2998 if (cur_port != NULL) { 2999 for (i = 0; i < acmp->acm_port_cnt; i++) { 3000 cur_port = &acmp->acm_ports[i]; 3001 if (cur_port->acm_intr_ph != NULL && 3002 cur_port->acm_port_state != 3003 USBSACM_PORT_CLOSED) { 3004 3005 mutex_exit(&acmp->acm_mutex); 3006 usbsacm_pipe_start_polling(cur_port); 3007 mutex_enter(&acmp->acm_mutex); 3008 } 3009 } 3010 } 3011 3012 acmp->acm_dev_state = USB_DEV_ONLINE; 3013 acmp->acm_pm->pm_cur_power = USB_DEV_OS_FULL_PWR; 3014 3015 /* FALLTHRU */ 3016 case USB_DEV_ONLINE: 3017 /* we are already in full power */ 3018 3019 /* FALLTHRU */ 3020 case USB_DEV_DISCONNECTED: 3021 case USB_DEV_SUSPENDED: 3022 3023 return (USB_SUCCESS); 3024 default: 3025 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 3026 "usbsacm_pwrlvl3: illegal device state"); 3027 3028 return (USB_FAILURE); 3029 } 3030 } 3031 3032 3033 /* 3034 * usbsacm_pipe_start_polling: 3035 * start polling on the interrupt pipe 3036 */ 3037 static void 3038 usbsacm_pipe_start_polling(usbsacm_port_t *acm_port) 3039 { 3040 usb_intr_req_t *intr; 3041 int rval; 3042 usbsacm_state_t *acmp = acm_port->acm_device; 3043 3044 USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh, 3045 "usbsacm_pipe_start_polling: "); 3046 3047 if (acm_port->acm_intr_ph == NULL) { 3048 3049 return; 3050 } 3051 3052 intr = usb_alloc_intr_req(acmp->acm_dip, 0, USB_FLAGS_SLEEP); 3053 3054 /* 3055 * If it is in interrupt context, usb_alloc_intr_req will return NULL if 3056 * called with SLEEP flag. 3057 */ 3058 if (!intr) { 3059 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 3060 "usbsacm_pipe_start_polling: alloc req failed."); 3061 3062 return; 3063 } 3064 3065 /* initialize the interrupt request. */ 3066 intr->intr_attributes = USB_ATTRS_SHORT_XFER_OK | 3067 USB_ATTRS_AUTOCLEARING; 3068 mutex_enter(&acm_port->acm_port_mutex); 3069 intr->intr_len = acm_port->acm_intr_ep_descr.wMaxPacketSize; 3070 mutex_exit(&acm_port->acm_port_mutex); 3071 intr->intr_client_private = (usb_opaque_t)acm_port; 3072 intr->intr_cb = usbsacm_intr_cb; 3073 intr->intr_exc_cb = usbsacm_intr_ex_cb; 3074 3075 rval = usb_pipe_intr_xfer(acm_port->acm_intr_ph, intr, USB_FLAGS_SLEEP); 3076 3077 mutex_enter(&acm_port->acm_port_mutex); 3078 if (rval == USB_SUCCESS) { 3079 acm_port->acm_intr_state = USBSACM_PIPE_BUSY; 3080 } else { 3081 usb_free_intr_req(intr); 3082 acm_port->acm_intr_state = USBSACM_PIPE_IDLE; 3083 USB_DPRINTF_L3(PRINT_MASK_OPEN, acmp->acm_lh, 3084 "usbsacm_pipe_start_polling: failed (%d)", rval); 3085 } 3086 mutex_exit(&acm_port->acm_port_mutex); 3087 } 3088 3089 3090 /* 3091 * usbsacm_intr_cb: 3092 * interrupt pipe normal callback 3093 */ 3094 /*ARGSUSED*/ 3095 static void 3096 usbsacm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req) 3097 { 3098 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->intr_client_private; 3099 usbsacm_state_t *acmp = acm_port->acm_device; 3100 mblk_t *data = req->intr_data; 3101 int data_len; 3102 3103 USB_DPRINTF_L4(PRINT_MASK_CB, acmp->acm_lh, 3104 "usbsacm_intr_cb: "); 3105 3106 data_len = (data) ? MBLKL(data) : 0; 3107 3108 /* check data length */ 3109 if (data_len < 8) { 3110 USB_DPRINTF_L2(PRINT_MASK_CB, acmp->acm_lh, 3111 "usbsacm_intr_cb: %d packet too short", data_len); 3112 usb_free_intr_req(req); 3113 3114 return; 3115 } 3116 req->intr_data = NULL; 3117 usb_free_intr_req(req); 3118 3119 mutex_enter(&acm_port->acm_port_mutex); 3120 /* parse interrupt data. */ 3121 usbsacm_parse_intr_data(acm_port, data); 3122 mutex_exit(&acm_port->acm_port_mutex); 3123 } 3124 3125 3126 /* 3127 * usbsacm_intr_ex_cb: 3128 * interrupt pipe exception callback 3129 */ 3130 /*ARGSUSED*/ 3131 static void 3132 usbsacm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req) 3133 { 3134 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->intr_client_private; 3135 usbsacm_state_t *acmp = acm_port->acm_device; 3136 usb_cr_t cr = req->intr_completion_reason; 3137 3138 USB_DPRINTF_L4(PRINT_MASK_CB, acmp->acm_lh, 3139 "usbsacm_intr_ex_cb: "); 3140 3141 usb_free_intr_req(req); 3142 3143 /* 3144 * If completion reason isn't USB_CR_PIPE_CLOSING and 3145 * USB_CR_STOPPED_POLLING, restart polling. 3146 */ 3147 if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING)) { 3148 mutex_enter(&acmp->acm_mutex); 3149 3150 if (acmp->acm_dev_state != USB_DEV_ONLINE) { 3151 3152 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3153 "usbsacm_intr_ex_cb: state = %d", 3154 acmp->acm_dev_state); 3155 3156 mutex_exit(&acmp->acm_mutex); 3157 3158 return; 3159 } 3160 mutex_exit(&acmp->acm_mutex); 3161 3162 usbsacm_pipe_start_polling(acm_port); 3163 } 3164 } 3165 3166 3167 /* 3168 * usbsacm_parse_intr_data: 3169 * Parse data received from interrupt callback 3170 */ 3171 static void 3172 usbsacm_parse_intr_data(usbsacm_port_t *acm_port, mblk_t *data) 3173 { 3174 usbsacm_state_t *acmp = acm_port->acm_device; 3175 uint8_t bmRequestType; 3176 uint8_t bNotification; 3177 uint16_t wValue; 3178 uint16_t wLength; 3179 uint16_t wData; 3180 3181 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 3182 "usbsacm_parse_intr_data: "); 3183 3184 bmRequestType = data->b_rptr[0]; 3185 bNotification = data->b_rptr[1]; 3186 /* 3187 * If Notification type is NETWORK_CONNECTION, wValue is 0 or 1, 3188 * mLength is 0. If Notification type is SERIAL_TYPE, mValue is 0, 3189 * mLength is 2. So we directly get the value from the byte. 3190 */ 3191 wValue = data->b_rptr[2]; 3192 wLength = data->b_rptr[6]; 3193 3194 if (bmRequestType != USB_CDC_NOTIFICATION_REQUEST_TYPE) { 3195 USB_DPRINTF_L2(PRINT_MASK_CB, acmp->acm_lh, 3196 "usbsacm_parse_intr_data: unknown request type - 0x%x", 3197 bmRequestType); 3198 3199 return; 3200 } 3201 3202 /* 3203 * Check the return value of device 3204 */ 3205 switch (bNotification) { 3206 case USB_CDC_NOTIFICATION_NETWORK_CONNECTION: 3207 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3208 "usbsacm_parse_intr_data: %s network!", 3209 wValue ? "connected to" :"disconnected from"); 3210 3211 break; 3212 case USB_CDC_NOTIFICATION_RESPONSE_AVAILABLE: 3213 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3214 "usbsacm_parse_intr_data: A response is a available."); 3215 3216 break; 3217 case USB_CDC_NOTIFICATION_SERIAL_STATE: 3218 /* check the parameter's length. */ 3219 if (wLength != 2) { 3220 3221 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3222 "usbsacm_parse_intr_data: error data length."); 3223 } else { 3224 /* 3225 * The Data field is a bitmapped value that contains 3226 * the current state of carrier detect, transmission 3227 * carrier, break, ring signal and device overrun 3228 * error. 3229 */ 3230 wData = data->b_rptr[8]; 3231 /* 3232 * Check the serial state of the current port. 3233 */ 3234 if (wData & USB_CDC_ACM_CONTROL_DCD) { 3235 3236 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3237 "usbsacm_parse_intr_data: " 3238 "receiver carrier is set."); 3239 } 3240 if (wData & USB_CDC_ACM_CONTROL_DSR) { 3241 3242 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3243 "usbsacm_parse_intr_data: " 3244 "transmission carrier is set."); 3245 3246 acm_port->acm_mctlin |= USB_CDC_ACM_CONTROL_DSR; 3247 } 3248 if (wData & USB_CDC_ACM_CONTROL_BREAK) { 3249 3250 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3251 "usbsacm_parse_intr_data: " 3252 "break detection mechanism is set."); 3253 } 3254 if (wData & USB_CDC_ACM_CONTROL_RNG) { 3255 3256 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3257 "usbsacm_parse_intr_data: " 3258 "ring signal detection is set."); 3259 3260 acm_port->acm_mctlin |= USB_CDC_ACM_CONTROL_RNG; 3261 } 3262 if (wData & USB_CDC_ACM_CONTROL_FRAMING) { 3263 3264 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3265 "usbsacm_parse_intr_data: " 3266 "A framing error has occurred."); 3267 } 3268 if (wData & USB_CDC_ACM_CONTROL_PARITY) { 3269 3270 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3271 "usbsacm_parse_intr_data: " 3272 "A parity error has occurred."); 3273 } 3274 if (wData & USB_CDC_ACM_CONTROL_OVERRUN) { 3275 3276 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3277 "usbsacm_parse_intr_data: " 3278 "Received data has been discarded " 3279 "due to overrun."); 3280 } 3281 } 3282 3283 break; 3284 default: 3285 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3286 "usbsacm_parse_intr_data: unknown notification - 0x%x!", 3287 bNotification); 3288 3289 break; 3290 } 3291 3292 freemsg(data); 3293 } 3294