aboutsummaryrefslogtreecommitdiffstats
path: root/include/sys/sunddi.h
blob: 65df2a053c2b80755b3a42cb0ef4d7bb904494a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/*****************************************************************************\
 *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
 *  Copyright (C) 2007 The Regents of the University of California.
 *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
 *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
 *  UCRL-CODE-235197
 *
 *  This file is part of the SPL, Solaris Porting Layer.
 *  For details, see <http://github.com/behlendorf/spl/>.
 *
 *  The SPL is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 2 of the License, or (at your
 *  option) any later version.
 *
 *  The SPL is distributed in the hope that it will be useful, but WITHOUT
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 *  for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
\*****************************************************************************/

#ifndef _SPL_SUNDDI_H
#define _SPL_SUNDDI_H

#include <sys/cred.h>
#include <sys/uio.h>
#include <sys/sunldi.h>
#include <sys/mutex.h>
#include <sys/u8_textprep.h>
#include <sys/vnode.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/list.h>
#include <spl-device.h>

#define DDI_MAX_NAME_LEN	32

typedef int ddi_devid_t;

typedef enum {
	DDI_INFO_DEVT2DEVINFO	= 0,
	DDI_INFO_DEVT2INSTANCE	= 1
} ddi_info_cmd_t;

typedef enum {
	DDI_ATTACH		= 0,
	DDI_RESUME		= 1,
	DDI_PM_RESUME		= 2
} ddi_attach_cmd_t;

typedef enum {
	DDI_DETACH		= 0,
	DDI_SUSPEND		= 1,
	DDI_PM_SUSPEND		= 2,
	DDI_HOTPLUG_DETACH	= 3
} ddi_detach_cmd_t;

typedef enum {
	DDI_RESET_FORCE = 0
} ddi_reset_cmd_t;

typedef enum {
	PROP_LEN		= 0,
	PROP_LEN_AND_VAL_BUF	= 1,
	PROP_LEN_AND_VAL_ALLOC	= 2,
	PROP_EXISTS		= 3
} ddi_prop_op_t;

typedef void *devmap_cookie_t;
typedef struct as {
       uchar_t  a_flags;
} as_t;

typedef struct pollhead {
	struct polldat *ph_list;
} pollhead_t;

typedef struct dev_info {
	kmutex_t di_lock;
	char di_name[DDI_MAX_NAME_LEN];
	struct dev_ops *di_ops;
	struct cdev *di_cdev;
	spl_class *di_class;
	spl_device *di_device;
	major_t	di_major;
	minor_t di_minor;
	dev_t di_dev;
	unsigned di_minors;
	int di_flags;
	struct list_head di_list;
} dev_info_t;

