Project

General

Profile

Feature #12756 » backup_vendor_1.patch

Jorge Schrauwen, 2020-09-20 12:16 PM

View differences:

usr/src/pkg/manifests/driver-serial-uchcom.mf
1
#
2
# CDDL HEADER START
3
#
4
# The contents of this file are subject to the terms of the
5
# Common Development and Distribution License (the "License").
6
# You may not use this file except in compliance with the License.
7
#
8
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9
# or http://www.opensolaris.org/os/licensing.
10
# See the License for the specific language governing permissions
11
# and limitations under the License.
12
#
13
# When distributing Covered Code, include this CDDL HEADER in each
14
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15
# If applicable, add the following below this CDDL HEADER, with the
16
# fields enclosed by brackets "[]" replaced with your own identifying
17
# information: Portions Copyright [yyyy] [name of copyright owner]
18
#
19
# CDDL HEADER END
20
#
21

  
22
#
23
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24
#
25

  
26
#
27
# The default for payload-bearing actions in this package is to appear in the
28
# global zone only.  See the include file for greater detail, as well as
29
# information about overriding the defaults.
30
#
31
<include global_zone_only_component>
32
set name=pkg.fmri value=pkg:/driver/serial/uchcom@$(PKGVERS)
33
set name=pkg.description value="CH340/CH341 serial driver"
34
set name=pkg.summary value="UCHCOM"
35
set name=info.classification value=org.opensolaris.category.2008:Drivers/Ports
36
set name=variant.arch value=$(ARCH)
37
dir path=kernel group=sys
38
dir path=kernel/drv group=sys
39
dir path=kernel/drv/$(ARCH64) group=sys
40
dir path=usr/share/man
41
dir path=usr/share/man/man7d
42
driver name=usbftdi perms="* 0666 root sys" \
43
    alias=usb1a86,5523 \
44
    alias=usb1a86,7523
45
file path=kernel/drv/$(ARCH64)/uchcom group=sys
46
file path=usr/share/man/man7d/uchcom.7d
47
legacy pkg=SUNWuftdi desc="CH340/CH341 serial driver" \
48
    name="UCHCOM"
49
license cr_Sun license=cr_Sun
50
license lic_CDDL license=lic_CDDL
usr/src/uts/common/Makefile.files
829 829

  
830 830
USBFTDI_OBJS += usbser_uftdi.o uftdi_dsd.o
831 831

  
832
UCHCOM_OBJS += usbser_uchcom.o uchcom_dsd.o
833

  
832 834
USBECM_OBJS += usbecm.o
833 835

  
834 836
WC_OBJS += wscons.o vcons.o
usr/src/uts/common/Makefile.rules
1248 1248
	$(COMPILE.c) -o $@ $<
1249 1249
	$(CTFCONVERT_O)
1250 1250

  
1251
$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/usb/clients/usbser/uchcom/%.c
1252
	$(COMPILE.c) -o $@ $<
1253
	$(CTFCONVERT_O)
1254

  
1251 1255
$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/usb/clients/usbecm/%.c
1252 1256
	$(COMPILE.c) -o $@ $<
1253 1257
	$(CTFCONVERT_O)
......
2541 2545
$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/usb/clients/usbser/usbsprl/%.c
2542 2546
	@($(LHEAD) $(LINT.c) $< $(LTAIL))
2543 2547

  
2548
$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/usb/clients/usbser/uchcom/%.c
2549
	@($(LHEAD) $(LINT.c) $< $(LTAIL))
2550

  
2544 2551
$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/usb/clients/usbecm/%.c
2545 2552
	@($(LHEAD) $(LINT.c) $< $(LTAIL))
2546 2553

  
usr/src/uts/common/io/usb/clients/usbser/uchcom/uchcom_dsd.c
1
/*
2
 * CDDL HEADER START
3
 *
4
 * The contents of this file are subject to the terms of the
5
 * Common Development and Distribution License (the "License").
6
 * You may not use this file except in compliance with the License.
7
 *
8
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9
 * or http://www.opensolaris.org/os/licensing.
10
 * See the License for the specific language governing permissions
11
 * and limitations under the License.
12
 *
13
 * When distributing Covered Code, include this CDDL HEADER in each
14
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15
 * If applicable, add the following below this CDDL HEADER, with the
16
 * fields enclosed by brackets "[]" replaced with your own identifying
17
 * information: Portions Copyright [yyyy] [name of copyright owner]
18
 *
19
 * CDDL HEADER END
20
 */
21

  
22
/*
23
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24
 * Use is subject to license terms.
25
 */
26

  
27
/*
28
 * Copyright 2020 Jorge Schrauwen <sjorge@blackdot.be>
29
 */
30

  
31
/*
32
 * DSD code for WinChipHead CH341/340 adapter
33
 */
34

  
35
#include <sys/types.h>
36
#include <sys/param.h>
37
#include <sys/conf.h>
38
#include <sys/stream.h>
39
#include <sys/strsun.h>
40
#include <sys/termio.h>
41
#include <sys/termiox.h>
42
#include <sys/ddi.h>
43
#include <sys/sunddi.h>
44

  
45
#define	USBDRV_MAJOR_VER	2
46
#define	USBDRV_MINOR_VER	0
47

  
48
#include <sys/usb/usba.h>
49
#include <sys/usb/usba/usba_types.h>
50
#include <sys/usb/usba/usba_impl.h>
51

  
52
#include <sys/usb/clients/usbser/usbser_dsdi.h>
53
#include <sys/usb/clients/usbser/uchcom/uchcom_var.h>
54
#include <sys/usb/clients/usbser/uchcom/uchcom_reg.h>
55

  
56
#include <sys/usb/usbdevs.h>
57

  
58
#include <sys/cmn_err.h>
59

  
60
/*
61
 * DSD operations
62
 */
63
static int	uchcom_attach(ds_attach_info_t *);
64
static void	uchcom_detach(ds_hdl_t);
65
static int	uchcom_register_cb(ds_hdl_t, uint_t, ds_cb_t *);
66
static void	uchcom_unregister_cb(ds_hdl_t, uint_t);
67
static int	uchcom_open_port(ds_hdl_t, uint_t);
68
static int	uchcom_close_port(ds_hdl_t, uint_t);
69

  
70
/* power management */
71
static int	uchcom_usb_power(ds_hdl_t, int, int, int *);
72
static int	uchcom_suspend(ds_hdl_t);
73
static int	uchcom_resume(ds_hdl_t);
74
static int	uchcom_disconnect(ds_hdl_t);
75
static int	uchcom_reconnect(ds_hdl_t);
76

  
77
/* standard UART operations */
78
static int	uchcom_set_port_params(ds_hdl_t, uint_t, ds_port_params_t *);
79
static int	uchcom_set_modem_ctl(ds_hdl_t, uint_t, int, int);
80
static int	uchcom_get_modem_ctl(ds_hdl_t, uint_t, int, int *);
81
static int	uchcom_break_ctl(ds_hdl_t, uint_t, int);
82

  
83
/* data xfer */
84
static int	uchcom_tx(ds_hdl_t, uint_t, mblk_t *);
85
static mblk_t	*uchcom_rx(ds_hdl_t, uint_t);
86
static void	uchcom_stop(ds_hdl_t, uint_t, int);
87
static void	uchcom_start(ds_hdl_t, uint_t, int);
88
static int	uchcom_fifo_flush(ds_hdl_t, uint_t, int);
89
static int	uchcom_fifo_drain(ds_hdl_t, uint_t, int);
90

  
91
/* polled I/O support */
92
static usb_pipe_handle_t uchcom_out_pipe(ds_hdl_t, uint_t);
93
static usb_pipe_handle_t uchcom_in_pipe(ds_hdl_t, uint_t);
94

  
95
/*
96
 * Sub-routines
97
 */
