160b08185Syz /*
260b08185Syz  * CDDL HEADER START
360b08185Syz  *
460b08185Syz  * The contents of this file are subject to the terms of the
5688b07c5Sgc  * Common Development and Distribution License (the "License").
6688b07c5Sgc  * You may not use this file except in compliance with the License.
760b08185Syz  *
860b08185Syz  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
960b08185Syz  * or http://www.opensolaris.org/os/licensing.
1060b08185Syz  * See the License for the specific language governing permissions
1160b08185Syz  * and limitations under the License.
1260b08185Syz  *
1360b08185Syz  * When distributing Covered Code, include this CDDL HEADER in each
1460b08185Syz  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1560b08185Syz  * If applicable, add the following below this CDDL HEADER, with the
1660b08185Syz  * fields enclosed by brackets "[]" replaced with your own identifying
1760b08185Syz  * information: Portions Copyright [yyyy] [name of copyright owner]
1860b08185Syz  *
1960b08185Syz  * CDDL HEADER END
2060b08185Syz  */
2160b08185Syz 
2260b08185Syz /*
2322eb7cb5Sgd  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2460b08185Syz  * Use is subject to license terms.
2560b08185Syz  */
2660b08185Syz 
2760b08185Syz 
2860b08185Syz /*
2960b08185Syz  *
3060b08185Syz  * DSD code for keyspan usb2serial adapters
3160b08185Syz  *
3260b08185Syz  */
3360b08185Syz #include <sys/types.h>
3460b08185Syz #include <sys/param.h>
3560b08185Syz #include <sys/conf.h>
3660b08185Syz #include <sys/stream.h>
3760b08185Syz #include <sys/strsun.h>
3860b08185Syz #include <sys/termio.h>
3960b08185Syz #include <sys/termiox.h>
4060b08185Syz #include <sys/ddi.h>
4160b08185Syz #include <sys/sunddi.h>
4260b08185Syz 
4360b08185Syz #define	USBDRV_MAJOR_VER	2
4460b08185Syz #define	USBDRV_MINOR_VER	0
4560b08185Syz 
4660b08185Syz #include <sys/usb/usba.h>
4760b08185Syz 
4860b08185Syz #include <sys/usb/clients/usbser/usbser_dsdi.h>
4960b08185Syz #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_var.h>
5060b08185Syz #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_pipe.h>
5160b08185Syz 
5260b08185Syz #include <sys/usb/clients/usbser/usbser_keyspan/usa90msg.h>
5360b08185Syz #include <sys/usb/clients/usbser/usbser_keyspan/usa49msg.h>
5460b08185Syz 
5560b08185Syz /*
5660b08185Syz  * DSD operations which are filled in ds_ops structure.
5760b08185Syz  */
5860b08185Syz static int	keyspan_attach(ds_attach_info_t *);
5960b08185Syz static void	keyspan_detach(ds_hdl_t);
6060b08185Syz static int	keyspan_register_cb(ds_hdl_t, uint_t, ds_cb_t *);
6160b08185Syz static void	keyspan_unregister_cb(ds_hdl_t, uint_t);
6260b08185Syz static int	keyspan_open_port(ds_hdl_t, uint_t);
6360b08185Syz static int	keyspan_close_port(ds_hdl_t, uint_t);
6460b08185Syz 
6560b08185Syz /* power management */
6660b08185Syz static int	keyspan_usb_power(ds_hdl_t, int, int, int *);
6760b08185Syz static int	keyspan_suspend(ds_hdl_t);
6860b08185Syz static int	keyspan_resume(ds_hdl_t);
6960b08185Syz 
7060b08185Syz /* hotplug */
7160b08185Syz static int	keyspan_disconnect(ds_hdl_t);
7260b08185Syz static int	keyspan_reconnect(ds_hdl_t);
7360b08185Syz 
7460b08185Syz /* standard UART operations */
7560b08185Syz static int	keyspan_set_port_params(ds_hdl_t, uint_t, ds_port_params_t *);
7660b08185Syz static int	keyspan_set_modem_ctl(ds_hdl_t, uint_t, int, int);
7760b08185Syz static int	keyspan_get_modem_ctl(ds_hdl_t, uint_t, int, int *);
7860b08185Syz static int	keyspan_break_ctl(ds_hdl_t, uint_t, int);
7960b08185Syz static int	keyspan_loopback(ds_hdl_t, uint_t, int);
8060b08185Syz 
8160b08185Syz /* data xfer */
8260b08185Syz static int	keyspan_tx(ds_hdl_t, uint_t, mblk_t *);
8360b08185Syz static mblk_t	*keyspan_rx(ds_hdl_t, uint_t);
8460b08185Syz static void	keyspan_stop(ds_hdl_t, uint_t, int);
8560b08185Syz static void	keyspan_start(ds_hdl_t, uint_t, int);
8660b08185Syz static int	keyspan_fifo_flush(ds_hdl_t, uint_t, int);
8760b08185Syz static int	keyspan_fifo_drain(ds_hdl_t, uint_t, int);
8860b08185Syz 
8960b08185Syz /*
9060b08185Syz  * Sub-routines
9160b08185Syz  */
9260b08185Syz 
9360b08185Syz /* configuration routines */
9460b08185Syz static void	keyspan_free_soft_state(keyspan_state_t *);
9560b08185Syz static void	keyspan_init_sync_objs(keyspan_state_t *);
9660b08185Syz static void	keyspan_fini_sync_objs(keyspan_state_t *);
9760b08185Syz static int	keyspan_usb_register(keyspan_state_t *);
9860b08185Syz static void	keyspan_usb_unregister(keyspan_state_t *);
9960b08185Syz static int	keyspan_attach_dev(keyspan_state_t *);
10060b08185Syz static void	keyspan_attach_ports(keyspan_state_t *);
10160b08185Syz static void	keyspan_detach_ports(keyspan_state_t *);
10260b08185Syz static void	keyspan_init_port_params(keyspan_state_t *);
10360b08185Syz static void	keyspan_free_descr_tree(keyspan_state_t *);
10460b08185Syz static int	keyspan_register_events(keyspan_state_t *);
10560b08185Syz static void	keyspan_unregister_events(keyspan_state_t *);
10660b08185Syz static void	keyspan_set_dev_state_online(keyspan_state_t *);
10760b08185Syz 
10860b08185Syz /* hotplug */
10960b08185Syz static int	keyspan_restore_device_state(keyspan_state_t *);
11060b08185Syz static int	keyspan_restore_ports_state(keyspan_state_t *);
11160b08185Syz 
11260b08185Syz /* power management */
11360b08185Syz static int	keyspan_create_pm_components(keyspan_state_t *);
11460b08185Syz static void	keyspan_destroy_pm_components(keyspan_state_t *);
11560b08185Syz static int	keyspan_pm_set_busy(keyspan_state_t *);
11660b08185Syz static void	keyspan_pm_set_idle(keyspan_state_t *);
11760b08185Syz static int	keyspan_pwrlvl0(keyspan_state_t *);
11860b08185Syz static int	keyspan_pwrlvl1(keyspan_state_t *);
11960b08185Syz static int	keyspan_pwrlvl2(keyspan_state_t *);
12060b08185Syz static int	keyspan_pwrlvl3(keyspan_state_t *);
12160b08185Syz 
12260b08185Syz /* pipe operations */
12360b08185Syz static int	keyspan_attach_pipes(keyspan_state_t *);
12460b08185Syz static void	keyspan_detach_pipes(keyspan_state_t *);
12560b08185Syz static void	keyspan_disconnect_pipes(keyspan_state_t *);
12660b08185Syz static int	keyspan_reconnect_pipes(keyspan_state_t *);
12760b08185Syz 
12860b08185Syz /* data transfer routines */
12960b08185Syz static int	keyspan_wait_tx_drain(keyspan_port_t *, int);
13060b08185Syz 
13160b08185Syz /* misc */
13260b08185Syz static void	keyspan_default_port_params(keyspan_port_t *);
13360b08185Syz static void	keyspan_build_cmd_msg(keyspan_port_t *, ds_port_params_t *);
13460b08185Syz static void	keyspan_save_port_params(keyspan_port_t	*);
13560b08185Syz 
13660b08185Syz /*
13760b08185Syz  * Model specific functions.
13860b08185Syz  */
13960b08185Syz 
14060b08185Syz /* usa19hs specific functions */
14160b08185Syz static void	keyspan_build_cmd_msg_usa19hs(keyspan_port_t *,
14260b08185Syz     ds_port_params_t *);
14360b08185Syz static void	keyspan_default_port_params_usa19hs(keyspan_port_t *);
14460b08185Syz static void	keyspan_save_port_params_usa19hs(keyspan_port_t	*);
14560b08185Syz 
146c138f478Syz 
14760b08185Syz /* usa49 specific functions */
14860b08185Syz static void	keyspan_build_cmd_msg_usa49(keyspan_port_t *,
14960b08185Syz     ds_port_params_t *);
15060b08185Syz static void	keyspan_default_port_params_usa49(keyspan_port_t *);
15160b08185Syz static void	keyspan_save_port_params_usa49(keyspan_port_t	*);
152c138f478Syz 
15360b08185Syz 
15460b08185Syz /*
15560b08185Syz  * DSD ops structure
15660b08185Syz  */
157*e8ed0869SJohn Beck ds_ops_t keyspan_ds_ops = {
15860b08185Syz 	DS_OPS_VERSION,
15960b08185Syz 	keyspan_attach,
16060b08185Syz 	keyspan_detach,
16160b08185Syz 	keyspan_register_cb,
16260b08185Syz 	keyspan_unregister_cb,
16360b08185Syz 	keyspan_open_port,
16460b08185Syz 	keyspan_close_port,
16560b08185Syz 	keyspan_usb_power,
16660b08185Syz 	keyspan_suspend,
16760b08185Syz 	keyspan_resume,
16860b08185Syz 	keyspan_disconnect,
16960b08185Syz 	keyspan_reconnect,
17060b08185Syz 	keyspan_set_port_params,
17160b08185Syz 	keyspan_set_modem_ctl,
17260b08185Syz 	keyspan_get_modem_ctl,
17360b08185Syz 	keyspan_break_ctl,
17460b08185Syz 	keyspan_loopback,
17560b08185Syz 	keyspan_tx,
17660b08185Syz 	keyspan_rx,
17760b08185Syz 	keyspan_stop,
17860b08185Syz 	keyspan_start,
17960b08185Syz 	keyspan_fifo_flush,
18060b08185Syz 	keyspan_fifo_drain
18160b08185Syz };
18260b08185Syz 
18360b08185Syz /*
18460b08185Syz  *  For USA19HS baud speed, precalculated using the following algorithm:
18560b08185Syz  *
18660b08185Syz  *	speed = (uint16_t)(14769231L / baud);
18760b08185Syz  */
18860b08185Syz static uint16_t	keyspan_speedtab_usa19hs[] = {
18960b08185Syz 	0x0,	/* B0 */
19060b08185Syz 	0x481d,	/* B50 */
19160b08185Syz 	0x3013,	/* B75 */
19260b08185Syz 	0x20c7,	/* B110 */
19360b08185Syz 	0x1ae8,	/* B134 */
19460b08185Syz 	0x1809,	/* B150 */
19560b08185Syz 	0x1207,	/* B200 */
19660b08185Syz 	0xc04,	/* B300 */
19760b08185Syz 	0x602,	/* B600 */
19860b08185Syz 	0x301,	/* B1200 */
19960b08185Syz 	0x200,	/* B1800 */
20060b08185Syz 	0x180,	/* B2400 */
20160b08185Syz 	0xc0,	/* B4800 */
20260b08185Syz 	0x60,	/* B9600 */
20360b08185Syz 	0x30,	/* B19200 */
20460b08185Syz 	0x18,	/* B38400 */
20560b08185Syz 	0x10,	/* B57600 */
20660b08185Syz 	0xc,	/* B76800 */
20760b08185Syz 	0x8,	/* B115200 */
20860b08185Syz 	0x6,	/* B153600 */
20960b08185Syz 	0x4,	/* B230400 */
21060b08185Syz };
211c138f478Syz 
21260b08185Syz /*
21360b08185Syz  *  For USA49WLC baud speed, precalculated.
21460b08185Syz  */
21560b08185Syz static uint16_t	keyspan_speedtab_usa49[] = {
21660b08185Syz 	0x0,	/* B0 */
21760b08185Syz 	0x7530,	/* B50 */
21860b08185Syz 	0x4e20,	/* B75 */
21960b08185Syz 	0x3544,	/* B110 */
22060b08185Syz 	0x2bba,	/* B134 */
22160b08185Syz 	0x2710,	/* B150 */
22260b08185Syz 	0x1d4c,	/* B200 */
22360b08185Syz 	0x1388,	/* B300 */
22460b08185Syz 	0x9c4,	/* B600 */
22560b08185Syz 	0x4e2,	/* B1200 */
22660b08185Syz 	0x25e,	/* B1800 */
22760b08185Syz 	0x271,	/* B2400 */
22860b08185Syz 	0xfa,	/* B4800 */
22960b08185Syz 	0x7d,	/* B9600 */
23060b08185Syz 	0x19,	/* B19200 */
23160b08185Syz 	0x27,	/* B38400 */
23260b08185Syz 	0x1a,	/* B57600 */
23360b08185Syz 	0xd,	/* B76800 */
23460b08185Syz 	0xd,	/* B115200 */
23560b08185Syz 	0x6,	/* B153600 */
23660b08185Syz 	0x4,	/* B230400 */
23760b08185Syz };
23860b08185Syz 
23960b08185Syz /*
24060b08185Syz  *  For USA49WLC prescaler, precalculated.
24160b08185Syz  */
24260b08185Syz static uint8_t	keyspan_prescaler_49wlc[] = {
24360b08185Syz 	0x0,	/* B0 */
24460b08185Syz 	0x8,	/* B50 */
24560b08185Syz 	0x8,	/* B75 */
24660b08185Syz 	0x8,	/* B110 */
24760b08185Syz 	0x8,	/* B134 */
24860b08185Syz 	0x8,	/* B150 */
24960b08185Syz 	0x8,	/* B200 */
25060b08185Syz 	0x8,	/* B300 */
25160b08185Syz 	0x8,	/* B600 */
25260b08185Syz 	0x8,	/* B1200 */
25360b08185Syz 	0xb,	/* B1800 */
25460b08185Syz 	0x8,	/* B2400 */
25560b08185Syz 	0xa,	/* B4800 */
25660b08185Syz 	0xa,	/* B9600 */
25760b08185Syz 	0x19,	/* B19200 */
25860b08185Syz 	0x8,	/* B38400 */
25960b08185Syz 	0x8,	/* B57600 */
26060b08185Syz 	0xc,	/* B76800 */
26160b08185Syz 	0x8,	/* B115200 */
26260b08185Syz 	0xd,	/* B153600 */
26360b08185Syz 	0xd,	/* B230400 */
26460b08185Syz };
265c138f478Syz 
26660b08185Syz 
26760b08185Syz /* convert baud code into baud rate */
26860b08185Syz static int keyspan_speed2baud[] = {
26960b08185Syz 	0,	/* B0 */
27060b08185Syz 	50,	/* B50 */
27160b08185Syz 	75,	/* B75 */
27260b08185Syz 	110,	/* B110 */
27360b08185Syz 	134,	/* B134 */
27460b08185Syz 	150,	/* B150 */
27560b08185Syz 	200,	/* B200 */
27660b08185Syz 	300,	/* B300 */
27760b08185Syz 	600,	/* B600 */
27860b08185Syz 	1200,	/* B1200 */
27960b08185Syz 	1800,	/* B1800 */
28060b08185Syz 	2400,	/* B2400 */
28160b08185Syz 	4800,	/* B4800 */
28260b08185Syz 	9600,	/* B9600 */
28360b08185Syz 	19200,	/* B19200 */
28460b08185Syz 	38400,	/* B38400 */
28560b08185Syz 	57600,	/* B57600 */
28660b08185Syz 	76800,	/* B76800 */
28760b08185Syz 	115200,	/* B115200 */
28860b08185Syz 	153600,	/* B153600 */
28960b08185Syz 	230400,	/* B230400 */
29060b08185Syz };
29160b08185Syz 
29260b08185Syz 
29360b08185Syz /* debug support */
29460b08185Syz static uint_t	keyspan_errlevel = USB_LOG_L4;
29560b08185Syz static uint_t	keyspan_errmask = DPRINT_MASK_ALL;
29660b08185Syz static uint_t	keyspan_instance_debug = (uint_t)-1;
29760b08185Syz 
29860b08185Syz static int
keyspan_attach(ds_attach_info_t * aip)29960b08185Syz keyspan_attach(ds_attach_info_t *aip)
30060b08185Syz {
30160b08185Syz 	keyspan_state_t	*ksp;
30202dd2108Slg 	int	rval = USB_SUCCESS;
30360b08185Syz 
30460b08185Syz 	ksp = (keyspan_state_t *)kmem_zalloc(sizeof (keyspan_state_t),
30560b08185Syz 	    KM_SLEEP);
30660b08185Syz 	ksp->ks_dip = aip->ai_dip;
30760b08185Syz 	ksp->ks_usb_events = aip->ai_usb_events;
30860b08185Syz 	*aip->ai_hdl = (ds_hdl_t)ksp;
30960b08185Syz 
31060b08185Syz 	if (keyspan_usb_register(ksp) != USB_SUCCESS) {
31160b08185Syz 
31260b08185Syz 		goto fail_register;
31360b08185Syz 	}
31460b08185Syz 
31560b08185Syz 	/* init mutex and semaphore */
31660b08185Syz 	keyspan_init_sync_objs(ksp);
31760b08185Syz 
31860b08185Syz 	/* get device specific parameters */
31960b08185Syz 	if (keyspan_attach_dev(ksp) != USB_SUCCESS) {
320d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh, "fail attach dev ");
32160b08185Syz 
32260b08185Syz 		goto fail_attach_dev;
32360b08185Syz 	}
32460b08185Syz 
32560b08185Syz 	keyspan_attach_ports(ksp);
32660b08185Syz 
32702dd2108Slg 	switch (ksp->ks_dev_spec.id_product) {
32802dd2108Slg 	case KEYSPAN_USA19HS_PID:
32902dd2108Slg 	case KEYSPAN_USA49WLC_PID:
33002dd2108Slg 		rval = keyspan_init_pipes(ksp);
33102dd2108Slg 
33202dd2108Slg 		break;
33302dd2108Slg 
33402dd2108Slg 	case KEYSPAN_USA49WG_PID:
33502dd2108Slg 		rval = keyspan_init_pipes_usa49wg(ksp);
33602dd2108Slg 
33702dd2108Slg 		break;
33802dd2108Slg 
33902dd2108Slg 	default:
34002dd2108Slg 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh, "keyspan_attach:"
34102dd2108Slg 		    "the device's product id can't be recognized");
34202dd2108Slg 
34302dd2108Slg 		return (USB_FAILURE);
34402dd2108Slg 	}
34502dd2108Slg 
34602dd2108Slg 	if (rval != USB_SUCCESS) {
347d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
34860b08185Syz 		    "keyspan_init_pipes: failed.");
34960b08185Syz 
35060b08185Syz 		goto fail_init_pipes;
35160b08185Syz 	}
35260b08185Syz 
35360b08185Syz 	keyspan_init_port_params(ksp);
35460b08185Syz 	keyspan_free_descr_tree(ksp);
35560b08185Syz 	keyspan_set_dev_state_online(ksp);
35660b08185Syz 
35760b08185Syz 	if (keyspan_create_pm_components(ksp) != USB_SUCCESS) {
358d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
35960b08185Syz 		    "keyspan_create_pm_components: failed.");
36060b08185Syz 
36160b08185Syz 		goto fail_pm;
36260b08185Syz 	}
36360b08185Syz 
36460b08185Syz 	if (keyspan_register_events(ksp) != USB_SUCCESS) {
36560b08185Syz 
36660b08185Syz 		goto fail_events;
36760b08185Syz 	}
36860b08185Syz 
36960b08185Syz 	/* open the global pipes */
37060b08185Syz 	if (keyspan_attach_pipes(ksp) != USB_SUCCESS) {
371d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
37260b08185Syz 		    "keyspan_attach_pipes: failed.");
37360b08185Syz 
37460b08185Syz 		goto fail_attach_pipes;
37560b08185Syz 	}
37660b08185Syz 
37760b08185Syz 	*aip->ai_port_cnt = ksp->ks_dev_spec.port_cnt;
37860b08185Syz 
37960b08185Syz 	return (USB_SUCCESS);
38060b08185Syz 
38160b08185Syz fail_attach_pipes:
38260b08185Syz 	keyspan_unregister_events(ksp);
38360b08185Syz fail_events:
38460b08185Syz 	keyspan_destroy_pm_components(ksp);
38560b08185Syz fail_pm:
38660b08185Syz 	keyspan_fini_pipes(ksp);
38760b08185Syz fail_init_pipes:
38860b08185Syz 	keyspan_detach_ports(ksp);
38960b08185Syz fail_attach_dev:
39060b08185Syz 	keyspan_fini_sync_objs(ksp);
39160b08185Syz 	keyspan_usb_unregister(ksp);
39260b08185Syz fail_register:
39360b08185Syz 	keyspan_free_soft_state(ksp);
39460b08185Syz 
39560b08185Syz 	return (USB_FAILURE);
39660b08185Syz }
39760b08185Syz 
39860b08185Syz 
39960b08185Syz /*
40060b08185Syz  * ds_detach
40160b08185Syz  */
40260b08185Syz static void
keyspan_detach(ds_hdl_t hdl)40360b08185Syz keyspan_detach(ds_hdl_t hdl)
40460b08185Syz {
40560b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
40660b08185Syz 
40760b08185Syz 	keyspan_detach_pipes(ksp);
40860b08185Syz 	keyspan_unregister_events(ksp);
40960b08185Syz 	keyspan_destroy_pm_components(ksp);
41060b08185Syz 	keyspan_fini_pipes(ksp);
41160b08185Syz 	keyspan_detach_ports(ksp);
41260b08185Syz 	keyspan_fini_sync_objs(ksp);
41360b08185Syz 	keyspan_usb_unregister(ksp);
41460b08185Syz 	keyspan_free_soft_state(ksp);
41560b08185Syz }
41660b08185Syz 
41760b08185Syz /*
41860b08185Syz  * ds_register_cb
41960b08185Syz  */
42060b08185Syz static int
keyspan_register_cb(ds_hdl_t hdl,uint_t port_num,ds_cb_t * cb)42160b08185Syz keyspan_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb)
42260b08185Syz {
42360b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
42460b08185Syz 	keyspan_port_t	*kp;
42560b08185Syz 
42660b08185Syz 	if (port_num >= ksp->ks_dev_spec.port_cnt) {
42760b08185Syz 
42860b08185Syz 		return (USB_FAILURE);
42960b08185Syz 	}
43060b08185Syz 	kp = &ksp->ks_ports[port_num];
43160b08185Syz 	kp->kp_cb = *cb;
43260b08185Syz 
43360b08185Syz 	return (USB_SUCCESS);
43460b08185Syz }
43560b08185Syz 
43660b08185Syz /*
43760b08185Syz  * ds_unregister_cb
43860b08185Syz  */
43960b08185Syz static void
keyspan_unregister_cb(ds_hdl_t hdl,uint_t port_num)44060b08185Syz keyspan_unregister_cb(ds_hdl_t hdl, uint_t port_num)
44160b08185Syz {
44260b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
44360b08185Syz 	keyspan_port_t	*kp;
44460b08185Syz 
44560b08185Syz 	if (port_num < ksp->ks_dev_spec.port_cnt) {
44660b08185Syz 		kp = &ksp->ks_ports[port_num];
44760b08185Syz 		bzero(&kp->kp_cb, sizeof (kp->kp_cb));
44860b08185Syz 	}
44960b08185Syz }
45060b08185Syz 
45160b08185Syz /*
45260b08185Syz  * initialize hardware serial port
45360b08185Syz  *
45460b08185Syz  * 'open_pipes' specifies whether to open USB pipes or not
45560b08185Syz  */
45660b08185Syz int
keyspan_open_hw_port(keyspan_port_t * kp,boolean_t open_pipes)45760b08185Syz keyspan_open_hw_port(keyspan_port_t *kp, boolean_t open_pipes)
45860b08185Syz {
45960b08185Syz 	int		rval;
46002dd2108Slg 	keyspan_state_t	*ksp = kp->kp_ksp;
46160b08185Syz 
46260b08185Syz 	USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh,
46360b08185Syz 	    "keyspan_open_hw_port: [%d]", kp->kp_port_num);
46460b08185Syz 
46560b08185Syz 	if (open_pipes) {
46660b08185Syz 
46760b08185Syz 		/* open r/w pipes for this port */
46860b08185Syz 		if ((rval = keyspan_open_port_pipes(kp)) != USB_SUCCESS) {
46960b08185Syz 
47060b08185Syz 			return (rval);
47160b08185Syz 		}
47260b08185Syz 	}
47360b08185Syz 
47460b08185Syz 	mutex_enter(&kp->kp_mutex);
47560b08185Syz 	kp->kp_state = KEYSPAN_PORT_OPEN;
47660b08185Syz 	mutex_exit(&kp->kp_mutex);
47760b08185Syz 
47802dd2108Slg 	switch (ksp->ks_dev_spec.id_product) {
47902dd2108Slg 	case KEYSPAN_USA19HS_PID:
48002dd2108Slg 	case KEYSPAN_USA49WLC_PID:
48102dd2108Slg 		if ((rval = keyspan_receive_data(&kp->kp_datain_pipe,
4824ee52f77Slg 		    kp->kp_read_len, kp)) != USB_SUCCESS) {
48360b08185Syz 
48402dd2108Slg 				goto fail;
48502dd2108Slg 		}
48602dd2108Slg 
48702dd2108Slg 		break;
48802dd2108Slg 
48902dd2108Slg 	case KEYSPAN_USA49WG_PID:
49002dd2108Slg 		mutex_enter(&ksp->ks_mutex);
49102dd2108Slg 		/* open data in pipe the first time, start receiving data */
49202dd2108Slg 		if ((ksp->ks_datain_open_cnt == 1) && open_pipes) {
49302dd2108Slg 			mutex_exit(&ksp->ks_mutex);
49402dd2108Slg 			if ((rval = keyspan_receive_data(&kp->kp_datain_pipe,
4954ee52f77Slg 			    kp->kp_read_len, kp)) != USB_SUCCESS) {
49602dd2108Slg 
49702dd2108Slg 					goto fail;
49802dd2108Slg 			}
49902dd2108Slg 		/* the device is reconnected to host, restart receiving data */
50002dd2108Slg 		} else if ((ksp->ks_reconnect_flag) && (!open_pipes)) {
50102dd2108Slg 			mutex_exit(&ksp->ks_mutex);
50202dd2108Slg 			if ((rval = keyspan_receive_data(&kp->kp_datain_pipe,
5034ee52f77Slg 			    kp->kp_read_len, kp)) != USB_SUCCESS) {
50402dd2108Slg 
50502dd2108Slg 					goto fail;
50602dd2108Slg 			}
50702dd2108Slg 			mutex_enter(&ksp->ks_mutex);
50802dd2108Slg 			ksp->ks_reconnect_flag = 0;
50902dd2108Slg 			mutex_exit(&ksp->ks_mutex);
51002dd2108Slg 
51102dd2108Slg 		} else {
51202dd2108Slg 			mutex_exit(&ksp->ks_mutex);
51302dd2108Slg 		}
51402dd2108Slg 
51502dd2108Slg 		break;
51602dd2108Slg 
51702dd2108Slg 	default:
51802dd2108Slg 		USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, "keyspan_open_hw_port:"
51902dd2108Slg 		    "the device's product id can't be recognized");
52002dd2108Slg 
52102dd2108Slg 		return (USB_FAILURE);
52260b08185Syz 	}
52360b08185Syz 
52460b08185Syz 	/* set the default port parameters and send cmd msg to enable port */
52560b08185Syz 	mutex_enter(&kp->kp_mutex);
52660b08185Syz 	keyspan_default_port_params(kp);
52760b08185Syz 	mutex_exit(&kp->kp_mutex);
52860b08185Syz 
52960b08185Syz 	(void) keyspan_send_cmd(kp);
53060b08185Syz 
53160b08185Syz 	USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh,
53260b08185Syz 	    "keyspan_open_hw_port: [%d] finished", kp->kp_port_num);
53360b08185Syz 
53460b08185Syz 	return (rval);
53560b08185Syz 
53660b08185Syz fail:
53760b08185Syz 
53860b08185Syz 	mutex_enter(&kp->kp_mutex);
53960b08185Syz 	kp->kp_state = KEYSPAN_PORT_CLOSED;
54060b08185Syz 	mutex_exit(&kp->kp_mutex);
54160b08185Syz 
54260b08185Syz 	if (open_pipes) {
54360b08185Syz 
54460b08185Syz 		/* close all ports' data pipes */
54560b08185Syz 		keyspan_close_port_pipes(kp);
54660b08185Syz 	}
54760b08185Syz 
548d291d9f2Sfrits 	USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh,
54960b08185Syz 	    "keyspan_open_hw_port: failed. This port can't be used.");
55060b08185Syz 
55160b08185Syz 	return (rval);
55260b08185Syz }
55360b08185Syz 
55460b08185Syz /*
55560b08185Syz  * ds_open_port
55660b08185Syz  */
55760b08185Syz static int
keyspan_open_port(ds_hdl_t hdl,uint_t port_num)55860b08185Syz keyspan_open_port(ds_hdl_t hdl, uint_t port_num)
55960b08185Syz {
56060b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
56160b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
56260b08185Syz 	int		rval;
56360b08185Syz 
56460b08185Syz 	if (port_num >= ksp->ks_dev_spec.port_cnt) {
56560b08185Syz 
56660b08185Syz 		return (USB_FAILURE);
56760b08185Syz 	}
56860b08185Syz 	USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh, "keyspan_open_port");
56960b08185Syz 
57060b08185Syz 	mutex_enter(&ksp->ks_mutex);
57160b08185Syz 	if (ksp->ks_dev_state == USB_DEV_DISCONNECTED) {
57260b08185Syz 		mutex_exit(&ksp->ks_mutex);
57360b08185Syz 
57460b08185Syz 		return (USB_FAILURE);
57560b08185Syz 	}
57660b08185Syz 	mutex_exit(&ksp->ks_mutex);
57760b08185Syz 
57860b08185Syz 	if (keyspan_pm_set_busy(ksp) != USB_SUCCESS) {
57960b08185Syz 
58060b08185Syz 		return (USB_FAILURE);
58160b08185Syz 	}
58260b08185Syz 
58360b08185Syz 	/*
58460b08185Syz 	 * initialize state
58560b08185Syz 	 */
58660b08185Syz 	mutex_enter(&kp->kp_mutex);
58760b08185Syz 	ASSERT(kp->kp_state == KEYSPAN_PORT_CLOSED);
58860b08185Syz 	ASSERT((kp->kp_rx_mp == NULL) && (kp->kp_tx_mp == NULL));
58960b08185Syz 
59060b08185Syz 	kp->kp_state = KEYSPAN_PORT_OPENING;
59160b08185Syz 	kp->kp_flags = 0;
59260b08185Syz 	mutex_exit(&kp->kp_mutex);
59360b08185Syz 
59460b08185Syz 	/*
59560b08185Syz 	 * initialize hardware serial port, B_TRUE means open pipes
59660b08185Syz 	 */
59760b08185Syz 	sema_p(&ksp->ks_pipes_sema);
59860b08185Syz 	rval = keyspan_open_hw_port(kp, B_TRUE);
59960b08185Syz 	if (rval != USB_SUCCESS) {
60060b08185Syz 		keyspan_pm_set_idle(ksp);
60160b08185Syz 	}
60260b08185Syz 	sema_v(&ksp->ks_pipes_sema);
60360b08185Syz 
60460b08185Syz 	return (rval);
60560b08185Syz }
60660b08185Syz 
60760b08185Syz 
60860b08185Syz /*
60960b08185Syz  * close hardware serial port
61060b08185Syz  */
61160b08185Syz void
keyspan_close_hw_port(keyspan_port_t * kp)61260b08185Syz keyspan_close_hw_port(keyspan_port_t *kp)
61360b08185Syz {
61460b08185Syz 	keyspan_state_t	*ksp = kp->kp_ksp;
61560b08185Syz 
61660b08185Syz 	ASSERT(!mutex_owned(&kp->kp_mutex));
61760b08185Syz 
61860b08185Syz 	USB_DPRINTF_L4(DPRINT_CLOSE, kp->kp_lh,
61960b08185Syz 	    "keyspan_close_hw_port");
62060b08185Syz 
62160b08185Syz 	/*
62260b08185Syz 	 * The bulk IN/OUT pipes might have got closed due to
62360b08185Syz 	 * a device disconnect event. So its required to check the
62460b08185Syz 	 * pipe handle and proceed if it is not NULL
62560b08185Syz 	 */
62660b08185Syz 
62760b08185Syz 	mutex_enter(&kp->kp_mutex);
62860b08185Syz 	if ((kp->kp_datain_pipe.pipe_handle == NULL) &&
62960b08185Syz 	    (kp->kp_dataout_pipe.pipe_handle == NULL)) {
63060b08185Syz 		mutex_exit(&kp->kp_mutex);
63160b08185Syz 
63260b08185Syz 		return;
63360b08185Syz 	}
63460b08185Syz 
63560b08185Syz 	switch (ksp->ks_dev_spec.id_product) {
63660b08185Syz 	case KEYSPAN_USA19HS_PID:
63760b08185Syz 		keyspan_build_cmd_msg_usa19hs(kp, NULL);
63860b08185Syz 		kp->kp_ctrl_msg.usa19hs.portEnabled = 0;
63960b08185Syz 		kp->kp_ctrl_msg.usa19hs.rxFlush = 0;
64060b08185Syz 		kp->kp_ctrl_msg.usa19hs.txFlush = 0;
64160b08185Syz 		kp->kp_ctrl_msg.usa19hs.returnStatus = 0;
64260b08185Syz 		kp->kp_ctrl_msg.usa19hs.setRts = 1;
64360b08185Syz 		kp->kp_ctrl_msg.usa19hs.rts = 0;
64460b08185Syz 		kp->kp_ctrl_msg.usa19hs.setDtr = 1;
64560b08185Syz 		kp->kp_ctrl_msg.usa19hs.dtr = 0;
64660b08185Syz 		kp->kp_ctrl_msg.usa19hs.setTxFlowControl = 1;
64760b08185Syz 		kp->kp_ctrl_msg.usa19hs.txFlowControl = 0;
64860b08185Syz 		kp->kp_ctrl_msg.usa19hs.setRxFlowControl = 1;
64960b08185Syz 		kp->kp_ctrl_msg.usa19hs.rxFlowControl = 0;
65060b08185Syz 		kp->kp_ctrl_msg.usa19hs.rxForwardingTimeout = 0;
65160b08185Syz 		kp->kp_ctrl_msg.usa19hs.rxForwardingLength = 0;
65260b08185Syz 
65360b08185Syz 		break;
65460b08185Syz 
655c138f478Syz 
65660b08185Syz 	case KEYSPAN_USA49WLC_PID:
65702dd2108Slg 	case KEYSPAN_USA49WG_PID:
65860b08185Syz 		keyspan_build_cmd_msg_usa49(kp, NULL);
65960b08185Syz 		kp->kp_ctrl_msg.usa49._txOn = 0;
66060b08185Syz 		kp->kp_ctrl_msg.usa49._txOff = 1;
66160b08185Syz 		kp->kp_ctrl_msg.usa49.txFlush = 0;
66260b08185Syz 		kp->kp_ctrl_msg.usa49.txBreak = 0;
66360b08185Syz 		kp->kp_ctrl_msg.usa49.rxOn = 0;
66460b08185Syz 		kp->kp_ctrl_msg.usa49.rxOff = 1;
66560b08185Syz 		kp->kp_ctrl_msg.usa49.rxFlush = 0;
66660b08185Syz 		kp->kp_ctrl_msg.usa49.rxForward = 0;
66760b08185Syz 		kp->kp_ctrl_msg.usa49.returnStatus = 0;
66860b08185Syz 		kp->kp_ctrl_msg.usa49.resetDataToggle = 0;
66960b08185Syz 		kp->kp_ctrl_msg.usa49.enablePort = 0;
67060b08185Syz 		kp->kp_ctrl_msg.usa49.disablePort = 1;
67160b08185Syz 
67260b08185Syz 		break;
673c138f478Syz 
67460b08185Syz 	default:
67560b08185Syz 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
67660b08185Syz 		    "keyspan_close_hw_port:"
67760b08185Syz 		    "the device's product id can't be recognized");
67860b08185Syz 		mutex_exit(&kp->kp_mutex);
67960b08185Syz 
68060b08185Syz 		return;
68160b08185Syz 	}
68260b08185Syz 
68360b08185Syz 	mutex_exit(&kp->kp_mutex);
68460b08185Syz 	/* send close port cmd to this port */
68560b08185Syz 	if (keyspan_send_cmd(kp) != USB_SUCCESS) {
68660b08185Syz 		USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
6874ee52f77Slg 		    "keyspan_close_hw_port: closing hw port, send cmd FAILED");
68860b08185Syz 	}
68960b08185Syz 
69060b08185Syz 	/* blow away bulkin requests or pipe close will wait until timeout */
69102dd2108Slg 	switch (ksp->ks_dev_spec.id_product) {
69202dd2108Slg 		case KEYSPAN_USA19HS_PID:
69302dd2108Slg 		case KEYSPAN_USA49WLC_PID:
69402dd2108Slg 			usb_pipe_reset(ksp->ks_dip,
6954ee52f77Slg 			    kp->kp_datain_pipe.pipe_handle,
6964ee52f77Slg 			    USB_FLAGS_SLEEP, NULL, NULL);
69702dd2108Slg 
69802dd2108Slg 			break;
69902dd2108Slg 		case KEYSPAN_USA49WG_PID:
70002dd2108Slg 			mutex_enter(&ksp->ks_mutex);
70102dd2108Slg 			/*
70202dd2108Slg 			 * if only this port is opened, shared data in pipe
70302dd2108Slg 			 * can be reset.
70402dd2108Slg 			 */
70502dd2108Slg 			if (ksp->ks_datain_open_cnt == 1) {
70602dd2108Slg 				mutex_exit(&ksp->ks_mutex);
70702dd2108Slg 
70802dd2108Slg 				usb_pipe_reset(ksp->ks_dip,
7094ee52f77Slg 				    kp->kp_datain_pipe.pipe_handle,
7104ee52f77Slg 				    USB_FLAGS_SLEEP, NULL, NULL);
71102dd2108Slg 			} else {
71202dd2108Slg 				mutex_exit(&ksp->ks_mutex);
71302dd2108Slg 			}
71402dd2108Slg 
71502dd2108Slg 			break;
71602dd2108Slg 		default:
71702dd2108Slg 			USB_DPRINTF_L2(DPRINT_CLOSE, kp->kp_lh,
7184ee52f77Slg 			    "keyspan_close_hw_port: the device's"
7194ee52f77Slg 			    " product id can't be recognized");
72002dd2108Slg 	}
72160b08185Syz 
72260b08185Syz 	(void) keyspan_close_port_pipes(kp);
72360b08185Syz }
72460b08185Syz 
72560b08185Syz /*
72660b08185Syz  * ds_close_port
72760b08185Syz  */
72860b08185Syz static int
keyspan_close_port(ds_hdl_t hdl,uint_t port_num)72960b08185Syz keyspan_close_port(ds_hdl_t hdl, uint_t port_num)
73060b08185Syz {
73160b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
73260b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
73360b08185Syz 
73460b08185Syz 	if (port_num >= ksp->ks_dev_spec.port_cnt) {
73560b08185Syz 
73660b08185Syz 		return (USB_FAILURE);
73760b08185Syz 	}
73860b08185Syz 	USB_DPRINTF_L4(DPRINT_CLOSE, kp->kp_lh, "keyspan_close_port");
73960b08185Syz 
74060b08185Syz 	sema_p(&ksp->ks_pipes_sema);
74160b08185Syz 	mutex_enter(&kp->kp_mutex);
74260b08185Syz 	kp->kp_no_more_reads = B_TRUE;
74360b08185Syz 
74460b08185Syz 	/* close hardware serial port */
74560b08185Syz 	mutex_exit(&kp->kp_mutex);
74660b08185Syz 
74760b08185Syz 	keyspan_close_hw_port(kp);
74860b08185Syz 	mutex_enter(&kp->kp_mutex);
74960b08185Syz 
75060b08185Syz 	/*
75160b08185Syz 	 * free resources and finalize state
75260b08185Syz 	 */
75360b08185Syz 	if (kp->kp_rx_mp) {
75460b08185Syz 		freemsg(kp->kp_rx_mp);
75560b08185Syz 		kp->kp_rx_mp = NULL;
75660b08185Syz 	}
75760b08185Syz 	if (kp->kp_tx_mp) {
75860b08185Syz 		freemsg(kp->kp_tx_mp);
75960b08185Syz 		kp->kp_tx_mp = NULL;
76060b08185Syz 	}
76160b08185Syz 
76260b08185Syz 	kp->kp_no_more_reads = B_FALSE;
76360b08185Syz 	kp->kp_state = KEYSPAN_PORT_CLOSED;
76460b08185Syz 	mutex_exit(&kp->kp_mutex);
76560b08185Syz 
76660b08185Syz 	keyspan_pm_set_idle(ksp);
76760b08185Syz 
76860b08185Syz 	sema_v(&ksp->ks_pipes_sema);
76960b08185Syz 
77060b08185Syz 	return (USB_SUCCESS);
77160b08185Syz }
77260b08185Syz 
77360b08185Syz /*
77460b08185Syz  * power management
77560b08185Syz  *
77660b08185Syz  * ds_usb_power
77760b08185Syz  */
77860b08185Syz /*ARGSUSED*/
77960b08185Syz static int
keyspan_usb_power(ds_hdl_t hdl,int comp,int level,int * new_state)78060b08185Syz keyspan_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state)
78160b08185Syz {
78260b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
78360b08185Syz 	keyspan_pm_t	*pm = ksp->ks_pm;
78460b08185Syz 	int		rval;
78560b08185Syz 
78660b08185Syz 	USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_usb_power");
78760b08185Syz 
78860b08185Syz 	mutex_enter(&ksp->ks_mutex);
78960b08185Syz 
79060b08185Syz 	/*
79160b08185Syz 	 * check if we are transitioning to a legal power level
79260b08185Syz 	 */
79360b08185Syz 	if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) {
79460b08185Syz 		USB_DPRINTF_L2(DPRINT_PM, ksp->ks_lh, "keyspan_usb_power:"
79560b08185Syz 		    "illegal power level %d, pwr_states=%x",
79660b08185Syz 		    level, pm->pm_pwr_states);
79760b08185Syz 		mutex_exit(&ksp->ks_mutex);
79860b08185Syz 
79960b08185Syz 		return (USB_FAILURE);
80060b08185Syz 	}
80160b08185Syz 
80260b08185Syz 	/*
80360b08185Syz 	 * if we are about to raise power and asked to lower power, fail
80460b08185Syz 	 */
80560b08185Syz 	if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
80660b08185Syz 		mutex_exit(&ksp->ks_mutex);
80760b08185Syz 
80860b08185Syz 		return (USB_FAILURE);
80960b08185Syz 	}
81060b08185Syz 
81160b08185Syz 	switch (level) {
81260b08185Syz 	case USB_DEV_OS_PWR_OFF:
81360b08185Syz 		rval = keyspan_pwrlvl0(ksp);
81460b08185Syz 
81560b08185Syz 		break;
81660b08185Syz 	case USB_DEV_OS_PWR_1:
81760b08185Syz 		rval = keyspan_pwrlvl1(ksp);
81860b08185Syz 
81960b08185Syz 		break;
82060b08185Syz 	case USB_DEV_OS_PWR_2:
82160b08185Syz 		rval = keyspan_pwrlvl2(ksp);
82260b08185Syz 
82360b08185Syz 		break;
82460b08185Syz 	case USB_DEV_OS_FULL_PWR:
82560b08185Syz 		rval = keyspan_pwrlvl3(ksp);
8264ee52f77Slg 		/*
8274ee52f77Slg 		 * If usbser dev_state is DISCONNECTED or SUSPENDED, it shows
8284ee52f77Slg 		 * that the usb serial device is disconnected/suspended while it
8294ee52f77Slg 		 * is under power down state, now the device is powered up
8304ee52f77Slg 		 * before it is reconnected/resumed. xxx_pwrlvl3() will set dev
8314ee52f77Slg 		 * state to ONLINE, we need to set the dev state back to
8324ee52f77Slg 		 * DISCONNECTED/SUSPENDED.
8334ee52f77Slg 		 */
8344ee52f77Slg 		if ((rval == USB_SUCCESS) &&
8354ee52f77Slg 		    ((*new_state == USB_DEV_DISCONNECTED) ||
8364ee52f77Slg 		    (*new_state == USB_DEV_SUSPENDED))) {
8374ee52f77Slg 			ksp->ks_dev_state = *new_state;
8384ee52f77Slg 		}
83960b08185Syz 
84060b08185Syz 		break;
84160b08185Syz 	default:
84260b08185Syz 		ASSERT(0);	/* cannot happen */
84360b08185Syz 	}
84460b08185Syz 
84560b08185Syz 	*new_state = ksp->ks_dev_state;
84660b08185Syz 	mutex_exit(&ksp->ks_mutex);
84760b08185Syz 
84860b08185Syz 	return (rval);
84960b08185Syz }
85060b08185Syz 
85160b08185Syz 
85260b08185Syz /*
85360b08185Syz  * ds_suspend
85460b08185Syz  */
85560b08185Syz static int
keyspan_suspend(ds_hdl_t hdl)85660b08185Syz keyspan_suspend(ds_hdl_t hdl)
85760b08185Syz {
85860b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
8594ee52f77Slg 	int		state = USB_DEV_SUSPENDED;
86060b08185Syz 
86160b08185Syz 	USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_suspend");
86260b08185Syz 
8634ee52f77Slg 	/*
8644ee52f77Slg 	 * If the device is suspended while it is under PWRED_DOWN state, we
8654ee52f77Slg 	 * need to keep the PWRED_DOWN state so that it could be powered up
8664ee52f77Slg 	 * later. In the mean while, usbser dev state will be changed to
8674ee52f77Slg 	 * SUSPENDED state.
8684ee52f77Slg 	 */
86960b08185Syz 	mutex_enter(&ksp->ks_mutex);
8704ee52f77Slg 	if (ksp->ks_dev_state != USB_DEV_PWRED_DOWN) {
8714ee52f77Slg 		ksp->ks_dev_state = USB_DEV_SUSPENDED;
8724ee52f77Slg 	}
87360b08185Syz 	mutex_exit(&ksp->ks_mutex);
87460b08185Syz 
87560b08185Syz 	keyspan_disconnect_pipes(ksp);
87660b08185Syz 
87760b08185Syz 	return (state);
87860b08185Syz }
87960b08185Syz 
88060b08185Syz 
88160b08185Syz /*
88260b08185Syz  * ds_resume
88360b08185Syz  */
88460b08185Syz static int
keyspan_resume(ds_hdl_t hdl)88560b08185Syz keyspan_resume(ds_hdl_t hdl)
88660b08185Syz {
88760b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
88860b08185Syz 	int		current_state;
88960b08185Syz 	int		rval;
89060b08185Syz 
89160b08185Syz 	USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_resume");
89260b08185Syz 
89360b08185Syz 	mutex_enter(&ksp->ks_mutex);
89460b08185Syz 	current_state = ksp->ks_dev_state;
89560b08185Syz 	mutex_exit(&ksp->ks_mutex);
89660b08185Syz 
89760b08185Syz 	if (current_state != USB_DEV_ONLINE) {
89860b08185Syz 		rval = keyspan_restore_device_state(ksp);
89960b08185Syz 	} else {
90060b08185Syz 		rval = USB_SUCCESS;
90160b08185Syz 	}
90260b08185Syz 
90360b08185Syz 	return (rval);
90460b08185Syz }
90560b08185Syz 
90660b08185Syz 
90760b08185Syz /*
90860b08185Syz  * ds_disconnect
90960b08185Syz  */
91060b08185Syz static int
keyspan_disconnect(ds_hdl_t hdl)91160b08185Syz keyspan_disconnect(ds_hdl_t hdl)
91260b08185Syz {
91360b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
9144ee52f77Slg 	int		state = USB_DEV_DISCONNECTED;
91560b08185Syz 
91660b08185Syz 	USB_DPRINTF_L4(DPRINT_HOTPLUG, ksp->ks_lh, "keyspan_disconnect");
91760b08185Syz 
9184ee52f77Slg 	/*
9194ee52f77Slg 	 * If the device is disconnected while it is under PWRED_DOWN state, we
9204ee52f77Slg 	 * need to keep the PWRED_DOWN state so that it could be powered up
9214ee52f77Slg 	 * later. In the mean while, usbser dev state will be changed to
9224ee52f77Slg 	 * DISCONNECTED state.
9234ee52f77Slg 	 */
92460b08185Syz 	mutex_enter(&ksp->ks_mutex);
9254ee52f77Slg 	if (ksp->ks_dev_state != USB_DEV_PWRED_DOWN) {
9264ee52f77Slg 		ksp->ks_dev_state = USB_DEV_DISCONNECTED;
9274ee52f77Slg 	}
92860b08185Syz 	mutex_exit(&ksp->ks_mutex);
92960b08185Syz 
93060b08185Syz 	keyspan_disconnect_pipes(ksp);
93160b08185Syz 
93260b08185Syz 	return (state);
93360b08185Syz }
93460b08185Syz 
93560b08185Syz 
93660b08185Syz /*
93760b08185Syz  * ds_reconnect
93860b08185Syz  */
93960b08185Syz static int
keyspan_reconnect(ds_hdl_t hdl)94060b08185Syz keyspan_reconnect(ds_hdl_t hdl)
94160b08185Syz {
94260b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
94360b08185Syz 
94460b08185Syz 	USB_DPRINTF_L4(DPRINT_HOTPLUG, ksp->ks_lh, "keyspan_reconnect");
94560b08185Syz 
94660b08185Syz 	return (keyspan_restore_device_state(ksp));
94760b08185Syz }
94860b08185Syz 
94960b08185Syz /*
95060b08185Syz  * ds_set_port_params
95160b08185Syz  */
95260b08185Syz static int
keyspan_set_port_params(ds_hdl_t hdl,uint_t port_num,ds_port_params_t * tp)95360b08185Syz keyspan_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp)
95460b08185Syz {
95560b08185Syz 	int		cnt = tp->tp_cnt;
95660b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
95760b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
95860b08185Syz 
95960b08185Syz 	ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
96060b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
96160b08185Syz 	    "keyspan_set_port_params: port: %d params", cnt);
96260b08185Syz 
96360b08185Syz 	if (cnt <= 0) {
96460b08185Syz 
96560b08185Syz 		return (USB_SUCCESS);
96660b08185Syz 	}
96760b08185Syz 
96860b08185Syz 	mutex_enter(&kp->kp_mutex);
96960b08185Syz 	ASSERT((kp->kp_state == KEYSPAN_PORT_OPENING) ||
97060b08185Syz 	    (kp->kp_state == KEYSPAN_PORT_OPEN));
97160b08185Syz 	keyspan_build_cmd_msg(kp, tp);
97260b08185Syz 	mutex_exit(&kp->kp_mutex);
97360b08185Syz 
97460b08185Syz 	if (keyspan_send_cmd(kp) != USB_SUCCESS) {
97502dd2108Slg 			USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
97602dd2108Slg 			    "keyspan_send_cmd() FAILED");
97760b08185Syz 
97802dd2108Slg 			return (USB_FAILURE);
97960b08185Syz 	}
98060b08185Syz 
98160b08185Syz 	return (USB_SUCCESS);
98260b08185Syz }
98360b08185Syz 
98460b08185Syz 
98560b08185Syz /*
98660b08185Syz  * ds_set_modem_ctl
98760b08185Syz  */
98860b08185Syz static int
keyspan_set_modem_ctl(ds_hdl_t hdl,uint_t port_num,int mask,int val)98960b08185Syz keyspan_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val)
99060b08185Syz {
99160b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
99260b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
99360b08185Syz 
99460b08185Syz 	ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
99560b08185Syz 
99660b08185Syz 	mutex_enter(&kp->kp_mutex);
99760b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_set_modem_ctl: "
99860b08185Syz 	    "mask=%x, val=%x", mask, val);
99960b08185Syz 
100060b08185Syz 	keyspan_build_cmd_msg(kp, NULL);
100160b08185Syz 
100260b08185Syz 	switch (ksp->ks_dev_spec.id_product) {
100360b08185Syz 	case KEYSPAN_USA19HS_PID:
100460b08185Syz 		if (mask & TIOCM_RTS) {
100560b08185Syz 
100660b08185Syz 			kp->kp_ctrl_msg.usa19hs.setRts = 0x01;
100760b08185Syz 
100860b08185Syz 			if (val & TIOCM_RTS) {
100960b08185Syz 				kp->kp_ctrl_msg.usa19hs.rts = 0x1;
101060b08185Syz 			} else {
101160b08185Syz 				kp->kp_ctrl_msg.usa19hs.rts = 0x0;
101260b08185Syz 			}
101360b08185Syz 
101460b08185Syz 		} else {
101560b08185Syz 			kp->kp_ctrl_msg.usa19hs.setRts = 0x0;
101660b08185Syz 		}
101760b08185Syz 
101860b08185Syz 		if (mask & TIOCM_DTR) {
101960b08185Syz 			kp->kp_ctrl_msg.usa19hs.setDtr = 0x01;
102060b08185Syz 
102160b08185Syz 			if (val & TIOCM_DTR) {
102260b08185Syz 				kp->kp_ctrl_msg.usa19hs.dtr = 0x1;
102360b08185Syz 			} else {
102460b08185Syz 				kp->kp_ctrl_msg.usa19hs.dtr = 0x0;
102560b08185Syz 			}
102660b08185Syz 
102760b08185Syz 		} else {
102860b08185Syz 			kp->kp_ctrl_msg.usa19hs.setDtr = 0x0;
102960b08185Syz 		}
103060b08185Syz 
103160b08185Syz 		break;
103260b08185Syz 
1033c138f478Syz 
103460b08185Syz 	case KEYSPAN_USA49WLC_PID:
103502dd2108Slg 	case KEYSPAN_USA49WG_PID:
103660b08185Syz 		if (mask & TIOCM_RTS) {
103760b08185Syz 
103860b08185Syz 			kp->kp_ctrl_msg.usa49.setRts = 0x1;
103960b08185Syz 
104060b08185Syz 			if (val & TIOCM_RTS) {
104160b08185Syz 				kp->kp_ctrl_msg.usa49.rts = 0x1;
104260b08185Syz 			} else {
104360b08185Syz 				kp->kp_ctrl_msg.usa49.rts = 0x0;
104460b08185Syz 			}
104560b08185Syz 
104660b08185Syz 		} else {
104760b08185Syz 			kp->kp_ctrl_msg.usa49.setRts = 0x0;
104860b08185Syz 		}
104960b08185Syz 
105060b08185Syz 		if (mask & TIOCM_DTR) {
105160b08185Syz 			kp->kp_ctrl_msg.usa49.setDtr = 0x1;
105260b08185Syz 
105360b08185Syz 			if (val & TIOCM_DTR) {
105460b08185Syz 				kp->kp_ctrl_msg.usa49.dtr = 0x1;
105560b08185Syz 			} else {
105660b08185Syz 				kp->kp_ctrl_msg.usa49.dtr = 0x0;
105760b08185Syz 			}
105860b08185Syz 
105960b08185Syz 		} else {
106060b08185Syz 			kp->kp_ctrl_msg.usa49.setDtr = 0x0;
106160b08185Syz 		}
106260b08185Syz 
106360b08185Syz 		break;
1064c138f478Syz 
106560b08185Syz 	default:
106660b08185Syz 		USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
106760b08185Syz 		    "keyspan_get_modem_ctl:"
106860b08185Syz 		    "the device's product id can't be recognized");
106960b08185Syz 		mutex_exit(&kp->kp_mutex);
107060b08185Syz 
107160b08185Syz 		return (USB_FAILURE);
107260b08185Syz 	}
107360b08185Syz 
107460b08185Syz 	mutex_exit(&kp->kp_mutex);
107560b08185Syz 
107660b08185Syz 	if (keyspan_send_cmd(kp) != USB_SUCCESS) {
107702dd2108Slg 			USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
107802dd2108Slg 			    "keyspan_send_cmd() FAILED");
107960b08185Syz 
108002dd2108Slg 			return (USB_FAILURE);
108160b08185Syz 	}
108260b08185Syz 
108360b08185Syz 	return (USB_SUCCESS);
108460b08185Syz }
108560b08185Syz 
108660b08185Syz /*
108760b08185Syz  * ds_get_modem_ctl
108860b08185Syz  */
108960b08185Syz static int
keyspan_get_modem_ctl(ds_hdl_t hdl,uint_t port_num,int mask,int * valp)109060b08185Syz keyspan_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp)
109160b08185Syz {
109260b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
109360b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
109460b08185Syz 	int	val = 0;
109560b08185Syz 
109660b08185Syz 	ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
109760b08185Syz 
109860b08185Syz 	mutex_enter(&kp->kp_mutex);
109960b08185Syz 
110060b08185Syz 	/*
110160b08185Syz 	 * rts and dtr are not in status_msg, but we can get it from
110260b08185Syz 	 * status_flag since it represents what we set the device last time.
110360b08185Syz 	 */
110460b08185Syz 	if (kp->kp_status_flag & KEYSPAN_PORT_RTS) {
110560b08185Syz 		val |= TIOCM_RTS;
110660b08185Syz 	}
110760b08185Syz 	if (kp->kp_status_flag & KEYSPAN_PORT_DTR) {
110860b08185Syz 		val |= TIOCM_DTR;
110960b08185Syz 	}
111060b08185Syz 
111160b08185Syz 	/* usbser don't deal with TIOCM_RI status */
111260b08185Syz 	switch (ksp->ks_dev_spec.id_product) {
111360b08185Syz 	case KEYSPAN_USA19HS_PID:
111460b08185Syz 		if (kp->kp_status_msg.usa19hs.dcd) {
111560b08185Syz 			val |= TIOCM_CD;
111660b08185Syz 		}
111760b08185Syz 		if (kp->kp_status_msg.usa19hs.cts) {
111860b08185Syz 			val |= TIOCM_CTS;
111960b08185Syz 		}
112060b08185Syz 		if (kp->kp_status_msg.usa19hs.dsr) {
112160b08185Syz 			val |= TIOCM_DSR;
112260b08185Syz 		}
112360b08185Syz 		break;
112460b08185Syz 
1125c138f478Syz 
112660b08185Syz 	case KEYSPAN_USA49WLC_PID:
112702dd2108Slg 	case KEYSPAN_USA49WG_PID:
112860b08185Syz 		if (kp->kp_status_msg.usa49.dcd) {
112960b08185Syz 			val |= TIOCM_CD;
113060b08185Syz 		}
113160b08185Syz 		if (kp->kp_status_msg.usa49.cts) {
113260b08185Syz 			val |= TIOCM_CTS;
113360b08185Syz 		}
113460b08185Syz 		if (kp->kp_status_msg.usa49.dsr) {
113560b08185Syz 			val |= TIOCM_DSR;
113660b08185Syz 		}
113760b08185Syz 		break;
1138c138f478Syz 
113960b08185Syz 	default:
114060b08185Syz 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
114160b08185Syz 		    "keyspan_get_modem_ctl:"
114260b08185Syz 		    "the device's product id can't be recognized");
114360b08185Syz 		mutex_exit(&kp->kp_mutex);
114460b08185Syz 
114560b08185Syz 		return (USB_FAILURE);
114660b08185Syz 	}
114760b08185Syz 
114860b08185Syz 	*valp = val & mask;
114960b08185Syz 
115060b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_get_modem_ctl:"
115160b08185Syz 	    "success. status_flag = %x, val=0%o",
115260b08185Syz 	    kp->kp_status_flag, *valp);
115360b08185Syz 
115460b08185Syz 	mutex_exit(&kp->kp_mutex);
115560b08185Syz 
115660b08185Syz 	return (USB_SUCCESS);
115760b08185Syz }
115860b08185Syz 
115960b08185Syz 
116060b08185Syz /*
116160b08185Syz  * ds_break_ctl
116260b08185Syz  */
116360b08185Syz static int
keyspan_break_ctl(ds_hdl_t hdl,uint_t port_num,int ctl)116460b08185Syz keyspan_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl)
116560b08185Syz {
116660b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
116760b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
116860b08185Syz 	int		is_break;
116960b08185Syz 	int		rval = USB_SUCCESS;
117060b08185Syz 
117160b08185Syz 	ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
117260b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
117360b08185Syz 	    "keyspan_break_ctl: ctl = %s", (ctl == DS_ON) ? "on" : "off");
117460b08185Syz 
117560b08185Syz 	mutex_enter(&kp->kp_mutex);
117660b08185Syz 	ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN);
117760b08185Syz 	ASSERT(ctl == DS_ON || ctl == DS_OFF);
117860b08185Syz 
117960b08185Syz 	is_break = kp->kp_status_flag & KEYSPAN_PORT_TXBREAK;
118060b08185Syz 
118160b08185Syz 	if ((ctl == DS_ON) && !is_break) {
118260b08185Syz 
118360b08185Syz 		keyspan_build_cmd_msg(kp, NULL);
118460b08185Syz 
118560b08185Syz 		switch (ksp->ks_dev_spec.id_product) {
118660b08185Syz 		case KEYSPAN_USA19HS_PID:
118760b08185Syz 			kp->kp_ctrl_msg.usa19hs.txBreak = 1;
118860b08185Syz 
118960b08185Syz 			break;
119060b08185Syz 
119160b08185Syz 		case KEYSPAN_USA49WLC_PID:
119202dd2108Slg 		case KEYSPAN_USA49WG_PID:
119360b08185Syz 			kp->kp_ctrl_msg.usa49.txBreak = 1;
119460b08185Syz 
119560b08185Syz 			break;
1196c138f478Syz 
119760b08185Syz 		default:
119860b08185Syz 			mutex_exit(&kp->kp_mutex);
119960b08185Syz 			USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
120060b08185Syz 			    "keyspan_break_ctl:"
120160b08185Syz 			    "the device's product id can't be recognized");
120260b08185Syz 
120360b08185Syz 			return (USB_FAILURE);
120460b08185Syz 		}
120560b08185Syz 
120660b08185Syz 		mutex_exit(&kp->kp_mutex);
120760b08185Syz 		rval = keyspan_send_cmd(kp);
120860b08185Syz 		return (rval);
120960b08185Syz 	}
121060b08185Syz 
121160b08185Syz 	if ((ctl == DS_OFF) && is_break) {
121260b08185Syz 		keyspan_build_cmd_msg(kp, NULL);
121360b08185Syz 
121460b08185Syz 		switch (ksp->ks_dev_spec.id_product) {
121560b08185Syz 		case KEYSPAN_USA19HS_PID:
121660b08185Syz 			kp->kp_ctrl_msg.usa19hs.txBreak = 0;
121760b08185Syz 
121860b08185Syz 			break;
1219c138f478Syz 
122060b08185Syz 		case KEYSPAN_USA49WLC_PID:
122102dd2108Slg 		case KEYSPAN_USA49WG_PID:
122260b08185Syz 			kp->kp_ctrl_msg.usa49._txOn = 1;
122360b08185Syz 			kp->kp_ctrl_msg.usa49.txBreak = 0;
122460b08185Syz 
122560b08185Syz 			break;
1226c138f478Syz 
122760b08185Syz 		default:
122860b08185Syz 			mutex_exit(&kp->kp_mutex);
122960b08185Syz 			USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
123060b08185Syz 			    "keyspan_break_ctl:"
123160b08185Syz 			    "the device's product id can't be recognized");
123260b08185Syz 
123360b08185Syz 			return (USB_FAILURE);
123460b08185Syz 		}
123560b08185Syz 
123660b08185Syz 		mutex_exit(&kp->kp_mutex);
123760b08185Syz 		rval = keyspan_send_cmd(kp);
123860b08185Syz 		if (rval == USB_SUCCESS) {
123960b08185Syz 			mutex_enter(&kp->kp_mutex);
124060b08185Syz 
124160b08185Syz 			/* resume transmit */
124260b08185Syz 			keyspan_tx_start(kp, NULL);
124360b08185Syz 			mutex_exit(&kp->kp_mutex);
124460b08185Syz 		}
124560b08185Syz 
124660b08185Syz 		return (rval);
124760b08185Syz 	}
124860b08185Syz 
124960b08185Syz 	mutex_exit(&kp->kp_mutex);
125060b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
125160b08185Syz 	    "keyspan_break_ctl: not necessary to set break, is_break = %d",
125260b08185Syz 	    is_break);
125360b08185Syz 
125460b08185Syz 	return (rval);
125560b08185Syz }
125660b08185Syz 
125760b08185Syz 
125860b08185Syz /*
125960b08185Syz  * ds_loopback
126060b08185Syz  */
126160b08185Syz static int
keyspan_loopback(ds_hdl_t hdl,uint_t port_num,int ctl)126260b08185Syz keyspan_loopback(ds_hdl_t hdl, uint_t port_num, int ctl)
126360b08185Syz {
126460b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
126560b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
126660b08185Syz 	int		is_loop;
126760b08185Syz 	int		rval = USB_SUCCESS;
126860b08185Syz 
126960b08185Syz 	ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
127060b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
127160b08185Syz 	    "keyspan_loopback: %s", (ctl == DS_ON) ? "on" : "off");
127260b08185Syz 
127360b08185Syz 	mutex_enter(&kp->kp_mutex);
127460b08185Syz 	ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN);
127560b08185Syz 	ASSERT(ctl == DS_ON || ctl == DS_OFF);
127660b08185Syz 
127760b08185Syz 	/* check bit indicating internal loopback state */
127860b08185Syz 	is_loop = kp->kp_status_flag & KEYSPAN_PORT_LOOPBACK;
127960b08185Syz 
128060b08185Syz 	if ((ctl == DS_ON) && !is_loop) {
128160b08185Syz 
128260b08185Syz 		keyspan_build_cmd_msg(kp, NULL);
128360b08185Syz 		switch (ksp->ks_dev_spec.id_product) {
128460b08185Syz 		case KEYSPAN_USA19HS_PID:
128560b08185Syz 			kp->kp_ctrl_msg.usa19hs.loopbackMode = 0;
128660b08185Syz 
128760b08185Syz 			break;
128860b08185Syz 
128960b08185Syz 		case KEYSPAN_USA49WLC_PID:
129002dd2108Slg 		case KEYSPAN_USA49WG_PID:
129160b08185Syz 			kp->kp_ctrl_msg.usa49.loopbackMode = 0;
129260b08185Syz 
129360b08185Syz 			break;
1294c138f478Syz 
129560b08185Syz 		default:
129660b08185Syz 			mutex_exit(&kp->kp_mutex);
129760b08185Syz 			USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
129860b08185Syz 			    "keyspan_loopback:"
129960b08185Syz 			    "the device's product id can't be recognized");
130060b08185Syz 
130160b08185Syz 			return (USB_FAILURE);
130260b08185Syz 		}
130360b08185Syz 		mutex_exit(&kp->kp_mutex);
130460b08185Syz 		rval = keyspan_send_cmd(kp);
130560b08185Syz 	} else if ((ctl == DS_OFF) && is_loop) {
130660b08185Syz 
130760b08185Syz 		keyspan_build_cmd_msg(kp, NULL);
130860b08185Syz 		switch (ksp->ks_dev_spec.id_product) {
130960b08185Syz 		case KEYSPAN_USA19HS_PID:
131060b08185Syz 			kp->kp_ctrl_msg.usa19hs.loopbackMode = 1;
131160b08185Syz 
131260b08185Syz 			break;
131360b08185Syz 
131460b08185Syz 		case KEYSPAN_USA49WLC_PID:
131502dd2108Slg 		case KEYSPAN_USA49WG_PID:
131660b08185Syz 			kp->kp_ctrl_msg.usa49.loopbackMode = 1;
131760b08185Syz 
131860b08185Syz 			break;
1319c138f478Syz 
132060b08185Syz 		default:
132160b08185Syz 			mutex_exit(&kp->kp_mutex);
132260b08185Syz 			USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
132360b08185Syz 			    "keyspan_loopback:"
132460b08185Syz 			    "the device's product id can't be recognized");
132560b08185Syz 
132660b08185Syz 			return (USB_FAILURE);
132760b08185Syz 		}
132860b08185Syz 		mutex_exit(&kp->kp_mutex);
132960b08185Syz 		rval = keyspan_send_cmd(kp);
133060b08185Syz 	} else {
133160b08185Syz 		mutex_exit(&kp->kp_mutex);
133260b08185Syz 		USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
133360b08185Syz 		    "keyspan_loopback: not necessary to set loopback,"
133460b08185Syz 		    "is_loop = %d", is_loop);
133560b08185Syz 	}
133660b08185Syz 
133760b08185Syz 	return (rval);
133860b08185Syz }
133960b08185Syz 
134060b08185Syz 
134160b08185Syz /*
134260b08185Syz  * ds_tx
134360b08185Syz  */
134460b08185Syz static int
keyspan_tx(ds_hdl_t hdl,uint_t port_num,mblk_t * mp)134560b08185Syz keyspan_tx(ds_hdl_t hdl, uint_t port_num, mblk_t *mp)
134660b08185Syz {
134760b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
134860b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
134960b08185Syz 	int		xferd;
135060b08185Syz 
135160b08185Syz 	ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
135260b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_tx");
135360b08185Syz 
135460b08185Syz 	/*
135560b08185Syz 	 * sanity checks
135660b08185Syz 	 */
135760b08185Syz 	if (mp == NULL) {
135860b08185Syz 		USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh, "keyspan_tx: mp=NULL");
135960b08185Syz 
136060b08185Syz 		return (USB_SUCCESS);
136160b08185Syz 	}
136260b08185Syz 
136360b08185Syz 	kp = &ksp->ks_ports[port_num];
136460b08185Syz 
136560b08185Syz 	mutex_enter(&kp->kp_mutex);
136660b08185Syz 
136760b08185Syz 	keyspan_put_tail(&kp->kp_tx_mp, mp);	/* add to the chain */
136860b08185Syz 
136960b08185Syz 	keyspan_tx_start(kp, &xferd);		/* go! */
137060b08185Syz 
137160b08185Syz 	mutex_exit(&kp->kp_mutex);
137260b08185Syz 
137360b08185Syz 	return (USB_SUCCESS);
137460b08185Syz }
137560b08185Syz 
137660b08185Syz 
137760b08185Syz /*
137860b08185Syz  * ds_rx. the real data receiving is in keyspan_open_hw_port
137960b08185Syz  */
138060b08185Syz static mblk_t *
keyspan_rx(ds_hdl_t hdl,uint_t port_num)138160b08185Syz keyspan_rx(ds_hdl_t hdl, uint_t port_num)
138260b08185Syz {
138360b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
138460b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
138560b08185Syz 	mblk_t		*mp;
138660b08185Syz 
138760b08185Syz 	ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
138860b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_rx");
138960b08185Syz 
139060b08185Syz 	mutex_enter(&kp->kp_mutex);
139160b08185Syz 	mp = kp->kp_rx_mp;
139260b08185Syz 	kp->kp_rx_mp = NULL;
139360b08185Syz 	mutex_exit(&kp->kp_mutex);
139460b08185Syz 
139560b08185Syz 	return (mp);
139660b08185Syz }
139760b08185Syz 
139860b08185Syz 
139960b08185Syz /*
140060b08185Syz  * ds_stop
140160b08185Syz  */
140260b08185Syz static void
keyspan_stop(ds_hdl_t hdl,uint_t port_num,int dir)140360b08185Syz keyspan_stop(ds_hdl_t hdl, uint_t port_num, int dir)
140460b08185Syz {
140560b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
140660b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
140760b08185Syz 
140860b08185Syz 	ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
140960b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_stop");
141060b08185Syz 
141160b08185Syz 	if (dir & DS_TX) {
141260b08185Syz 		mutex_enter(&kp->kp_mutex);
141360b08185Syz 		kp->kp_flags |= KEYSPAN_PORT_TX_STOPPED;
141460b08185Syz 		mutex_exit(&kp->kp_mutex);
141560b08185Syz 	}
141660b08185Syz }
141760b08185Syz 
141860b08185Syz 
141960b08185Syz /*
142060b08185Syz  * ds_start
142160b08185Syz  */
142260b08185Syz static void
keyspan_start(ds_hdl_t hdl,uint_t port_num,int dir)142360b08185Syz keyspan_start(ds_hdl_t hdl, uint_t port_num, int dir)
142460b08185Syz {
142560b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
142660b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
142760b08185Syz 
142860b08185Syz 	ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
142960b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_start");
143060b08185Syz 
143160b08185Syz 	if (dir & DS_TX) {
143260b08185Syz 		mutex_enter(&kp->kp_mutex);
143360b08185Syz 		if (kp->kp_flags & KEYSPAN_PORT_TX_STOPPED) {
143460b08185Syz 			kp->kp_flags &= ~KEYSPAN_PORT_TX_STOPPED;
143560b08185Syz 			keyspan_tx_start(kp, NULL);
143660b08185Syz 		}
143760b08185Syz 		mutex_exit(&kp->kp_mutex);
143860b08185Syz 	}
143960b08185Syz }
144060b08185Syz 
144160b08185Syz 
144260b08185Syz /*
144360b08185Syz  * ds_fifo_flush
144460b08185Syz  * send flush cmd and wait for completion, then turn off the flush.
144560b08185Syz  */
144660b08185Syz static int
keyspan_fifo_flush(ds_hdl_t hdl,uint_t port_num,int dir)144760b08185Syz keyspan_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir)
144860b08185Syz {
144960b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
145060b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
145160b08185Syz 
145260b08185Syz 	ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
145360b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
145460b08185Syz 	    "keyspan_fifo_flush: dir=%x", dir);
145560b08185Syz 
145660b08185Syz 	mutex_enter(&kp->kp_mutex);
145760b08185Syz 	ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN);
145860b08185Syz 
145960b08185Syz 	/* discard the data in DSD buffers */
146060b08185Syz 	if ((dir & DS_TX) && kp->kp_tx_mp) {
146160b08185Syz 		freemsg(kp->kp_tx_mp);
146260b08185Syz 		kp->kp_tx_mp = NULL;
146360b08185Syz 	}
146460b08185Syz 	if ((dir & DS_RX) && kp->kp_rx_mp) {
146560b08185Syz 		freemsg(kp->kp_rx_mp);
146660b08185Syz 		kp->kp_rx_mp = NULL;
146760b08185Syz 	}
146860b08185Syz 
146960b08185Syz 	mutex_exit(&kp->kp_mutex);
147060b08185Syz 
147160b08185Syz 	return (USB_SUCCESS);
147260b08185Syz }
147360b08185Syz 
147460b08185Syz /*
147560b08185Syz  * ds_fifo_drain
147660b08185Syz  *
147760b08185Syz  * it is the caller's responsibility to cease submitting new tx data
147860b08185Syz  * while this function executes
147960b08185Syz  */
148060b08185Syz static int
keyspan_fifo_drain(ds_hdl_t hdl,uint_t port_num,int timeout)148160b08185Syz keyspan_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout)
148260b08185Syz {
148360b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)hdl;
148460b08185Syz 	keyspan_port_t	*kp = &ksp->ks_ports[port_num];
148560b08185Syz 	int		rval = USB_SUCCESS;
148660b08185Syz 
148760b08185Syz 	ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
148860b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
148960b08185Syz 	    "keyspan_fifo_drain, timeout = %d", timeout);
149060b08185Syz 
149160b08185Syz 	mutex_enter(&kp->kp_mutex);
149260b08185Syz 	ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN);
149360b08185Syz 
149460b08185Syz 	/* wait until local data drains */
149560b08185Syz 	if (keyspan_wait_tx_drain(kp, 0) != USB_SUCCESS) {
149660b08185Syz 		mutex_exit(&kp->kp_mutex);
149760b08185Syz 
149860b08185Syz 		return (USB_FAILURE);
149960b08185Syz 	}
150060b08185Syz 	mutex_exit(&kp->kp_mutex);
150160b08185Syz 
150260b08185Syz 	/* wait until hw fifo drains */
150360b08185Syz 	delay(drv_usectohz(500*1000));
150460b08185Syz 
150560b08185Syz 	return (rval);
150660b08185Syz }
150760b08185Syz 
150860b08185Syz 
150960b08185Syz /*
151060b08185Syz  * configuration routines
151160b08185Syz  * ----------------------
151260b08185Syz  *
151360b08185Syz  */
151460b08185Syz 
151560b08185Syz /*
151660b08185Syz  * free state structure
151760b08185Syz  */
151860b08185Syz static void
keyspan_free_soft_state(keyspan_state_t * ksp)151960b08185Syz keyspan_free_soft_state(keyspan_state_t *ksp)
152060b08185Syz {
152160b08185Syz 	kmem_free(ksp, sizeof (keyspan_state_t));
152260b08185Syz }
152360b08185Syz 
152460b08185Syz 
152560b08185Syz /*
152660b08185Syz  * register/unregister USBA client
152760b08185Syz  */
152860b08185Syz static int
keyspan_usb_register(keyspan_state_t * ksp)152960b08185Syz keyspan_usb_register(keyspan_state_t *ksp)
153060b08185Syz {
153160b08185Syz 	int	rval;
153260b08185Syz 
153360b08185Syz 	rval = usb_client_attach(ksp->ks_dip, USBDRV_VERSION, 0);
153460b08185Syz 	if (rval == USB_SUCCESS) {
153560b08185Syz 		rval = usb_get_dev_data(ksp->ks_dip, &ksp->ks_dev_data,
153660b08185Syz 		    USB_PARSE_LVL_IF, 0);
153760b08185Syz 		if (rval == USB_SUCCESS) {
153860b08185Syz 			ksp->ks_lh =
153960b08185Syz 			    usb_alloc_log_hdl(ksp->ks_dip, "keyspan[*].",
154060b08185Syz 			    &keyspan_errlevel, &keyspan_errmask,
154160b08185Syz 			    &keyspan_instance_debug, 0);
154260b08185Syz 
154360b08185Syz 			ksp->ks_def_pipe.pipe_handle =
154460b08185Syz 			    ksp->ks_dev_data->dev_default_ph;
154560b08185Syz 			ksp->ks_def_pipe.pipe_ksp = ksp;
154660b08185Syz 			ksp->ks_def_pipe.pipe_lh = ksp->ks_lh;
154760b08185Syz 		}
154860b08185Syz 	}
154960b08185Syz 
155060b08185Syz 	return (rval);
155160b08185Syz }
155260b08185Syz 
155360b08185Syz 
155460b08185Syz static void
keyspan_usb_unregister(keyspan_state_t * ksp)155560b08185Syz keyspan_usb_unregister(keyspan_state_t *ksp)
155660b08185Syz {
155760b08185Syz 	usb_free_log_hdl(ksp->ks_lh);
155860b08185Syz 	ksp->ks_lh = NULL;
155960b08185Syz 	usb_client_detach(ksp->ks_dip, ksp->ks_dev_data);
156060b08185Syz 	ksp->ks_def_pipe.pipe_handle = NULL;
156160b08185Syz 	ksp->ks_dev_data = NULL;
156260b08185Syz }
156360b08185Syz 
156460b08185Syz 
156560b08185Syz /*
156660b08185Syz  * init/fini soft state during attach
156760b08185Syz  */
156860b08185Syz static void
keyspan_init_sync_objs(keyspan_state_t * ksp)156960b08185Syz keyspan_init_sync_objs(keyspan_state_t *ksp)
157060b08185Syz {
157160b08185Syz 	mutex_init(&ksp->ks_mutex, NULL, MUTEX_DRIVER,
15724ee52f77Slg 	    ksp->ks_dev_data->dev_iblock_cookie);
157360b08185Syz 	sema_init(&ksp->ks_pipes_sema, 1, NULL, SEMA_DRIVER, NULL);
157460b08185Syz }
157560b08185Syz 
157660b08185Syz 
157760b08185Syz static void
keyspan_fini_sync_objs(keyspan_state_t * ksp)157860b08185Syz keyspan_fini_sync_objs(keyspan_state_t *ksp)
157960b08185Syz {
158060b08185Syz 	mutex_destroy(&ksp->ks_mutex);
158160b08185Syz 	sema_destroy(&ksp->ks_pipes_sema);
158260b08185Syz }
158360b08185Syz 
158460b08185Syz 
158560b08185Syz /*
158660b08185Syz  * device specific attributes
158760b08185Syz  */
158860b08185Syz static int
keyspan_attach_dev(keyspan_state_t * ksp)158960b08185Syz keyspan_attach_dev(keyspan_state_t *ksp)
159060b08185Syz {
159160b08185Syz 
159260b08185Syz 	mutex_enter(&ksp->ks_mutex);
159360b08185Syz 	switch (ksp->ks_dev_data->dev_descr->idProduct) {
159460b08185Syz 	case KEYSPAN_USA19HS_PID:
159560b08185Syz 		ksp->ks_dev_spec.id_product = KEYSPAN_USA19HS_PID;
159660b08185Syz 		ksp->ks_dev_spec.port_cnt = 1;
159760b08185Syz 		ksp->ks_dev_spec.ctrl_ep_addr = 0x02;
159860b08185Syz 		ksp->ks_dev_spec.stat_ep_addr = 0x82;
159960b08185Syz 		ksp->ks_dev_spec.dataout_ep_addr[0] = 0x01;
160060b08185Syz 		ksp->ks_dev_spec.datain_ep_addr[0] = 0x81;
160160b08185Syz 
160260b08185Syz 		break;
160360b08185Syz 
160460b08185Syz 	case KEYSPAN_USA49WLC_PID:
160560b08185Syz 		ksp->ks_dev_spec.id_product = KEYSPAN_USA49WLC_PID;
160660b08185Syz 		ksp->ks_dev_spec.port_cnt = 4;
160760b08185Syz 		ksp->ks_dev_spec.ctrl_ep_addr = 0x07;
160860b08185Syz 		ksp->ks_dev_spec.stat_ep_addr = 0x87;
160960b08185Syz 		ksp->ks_dev_spec.dataout_ep_addr[0] = 0x01;
161060b08185Syz 		ksp->ks_dev_spec.dataout_ep_addr[1] = 0x02;
161160b08185Syz 		ksp->ks_dev_spec.dataout_ep_addr[2] = 0x03;
161260b08185Syz 		ksp->ks_dev_spec.dataout_ep_addr[3] = 0x04;
161360b08185Syz 		ksp->ks_dev_spec.datain_ep_addr[0] = 0x81;
161460b08185Syz 		ksp->ks_dev_spec.datain_ep_addr[1] = 0x82;
161560b08185Syz 		ksp->ks_dev_spec.datain_ep_addr[2] = 0x83;
161660b08185Syz 		ksp->ks_dev_spec.datain_ep_addr[3] = 0x84;
161760b08185Syz 
161860b08185Syz 		break;
1619c138f478Syz 
162002dd2108Slg 	case KEYSPAN_USA49WG_PID:
162102dd2108Slg 		ksp->ks_dev_spec.id_product = KEYSPAN_USA49WG_PID;
162202dd2108Slg 		ksp->ks_dev_spec.port_cnt = 4;
162302dd2108Slg 		ksp->ks_dev_spec.stat_ep_addr = 0x81;
162402dd2108Slg 		ksp->ks_dev_spec.dataout_ep_addr[0] = 0x01;
162502dd2108Slg 		ksp->ks_dev_spec.dataout_ep_addr[1] = 0x02;
162602dd2108Slg 		ksp->ks_dev_spec.dataout_ep_addr[2] = 0x04;
162702dd2108Slg 		ksp->ks_dev_spec.dataout_ep_addr[3] = 0x06;
162802dd2108Slg 		ksp->ks_dev_spec.datain_ep_addr[0] = 0x88;
162902dd2108Slg 		ksp->ks_dev_spec.datain_ep_addr[1] = 0x88;
163002dd2108Slg 		ksp->ks_dev_spec.datain_ep_addr[2] = 0x88;
163102dd2108Slg 		ksp->ks_dev_spec.datain_ep_addr[3] = 0x88;
163202dd2108Slg 
163302dd2108Slg 		break;
163402dd2108Slg 
163560b08185Syz 	default:
163660b08185Syz 		mutex_exit(&ksp->ks_mutex);
1637d291d9f2Sfrits 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
163860b08185Syz 		    "keyspan_attach_dev:"
163960b08185Syz 		    "the device's product id can't be recognized");
164060b08185Syz 
164160b08185Syz 		return (USB_FAILURE);
164260b08185Syz 	}
164360b08185Syz 
164460b08185Syz 	mutex_exit(&ksp->ks_mutex);
164560b08185Syz 
164660b08185Syz 	return (USB_SUCCESS);
164760b08185Syz }
164860b08185Syz 
164960b08185Syz /*
165060b08185Syz  * allocate and initialize per port resources.
165160b08185Syz  */
165260b08185Syz static void
keyspan_attach_ports(keyspan_state_t * ksp)165360b08185Syz keyspan_attach_ports(keyspan_state_t *ksp)
165460b08185Syz {
165560b08185Syz 	int		i;
165660b08185Syz 	keyspan_port_t	*kp;
165760b08185Syz 
165860b08185Syz 	ksp->ks_ports = kmem_zalloc(ksp->ks_dev_spec.port_cnt *
16594ee52f77Slg 	    sizeof (keyspan_port_t), KM_SLEEP);
166060b08185Syz 
166160b08185Syz 	for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
166260b08185Syz 		kp = &ksp->ks_ports[i];
166360b08185Syz 		kp->kp_port_num = i;
166460b08185Syz 		kp->kp_ksp = ksp;
166560b08185Syz 
166660b08185Syz 		(void) sprintf(kp->kp_lh_name, "keyspan[%d].", i);
166760b08185Syz 		kp->kp_lh = usb_alloc_log_hdl(ksp->ks_dip, kp->kp_lh_name,
16684ee52f77Slg 		    &keyspan_errlevel, &keyspan_errmask,
16694ee52f77Slg 		    &keyspan_instance_debug, 0);
167060b08185Syz 
167160b08185Syz 		kp->kp_state = KEYSPAN_PORT_CLOSED;
167260b08185Syz 		mutex_init(&kp->kp_mutex, NULL, MUTEX_DRIVER,
16734ee52f77Slg 		    ksp->ks_dev_data->dev_iblock_cookie);
167460b08185Syz 		cv_init(&kp->kp_tx_cv, NULL, CV_DRIVER, NULL);
167560b08185Syz 	}
167660b08185Syz }
167760b08185Syz 
167860b08185Syz 
167960b08185Syz /*
168060b08185Syz  * free per port resources
168160b08185Syz  */
168260b08185Syz static void
keyspan_detach_ports(keyspan_state_t * ksp)168360b08185Syz keyspan_detach_ports(keyspan_state_t *ksp)
168460b08185Syz {
168560b08185Syz 	int		i;
168660b08185Syz 	keyspan_port_t	*kp;
168760b08185Syz 
168860b08185Syz 	for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
168960b08185Syz 		kp = &ksp->ks_ports[i];
169060b08185Syz 		if (kp->kp_state != KEYSPAN_PORT_NOT_INIT) {
169160b08185Syz 			ASSERT(kp->kp_state == KEYSPAN_PORT_CLOSED);
169260b08185Syz 
169360b08185Syz 			mutex_destroy(&kp->kp_mutex);
169460b08185Syz 			cv_destroy(&kp->kp_tx_cv);
169560b08185Syz 			usb_free_log_hdl(kp->kp_lh);
169660b08185Syz 		}
169760b08185Syz 	}
169860b08185Syz 	kmem_free(ksp->ks_ports,
169960b08185Syz 	    ksp->ks_dev_spec.port_cnt * sizeof (keyspan_port_t));
170060b08185Syz }
170160b08185Syz 
170260b08185Syz static void
keyspan_init_port_params(keyspan_state_t * ksp)170360b08185Syz keyspan_init_port_params(keyspan_state_t *ksp)
170460b08185Syz {
170560b08185Syz 	int		i;
170660b08185Syz 	size_t		sz;
170702dd2108Slg 	uint_t		read_len;
170802dd2108Slg 	uint_t		write_len;
170902dd2108Slg 
171002dd2108Slg 	/* the max data len of every bulk in req. */
171102dd2108Slg 	if (usb_pipe_get_max_bulk_transfer_size(ksp->ks_dip, &sz) ==
17124ee52f77Slg 	    USB_SUCCESS) {
171302dd2108Slg 		if (ksp->ks_dev_spec.id_product == KEYSPAN_USA49WG_PID) {
1714d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			read_len = (uint_t)min(sz, KEYSPAN_BULKIN_MAX_LEN_49WG);
171502dd2108Slg 		} else {
1716d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			read_len = (uint_t)min(sz, KEYSPAN_BULKIN_MAX_LEN);
171702dd2108Slg 		}
171802dd2108Slg 	} else {
171902dd2108Slg 		if (ksp->ks_dev_spec.id_product == KEYSPAN_USA49WG_PID) {
172002dd2108Slg 			read_len = KEYSPAN_BULKIN_MAX_LEN_49WG;
172160b08185Syz 		} else {
172202dd2108Slg 			read_len = KEYSPAN_BULKIN_MAX_LEN;
172360b08185Syz 		}
172402dd2108Slg 	}
172560b08185Syz 
172602dd2108Slg 	for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
172702dd2108Slg 		ksp->ks_ports[i].kp_read_len = read_len;
172860b08185Syz 		/* the max data len of every bulk out req. */
172902dd2108Slg 		switch (ksp->ks_dev_spec.id_product) {
173002dd2108Slg 		case KEYSPAN_USA19HS_PID:
173102dd2108Slg 			ksp->ks_ports[i].kp_write_len =
17324ee52f77Slg 			    KEYSPAN_BULKOUT_MAX_LEN_19HS;
173302dd2108Slg 
173402dd2108Slg 			break;
173502dd2108Slg 		case KEYSPAN_USA49WLC_PID:
173602dd2108Slg 			ksp->ks_ports[i].kp_write_len =
17374ee52f77Slg 			    KEYSPAN_BULKOUT_MAX_LEN_49WLC;
173802dd2108Slg 
173902dd2108Slg 			break;
174002dd2108Slg 		case KEYSPAN_USA49WG_PID:
174102dd2108Slg 			/*
174202dd2108Slg 			 * USA49WG port0 uses intr out pipe send data while
174302dd2108Slg 			 * other ports use bulk out pipes, so port0's max
174402dd2108Slg 			 * packet length for "bulk out" is different from other
174502dd2108Slg 			 * ports' while the same as USA49WLC.
174602dd2108Slg 			 */
174702dd2108Slg 			write_len = ((i == 0) ? KEYSPAN_BULKOUT_MAX_LEN_49WLC :
17484ee52f77Slg 			    KEYSPAN_BULKOUT_MAX_LEN_49WG);
174902dd2108Slg 			ksp->ks_ports[i].kp_write_len = write_len;
175002dd2108Slg 
175102dd2108Slg 			break;
175202dd2108Slg 		default:
175302dd2108Slg 			USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
17544ee52f77Slg 			    "keyspan_init_port_params:"
17554ee52f77Slg 			    "the device's product id can't be recognized");
175602dd2108Slg 
175702dd2108Slg 			return;
175802dd2108Slg 		}
175960b08185Syz 	}
176060b08185Syz }
176160b08185Syz 
176260b08185Syz 
176360b08185Syz /*
176460b08185Syz  * free descriptor tree
176560b08185Syz  */
176660b08185Syz static void
keyspan_free_descr_tree(keyspan_state_t * ksp)176760b08185Syz keyspan_free_descr_tree(keyspan_state_t *ksp)
176860b08185Syz {
176960b08185Syz 	usb_free_descr_tree(ksp->ks_dip, ksp->ks_dev_data);
177060b08185Syz 
177160b08185Syz }
177260b08185Syz 
177360b08185Syz 
177460b08185Syz /*
177560b08185Syz  * register/unregister USB event callbacks
177660b08185Syz  */
177760b08185Syz static int
keyspan_register_events(keyspan_state_t * ksp)177860b08185Syz keyspan_register_events(keyspan_state_t *ksp)
177960b08185Syz {
178060b08185Syz 	return (usb_register_event_cbs(ksp->ks_dip, ksp->ks_usb_events, 0));
178160b08185Syz }
178260b08185Syz 
178360b08185Syz 
178460b08185Syz static void
keyspan_unregister_events(keyspan_state_t * ksp)178560b08185Syz keyspan_unregister_events(keyspan_state_t *ksp)
178660b08185Syz {
178760b08185Syz 	usb_unregister_event_cbs(ksp->ks_dip, ksp->ks_usb_events);
178860b08185Syz }
178960b08185Syz 
179060b08185Syz 
179160b08185Syz static void
keyspan_set_dev_state_online(keyspan_state_t * ksp)179260b08185Syz keyspan_set_dev_state_online(keyspan_state_t *ksp)
179360b08185Syz {
179460b08185Syz 	ksp->ks_dev_state = USB_DEV_ONLINE;
179560b08185Syz }
179660b08185Syz 
179760b08185Syz /*
179802dd2108Slg  * send command to the port and save the params after its completion for
179902dd2108Slg  * USA19HS and USA49WLC
180060b08185Syz  */
180160b08185Syz int
keyspan_send_cmd_usa49(keyspan_port_t * kp)180202dd2108Slg keyspan_send_cmd_usa49(keyspan_port_t *kp)
180360b08185Syz {
180460b08185Syz 	keyspan_state_t	*ksp = kp->kp_ksp;
180560b08185Syz 	mblk_t		*mp;
180660b08185Syz 	int		rval = USB_SUCCESS;
180760b08185Syz 	int	size;
180860b08185Syz 	usb_bulk_req_t	*br;
180960b08185Syz 
181060b08185Syz 	ASSERT(!mutex_owned(&kp->kp_mutex));
181102dd2108Slg 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_send_cmd_usa49");
181260b08185Syz 
181360b08185Syz 	switch (ksp->ks_dev_spec.id_product) {
181460b08185Syz 	case KEYSPAN_USA19HS_PID:
181560b08185Syz 		size = sizeof (keyspan_usa19hs_port_ctrl_msg_t);
181660b08185Syz 
181760b08185Syz 		break;
181860b08185Syz 
1819c138f478Syz 
182060b08185Syz 	case KEYSPAN_USA49WLC_PID:
182160b08185Syz 		size = sizeof (keyspan_usa49_port_ctrl_msg_t);
182260b08185Syz 
182360b08185Syz 		break;
1824c138f478Syz 
182560b08185Syz 	default:
182602dd2108Slg 		USB_DPRINTF_L2(DPRINT_CTLOP, ksp->ks_lh,
18274ee52f77Slg 		    "keyspan_send_cmd_usa49:"
18284ee52f77Slg 		    "the device's product id can't be recognized");
182960b08185Syz 		return (USB_FAILURE);
183060b08185Syz 	}
183160b08185Syz 
183260b08185Syz 	if ((mp = allocb(size, BPRI_LO)) == NULL) {
183360b08185Syz 
183460b08185Syz 		return (USB_FAILURE);
183560b08185Syz 	}
183660b08185Syz 	bcopy(&kp->kp_ctrl_msg, mp->b_rptr, size);
183760b08185Syz 
183860b08185Syz 	br = usb_alloc_bulk_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP);
183960b08185Syz 	br->bulk_len = size;
184060b08185Syz 	br->bulk_data = mp;
184160b08185Syz 	br->bulk_timeout = KEYSPAN_BULK_TIMEOUT;
184260b08185Syz 	br->bulk_client_private = (void *)kp;
184360b08185Syz 	br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
184460b08185Syz 
184560b08185Syz 	rval = usb_pipe_bulk_xfer(ksp->ks_ctrlout_pipe.pipe_handle, br,
184660b08185Syz 	    USB_FLAGS_SLEEP);
184760b08185Syz 	if (rval == USB_SUCCESS) {
184860b08185Syz 		mutex_enter(&kp->kp_mutex);
184960b08185Syz 		keyspan_save_port_params(kp);
185060b08185Syz 		mutex_exit(&kp->kp_mutex);
185160b08185Syz 	} else {
185202dd2108Slg 		USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh, "keyspan_send_cmd_usa49"
18534ee52f77Slg 		    ": failure, rval=%d", rval);
185460b08185Syz 	}
185560b08185Syz 
185660b08185Syz 	usb_free_bulk_req(br);
185760b08185Syz 
185860b08185Syz 	return (rval);
185960b08185Syz }
186060b08185Syz 
186102dd2108Slg /*
186202dd2108Slg  * send command to the port and save the params after its completion for
186302dd2108Slg  * USA_49WG only
186402dd2108Slg  */
186502dd2108Slg int
keyspan_send_cmd_usa49wg(keyspan_port_t * kp)186602dd2108Slg keyspan_send_cmd_usa49wg(keyspan_port_t *kp)
186702dd2108Slg {
186802dd2108Slg 	keyspan_state_t	*ksp = kp->kp_ksp;
186902dd2108Slg 	mblk_t		*mp;
187002dd2108Slg 	int		rval = USB_SUCCESS;
1871d29f5a71Szhigang lu - Sun Microsystems - Beijing China 	uint16_t		size = sizeof (keyspan_usa49_port_ctrl_msg_t);
187202dd2108Slg 	usb_cb_flags_t	cb_flags;
187302dd2108Slg 	usb_cr_t	cr;
187402dd2108Slg 	usb_ctrl_setup_t setup;
187502dd2108Slg 
187602dd2108Slg 	ASSERT(!mutex_owned(&kp->kp_mutex));
187702dd2108Slg 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_send_cmd_usa49wg");
187802dd2108Slg 
187902dd2108Slg 	if ((mp = allocb(size, BPRI_LO)) == NULL) {
188002dd2108Slg 
188102dd2108Slg 		return (USB_FAILURE);
188202dd2108Slg 	}
188302dd2108Slg 	bcopy(&kp->kp_ctrl_msg, mp->b_rptr, size);
188402dd2108Slg 
188502dd2108Slg 	setup.bmRequestType = USB_DEV_REQ_TYPE_VENDOR;
188602dd2108Slg 	setup.bRequest = KEYSPAN_SET_CONTROL_REQUEST;
188702dd2108Slg 	setup.wValue = 0;
188802dd2108Slg 	setup.wIndex = 0;
188902dd2108Slg 	setup.wLength = size;
189002dd2108Slg 	setup.attrs = 0;
189102dd2108Slg 
189202dd2108Slg 	rval = usb_pipe_ctrl_xfer_wait(ksp->ks_def_pipe.pipe_handle, &setup,
189302dd2108Slg 	    &mp, &cr, &cb_flags, 0);
189402dd2108Slg 
189502dd2108Slg 	if (rval == USB_SUCCESS) {
189602dd2108Slg 		mutex_enter(&kp->kp_mutex);
189702dd2108Slg 		keyspan_save_port_params(kp);
189802dd2108Slg 		mutex_exit(&kp->kp_mutex);
189902dd2108Slg 	} else {
190002dd2108Slg 		USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
19014ee52f77Slg 		    "keyspan_send_cmd_usa49wg: failure, rval=%d", rval);
190202dd2108Slg 	}
190302dd2108Slg 	if (mp) {
190402dd2108Slg 		freemsg(mp);
190502dd2108Slg 	}
190602dd2108Slg 
190702dd2108Slg 	return (rval);
190802dd2108Slg }
190902dd2108Slg 
191002dd2108Slg /*
191102dd2108Slg  * send command to the port and save the params after its completion
191202dd2108Slg  */
191302dd2108Slg int
keyspan_send_cmd(keyspan_port_t * kp)191402dd2108Slg keyspan_send_cmd(keyspan_port_t *kp)
191502dd2108Slg {
191602dd2108Slg 	keyspan_state_t	*ksp = kp->kp_ksp;
191702dd2108Slg 	int		rval = USB_FAILURE;
191802dd2108Slg 
191902dd2108Slg 	switch (ksp->ks_dev_spec.id_product) {
192002dd2108Slg 	case KEYSPAN_USA19HS_PID:
192102dd2108Slg 	case KEYSPAN_USA49WLC_PID:
192202dd2108Slg 		rval = keyspan_send_cmd_usa49(kp);
192302dd2108Slg 
192402dd2108Slg 		break;
192502dd2108Slg 	case KEYSPAN_USA49WG_PID:
192602dd2108Slg 		rval = keyspan_send_cmd_usa49wg(kp);
192702dd2108Slg 
192802dd2108Slg 		break;
192902dd2108Slg 	default:
193002dd2108Slg 		USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
19314ee52f77Slg 		    "keyspan_send_cmd: "
19324ee52f77Slg 		    "the device's product id can't be recognized");
193302dd2108Slg 	}
193402dd2108Slg 
193502dd2108Slg 	if (rval != USB_SUCCESS) {
193602dd2108Slg 			USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
193702dd2108Slg 			    "keyspan_send_cmd() FAILED");
193802dd2108Slg 
193902dd2108Slg 			return (rval);
194002dd2108Slg 	}
194102dd2108Slg 
194202dd2108Slg 	return (USB_SUCCESS);
194302dd2108Slg 
194402dd2108Slg }
194502dd2108Slg 
194660b08185Syz /*
194760b08185Syz  * hotplug
194860b08185Syz  * -------
194960b08185Syz  *
195060b08185Syz  * restore device state after CPR resume or reconnect
195160b08185Syz  */
195260b08185Syz static int
keyspan_restore_device_state(keyspan_state_t * ksp)195360b08185Syz keyspan_restore_device_state(keyspan_state_t *ksp)
195460b08185Syz {
195560b08185Syz 	int	state;
195660b08185Syz 
195760b08185Syz 	mutex_enter(&ksp->ks_mutex);
195860b08185Syz 	state = ksp->ks_dev_state;
195960b08185Syz 	mutex_exit(&ksp->ks_mutex);
196060b08185Syz 
196160b08185Syz 	if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
196260b08185Syz 
196360b08185Syz 		return (state);
196460b08185Syz 	}
196560b08185Syz 
1966d291d9f2Sfrits 	if (usb_check_same_device(ksp->ks_dip, ksp->ks_lh, USB_LOG_L0,
196760b08185Syz 	    DPRINT_MASK_ALL, USB_CHK_ALL, NULL) != USB_SUCCESS) {
196860b08185Syz 		mutex_enter(&ksp->ks_mutex);
196960b08185Syz 		state = ksp->ks_dev_state = USB_DEV_DISCONNECTED;
197060b08185Syz 		mutex_exit(&ksp->ks_mutex);
197160b08185Syz 
197260b08185Syz 		return (state);
197360b08185Syz 	}
197460b08185Syz 
197560b08185Syz 	if (state == USB_DEV_DISCONNECTED) {
197660b08185Syz 		USB_DPRINTF_L0(DPRINT_HOTPLUG, ksp->ks_lh,
197760b08185Syz 		    "device has been reconnected but data may have been lost");
197860b08185Syz 	}
197960b08185Syz 
198060b08185Syz 	if (keyspan_reconnect_pipes(ksp) != USB_SUCCESS) {
198160b08185Syz 
198260b08185Syz 		return (state);
198360b08185Syz 	}
198460b08185Syz 
198560b08185Syz 	/*
198660b08185Syz 	 * init device state
198760b08185Syz 	 */
198860b08185Syz 	mutex_enter(&ksp->ks_mutex);
198960b08185Syz 	state = ksp->ks_dev_state = USB_DEV_ONLINE;
199002dd2108Slg 	ksp->ks_reconnect_flag = 1;
199160b08185Syz 	mutex_exit(&ksp->ks_mutex);
199260b08185Syz 
199360b08185Syz 	/*
199460b08185Syz 	 * now restore each open port
199560b08185Syz 	 */
199660b08185Syz 	(void) keyspan_restore_ports_state(ksp);
199760b08185Syz 
199860b08185Syz 	return (state);
199960b08185Syz }
200060b08185Syz 
200160b08185Syz /*
200260b08185Syz  * restore ports state after CPR resume or reconnect
200360b08185Syz  */
200460b08185Syz static int
keyspan_restore_ports_state(keyspan_state_t * ksp)200560b08185Syz keyspan_restore_ports_state(keyspan_state_t *ksp)
200660b08185Syz {
200760b08185Syz 	keyspan_port_t	*kp;
200860b08185Syz 	int		rval = USB_SUCCESS;
200960b08185Syz 	int		err;
201060b08185Syz 	int		i;
201160b08185Syz 
201260b08185Syz 	for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
201360b08185Syz 		kp = &ksp->ks_ports[i];
201460b08185Syz 		/*
201560b08185Syz 		 * only care about open ports
201660b08185Syz 		 */
201760b08185Syz 		mutex_enter(&kp->kp_mutex);
201860b08185Syz 		if (kp->kp_state != KEYSPAN_PORT_OPEN) {
201960b08185Syz 			mutex_exit(&kp->kp_mutex);
202060b08185Syz 			continue;
202160b08185Syz 		}
202260b08185Syz 		mutex_exit(&kp->kp_mutex);
202360b08185Syz 
202460b08185Syz 		sema_p(&ksp->ks_pipes_sema);
202560b08185Syz 		/* open hardware serial port */
202660b08185Syz 		err = keyspan_open_hw_port(kp, B_FALSE);
202760b08185Syz 		sema_v(&ksp->ks_pipes_sema);
202860b08185Syz 		if (err != USB_SUCCESS) {
202960b08185Syz 			USB_DPRINTF_L2(DPRINT_HOTPLUG, kp->kp_lh,
203060b08185Syz 			    "keyspan_restore_ports_state: failed");
203160b08185Syz 			rval = err;
203260b08185Syz 		}
203360b08185Syz 	}
203460b08185Syz 
203560b08185Syz 	return (rval);
203660b08185Syz }
203760b08185Syz 
203860b08185Syz 
203960b08185Syz /*
204060b08185Syz  * power management
204160b08185Syz  * ----------------
204260b08185Syz  *
204360b08185Syz  *
204460b08185Syz  * create PM components
204560b08185Syz  */
204660b08185Syz static int
keyspan_create_pm_components(keyspan_state_t * ksp)204760b08185Syz keyspan_create_pm_components(keyspan_state_t *ksp)
204860b08185Syz {
204960b08185Syz 	dev_info_t	*dip = ksp->ks_dip;
205060b08185Syz 	keyspan_pm_t	*pm;
205160b08185Syz 	uint_t		pwr_states;
205260b08185Syz 
205360b08185Syz 	pm = ksp->ks_pm = kmem_zalloc(sizeof (keyspan_pm_t), KM_SLEEP);
205460b08185Syz 	pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
205560b08185Syz 
205660b08185Syz 	if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
205760b08185Syz 		USB_DPRINTF_L2(DPRINT_PM, ksp->ks_lh,
205860b08185Syz 		    "keyspan_create_pm_components: failed");
205960b08185Syz 
206060b08185Syz 		return (USB_SUCCESS);
206160b08185Syz 	}
206260b08185Syz 
206360b08185Syz 	pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip,
20644ee52f77Slg 	    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS);
206560b08185Syz 	pm->pm_pwr_states = (uint8_t)pwr_states;
206660b08185Syz 
206760b08185Syz 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
206860b08185Syz 
206960b08185Syz 	return (USB_SUCCESS);
207060b08185Syz }
207160b08185Syz 
207260b08185Syz 
207360b08185Syz /*
207460b08185Syz  * destroy PM components
207560b08185Syz  */
207660b08185Syz static void
keyspan_destroy_pm_components(keyspan_state_t * ksp)207760b08185Syz keyspan_destroy_pm_components(keyspan_state_t *ksp)
207860b08185Syz {
207960b08185Syz 	keyspan_pm_t	*pm = ksp->ks_pm;
208060b08185Syz 	dev_info_t	*dip = ksp->ks_dip;
208160b08185Syz 	int		rval;
208260b08185Syz 
208360b08185Syz 	if (ksp->ks_dev_state != USB_DEV_DISCONNECTED) {
208460b08185Syz 		if (pm->pm_wakeup_enabled) {
208560b08185Syz 			(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
208660b08185Syz 
208760b08185Syz 			rval = usb_handle_remote_wakeup(dip,
208860b08185Syz 			    USB_REMOTE_WAKEUP_DISABLE);
208960b08185Syz 			if (rval != USB_SUCCESS) {
209060b08185Syz 				USB_DPRINTF_L2(DPRINT_PM, ksp->ks_lh,
209160b08185Syz 				    "keyspan_destroy_pm_components: disable "
209260b08185Syz 				    "remote wakeup failed, rval=%d", rval);
209360b08185Syz 			}
209460b08185Syz 		}
209560b08185Syz 
209660b08185Syz 		(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
209760b08185Syz 	}
209860b08185Syz 	kmem_free(pm, sizeof (keyspan_pm_t));
209960b08185Syz 	ksp->ks_pm = NULL;
210060b08185Syz }
210160b08185Syz 
210260b08185Syz 
210360b08185Syz /*
210460b08185Syz  * mark device busy and raise power
210560b08185Syz  */
210660b08185Syz static int
keyspan_pm_set_busy(keyspan_state_t * ksp)210760b08185Syz keyspan_pm_set_busy(keyspan_state_t *ksp)
210860b08185Syz {
210960b08185Syz 	keyspan_pm_t	*pm = ksp->ks_pm;
211060b08185Syz 	dev_info_t	*dip = ksp->ks_dip;
211160b08185Syz 
211260b08185Syz 	USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pm_set_busy");
211360b08185Syz 
211460b08185Syz 	mutex_enter(&ksp->ks_mutex);
211560b08185Syz 	/* if already marked busy, just increment the counter */
211660b08185Syz 	if (pm->pm_busy_cnt++ > 0) {
211760b08185Syz 		USB_DPRINTF_L3(DPRINT_PM, ksp->ks_lh, "keyspan_pm_set_busy:"
211860b08185Syz 		    "already busy, busy_cnt = %d", pm->pm_busy_cnt);
211960b08185Syz 		mutex_exit(&ksp->ks_mutex);
212060b08185Syz 
212160b08185Syz 		return (USB_SUCCESS);
212260b08185Syz 	}
212360b08185Syz 
212460b08185Syz 	(void) pm_busy_component(dip, 0);
212560b08185Syz 
212660b08185Syz 	if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
212760b08185Syz 		mutex_exit(&ksp->ks_mutex);
212860b08185Syz 
212960b08185Syz 		return (USB_SUCCESS);
213060b08185Syz 	}
213160b08185Syz 
213260b08185Syz 	/* need to raise power	*/
213360b08185Syz 	pm->pm_raise_power = B_TRUE;
213460b08185Syz 	mutex_exit(&ksp->ks_mutex);
213560b08185Syz 
213660b08185Syz 	USB_DPRINTF_L3(DPRINT_PM, ksp->ks_lh,
213760b08185Syz 	    "keyspan_pm_set_busy: raise power");
213860b08185Syz 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
213960b08185Syz 
214060b08185Syz 	mutex_enter(&ksp->ks_mutex);
214160b08185Syz 	pm->pm_raise_power = B_FALSE;
214260b08185Syz 	mutex_exit(&ksp->ks_mutex);
214360b08185Syz 
214460b08185Syz 	return (USB_SUCCESS);
214560b08185Syz }
214660b08185Syz 
214760b08185Syz 
214860b08185Syz /*
214960b08185Syz  * mark device idle
215060b08185Syz  */
215160b08185Syz static void
keyspan_pm_set_idle(keyspan_state_t * ksp)215260b08185Syz keyspan_pm_set_idle(keyspan_state_t *ksp)
215360b08185Syz {
215460b08185Syz 	keyspan_pm_t	*pm = ksp->ks_pm;
215560b08185Syz 	dev_info_t	*dip = ksp->ks_dip;
215660b08185Syz 
215760b08185Syz 	USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pm_set_idle");
215860b08185Syz 
215960b08185Syz 	/*
216060b08185Syz 	 * if more ports use the device, do not mark as yet
216160b08185Syz 	 */
216260b08185Syz 	mutex_enter(&ksp->ks_mutex);
216360b08185Syz 	if (--pm->pm_busy_cnt > 0) {
216460b08185Syz 		mutex_exit(&ksp->ks_mutex);
216560b08185Syz 
216660b08185Syz 		return;
216760b08185Syz 	}
216860b08185Syz 
216960b08185Syz 	USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pm_set_idle: set idle");
217060b08185Syz 	(void) pm_idle_component(dip, 0);
217160b08185Syz 
217260b08185Syz 	mutex_exit(&ksp->ks_mutex);
217360b08185Syz }
217460b08185Syz 
217560b08185Syz 
217660b08185Syz /*
217760b08185Syz  * Functions to handle power transition for OS levels 0 -> 3
217860b08185Syz  */
217960b08185Syz static int
keyspan_pwrlvl0(keyspan_state_t * ksp)218060b08185Syz keyspan_pwrlvl0(keyspan_state_t *ksp)
218160b08185Syz {
218260b08185Syz 	int	rval;
218302dd2108Slg 	keyspan_pipe_t *statin = &ksp->ks_statin_pipe;
218460b08185Syz 
218560b08185Syz 	USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pwrlvl0");
218660b08185Syz 
218760b08185Syz 	switch (ksp->ks_dev_state) {
218860b08185Syz 	case USB_DEV_ONLINE:
218960b08185Syz 		/* issue USB D3 command to the device */
219060b08185Syz 		rval = usb_set_device_pwrlvl3(ksp->ks_dip);
219160b08185Syz 		ASSERT(rval == USB_SUCCESS);
219202dd2108Slg 
219302dd2108Slg 		if (ksp->ks_dev_spec.id_product == KEYSPAN_USA49WG_PID) {
219402dd2108Slg 			mutex_exit(&ksp->ks_mutex);
219502dd2108Slg 			usb_pipe_stop_intr_polling(statin->pipe_handle,
21964ee52f77Slg 			    USB_FLAGS_SLEEP);
219702dd2108Slg 			mutex_enter(&ksp->ks_mutex);
219802dd2108Slg 
219902dd2108Slg 			mutex_enter(&statin->pipe_mutex);
220002dd2108Slg 			statin->pipe_state = KEYSPAN_PIPE_CLOSED;
220102dd2108Slg 			mutex_exit(&statin->pipe_mutex);
220202dd2108Slg 		}
220360b08185Syz 		ksp->ks_dev_state = USB_DEV_PWRED_DOWN;
220460b08185Syz 		ksp->ks_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
220560b08185Syz 
220660b08185Syz 		/* FALLTHRU */
220760b08185Syz 	case USB_DEV_DISCONNECTED:
220860b08185Syz 	case USB_DEV_SUSPENDED:
220960b08185Syz 		/* allow a disconnect/cpr'ed device to go to lower power */
221060b08185Syz 
221160b08185Syz 		return (USB_SUCCESS);
221260b08185Syz 	case USB_DEV_PWRED_DOWN:
221360b08185Syz 	default:
221460b08185Syz 		USB_DPRINTF_L2(DPRINT_PM, ksp->ks_lh,
221560b08185Syz 		    "keyspan_pwrlvl0: illegal device state");
221660b08185Syz 
221760b08185Syz 		return (USB_FAILURE);
221860b08185Syz 	}
221960b08185Syz }
222060b08185Syz 
222160b08185Syz 
222260b08185Syz static int
keyspan_pwrlvl1(keyspan_state_t * ksp)222360b08185Syz keyspan_pwrlvl1(keyspan_state_t *ksp)
222460b08185Syz {
222560b08185Syz 	USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pwrlvl1");
222660b08185Syz 
222760b08185Syz 	/* issue USB D2 command to the device */
222860b08185Syz 	(void) usb_set_device_pwrlvl2(ksp->ks_dip);
222960b08185Syz 
223060b08185Syz 	return (USB_FAILURE);
223160b08185Syz }
223260b08185Syz 
223360b08185Syz 
223460b08185Syz static int
keyspan_pwrlvl2(keyspan_state_t * ksp)223560b08185Syz keyspan_pwrlvl2(keyspan_state_t *ksp)
223660b08185Syz {
223760b08185Syz 	USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pwrlvl2");
223860b08185Syz 
223960b08185Syz 	/* issue USB D1 command to the device */
224060b08185Syz 	(void) usb_set_device_pwrlvl1(ksp->ks_dip);
224160b08185Syz 
224260b08185Syz 	return (USB_FAILURE);
224360b08185Syz }
224460b08185Syz 
224560b08185Syz 
224660b08185Syz static int
keyspan_pwrlvl3(keyspan_state_t * ksp)224760b08185Syz keyspan_pwrlvl3(keyspan_state_t *ksp)
224860b08185Syz {
224960b08185Syz 	int	rval;
225060b08185Syz 
225160b08185Syz 	USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pwrlvl3");
225260b08185Syz 
225360b08185Syz 	switch (ksp->ks_dev_state) {
225460b08185Syz 	case USB_DEV_PWRED_DOWN:
225560b08185Syz 		/* Issue USB D0 command to the device here */
225660b08185Syz 		rval = usb_set_device_pwrlvl0(ksp->ks_dip);
225760b08185Syz 		ASSERT(rval == USB_SUCCESS);
225802dd2108Slg 
225902dd2108Slg 		if (ksp->ks_dev_spec.id_product == KEYSPAN_USA49WG_PID) {
226002dd2108Slg 			mutex_exit(&ksp->ks_mutex);
226102dd2108Slg 			keyspan_pipe_start_polling(&ksp->ks_statin_pipe);
226202dd2108Slg 			mutex_enter(&ksp->ks_mutex);
226302dd2108Slg 		}
226402dd2108Slg 
226560b08185Syz 		ksp->ks_dev_state = USB_DEV_ONLINE;
226660b08185Syz 		ksp->ks_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
226760b08185Syz 
226860b08185Syz 		/* FALLTHRU */
226960b08185Syz 	case USB_DEV_ONLINE:
227060b08185Syz 		/* we are already in full power */
227160b08185Syz 
227260b08185Syz 		/* FALLTHRU */
227360b08185Syz 	case USB_DEV_DISCONNECTED:
227460b08185Syz 	case USB_DEV_SUSPENDED:
227560b08185Syz 
227660b08185Syz 		return (USB_SUCCESS);
227760b08185Syz 	default:
227860b08185Syz 		USB_DPRINTF_L2(DPRINT_PM, ksp->ks_lh,
227960b08185Syz 		    "keyspan_pwrlvl3: illegal device state");
228060b08185Syz 
228160b08185Syz 		return (USB_FAILURE);
228260b08185Syz 	}
228360b08185Syz }
228460b08185Syz 
228560b08185Syz 
228660b08185Syz /*
228760b08185Syz  * pipe operations
228860b08185Syz  * ---------------
228960b08185Syz  *
229060b08185Syz  * XXX keyspan seem to malfunction after the pipes are closed
229160b08185Syz  * and reopened again (does not respond to OPEN_PORT command).
229260b08185Syz  * so we open them once in attach
229360b08185Syz  */
229460b08185Syz static int
keyspan_attach_pipes(keyspan_state_t * ksp)229560b08185Syz keyspan_attach_pipes(keyspan_state_t *ksp)
229660b08185Syz {
229760b08185Syz 	return (keyspan_open_dev_pipes(ksp));
229860b08185Syz }
229960b08185Syz 
230060b08185Syz void
keyspan_detach_pipes(keyspan_state_t * ksp)230160b08185Syz keyspan_detach_pipes(keyspan_state_t *ksp)
230260b08185Syz {
230360b08185Syz 
230460b08185Syz 	/*
230560b08185Syz 	 * Blow away status bulk in requests or
230660b08185Syz 	 * pipe close will wait until timeout.
230760b08185Syz 	 */
230860b08185Syz 	if (ksp->ks_statin_pipe.pipe_handle) {
230902dd2108Slg 		usb_pipe_stop_intr_polling(ksp->ks_statin_pipe.pipe_handle,
23104ee52f77Slg 		    USB_FLAGS_SLEEP);
231160b08185Syz 	}
231260b08185Syz 
231360b08185Syz 	/* Close the globle pipes */
231460b08185Syz 	keyspan_close_dev_pipes(ksp);
231560b08185Syz }
231660b08185Syz 
231760b08185Syz 
231860b08185Syz /*
231960b08185Syz  * during device disconnect/suspend, close pipes if they are open.
232060b08185Syz  */
232160b08185Syz static void
keyspan_disconnect_pipes(keyspan_state_t * ksp)232260b08185Syz keyspan_disconnect_pipes(keyspan_state_t *ksp)
232360b08185Syz {
232460b08185Syz 	sema_p(&ksp->ks_pipes_sema);
232560b08185Syz 	keyspan_close_pipes(ksp);
232660b08185Syz 	sema_v(&ksp->ks_pipes_sema);
232760b08185Syz }
232860b08185Syz 
232960b08185Syz 
233060b08185Syz /*
233160b08185Syz  * during device reconnect/resume, reopen pipes if they were open.
233260b08185Syz  */
233360b08185Syz static int
keyspan_reconnect_pipes(keyspan_state_t * ksp)233460b08185Syz keyspan_reconnect_pipes(keyspan_state_t *ksp)
233560b08185Syz {
233660b08185Syz 	int	rval = USB_SUCCESS;
233760b08185Syz 
233860b08185Syz 	sema_p(&ksp->ks_pipes_sema);
233960b08185Syz 	rval = keyspan_reopen_pipes(ksp);
234060b08185Syz 	sema_v(&ksp->ks_pipes_sema);
234160b08185Syz 
234260b08185Syz 	return (rval);
234360b08185Syz }
234460b08185Syz 
234560b08185Syz /*
234660b08185Syz  * data transfer routines
234760b08185Syz  * ----------------------
234860b08185Syz  *
234960b08185Syz  *
235060b08185Syz  * start data transmit
235160b08185Syz  */
235260b08185Syz void
keyspan_tx_start(keyspan_port_t * kp,int * xferd)235360b08185Syz keyspan_tx_start(keyspan_port_t *kp, int *xferd)
235460b08185Syz {
235560b08185Syz 	keyspan_state_t	*ksp = kp->kp_ksp;
235660b08185Syz 	int		len;		/* # of bytes we can transmit */
235760b08185Syz 	mblk_t		*data;		/* data to be transmitted */
235802dd2108Slg 	int		data_len = 0;	/* # of bytes in 'data' */
235902dd2108Slg 	int		tran_len;
236060b08185Syz 	int		rval;
236102dd2108Slg 	int		status_len = 0;
236260b08185Syz 
236360b08185Syz 	ASSERT(!mutex_owned(&ksp->ks_mutex));
236460b08185Syz 	ASSERT(mutex_owned(&kp->kp_mutex));
236560b08185Syz 	ASSERT(kp->kp_state != KEYSPAN_PORT_CLOSED);
236660b08185Syz 
236760b08185Syz 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, kp->kp_lh, "keyspan_tx_start");
236860b08185Syz 
236960b08185Syz 	if (xferd) {
237060b08185Syz 		*xferd = 0;
237160b08185Syz 	}
237260b08185Syz 	if ((kp->kp_flags & KEYSPAN_PORT_TX_STOPPED) ||
237360b08185Syz 	    (kp->kp_tx_mp == NULL)) {
237460b08185Syz 
237560b08185Syz 		return;
237660b08185Syz 	}
237760b08185Syz 
237860b08185Syz 	len = min(msgdsize(kp->kp_tx_mp), kp->kp_write_len);
237960b08185Syz 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, kp->kp_lh, "keyspan_tx_start:"
238060b08185Syz 	    "len = %d, tx_mp_len = %d", len, (int)msgdsize(kp->kp_tx_mp));
238160b08185Syz 
238260b08185Syz 	mutex_exit(&kp->kp_mutex);
238360b08185Syz 
238460b08185Syz 	/*
238560b08185Syz 	 * Some keyspan adapters, such as usa49wlc,
238660b08185Syz 	 * need use the first byte as flag.
238760b08185Syz 	 */
238860b08185Syz 	switch (ksp->ks_dev_spec.id_product) {
238960b08185Syz 	case KEYSPAN_USA19HS_PID:
239060b08185Syz 
239160b08185Syz 		if ((data = allocb(len, BPRI_LO)) == NULL) {
239260b08185Syz 			mutex_enter(&kp->kp_mutex);
239360b08185Syz 
239460b08185Syz 			return;
239560b08185Syz 		}
239660b08185Syz 		mutex_enter(&kp->kp_mutex);
239760b08185Syz 
239802dd2108Slg 		/* copy at most 'len' bytes from mblk chain for transmission */
239902dd2108Slg 		data_len = keyspan_tx_copy_data(kp, data, len);
240002dd2108Slg 		if (data_len <= 0) {
240102dd2108Slg 			USB_DPRINTF_L3(DPRINT_OUT_PIPE, kp->kp_lh,
24024ee52f77Slg 			    "keyspan_tx_start:keyspan_tx_copy_data copied"
24034ee52f77Slg 			    " zero bytes");
240402dd2108Slg 		}
240560b08185Syz 
240602dd2108Slg 		break;
2407c138f478Syz 
240860b08185Syz 	case KEYSPAN_USA49WLC_PID:
240902dd2108Slg 	case KEYSPAN_USA49WG_PID:
241002dd2108Slg 		status_len = len / 64 + 1;
241102dd2108Slg 		if ((data = allocb(len + status_len, BPRI_LO)) == NULL) {
241260b08185Syz 			mutex_enter(&kp->kp_mutex);
241360b08185Syz 
241402dd2108Slg 			return;
241502dd2108Slg 		}
241602dd2108Slg 		mutex_enter(&kp->kp_mutex);
241702dd2108Slg 		/*
241802dd2108Slg 		 * the data format is [status byte][63 data bytes][...][status]
241902dd2108Slg 		 * byte][up to 63 bytes] according to keyspan spec
242002dd2108Slg 		 */
242102dd2108Slg 		while (data_len < len) {
242202dd2108Slg 			/* Add status byte per 63 data bytes */
242302dd2108Slg 			*(data->b_wptr++) = 0;
242402dd2108Slg 			/* copy at most 63 bytes from mblk chain for trans */
242502dd2108Slg 			tran_len = keyspan_tx_copy_data(kp, data, 63);
242602dd2108Slg 			if (tran_len <= 0) {
242702dd2108Slg 				USB_DPRINTF_L3(DPRINT_OUT_PIPE, kp->kp_lh,
24284ee52f77Slg 				    "keyspan_tx_start:keyspan_tx_copy_data"
24294ee52f77Slg 				    " copied zero bytes");
243002dd2108Slg 
243102dd2108Slg 				break;
243260b08185Syz 			}
243302dd2108Slg 			data_len += tran_len;
243460b08185Syz 		}
243560b08185Syz 
243660b08185Syz 		break;
243760b08185Syz 	default:
243860b08185Syz 
243960b08185Syz 		mutex_enter(&kp->kp_mutex);
244060b08185Syz 		USB_DPRINTF_L2(DPRINT_OUT_PIPE, ksp->ks_lh, "keyspan_tx_start:"
244160b08185Syz 		    "the device's product id can't be recognized");
244260b08185Syz 
244360b08185Syz 		return;
244460b08185Syz 	}
244560b08185Syz 
244602dd2108Slg 	mutex_exit(&kp->kp_mutex);
244760b08185Syz 
244802dd2108Slg 	/*
244902dd2108Slg 	 * For USA-49WG, the port0 uses intr out pipe as data out pipe, while
245002dd2108Slg 	 * other ports use bulk out pipe.
245102dd2108Slg 	 */
245202dd2108Slg 
245302dd2108Slg 	if ((kp->kp_port_num == 0) &&
24544ee52f77Slg 	    (ksp->ks_dev_spec.id_product == KEYSPAN_USA49WG_PID)) {
245502dd2108Slg 		rval = keyspan_send_data_port0(&kp->kp_dataout_pipe, &data, kp);
245602dd2108Slg 	} else {
245702dd2108Slg 		rval = keyspan_send_data(&kp->kp_dataout_pipe, &data, kp);
245860b08185Syz 	}
245960b08185Syz 	mutex_enter(&kp->kp_mutex);
246060b08185Syz 
246160b08185Syz 	/*
246260b08185Syz 	 * if send failed, put data back
246360b08185Syz 	 */
246460b08185Syz 	if (rval != USB_SUCCESS) {
246560b08185Syz 		ASSERT(data);
246660b08185Syz 		keyspan_put_head(&kp->kp_tx_mp, data, kp);
246760b08185Syz 	} else if (xferd) {
246860b08185Syz 		*xferd = data_len;
246960b08185Syz 	}
247060b08185Syz 
247160b08185Syz 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, kp->kp_lh, "keyspan_tx_start[%d]: over"
247260b08185Syz 	    "(%d) rval=%d", kp->kp_port_num, data_len, rval);
247360b08185Syz 
247460b08185Syz }
247560b08185Syz 
247660b08185Syz 
247760b08185Syz /*
247860b08185Syz  * copy no more than 'len' bytes from mblk chain to transmit mblk 'data'.
247960b08185Syz  * return number of bytes copied
248060b08185Syz  */
248160b08185Syz int
keyspan_tx_copy_data(keyspan_port_t * kp,mblk_t * data,int len)248260b08185Syz keyspan_tx_copy_data(keyspan_port_t *kp, mblk_t *data, int len)
248360b08185Syz {
248460b08185Syz 	mblk_t		*mp;	/* current msgblk */
248560b08185Syz 	int		copylen; /* # of bytes to copy from 'mp' to 'data' */
248660b08185Syz 	int		data_len = 0;
248760b08185Syz 
248860b08185Syz 	ASSERT(mutex_owned(&kp->kp_mutex));
248960b08185Syz 
2490688b07c5Sgc 	if (msgdsize(kp->kp_tx_mp) == 0) {
2491688b07c5Sgc 		data->b_wptr = data->b_rptr;
2492688b07c5Sgc 		freeb(kp->kp_tx_mp);
2493688b07c5Sgc 		kp->kp_tx_mp = NULL;
2494688b07c5Sgc 
2495688b07c5Sgc 		return (data_len);
2496688b07c5Sgc 	}
2497688b07c5Sgc 
249860b08185Syz 	while ((data_len < len) && kp->kp_tx_mp) {
249960b08185Syz 		mp = kp->kp_tx_mp;
250060b08185Syz 		copylen = min(MBLKL(mp), len - data_len);
250160b08185Syz 		bcopy(mp->b_rptr, data->b_wptr, copylen);
250260b08185Syz 
250360b08185Syz 		mp->b_rptr += copylen;
250460b08185Syz 		data->b_wptr += copylen;
250560b08185Syz 		data_len += copylen;
250660b08185Syz 
250722eb7cb5Sgd 		if (MBLKL(mp) < 1) {
250860b08185Syz 			kp->kp_tx_mp = unlinkb(mp);
250960b08185Syz 			freeb(mp);
251060b08185Syz 		} else {
251160b08185Syz 			ASSERT(data_len == len);
251260b08185Syz 		}
251360b08185Syz 	}
251460b08185Syz 	USB_DPRINTF_L3(DPRINT_OUT_DATA, kp->kp_lh, "keyspan_tx_copy_data:"
251560b08185Syz 	    "copied data_len = %d", data_len);
251660b08185Syz 
251760b08185Syz 	return (data_len);
251860b08185Syz }
251960b08185Syz 
252060b08185Syz 
252160b08185Syz /*
252260b08185Syz  * wait until local tx buffer drains.
252360b08185Syz  * 'timeout' is in seconds, zero means wait forever
252460b08185Syz  */
252560b08185Syz static int
keyspan_wait_tx_drain(keyspan_port_t * kp,int timeout)252660b08185Syz keyspan_wait_tx_drain(keyspan_port_t *kp, int timeout)
252760b08185Syz {
252860b08185Syz 	clock_t	until;
252960b08185Syz 	int	over = 0;
253060b08185Syz 
253160b08185Syz 	USB_DPRINTF_L4(DPRINT_OUT_DATA, kp->kp_lh, "keyspan_wait_tx_drain:"
253260b08185Syz 	    "timeout = %d", timeout);
253360b08185Syz 	until = ddi_get_lbolt() + drv_usectohz(1000000 * timeout);
253460b08185Syz 
253560b08185Syz 	while (kp->kp_tx_mp && !over) {
253660b08185Syz 		if (timeout > 0) {
253760b08185Syz 			over = (cv_timedwait_sig(&kp->kp_tx_cv,
25384ee52f77Slg 			    &kp->kp_mutex, until) <= 0);
253960b08185Syz 		} else {
254060b08185Syz 			over = (cv_wait_sig(&kp->kp_tx_cv, &kp->kp_mutex) == 0);
254160b08185Syz 		}
254260b08185Syz 	}
254360b08185Syz 
254460b08185Syz 	return ((kp->kp_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE);
254560b08185Syz }
254660b08185Syz 
254760b08185Syz /*
254860b08185Syz  * returns 0 if device is not online, != 0 otherwise
254960b08185Syz  */
255060b08185Syz int
keyspan_dev_is_online(keyspan_state_t * ksp)255160b08185Syz keyspan_dev_is_online(keyspan_state_t *ksp)
255260b08185Syz {
255360b08185Syz 	int	rval;
255460b08185Syz 
255560b08185Syz 	mutex_enter(&ksp->ks_mutex);
255660b08185Syz 	rval = (ksp->ks_dev_state == USB_DEV_ONLINE);
255760b08185Syz 	mutex_exit(&ksp->ks_mutex);
255860b08185Syz 
255960b08185Syz 	return (rval);
256060b08185Syz }
256160b08185Syz 
256260b08185Syz /*
256360b08185Syz  * link a message block to tail of message
256460b08185Syz  * account for the case when message is null
256560b08185Syz  */
256660b08185Syz void
keyspan_put_tail(mblk_t ** mpp,mblk_t * bp)256760b08185Syz keyspan_put_tail(mblk_t **mpp, mblk_t *bp)
256860b08185Syz {
256960b08185Syz 	if (*mpp) {
257060b08185Syz 		linkb(*mpp, bp);
257160b08185Syz 	} else {
257260b08185Syz 		*mpp = bp;
257360b08185Syz 	}
257460b08185Syz }
257560b08185Syz 
257660b08185Syz /*
257760b08185Syz  * put a message block at the head of the message
257860b08185Syz  * account for the case when message is null
257960b08185Syz  */
258060b08185Syz void
keyspan_put_head(mblk_t ** mpp,mblk_t * bp,keyspan_port_t * kp)258160b08185Syz keyspan_put_head(mblk_t **mpp, mblk_t *bp, keyspan_port_t *kp)
258260b08185Syz {
258360b08185Syz 	switch (kp->kp_ksp->ks_dev_spec.id_product) {
258460b08185Syz 	case KEYSPAN_USA19HS_PID:
258560b08185Syz 		if (*mpp) {
258660b08185Syz 			linkb(bp, *mpp);
258760b08185Syz 		}
258860b08185Syz 		*mpp = bp;
258960b08185Syz 
259060b08185Syz 		break;
259160b08185Syz 
2592c138f478Syz 
259360b08185Syz 	case KEYSPAN_USA49WLC_PID:
259402dd2108Slg 	case KEYSPAN_USA49WG_PID:
259560b08185Syz 
259660b08185Syz 		/* get rid of the first byte of the msg data which is a flag */
259760b08185Syz 		if (*mpp) {
259860b08185Syz 			linkb(bp, *mpp);
259960b08185Syz 		}
260060b08185Syz 		bp->b_rptr = bp->b_datap->db_base + 1;
260160b08185Syz 		*mpp = bp;
260260b08185Syz 
260360b08185Syz 		break;
2604c138f478Syz 
260560b08185Syz 	default:
260660b08185Syz 		USB_DPRINTF_L2(DPRINT_OUT_DATA, kp->kp_lh, "keyspan_put_head:"
260760b08185Syz 		    "the device's product id can't be recognized");
260860b08185Syz 
260960b08185Syz 		return;
261060b08185Syz 	}
261160b08185Syz 
261260b08185Syz }
261360b08185Syz 
261460b08185Syz /*
261560b08185Syz  * Set the port parameters to default values
261660b08185Syz  */
261760b08185Syz static void
keyspan_default_port_params(keyspan_port_t * kp)261860b08185Syz keyspan_default_port_params(keyspan_port_t *kp)
261960b08185Syz {
262060b08185Syz 	keyspan_state_t	*ksp = kp->kp_ksp;
262160b08185Syz 
262260b08185Syz 	ASSERT(mutex_owned(&kp->kp_mutex));
262360b08185Syz 
262460b08185Syz 	switch (ksp->ks_dev_spec.id_product) {
262560b08185Syz 	case KEYSPAN_USA19HS_PID:
262660b08185Syz 		keyspan_default_port_params_usa19hs(kp);
262760b08185Syz 
262860b08185Syz 		break;
262960b08185Syz 
2630c138f478Syz 
263160b08185Syz 	case KEYSPAN_USA49WLC_PID:
263202dd2108Slg 	case KEYSPAN_USA49WG_PID:
263360b08185Syz 		keyspan_default_port_params_usa49(kp);
263460b08185Syz 
263560b08185Syz 		break;
2636c138f478Syz 
263760b08185Syz 	default:
263860b08185Syz 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
263960b08185Syz 		    "keyspan_default_port_params:"
264060b08185Syz 		    "the device's product id can't be recognized");
264160b08185Syz 	}
264260b08185Syz 
264360b08185Syz 	USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
264460b08185Syz 	    "keyspan_default_port_params: setted.");
264560b08185Syz }
264660b08185Syz 
264760b08185Syz /*
264860b08185Syz  * Build the command message according to the params from usbser.
264960b08185Syz  * The message will then be sent to deivce by keyspan_send_cmd.
265060b08185Syz  */
265160b08185Syz static void
keyspan_build_cmd_msg(keyspan_port_t * kp,ds_port_params_t * tp)265260b08185Syz keyspan_build_cmd_msg(keyspan_port_t *kp, ds_port_params_t *tp)
265360b08185Syz {
265460b08185Syz 	keyspan_state_t	*ksp = kp->kp_ksp;
265560b08185Syz 
265660b08185Syz 	switch (ksp->ks_dev_spec.id_product) {
265760b08185Syz 	case KEYSPAN_USA19HS_PID:
265860b08185Syz 		keyspan_build_cmd_msg_usa19hs(kp, tp);
265960b08185Syz 
266060b08185Syz 		break;
266160b08185Syz 
2662c138f478Syz 
266360b08185Syz 	case KEYSPAN_USA49WLC_PID:
266402dd2108Slg 	case KEYSPAN_USA49WG_PID:
266560b08185Syz 		keyspan_build_cmd_msg_usa49(kp, tp);
266660b08185Syz 
266760b08185Syz 		break;
2668c138f478Syz 
266960b08185Syz 	default:
267060b08185Syz 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
267160b08185Syz 		    "keyspan_build_cmd_msg:"
267260b08185Syz 		    "the device's product id can't be recognized");
267360b08185Syz 	}
267460b08185Syz }
267560b08185Syz 
267660b08185Syz /* save the port params after send cmd successfully */
267760b08185Syz static void
keyspan_save_port_params(keyspan_port_t * kp)267860b08185Syz keyspan_save_port_params(keyspan_port_t	*kp)
267960b08185Syz {
268060b08185Syz 	keyspan_state_t	*ksp = kp->kp_ksp;
268160b08185Syz 
268260b08185Syz 	ASSERT(mutex_owned(&kp->kp_mutex));
268360b08185Syz 
268460b08185Syz 	switch (ksp->ks_dev_spec.id_product) {
268560b08185Syz 	case KEYSPAN_USA19HS_PID:
268660b08185Syz 		keyspan_save_port_params_usa19hs(kp);
268760b08185Syz 
268860b08185Syz 		break;
268960b08185Syz 
2690c138f478Syz 
269160b08185Syz 	case KEYSPAN_USA49WLC_PID:
269202dd2108Slg 	case KEYSPAN_USA49WG_PID:
269360b08185Syz 		keyspan_save_port_params_usa49(kp);
269460b08185Syz 
269560b08185Syz 		break;
2696c138f478Syz 
269760b08185Syz 	default:
269860b08185Syz 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
269960b08185Syz 		    "keyspan_save_port_params:"
270060b08185Syz 		    "the device's product id can't be recognized");
270160b08185Syz 	}
270260b08185Syz 
270360b08185Syz 	USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
270460b08185Syz 	    "keyspan_save_port_params: baud = %x, lcr = %x,"
270560b08185Syz 	    "status_flag = %x", kp->kp_baud, kp->kp_lcr, kp->kp_status_flag);
270660b08185Syz 
270760b08185Syz }
270860b08185Syz 
270960b08185Syz /* save the port params after send cmd successfully */
271060b08185Syz static void
keyspan_save_port_params_usa19hs(keyspan_port_t * kp)271160b08185Syz keyspan_save_port_params_usa19hs(keyspan_port_t	*kp)
271260b08185Syz {
271360b08185Syz 	keyspan_usa19hs_port_ctrl_msg_t	*ctrl_msg = &(kp->kp_ctrl_msg.usa19hs);
271460b08185Syz 
271560b08185Syz 	ASSERT(mutex_owned(&kp->kp_mutex));
271660b08185Syz 
271760b08185Syz 	if (ctrl_msg->setClocking) {
271860b08185Syz 		kp->kp_baud = ctrl_msg->baudHi;
271960b08185Syz 		kp->kp_baud = (kp->kp_baud << 8);
272060b08185Syz 		kp->kp_baud |= ctrl_msg->baudLo;
272160b08185Syz 	}
272260b08185Syz 	if (ctrl_msg->setLcr) {
272360b08185Syz 		kp->kp_lcr = ctrl_msg->lcr;
272460b08185Syz 	}
272560b08185Syz 	if (ctrl_msg->setRts) {
272660b08185Syz 		if (ctrl_msg->rts) {
272760b08185Syz 			kp->kp_status_flag |= KEYSPAN_PORT_RTS;
272860b08185Syz 		} else {
272960b08185Syz 			kp->kp_status_flag &= ~KEYSPAN_PORT_RTS;
273060b08185Syz 		}
273160b08185Syz 	}
273260b08185Syz 	if (ctrl_msg->setDtr) {
273360b08185Syz 		if (ctrl_msg->dtr) {
273460b08185Syz 			kp->kp_status_flag |= KEYSPAN_PORT_DTR;
273560b08185Syz 		} else {
273660b08185Syz 			kp->kp_status_flag &= ~KEYSPAN_PORT_DTR;
273760b08185Syz 		}
273860b08185Syz 	}
273960b08185Syz 
274060b08185Syz 	if (ctrl_msg->portEnabled) {
274160b08185Syz 		kp->kp_status_flag |= KEYSPAN_PORT_ENABLE;
274260b08185Syz 	} else {
274360b08185Syz 		kp->kp_status_flag &= ~KEYSPAN_PORT_ENABLE;
274460b08185Syz 	}
274560b08185Syz 
274660b08185Syz 	USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
274760b08185Syz 	    "keyspan_save_port_params: baud = %x, lcr = %x,"
274860b08185Syz 	    "status_flag = %x", kp->kp_baud, kp->kp_lcr, kp->kp_status_flag);
274960b08185Syz 
275060b08185Syz }
275160b08185Syz 
275260b08185Syz /*
275360b08185Syz  * Set the port parameters to default values
275460b08185Syz  */
275560b08185Syz static void
keyspan_default_port_params_usa19hs(keyspan_port_t * kp)275660b08185Syz keyspan_default_port_params_usa19hs(keyspan_port_t *kp)
275760b08185Syz {
275860b08185Syz 	keyspan_usa19hs_port_ctrl_msg_t	*ctrl_msg = &(kp->kp_ctrl_msg.usa19hs);
275960b08185Syz 	ASSERT(mutex_owned(&kp->kp_mutex));
276060b08185Syz 
276160b08185Syz 	keyspan_build_cmd_msg(kp, NULL);
276260b08185Syz 
276360b08185Syz 	ctrl_msg->setRts = 0x01;
276460b08185Syz 	ctrl_msg->rts = 0x1;
276560b08185Syz 	ctrl_msg->setDtr = 0x01;
276660b08185Syz 	ctrl_msg->dtr = 0x1;
276760b08185Syz 
276860b08185Syz 	ctrl_msg->setClocking = 1;
276960b08185Syz 	ctrl_msg->setRxMode = 1;
277060b08185Syz 	ctrl_msg->setTxMode = 1;
277160b08185Syz 
277260b08185Syz 	/* set baud rate to 9600 */
277360b08185Syz 	ctrl_msg->baudLo = keyspan_speedtab_usa19hs[13] & 0xff;
277460b08185Syz 	ctrl_msg->baudHi = (keyspan_speedtab_usa19hs[13] >> 8) & 0xff;
277560b08185Syz 	ctrl_msg->rxMode = RXMODE_BYHAND;
277660b08185Syz 	ctrl_msg->txMode = TXMODE_BYHAND;
277760b08185Syz 
277860b08185Syz 	ctrl_msg->lcr = 0x3;
277960b08185Syz 	ctrl_msg->setLcr = 0x1;
278060b08185Syz 
278160b08185Syz 	ctrl_msg->xonChar = CSTART;
278260b08185Syz 	ctrl_msg->xoffChar = CSTOP;
278360b08185Syz 	ctrl_msg->setTxFlowControl = 1;
278460b08185Syz 	ctrl_msg->txFlowControl = TXFLOW_CTS;
278560b08185Syz 	ctrl_msg->setRxFlowControl = 1;
278660b08185Syz 	ctrl_msg->rxFlowControl = RXFLOW_RTS;
278760b08185Syz 	ctrl_msg->rxFlush = 0;
278860b08185Syz 
278960b08185Syz }
279060b08185Syz 
279160b08185Syz /*
279260b08185Syz  * Build the command message according to the params from usbser.
279360b08185Syz  * The message will then be sent to deivce by keyspan_send_cmd.
279460b08185Syz  */
279560b08185Syz static void
keyspan_build_cmd_msg_usa19hs(keyspan_port_t * kp,ds_port_params_t * tp)279660b08185Syz keyspan_build_cmd_msg_usa19hs(keyspan_port_t *kp, ds_port_params_t *tp)
279760b08185Syz {
279860b08185Syz 	int		cnt, i;
279960b08185Syz 	uint_t		ui;
280060b08185Syz 	ds_port_param_entry_t *pe;
280160b08185Syz 	keyspan_usa19hs_port_ctrl_msg_t	*ctrl_msg = &(kp->kp_ctrl_msg.usa19hs);
280260b08185Syz 
280360b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
280460b08185Syz 	    "keyspan_build_cmd_msg_usa19hs: tp = %p", (void *)tp);
280560b08185Syz 
280660b08185Syz 	ASSERT(mutex_owned(&kp->kp_mutex));
280760b08185Syz 	ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN ||
280860b08185Syz 	    kp->kp_state == KEYSPAN_PORT_OPENING);
280960b08185Syz 
281060b08185Syz 	/* bzero all elements */
281160b08185Syz 	bzero(ctrl_msg, sizeof (keyspan_usa19hs_port_ctrl_msg_t));
281260b08185Syz 
281360b08185Syz 	/* it is usaually 16, according to Keyspan spec */
281460b08185Syz 	ctrl_msg->rxForwardingLength = 16;
281560b08185Syz 	/* from 1ms to 31ms, according to Keyspan spec. */
281660b08185Syz 	ctrl_msg->rxForwardingTimeout = 16;
281760b08185Syz 
281860b08185Syz 	ctrl_msg->portEnabled = 1;
281960b08185Syz 	ctrl_msg->returnStatus = 1;
282060b08185Syz 
282160b08185Syz 	if (tp == NULL) {
282260b08185Syz 
282360b08185Syz 		return;
282460b08185Syz 	}
282560b08185Syz 
282660b08185Syz 	cnt = tp->tp_cnt;
282760b08185Syz 	pe = tp->tp_entries;
282860b08185Syz 
282960b08185Syz 	/* translate tp parameters into cmd_msg elements */
283060b08185Syz 	for (i = 0; i < cnt; i++, pe++) {
283160b08185Syz 		switch (pe->param) {
283260b08185Syz 		case DS_PARAM_BAUD:
283360b08185Syz 			ui = pe->val.ui;
283460b08185Syz 
283560b08185Syz 			/*
283660b08185Syz 			 * if we don't support this speed,
283760b08185Syz 			 * then return failure.
283860b08185Syz 			 */
283960b08185Syz 			if ((ui >= NELEM(keyspan_speedtab_usa19hs)) ||
284060b08185Syz 			    ((ui > 0) && (keyspan_speedtab_usa19hs[ui] == 0))) {
284160b08185Syz 
284260b08185Syz 				USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
284360b08185Syz 				    "keyspan_build_cmd_msg_usa19hs:"
284460b08185Syz 				    " bad baud %d", ui);
284560b08185Syz 
284660b08185Syz 				break;
284760b08185Syz 			}
284860b08185Syz 
284960b08185Syz 			/* if the same as the old rate, need not set the rate */
285060b08185Syz 			if (kp->kp_baud == keyspan_speedtab_usa19hs[ui]) {
285160b08185Syz 
285260b08185Syz 				USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
285360b08185Syz 				    "keyspan_build_cmd_msg_usa19hs:"
285460b08185Syz 				    " same as old baud setting, baud = %d",
285560b08185Syz 				    keyspan_speed2baud[ui]);
285660b08185Syz 
285760b08185Syz 				break;
285860b08185Syz 			}
285960b08185Syz 			ctrl_msg->setClocking = 1; /* enable the setting */
286060b08185Syz 			ctrl_msg->setRxMode = 1;
286160b08185Syz 			ctrl_msg->setTxMode = 1;
286260b08185Syz 
286360b08185Syz 			ctrl_msg->baudLo = keyspan_speedtab_usa19hs[ui] & 0xff;
286460b08185Syz 			ctrl_msg->baudHi = (keyspan_speedtab_usa19hs[ui] >> 8)
286560b08185Syz 			    & 0xff;
286660b08185Syz 
286760b08185Syz 			ctrl_msg->rxMode = RXMODE_BYHAND;
286860b08185Syz 			ctrl_msg->txMode = TXMODE_BYHAND;
286960b08185Syz 
287060b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
287160b08185Syz 			    "keyspan_build_cmd_msg_usa19hs: baud=%d",
287260b08185Syz 			    keyspan_speed2baud[ui]);
287360b08185Syz 
287460b08185Syz 			break;
287560b08185Syz 		case DS_PARAM_PARITY:
287660b08185Syz 			if (pe->val.ui & PARENB) {
287760b08185Syz 
287860b08185Syz 				/*
287960b08185Syz 				 * Since USA_PARITY_NONE == 0, it's not
288060b08185Syz 				 * necessary to or it in here.
288160b08185Syz 				 */
288260b08185Syz 				if (pe->val.ui & PARODD) {
288360b08185Syz 					ctrl_msg->lcr |= USA_PARITY_ODD;
288460b08185Syz 				} else {
288560b08185Syz 					ctrl_msg->lcr |= USA_PARITY_EVEN;
288660b08185Syz 				}
288760b08185Syz 			}
288860b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
288960b08185Syz 			    "keyspan_build_cmd_msg_usa19hs: parity=%x,lcr = %x",
289060b08185Syz 			    pe->val.ui, ctrl_msg->lcr);
289160b08185Syz 
289260b08185Syz 			break;
289360b08185Syz 		case DS_PARAM_STOPB:
289460b08185Syz 			if (pe->val.ui & CSTOPB) {
289560b08185Syz 				ctrl_msg->lcr |= STOPBITS_678_2;
289660b08185Syz 			} else {
289760b08185Syz 
289860b08185Syz 				/*
289960b08185Syz 				 * STOPBITS_5678_1 equals zero,
290060b08185Syz 				 * so it's not necessary to or it in.
290160b08185Syz 				 */
290260b08185Syz 				USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
290360b08185Syz 				    "keyspan_build_cmd_msg_usa19hs:"
290460b08185Syz 				    " STOPBITS_5678_1");
290560b08185Syz 			}
290660b08185Syz 
290760b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
290860b08185Syz 			    "keyspan_build_cmd_msg_usa19hs: stopb=%x, lcr = %x",
290960b08185Syz 			    pe->val.ui, ctrl_msg->lcr);
291060b08185Syz 
291160b08185Syz 			break;
291260b08185Syz 		case DS_PARAM_CHARSZ:
291360b08185Syz 			switch (pe->val.ui) {
291460b08185Syz 			case CS5:
291560b08185Syz 
291660b08185Syz 				/*
291760b08185Syz 				 * USA_DATABITS_5 equals zero,
291860b08185Syz 				 * not necessary to or it in.
291960b08185Syz 				 */
292060b08185Syz 				USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
292160b08185Syz 				    "keyspan_build_cmd_msg_usa19hs:"
292260b08185Syz 				    " USA_DATABITS_5");
292360b08185Syz 
292460b08185Syz 				break;
292560b08185Syz 			case CS6:
292660b08185Syz 				ctrl_msg->lcr |= USA_DATABITS_6;
292760b08185Syz 
292860b08185Syz 				break;
292960b08185Syz 			case CS7:
293060b08185Syz 				ctrl_msg->lcr |= USA_DATABITS_7;
293160b08185Syz 
293260b08185Syz 				break;
293360b08185Syz 			case CS8:
293460b08185Syz 			default:
293560b08185Syz 				/*
293660b08185Syz 				 * The default value is USA_DATABITS_8. It is
293760b08185Syz 				 * safe to set to the default one here.
293860b08185Syz 				 */
293960b08185Syz 				ctrl_msg->lcr |= USA_DATABITS_8;
294060b08185Syz 
294160b08185Syz 				break;
294260b08185Syz 			}
294360b08185Syz 
294460b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
294560b08185Syz 			    "keyspan_build_cmd_msg_usa19hs: cs=%x, lcr = %x",
294660b08185Syz 			    pe->val.ui, ctrl_msg->lcr);
294760b08185Syz 
294860b08185Syz 			break;
294960b08185Syz 		case DS_PARAM_XON_XOFF:
295060b08185Syz 			ctrl_msg->xonChar = pe->val.uc[0]; /* init to CSTART */
295160b08185Syz 			ctrl_msg->xoffChar = pe->val.uc[1]; /* init to CSTOP */
295260b08185Syz 
295360b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
295460b08185Syz 			    "keyspan_build_cmd_msg_usa19hs: xonChar=%x, "
295560b08185Syz 			    "xoffChar = %x", ctrl_msg->xonChar,
295660b08185Syz 			    ctrl_msg->xoffChar);
295760b08185Syz 
295860b08185Syz 			break;
295960b08185Syz 		case DS_PARAM_FLOW_CTL:
296060b08185Syz 			if (pe->val.ui & CTSXON) {
296160b08185Syz 				ctrl_msg->txFlowControl = TXFLOW_CTS;
296260b08185Syz 				ctrl_msg->setTxFlowControl = 1;
296360b08185Syz 			} else {
296460b08185Syz 				/* Clear the tx flow control setting */
296560b08185Syz 				ctrl_msg->txFlowControl = 0;
296660b08185Syz 				ctrl_msg->setTxFlowControl = 1;
296760b08185Syz 			}
296860b08185Syz 			if (pe->val.ui & RTSXOFF) {
296960b08185Syz 				ctrl_msg->rxFlowControl = RXFLOW_RTS;
297060b08185Syz 				ctrl_msg->setRxFlowControl = 1;
297160b08185Syz 			} else {
297260b08185Syz 				/* Clear the rx flow control setting */
297360b08185Syz 				ctrl_msg->rxFlowControl = 0;
297460b08185Syz 				ctrl_msg->setRxFlowControl = 1;
297560b08185Syz 			}
297660b08185Syz 
297760b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
297860b08185Syz 			    "keyspan_build_cmd_msg_usa19hs: txFlowControl = %x,"
297960b08185Syz 			    "rxFlowControl = %x", ctrl_msg->txFlowControl,
298060b08185Syz 			    ctrl_msg->rxFlowControl);
298160b08185Syz 
298260b08185Syz 			break;
298360b08185Syz 		default:
298460b08185Syz 			USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
298560b08185Syz 			    "keyspan_build_cmd_msg_usa19hs: bad param %d",
298660b08185Syz 			    pe->param);
298760b08185Syz 
298860b08185Syz 			break;
298960b08185Syz 		}
299060b08185Syz 
299160b08185Syz 	}
299260b08185Syz 
299360b08185Syz 	/*
299460b08185Syz 	 * Enable the lcr settings only if they are different
299560b08185Syz 	 * with the existing settings.
299660b08185Syz 	 */
299760b08185Syz 	ctrl_msg->setLcr =  (ctrl_msg->lcr == kp->kp_lcr) ? 0 : 1;
299860b08185Syz 
299960b08185Syz }
300060b08185Syz 
3001c138f478Syz 
300260b08185Syz /*
300360b08185Syz  * Build the command message according to the params from usbser.
300460b08185Syz  * The message will then be sent to deivce by keyspan_send_cmd.
300560b08185Syz  */
300660b08185Syz static void
keyspan_build_cmd_msg_usa49(keyspan_port_t * kp,ds_port_params_t * tp)300760b08185Syz keyspan_build_cmd_msg_usa49(keyspan_port_t *kp, ds_port_params_t *tp)
300860b08185Syz {
300960b08185Syz 	int		cnt, i;
301060b08185Syz 	uint_t		ui;
301160b08185Syz 	ds_port_param_entry_t *pe;
301260b08185Syz 	keyspan_usa49_port_ctrl_msg_t	*ctrl_msg = &(kp->kp_ctrl_msg.usa49);
301360b08185Syz 
301460b08185Syz 	USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
301560b08185Syz 	    "keyspan_build_cmd_msg_usa49: tp = %p", (void *)tp);
301660b08185Syz 
301760b08185Syz 	ASSERT(mutex_owned(&kp->kp_mutex));
301860b08185Syz 	ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN ||
301960b08185Syz 	    kp->kp_state == KEYSPAN_PORT_OPENING);
302060b08185Syz 
302160b08185Syz 	/* bzero all elements */
302260b08185Syz 	bzero(ctrl_msg, sizeof (keyspan_usa49_port_ctrl_msg_t));
302360b08185Syz 
302460b08185Syz 	ctrl_msg->portNumber = kp->kp_port_num;
302560b08185Syz 
302660b08185Syz 	/* it is usaually 16, according to Keyspan spec */
302760b08185Syz 	ctrl_msg->forwardingLength = 16;
302860b08185Syz 
302960b08185Syz 	ctrl_msg->enablePort = 1;
303060b08185Syz 	ctrl_msg->returnStatus = 1;
303160b08185Syz 
303260b08185Syz 	if (tp == NULL) {
303360b08185Syz 
303460b08185Syz 		return;
303560b08185Syz 	}
303660b08185Syz 
303760b08185Syz 	cnt = tp->tp_cnt;
303860b08185Syz 	pe = tp->tp_entries;
303960b08185Syz 
304060b08185Syz 	/* translate tp parameters into cmd_msg elements */
304160b08185Syz 	for (i = 0; i < cnt; i++, pe++) {
304260b08185Syz 		switch (pe->param) {
304360b08185Syz 		case DS_PARAM_BAUD:
304460b08185Syz 			ui = pe->val.ui;
304560b08185Syz 
304660b08185Syz 			/*
304760b08185Syz 			 * If we don't support this speed,
304860b08185Syz 			 * then return failure.
304960b08185Syz 			 */
305060b08185Syz 			if ((ui >= NELEM(keyspan_speedtab_usa49)) ||
305160b08185Syz 			    ((ui > 0) && (keyspan_speedtab_usa49[ui] == 0))) {
305260b08185Syz 
305360b08185Syz 				USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
305460b08185Syz 				    "keyspan_build_cmd_msg_usa49:"
305560b08185Syz 				    " bad baud %d", ui);
305660b08185Syz 
305760b08185Syz 				break;
305860b08185Syz 			}
305960b08185Syz 
306060b08185Syz 			/* if the same as the old rate, need not set the rate */
306160b08185Syz 			if (kp->kp_baud == keyspan_speedtab_usa49[ui]) {
306260b08185Syz 
306360b08185Syz 				USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
30644ee52f77Slg 				    "keyspan_build_cmd_msg_usa49: "
30654ee52f77Slg 				    "same as old baud setting, baud = %d",
30664ee52f77Slg 				    keyspan_speed2baud[ui]);
306760b08185Syz 
306860b08185Syz 				break;
306960b08185Syz 			}
307060b08185Syz 			ctrl_msg->setClocking = 0xff; /* enable the setting */
307160b08185Syz 			ctrl_msg->baudLo = keyspan_speedtab_usa49[ui] & 0xff;
307260b08185Syz 			ctrl_msg->baudHi = (keyspan_speedtab_usa49[ui] >> 8)
307360b08185Syz 			    & 0xff;
307460b08185Syz 			ctrl_msg->prescaler = keyspan_prescaler_49wlc[ui];
307560b08185Syz 
307660b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
307760b08185Syz 			    "keyspan_build_cmd_msg_usa49: baud=%d",
307860b08185Syz 			    keyspan_speed2baud[ui]);
307960b08185Syz 
308060b08185Syz 			break;
308160b08185Syz 		case DS_PARAM_PARITY:
308260b08185Syz 			if (pe->val.ui & PARENB) {
308360b08185Syz 
308460b08185Syz 				/*
308560b08185Syz 				 * Since USA_PARITY_NONE == 0,
308660b08185Syz 				 * it's not necessary to or it in here.
308760b08185Syz 				 */
308860b08185Syz 				if (pe->val.ui & PARODD) {
308960b08185Syz 					ctrl_msg->lcr |= USA_PARITY_ODD;
309060b08185Syz 				} else {
309160b08185Syz 					ctrl_msg->lcr |= USA_PARITY_EVEN;
309260b08185Syz 				}
309360b08185Syz 			}
309460b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
309560b08185Syz 			    "keyspan_build_cmd_msg_usa49: parity=%x, lcr = %x",
309660b08185Syz 			    pe->val.ui, ctrl_msg->lcr);
309760b08185Syz 
309860b08185Syz 			break;
309960b08185Syz 		case DS_PARAM_STOPB:
310060b08185Syz 			if (pe->val.ui & CSTOPB) {
310160b08185Syz 				ctrl_msg->lcr |= STOPBITS_678_2;
310260b08185Syz 			} else {
310360b08185Syz 
310460b08185Syz 				/*
310560b08185Syz 				 * STOPBITS_5678_1 equals zero,
310660b08185Syz 				 * not necessary to or it in.
310760b08185Syz 				 */
310860b08185Syz 				USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
310960b08185Syz 				    "keyspan_build_cmd_msg_usa49: "
311060b08185Syz 				    "STOPBITS_5678_1");
311160b08185Syz 			}
311260b08185Syz 
311360b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
311460b08185Syz 			    "keyspan_build_cmd_msg_usa49: stopb=%x, lcr = %x",
311560b08185Syz 			    pe->val.ui, ctrl_msg->lcr);
311660b08185Syz 
311760b08185Syz 			break;
311860b08185Syz 		case DS_PARAM_CHARSZ:
311960b08185Syz 			switch (pe->val.ui) {
312060b08185Syz 			case CS5:
312160b08185Syz 
312260b08185Syz 				/*
312360b08185Syz 				 * USA_DATABITS_5 equals zero,
312460b08185Syz 				 * not necessary to or it in.
312560b08185Syz 				 */
312660b08185Syz 				USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
312760b08185Syz 				    "keyspan_build_cmd_msg_usa49:"
312860b08185Syz 				    " USA_DATABITS_5");
312960b08185Syz 
313060b08185Syz 				break;
313160b08185Syz 			case CS6:
313260b08185Syz 				ctrl_msg->lcr |= USA_DATABITS_6;
313360b08185Syz 
313460b08185Syz 				break;
313560b08185Syz 			case CS7:
313660b08185Syz 				ctrl_msg->lcr |= USA_DATABITS_7;
313760b08185Syz 
313860b08185Syz 				break;
313960b08185Syz 			case CS8:
314060b08185Syz 			default:
314160b08185Syz 				ctrl_msg->lcr |= USA_DATABITS_8;
314260b08185Syz 
314360b08185Syz 				break;
314460b08185Syz 			}
314560b08185Syz 
314660b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
314760b08185Syz 			    "keyspan_build_cmd_msg_usa49: cs=%x, lcr = %x",
314860b08185Syz 			    pe->val.ui, ctrl_msg->lcr);
314960b08185Syz 
315060b08185Syz 			break;
315160b08185Syz 		case DS_PARAM_XON_XOFF:
315260b08185Syz 			ctrl_msg->xonChar = pe->val.uc[0]; /* init to CSTART */
315360b08185Syz 			ctrl_msg->xoffChar = pe->val.uc[1]; /* init to CSTOP */
315460b08185Syz 
315560b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
315660b08185Syz 			    "keyspan_build_cmd_msg_usa49: xonChar=%x, "
315760b08185Syz 			    "xoffChar = %x", ctrl_msg->xonChar,
315860b08185Syz 			    ctrl_msg->xoffChar);
315960b08185Syz 
316060b08185Syz 			break;
316160b08185Syz 		case DS_PARAM_FLOW_CTL:
316260b08185Syz 			if (pe->val.ui & CTSXON) {
316360b08185Syz 				ctrl_msg->ctsFlowControl = 1;
316460b08185Syz 				ctrl_msg->setFlowControl = 1;
316560b08185Syz 			} else {
316660b08185Syz 				ctrl_msg->ctsFlowControl = 0;
316760b08185Syz 				ctrl_msg->setFlowControl = 1;
316860b08185Syz 			}
316960b08185Syz 			if (pe->val.ui & RTSXOFF) {
317060b08185Syz 				USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
317160b08185Syz 				    "keyspan_build_cmd_msg_usa49: "
317260b08185Syz 				    "pe->val.ui = %x, flow_ctl: RTSXOFF, "
317360b08185Syz 				    "no hardware support", pe->val.ui);
317460b08185Syz 			}
317560b08185Syz 
317660b08185Syz 			USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
317760b08185Syz 			    "keyspan_build_cmd_msg_usa49: ctsFlowControl = %x,"
317860b08185Syz 			    "dsrFlowControl = %x", ctrl_msg->ctsFlowControl,
317960b08185Syz 			    ctrl_msg->dsrFlowControl);
318060b08185Syz 
318160b08185Syz 			break;
318260b08185Syz 		default:
318360b08185Syz 			USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
318460b08185Syz 			    "keyspan_build_cmd_msg_usa49: bad param %d",
318560b08185Syz 			    pe->param);
318660b08185Syz 
318760b08185Syz 			break;
318860b08185Syz 		}
318960b08185Syz 	}
319060b08185Syz 
319160b08185Syz 	/*
319260b08185Syz 	 * enable the lcr settings only if they are different
319360b08185Syz 	 * with the existing settings.
319460b08185Syz 	 */
319560b08185Syz 	ctrl_msg->setLcr =  (ctrl_msg->lcr == kp->kp_lcr) ? 0 : 1;
319660b08185Syz 
319760b08185Syz }
319860b08185Syz 
319960b08185Syz 
320060b08185Syz /*
320160b08185Syz  * Set the port parameters to default values
320260b08185Syz  */
320360b08185Syz static void
keyspan_default_port_params_usa49(keyspan_port_t * kp)320460b08185Syz keyspan_default_port_params_usa49(keyspan_port_t *kp)
320560b08185Syz {
320660b08185Syz 	keyspan_usa49_port_ctrl_msg_t	*ctrl_msg = &(kp->kp_ctrl_msg.usa49);
320760b08185Syz 	ASSERT(mutex_owned(&kp->kp_mutex));
320860b08185Syz 
320960b08185Syz 	keyspan_build_cmd_msg(kp, NULL);
321060b08185Syz 
321160b08185Syz 	ctrl_msg->setRts = 1;
321260b08185Syz 	ctrl_msg->rts = 1;
321360b08185Syz 	ctrl_msg->setDtr = 1;
321460b08185Syz 	ctrl_msg->dtr = 1;
321560b08185Syz 
321660b08185Syz 	ctrl_msg->_txOn = 1;
321760b08185Syz 	ctrl_msg->_txOff = 0;
321860b08185Syz 	ctrl_msg->txFlush = 0;
321960b08185Syz 	ctrl_msg->txBreak = 0;
322060b08185Syz 	ctrl_msg->rxOn = 1;
322160b08185Syz 	ctrl_msg->rxOff = 0;
322260b08185Syz 	ctrl_msg->rxFlush = 0;
322360b08185Syz 	ctrl_msg->rxForward = 0;
322460b08185Syz 	ctrl_msg->returnStatus = 1;
322560b08185Syz 	ctrl_msg->resetDataToggle = 0;
322660b08185Syz 	ctrl_msg->enablePort = 1;
322760b08185Syz 	ctrl_msg->disablePort = 0;
322860b08185Syz 
322960b08185Syz 	/* set baud rate to 9600 */
323060b08185Syz 	ctrl_msg->setClocking = 1;
323160b08185Syz 	ctrl_msg->baudLo = keyspan_speedtab_usa49[13] & 0xff;
323260b08185Syz 	ctrl_msg->baudHi = (keyspan_speedtab_usa49[13] >> 8) & 0xff;
323360b08185Syz 	ctrl_msg->prescaler = keyspan_prescaler_49wlc[13];
323460b08185Syz 
323560b08185Syz 	ctrl_msg->lcr = 0x3;
323660b08185Syz 	ctrl_msg->setLcr = 1;
323760b08185Syz 
323860b08185Syz 	ctrl_msg->xonChar = CSTART;
323960b08185Syz 	ctrl_msg->xoffChar = CSTOP;
324060b08185Syz 	ctrl_msg->ctsFlowControl = 1;
324160b08185Syz 	ctrl_msg->setFlowControl = 1;
324260b08185Syz 
324360b08185Syz }
324460b08185Syz 
324560b08185Syz 
324660b08185Syz /* save the port params after send cmd successfully */
324760b08185Syz static void
keyspan_save_port_params_usa49(keyspan_port_t * kp)324860b08185Syz keyspan_save_port_params_usa49(keyspan_port_t	*kp)
324960b08185Syz {
325060b08185Syz 	keyspan_usa49_port_ctrl_msg_t	*ctrl_msg = &(kp->kp_ctrl_msg.usa49);
325160b08185Syz 
325260b08185Syz 	ASSERT(mutex_owned(&kp->kp_mutex));
325360b08185Syz 
325460b08185Syz 	if (ctrl_msg->setClocking) {
325560b08185Syz 		kp->kp_baud = ctrl_msg->baudHi;
325660b08185Syz 		kp->kp_baud = (kp->kp_baud << 8);
325760b08185Syz 		kp->kp_baud |= ctrl_msg->baudLo;
325860b08185Syz 	}
325960b08185Syz 	if (ctrl_msg->setLcr) {
326060b08185Syz 		kp->kp_lcr = ctrl_msg->lcr;
326160b08185Syz 	}
326260b08185Syz 	if (ctrl_msg->setRts) {
326360b08185Syz 		if (ctrl_msg->rts) {
326460b08185Syz 			kp->kp_status_flag |= KEYSPAN_PORT_RTS;
326560b08185Syz 		} else {
326660b08185Syz 			kp->kp_status_flag &= ~KEYSPAN_PORT_RTS;
326760b08185Syz 		}
326860b08185Syz 	}
326960b08185Syz 	if (ctrl_msg->setDtr) {
327060b08185Syz 		if (ctrl_msg->dtr) {
327160b08185Syz 			kp->kp_status_flag |= KEYSPAN_PORT_DTR;
327260b08185Syz 		} else {
327360b08185Syz 			kp->kp_status_flag &= ~KEYSPAN_PORT_DTR;
327460b08185Syz 		}
327560b08185Syz 	}
327660b08185Syz 
327760b08185Syz 	if (ctrl_msg->enablePort) {
327860b08185Syz 		kp->kp_status_flag |= KEYSPAN_PORT_ENABLE;
327960b08185Syz 	} else {
328060b08185Syz 		kp->kp_status_flag &= ~KEYSPAN_PORT_ENABLE;
328160b08185Syz 	}
328260b08185Syz 
328360b08185Syz 	/*
328460b08185Syz 	 * There are no flags in status msg (49wlc) can indicate the
328560b08185Syz 	 * break status, so we make use of ctrl_msg->txBreak here.
328660b08185Syz 	 */
328760b08185Syz 	if (ctrl_msg->txBreak) {
328860b08185Syz 		kp->kp_status_flag |= KEYSPAN_PORT_TXBREAK;
328960b08185Syz 	} else {
329060b08185Syz 		kp->kp_status_flag &= ~KEYSPAN_PORT_TXBREAK;
329160b08185Syz 	}
329260b08185Syz 
329360b08185Syz 	USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
329460b08185Syz 	    "keyspan_save_port_params: baud = %x, lcr = %x,"
329560b08185Syz 	    "status_flag = %x", kp->kp_baud, kp->kp_lcr, kp->kp_status_flag);
329660b08185Syz 
329760b08185Syz }
3298