typedef struct cb_ops {
	int (*cb_open)(dev_t *devp, int flag, int otyp, cred_t *credp);
	int (*cb_close)(dev_t dev, int flag, int otyp, cred_t *credp);
	int (*cb_strategy)(void *bp);
	int (*cb_print)(dev_t dev, char *str);
	int (*cb_dump)(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
	int (*cb_read)(dev_t dev, struct uio *uiop, cred_t *credp);
	int (*cb_write)(dev_t dev, struct uio *uiop, cred_t *credp);
	int (*cb_ioctl)(dev_t dev, int cmd, intptr_t arg, int mode,
	                cred_t *credp, int *rvalp);
	int (*cb_devmap)(dev_t dev, devmap_cookie_t dhp, offset_t off,
	                 size_t len, size_t *maplen, uint_t model);
	int (*cb_mmap)(dev_t dev, off_t off, int prot);
	int (*cb_segmap)(dev_t dev, off_t off, struct as *asp,
	                 caddr_t *addrp, off_t len, unsigned int prot,
	                 unsigned int maxprot, unsigned int flags,
	                 cred_t *credp);
	int (*cb_chpoll)(dev_t dev, short events, int anyyet,
	                 short *reventsp, struct pollhead **phpp);
	int (*cb_prop_op)(dev_t dev, dev_info_t *dip,
	                  ddi_prop_op_t prop_op, int mod_flags,
	                  char *name, caddr_t valuep, int *length);
	struct streamtab *cb_str;
	int cb_flag;
	int cb_rev;
	int (*cb_aread)(dev_t dev, struct aio_req *aio, cred_t *credp);
	int (*cb_awrite)(dev_t dev, struct aio_req *aio, cred_t *credp);
} cb_ops_t;

typedef struct dev_ops {
	int devo_rev;
	int devo_refcnt;

	int (*devo_getinfo)(dev_info_t *dip,
	                    ddi_info_cmd_t infocmd, void *arg, void **result);
	int (*devo_identify)(dev_info_t *dip);
	int (*devo_probe)(dev_info_t *dip);
	int (*devo_attach)(dev_info_t *dip, ddi_attach_cmd_t cmd);
	int (*devo_detach)(dev_info_t *dip, ddi_detach_cmd_t cmd);
	int (*devo_reset)(dev_info_t *dip, ddi_reset_cmd_t cmd);

	struct cb_ops *devo_cb_ops;
	struct bus_ops *devo_bus_ops;
	int (*devo_power)(dev_info_t *dip, int component, int level);
	int (*devo_quiesce)(dev_info_t *dip);
} dev_ops_t;

typedef struct mod_ops {
	int (*modm_install)(void);
	int (*modm_remove)(void);
	int (*modm_info)(void);
} mod_ops_t;

typedef struct modldrv {
	struct mod_ops *drv_modops;
	char *drv_linkinfo;
	struct dev_ops *drv_dev_ops;
	struct dev_info *drv_dev_info;
} modldrv_t;

#define	MODREV_1			1

#define	D_NEW				0x000
#define D_MP				0x020
#define	D_64BIT				0x200

#define	DEVO_REV			3
#define	CB_REV				1

#define	DDI_SUCCESS			0
#define	DDI_FAILURE			-1

#define	DDI_PSEUDO			"ddi_pseudo"

#define nodev				NULL
#define nochpoll			NULL
#define nulldev				NULL
#define mod_driverops			NULL
#define ddi_prop_op			NULL

#define getminor(x)			(x)
#define getmajor(x)			(x)
#define ddi_driver_major(di)		getmajor(di->di_dev)

#define	DDI_DEV_T_NONE			((dev_t)-1)
#define	DDI_DEV_T_ANY			((dev_t)-2)
#define	DDI_MAJOR_T_UNKNOWN		((major_t)0)

#define	DDI_PROP_DONTPASS		0x0001
#define	DDI_PROP_CANSLEEP		0x0002

#define	GLOBAL_DEV			0x02
#define	NODEBOUND_DEV			0x04
#define	NODESPECIFIC_DEV		0x06
#define	ENUMERATED_DEV			0x08

#define ddi_prop_lookup_string(x1,x2,x3,x4,x5)	(*x5 = NULL)
#define ddi_prop_free(x)			(void)0
#define ddi_root_node()				(void)0

#define mod_install(x)			0
#define mod_remove(x)			0

extern int __ddi_create_minor_node(dev_info_t *dip, char *name, int spec_type,
                                   minor_t minor_num, char *node_type,
				   int flags, struct module *mod);
extern void __ddi_remove_minor_node(dev_info_t *dip, char *name);
extern int ddi_quiesce_not_needed(dev_info_t *dip);
extern int __mod_install(struct modlinkage *modlp);
extern int __mod_remove(struct modlinkage *modlp);
extern int __mod_mknod(char *name, char *type, int major, int minor);

extern int ddi_strtoul(const char *, char **, int, unsigned long *);
extern int ddi_strtol(const char *, char **, int, long *);
extern int ddi_strtoull(const char *, char **, int, unsigned long long *);
extern int ddi_strtoll(const char *, char **, int, long long *);

extern int ddi_copyin(const void *from, void *to, size_t len, int flags);
extern int ddi_copyout(const void *from, void *to, size_t len, int flags);

static __inline__ void ddi_report_dev(dev_info_t *d) { }
static __inline__ void ddi_prop_remove_all(dev_info_t *dip) { }

static __inline__ void
ddi_remove_minor_node(dev_info_t *di, char *name)
{
#ifdef HAVE_GPL_ONLY_SYMBOLS
	/* Cleanup udev (GPL-only symbols required).  This is performed as
	 * part of an inline function to ensure that these symbols are not
	 * linked against the SPL which is GPL'ed.  But instead they are
	 * linked against the package building against the SPL to ensure
	 * its license allows linking with GPL-only symbols. */
	if (di->di_class) {
		spl_device_destroy(di->di_class, di->di_device, di->di_dev);
		spl_class_destroy(di->di_class);
		di->di_class = NULL;
		di->di_dev = 0;
	}
#else
	/* When we do not have access to the GPL-only device interfaces we
	 * are forced to do something crude.  We unlink the special device
	 * file in /dev/ ourselves from within the kernel.  On the upside we
	 * are already providing this functionality for Solaris, and it is
	 * easy to leverage the Solaris API to perform the unlink. */
	if (strlen(di->di_name) > 0)
		vn_remove(di->di_name, UIO_SYSSPACE, RMFILE);

#endif /* HAVE_GPL_ONLY_SYMBOLS */

	__ddi_remove_minor_node(di, name);
}

static __inline__ int
ddi_create_minor_node(dev_info_t *di, char *name, int spec_type,
                      minor_t minor_num, char *node_type, int flags)
{
	int rc;

	rc = __ddi_create_minor_node(di, name, spec_type, minor_num,
	                             node_type, flags, THIS_MODULE);
	if (rc)
		return rc;

#ifdef HAVE_GPL_ONLY_SYMBOLS
	/* Setup udev (GPL-only symbols required).  This is performed as
	 * part of an inline function to ensure that these symbols are not
	 * linked against the SPL which is GPL'ed.  But instead they are
	 * linked against the package building against the SPL to ensure
	 * its license allows linking with GPL-only symbols. */
	di->di_class = spl_class_create(THIS_MODULE, name);
	if (IS_ERR(di->di_class)) {
		rc = PTR_ERR(di->di_class);
		di->di_class = NULL;
		ddi_remove_minor_node(di, name);
		return DDI_FAILURE;
	}

	/* Do not append a 0 to devices with minor nums of 0 */
	di->di_device = spl_device_create(di->di_class, NULL, di->di_dev, NULL,
					  (di->di_minor == 0) ? "%s" : "%s%d",
					  name, di->di_minor);
#else
	/* When we do not have access to the GPL-only device interfaces we
	 * are forced to do something horible.  We use a user mode helper to
	 * create the special device file in /dev/.  By futher extending the
	 * Solaris vnode implementation we could potentially do a vn_create()
	 * from within the kernel but that's still a hack. */
	if (name) {
		rc = __mod_mknod(di->di_name, "c", di->di_major, di->di_minor);
		if (rc) {
			ddi_remove_minor_node(di, name);
		}
	}

#endif /* HAVE_GPL_ONLY_SYMBOLS */

	return rc;
}

#undef mod_install
#undef mod_remove

#define mod_install			__mod_install
#define mod_remove			__mod_remove

#endif /* SPL_SUNDDI_H */