98

  
99
/* configuration routines */
100
static void	uchcom_cleanup(uchcom_state_t *, int);
101
static int	uchcom_dev_attach(uchcom_state_t *);
102
static int	uchcom_open_hw_port(uchcom_state_t *);
103

  
104
/* hotplug */
105
static int	uchcom_restore_device_state(uchcom_state_t *);
106
static int	uchcom_restore_port_state(uchcom_state_t *);
107

  
108
/* power management */
109
static int	uchcom_create_pm_components(uchcom_state_t *);
110
static void	uchcom_destroy_pm_components(uchcom_state_t *);
111
static int	uchcom_pm_set_busy(uchcom_state_t *);
112
static void	uchcom_pm_set_idle(uchcom_state_t *);
113
static int	uchcom_pwrlvl0(uchcom_state_t *);
114
static int	uchcom_pwrlvl1(uchcom_state_t *);
115
static int	uchcom_pwrlvl2(uchcom_state_t *);
116
static int	uchcom_pwrlvl3(uchcom_state_t *);
117

  
118
/* pipe operations */
119
static int	uchcom_open_pipes(uchcom_state_t *);
120
static void	uchcom_close_pipes(uchcom_state_t *);
121
static void	uchcom_disconnect_pipes(uchcom_state_t *);
122
static int	uchcom_reconnect_pipes(uchcom_state_t *);
123

  
124
/* pipe callbacks */
125
static void	uchcom_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
126
static void	uchcom_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
127

  
128
/* data transfer routines */
129
static int	uchcom_rx_start(uchcom_state_t *);
130
static void	uchcom_tx_start(uchcom_state_t *, int *);
131
static int	uchcom_send_data(uchcom_state_t *, mblk_t *);
132
static int	uchcom_wait_tx_drain(uchcom_state_t *, int);
133

  
134
/* vendor-specific commands */
135
static int      uchcom_cmd_vendor_ctrl_write(uchcom_state_t *,
136
		    uint16_t, uint16_t, uint16_t);
137
static int	uchcom_cmd_vendor_ctrl_read(uchcom_state_t *,
138
		    uint16_t, uint16_t, uint16_t, void *, uint16_t);
139
static int	uchcom_cmd_vendor_reg_write(uchcom_state_t *,
140
		    uint8_t, uint8_t, uint8_t, uint8_t);
141
static int	uchcom_cmd_vendor_reg_read(uchcom_state_t *,
142
		    uint8_t, uint8_t *, uint8_t, uint8_t *);
143

  
144
static int	uchcom_cmd_vendor_get_version(uchcom_state_t *,
145
		    uint8_t *);
146
static int	uchcom_cmd_vendor_update_version(uchcom_state_t *);
147
static int	uchcom_cmd_vendor_get_status(uchcom_state_t *,
148
		    uint8_t *);
149
static void	uchcom_cmd_vendor_convert_status(uchcom_state_t *,
150
		    uint8_t);
151
static int	uchcom_cmd_vendor_update_status(uchcom_state_t *);
152
static int	uchcom_cmd_vendor_set_dtr_rts(uchcom_state_t *);
153
static int	uchcom_cmd_vendor_calc_divider_settings(uchcom_state_t *,
154
		    uint32_t);
155
static int	uchcom_cmd_vendor_set_baudrate(uchcom_state_t *,
156
		    uint32_t);
157

  
158
/* misc */
159
static void	uchcom_put_tail(mblk_t **, mblk_t *);
160
static void	uchcom_put_head(mblk_t **, mblk_t *);
161

  
162

  
163
/*
164
 * DSD ops structure
165
 */
166
ds_ops_t uchcom_ds_ops = {
167
	DS_OPS_VERSION,
168
	uchcom_attach,
169
	uchcom_detach,
170
	uchcom_register_cb,
171
	uchcom_unregister_cb,
172
	uchcom_open_port,
173
	uchcom_close_port,
174
	uchcom_usb_power,
175
	uchcom_suspend,
176
	uchcom_resume,
177
	uchcom_disconnect,
178
	uchcom_reconnect,
179
	uchcom_set_port_params,
180
	uchcom_set_modem_ctl,
181
	uchcom_get_modem_ctl,
182
	uchcom_break_ctl,
183
	NULL,			/* no loopback support */
184
	uchcom_tx,
185
	uchcom_rx,
186
	uchcom_stop,
187
	uchcom_start,
188
	uchcom_fifo_flush,
189
	uchcom_fifo_drain,
190
	uchcom_out_pipe,
191
	uchcom_in_pipe
192
};
193

  
194
/* debug support */
195
static uint_t	uchcom_errlevel = USB_LOG_L4;
196
static uint_t	uchcom_errmask = DPRINT_MASK_ALL;
197
static uint_t	uchcom_instance_debug = (uint_t)-1;
198

  
199
/*
200
 * ds_attach
201
 */
