]> git.proxmox.com Git - mirror_spl.git/blob - include/sys/sunddi.h
Add ddi_copyin/ddi_copyout support for fake kernel originated ioctls.
[mirror_spl.git] / include / sys / sunddi.h
1 /*
2 * This file is part of the SPL: Solaris Porting Layer.
3 *
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
6 * Written by:
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
10 * UCRL-CODE-235197
11 *
12 * This is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27 #ifndef _SPL_SUNDDI_H
28 #define _SPL_SUNDDI_H
29
30 #include <sys/cred.h>
31 #include <sys/uio.h>
32 #include <sys/sunldi.h>
33 #include <sys/mutex.h>
34 #include <sys/u8_textprep.h>
35 #include <sys/vnode.h>
36 #include <linux/kdev_t.h>
37 #include <linux/fs.h>
38 #include <linux/cdev.h>
39 #include <linux/list.h>
40 #include <spl-device.h>
41
42 #define DDI_MAX_NAME_LEN 32
43
44 typedef int ddi_devid_t;
45
46 typedef enum {
47 DDI_INFO_DEVT2DEVINFO = 0,
48 DDI_INFO_DEVT2INSTANCE = 1
49 } ddi_info_cmd_t;
50
51 typedef enum {
52 DDI_ATTACH = 0,
53 DDI_RESUME = 1,
54 DDI_PM_RESUME = 2
55 } ddi_attach_cmd_t;
56
57 typedef enum {
58 DDI_DETACH = 0,
59 DDI_SUSPEND = 1,
60 DDI_PM_SUSPEND = 2,
61 DDI_HOTPLUG_DETACH = 3
62 } ddi_detach_cmd_t;
63
64 typedef enum {
65 DDI_RESET_FORCE = 0
66 } ddi_reset_cmd_t;
67
68 typedef enum {
69 PROP_LEN = 0,
70 PROP_LEN_AND_VAL_BUF = 1,
71 PROP_LEN_AND_VAL_ALLOC = 2,
72 PROP_EXISTS = 3
73 } ddi_prop_op_t;
74
75 typedef void *devmap_cookie_t;
76 typedef struct as {
77 uchar_t a_flags;
78 } as_t;
79
80 typedef struct pollhead {
81 struct polldat *ph_list;
82 } pollhead_t;
83
84 typedef struct dev_info {
85 kmutex_t di_lock;
86 char di_name[DDI_MAX_NAME_LEN];
87 struct dev_ops *di_ops;
88 struct cdev *di_cdev;
89 spl_class *di_class;
90 spl_device *di_device;
91 major_t di_major;
92 minor_t di_minor;
93 dev_t di_dev;
94 unsigned di_minors;
95 int di_flags;
96 struct list_head di_list;
97 } dev_info_t;
98
99 typedef struct cb_ops {
100 int (*cb_open)(dev_t *devp, int flag, int otyp, cred_t *credp);
101 int (*cb_close)(dev_t dev, int flag, int otyp, cred_t *credp);
102 int (*cb_strategy)(void *bp);
103 int (*cb_print)(dev_t dev, char *str);
104 int (*cb_dump)(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
105 int (*cb_read)(dev_t dev, struct uio *uiop, cred_t *credp);
106 int (*cb_write)(dev_t dev, struct uio *uiop, cred_t *credp);
107 int (*cb_ioctl)(dev_t dev, int cmd, intptr_t arg, int mode,
108 cred_t *credp, int *rvalp);
109 int (*cb_devmap)(dev_t dev, devmap_cookie_t dhp, offset_t off,
110 size_t len, size_t *maplen, uint_t model);
111 int (*cb_mmap)(dev_t dev, off_t off, int prot);
112 int (*cb_segmap)(dev_t dev, off_t off, struct as *asp,
113 caddr_t *addrp, off_t len, unsigned int prot,
114 unsigned int maxprot, unsigned int flags,
115 cred_t *credp);
116 int (*cb_chpoll)(dev_t dev, short events, int anyyet,
117 short *reventsp, struct pollhead **phpp);
118 int (*cb_prop_op)(dev_t dev, dev_info_t *dip,
119 ddi_prop_op_t prop_op, int mod_flags,
120 char *name, caddr_t valuep, int *length);
121 struct streamtab *cb_str;
122 int cb_flag;
123 int cb_rev;
124 int (*cb_aread)(dev_t dev, struct aio_req *aio, cred_t *credp);
125 int (*cb_awrite)(dev_t dev, struct aio_req *aio, cred_t *credp);
126 } cb_ops_t;
127
128 typedef struct dev_ops {
129 int devo_rev;
130 int devo_refcnt;
131
132 int (*devo_getinfo)(dev_info_t *dip,
133 ddi_info_cmd_t infocmd, void *arg, void **result);
134 int (*devo_identify)(dev_info_t *dip);
135 int (*devo_probe)(dev_info_t *dip);
136 int (*devo_attach)(dev_info_t *dip, ddi_attach_cmd_t cmd);
137 int (*devo_detach)(dev_info_t *dip, ddi_detach_cmd_t cmd);
138 int (*devo_reset)(dev_info_t *dip, ddi_reset_cmd_t cmd);
139
140 struct cb_ops *devo_cb_ops;
141 struct bus_ops *devo_bus_ops;
142 int (*devo_power)(dev_info_t *dip, int component, int level);
143 int (*devo_quiesce)(dev_info_t *dip);
144 } dev_ops_t;
145
146 typedef struct mod_ops {
147 int (*modm_install)(void);
148 int (*modm_remove)(void);
149 int (*modm_info)(void);
150 } mod_ops_t;
151
152 typedef struct modldrv {
153 struct mod_ops *drv_modops;
154 char *drv_linkinfo;
155 struct dev_ops *drv_dev_ops;
156 struct dev_info *drv_dev_info;
157 } modldrv_t;
158
159 #define MODREV_1 1
160
161 #define D_NEW 0x000
162 #define D_MP 0x020
163 #define D_64BIT 0x200
164
165 #define DEVO_REV 3
166 #define CB_REV 1
167
168 #define DDI_SUCCESS 0
169 #define DDI_FAILURE -1
170
171 #define DDI_PSEUDO "ddi_pseudo"
172
173 #define nodev NULL
174 #define nochpoll NULL
175 #define nulldev NULL
176 #define mod_driverops NULL
177 #define ddi_prop_op NULL
178
179 #define getminor(x) (x)
180 #define getmajor(x) (x)
181 #define ddi_driver_major(di) getmajor(di->di_dev)
182
183 #define DDI_DEV_T_NONE ((dev_t)-1)
184 #define DDI_DEV_T_ANY ((dev_t)-2)
185 #define DDI_MAJOR_T_UNKNOWN ((major_t)0)
186
187 #define DDI_PROP_DONTPASS 0x0001
188 #define DDI_PROP_CANSLEEP 0x0002
189
190 #define GLOBAL_DEV 0x02
191 #define NODEBOUND_DEV 0x04
192 #define NODESPECIFIC_DEV 0x06
193 #define ENUMERATED_DEV 0x08
194
195 #define ddi_prop_lookup_string(x1,x2,x3,x4,x5) (*x5 = NULL)
196 #define ddi_prop_free(x) (void)0
197 #define ddi_root_node() (void)0
198
199 #define mod_install(x) 0
200 #define mod_remove(x) 0
201
202 extern int __ddi_create_minor_node(dev_info_t *dip, char *name, int spec_type,
203 minor_t minor_num, char *node_type,
204 int flags, struct module *mod);
205 extern void __ddi_remove_minor_node(dev_info_t *dip, char *name);
206 extern int ddi_quiesce_not_needed(dev_info_t *dip);
207 extern int __mod_install(struct modlinkage *modlp);
208 extern int __mod_remove(struct modlinkage *modlp);
209 extern int __mod_mknod(char *name, char *type, int major, int minor);
210
211 extern int ddi_strtoul(const char *, char **, int, unsigned long *);
212 extern int ddi_strtol(const char *, char **, int, long *);
213 extern int ddi_strtoull(const char *, char **, int, unsigned long long *);
214 extern int ddi_strtoll(const char *, char **, int, long long *);
215
216 extern int ddi_copyin(const void *from, void *to, size_t len, int flags);
217 extern int ddi_copyout(const void *from, void *to, size_t len, int flags);
218
219 static __inline__ void ddi_report_dev(dev_info_t *d) { }
220 static __inline__ void ddi_prop_remove_all(dev_info_t *dip) { }
221
222 static __inline__ void
223 ddi_remove_minor_node(dev_info_t *di, char *name)
224 {
225 #ifdef HAVE_GPL_ONLY_SYMBOLS
226 /* Cleanup udev (GPL-only symbols required). This is performed as
227 * part of an inline function to ensure that these symbols are not
228 * linked against the SPL which is GPL'ed. But instead they are
229 * linked against the package building against the SPL to ensure
230 * its license allows linking with GPL-only symbols. */
231 if (di->di_class) {
232 spl_device_destroy(di->di_class, di->di_device, di->di_dev);
233 spl_class_destroy(di->di_class);
234 di->di_class = NULL;
235 di->di_dev = 0;
236 }
237 #else
238 /* When we do not have access to the GPL-only device interfaces we
239 * are forced to do something crude. We unlink the special device
240 * file in /dev/ ourselves from within the kernel. On the upside we
241 * are already providing this functionality for Solaris, and it is
242 * easy to leverage the Solaris API to perform the unlink. */
243 if (strlen(di->di_name) > 0)
244 vn_remove(di->di_name, UIO_SYSSPACE, RMFILE);
245
246 #endif /* HAVE_GPL_ONLY_SYMBOLS */
247
248 __ddi_remove_minor_node(di, name);
249 }
250
251 static __inline__ int
252 ddi_create_minor_node(dev_info_t *di, char *name, int spec_type,
253 minor_t minor_num, char *node_type, int flags)
254 {
255 int rc;
256
257 rc = __ddi_create_minor_node(di, name, spec_type, minor_num,
258 node_type, flags, THIS_MODULE);
259 if (rc)
260 return rc;
261
262 #ifdef HAVE_GPL_ONLY_SYMBOLS
263 /* Setup udev (GPL-only symbols required). This is performed as
264 * part of an inline function to ensure that these symbols are not
265 * linked against the SPL which is GPL'ed. But instead they are
266 * linked against the package building against the SPL to ensure
267 * its license allows linking with GPL-only symbols. */
268 di->di_class = spl_class_create(THIS_MODULE, name);
269 if (IS_ERR(di->di_class)) {
270 rc = PTR_ERR(di->di_class);
271 di->di_class = NULL;
272 ddi_remove_minor_node(di, name);
273 CERROR("Error creating %s class, %d\n", name, rc);
274 return DDI_FAILURE;
275 }
276
277 /* Do not append a 0 to devices with minor nums of 0 */
278 di->di_device = spl_device_create(di->di_class, NULL, di->di_dev, NULL,
279 (di->di_minor == 0) ? "%s" : "%s%d",
280 name, di->di_minor);
281 #else
282 /* When we do not have access to the GPL-only device interfaces we
283 * are forced to do something horible. We use a user mode helper to
284 * create the special device file in /dev/. By futher extending the
285 * Solaris vnode implementation we could potentially do a vn_create()
286 * from within the kernel but that's still a hack. */
287 if (name) {
288 rc = __mod_mknod(di->di_name, "c", di->di_major, di->di_minor);
289 if (rc) {
290 CERROR("Error mknod %s, %d\n", di->di_name, rc);
291 ddi_remove_minor_node(di, name);
292 }
293 }
294
295 #endif /* HAVE_GPL_ONLY_SYMBOLS */
296
297 return rc;
298 }
299
300 #undef mod_install
301 #undef mod_remove
302
303 #define mod_install __mod_install
304 #define mod_remove __mod_remove
305
306 #endif /* SPL_SUNDDI_H */