1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 /*
28 * UWB HWA Radio Controller driver.
29 *
30 *
31 * The device has four states (refer to usbai.h):
32 * USB_DEV_ONLINE: In action or ready for action.
33 * USB_DEV_DISCONNECTED: Hotplug removed, or device not present/correct on
34 * resume (CPR).
35 * USB_DEV_SUSPENDED: Device has been suspended along with the system.
36 * USB_DEV_PWRED_DOWN: Device has been powered down. (Note that this
37 * driver supports only two power states, powered down and
38 * full power.)
39 *
40 * In order to avoid race conditions between driver entry points,
41 * access to the device is serialized. Race conditions are an issue in
42 * particular between disconnect event callbacks, detach, power, open
43 * and data transfer callbacks. The functions hwarc_serialize/release_access
44 * are implemented for this purpose.
45 *
46 * Mutexes should never be held when making calls into USBA or when
47 * sleeping.
48 *
49 * pm_busy_component and pm_idle_component mark the device as busy or idle to
50 * the system. These functions are paired, and are called only from code
51 * bracketed by hwarc_serialize_access and hwarc_release_access.
52 *
53 */
54
55 #define USBDRV_MAJOR_VER 2
56 #define USBDRV_MINOR_VER 0
57
58 #include <sys/strsun.h>
59 #include <sys/usb/usba.h>
60 #include <sys/usb/clients/hwarc/hwarc.h>
61
62
63
64 uint_t hwarc_errlevel = 4;
65 static uint_t hwarc_errmask = (uint_t)PRINT_MASK_ALL;
66 static uint_t hwarc_instance_debug = (uint_t)-1;
67
68 static char *name = "hwarc"; /* Driver name, used all over */
69
70
71 /* Function Prototypes */
72 static int hwarc_attach(dev_info_t *, ddi_attach_cmd_t);
73 static int hwarc_detach(dev_info_t *, ddi_detach_cmd_t);
74 static int hwarc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
75 static int hwarc_cleanup(dev_info_t *, hwarc_state_t *);
76 static int hwarc_open(dev_t *, int, int, cred_t *);
77 static int hwarc_close(dev_t, int, int, cred_t *);
78 static int hwarc_send_cmd(uwb_dev_handle_t, mblk_t *, uint16_t);
79 static int hwarc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
80 static int hwarc_disconnect_callback(dev_info_t *);
81 static int hwarc_reconnect_callback(dev_info_t *);
82 static void hwarc_restore_device_state(dev_info_t *, hwarc_state_t *);
83 static int hwarc_cpr_suspend(dev_info_t *);
84 static void hwarc_cpr_resume(dev_info_t *);
85 static int hwarc_open_intr_pipe(hwarc_state_t *);
86 static void hwarc_close_intr_pipe(hwarc_state_t *);
87 static void hwarc_pm_busy_component(hwarc_state_t *);
88 static void hwarc_pm_idle_component(hwarc_state_t *);
89 static int hwarc_power(dev_info_t *, int, int);
90 static int hwarc_serialize_access(hwarc_state_t *, boolean_t);
91 static void hwarc_release_access(hwarc_state_t *);
92 static int hwarc_reset_device(hwarc_state_t *);
93 static int hwarc_init_phy(hwarc_state_t *);
94
95
96 static int hwarc_start_polling(hwarc_state_t *, usb_pipe_handle_t);
97
98
99 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req))
100 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_intr_req))
101 _NOTE(SCHEME_PROTECTS_DATA("unique per call", buf))
102
103 /* module loading stuff */
104 struct cb_ops hwarc_cb_ops = {
105 hwarc_open, /* open */
106 hwarc_close, /* close */
107 nodev, /* strategy */
108 nulldev, /* print */
109 nulldev, /* dump */
110 nodev, /* read */
111 nodev, /* write */
112 hwarc_ioctl, /* ioctl */
113 nulldev, /* devmap */
114 nodev, /* mmap */
115 nodev, /* segmap */
116 nochpoll, /* poll */
117 ddi_prop_op, /* cb_prop_op */
118 NULL, /* streamtab */
119 D_MP
120 };
121
122 static struct dev_ops hwarc_ops = {
123 DEVO_REV, /* devo_rev, */
124 0, /* refcnt */
125 hwarc_info, /* info */
126 nulldev, /* identify */
127 nulldev, /* probe */
128 hwarc_attach, /* attach */
129 hwarc_detach, /* detach */
130 nodev, /* reset */
131 &hwarc_cb_ops, /* driver operations */
132 NULL, /* bus operations */
133 hwarc_power, /* power */
134 ddi_quiesce_not_needed, /* devo_quiesce */
135 };
136
137 static struct modldrv hwarc_modldrv = {
138 &mod_driverops,
139 "USB HWA Radio Controller driver",
140 &hwarc_ops
141 };
142
143 static struct modlinkage modlinkage = {
144 MODREV_1,
145 &hwarc_modldrv,
146 NULL
147 };
148
149 /* Soft state structures */
150 #define HWARC_INITIAL_SOFT_SPACE 1
151 static void *hwarc_statep;
152
153
154 /* Module-wide initialization routine */
155 int
_init(void)156 _init(void)
157 {
158 int rval;
159
160 if ((rval = ddi_soft_state_init(&hwarc_statep,
161 sizeof (hwarc_state_t), HWARC_INITIAL_SOFT_SPACE)) != 0) {
162
163 return (rval);
164 }
165
166 if ((rval = mod_install(&modlinkage)) != 0) {
167 ddi_soft_state_fini(&hwarc_statep);
168 }
169
170 return (rval);
171 }
172
173
174 /* Module-wide tear-down routine */
175 int
_fini(void)176 _fini(void)
177 {
178 int rval;
179
180 if ((rval = mod_remove(&modlinkage)) != 0) {
181
182 return (rval);
183 }
184
185 ddi_soft_state_fini(&hwarc_statep);
186
187 return (rval);
188 }
189
190
191 int
_info(struct modinfo * modinfop)192 _info(struct modinfo *modinfop)
193 {
194 return (mod_info(&modlinkage, modinfop));
195 }
196
197
198 /*
199 * hwarc_info:
200 * Get minor number, soft state structure, etc.
201 */
202 /*ARGSUSED*/
203 static int
hwarc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)204 hwarc_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
205 void *arg, void **result)
206 {
207 hwarc_state_t *hrcp;
208 int error = DDI_FAILURE;
209
210 switch (infocmd) {
211 case DDI_INFO_DEVT2DEVINFO:
212 *result = NULL;
213 if ((hrcp = ddi_get_soft_state(hwarc_statep,
214 getminor((dev_t)arg))) != NULL) {
215 *result = hrcp->hrc_dip;
216 }
217 error = (*result)? DDI_SUCCESS:DDI_FAILURE;
218
219 break;
220 case DDI_INFO_DEVT2INSTANCE:
221 *result = (void *)(uintptr_t)getminor((dev_t)arg);
222 error = DDI_SUCCESS;
223 break;
224 default:
225 break;
226 }
227
228 return (error);
229 }
230
231
232
233 /*
234 * hwarc_init_power_mgmt:
235 * Initialize power management and remote wakeup functionality.
236 * No mutex is necessary in this function as it's called only by attach.
237 */
238 static void
hwarc_init_power_mgmt(hwarc_state_t * hrcp)239 hwarc_init_power_mgmt(hwarc_state_t *hrcp)
240 {
241 hwarc_power_t *hrcpm = NULL;
242 uint_t pwr_states;
243
244 USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
245 "init_power_mgmt enter");
246
247 /* Put online before PM init as can get power managed afterward. */
248 hrcp->hrc_dev_state = USB_DEV_ONLINE;
249
250 /* Allocate the state structure */
251 hrcpm = kmem_zalloc(sizeof (hwarc_power_t), KM_SLEEP);
252
253 hrcpm->hrc_state = hrcp;
254 hrcpm->hrc_pm_capabilities = 0;
255 hrcpm->hrc_current_power = USB_DEV_OS_FULL_PWR;
256
257
258 if (usb_create_pm_components(hrcp->hrc_dip, &pwr_states) ==
259 USB_SUCCESS) {
260 hrcpm->hrc_pwr_states = (uint8_t)pwr_states;
261
262 if (usb_handle_remote_wakeup(hrcp->hrc_dip,
263 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
264 hrcpm->hrc_wakeup_enabled = 1;
265 } else {
266 USB_DPRINTF_L2(PRINT_MASK_PM,
267 hrcp->hrc_log_hdl, "hwarc_init_power_mgmt:"
268 " remote wakeup not supported");
269 }
270
271 } else {
272 USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
273 "hwarc_init_power_mgmt:created PM components failed");
274 }
275 mutex_enter(&hrcp->hrc_mutex);
276 hrcp->hrc_pm = hrcpm;
277 hwarc_pm_busy_component(hrcp);
278 mutex_exit(&hrcp->hrc_mutex);
279
280 (void) pm_raise_power(
281 hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
282
283 USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
284 "hwarc_init_power_mgmt: end");
285 }
286
287
288 /*
289 * hwarc_destroy_power_mgmt:
290 * Shut down and destroy power management and remote wakeup functionality.
291 */
292 static void
hwarc_destroy_power_mgmt(hwarc_state_t * hrcp)293 hwarc_destroy_power_mgmt(hwarc_state_t *hrcp)
294 {
295 hwarc_power_t *pm;
296
297 USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
298 "destroy_power_mgmt enter");
299
300 mutex_enter(&hrcp->hrc_mutex);
301
302 if ((pm = hrcp->hrc_pm) == NULL) {
303 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
304 "hwarc_destroy_power_mgmt:pm not supported");
305 goto done;
306 }
307
308 if (hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) {
309 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
310 "hwarc_destroy_power_mgmt:device disconnected");
311 goto done;
312 }
313
314 hwarc_pm_busy_component(hrcp);
315
316 mutex_exit(&hrcp->hrc_mutex);
317
318 if (pm->hrc_wakeup_enabled) {
319
320 /* First bring the device to full power */
321 (void) pm_raise_power(hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
322 if (usb_handle_remote_wakeup(hrcp->hrc_dip,
323 USB_REMOTE_WAKEUP_DISABLE) != USB_SUCCESS) {
324 USB_DPRINTF_L2(PRINT_MASK_PM,
325 hrcp->hrc_log_hdl, "hwarc_destroy_power_mgmt: "
326 "Error disabling rmt wakeup");
327 }
328
329 }
330
331 /*
332 * Since remote wakeup is disabled now,
333 * no one can raise power
334 * and get to device once power is lowered here.
335 */
336 (void) pm_lower_power(hrcp->hrc_dip, 0, USB_DEV_OS_PWR_OFF);
337
338 mutex_enter(&hrcp->hrc_mutex);
339
340 hwarc_pm_idle_component(hrcp);
341
342 done:
343 if (pm) {
344 kmem_free(pm, sizeof (hwarc_power_t));
345
346 hrcp->hrc_pm = NULL;
347 }
348 mutex_exit(&hrcp->hrc_mutex);
349 }
350
351
352 static void
hwarc_pm_busy_component(hwarc_state_t * hrcp)353 hwarc_pm_busy_component(hwarc_state_t *hrcp)
354 {
355 ASSERT(mutex_owned(&hrcp->hrc_mutex));
356
357 USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
358 "hwarc_pm_busy_component: enter");
359 if (hrcp->hrc_pm == NULL) {
360 USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
361 "hwarc_pm_busy_component: pm not supported, return");
362
363 return;
364 }
365
366 hrcp->hrc_pm->hrc_pm_busy++;
367
368 mutex_exit(&hrcp->hrc_mutex);
369 if (pm_busy_component(hrcp->hrc_dip, 0) !=
370 DDI_SUCCESS) {
371 mutex_enter(&hrcp->hrc_mutex);
372 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
373 "hwarc_pm_busy_component: pm busy fail, hrc_pm_busy=%d",
374 hrcp->hrc_pm->hrc_pm_busy);
375
376 hrcp->hrc_pm->hrc_pm_busy--;
377 mutex_exit(&hrcp->hrc_mutex);
378 }
379 mutex_enter(&hrcp->hrc_mutex);
380
381 USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
382 "hwarc_pm_busy_component: exit");
383 }
384
385
386 static void
hwarc_pm_idle_component(hwarc_state_t * hrcp)387 hwarc_pm_idle_component(hwarc_state_t *hrcp)
388 {
389 ASSERT(mutex_owned(&hrcp->hrc_mutex));
390 USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
391 "hwarc_pm_idle_component: enter");
392
393 if (hrcp->hrc_pm == NULL) {
394 USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl,
395 "hwarc_pm_idle_component: pm not supported");
396
397 return;
398 }
399
400 mutex_exit(&hrcp->hrc_mutex);
401 if (pm_idle_component(hrcp->hrc_dip, 0) == DDI_SUCCESS) {
402 mutex_enter(&hrcp->hrc_mutex);
403 ASSERT(hrcp->hrc_pm->hrc_pm_busy > 0);
404 hrcp->hrc_pm->hrc_pm_busy--;
405 mutex_exit(&hrcp->hrc_mutex);
406 }
407 mutex_enter(&hrcp->hrc_mutex);
408
409 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
410 "hwarc_pm_idle_component: %d", hrcp->hrc_pm->hrc_pm_busy);
411
412 }
413
414
415 /*
416 * hwarc_pwrlvl0:
417 * Functions to handle power transition for OS levels 0 -> 3
418 */
419 static int
hwarc_pwrlvl0(hwarc_state_t * hrcp)420 hwarc_pwrlvl0(hwarc_state_t *hrcp)
421 {
422 int rval;
423
424 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
425 "hwarc_pwrlvl0, dev_state: %x", hrcp->hrc_dev_state);
426
427 switch (hrcp->hrc_dev_state) {
428 case USB_DEV_ONLINE:
429 /* Deny the powerdown request if the device is busy */
430 if (hrcp->hrc_pm->hrc_pm_busy != 0) {
431 USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
432 "hwarc_pwrlvl0: hrc_pm_busy");
433
434 return (USB_FAILURE);
435 }
436
437 /* Close the interrupt pipe */
438 mutex_exit(&hrcp->hrc_mutex);
439 hwarc_close_intr_pipe(hrcp);
440 mutex_enter(&hrcp->hrc_mutex);
441
442 /* Issue USB D3 command to the device here */
443 rval = usb_set_device_pwrlvl3(hrcp->hrc_dip);
444 ASSERT(rval == USB_SUCCESS);
445
446 hrcp->hrc_dev_state = USB_DEV_PWRED_DOWN;
447 hrcp->hrc_pm->hrc_current_power = USB_DEV_OS_PWR_OFF;
448
449 /* FALLTHRU */
450 case USB_DEV_DISCONNECTED:
451 case USB_DEV_SUSPENDED:
452
453 return (USB_SUCCESS);
454
455 case USB_DEV_PWRED_DOWN:
456 default:
457 USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
458 "hwarc_pwrlvl0: illegal dev state");
459
460 return (USB_FAILURE);
461 }
462 }
463
464
465 /*
466 * hwarc_pwrlvl1:
467 * Functions to handle power transition to OS levels -> 2
468 */
469 static int
hwarc_pwrlvl1(hwarc_state_t * hrcp)470 hwarc_pwrlvl1(hwarc_state_t *hrcp)
471 {
472 int rval;
473
474 USB_DPRINTF_L4(PRINT_MASK_PM, hrcp->hrc_log_hdl, "hwarc_pwrlvl1");
475
476 /* Issue USB D2 command to the device here */
477 rval = usb_set_device_pwrlvl2(hrcp->hrc_dip);
478 ASSERT(rval == USB_SUCCESS);
479
480 return (USB_FAILURE);
481 }
482
483
484 /*
485 * hwarc_pwrlvl2:
486 * Functions to handle power transition to OS levels -> 1
487 */
488 static int
hwarc_pwrlvl2(hwarc_state_t * hrcp)489 hwarc_pwrlvl2(hwarc_state_t *hrcp)
490 {
491 int rval;
492
493 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
494 "hwarc_pwrlvl2, dev_stat=%d", hrcp->hrc_dev_state);
495
496 /* Issue USB D1 command to the device here */
497 rval = usb_set_device_pwrlvl1(hrcp->hrc_dip);
498 ASSERT(rval == USB_SUCCESS);
499
500 return (USB_FAILURE);
501 }
502
503
504 /*
505 * hwarc_pwrlvl3:
506 * Functions to handle power transition to OS level -> 0
507 */
508 static int
hwarc_pwrlvl3(hwarc_state_t * hrcp)509 hwarc_pwrlvl3(hwarc_state_t *hrcp)
510 {
511
512 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
513 "hwarc_pwrlvl3, dev_stat=%d", hrcp->hrc_dev_state);
514
515 switch (hrcp->hrc_dev_state) {
516 case USB_DEV_PWRED_DOWN:
517 /* Issue USB D0 command to the device here */
518 (void) usb_set_device_pwrlvl0(hrcp->hrc_dip);
519
520 mutex_exit(&hrcp->hrc_mutex);
521 if (hwarc_open_intr_pipe(hrcp) != USB_SUCCESS) {
522 mutex_enter(&hrcp->hrc_mutex);
523
524 return (USB_FAILURE);
525 }
526 mutex_enter(&hrcp->hrc_mutex);
527
528 /* Todo: Reset device or not */
529 hrcp->hrc_dev_state = USB_DEV_ONLINE;
530 hrcp->hrc_pm->hrc_current_power = USB_DEV_OS_FULL_PWR;
531
532 /* FALLTHRU */
533 case USB_DEV_ONLINE:
534 /* we are already in full power */
535 /* FALLTHRU */
536 case USB_DEV_DISCONNECTED:
537 case USB_DEV_SUSPENDED:
538 /*
539 * PM framework tries to put us in full power
540 * during system shutdown. If we are disconnected/cpr'ed
541 * return success anyways
542 */
543
544 return (USB_SUCCESS);
545
546 default:
547 USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
548 "hwarc_pwrlvl3: illegal dev state");
549
550 return (USB_FAILURE);
551 }
552 }
553
554 /* Init dev inst */
555 static void
hwarc_init_devinst(dev_info_t * dip,hwarc_state_t * hrcp)556 hwarc_init_devinst(dev_info_t *dip, hwarc_state_t *hrcp)
557 {
558 char *devinst;
559 int devinstlen;
560
561 hrcp->hrc_dip = dip;
562 hrcp->hrc_log_hdl = usb_alloc_log_hdl(dip,
563 "hwarc", &hwarc_errlevel,
564 &hwarc_errmask, &hwarc_instance_debug, 0);
565
566 devinst = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
567 devinstlen = snprintf(devinst, USB_MAXSTRINGLEN, "%s%d: ",
568 ddi_driver_name(dip), ddi_get_instance(dip));
569
570 hrcp->hrc_devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP);
571 (void) strncpy(hrcp->hrc_devinst, devinst, devinstlen);
572
573 kmem_free(devinst, USB_MAXSTRINGLEN);
574 }
575
576 /* init endpoints */
577 static int
hwarc_init_ep(dev_info_t * dip,hwarc_state_t * hrcp)578 hwarc_init_ep(dev_info_t *dip, hwarc_state_t *hrcp)
579 {
580 int status = USB_SUCCESS;
581 usb_ep_data_t *ep_datap;
582 if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) !=
583 USB_SUCCESS) {
584 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
585 "hwarc_init_ep: usb_client_attach failed"
586 " error code = %d", status);
587 goto done;
588 }
589
590 if ((status = usb_get_dev_data(dip, &hrcp->hrc_reg, USB_PARSE_LVL_ALL,
591 0)) != USB_SUCCESS) {
592 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
593 "hwarc_init_ep: usb_get_dev_data failed"
594 "error code = %d", status);
595 goto done;
596 }
597 hrcp->hrc_if_descr =
598 &hrcp->hrc_reg->dev_curr_cfg->cfg_if[hrcp->hrc_reg->dev_curr_if];
599 hrcp->hrc_default_ph = hrcp->hrc_reg->dev_default_ph;
600
601 /*
602 * Get the descriptor for an intr pipe at alt 0 of current interface.
603 * This will be used later to open the pipe.
604 */
605 if ((ep_datap = usb_lookup_ep_data(dip, hrcp->hrc_reg,
606 hrcp->hrc_reg->dev_curr_if, 0, 0,
607 USB_EP_ATTR_INTR, USB_EP_DIR_IN)) == NULL) {
608 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
609 "hwarc_init_ep: Error getting intr endpoint descriptor");
610 status = USB_FAILURE;
611 goto done;
612 }
613 hrcp->hrc_intr_ep_descr = ep_datap->ep_descr;
614
615 done:
616
617 return (status);
618 }
619 /* init mutex */
620 static void
hwarc_init_mutex(hwarc_state_t * hrcp)621 hwarc_init_mutex(hwarc_state_t *hrcp) {
622 mutex_init(&hrcp->hrc_mutex, NULL, MUTEX_DRIVER,
623 hrcp->hrc_reg->dev_iblock_cookie);
624
625 cv_init(&hrcp->hrc_serial_cv, NULL, CV_DRIVER, NULL);
626 hrcp->hrc_serial_inuse = B_FALSE;
627
628 hrcp->hrc_locks_initialized = B_TRUE;
629 }
630 /*
631 * hwarc_attach:
632 * Attach or resume.
633 *
634 * For attach, initialize state and device, including:
635 * state variables, locks, device node
636 * device registration with system
637 * power management, hotplugging
638 * For resume, restore device and state
639 */
640 static int
hwarc_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)641 hwarc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
642 {
643 int instance = ddi_get_instance(dip);
644 hwarc_state_t *hrcp = NULL;
645
646 switch (cmd) {
647 case DDI_ATTACH:
648 break;
649
650 case DDI_RESUME:
651 hwarc_cpr_resume(dip);
652 /*
653 * Always return success to work around enumeration
654 * failures.This works around an issue where devices
655 * which are present before a suspend and absent upon
656 * resume could cause a system panic on resume.
657 */
658
659 return (DDI_SUCCESS);
660 default:
661 return (DDI_FAILURE);
662 }
663
664 if (ddi_soft_state_zalloc(hwarc_statep, instance) == DDI_SUCCESS) {
665 hrcp = ddi_get_soft_state(hwarc_statep, instance);
666 }
667 if (hrcp == NULL) {
668 USB_DPRINTF_L2(PRINT_MASK_ATTA, NULL,
669 "hwarc_attach: get soft state failed for instance %d",
670 instance);
671
672 return (DDI_FAILURE);
673 }
674
675 (void) hwarc_init_devinst(dip, hrcp);
676
677 if (hwarc_init_ep(dip, hrcp) != USB_SUCCESS) {
678 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
679 "attach: Error init usb data");
680 goto fail;
681 }
682 hwarc_init_mutex(hrcp);
683
684 /* create minor node */
685 if (ddi_create_minor_node(dip, name, S_IFCHR, instance,
686 NULL, 0) != DDI_SUCCESS) {
687 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
688 "attach: Error creating minor node");
689 goto fail;
690 }
691
692 /* initialize power management */
693 hwarc_init_power_mgmt(hrcp);
694
695 if (usb_register_hotplug_cbs(dip, hwarc_disconnect_callback,
696 hwarc_reconnect_callback) != USB_SUCCESS) {
697 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
698 "attach: Error register hotplug cbs");
699
700 goto fail;
701 }
702
703 /* register this device to uwba */
704 uwb_dev_attach(dip, &hrcp->hrc_dev_hdl, 0, hwarc_send_cmd);
705
706 if (hwarc_open_intr_pipe(hrcp) != USB_SUCCESS) {
707 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
708 "attach: Error open intr pipe");
709
710 goto fail;
711 }
712
713 /* reset device */
714 if (hwarc_reset_device(hrcp) != USB_SUCCESS) {
715 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
716 "attach: Error reset deivce");
717 goto fail;
718 }
719 /* init phy capabilities */
720 if (hwarc_init_phy(hrcp) != USB_SUCCESS) {
721 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
722 "attach: Error get phy ie");
723
724 goto fail;
725 }
726 /* Report device */
727 ddi_report_dev(dip);
728
729 mutex_enter(&hrcp->hrc_mutex);
730 hwarc_pm_idle_component(hrcp);
731 mutex_exit(&hrcp->hrc_mutex);
732
733 return (DDI_SUCCESS);
734
735 fail:
736 (void) hwarc_cleanup(dip, hrcp);
737
738 return (DDI_FAILURE);
739 }
740
741
742 /*
743 * hwarc_detach:
744 * detach or suspend driver instance
745 *
746 * Note: in detach, only contention threads is from pm and disconnnect.
747 */
748 static int
hwarc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)749 hwarc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
750 {
751 int rval = USB_SUCCESS;
752 hwarc_state_t *hrcp =
753 ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
754
755 USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
756 "hwarc_detach: enter for detach, cmd = %d", cmd);
757
758
759 switch (cmd) {
760 case DDI_DETACH:
761
762 rval = hwarc_cleanup(dip, hrcp);
763
764 break;
765 case DDI_SUSPEND:
766
767 rval = hwarc_cpr_suspend(dip);
768 default:
769
770 break;
771 }
772
773 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
774 }
775
776
777 /*
778 * hwarc_cleanup:
779 * clean up the driver state for detach
780 */
781 static int
hwarc_cleanup(dev_info_t * dip,hwarc_state_t * hrcp)782 hwarc_cleanup(dev_info_t *dip, hwarc_state_t *hrcp)
783 {
784 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "Cleanup: enter");
785
786 if (hrcp->hrc_locks_initialized) {
787
788 (void) uwb_stop_beacon(dip);
789 /* This must be done 1st to prevent more events from coming. */
790 usb_unregister_hotplug_cbs(dip);
791
792 hwarc_close_intr_pipe(hrcp);
793
794 /*
795 * At this point, no new activity can be initiated. The driver
796 * has disabled hotplug callbacks. The Solaris framework has
797 * disabled new opens on a device being detached, and does not
798 * allow detaching an open device.
799 *
800 * The following ensures that all driver activity has drained.
801 */
802 mutex_enter(&hrcp->hrc_mutex);
803 (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
804 hwarc_release_access(hrcp);
805 mutex_exit(&hrcp->hrc_mutex);
806
807 /* All device activity has died down. */
808 hwarc_destroy_power_mgmt(hrcp);
809
810 /* start dismantling */
811 ddi_remove_minor_node(dip, NULL);
812 cv_destroy(&hrcp->hrc_serial_cv);
813 mutex_destroy(&hrcp->hrc_mutex);
814 }
815
816 usb_client_detach(dip, hrcp->hrc_reg);
817
818 USB_DPRINTF_L4(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "Cleanup: end");
819
820 usb_free_log_hdl(hrcp->hrc_log_hdl);
821
822 uwb_dev_detach(hrcp->hrc_dev_hdl);
823
824 kmem_free(hrcp->hrc_devinst, strlen(hrcp->hrc_devinst) + 1);
825
826 ddi_soft_state_free(hwarc_statep, ddi_get_instance(dip));
827 ddi_prop_remove_all(dip);
828
829 return (USB_SUCCESS);
830 }
831
832
833
834 /*ARGSUSED*/
835 static int
hwarc_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)836 hwarc_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
837 {
838 hwarc_state_t *hrcp = NULL;
839 int rval = 0;
840
841 hrcp = ddi_get_soft_state(hwarc_statep, getminor(*devp));
842
843 ASSERT(hrcp != NULL);
844
845 USB_DPRINTF_L4(PRINT_MASK_OPEN, hrcp->hrc_log_hdl, "hwarc_open: enter");
846
847 /*
848 * Keep it simple: one client at a time.
849 * Exclusive open only
850 */
851 mutex_enter(&hrcp->hrc_mutex);
852 /* exclusive open */
853 if ((flag & FEXCL) && (hrcp->hrc_open_count > 0)) {
854 USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
855 "hwarc_open failed, open count=%d", hrcp->hrc_open_count);
856 mutex_exit(&hrcp->hrc_mutex);
857
858 return (EBUSY);
859 }
860
861 if ((hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) ||
862 (hrcp->hrc_dev_state == USB_DEV_SUSPENDED)) {
863
864 USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
865 "hwarc_open failed, dev_stat=%d", hrcp->hrc_dev_state);
866 mutex_exit(&hrcp->hrc_mutex);
867
868 return (EIO);
869 }
870
871 hrcp->hrc_open_count++;
872
873 USB_DPRINTF_L3(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
874 "hwarc_open, open count=%d", hrcp->hrc_open_count);
875 if (hwarc_serialize_access(hrcp, HWARC_SER_SIG) == 0) {
876 hrcp->hrc_open_count--;
877 hwarc_release_access(hrcp);
878 mutex_exit(&hrcp->hrc_mutex);
879
880 return (EINTR);
881 }
882
883 hwarc_pm_busy_component(hrcp);
884
885 mutex_exit(&hrcp->hrc_mutex);
886 (void) pm_raise_power(hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
887
888 mutex_enter(&hrcp->hrc_mutex);
889 /* Fail if device is no longer ready. */
890 if (hrcp->hrc_dev_state != USB_DEV_ONLINE) {
891 USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
892 "hwarc_open failed, dev_stat=%d", hrcp->hrc_dev_state);
893 rval = EIO;
894 }
895 hwarc_release_access(hrcp);
896 /* Device specific initialization goes here. */
897 if (rval != 0) {
898 hrcp->hrc_open_count--;
899 hwarc_pm_idle_component(hrcp);
900 }
901 mutex_exit(&hrcp->hrc_mutex);
902
903 USB_DPRINTF_L4(PRINT_MASK_OPEN, hrcp->hrc_log_hdl, "hwarc_open: leave");
904
905 return (0);
906 }
907
908
909 /*ARGSUSED*/
910 static int
hwarc_close(dev_t dev,int flag,int otyp,cred_t * cred_p)911 hwarc_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
912 {
913 hwarc_state_t *hrcp =
914 ddi_get_soft_state(hwarc_statep, getminor(dev));
915
916 USB_DPRINTF_L4(PRINT_MASK_CLOSE, hrcp->hrc_log_hdl,
917 "hwarc_close: enter");
918
919 mutex_enter(&hrcp->hrc_mutex);
920 (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
921
922 hrcp->hrc_open_count--;
923 USB_DPRINTF_L3(PRINT_MASK_CLOSE, hrcp->hrc_log_hdl,
924 "hwarc_close: open count=%d", hrcp->hrc_open_count);
925
926 hwarc_release_access(hrcp);
927 hwarc_pm_idle_component(hrcp);
928
929 mutex_exit(&hrcp->hrc_mutex);
930
931 USB_DPRINTF_L4(PRINT_MASK_CLOSE, hrcp->hrc_log_hdl,
932 "hwarc_close: leave");
933
934 return (0);
935 }
936
937 /* Send cmd to hwarc device */
938 int
hwarc_send_cmd(uwb_dev_handle_t uwb_dev_hdl,mblk_t * data,uint16_t data_len)939 hwarc_send_cmd(uwb_dev_handle_t uwb_dev_hdl, mblk_t *data, uint16_t data_len)
940 {
941 usb_cb_flags_t cb_flags;
942 usb_cr_t cr;
943 usb_ctrl_setup_t setup;
944 int rval;
945 hwarc_state_t *hrcp = NULL;
946 dev_info_t *dip = uwb_get_dip(uwb_dev_hdl);
947
948 hrcp = ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
949
950 ASSERT((hrcp != NULL) && (data != NULL));
951
952 setup.bmRequestType = HWARC_SET_IF;
953 setup.bRequest = HWA_EXEC_RC_CMD;
954
955 setup.wValue = 0;
956 setup.wIndex = hrcp->hrc_if_descr->if_alt->altif_descr.bInterfaceNumber;
957
958 setup.wLength = data_len;
959 setup.attrs = 0;
960
961 USB_DPRINTF_L3(PRINT_MASK_DEVCTRL, hrcp->hrc_log_hdl,
962 "hwarc_send_cmd: wLength=%d, data[0], [1], [2], [3]=%d, %d, %d, %d",
963 setup.wLength, data->b_rptr[0], data->b_rptr[1], data->b_rptr[2],
964 data->b_rptr[3]);
965
966 if ((rval = usb_pipe_ctrl_xfer_wait(hrcp->hrc_default_ph, &setup,
967 &data, &cr, &cb_flags, 0)) != USB_SUCCESS) {
968 USB_DPRINTF_L2(PRINT_MASK_DEVCTRL, hrcp->hrc_log_hdl,
969 "hwarc_send_cmd: fail, rval=%d, cr=%d, "
970 "cb_flags=%x", rval, cr, cb_flags);
971
972 }
973
974 freemsg(data);
975
976 return (rval);
977 }
978
979 /* ioctl, call uwb ioctl */
980 /*ARGSUSED*/
981 static int
hwarc_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)982 hwarc_ioctl(dev_t dev, int cmd, intptr_t arg,
983 int mode, cred_t *cred_p, int *rval_p)
984 {
985 int rv = 0;
986
987 hwarc_state_t *hrcp =
988 ddi_get_soft_state(hwarc_statep, getminor(dev));
989 if (hrcp == NULL) {
990
991 return (ENXIO);
992 }
993
994 if (drv_priv(cred_p) != 0) {
995 USB_DPRINTF_L3(PRINT_MASK_ALL, hrcp->hrc_log_hdl,
996 "hwahc_wusb_ioctl: user must have SYS_DEVICE privilege,"
997 "cmd=%x", cmd);
998
999 return (EPERM);
1000 }
1001
1002
1003
1004 USB_DPRINTF_L4(PRINT_MASK_ALL, hrcp->hrc_log_hdl, "hwarc_ioctl: enter");
1005
1006 mutex_enter(&hrcp->hrc_mutex);
1007 if (hrcp->hrc_dev_state != USB_DEV_ONLINE) {
1008 USB_DPRINTF_L2(PRINT_MASK_ALL, hrcp->hrc_log_hdl,
1009 "ioctl: Device is not online,"
1010 " dev_stat=%d", hrcp->hrc_dev_state);
1011 mutex_exit(&hrcp->hrc_mutex);
1012
1013 return (EFAULT);
1014 }
1015 mutex_exit(&hrcp->hrc_mutex);
1016
1017 rv = uwb_do_ioctl(hrcp->hrc_dev_hdl, cmd, arg, mode);
1018
1019 return (rv);
1020 }
1021
1022
1023 /*
1024 * hwarc_disconnect_callback:
1025 * Called when device hotplug-removed.
1026 * Close pipes. (This does not attempt to contact device.)
1027 * Set state to DISCONNECTED
1028 */
1029 static int
hwarc_disconnect_callback(dev_info_t * dip)1030 hwarc_disconnect_callback(dev_info_t *dip)
1031 {
1032 hwarc_state_t *hrcp =
1033 ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
1034
1035 USB_DPRINTF_L4(PRINT_MASK_CB, hrcp->hrc_log_hdl, "disconnect: enter");
1036
1037 /* Disconnect the uwb device will stop beacon and save state */
1038 (void) uwb_dev_disconnect(dip);
1039 hwarc_close_intr_pipe(hrcp);
1040
1041 mutex_enter(&hrcp->hrc_mutex);
1042 (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1043
1044 /*
1045 * Save any state of device or IO in progress required by
1046 * hwarc_restore_device_state for proper device "thawing" later.
1047 */
1048 hrcp->hrc_dev_state = USB_DEV_DISCONNECTED;
1049
1050 hwarc_release_access(hrcp);
1051 mutex_exit(&hrcp->hrc_mutex);
1052
1053 return (USB_SUCCESS);
1054 }
1055
1056
1057 /*
1058 * hwarc_reconnect_callback:
1059 * Called with device hotplug-inserted
1060 * Restore state
1061 */
1062 static int
hwarc_reconnect_callback(dev_info_t * dip)1063 hwarc_reconnect_callback(dev_info_t *dip)
1064 {
1065 int instance = ddi_get_instance(dip);
1066 hwarc_state_t *hrcp =
1067 ddi_get_soft_state(hwarc_statep, instance);
1068
1069 USB_DPRINTF_L4(PRINT_MASK_CB, hrcp->hrc_log_hdl, "reconnect: enter");
1070
1071 mutex_enter(&hrcp->hrc_mutex);
1072 (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1073 hwarc_restore_device_state(dip, hrcp);
1074 hwarc_release_access(hrcp);
1075 mutex_exit(&hrcp->hrc_mutex);
1076
1077 /* Reconnect the uwb device will restore uwb device state */
1078 (void) uwb_dev_reconnect(dip);
1079 return (USB_SUCCESS);
1080 }
1081
1082
1083 /*
1084 * hwarc_restore_device_state:
1085 * Called during hotplug-reconnect and resume.
1086 * reenable power management
1087 * Verify the device is the same as before the disconnect/suspend.
1088 * Restore device state
1089 * Thaw any IO which was frozen.
1090 * Quiesce device. (Other routines will activate if thawed IO.)
1091 * Set device online.
1092 * Leave device disconnected if there are problems.
1093 */
1094 static void
hwarc_restore_device_state(dev_info_t * dip,hwarc_state_t * hrcp)1095 hwarc_restore_device_state(dev_info_t *dip, hwarc_state_t *hrcp)
1096 {
1097
1098 USB_DPRINTF_L4(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1099 "hwarc_restore_device_state: enter");
1100
1101 ASSERT(mutex_owned(&hrcp->hrc_mutex));
1102
1103 ASSERT((hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) ||
1104 (hrcp->hrc_dev_state == USB_DEV_SUSPENDED));
1105
1106 hwarc_pm_busy_component(hrcp);
1107
1108 mutex_exit(&hrcp->hrc_mutex);
1109
1110 (void) pm_raise_power(hrcp->hrc_dip, 0, USB_DEV_OS_FULL_PWR);
1111
1112 if (usb_check_same_device(dip, hrcp->hrc_log_hdl, USB_LOG_L2,
1113 PRINT_MASK_ALL, USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS) {
1114 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1115 "hwarc_restore_device_state: check same device failed");
1116
1117 goto fail;
1118
1119 }
1120 if (hwarc_open_intr_pipe(hrcp) != USB_SUCCESS) {
1121
1122 goto fail;
1123 }
1124 mutex_enter(&hrcp->hrc_mutex);
1125
1126 hrcp->hrc_dev_state = USB_DEV_ONLINE;
1127
1128 if (hrcp->hrc_pm && hrcp->hrc_pm->hrc_wakeup_enabled) {
1129
1130 mutex_exit(&hrcp->hrc_mutex);
1131 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) !=
1132 USB_SUCCESS) {
1133 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1134 "hwarc_restore_device_state: "
1135 "fail to enable device remote wakeup");
1136 }
1137 mutex_enter(&hrcp->hrc_mutex);
1138
1139 }
1140
1141 hwarc_pm_idle_component(hrcp);
1142
1143 USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1144 "hwarc_restore_device_state: end");
1145
1146 return;
1147
1148 fail:
1149 /* change the device state from suspended to disconnected */
1150 mutex_enter(&hrcp->hrc_mutex);
1151 hrcp->hrc_dev_state = USB_DEV_DISCONNECTED;
1152 hwarc_pm_idle_component(hrcp);
1153 }
1154
1155
1156 /*
1157 * hwarc_cpr_suspend:
1158 * Clean up device.
1159 * Wait for any IO to finish, then close pipes.
1160 * Quiesce device.
1161 */
1162 static int
hwarc_cpr_suspend(dev_info_t * dip)1163 hwarc_cpr_suspend(dev_info_t *dip)
1164 {
1165 hwarc_state_t *hrcp = ddi_get_soft_state(hwarc_statep,
1166 ddi_get_instance(dip));
1167
1168 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1169 "hwarc_cpr_suspend, dev_stat=%d", hrcp->hrc_dev_state);
1170
1171 /* Disconnect the uwb device will stop beacon and save state */
1172 (void) uwb_dev_disconnect(dip);
1173
1174 /* Serialize to prevent races with detach, open, device access. */
1175 mutex_enter(&hrcp->hrc_mutex);
1176 (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1177
1178 hwarc_pm_busy_component(hrcp);
1179
1180 /*
1181 * Set dev_state to suspended so other driver threads don't start any
1182 * new I/O. In a real driver, there may be draining of requests done
1183 * afterwards, and we don't want the draining to compete with new
1184 * requests being queued.
1185 */
1186
1187 /* Don't suspend if the device is open. */
1188 if (hrcp->hrc_open_count != 0) {
1189 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1190 "suspend: Device is open. Can't suspend");
1191
1192 hwarc_release_access(hrcp);
1193 hwarc_pm_idle_component(hrcp);
1194 mutex_exit(&hrcp->hrc_mutex);
1195
1196 return (USB_FAILURE);
1197 }
1198
1199 /* Access device here to clean it up. */
1200 mutex_exit(&hrcp->hrc_mutex);
1201 hwarc_close_intr_pipe(hrcp);
1202 mutex_enter(&hrcp->hrc_mutex);
1203
1204 hrcp->hrc_dev_state = USB_DEV_SUSPENDED;
1205
1206 /*
1207 * Save any state of device required by hwarc_restore_device_state
1208 * for proper device "thawing" later.
1209 */
1210 hwarc_release_access(hrcp);
1211 hwarc_pm_idle_component(hrcp);
1212 mutex_exit(&hrcp->hrc_mutex);
1213
1214 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl, "suspend: success");
1215
1216 return (USB_SUCCESS);
1217 }
1218
1219
1220 /*
1221 * hwarc_cpr_resume:
1222 *
1223 * hwarc_restore_device_state marks success by putting device back online
1224 */
1225 static void
hwarc_cpr_resume(dev_info_t * dip)1226 hwarc_cpr_resume(dev_info_t *dip)
1227 {
1228 int instance = ddi_get_instance(dip);
1229 hwarc_state_t *hrcp = ddi_get_soft_state(hwarc_statep,
1230 instance);
1231
1232 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1233 "hwarc_cpr_resume, dev_stat=%d", hrcp->hrc_dev_state);
1234
1235 /*
1236 * NOTE: A pm_raise_power in hwarc_restore_device_state will bring
1237 * the power-up state of device into synch with the system.
1238 */
1239 mutex_enter(&hrcp->hrc_mutex);
1240 hwarc_restore_device_state(dip, hrcp);
1241 mutex_exit(&hrcp->hrc_mutex);
1242
1243 /* Reconnect the uwb device will restore uwb device state */
1244 (void) uwb_dev_reconnect(dip);
1245 }
1246
1247 /*
1248 * pipe callbacks
1249 * --------------
1250 *
1251 * intr in callback for event receiving for hwarc device
1252 */
1253 /*ARGSUSED*/
1254 void
hwarc_intr_cb(usb_pipe_handle_t pipe,usb_intr_req_t * req)1255 hwarc_intr_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req)
1256 {
1257 hwarc_state_t *hrcp = (hwarc_state_t *)req->intr_client_private;
1258 uwb_dev_handle_t uwb_dev_hd;
1259 mblk_t *data = req->intr_data;
1260 int data_len, parse_err;
1261
1262 uwb_dev_hd = hrcp->hrc_dev_hdl;
1263 data_len = (data) ? MBLKL(data) : 0;
1264
1265 if (data_len == 0) {
1266
1267 return;
1268 }
1269
1270 /*
1271 * Parse the event/notifications from the device, and cv_signal the
1272 * waiting cmd
1273 */
1274 parse_err = uwb_parse_evt_notif((uint8_t *)data->b_rptr,
1275 data_len, uwb_dev_hd);
1276 if (parse_err != UWB_SUCCESS) {
1277 USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1278 "hwarc_intr_cb: parse failed, no cmd result or "
1279 "notifs delivered. parse_err= %d", parse_err);
1280 if (data_len >= 5) {
1281 USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1282 "hwarc_intr_cb: erro evt len=%d"
1283 " evtcode=%d %d,evt_context=%d, result-code=%d",
1284 data_len, data->b_rptr[1], data->b_rptr[2],
1285 data->b_rptr[3], data->b_rptr[4]);
1286 }
1287 }
1288
1289 usb_free_intr_req(req);
1290 }
1291
1292 /*
1293 * pipe callbacks
1294 * --------------
1295 *
1296 * intr in exception callback
1297 */
1298 void
hwarc_intr_ex_cb(usb_pipe_handle_t pipe,usb_intr_req_t * req)1299 hwarc_intr_ex_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req)
1300 {
1301 hwarc_state_t *hrcp = (hwarc_state_t *)req->intr_client_private;
1302 usb_cr_t cr = req->intr_completion_reason;
1303
1304 USB_DPRINTF_L4(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1305 "hwarc_intr_ex_cb: ph = 0x%p req = 0x%p cr=%d flags=%x",
1306 (void *)pipe, (void *)req, cr, req->intr_cb_flags);
1307
1308 usb_free_intr_req(req);
1309
1310 /* restart polling */
1311 if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING) &&
1312 (cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) &&
1313 (cr != USB_CR_PIPE_RESET) &&
1314 (hrcp->hrc_dev_state == USB_DEV_ONLINE)) {
1315 if (hwarc_start_polling(hrcp, hrcp->hrc_intr_ph) !=
1316 USB_SUCCESS) {
1317 USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1318 "hwarc_intr_ex_cb:"
1319 "Restart pollling failed.");
1320 }
1321 } else {
1322 USB_DPRINTF_L2(PRINT_MASK_CB, hrcp->hrc_log_hdl,
1323 "hwarc_intr_ex_cb:"
1324 "get events failed: cr=%d", cr);
1325 }
1326 }
1327
1328 /*
1329 * start polling on the interrupt pipe for events
1330 */
1331 int
hwarc_start_polling(hwarc_state_t * hrcp,usb_pipe_handle_t intr_ph)1332 hwarc_start_polling(hwarc_state_t *hrcp, usb_pipe_handle_t intr_ph)
1333 {
1334 usb_intr_req_t *br;
1335 int rval = USB_SUCCESS;
1336
1337 USB_DPRINTF_L3(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
1338 "hwarc_start_polling");
1339
1340 br = usb_alloc_intr_req(hrcp->hrc_dip, 0, USB_FLAGS_SLEEP);
1341
1342 if (!br) {
1343 USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
1344 "hwarc_start_polling: alloc req failed.");
1345
1346 return (USB_FAILURE);
1347 }
1348 br->intr_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
1349 br->intr_len = hrcp->hrc_intr_ep_descr.wMaxPacketSize;
1350 br->intr_client_private = (void *)hrcp;
1351
1352 br->intr_cb = hwarc_intr_cb;
1353 br->intr_exc_cb = hwarc_intr_ex_cb;
1354
1355 rval = usb_pipe_intr_xfer(intr_ph, br, USB_FLAGS_SLEEP);
1356
1357 if (rval != USB_SUCCESS) {
1358 usb_free_intr_req(br);
1359
1360 USB_DPRINTF_L2(PRINT_MASK_OPEN, hrcp->hrc_log_hdl,
1361 "hwarc_start_polling: failed (%d)", rval);
1362 }
1363
1364 return (rval);
1365 }
1366
1367 /*
1368 * hwarc_open_intr_pipe:
1369 * Open any pipes other than default pipe.
1370 * Mutex is assumed to be held.
1371 */
1372 static int
hwarc_open_intr_pipe(hwarc_state_t * hrcp)1373 hwarc_open_intr_pipe(hwarc_state_t *hrcp)
1374 {
1375
1376 int rval = USB_SUCCESS;
1377 usb_pipe_policy_t pipe_policy;
1378 usb_pipe_handle_t pipe_handle;
1379
1380 USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "open_pipes enter");
1381
1382 bzero(&pipe_policy, sizeof (pipe_policy));
1383
1384 /*
1385 * Allow that pipes can support at least two asynchronous operations
1386 * going on simultaneously. Operations include asynchronous callbacks,
1387 * resets, closures.
1388 */
1389 pipe_policy.pp_max_async_reqs = 2;
1390
1391 if ((rval = usb_pipe_open(hrcp->hrc_dip,
1392 &hrcp->hrc_intr_ep_descr, &pipe_policy,
1393 USB_FLAGS_SLEEP, &pipe_handle)) != USB_SUCCESS) {
1394 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1395 "hwarc_open_intr_pipe:Error opening intr pipe: status = %d",
1396 rval);
1397 goto done;
1398 }
1399
1400 mutex_enter(&hrcp->hrc_mutex);
1401 hrcp->hrc_intr_ph = pipe_handle;
1402 mutex_exit(&hrcp->hrc_mutex);
1403
1404 /*
1405 * At this point, polling could be started on the pipe by making an
1406 * asynchronous input request on the pipe. Allocate a request by
1407 * calling usb_alloc_intr_req(9F) with a zero length, initialize
1408 * attributes with USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING,
1409 * initialize length to be packetsize of the endpoint, specify the
1410 * callbacks. Pass this request to usb_pipe_intr_xfer to start polling.
1411 * Call usb_pipe_stop_intr_poling(9F) to stop polling.
1412 */
1413 rval = hwarc_start_polling(hrcp, hrcp->hrc_intr_ph);
1414 if (rval != USB_SUCCESS) {
1415 hwarc_close_intr_pipe(hrcp);
1416
1417 USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1418 "hwarc_open_intr_pipe: Error start "
1419 "polling intr pipe: rval = %d", rval);
1420 }
1421
1422 done:
1423
1424 return (rval);
1425 }
1426
1427
1428 /*
1429 * hwarc_close_intr_pipe:
1430 * Close pipes. Mutex is assumed to be held.
1431 */
1432 static void
hwarc_close_intr_pipe(hwarc_state_t * hrcp)1433 hwarc_close_intr_pipe(hwarc_state_t *hrcp)
1434 {
1435 usb_pipe_handle_t pipe_handle = NULL;
1436 USB_DPRINTF_L3(PRINT_MASK_ATTA, hrcp->hrc_log_hdl, "close_pipes enter");
1437
1438 mutex_enter(&hrcp->hrc_mutex);
1439 if (!hrcp->hrc_intr_ph) {
1440 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1441 "hwarc intr pipe not exist");
1442 mutex_exit(&hrcp->hrc_mutex);
1443 return;
1444 }
1445
1446 pipe_handle = hrcp->hrc_intr_ph;
1447 hrcp->hrc_intr_ph = NULL;
1448 mutex_exit(&hrcp->hrc_mutex);
1449
1450 /* Stop polling */
1451 usb_pipe_stop_intr_polling(pipe_handle, USB_FLAGS_SLEEP);
1452
1453 /* Close Pipe */
1454 usb_pipe_close(hrcp->hrc_dip, pipe_handle, USB_FLAGS_SLEEP, NULL, 0);
1455 }
1456
1457 /*
1458 * hwarc_power :
1459 * Power entry point, the workhorse behind pm_raise_power, pm_lower_power,
1460 * usb_req_raise_power and usb_req_lower_power.
1461 */
1462 /*ARGSUSED*/
1463 static int
hwarc_power(dev_info_t * dip,int comp,int level)1464 hwarc_power(dev_info_t *dip, int comp, int level)
1465 {
1466 hwarc_state_t *hrcp;
1467 int rval = USB_FAILURE;
1468
1469 hrcp = ddi_get_soft_state(hwarc_statep, ddi_get_instance(dip));
1470
1471 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1472 "hwarc_power: level = %d", level);
1473
1474 mutex_enter(&hrcp->hrc_mutex);
1475
1476 ASSERT(hrcp->hrc_pm != NULL);
1477
1478 (void) hwarc_serialize_access(hrcp, HWARC_SER_NOSIG);
1479
1480 /*
1481 * If we are disconnected/suspended, return success. Note that if we
1482 * return failure, bringing down the system will hang when
1483 * PM tries to power up all devices
1484 */
1485 if ((hrcp->hrc_dev_state == USB_DEV_DISCONNECTED) ||
1486 (hrcp->hrc_dev_state == USB_DEV_SUSPENDED)) {
1487
1488 USB_DPRINTF_L3(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1489 "hwarc_power: disconnected/suspended "
1490 "dev_state=%d", hrcp->hrc_dev_state);
1491 rval = USB_SUCCESS;
1492
1493 goto done;
1494 }
1495
1496
1497 /* Check if we are transitioning to a legal power level */
1498 if (USB_DEV_PWRSTATE_OK(hrcp->hrc_pm->hrc_pwr_states, level)) {
1499 USB_DPRINTF_L2(PRINT_MASK_PM, hrcp->hrc_log_hdl,
1500 "hwarc_power: illegal power level = %d "
1501 "pwr_states: %x", level, hrcp->hrc_pm->hrc_pwr_states);
1502
1503 goto done;
1504 }
1505
1506 switch (level) {
1507 case USB_DEV_OS_PWR_OFF :
1508 rval = hwarc_pwrlvl0(hrcp);
1509
1510 break;
1511 case USB_DEV_OS_PWR_1:
1512 rval = hwarc_pwrlvl1(hrcp);
1513
1514 break;
1515 case USB_DEV_OS_PWR_2:
1516 rval = hwarc_pwrlvl2(hrcp);
1517
1518 break;
1519 case USB_DEV_OS_FULL_PWR :
1520 rval = hwarc_pwrlvl3(hrcp);
1521
1522 break;
1523 }
1524
1525 done:
1526 hwarc_release_access(hrcp);
1527 mutex_exit(&hrcp->hrc_mutex);
1528
1529 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
1530 }
1531
1532
1533 /*
1534 * hwarc_serialize_access:
1535 * Get the serial synchronization object before returning.
1536 *
1537 * Arguments:
1538 * hrcp - Pointer to hwarc state structure
1539 * waitsig - Set to:
1540 * HWARC_SER_SIG - to wait such that a signal can interrupt
1541 * HWARC_SER_NOSIG - to wait such that a signal cannot interrupt
1542 */
1543 static int
hwarc_serialize_access(hwarc_state_t * hrcp,boolean_t waitsig)1544 hwarc_serialize_access(hwarc_state_t *hrcp, boolean_t waitsig)
1545 {
1546 int rval = 1;
1547
1548 ASSERT(mutex_owned(&hrcp->hrc_mutex));
1549
1550 while (hrcp->hrc_serial_inuse) {
1551 if (waitsig == HWARC_SER_SIG) {
1552 rval = cv_wait_sig(&hrcp->hrc_serial_cv,
1553 &hrcp->hrc_mutex);
1554 } else {
1555 cv_wait(&hrcp->hrc_serial_cv,
1556 &hrcp->hrc_mutex);
1557 }
1558 }
1559 hrcp->hrc_serial_inuse = B_TRUE;
1560
1561 return (rval);
1562 }
1563
1564
1565 /*
1566 * hwarc_release_access:
1567 * Release the serial synchronization object.
1568 */
1569 static void
hwarc_release_access(hwarc_state_t * hrcp)1570 hwarc_release_access(hwarc_state_t *hrcp)
1571 {
1572 ASSERT(mutex_owned(&hrcp->hrc_mutex));
1573 hrcp->hrc_serial_inuse = B_FALSE;
1574 cv_broadcast(&hrcp->hrc_serial_cv);
1575 }
1576
1577
1578 /*
1579 * hwarc_reset_device:
1580 * Reset the readio controller with uwb interfaces.
1581 * if the device is different. Can block.
1582 */
1583 static int
hwarc_reset_device(hwarc_state_t * hrcp)1584 hwarc_reset_device(hwarc_state_t *hrcp)
1585 {
1586 if (uwb_reset_dev(hrcp->hrc_dip) != UWB_SUCCESS) {
1587 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1588 "hwarc_reset_device: uwb_reset_dev failed");
1589
1590 return (USB_FAILURE);
1591 }
1592
1593 return (USB_SUCCESS);
1594 }
1595
1596 /*
1597 * hwarc_init_phy
1598 * init the physical capabilities of the radio controller.
1599 * the band groups and phy rates will be initialized in the
1600 * uwb devices.
1601 */
1602 static int
hwarc_init_phy(hwarc_state_t * hrcp)1603 hwarc_init_phy(hwarc_state_t *hrcp)
1604 {
1605 if (uwb_init_phy(hrcp->hrc_dip) != UWB_SUCCESS) {
1606 USB_DPRINTF_L2(PRINT_MASK_ATTA, hrcp->hrc_log_hdl,
1607 "hwarc_init_phy: uwb_init_phy failed");
1608
1609 return (USB_FAILURE);
1610 }
1611
1612 return (USB_SUCCESS);
1613 }
1614