202
static int
203
uchcom_attach(ds_attach_info_t *aip)
204
{
205
	uchcom_state_t *uch;
206
	usb_dev_descr_t *dd;
207
	boolean_t recognized;
208

  
209
	uch = kmem_zalloc(sizeof (*uch), KM_SLEEP);
210
	uch->uch_dip = aip->ai_dip;
211
	uch->uch_usb_events = aip->ai_usb_events;
212
	*aip->ai_hdl = (ds_hdl_t)uch;
213

  
214
	/* only one port */
215
	*aip->ai_port_cnt = 1;
216

  
217
	if (usb_client_attach(uch->uch_dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
218
		uchcom_cleanup(uch, 1);
219
		return (USB_FAILURE);
220
	}
221

  
222
	if (usb_get_dev_data(uch->uch_dip,
223
	    &uch->uch_dev_data, USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
224
		uchcom_cleanup(uch, 2);
225
		return (USB_FAILURE);
226
	}
227

  
228
	mutex_init(&uch->uch_lock, NULL, MUTEX_DRIVER,
229
	    uch->uch_dev_data->dev_iblock_cookie);
230

  
231
	cv_init(&uch->uch_tx_cv, NULL, CV_DRIVER, NULL);
232

  
233
	uch->uch_lh = usb_alloc_log_hdl(uch->uch_dip, "uchcom",
234
	    &uchcom_errlevel, &uchcom_errmask, &uchcom_instance_debug, 0);
235

  
236

  
237
	recognized = B_FALSE;
238
	dd = uch->uch_dev_data->dev_descr;
239
	if (dd->idVendor == UCHCOM_VENDOR) {
240
		switch (dd->idProduct) {
241
			case UCHCOM_CHIP_CH340:
242
				USB_DPRINTF_L3(DPRINT_ATTACH, uch->uch_lh,
243
				    "Chip Type: CH340");
244
				cmn_err(CE_NOTE, "Chip Type: CH340");
245
				recognized = B_TRUE;
246
				break;
247
			case UCHCOM_CHIP_CH341:
248
				USB_DPRINTF_L3(DPRINT_ATTACH, uch->uch_lh,
249
				    "Chip Type: CH341");
250
				cmn_err(CE_NOTE, "Chip Type: CH341");
251
				recognized = B_TRUE;
252
				recognized = B_TRUE;
253
				break;
254
		}
255
	}
256

  
257
	if (!recognized) {
258
		uchcom_cleanup(uch, 3);
259
		return (USB_FAILURE);
260
	}
261

  
262
	uch->uch_def_ph = uch->uch_dev_data->dev_default_ph;
263

  
264
	mutex_enter(&uch->uch_lock);
265
	uch->uch_dev_state = USB_DEV_ONLINE;
266
	uch->uch_port_state = UCHCOM_PORT_CLOSED;
267
	mutex_exit(&uch->uch_lock);
268

  
269
	if (uchcom_create_pm_components(uch) != USB_SUCCESS) {
270
		uchcom_cleanup(uch, 3);
271
		return (USB_FAILURE);
272
	}
273

  
274
	if (usb_register_event_cbs(uch->uch_dip,
275
	    uch->uch_usb_events, 0) != USB_SUCCESS) {
276
		uchcom_cleanup(uch, 4);
277
		return (USB_FAILURE);
278
	}
279

  
280
	if (uchcom_dev_attach(uch) != USB_SUCCESS) {
281
		uchcom_cleanup(uch, 5);
282
		return (USB_FAILURE);
283
	}
284

  
285
	if (uchcom_cmd_vendor_update_version(uch) != USB_SUCCESS) {
286
		uchcom_cleanup(uch, 6);
287
		return (USB_FAILURE);
288
	}
289

  
290
	return (USB_SUCCESS);
291
}
292

  
293
/*
294
 * ds_detach
295
 */
296
static void
297
uchcom_detach(ds_hdl_t hdl)
298
{
299
	uchcom_cleanup((uchcom_state_t *)hdl, UCHCOM_CLEANUP_LEVEL_MAX);
300
}
301

  
302
/*
303
 * ds_register_cb
304
 */
305
/*ARGSUSED*/
306
static int
307
uchcom_register_cb(ds_hdl_t hdl, uint_t portno, ds_cb_t *cb)
308
{
309
	uchcom_state_t *uch = (uchcom_state_t *)hdl;
310

  
311
	ASSERT(portno == 0);
312

  
313
	uch->uch_cb = *cb;
314
	return (USB_SUCCESS);
315
}
316

  
317
/*
318
 * ds_unregister_cb
319
 */
320
/*ARGSUSED*/
321
static void
322
uchcom_unregister_cb(ds_hdl_t hdl, uint_t portno)
323
{
324
	uchcom_state_t *uch = (uchcom_state_t *)hdl;
325

  
326
	ASSERT(portno == 0);
327

  
328
	bzero(&uch->uch_cb, sizeof (uch->uch_cb));
329
}
330

  
331
/*
332
 * ds_open_port
333
 */
334
/*ARGSUSED*/
335
static int
336
uchcom_open_port(ds_hdl_t hdl, uint_t portno)
337
{
338
	uchcom_state_t *uch = (uchcom_state_t *)hdl;
339
	int rval;
340

  
341
	USB_DPRINTF_L4(DPRINT_OPEN, uch->uch_lh, "uchcom_open_port %d", portno);
342

  
343
	mutex_enter(&uch->uch_lock);
344
	if (uch->uch_dev_state == USB_DEV_DISCONNECTED ||
345
	    uch->uch_port_state != UCHCOM_PORT_CLOSED) {
346
		mutex_exit(&uch->uch_lock);
347
		return (USB_FAILURE);
348
	}
349
	mutex_exit(&uch->uch_lock);
350

  
351
	if ((rval = uchcom_pm_set_busy(uch)) != USB_SUCCESS)
352
		return (rval);
353

  
354
	/* initialize hardware serial port */
355
	rval = uchcom_open_hw_port(uch);
356

  
357
	if (rval == USB_SUCCESS) {
358
		mutex_enter(&uch->uch_lock);
359

  
360
		/* start to receive data */
361
		if (uchcom_rx_start(uch) != USB_SUCCESS) {
362
			mutex_exit(&uch->uch_lock);
363
			return (USB_FAILURE);
364
		}
365
		uch->uch_port_state = UCHCOM_PORT_OPEN;
366
		mutex_exit(&uch->uch_lock);
367
	} else
368
		uchcom_pm_set_idle(uch);
369

  
370
	return (rval);
371
}
372

  
373
/*
374
 * ds_close_port
375
 */
376
/*ARGSUSED*/
377
static int
378
uchcom_close_port(ds_hdl_t hdl, uint_t portno)
379
{
380
	uchcom_state_t *uch = (uchcom_state_t *)hdl;
381

  
382
	USB_DPRINTF_L4(DPRINT_CLOSE, uch->uch_lh, "uchcom_close_port %d", portno);
383

  
384
	mutex_enter(&uch->uch_lock);
385

  
386
	/* free resources and finalize state */
387
	freemsg(uch->uch_rx_mp);
388
	uch->uch_rx_mp = NULL;
389

  
390
	freemsg(uch->uch_tx_mp);
391
	uch->uch_tx_mp = NULL;
392

  
393
	uch->uch_port_state = UCHCOM_PORT_CLOSED;
394
	mutex_exit(&uch->uch_lock);
395

  
396
	uchcom_pm_set_idle(uch);
397

  
398
	return (USB_SUCCESS);
399
}
400

  
401
/*
402
 * ds_usb_power
403
 */
404
/*ARGSUSED*/
405
static int
406
uchcom_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state)
407
{
408
	uchcom_state_t	*uch = (uchcom_state_t *)hdl;
409
	uchcom_pm_t	*pm = uch->uch_pm;
410
	int		rval;
411

  
412
	USB_DPRINTF_L4(DPRINT_PM, uch->uch_lh, "uchcom_usb_power");
413

  
414
	if (!pm)
415
		return (USB_FAILURE);
416

  
417
	mutex_enter(&uch->uch_lock);
418

  
419
	/*
420
	 * check if we are transitioning to a legal power level
421
	 */
422
	if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) {
423
		USB_DPRINTF_L2(DPRINT_PM, uch->uch_lh, "uchcom_usb_power: "
424
		    "illegal power level %d, pwr_states=0x%x",
425
		    level, pm->pm_pwr_states);
426
		mutex_exit(&uch->uch_lock);
427
		return (USB_FAILURE);
428
	}
429

  
430
	/*
431
	 * if we are about to raise power and asked to lower power, fail
432
	 */
433
	if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
434
		mutex_exit(&uch->uch_lock);
435
		return (USB_FAILURE);
436
	}
