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