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