437

  
438
	switch (level) {
439
	case USB_DEV_OS_PWR_OFF:
440
		rval = uchcom_pwrlvl0(uch);
441
		break;
442
	case USB_DEV_OS_PWR_1:
443
		rval = uchcom_pwrlvl1(uch);
444
		break;
445
	case USB_DEV_OS_PWR_2:
446
		rval = uchcom_pwrlvl2(uch);
447
		break;
448
	case USB_DEV_OS_FULL_PWR:
449
		rval = uchcom_pwrlvl3(uch);
450
		/*
451
		 * If usbser dev_state is DISCONNECTED or SUSPENDED, it shows
452
		 * that the usb serial device is disconnected/suspended while it
453
		 * is under power down state, now the device is powered up
454
		 * before it is reconnected/resumed. xxx_pwrlvl3() will set dev
455
		 * state to ONLINE, we need to set the dev state back to
456
		 * DISCONNECTED/SUSPENDED.
457
		 */
458
		if (rval == USB_SUCCESS &&
459
		    (*new_state == USB_DEV_DISCONNECTED ||
460
		    *new_state == USB_DEV_SUSPENDED))
461
			uch->uch_dev_state = *new_state;
462
		break;
463
	default:
464
		ASSERT(0);      /* cannot happen */
465
	}
466

  
467
	*new_state = uch->uch_dev_state;
468
	mutex_exit(&uch->uch_lock);
469

  
470
	return (rval);
471
}
472

  
473
/*
474
 * ds_suspend
475
 */
476
static int
477
uchcom_suspend(ds_hdl_t hdl)
478
{
479
	uchcom_state_t	*uch = (uchcom_state_t *)hdl;
480
	int		state = USB_DEV_SUSPENDED;
481

  
482
	USB_DPRINTF_L4(DPRINT_PM, uch->uch_lh, "uchcom_suspend");
483

  
484
	/*
485
	 * If the device is suspended while it is under PWRED_DOWN state, we
486
	 * need to keep the PWRED_DOWN state so that it could be powered up
487
	 * later. In the mean while, usbser dev state will be changed to
488
	 * SUSPENDED state.
489
	 */
490
	mutex_enter(&uch->uch_lock);
491
	if (uch->uch_dev_state != USB_DEV_PWRED_DOWN)
492
		uch->uch_dev_state = USB_DEV_SUSPENDED;
493
	mutex_exit(&uch->uch_lock);
494

  
495
	uchcom_disconnect_pipes(uch);
496
	return (state);
497
}
498

  
499
/*
500
 * ds_resume
501
 */
502
static int
503
uchcom_resume(ds_hdl_t hdl)
504
{
505
	uchcom_state_t	*uch = (uchcom_state_t *)hdl;
506
	int		current_state;
507

  
508
	USB_DPRINTF_L4(DPRINT_PM, uch->uch_lh, "uchcom_resume");
509

  
510
	mutex_enter(&uch->uch_lock);
511
	current_state = uch->uch_dev_state;
512
	mutex_exit(&uch->uch_lock);
513

  
514
	if (current_state == USB_DEV_ONLINE)
515
		return (USB_SUCCESS);
516

  
517
	return (uchcom_restore_device_state(uch));
518
}
519

  
520
/*
521
 * ds_disconnect
522
 */
523
static int
524
uchcom_disconnect(ds_hdl_t hdl)
525
{
526
	uchcom_state_t	*uch = (uchcom_state_t *)hdl;
527
	int		state = USB_DEV_DISCONNECTED;
528

  
529
	USB_DPRINTF_L4(DPRINT_HOTPLUG, uch->uch_lh, "uchcom_disconnect");
530

  
531
	/*
532
	 * If the device is disconnected while it is under PWRED_DOWN state, we
533
	 * need to keep the PWRED_DOWN state so that it could be powered up
534
	 * later. In the mean while, usbser dev state will be changed to
535
	 * DISCONNECTED state.
536
	 */
537
	mutex_enter(&uch->uch_lock);
538
	if (uch->uch_dev_state != USB_DEV_PWRED_DOWN)
539
		uch->uch_dev_state = USB_DEV_DISCONNECTED;
540
	mutex_exit(&uch->uch_lock);
541

  
542
	uchcom_disconnect_pipes(uch);
543

  
544
	return (state);
545
}
546

  
547
/*
548
 * ds_reconnect
549
 */
550
static int
551
uchcom_reconnect(ds_hdl_t hdl)
552
{
553
	uchcom_state_t *uch = (uchcom_state_t *)hdl;
554

  
555
	USB_DPRINTF_L4(DPRINT_HOTPLUG, uch->uch_lh, "uchcom_reconnect");
556

  
557
	return (uchcom_restore_device_state(uch));
558
}
559

  
560
/*
561
 * ds_set_port_params
562
 */
563
static int
564
uchcom_set_port_params(ds_hdl_t hdl, uint_t portno, ds_port_params_t *tp)
565
{
566
	uchcom_state_t		*uch = (uchcom_state_t *)hdl;
567
	int			rval;
568
	int			i;
569
	ds_port_param_entry_t	*pe;
570

  
571
	if (tp == NULL)
572
		return (USB_FAILURE);
573

  
574
	USB_DPRINTF_L4(DPRINT_CTLOP, uch->uch_lh, "uchcom_set_port_params");
575

  
576
	// clear configuration
577
	rval = uchcom_cmd_vendor_ctrl_write(uch, UCHCOM_REQ_RESET, 0, 0);
578
        if (rval != USB_SUCCESS) {
579
                USB_DPRINTF_L2(DPRINT_DEF_PIPE, uch->uch_lh,
580
                    "uchcom_set_port_params: failed to reset!");
581
                return (rval);
582
        }
583

  
584
	// configure
585
        for (i = 0, pe = tp->tp_entries; i < tp->tp_cnt; i++, pe++) {
586
                switch (pe->param) {
587
                case DS_PARAM_BAUD:
588
                        switch (pe->val.ui) {
589
                        case B300:
590
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 300");
591
                                break;
592
                        case B600:
593
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 600");
594
                                break;
595
                        case B1200:
596
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 1200");
597
                                break;
598
                        case B2400:
599
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 2400");
600
                                break;
601
                        case B4800:
602
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 4800");
603
                                break;
604
                        case B9600:
605
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 9400");
606
                                break;
607
                        case B19200:
608
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 19200");
609
                                break;
610
                        case B38400:
611
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 38400");
612
                                break;
613
                        case B57600:
614
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 57600");
615
                                break;
616
                        case B115200:
617
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 115200");
618
                                break;
619
                        case B230400:
620
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 230400");
621
                                break;
622
                        case B460800:
623
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 460800");
624
                                break;
625
                        case B921600:
626
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params br 921600");
627
                                break;
628
                        default:
629
                                USB_DPRINTF_L3(DPRINT_CTLOP, uch->uch_lh,
630
                                    "uchcom_set_port_params: bad baud %d",
631
                                    pe->val.ui);
632
                                return (USB_FAILURE);
633
                        }
634
                        break;
635

  
636
                case DS_PARAM_PARITY:
637
                        if (pe->val.ui & PARENB) {
638
                                if (pe->val.ui & PARODD)
639
					cmn_err(CE_WARN, "XXX: uchcom_set_port_params par odd");
640
                                else
641
					cmn_err(CE_WARN, "XXX: uchcom_set_port_params par even");
642
                        } else {
643
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params par none");
644
                        }
645
                        break;
646

  
647
                case DS_PARAM_STOPB:
648
                        if (pe->val.ui & CSTOPB)
649
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params stop bits2");
650
                        else {
651
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params stop bits1");
652
                        }
653
                        break;
654

  
655
                case DS_PARAM_CHARSZ:
656
                        switch (pe->val.ui) {
657
                        case CS8:
658
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params csz cs8");
659
                                break;
660
                        default:
661
                                USB_DPRINTF_L3(DPRINT_CTLOP, uch->uch_lh,
662
                                    "uchcom_set_port_params: bad charsz");
663
                                return (USB_FAILURE);
664
                        }
665
                        break;
666

  
667
                case DS_PARAM_XON_XOFF:         /* Software flow control */
668
                        if ((pe->val.ui & IXON) || (pe->val.ui & IXOFF)) {
669
                                uint8_t xonc = pe->val.uc[0];
670
                                uint8_t xoffc = pe->val.uc[1];
671

  
672
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params soft flow ???");
673
                        }
674
                        break;
675

  
676
                case DS_PARAM_FLOW_CTL:         /* Hardware flow control */
677
                        if (pe->val.ui & (RTSXOFF | CTSXON)) {
678
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params hard flow RTS_CTS_HS");
679
                        }
680
                        if (pe->val.ui & DTRXOFF) {
681
				cmn_err(CE_WARN, "XXX: uchcom_set_port_params hard flow DTR_DSR_HS");
682
                        }
683
                        break;
684
                default:
685
                        USB_DPRINTF_L2(DPRINT_CTLOP, uch->uch_lh,
686
                            "uchcom_set_port_params: bad param %d", pe->param);
687
                        break;
688
                }
689
        }
690

  
691
	return (USB_SUCCESS);
692
}
693

  
694
/*
695
 * ds_set_modem_ctl
696
 */
