xref: /onnv-gate/usr/src/uts/common/io/usb/clients/wusb_df/wusb_df.c (revision 9430:637732b28916)
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  * This driver is to be used for download firmware for devices.
29  */
30 
31 #if defined(lint) && !defined(DEBUG)
32 #define	DEBUG
33 #endif
34 
35 #define	USBDRV_MAJOR_VER	2
36 #define	USBDRV_MINOR_VER	0
37 
38 #include <sys/kobj.h>
39 #include <sys/usb/usba.h>
40 #include <sys/usb/usba/usbai_private.h>
41 #include <sys/usb/clients/wusb_df/wusb_df.h>
42 
43 #define	WUSB_DF_INITIAL_SOFT_SPACE	1
44 #define	MAX_DAT_FILE_SIZE	(512 * 1024)
45 
46 uint_t	wusb_df_errlevel = USB_LOG_L4;
47 uint_t  wusb_df_errmask   = (uint_t)PRINT_MASK_ALL;
48 uint_t  wusb_df_instance_debug = (uint_t)-1;
49 static char	*name = "wusb_df";	/* Driver name, used all over. */
50 static char wusb_fwmod[] = "hwa1480_fw";
51 static char wusb_fwsym1[] = "hwa1480_fw";
52 
53 /* Soft state structures */
54 static void *wusb_df_statep;
55 
56 /*
57  * Function Prototypes
58  */
59 static int	wusb_df_attach(dev_info_t *, ddi_attach_cmd_t);
60 static int	wusb_df_detach(dev_info_t *, ddi_detach_cmd_t);
61 static int	wusb_df_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
62 static int	wusb_df_cleanup(dev_info_t *, wusb_df_state_t *);
63 static int	wusb_df_disconnect_callback(dev_info_t *);
64 static int	wusb_df_reconnect_callback(dev_info_t *);
65 static void	wusb_df_restore_device_state(dev_info_t *, wusb_df_state_t *);
66 static int	wusb_df_cpr_suspend(dev_info_t *);
67 static void	wusb_df_cpr_resume(dev_info_t *);
68 static void	wusb_df_pm_busy_component(wusb_df_state_t *);
69 static void	wusb_df_pm_idle_component(wusb_df_state_t *);
70 static int	wusb_df_power(dev_info_t *, int, int);
71 static void	wusb_df_init_power_mgmt(wusb_df_state_t *);
72 static void	wusb_df_destroy_power_mgmt(wusb_df_state_t *);
73 static int	wusb_df_serialize_access(wusb_df_state_t *, boolean_t);
74 static void	wusb_df_release_access(wusb_df_state_t *);
75 static int	wusb_df_firmware_download(wusb_df_state_t *wusbp);
76 
77 
78 /* _NOTE is an advice for locklint.  Locklint checks lock use for deadlocks. */
79 _NOTE(SCHEME_PROTECTS_DATA("unique per call", usb_ctrl_req))
80 _NOTE(SCHEME_PROTECTS_DATA("unique per call", buf))
81 
82 /* module loading stuff */
83 struct cb_ops wusb_df_cb_ops = {
84 	nodev,			/* open  */
85 	nodev,  		/* close */
86 	nodev,			/* strategy */
87 	nulldev,		/* print */
88 	nulldev,		/* dump */
89 	nodev,			/* read */
90 	nodev,			/* write */
91 	nodev,			/* ioctl */
92 	nulldev,		/* devmap */
93 	nodev,			/* mmap */
94 	nodev,			/* segmap */
95 	nochpoll,		/* poll */
96 	ddi_prop_op,		/* cb_prop_op */
97 	NULL,			/* streamtab  */
98 	D_MP
99 };
100 
101 static struct dev_ops wusb_df_ops = {
102 	DEVO_REV,		/* devo_rev, */
103 	0,			/* refcnt  */
104 	wusb_df_info,		/* info */
105 	nulldev,		/* identify */
106 	nulldev,		/* probe */
107 	wusb_df_attach,		/* attach */
108 	wusb_df_detach,		/* detach */
109 	nodev,			/* reset */
110 	&wusb_df_cb_ops,	/* driver operations */
111 	NULL,			/* bus operations */
112 	wusb_df_power		/* power */
113 };
114 
115 static struct modldrv wusb_df_modldrv =	{
116 	&mod_driverops,
117 	"WUSB firmware download",
118 	&wusb_df_ops
119 };
120 
121 static struct modlinkage modlinkage = {
122 	MODREV_1,
123 	&wusb_df_modldrv,
124 	NULL
125 };
126 
127 /*
128  * Descriptor for a record of firmware
129  */
130 typedef struct fw_dsc {
131 	uint32_t		addr;
132 	size_t			size;
133 	uint8_t			*data;
134 	struct fw_dsc		*next;
135 } fw_dsc_t;
136 
137 
138 /*
139  * Module-wide initialization routine.
140  */
141 int
_init(void)142 _init(void)
143 {
144 	int rval;
145 
146 
147 	if ((rval = ddi_soft_state_init(&wusb_df_statep,
148 	    sizeof (wusb_df_state_t), WUSB_DF_INITIAL_SOFT_SPACE)) != 0) {
149 
150 		return (rval);
151 	}
152 
153 	if ((rval = mod_install(&modlinkage)) != 0) {
154 		ddi_soft_state_fini(&wusb_df_statep);
155 	}
156 
157 
158 	return (rval);
159 }
160 
161 
162 /*
163  * Module-wide tear-down routine.
164  */
165 int
_fini(void)166 _fini(void)
167 {
168 	int rval;
169 
170 	if ((rval = mod_remove(&modlinkage)) != 0) {
171 
172 		return (rval);
173 	}
174 
175 	ddi_soft_state_fini(&wusb_df_statep);
176 
177 	return (rval);
178 }
179 
180 
181 int
_info(struct modinfo * modinfop)182 _info(struct modinfo *modinfop)
183 {
184 	return (mod_info(&modlinkage, modinfop));
185 }
186 
187 /*
188  * wusb_df_attach:
189  *	Attach or resume.
190  *
191  *	For attach, initialize state and device, including:
192  *		state variables, locks, device node
193  *		device registration with system
194  *		power management, hotplugging
195  *	For resume, restore device and state
196  */
197 static int
wusb_df_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)198 wusb_df_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
199 {
200 	int			instance = ddi_get_instance(dip);
201 	char			*devinst;
202 	int			devinstlen;
203 	wusb_df_state_t		*wusb_dfp = NULL;
204 	usb_ep_data_t		*ep_datap;
205 	int			status;
206 
207 	switch (cmd) {
208 	case DDI_ATTACH:
209 		break;
210 
211 	case DDI_RESUME:
212 		wusb_df_cpr_resume(dip);
213 
214 		/*
215 		 * Always return success to work around enumeration failures.
216 		 * This works around an issue where devices which are present
217 		 * before a suspend and absent upon resume could cause a system
218 		 * panic on resume.
219 		 */
220 		return (DDI_SUCCESS);
221 	default:
222 		return (DDI_FAILURE);
223 	}
224 
225 	if (ddi_soft_state_zalloc(wusb_df_statep, instance) == DDI_SUCCESS) {
226 		wusb_dfp = ddi_get_soft_state(wusb_df_statep, instance);
227 	}
228 	if (wusb_dfp == NULL)  {
229 
230 		return (DDI_FAILURE);
231 	}
232 
233 	wusb_dfp->wusb_df_dip = dip;
234 
235 	devinst = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
236 	devinstlen = snprintf(devinst, USB_MAXSTRINGLEN, "%s%d: ",
237 	    ddi_driver_name(dip), instance);
238 
239 	wusb_dfp->wusb_df_devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP);
240 	(void) strncpy(wusb_dfp->wusb_df_devinst, devinst, devinstlen);
241 	kmem_free(devinst, USB_MAXSTRINGLEN);
242 
243 	wusb_dfp->wusb_df_log_hdl = usb_alloc_log_hdl(dip, "wusb_df",
244 	    &wusb_df_errlevel, &wusb_df_errmask, &wusb_df_instance_debug, 0);
245 
246 	USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
247 	    "Attach: enter for attach");
248 
249 	if ((status = usb_client_attach(dip, USBDRV_VERSION, 0)) !=
250 	    USB_SUCCESS) {
251 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
252 		    "attach: usb_client_attach failed, error code:%d", status);
253 		goto fail;
254 	}
255 
256 	if ((status = usb_get_dev_data(dip, &wusb_dfp->wusb_df_reg,
257 	    USB_PARSE_LVL_ALL, 0)) != USB_SUCCESS) {
258 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
259 		    "attach: usb_get_dev_data failed, error code:%d", status);
260 		goto fail;
261 	}
262 
263 
264 	/*
265 	 * Get the descriptor for an intr pipe at alt 0 of current interface.
266 	 * This will be used later to open the pipe.
267 	 */
268 	if ((ep_datap = usb_lookup_ep_data(dip, wusb_dfp->wusb_df_reg,
269 	    wusb_dfp->wusb_df_reg->dev_curr_if, 0, 0,
270 	    USB_EP_ATTR_INTR, USB_EP_DIR_IN)) == NULL) {
271 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
272 		    "attach: Error getting intr endpoint descriptor");
273 		goto fail;
274 	}
275 	wusb_dfp->wusb_df_intr_ep_descr = ep_datap->ep_descr;
276 
277 	usb_free_descr_tree(dip, wusb_dfp->wusb_df_reg);
278 
279 	mutex_init(&wusb_dfp->wusb_df_mutex, NULL, MUTEX_DRIVER,
280 	    wusb_dfp->wusb_df_reg->dev_iblock_cookie);
281 
282 	cv_init(&wusb_dfp->wusb_df_serial_cv, NULL, CV_DRIVER, NULL);
283 	wusb_dfp->wusb_df_serial_inuse = B_FALSE;
284 
285 	wusb_dfp->wusb_df_locks_initialized = B_TRUE;
286 
287 	/* create minor node */
288 	if (ddi_create_minor_node(dip, name, S_IFCHR, instance,
289 	    "wusb_df", 0) != DDI_SUCCESS) {
290 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
291 		    "attach: Error creating minor node");
292 		goto fail;
293 	}
294 
295 	/* Put online before PM init as can get power managed afterward. */
296 	wusb_dfp->wusb_df_dev_state = USB_DEV_ONLINE;
297 
298 	/* initialize power management */
299 	wusb_df_init_power_mgmt(wusb_dfp);
300 
301 	if (usb_register_hotplug_cbs(dip, wusb_df_disconnect_callback,
302 	    wusb_df_reconnect_callback) != USB_SUCCESS) {
303 
304 		goto fail;
305 	}
306 
307 	/* Report device */
308 	ddi_report_dev(dip);
309 
310 	(void) wusb_df_firmware_download(wusb_dfp);
311 
312 	if (usb_reset_device(dip, USB_RESET_LVL_REATTACH) != USB_SUCCESS) {
313 		USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
314 		    "reset device failed");
315 
316 		return (USB_FAILURE);
317 	}
318 
319 	return (DDI_SUCCESS);
320 
321 fail:
322 	if (wusb_dfp) {
323 		(void) wusb_df_cleanup(dip, wusb_dfp);
324 	}
325 
326 	return (DDI_FAILURE);
327 }
328 
329 
330 /*
331  * wusb_df_detach:
332  *	detach or suspend driver instance
333  *
334  * Note: in detach, only contention threads is from pm and disconnnect.
335  */
336 static int
wusb_df_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)337 wusb_df_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
338 {
339 	int		instance = ddi_get_instance(dip);
340 	wusb_df_state_t	*wusb_dfp =
341 	    ddi_get_soft_state(wusb_df_statep, instance);
342 	int		rval = DDI_FAILURE;
343 
344 	switch (cmd) {
345 	case DDI_DETACH:
346 
347 		USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
348 		    "Detach: enter for detach");
349 
350 		rval = wusb_df_cleanup(dip, wusb_dfp);
351 
352 		break;
353 	case DDI_SUSPEND:
354 		USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
355 		    "Detach: enter for suspend");
356 
357 		rval = wusb_df_cpr_suspend(dip);
358 	default:
359 
360 		break;
361 	}
362 
363 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
364 }
365 
366 
367 /*
368  * wusb_df_cleanup:
369  *	clean up the driver state for detach
370  */
371 static int
wusb_df_cleanup(dev_info_t * dip,wusb_df_state_t * wusb_dfp)372 wusb_df_cleanup(dev_info_t *dip, wusb_df_state_t *wusb_dfp)
373 {
374 
375 	USB_DPRINTF_L3(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
376 	    "Cleanup: enter");
377 
378 	if (wusb_dfp->wusb_df_locks_initialized) {
379 
380 		/* This must be done 1st to prevent more events from coming. */
381 		usb_unregister_hotplug_cbs(dip);
382 
383 		/*
384 		 * At this point, no new activity can be initiated. The driver
385 		 * has disabled hotplug callbacks. The Solaris framework has
386 		 * disabled new opens on a device being detached, and does not
387 		 * allow detaching an open device.
388 		 *
389 		 * The following ensures that all driver activity has drained.
390 		 */
391 		mutex_enter(&wusb_dfp->wusb_df_mutex);
392 		(void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG);
393 		wusb_df_release_access(wusb_dfp);
394 		mutex_exit(&wusb_dfp->wusb_df_mutex);
395 
396 		/* All device activity has died down. */
397 		wusb_df_destroy_power_mgmt(wusb_dfp);
398 
399 		/* start dismantling */
400 		ddi_remove_minor_node(dip, NULL);
401 
402 		cv_destroy(&wusb_dfp->wusb_df_serial_cv);
403 		mutex_destroy(&wusb_dfp->wusb_df_mutex);
404 	}
405 
406 	usb_client_detach(dip, wusb_dfp->wusb_df_reg);
407 
408 	usb_free_log_hdl(wusb_dfp->wusb_df_log_hdl);
409 
410 	if (wusb_dfp->wusb_df_devinst != NULL) {
411 		kmem_free(wusb_dfp->wusb_df_devinst,
412 		    strlen(wusb_dfp->wusb_df_devinst) + 1);
413 	}
414 
415 	ddi_soft_state_free(wusb_df_statep, ddi_get_instance(dip));
416 	ddi_prop_remove_all(dip);
417 
418 	return (USB_SUCCESS);
419 }
420 
421 
422 /*
423  * wusb_df_disconnect_callback:
424  *	Called when device hotplug-removed.
425  *		Close pipes. (This does not attempt to contact device.)
426  *		Set state to DISCONNECTED
427  */
428 static int
wusb_df_disconnect_callback(dev_info_t * dip)429 wusb_df_disconnect_callback(dev_info_t *dip)
430 {
431 	int instance = ddi_get_instance(dip);
432 	wusb_df_state_t	*wusb_dfp =
433 	    ddi_get_soft_state(wusb_df_statep, instance);
434 
435 
436 	USB_DPRINTF_L4(PRINT_MASK_CB, wusb_dfp->wusb_df_log_hdl,
437 	    "disconnect: enter");
438 
439 	mutex_enter(&wusb_dfp->wusb_df_mutex);
440 	(void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG);
441 
442 	/*
443 	 * Save any state of device or IO in progress required by
444 	 * wusb_df_restore_device_state for proper device "thawing" later.
445 	 */
446 	wusb_dfp->wusb_df_dev_state = USB_DEV_DISCONNECTED;
447 
448 	wusb_df_release_access(wusb_dfp);
449 	mutex_exit(&wusb_dfp->wusb_df_mutex);
450 
451 	return (USB_SUCCESS);
452 }
453 
454 
455 /*
456  * wusb_df_reconnect_callback:
457  *	Called with device hotplug-inserted
458  *		Restore state
459  */
460 static int
wusb_df_reconnect_callback(dev_info_t * dip)461 wusb_df_reconnect_callback(dev_info_t *dip)
462 {
463 	int instance = ddi_get_instance(dip);
464 	wusb_df_state_t	*wusb_dfp =
465 	    ddi_get_soft_state(wusb_df_statep, instance);
466 
467 	USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
468 	    "reconnect: enter");
469 
470 	wusb_df_pm_busy_component(wusb_dfp);
471 	(void) pm_raise_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_FULL_PWR);
472 
473 	mutex_enter(&wusb_dfp->wusb_df_mutex);
474 	(void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG);
475 	wusb_df_restore_device_state(dip, wusb_dfp);
476 	wusb_df_release_access(wusb_dfp);
477 	mutex_exit(&wusb_dfp->wusb_df_mutex);
478 
479 	wusb_df_pm_idle_component(wusb_dfp);
480 
481 	return (USB_SUCCESS);
482 }
483 
484 
485 /*
486  * wusb_df_restore_device_state:
487  *	Called during hotplug-reconnect and resume.
488  *		reenable power management
489  *		Verify the device is the same as before the disconnect/suspend.
490  *		Restore device state
491  *		Thaw any IO which was frozen.
492  *		Quiesce device.  (Other routines will activate if thawed IO.)
493  *		Set device online.
494  *		Leave device disconnected if there are problems.
495  */
496 static void
wusb_df_restore_device_state(dev_info_t * dip,wusb_df_state_t * wusb_dfp)497 wusb_df_restore_device_state(dev_info_t *dip, wusb_df_state_t *wusb_dfp)
498 {
499 	USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
500 	    "wusb_df_restore_device_state: enter");
501 
502 	ASSERT(mutex_owned(&wusb_dfp->wusb_df_mutex));
503 
504 	ASSERT((wusb_dfp->wusb_df_dev_state == USB_DEV_DISCONNECTED) ||
505 	    (wusb_dfp->wusb_df_dev_state == USB_DEV_SUSPENDED));
506 
507 	mutex_exit(&wusb_dfp->wusb_df_mutex);
508 
509 
510 	/* Check if we are talking to the same device */
511 	if (usb_check_same_device(dip, wusb_dfp->wusb_df_log_hdl,
512 	    USB_LOG_L0, PRINT_MASK_ALL,
513 	    USB_CHK_ALL, NULL) != USB_SUCCESS) {
514 
515 		/* change the device state from suspended to disconnected */
516 		mutex_enter(&wusb_dfp->wusb_df_mutex);
517 		wusb_dfp->wusb_df_dev_state = USB_DEV_SUSPENDED;
518 		USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
519 		    "wusb_df_restore_device_state: check same device failed");
520 		return;
521 	}
522 
523 	mutex_enter(&wusb_dfp->wusb_df_mutex);
524 	wusb_dfp->wusb_df_dev_state = USB_DEV_ONLINE;
525 
526 	if (wusb_dfp->wusb_df_pm &&
527 	    wusb_dfp->wusb_df_pm->wusb_df_wakeup_enabled) {
528 
529 		/* Failure here means device disappeared again. */
530 		mutex_exit(&wusb_dfp->wusb_df_mutex);
531 		if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) !=
532 		    USB_SUCCESS) {
533 			USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
534 			    "device may or may not be accessible. "
535 			    "Please verify reconnection");
536 		}
537 		mutex_enter(&wusb_dfp->wusb_df_mutex);
538 	}
539 
540 
541 	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
542 	    "wusb_df_restore_device_state: end");
543 
544 }
545 
546 
547 /*
548  * wusb_df_cpr_suspend:
549  *	Clean up device.
550  *	Wait for any IO to finish, then close pipes.
551  *	Quiesce device.
552  */
553 static int
wusb_df_cpr_suspend(dev_info_t * dip)554 wusb_df_cpr_suspend(dev_info_t *dip)
555 {
556 	int		instance = ddi_get_instance(dip);
557 	wusb_df_state_t	*wusb_dfp =
558 	    ddi_get_soft_state(wusb_df_statep, instance);
559 
560 	USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
561 	    "suspend enter");
562 
563 	/* Serialize to prevent races with detach, open, device access. */
564 	mutex_enter(&wusb_dfp->wusb_df_mutex);
565 	(void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG);
566 	mutex_exit(&wusb_dfp->wusb_df_mutex);
567 
568 	wusb_df_pm_busy_component(wusb_dfp);
569 
570 	mutex_enter(&wusb_dfp->wusb_df_mutex);
571 
572 	/* Access device here to clean it up. */
573 
574 	wusb_dfp->wusb_df_dev_state = USB_DEV_SUSPENDED;
575 
576 	/*
577 	 * Save any state of device required by wusb_df_restore_device_state
578 	 * for proper device "thawing" later.
579 	 */
580 
581 	wusb_df_release_access(wusb_dfp);
582 	mutex_exit(&wusb_dfp->wusb_df_mutex);
583 
584 	wusb_df_pm_idle_component(wusb_dfp);
585 
586 	USB_DPRINTF_L4(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
587 	    "suspend: success");
588 
589 	return (USB_SUCCESS);
590 }
591 
592 
593 /*
594  * wusb_df_cpr_resume:
595  *
596  *	wusb_df_restore_device_state marks success by putting device back online
597  */
598 static void
wusb_df_cpr_resume(dev_info_t * dip)599 wusb_df_cpr_resume(dev_info_t *dip)
600 {
601 	int		instance = ddi_get_instance(dip);
602 	wusb_df_state_t	*wusb_dfp =
603 	    ddi_get_soft_state(wusb_df_statep, instance);
604 
605 	USB_DPRINTF_L4(PRINT_MASK_CPR, wusb_dfp->wusb_df_log_hdl,
606 	    "resume: enter");
607 
608 	/*
609 	 * NOTE: A pm_raise_power in wusb_df_restore_device_state will bring
610 	 * the power-up state of device into synch with the system.
611 	 */
612 	wusb_df_pm_busy_component(wusb_dfp);
613 	(void) pm_raise_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_FULL_PWR);
614 	mutex_enter(&wusb_dfp->wusb_df_mutex);
615 	wusb_df_restore_device_state(dip, wusb_dfp);
616 	mutex_exit(&wusb_dfp->wusb_df_mutex);
617 	wusb_df_pm_idle_component(wusb_dfp);
618 }
619 
620 static void
wusb_df_pm_busy_component(wusb_df_state_t * wusb_dfp)621 wusb_df_pm_busy_component(wusb_df_state_t *wusb_dfp)
622 {
623 	ASSERT(!mutex_owned(&wusb_dfp->wusb_df_mutex));
624 
625 	mutex_enter(&wusb_dfp->wusb_df_mutex);
626 	if (wusb_dfp->wusb_df_pm == NULL) {
627 		USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
628 		    "wusb_df_pm_busy_component: pm = NULL");
629 		goto done;
630 	}
631 
632 	wusb_dfp->wusb_df_pm->wusb_df_pm_busy++;
633 	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
634 	    "wusb_df_pm_busy_component: %d",
635 	    wusb_dfp->wusb_df_pm->wusb_df_pm_busy);
636 
637 	mutex_exit(&wusb_dfp->wusb_df_mutex);
638 
639 	if (pm_busy_component(wusb_dfp->wusb_df_dip, 0) != DDI_SUCCESS) {
640 		mutex_enter(&wusb_dfp->wusb_df_mutex);
641 		wusb_dfp->wusb_df_pm->wusb_df_pm_busy--;
642 
643 		USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
644 		    "wusb_df_pm_busy_component: %d",
645 		    wusb_dfp->wusb_df_pm->wusb_df_pm_busy);
646 		mutex_exit(&wusb_dfp->wusb_df_mutex);
647 
648 
649 	}
650 	return;
651 done:
652 		mutex_exit(&wusb_dfp->wusb_df_mutex);
653 
654 }
655 
656 static void
wusb_df_pm_idle_component(wusb_df_state_t * wusb_dfp)657 wusb_df_pm_idle_component(wusb_df_state_t *wusb_dfp)
658 {
659 	ASSERT(!mutex_owned(&wusb_dfp->wusb_df_mutex));
660 	mutex_enter(&wusb_dfp->wusb_df_mutex);
661 	if (wusb_dfp->wusb_df_pm == NULL) {
662 		mutex_exit(&wusb_dfp->wusb_df_mutex);
663 		return;
664 	}
665 	mutex_exit(&wusb_dfp->wusb_df_mutex);
666 
667 
668 	if (pm_idle_component(wusb_dfp->wusb_df_dip, 0) == DDI_SUCCESS) {
669 		mutex_enter(&wusb_dfp->wusb_df_mutex);
670 		ASSERT(wusb_dfp->wusb_df_pm->wusb_df_pm_busy > 0);
671 		wusb_dfp->wusb_df_pm->wusb_df_pm_busy--;
672 
673 		USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
674 		    "wusb_df_pm_idle_component: %d",
675 		    wusb_dfp->wusb_df_pm->wusb_df_pm_busy);
676 
677 		mutex_exit(&wusb_dfp->wusb_df_mutex);
678 	}
679 }
680 
681 /*
682  * wusb_df_power :
683  *	Power entry point, the workhorse behind pm_raise_power, pm_lower_power,
684  *	usb_req_raise_power and usb_req_lower_power.
685  */
686 /* ARGSUSED */
687 static int
wusb_df_power(dev_info_t * dip,int comp,int level)688 wusb_df_power(dev_info_t *dip, int comp, int level)
689 {
690 	wusb_df_state_t	*wusb_dfp;
691 	wusb_df_power_t	*pm;
692 	int	rval = USB_SUCCESS;
693 
694 	wusb_dfp = ddi_get_soft_state(wusb_df_statep, ddi_get_instance(dip));
695 
696 	USB_DPRINTF_L3(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
697 	    "wusb_df_power: enter: level = %d", level);
698 
699 	mutex_enter(&wusb_dfp->wusb_df_mutex);
700 	(void) wusb_df_serialize_access(wusb_dfp, WUSB_DF_SER_NOSIG);
701 
702 
703 	/*
704 	 * If we are disconnected/suspended, return success. Note that if we
705 	 * return failure, bringing down the system will hang when
706 	 * PM tries to power up all devices
707 	 */
708 	if ((wusb_dfp->wusb_df_dev_state == USB_DEV_DISCONNECTED) ||
709 	    (wusb_dfp->wusb_df_dev_state == USB_DEV_SUSPENDED)) {
710 
711 		USB_DPRINTF_L3(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
712 		    "wusb_df_power: disconnected/suspended "
713 		    "dev_state=%d", wusb_dfp->wusb_df_dev_state);
714 		rval = USB_SUCCESS;
715 
716 		goto done;
717 	}
718 
719 	if (wusb_dfp->wusb_df_pm == NULL) {
720 
721 		goto done;
722 	}
723 
724 	pm = wusb_dfp->wusb_df_pm;
725 
726 	/* Check if we are transitioning to a legal power level */
727 	if (USB_DEV_PWRSTATE_OK(pm->wusb_df_pwr_states, level)) {
728 		USB_DPRINTF_L3(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
729 		    "wusb_df_power: illegal power level = %d "
730 		    "pwr_states: %x", level, pm->wusb_df_pwr_states);
731 
732 		goto done;
733 	}
734 
735 	switch (level) {
736 	case USB_DEV_OS_PWR_OFF :
737 		/* fail attempt to go to low power if busy */
738 		if (pm->wusb_df_pm_busy) {
739 
740 			goto done;
741 		}
742 		if (wusb_dfp->wusb_df_dev_state == USB_DEV_ONLINE) {
743 			wusb_dfp->wusb_df_dev_state = USB_DEV_PWRED_DOWN;
744 			wusb_dfp->wusb_df_pm->wusb_df_current_power =
745 			    USB_DEV_OS_PWR_OFF;
746 		} else {
747 			rval = USB_SUCCESS;
748 		}
749 		break;
750 
751 	case USB_DEV_OS_FULL_PWR :
752 		/*
753 		 * PM framework tries to put us in full power during system
754 		 * shutdown.
755 		 */
756 		wusb_dfp->wusb_df_dev_state = USB_DEV_ONLINE;
757 		wusb_dfp->wusb_df_pm->wusb_df_current_power =
758 		    USB_DEV_OS_FULL_PWR;
759 		break;
760 
761 	/* Levels 1 and 2 are not supported by this driver to keep it simple. */
762 	default:
763 		USB_DPRINTF_L3(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
764 		    "wusb_df_power: power level %d not supported", level);
765 		break;
766 	}
767 done:
768 	wusb_df_release_access(wusb_dfp);
769 	mutex_exit(&wusb_dfp->wusb_df_mutex);
770 
771 	return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
772 }
773 
774 
775 /*
776  * wusb_df_init_power_mgmt:
777  *	Initialize power management and remote wakeup functionality.
778  *	No mutex is necessary in this function as it's called only by attach.
779  */
780 static void
wusb_df_init_power_mgmt(wusb_df_state_t * wusb_dfp)781 wusb_df_init_power_mgmt(wusb_df_state_t *wusb_dfp)
782 {
783 	wusb_df_power_t *wusb_dfpm;
784 	uint_t		pwr_states;
785 
786 	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
787 	    "init_power_mgmt enter");
788 
789 	/*
790 	 * If remote wakeup is not available you may not want to do
791 	 * power management.
792 	 */
793 	/* Allocate the state structure */
794 	wusb_dfpm = kmem_zalloc(sizeof (wusb_df_power_t), KM_SLEEP);
795 	wusb_dfp->wusb_df_pm = wusb_dfpm;
796 	wusb_dfpm->wusb_df_state = wusb_dfp;
797 	wusb_dfpm->wusb_df_pm_capabilities = 0;
798 	wusb_dfpm->wusb_df_current_power = USB_DEV_OS_FULL_PWR;
799 
800 	if (usb_create_pm_components(wusb_dfp->wusb_df_dip, &pwr_states) ==
801 	    USB_SUCCESS) {
802 
803 		USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
804 		    "wusb_df_init_power_mgmt: created PM components");
805 
806 		wusb_dfpm->wusb_df_pwr_states = (uint8_t)pwr_states;
807 		(void) pm_raise_power(wusb_dfp->wusb_df_dip, 0,
808 		    USB_DEV_OS_FULL_PWR);
809 
810 		if (usb_handle_remote_wakeup(wusb_dfp->wusb_df_dip,
811 		    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
812 			wusb_dfpm->wusb_df_wakeup_enabled = 1;
813 		} else {
814 			USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
815 			    "wusb_df_init_power_mgmt:"
816 			    "fail to enable remote wakeup");
817 		}
818 
819 	} else {
820 		USB_DPRINTF_L2(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
821 		    "wusb_df_init_power_mgmt: create_pm_compts failed");
822 	}
823 	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
824 	    "wusb_df_init_power_mgmt: end");
825 
826 }
827 
828 
829 /*
830  * wusb_df_destroy_power_mgmt:
831  *	Shut down and destroy power management and remote wakeup functionality.
832  */
833 static void
wusb_df_destroy_power_mgmt(wusb_df_state_t * wusb_dfp)834 wusb_df_destroy_power_mgmt(wusb_df_state_t *wusb_dfp)
835 {
836 	USB_DPRINTF_L4(PRINT_MASK_PM, wusb_dfp->wusb_df_log_hdl,
837 	    "destroy_power_mgmt enter");
838 
839 	ASSERT(!mutex_owned(&wusb_dfp->wusb_df_mutex));
840 
841 	mutex_enter(&wusb_dfp->wusb_df_mutex);
842 	if (!wusb_dfp->wusb_df_pm) {
843 		mutex_exit(&wusb_dfp->wusb_df_mutex);
844 		return;
845 	}
846 	mutex_exit(&wusb_dfp->wusb_df_mutex);
847 
848 	(void) wusb_df_pm_busy_component(wusb_dfp);
849 
850 	mutex_enter(&wusb_dfp->wusb_df_mutex);
851 	if (wusb_dfp->wusb_df_dev_state != USB_DEV_DISCONNECTED) {
852 
853 		if (wusb_dfp->wusb_df_pm->wusb_df_wakeup_enabled) {
854 			mutex_exit(&wusb_dfp->wusb_df_mutex);
855 
856 			(void) pm_raise_power(wusb_dfp->wusb_df_dip, 0,
857 			    USB_DEV_OS_FULL_PWR);
858 			if (usb_handle_remote_wakeup(wusb_dfp->wusb_df_dip,
859 			    USB_REMOTE_WAKEUP_DISABLE) != USB_SUCCESS) {
860 				USB_DPRINTF_L2(PRINT_MASK_PM,
861 				    wusb_dfp->wusb_df_log_hdl,
862 				    "wusb_df_destroy_power_mgmt: "
863 				    "Error disabling rmt wakeup");
864 			}
865 			mutex_enter(&wusb_dfp->wusb_df_mutex);
866 
867 		}
868 	}
869 	mutex_exit(&wusb_dfp->wusb_df_mutex);
870 
871 	/*
872 	 * Since remote wakeup is disabled now,
873 	 * no one can raise power
874 	 * and get to device once power is lowered here.
875 	 */
876 	(void) pm_lower_power(wusb_dfp->wusb_df_dip, 0, USB_DEV_OS_PWR_OFF);
877 	wusb_df_pm_idle_component(wusb_dfp);
878 
879 	mutex_enter(&wusb_dfp->wusb_df_mutex);
880 	kmem_free(wusb_dfp->wusb_df_pm, sizeof (wusb_df_power_t));
881 	wusb_dfp->wusb_df_pm = NULL;
882 	mutex_exit(&wusb_dfp->wusb_df_mutex);
883 }
884 
885 
886 /*
887  * wusb_df_serialize_access:
888  *    Get the serial synchronization object before returning.
889  *
890  * Arguments:
891  *    wusb_dfp - Pointer to wusb_df state structure
892  *    waitsig - Set to:
893  *	WUSB_DF_SER_SIG - to wait such that a signal can interrupt
894  *	WUSB_DF_SER_NOSIG - to wait such that a signal cannot interrupt
895  */
896 static int
wusb_df_serialize_access(wusb_df_state_t * wusb_dfp,boolean_t waitsig)897 wusb_df_serialize_access(wusb_df_state_t *wusb_dfp, boolean_t waitsig)
898 {
899 	int rval = 1;
900 
901 	ASSERT(mutex_owned(&wusb_dfp->wusb_df_mutex));
902 
903 	while (wusb_dfp->wusb_df_serial_inuse) {
904 		if (waitsig == WUSB_DF_SER_SIG) {
905 			rval = cv_wait_sig(&wusb_dfp->wusb_df_serial_cv,
906 			    &wusb_dfp->wusb_df_mutex);
907 		} else {
908 			cv_wait(&wusb_dfp->wusb_df_serial_cv,
909 			    &wusb_dfp->wusb_df_mutex);
910 		}
911 	}
912 	wusb_dfp->wusb_df_serial_inuse = B_TRUE;
913 
914 	return (rval);
915 }
916 
917 
918 /*
919  * wusb_df_release_access:
920  *    Release the serial synchronization object.
921  */
922 static void
wusb_df_release_access(wusb_df_state_t * wusb_dfp)923 wusb_df_release_access(wusb_df_state_t *wusb_dfp)
924 {
925 	ASSERT(mutex_owned(&wusb_dfp->wusb_df_mutex));
926 	wusb_dfp->wusb_df_serial_inuse = B_FALSE;
927 	cv_broadcast(&wusb_dfp->wusb_df_serial_cv);
928 }
929 
930 /*
931  * wusb_df_info:
932  *	Get minor number, soft state structure, etc.
933  */
934 /*ARGSUSED*/
935 static int
wusb_df_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)936 wusb_df_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
937 			void *arg, void **result)
938 {
939 	wusb_df_state_t	*wusb_dfp;
940 	int error = DDI_FAILURE;
941 
942 	switch (infocmd) {
943 	case DDI_INFO_DEVT2DEVINFO:
944 		if ((wusb_dfp = ddi_get_soft_state(wusb_df_statep,
945 		    getminor((dev_t)arg))) != NULL) {
946 			*result = wusb_dfp->wusb_df_dip;
947 			if (*result != NULL) {
948 				error = DDI_SUCCESS;
949 			}
950 		} else {
951 			*result = NULL;
952 		}
953 		break;
954 	case DDI_INFO_DEVT2INSTANCE:
955 		*result = (void *)(uintptr_t)getminor((dev_t)arg);
956 		error = DDI_SUCCESS;
957 		break;
958 	default:
959 		break;
960 	}
961 
962 	return (error);
963 }
964 
965 /* Free a chain of firmware headers */
966 static void
free_fw_dscs(struct fw_dsc * head)967 free_fw_dscs(struct fw_dsc *head)
968 {
969 	struct fw_dsc *next;
970 
971 	while (head) {
972 		next = head->next;
973 		kmem_free(head, sizeof (fw_dsc_t));
974 		head = next;
975 	}
976 }
977 
978 static unsigned int
char2int32(unsigned char * input)979 char2int32(unsigned char *input)
980 {
981 	return ((*input) |
982 	    (*(input + 1) <<  8) |
983 	    (*(input + 2) << 16) |
984 	    (*(input + 3) << 24));
985 }
986 
987 /*
988  * download firmware or command by control pipe
989  */
990 static int
wusb_df_send_data(wusb_df_state_t * wusbp,unsigned int address,const unsigned char * buffer,unsigned int size)991 wusb_df_send_data(wusb_df_state_t *wusbp,
992 		unsigned int address,
993 		const unsigned char *buffer,
994 		unsigned int size)
995 {
996 	int			error = DDI_FAILURE;
997 	usb_ctrl_setup_t	setup;
998 	usb_cb_flags_t		cb_flags;
999 	usb_cr_t		cr;
1000 	mblk_t			*data = NULL;	/* data for USBA */
1001 	uint16_t		data_len;	/* # of bytes want to write */
1002 	uint_t			cnt;		/* # of xfered bytes */
1003 
1004 	setup.bmRequestType	= USB_DEV_REQ_TYPE_VENDOR |
1005 	    USB_DEV_REQ_HOST_TO_DEV | USB_DEV_REQ_RCPT_DEV;
1006 	setup.bRequest		= 0xf0;
1007 	setup.attrs		= 0;
1008 
1009 	for (cnt = 0; cnt < size; cnt += data_len) {
1010 		data_len = min(size - cnt, 512);
1011 
1012 		/* reuse previous mblk if possible */
1013 		if ((data = reallocb(data, data_len, 0)) == NULL) {
1014 
1015 			return (USB_FAILURE);
1016 		}
1017 		bcopy(buffer + cnt, data->b_rptr, data_len);
1018 		data->b_wptr += data_len;
1019 
1020 		setup.wValue		= (address + cnt) & 0xffff;
1021 		setup.wIndex		= ((address + cnt) >> 16) & 0xffff;
1022 		setup.wLength		= data_len;
1023 		error = usb_pipe_ctrl_xfer_wait(
1024 		    wusbp->wusb_df_reg->dev_default_ph, &setup, &data,
1025 		    &cr, &cb_flags, 0);
1026 		if (error != USB_SUCCESS) {
1027 			USB_DPRINTF_L2(PRINT_MASK_ATTA, wusbp->wusb_df_log_hdl,
1028 			    "wusb_df_send_data: "
1029 			    "send failed rval=%d, cr=%d, cb=0x%x\n",
1030 			    error, cr, cb_flags);
1031 
1032 			break;
1033 		}
1034 	}
1035 
1036 	if (data) {
1037 		freemsg(data);
1038 	}
1039 
1040 	return (error);
1041 }
1042 
1043 /*
1044  * find the firmware module's "_start", "_end" symbols
1045  * and get the size of firmware.
1046  */
1047 static int
wusbdf_mod_loadsym(wusb_df_state_t * dfp,ddi_modhandle_t modp,char * mod,char * sym,char ** start,size_t * len)1048 wusbdf_mod_loadsym(wusb_df_state_t *dfp, ddi_modhandle_t modp, char *mod,
1049 	char *sym, char **start, size_t *len)
1050 {
1051 	char start_sym[256];
1052 	char end_sym[256];
1053 	char *p, *end;
1054 	int rv;
1055 	size_t n;
1056 
1057 	(void) snprintf(start_sym, sizeof (start_sym), "%s_start", sym);
1058 	(void) snprintf(end_sym, sizeof (end_sym), "%s_end", sym);
1059 
1060 	p = (char *)ddi_modsym(modp, start_sym, &rv);
1061 	if (p == NULL || rv != 0) {
1062 		USB_DPRINTF_L2(PRINT_MASK_ATTA, dfp->wusb_df_log_hdl,
1063 		    "mod %s: symbol %s not found\n", mod, start_sym);
1064 		return (-1);
1065 	}
1066 	end = (char *)ddi_modsym(modp, end_sym, &rv);
1067 	if (end == NULL || rv != 0) {
1068 		USB_DPRINTF_L2(PRINT_MASK_ATTA, dfp->wusb_df_log_hdl,
1069 		    "mod %s: symbol %s not found\n", mod, end_sym);
1070 		return (-1);
1071 	}
1072 	n = end - p;
1073 
1074 	*start = p;
1075 	*len = n;
1076 
1077 	return (0);
1078 }
1079 
1080 /* write firmware segments into device through control endpoint */
1081 static int
wusb_df_fw_download(wusb_df_state_t * wusb_dfp)1082 wusb_df_fw_download(wusb_df_state_t *wusb_dfp)
1083 {
1084 	int		error = USB_SUCCESS;
1085 	size_t		size  = 0, record_cnt = 0;
1086 	unsigned char	*pdata, *data_end;
1087 	unsigned char	*firmware_image;
1088 	fw_dsc_t	*pdsc = NULL, *rcd_head = NULL, *tmpr = NULL;
1089 	unsigned int	remaining_size;
1090 	int		rv = 0;
1091 	ddi_modhandle_t modp;
1092 	char *firm_start;
1093 
1094 	USB_DPRINTF_L3(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
1095 	    "Download firmware: %s", wusb_fwmod);
1096 
1097 	/* allow user specify firmware in .conf? */
1098 
1099 	/* see elfwrap(1) for how to turn firmware into loadable module */
1100 	modp = ddi_modopen(wusb_fwmod, KRTLD_MODE_FIRST, &rv);
1101 	if (modp == NULL) {
1102 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
1103 		    "module %s not found", wusb_fwmod);
1104 
1105 		error = USB_FAILURE;
1106 		goto checkstatus;
1107 	}
1108 
1109 	rv = wusbdf_mod_loadsym(wusb_dfp, modp, wusb_fwmod, wusb_fwsym1,
1110 	    &firm_start, &size);
1111 	if (rv != 0) {
1112 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
1113 		    "module(%s) loadsym error", wusb_fwmod);
1114 
1115 		error = USB_FAILURE;
1116 		goto checkstatus;
1117 	}
1118 
1119 	if (size >= MAX_DAT_FILE_SIZE) {
1120 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
1121 		    "file size too big");
1122 
1123 		error = USB_FAILURE;
1124 		goto checkstatus;
1125 	} else {
1126 		firmware_image = (unsigned char *)kmem_alloc(size, KM_SLEEP);
1127 
1128 		if (!firmware_image) {
1129 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
1130 			    wusb_dfp->wusb_df_log_hdl, "malloc failed");
1131 
1132 			error = USB_FAILURE;
1133 			goto checkstatus;
1134 		}
1135 
1136 		(void) memcpy(firmware_image, firm_start, size);
1137 	}
1138 
1139 	USB_DPRINTF_L3(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
1140 	    "file size = %d", (int)size);
1141 
1142 	/*
1143 	 * close the module, return if 1) fail to close or 2) encounter error
1144 	 * when getting above symbol
1145 	 */
1146 checkstatus:
1147 	if (modp != NULL)
1148 		rv = ddi_modclose(modp);
1149 
1150 	if ((rv != 0) || (error != USB_SUCCESS)) {
1151 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
1152 		    "modclose(%s) error", wusb_fwmod);
1153 
1154 		return (USB_FAILURE);
1155 	}
1156 
1157 	/*
1158 	 * BIN firmware has this format:
1159 	 * address(4B) + length(4B) + data(Length Bytes) ... repeat
1160 	 */
1161 	pdata = firmware_image;
1162 	data_end = firmware_image + size;
1163 	while (pdata < data_end) {
1164 		error = USB_FAILURE;
1165 		pdsc = (fw_dsc_t *)kmem_zalloc(sizeof (fw_dsc_t), KM_SLEEP);
1166 
1167 		/* hdr_offset = pdata - firmware_image; */
1168 		remaining_size = data_end - pdata;
1169 
1170 		if ((pdata + 8) > data_end) {
1171 			kmem_free(pdsc, sizeof (fw_dsc_t));
1172 			free_fw_dscs(rcd_head);
1173 			break;
1174 		}
1175 
1176 		pdsc->next = NULL;
1177 		pdsc->addr = char2int32(pdata);
1178 		pdsc->size = 4 * char2int32(pdata + 4);
1179 		pdsc->data = pdata + 8;
1180 		if (pdsc->size > remaining_size) {
1181 			kmem_free(pdsc, sizeof (fw_dsc_t));
1182 			free_fw_dscs(rcd_head);
1183 			break;
1184 		}
1185 		USB_DPRINTF_L3(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
1186 		    "address = 0x%x, length = 0x%x, "
1187 		    "first 4 byte is : 0x%02x 0x%02x 0x%02x 0x%02x",
1188 		    pdsc->addr, (int)pdsc->size, pdsc->data[0], pdsc->data[1],
1189 		    pdsc->data[2], pdsc->data[3]);
1190 
1191 		pdata += 8 + pdsc->size;
1192 		if (rcd_head == NULL) {
1193 			rcd_head = pdsc;
1194 		} else {
1195 			tmpr->next = pdsc;
1196 		}
1197 
1198 		tmpr = pdsc; /* tmp record */
1199 		record_cnt ++;
1200 		error = USB_SUCCESS;
1201 	}
1202 
1203 	USB_DPRINTF_L3(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
1204 	    "Start download firmware ...");
1205 	for (pdsc = rcd_head; pdsc != NULL; pdsc = pdsc->next) {
1206 		error = wusb_df_send_data(wusb_dfp, pdsc->addr,
1207 		    pdsc->data, pdsc->size);
1208 		if (error != USB_SUCCESS) {
1209 
1210 			USB_DPRINTF_L2(PRINT_MASK_ATTA,
1211 			    wusb_dfp->wusb_df_log_hdl, "Download failure!");
1212 			break;
1213 		}
1214 
1215 		delay(drv_usectohz(1000));
1216 	}
1217 
1218 	USB_DPRINTF_L2(PRINT_MASK_ATTA, wusb_dfp->wusb_df_log_hdl,
1219 	    "Download firmware end.");
1220 
1221 	free_fw_dscs(rcd_head);
1222 	kmem_free(firmware_image, size);
1223 
1224 	return (error);
1225 }
1226 
1227 
1228 /*
1229  * Firmware download. Program device special registers and then call
1230  * wusb_df_fw_download() to download the true data.
1231  */
1232 static int
wusb_df_firmware_download(wusb_df_state_t * wusbp)1233 wusb_df_firmware_download(wusb_df_state_t *wusbp)
1234 {
1235 	int error = USB_FAILURE;
1236 	unsigned char buf[4];
1237 
1238 	(void) memset(buf, 0, 4);
1239 	/* program the device register to make it ready to accept fw */
1240 	error = wusb_df_send_data(wusbp, 0x800000c0, buf, 4);
1241 	if (error != USB_SUCCESS) {
1242 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusbp->wusb_df_log_hdl,
1243 		    "Fail init");
1244 		return (error);
1245 	}
1246 
1247 	error = wusb_df_fw_download(wusbp);
1248 	if (error != USB_SUCCESS) {
1249 		USB_DPRINTF_L2(PRINT_MASK_ATTA, wusbp->wusb_df_log_hdl,
1250 		    "Fail to download firmware");
1251 		return (error);
1252 	}
1253 
1254 	buf[0] = 0x48;
1255 	buf[1] = 0x56;
1256 	buf[2] = 0x2c;
1257 	buf[3] = 0x00;
1258 	error = wusb_df_send_data(wusbp, 0x80008060, buf, 4);
1259 	if (error != USB_SUCCESS) {
1260 		return (error);
1261 	}
1262 
1263 	(void) memset(buf, 0, 4);
1264 	buf[0] = 0x18;
1265 	/* firmware download finished, program the device to lock fw */
1266 	error = wusb_df_send_data(wusbp, 0x800000c0, buf, 4);
1267 
1268 	return (error);
1269 }
1270