usbser_var.h revision 7492:2387323b838f
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#ifndef _SYS_USB_USBSER_VAR_H
27#define	_SYS_USB_USBSER_VAR_H
28
29
30/*
31 * USB-to-serial driver definitions
32 */
33
34#include <sys/tty.h>
35#include <sys/mkdev.h>
36#include <sys/sunddi.h>
37#include <sys/note.h>
38
39#include <sys/usb/clients/usbser/usbser_dsdi.h>
40
41#ifdef	__cplusplus
42extern "C" {
43#endif
44
45typedef struct usbser_state	usbser_state_t;
46typedef struct usbser_port	usbser_port_t;
47
48/*
49 * because put() and srv() routines are not allowed to block, usbser
50 * provides each port with two threads: for read and write processing
51 * this structure describes the data associated with a usbser thread
52 */
53typedef struct usbser_thread {
54	kcondvar_t	thr_cv;		/* cv for request wait */
55	uint_t		thr_flags;	/* state flags */
56	usbser_port_t	*thr_port;	/* port owner of this thread */
57	void		(*thr_func)(void *);	/* function to be run */
58	void		*thr_arg;	/* function argument */
59} usbser_thread_t;
60
61/*
62 * thr_flags
63 */
64enum {
65	USBSER_THR_RUNNING	= 0x01,	/* thread is running */
66	USBSER_THR_WAKE		= 0x02,	/* wake requested */
67	USBSER_THR_EXITED	= 0x04	/* thread exited */
68};
69
70/*
71 * additional device state
72 */
73#define	USBSER_DEV_INIT		0x80	/* device is being initialized */
74
75/*
76 * per instance data
77 */
78struct usbser_state {
79	struct usbser_state *us_next;		/* linked list */
80	dev_info_t	*us_dip;		/* device information */
81	kmutex_t	us_mutex;		/* structure lock */
82	void		*us_statep;		/* soft state anchor */
83	int		us_instance;		/* instance number */
84	ds_ops_t	*us_ds_ops;		/* DSD operations */
85	ds_hdl_t	us_ds_hdl;		/* DSD device handle */
86	uint_t		us_port_cnt;		/* port count */
87	usbser_port_t	*us_ports;		/* array of port structs */
88	uint_t		us_dev_state;		/* USB device state */
89	usb_log_handle_t us_lh;			/* USB log handle */
90	ddi_taskq_t	*us_taskq;		/* taskq for command handling */
91};
92
93_NOTE(MUTEX_PROTECTS_DATA(usbser_state::us_mutex, usbser_state::us_dev_state))
94
95/*
96 * per port data
97 */
98struct usbser_port {
99	kmutex_t	port_mutex;		/* structure lock */
100	usbser_state_t	*port_usp;		/* back pointer to state */
101	char		port_lh_name[16];	/* log handle name */
102	usb_log_handle_t port_lh;		/* log handle */
103	ds_ops_t	*port_ds_ops;		/* copy from usbser_state */
104	ds_hdl_t	port_ds_hdl;		/* copy from usbser_state */
105	uint_t		port_num;		/* port number */
106	uint_t		port_state;		/* port state */
107	uint_t		port_act;		/* current activities on port */
108	uint_t		port_flags;		/* port flags */
109	kcondvar_t	port_state_cv;		/* port state cv */
110	kcondvar_t	port_act_cv;		/* port activity cv */
111	kcondvar_t	port_car_cv;		/* port carrier cv */
112	uint_t		port_wq_data_cnt;	/* amount of unsent data */
113	usbser_thread_t	port_wq_thread;		/* wq thread */
114	usbser_thread_t	port_rq_thread;		/* rq thread */
115	tty_common_t	port_ttycommon;		/* tty driver common data */
116	uchar_t		port_flowc;		/* flow control char */
117	timeout_id_t	port_delay_id;		/* delay/break timeout id */
118};
119
120_NOTE(MUTEX_PROTECTS_DATA(usbser_port::port_mutex, usbser_port))
121_NOTE(DATA_READABLE_WITHOUT_LOCK(usbser_port::{
122	port_usp
123	port_lh
124	port_ds_ops
125	port_ds_hdl
126	port_num
127	port_ttycommon.t_{readq writeq}
128}))
129
130_NOTE(LOCK_ORDER(usbser_state::us_mutex usbser_port::port_mutex))
131
132/*
133 * port_state:
134 *
135 *   USBSER_PORT_NOT_INIT
136 *          |   ^
137 *          |   |
138 *     attach   detach
139 *          |   |
140 *          |   |    +----open[1]----> USBSER_PORT_OPENING_TTY ------+
141 *          |   |    |                      |    |                   |
142 *          v   |    |                      |    |                   |
143 *   USBSER_PORT_CLOSED <---device error---<    overtake[2]          |
144 *            |      |                      |    |                   v
145 *            |      |                      |    v                   |
146 *            |      +----open[1]----> USBSER_PORT_OPENING_OUT       |
147 *            |                             |                        |
148 *            |                             |    +-------------------+
149 *            |                             |    |
150 *            |                             v    v
151 * USBSER_PORT_CLOSING <-----close----- USBSER_PORT_OPEN <-----------+
152 *            ^                             |    ^       --------+   |
153 *            |                             |    |               |   |
154 *            |                             |    |               |   |
155 *            |                             v    |               v   |
156 *            +------close----- USBSER_PORT_DISCONNECTED  USBSER_PORT_SUSPENDED
157 *
158 * Notes:
159 *
160 * [1] for each physical port N two device nodes are created:
161 *
162 *       /dev/term/N (tty mode)
163 *       /dev/cua/N  (dial-out mode)
164 *
165 *     the port can only be opened in one of these modes at a time.
166 *     difference between the two is that in tty mode the driver
167 *     will block in open(9E) until the CD (Carrier Detect) pin comes up,
168 *     while in dial-out mode CD is ignored. opening and closing states
169 *     help to avoid race conditions between two threads trying to open/close
170 *     one physical port in two different modes simultaneously.
171 *
172 * [2] tty mode open may be blocked waiting for carrier.
173 *     if dial-out mode open happens at this time, it is allowed
174 *     for it to overtake the port; from zs(7D) man page:
175 *
176 *	 This allows a modem to be attached to  /dev/term/[n]
177 *	 and used for dial-in (by enabling the line for login in /etc/inittab)
178 *	 and also used for  dial-out  (by  tip(1) or uucp(1C)) as /dev/cua/[n]
179 *	 when no one is logged in on the line.
180 */
181enum {
182	USBSER_PORT_NOT_INIT = 0,	/* port not initialized */
183	USBSER_PORT_CLOSED,		/* port is closed */
184	USBSER_PORT_OPENING_TTY,	/* tty open in progress */
185	USBSER_PORT_OPENING_OUT,	/* dial-out open in progress */
186	USBSER_PORT_OPEN,		/* port is open */
187	USBSER_PORT_SUSPENDED,		/* port is suspended */
188	USBSER_PORT_DISCONNECTED,	/* port is disconnected */
189	USBSER_PORT_CLOSING		/* close() is in progress */
190};
191
192/* constants used by state machine implementation */
193enum {
194	USBSER_CONTINUE			= -1,
195	USBSER_COMPLETE			= 0
196};
197
198/*
199 * port_act: current activities on the port.
200 * only one activity of each type is allowed at a time.
201 */
202enum {
203	USBSER_ACT_TX		= 0x0001,	/* transmitting data */
204	USBSER_ACT_RX		= 0x0002,	/* receiving data */
205	USBSER_ACT_CTL		= 0x0004,	/* controlling the device */
206	USBSER_ACT_BREAK	= 0x0010,	/* doing break */
207	USBSER_ACT_DELAY	= 0x0020,	/* doing delay */
208	USBSER_ACT_ALL		= 0xffff	/* all actions (must be >0) */
209};
210
211/*
212 * port_flags
213 */
214enum {
215	USBSER_FL_OUT		= 0x0001,	/* dial-out */
216	USBSER_FL_WOPEN		= 0x0002,	/* waiting in open() */
217	USBSER_FL_CARR_ON	= 0x0004,	/* carrier is on */
218	USBSER_FL_TX_STOPPED	= 0x0008,	/* output stopped */
219	USBSER_FL_RX_STOPPED	= 0x0010,	/* input stopped */
220	USBSER_FL_HUNGUP	= 0x0020,	/* stream is hung up */
221	USBSER_FL_DSD_OPEN	= 0x0040,	/* DSD is open */
222	USBSER_FL_STATUS_CB	= 0x0080,	/* status callback pending */
223	USBSER_FL_IGNORE_CD	= 0x0100,	/* ignore carrier detect */
224	USBSER_FL_PRESERVE	= USBSER_FL_IGNORE_CD
225						/* flags that need to */
226						/* be preserved across opens */
227};
228
229/*
230 * current sun compiler does not seem to inline static leaf routines at O3
231 * so we have to use preprocessor macros to make up for compiler disability
232 *
233 * can we access the port?
234 */
235#define	USBSER_PORT_ACCESS_OK(pp)	((pp)->port_state == USBSER_PORT_OPEN)
236
237/*
238 * is port doing something?
239 */
240#define	USBSER_PORT_IS_BUSY(pp)		((pp)->port_act != 0)
241
242/*
243 * is the port opening?
244 */
245#define	USBSER_IS_OPENING(pp)	\
246	(((pp)->port_state == USBSER_PORT_OPENING_TTY) || \
247	((pp)->port_state == USBSER_PORT_OPENING_OUT))
248
249/*
250 * determine, while we are trying to open the port,
251 * whether it is currently being open in the opposite mode
252 */
253#define	USBSER_NO_OTHER_OPEN(pp, minor)	\
254	((((minor) & OUTLINE) &&	\
255	((pp)->port_state == USBSER_PORT_OPENING_OUT)) ||	\
256	(!((minor) & OUTLINE) && ((pp)->port_state == USBSER_PORT_OPENING_TTY)))
257
258/*
259 * determine, while we are trying to open the port,
260 * whether it is already open in the opposite mode
261 */
262#define	USBSER_OPEN_IN_OTHER_MODE(pp, minor)	\
263	((((minor) & OUTLINE) && !((pp)->port_flags & USBSER_FL_OUT)) || \
264	(!((minor) & OUTLINE) && ((pp)->port_flags & USBSER_FL_OUT)))
265
266/*
267 * minor number manipulation
268 */
269enum {
270	MAXPORTS_PER_DEVICE_SHIFT	= 4,
271	MAXPORTS_PER_DEVICE		= (1 << MAXPORTS_PER_DEVICE_SHIFT),
272	MAXPORTS_PER_DEVICE_MASK	= (MAXPORTS_PER_DEVICE - 1),
273	OUTLINE				= (1 << (NBITSMINOR32 - 1))
274};
275
276#define	USBSER_MAKEMINOR(instance, port, outline)	\
277		((port) | ((instance) << MAXPORTS_PER_DEVICE_SHIFT) | (outline))
278
279#define	USBSER_MINOR2INST(minor)	\
280	(((minor) & ~(OUTLINE | MAXPORTS_PER_DEVICE_MASK)) \
281	>> MAXPORTS_PER_DEVICE_SHIFT)
282
283#define	USBSER_MINOR2PORT(minor)	((minor) & MAXPORTS_PER_DEVICE_MASK)
284
285/*
286 * various tunables
287 *
288 * timeouts are in seconds
289 */
290enum {
291	USBSER_TX_FIFO_DRAIN_TIMEOUT	= 5, /* tx fifo drain timeout */
292	USBSER_WQ_DRAIN_TIMEOUT		= 2, /* wq drain timeout */
293	USBSER_SUSPEND_TIMEOUT		= 10 /* cpr suspend timeout */
294};
295
296/*
297 * debug printing masks
298 */
299#define	DPRINT_ATTACH		0x00000001
300#define	DPRINT_DETACH		0x00000002
301#define	DPRINT_OPEN		0x00000004
302#define	DPRINT_CLOSE		0x00000008
303#define	DPRINT_WQ		0x00000010
304#define	DPRINT_RQ		0x00000020
305#define	DPRINT_IOCTL		0x00000040
306#define	DPRINT_RX_CB		0x00000100
307#define	DPRINT_TX_CB		0x00000200
308#define	DPRINT_STATUS_CB	0x00000400
309#define	DPRINT_EVENTS		0x00001000
310#define	DPRINT_CPR		0x00002000
311#define	DPRINT_MASK_ALL		0xFFFFFFFF
312
313/*
314 * misc macros
315 */
316#define	NELEM(a)	(sizeof (a) / sizeof (*(a)))
317
318/*
319 * shortcuts to DSD operations
320 */
321#define	USBSER_DS_ATTACH(usp, aip)	usp->us_ds_ops->ds_attach(aip)
322
323#define	USBSER_DS_DETACH(usp)	usp->us_ds_ops->ds_detach(usp->us_ds_hdl)
324
325#define	USBSER_DS_OPEN_PORT(usp, port_num)	\
326	usp->us_ds_ops->ds_open_port(usp->us_ds_hdl, port_num)
327
328#define	USBSER_DS_CLOSE_PORT(usp, port_num)	\
329	usp->us_ds_ops->ds_close_port(usp->us_ds_hdl, port_num)
330
331#define	USBSER_DS_REGISTER_CB(usp, port_num, cb)	\
332	usp->us_ds_ops->ds_register_cb(usp->us_ds_hdl, port_num, cb)
333
334#define	USBSER_DS_UNREGISTER_CB(usp, port_num)	\
335	usp->us_ds_ops->ds_unregister_cb(usp->us_ds_hdl, port_num)
336
337/* power management */
338#define	USBSER_DS_USB_POWER(usp, comp, level, new_statep)	\
339	usp->us_ds_ops->ds_usb_power(usp->us_ds_hdl, comp, level, new_statep)
340
341#define	USBSER_DS_SUSPEND(usp)	usp->us_ds_ops->ds_suspend(usp->us_ds_hdl)
342
343#define	USBSER_DS_RESUME(usp)	usp->us_ds_ops->ds_resume(usp->us_ds_hdl)
344
345#define	USBSER_DS_DISCONNECT(usp) usp->us_ds_ops->ds_disconnect(usp->us_ds_hdl)
346
347#define	USBSER_DS_RECONNECT(usp) usp->us_ds_ops->ds_reconnect(usp->us_ds_hdl)
348
349/* standard UART operations */
350#define	USBSER_DS_SET_PORT_PARAMS(pp, params)	\
351	pp->port_ds_ops->ds_set_port_params(pp->port_ds_hdl, pp->port_num, \
352		params)
353
354#define	USBSER_DS_SET_MODEM_CTL(pp, mask, val)	\
355	pp->port_ds_ops->ds_set_modem_ctl(pp->port_ds_hdl, pp->port_num, mask, \
356		val)
357
358#define	USBSER_DS_GET_MODEM_CTL(pp, mask, valp)	\
359	pp->port_ds_ops->ds_get_modem_ctl(pp->port_ds_hdl, pp->port_num, \
360		mask, valp)
361
362#define	USBSER_DS_BREAK_CTL(pp, val)		\
363	pp->port_ds_ops->ds_break_ctl(pp->port_ds_hdl, pp->port_num, val)
364
365#define	USBSER_DS_LOOPBACK(pp, val)		\
366	pp->port_ds_ops->ds_loopback(pp->port_ds_hdl, pp->port_num, val)
367
368/* data xfer */
369#define	USBSER_DS_TX(pp, mp)		\
370	pp->port_ds_ops->ds_tx(pp->port_ds_hdl, pp->port_num, mp)
371
372#define	USBSER_DS_RX(pp)		\
373	pp->port_ds_ops->ds_rx(pp->port_ds_hdl, pp->port_num)
374
375#define	USBSER_DS_STOP(pp, dir)		\
376	pp->port_ds_ops->ds_stop(pp->port_ds_hdl, pp->port_num, dir)
377
378#define	USBSER_DS_START(pp, dir)	\
379	pp->port_ds_ops->ds_start(pp->port_ds_hdl, pp->port_num, dir)
380
381/* fifos */
382#define	USBSER_DS_FIFO_FLUSH(pp, mask)		\
383	pp->port_ds_ops->ds_fifo_flush(pp->port_ds_hdl, pp->port_num, mask)
384
385#define	USBSER_DS_FIFO_DRAIN(pp, tmout)		\
386	pp->port_ds_ops->ds_fifo_drain(pp->port_ds_hdl, pp->port_num, tmout)
387
388
389/* check for supported operations */
390#define	USBSER_DS_LOOPBACK_SUPPORTED(pp) (pp->port_ds_ops->ds_loopback != 0)
391
392#ifdef	__cplusplus
393}
394#endif
395
396#endif	/* _SYS_USB_USBSER_VAR_H */
397