697
static int
698
uchcom_set_modem_ctl(ds_hdl_t hdl, uint_t portno, int mask, int val)
699
{
700
	uchcom_state_t	*uch = (uchcom_state_t *)hdl;
701

  
702
	USB_DPRINTF_L4(DPRINT_CTLOP, uch->uch_lh, "uchcom_set_modem_ctl");
703

  
704
	// XXX: chip is weird and picky, figure out later
705
	cmn_err(CE_WARN, "XXX: uchcom_set_modem_ctl");
706

  
707
	return (USB_SUCCESS);
708
}
709

  
710
/*
711
 * ds_get_modem_ctl
712
 */
713
static int
714
uchcom_get_modem_ctl(ds_hdl_t hdl, uint_t portno, int mask, int *valp)
715
{
716
	uchcom_state_t	*uch = (uchcom_state_t *)hdl;
717

  
718
	USB_DPRINTF_L4(DPRINT_CTLOP, uch->uch_lh, "uchcom_get_modem_ctl");
719

  
720
	// XXX: chip is weird and picky, figure out later
721
	cmn_err(CE_WARN, "XXX: uchcom_get_modem_ctl");
722

  
723
	return (USB_SUCCESS);
724
}
725

  
726
/*
727
 * ds_break_ctl
728
 */
729
static int
730
uchcom_break_ctl(ds_hdl_t hdl, uint_t portno, int ctl)
731
{
732
	uchcom_state_t	*uch = (uchcom_state_t *)hdl;
733

  
734
	USB_DPRINTF_L4(DPRINT_CTLOP, uch->uch_lh, "uchcom_break_ctl");
735

  
736
	// XXX: chip is weird and picky, figure out later
737
	cmn_err(CE_WARN, "XXX: uchcom_break_ctl");
738

  
739
	return (USB_SUCCESS);
740
}
741

  
742
/*
743
 * ds_tx
744
 */
745
/*ARGSUSED*/
746
static int
747
uchcom_tx(ds_hdl_t hdl, uint_t portno, mblk_t *mp)
748
{
749
	uchcom_state_t *uch = (uchcom_state_t *)hdl;
750

  
751
	USB_DPRINTF_L4(DPRINT_CTLOP, uch->uch_lh, "uchcom_tx");
752

  
753
	ASSERT(mp != NULL && MBLKL(mp) >= 1);
754

  
755
	mutex_enter(&uch->uch_lock);
756
	uchcom_put_tail(&uch->uch_tx_mp, mp);      /* add to the chain */
757
	uchcom_tx_start(uch, NULL);
758
	mutex_exit(&uch->uch_lock);
759

  
760
	return (USB_SUCCESS);
761
}
762

  
763

  
764
/*
765
 * ds_rx
766
 */
767
/*ARGSUSED*/
768
static mblk_t *
769
uchcom_rx(ds_hdl_t hdl, uint_t portno)
770
{
771
	uchcom_state_t *uch = (uchcom_state_t *)hdl;
772
	mblk_t *mp;
773

  
774
	USB_DPRINTF_L4(DPRINT_CTLOP, uch->uch_lh, "uchcom_rx");
775

  
776
	mutex_enter(&uch->uch_lock);
777
	mp = uch->uch_rx_mp;
778
	uch->uch_rx_mp = NULL;
779
	mutex_exit(&uch->uch_lock);
780

  
781
	return (mp);
782
}
783

  
784
/*
785
 * ds_stop
786
 */
787
/*ARGSUSED*/
788
static void
789
uchcom_stop(ds_hdl_t hdl, uint_t portno, int dir)
790
{
791
	uchcom_state_t *uch = (uchcom_state_t *)hdl;
792

  
793
	USB_DPRINTF_L4(DPRINT_CTLOP, uch->uch_lh, "uchcom_stop");
794

  
795
	if (dir & DS_TX) {
796
		mutex_enter(&uch->uch_lock);
797
		uch->uch_port_flags |= UCHCOM_PORT_TX_STOPPED;
798
		mutex_exit(&uch->uch_lock);
799
	}
800
}
801

  
802

  
803
/*
804
 * ds_start
805
 */
806
/*ARGSUSED*/
807
static void
808
uchcom_start(ds_hdl_t hdl, uint_t portno, int dir)
809
{
810
	uchcom_state_t *uch = (uchcom_state_t *)hdl;
811

  
812
	USB_DPRINTF_L4(DPRINT_CTLOP, uch->uch_lh, "uchcom_start");
813

  
814
	if (dir & DS_TX) {
815
		mutex_enter(&uch->uch_lock);
816
		if (uch->uch_port_flags & UCHCOM_PORT_TX_STOPPED) {
817
			uch->uch_port_flags &= ~UCHCOM_PORT_TX_STOPPED;
818
			uchcom_tx_start(uch, NULL);
819
		}
820
		mutex_exit(&uch->uch_lock);
821
	}
822
}
823

  
824
/*
825
 * ds_fifo_flush
826
 */
827
/*ARGSUSED*/
828
static int
829
uchcom_fifo_flush(ds_hdl_t hdl, uint_t portno, int dir)
830
{
831
	uchcom_state_t *uch = (uchcom_state_t *)hdl;
832

  
833
	USB_DPRINTF_L4(DPRINT_CTLOP, uch->uch_lh,
834
	    "uchcom_fifo_flush: dir=0x%x", dir);
835

  
836
	mutex_enter(&uch->uch_lock);
837
	ASSERT(uch->uch_port_state == UCHCOM_PORT_OPEN);
838

  
839
	if (dir & DS_TX) {
840
		freemsg(uch->uch_tx_mp);
841
		uch->uch_tx_mp = NULL;
842
	}
843

  
844
	if (dir & DS_RX) {
845
		freemsg(uch->uch_rx_mp);
846
		uch->uch_rx_mp = NULL;
847
	}
848
	mutex_exit(&uch->uch_lock);
849

  
850
	return (USB_SUCCESS);
851
}
852

  
853
/*
854
 * ds_fifo_drain
855
 */
856
/*ARGSUSED*/
857
static int
858
uchcom_fifo_drain(ds_hdl_t hdl, uint_t portno, int timeout)
859
{
860
	uchcom_state_t *uch = (uchcom_state_t *)hdl;
861

  
862
	USB_DPRINTF_L4(DPRINT_CTLOP, uch->uch_lh, "uchcom_fifo_drain");
863

  
864
	mutex_enter(&uch->uch_lock);
865
	ASSERT(uch->uch_port_state == UCHCOM_PORT_OPEN);
866

  
867
	if (uchcom_wait_tx_drain(uch, 0) != USB_SUCCESS) {
868
		mutex_exit(&uch->uch_lock);
869
		return (USB_FAILURE);
870
	}
871

  
872
	mutex_exit(&uch->uch_lock);
873

  
874
	/* wait 500 ms until hw fifo drains */
875
	delay(drv_usectohz(500*1000));
876

  
877
	return (USB_SUCCESS);
878
}
879

  
880
/*ARGSUSED*/
881
static usb_pipe_handle_t
882
uchcom_out_pipe(ds_hdl_t hdl, uint_t port_num)
883
{
884
	uchcom_state_t	*uch = (uchcom_state_t *)hdl;
885

  
886
	return (uch->uch_bulkout_ph);
887
}
888

  
889
/*ARGSUSED*/
890
static usb_pipe_handle_t
891
uchcom_in_pipe(ds_hdl_t hdl, uint_t port_num)
892
{
893
	uchcom_state_t  *uch = (uchcom_state_t *)hdl;
894

  
895
	return (uch->uch_bulkin_ph);
896
}
897

  
898
/*
899
 * configuration clean up
900
 */
901
static void
902
uchcom_cleanup(uchcom_state_t *uch, int level)
903
{
904
	ASSERT(level > 0 && level <= UCHCOM_CLEANUP_LEVEL_MAX);
905

  
906
	switch (level) {
907
	default:
908
	case 6:
909
		uchcom_close_pipes(uch);
910
		/*FALLTHROUGH*/
911
	case 5:
912
		usb_unregister_event_cbs(uch->uch_dip, uch->uch_usb_events);
913
		/*FALLTHROUGH*/
914
	case 4:
915
		 uchcom_destroy_pm_components(uch);
916
		/*FALLTHROUGH*/
917
	case 3:
918
		mutex_destroy(&uch->uch_lock);
919
		cv_destroy(&uch->uch_tx_cv);
920

  
921
		usb_free_log_hdl(uch->uch_lh);
922
		uch->uch_lh = NULL;
923

  
924
		usb_free_descr_tree(uch->uch_dip, uch->uch_dev_data);
925
		uch->uch_def_ph = NULL;
926
		/*FALLTHROUGH*/
927
	case 2:
928
		usb_client_detach(uch->uch_dip, uch->uch_dev_data);
929
		/*FALLTHROUGH*/
930
	case 1:
931
		kmem_free(uch, sizeof (*uch));
932
		break;
933
	}
934
}
935

  
936
/*
937
 * device specific attach
938
 */
939
static int
940
uchcom_dev_attach(uchcom_state_t *uch)
941
{
942
	return (uchcom_open_pipes(uch));
943
}
944

  
945
static int
946
uchcom_open_hw_port(uchcom_state_t *uch)
947
{
948
	int rval;
949

  
950
	// initialize device with defaults
951
	rval = uchcom_cmd_vendor_ctrl_write(uch, UCHCOM_REQ_RESET,
952
	    UCHCOM_RESET_VALUE, UCHCOM_RESET_INDEX);
953
	if (rval != USB_SUCCESS) {
954
		USB_DPRINTF_L2(DPRINT_DEF_PIPE, uch->uch_lh,
955
		    "uchcom_open_hw_port: failed to reset!");
956
	}
957

  
958
	return (rval);
959
}
960

  
961
/*
962
 * restore device state after CPR resume or reconnect
963
 */
964
static int
965
uchcom_restore_device_state(uchcom_state_t *uch)
966
{
967
	int state;
968

  
969
	mutex_enter(&uch->uch_lock);
970
	state = uch->uch_dev_state;
971
	mutex_exit(&uch->uch_lock);
972

  
973
	if (state != USB_DEV_DISCONNECTED && state != USB_DEV_SUSPENDED)
974
		return (state);
975

  
976
	if (usb_check_same_device(uch->uch_dip, uch->uch_lh, USB_LOG_L0,
977
	    DPRINT_MASK_ALL, USB_CHK_ALL, NULL) != USB_SUCCESS) {
978
		mutex_enter(&uch->uch_lock);
979
		state = uch->uch_dev_state = USB_DEV_DISCONNECTED;
980
		mutex_exit(&uch->uch_lock);
981
		return (state);
982
	}
983

  
984
	if (state == USB_DEV_DISCONNECTED) {
985
		USB_DPRINTF_L0(DPRINT_HOTPLUG, uch->uch_lh,
986
		    "Device has been reconnected but data may have been lost");
987
	}
988

  
989
	if (uchcom_reconnect_pipes(uch) != USB_SUCCESS)
990
		return (state);
991

  
992
	/*
993
	 * init device state
994
	 */
995
	mutex_enter(&uch->uch_lock);
996
	state = uch->uch_dev_state = USB_DEV_ONLINE;
997
	mutex_exit(&uch->uch_lock);
998

  
999
	if ((uchcom_restore_port_state(uch) != USB_SUCCESS)) {
1000
		USB_DPRINTF_L2(DPRINT_HOTPLUG, uch->uch_lh,
1001
		    "uchcom_restore_device_state: failed");
1002
	}
1003

  
1004
	return (state);
1005
}
1006

  
1007
/*
1008
 * restore ports state after CPR resume or reconnect
1009
 */
1010
static int
1011
uchcom_restore_port_state(uchcom_state_t *uch)
1012
{
1013
	int rval;
1014

  
1015
	mutex_enter(&uch->uch_lock);
1016
	if (uch->uch_port_state != UCHCOM_PORT_OPEN) {
1017
		mutex_exit(&uch->uch_lock);
1018
		return (USB_SUCCESS);
1019
	}
1020
	mutex_exit(&uch->uch_lock);
1021

  
1022
	/* open hardware serial port, restoring old settings */
1023
	if ((rval = uchcom_open_hw_port(uch)) != USB_SUCCESS) {
1024
		USB_DPRINTF_L2(DPRINT_HOTPLUG, uch->uch_lh,
1025
		    "uchcom_restore_port_state: failed");
1026
	}
1027

  
1028
	return (rval);
1029
}
1030

  
1031
/*
1032
 * create PM components
1033
 */
1034
static int
1035
uchcom_create_pm_components(uchcom_state_t *uch)
1036
{
1037
	dev_info_t	*dip = uch->uch_dip;
1038
	uchcom_pm_t	*pm;
1039
	uint_t		pwr_states;
1040

  
1041
	if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
1042
		USB_DPRINTF_L2(DPRINT_PM, uch->uch_lh,
1043
		    "uchcom_create_pm_components: failed");
1044
		return (USB_SUCCESS);
1045
	}
1046

  
1047
	pm = uch->uch_pm = kmem_zalloc(sizeof (*pm), KM_SLEEP);
1048

  
1049
	pm->pm_pwr_states = (uint8_t)pwr_states;
1050
	pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
1051
	pm->pm_wakeup_enabled = usb_handle_remote_wakeup(dip,
1052
	    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS;
1053

  
1054
	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1055

  
1056
	return (USB_SUCCESS);
1057
}
1058

  
1059
/*
1060
 * destroy PM components
1061
 */
1062
static void
1063
uchcom_destroy_pm_components(uchcom_state_t *uch)
1064
{
1065
	uchcom_pm_t *pm = uch->uch_pm;
1066
	dev_info_t *dip = uch->uch_dip;
1067
	int rval;
1068

  
1069
	if (!pm)
1070
		return;
1071

  
1072
	if (uch->uch_dev_state != USB_DEV_DISCONNECTED) {
1073
		if (pm->pm_wakeup_enabled) {
1074
			rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1075
			if (rval != DDI_SUCCESS)
1076
				USB_DPRINTF_L2(DPRINT_PM, uch->uch_lh,
1077
				    "uchcom_destroy_pm_components: "
1078
				    "raising power failed, rval=%d", rval);
1079

  
1080
			rval = usb_handle_remote_wakeup(dip,
1081
			    USB_REMOTE_WAKEUP_DISABLE);
1082

  
1083
			if (rval != USB_SUCCESS)
1084
				USB_DPRINTF_L2(DPRINT_PM, uch->uch_lh,
1085
				    "uchcom_destroy_pm_components: disable "
1086
				    "remote wakeup failed, rval=%d", rval);
1087
		}
1088
		(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
1089
	}
1090
	kmem_free(pm, sizeof (*pm));
1091
	uch->uch_pm = NULL;
1092
}
1093

  
1094
/*
1095
 * mark device busy and raise power
1096
 */
1097
static int
1098
uchcom_pm_set_busy(uchcom_state_t *uch)
1099
{
1100
	uchcom_pm_t	*pm = uch->uch_pm;
1101
	dev_info_t	*dip = uch->uch_dip;
1102
	int		rval;
1103

  
1104
	USB_DPRINTF_L4(DPRINT_PM, uch->uch_lh, "uchcom_pm_set_busy");
1105

  
1106
	if (!pm)
1107
		return (USB_SUCCESS);
1108

  
1109
	mutex_enter(&uch->uch_lock);
1110
	/* if already marked busy, just increment the counter */
1111
	if (pm->pm_busy_cnt++ > 0) {
1112
		mutex_exit(&uch->uch_lock);
1113
		return (USB_SUCCESS);
1114
	}
1115

  
1116
	rval = pm_busy_component(dip, 0);
1117
	ASSERT(rval == DDI_SUCCESS);
1118

  
1119
	if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
1120
		mutex_exit(&uch->uch_lock);
1121
		return (USB_SUCCESS);
1122
	}
1123

  
1124
	/* need to raise power  */
1125
	pm->pm_raise_power = B_TRUE;
1126
	mutex_exit(&uch->uch_lock);
1127

  
1128
	rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1129
	if (rval != DDI_SUCCESS)
1130
		USB_DPRINTF_L2(DPRINT_PM, uch->uch_lh, "raising power failed");
1131

  
1132
	mutex_enter(&uch->uch_lock);
1133
	pm->pm_raise_power = B_FALSE;
1134
	mutex_exit(&uch->uch_lock);
1135

  
1136
	return (USB_SUCCESS);
1137
}
1138

  
1139
/*
1140
 * mark device idle
1141
 */
1142
static void
1143
uchcom_pm_set_idle(uchcom_state_t *uch)
1144
{
1145
	uchcom_pm_t     *pm = uch->uch_pm;
1146
	dev_info_t      *dip = uch->uch_dip;
1147

  
1148
	USB_DPRINTF_L4(DPRINT_PM, uch->uch_lh, "uchcom_pm_set_idle");
1149

  
1150
	if (!pm)
1151
		return;
1152

  
1153
	/*
1154
	 * if more ports use the device, do not mark as yet
1155
	 */
1156
	mutex_enter(&uch->uch_lock);
1157
	if (--pm->pm_busy_cnt > 0) {
1158
		mutex_exit(&uch->uch_lock);
1159
		return;
1160
	}
1161

  
1162
	if (pm)
1163
		(void) pm_idle_component(dip, 0);
1164

  
1165
	mutex_exit(&uch->uch_lock);
1166
}
1167

  
1168
/*
1169
 * Functions to handle power transition for OS levels 0 -> 3
1170
 * The same level as OS state, different from USB state
1171
 */
1172
static int
1173
uchcom_pwrlvl0(uchcom_state_t *uch)
1174
{
1175
	int     rval;
1176

  
1177
	USB_DPRINTF_L4(DPRINT_PM, uch->uch_lh, "uchcom_pwrlvl0");
1178

  
1179
	switch (uch->uch_dev_state) {
1180
	case USB_DEV_ONLINE:
1181
		/* issue USB D3 command to the device */
1182
		rval = usb_set_device_pwrlvl3(uch->uch_dip);
1183
		ASSERT(rval == USB_SUCCESS);
1184

  
1185
		uch->uch_dev_state = USB_DEV_PWRED_DOWN;
1186
		uch->uch_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
1187

  
1188
		/* FALLTHRU */
1189
	case USB_DEV_DISCONNECTED:
1190
	case USB_DEV_SUSPENDED:
1191
		/* allow a disconnect/cpr'ed device to go to lower power */
1192

  
1193
		return (USB_SUCCESS);
1194
	case USB_DEV_PWRED_DOWN:
1195
	default:
1196
		USB_DPRINTF_L2(DPRINT_PM, uch->uch_lh,
1197
		    "uchcom_pwrlvl0: illegal device state");
1198

  
1199
		return (USB_FAILURE);
1200
	}
1201
}
1202

  
1203
static int
1204
uchcom_pwrlvl1(uchcom_state_t *uch)
1205
{
1206
	USB_DPRINTF_L4(DPRINT_PM, uch->uch_lh, "uchcom_pwrlvl1");
1207

  
1208
	/* issue USB D2 command to the device */
1209
	(void) usb_set_device_pwrlvl2(uch->uch_dip);
1210

  
1211
	return (USB_FAILURE);
1212
}
1213

  
1214

  
1215
static int
1216
uchcom_pwrlvl2(uchcom_state_t *uch)
1217
{
1218
	USB_DPRINTF_L4(DPRINT_PM, uch->uch_lh, "uchcom_pwrlvl2");
1219

  
1220
	/* issue USB D1 command to the device */
1221
	(void) usb_set_device_pwrlvl1(uch->uch_dip);
1222

  
1223
	return (USB_FAILURE);
1224
}
1225

  
1226

  
1227
static int
1228
uchcom_pwrlvl3(uchcom_state_t *uch)
1229
{
1230
	int     rval;
1231

  
1232
	USB_DPRINTF_L4(DPRINT_PM, uch->uch_lh, "uchcom_pwrlvl3");
1233

  
1234
	switch (uch->uch_dev_state) {
1235
	case USB_DEV_PWRED_DOWN:
1236
		/* Issue USB D0 command to the device here */
1237
		rval = usb_set_device_pwrlvl0(uch->uch_dip);
1238
		ASSERT(rval == USB_SUCCESS);
1239

  
1240
		uch->uch_dev_state = USB_DEV_ONLINE;
1241
		uch->uch_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
1242

  
1243
		/* FALLTHRU */
1244
	case USB_DEV_ONLINE:
1245
		/* we are already in full power */
1246

  
1247
		/* FALLTHRU */
1248
	case USB_DEV_DISCONNECTED:
1249
	case USB_DEV_SUSPENDED:
1250

  
1251
		return (USB_SUCCESS);
1252
	default:
1253
		USB_DPRINTF_L2(DPRINT_PM, uch->uch_lh,
1254
		    "uchcom_pwrlvl3: illegal device state");
1255

  
1256
		return (USB_FAILURE);
1257
	}
1258
}
1259

  
1260
/*
1261
 * pipe operations
1262
 */
1263
static int
1264
uchcom_open_pipes(uchcom_state_t *uch)
1265
{
1266
	int			ifc, alt;
1267
	usb_pipe_policy_t	policy;
1268
	usb_ep_data_t		*in_data, *out_data;
1269
	size_t			max_xfer_sz;
1270

  
1271
	/* get ep data */
1272
	ifc = uch->uch_dev_data->dev_curr_if;
1273
	alt = 0;
1274

  
1275
	in_data = usb_lookup_ep_data(uch->uch_dip, uch->uch_dev_data, ifc, alt,
1276
	    0, USB_EP_ATTR_BULK, USB_EP_DIR_IN);
1277

  
1278
	out_data = usb_lookup_ep_data(uch->uch_dip, uch->uch_dev_data, ifc, alt,
1279
	    0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
1280

  
1281
	if ((in_data == NULL) || (out_data == NULL)) {
1282
		USB_DPRINTF_L2(DPRINT_ATTACH, uch->uch_lh,
1283
		    "uchcom_open_pipes: can't get ep data");
1284

  
1285
		return (USB_FAILURE);
1286
	}
1287

  
1288
        /*
1289
         * Set buffer sizes. Default to UCHCOM_XFER_SZ_MAX.
1290
         * Use wMaxPacketSize from endpoint descriptor if it is nonzero.
1291
         * Cap at a max transfer size of host controller.
1292
         */
1293
        uch->uch_ibuf_sz = uch->uch_obuf_sz = UCHCOM_XFER_SZ_MAX;
1294

  
1295
        if (in_data->ep_descr.wMaxPacketSize)
1296
                uch->uch_ibuf_sz = in_data->ep_descr.wMaxPacketSize;
1297
        uch->uch_ibuf_sz = min(uch->uch_ibuf_sz, max_xfer_sz);
1298

  
1299
        if (out_data->ep_descr.wMaxPacketSize)
1300
                uch->uch_obuf_sz = out_data->ep_descr.wMaxPacketSize;
1301
        uch->uch_obuf_sz = min(uch->uch_obuf_sz, max_xfer_sz);
1302

  
1303
	/* open pipes */
1304
	policy.pp_max_async_reqs = 2;
1305

  
1306
	if (usb_pipe_open(uch->uch_dip, &in_data->ep_descr, &policy,
1307
	    USB_FLAGS_SLEEP, &uch->uch_bulkin_ph) != USB_SUCCESS) {
1308

  
1309
		return (USB_FAILURE);
1310
	}
1311

  
1312
	if (usb_pipe_open(uch->uch_dip, &out_data->ep_descr, &policy,
1313
	    USB_FLAGS_SLEEP, &uch->uch_bulkout_ph) != USB_SUCCESS) {
1314
		usb_pipe_close(uch->uch_dip, uch->uch_bulkin_ph, USB_FLAGS_SLEEP,
1315
		    NULL, NULL);
1316

  
1317
		return (USB_FAILURE);
1318
	}
1319

  
1320
	mutex_enter(&uch->uch_lock);
1321
	uch->uch_bulkin_state = UCHCOM_PIPE_IDLE;
1322
	uch->uch_bulkout_state = UCHCOM_PIPE_IDLE;
1323
	mutex_exit(&uch->uch_lock);
1324

  
1325
	return (USB_SUCCESS);
1326
}
1327

  
1328
static void
1329
uchcom_close_pipes(uchcom_state_t *uch)
1330
{
1331
	if (uch->uch_bulkin_ph)
1332
		usb_pipe_close(uch->uch_dip, uch->uch_bulkin_ph,
1333
		    USB_FLAGS_SLEEP, 0, 0);
1334
	if (uch->uch_bulkout_ph)
1335
		usb_pipe_close(uch->uch_dip, uch->uch_bulkout_ph,
1336
		    USB_FLAGS_SLEEP, 0, 0);
1337

  
1338
	mutex_enter(&uch->uch_lock);
1339
	uch->uch_bulkin_state = UCHCOM_PIPE_CLOSED;
1340
	uch->uch_bulkout_state = UCHCOM_PIPE_CLOSED;
1341
	mutex_exit(&uch->uch_lock);
1342
}
1343

  
1344
static void
1345
uchcom_disconnect_pipes(uchcom_state_t *uch)
1346
{
1347
	uchcom_close_pipes(uch);
1348
}
1349

  
1350

  
1351
static int
1352
uchcom_reconnect_pipes(uchcom_state_t *uch)
1353
{
1354
	return (uchcom_open_pipes(uch));
1355
}
1356

  
1357
/*
1358
 * pipe callbacks bulk in common and exeception callback
1359
 */
1360
/*ARGSUSED*/
1361
void
1362
uchcom_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1363
{
1364
	uchcom_state_t 	*uch = (uchcom_state_t *)req->bulk_client_private;
1365
	mblk_t		*data;
1366
	int		data_len;
1367

  
1368
	data = req->bulk_data;
1369
	data_len = (data) ? MBLKL(data) : 0;
1370

  
1371
	USB_DPRINTF_L4(DPRINT_IN_PIPE, uch->uch_lh, "uchcom_bulkin_cb: "
1372
	    "cr=%d len=%d",
1373
	    req->bulk_completion_reason,
1374
	    data_len);
1375

  
1376
	/* save data and notify GSD */
1377
	if ((uch->uch_port_state == UCHCOM_PORT_OPEN) && (data_len) &&
1378
	    (req->bulk_completion_reason == USB_CR_OK)) {
1379
		req->bulk_data = NULL;
1380
		uchcom_put_tail(&uch->uch_rx_mp, data);
1381
		if (uch->uch_cb.cb_rx) {
1382
			uch->uch_cb.cb_rx(uch->uch_cb.cb_arg);
1383
		}
1384
	}
1385

  
1386
	usb_free_bulk_req(req);
1387

  
1388
	/* receive more */
1389
	mutex_enter(&uch->uch_lock);
1390
	uch->uch_bulkin_state = UCHCOM_PIPE_IDLE;
1391
	if ((uch->uch_port_state == UCHCOM_PORT_OPEN) &&
1392
	    (uch->uch_dev_state == USB_DEV_ONLINE)) {
1393
		if (uchcom_rx_start(uch) != USB_SUCCESS) {
1394
			USB_DPRINTF_L2(DPRINT_IN_PIPE, uch->uch_lh,
1395
			    "uchcom_bulkin_cb: restart rx fail");
1396
		}
1397
	}
1398
	mutex_exit(&uch->uch_lock);
1399
}
1400

  
1401
/*
... This diff was truncated because it exceeds the maximum size that can be displayed.
(1-1/2)