device.h revision 299960
1219820Sjeff/*-
2219820Sjeff * Copyright (c) 2010 Isilon Systems, Inc.
3219820Sjeff * Copyright (c) 2010 iX Systems, Inc.
4219820Sjeff * Copyright (c) 2010 Panasas, Inc.
5299674Shselasky * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
6219820Sjeff * All rights reserved.
7219820Sjeff *
8219820Sjeff * Redistribution and use in source and binary forms, with or without
9219820Sjeff * modification, are permitted provided that the following conditions
10219820Sjeff * are met:
11219820Sjeff * 1. Redistributions of source code must retain the above copyright
12219820Sjeff *    notice unmodified, this list of conditions, and the following
13219820Sjeff *    disclaimer.
14219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
15219820Sjeff *    notice, this list of conditions and the following disclaimer in the
16219820Sjeff *    documentation and/or other materials provided with the distribution.
17219820Sjeff *
18219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28289644Shselasky *
29289644Shselasky * $FreeBSD: head/sys/compat/linuxkpi/common/include/linux/device.h 299960 2016-05-16 17:41:25Z hselasky $
30219820Sjeff */
31219820Sjeff#ifndef	_LINUX_DEVICE_H_
32219820Sjeff#define	_LINUX_DEVICE_H_
33219820Sjeff
34299933Shselasky#include <linux/err.h>
35219820Sjeff#include <linux/types.h>
36219820Sjeff#include <linux/kobject.h>
37290335Shselasky#include <linux/sysfs.h>
38219820Sjeff#include <linux/list.h>
39219820Sjeff#include <linux/compiler.h>
40219820Sjeff#include <linux/types.h>
41219820Sjeff#include <linux/module.h>
42219820Sjeff#include <linux/workqueue.h>
43219820Sjeff#include <linux/sysfs.h>
44219820Sjeff#include <linux/kdev_t.h>
45219820Sjeff#include <asm/atomic.h>
46219820Sjeff
47219820Sjeff#include <sys/bus.h>
48219820Sjeff
49219820Sjeffenum irqreturn	{ IRQ_NONE = 0, IRQ_HANDLED, IRQ_WAKE_THREAD, };
50219820Sjefftypedef enum irqreturn	irqreturn_t;
51219820Sjeff
52219820Sjeffstruct class {
53219820Sjeff	const char	*name;
54219820Sjeff	struct module	*owner;
55219820Sjeff	struct kobject	kobj;
56219820Sjeff	devclass_t	bsdclass;
57219820Sjeff	void		(*class_release)(struct class *class);
58219820Sjeff	void		(*dev_release)(struct device *dev);
59270710Shselasky	char *		(*devnode)(struct device *dev, umode_t *mode);
60219820Sjeff};
61219820Sjeff
62219820Sjeffstruct device {
63219820Sjeff	struct device	*parent;
64219820Sjeff	struct list_head irqents;
65219820Sjeff	device_t	bsddev;
66219820Sjeff	dev_t		devt;
67219820Sjeff	struct class	*class;
68219820Sjeff	void		(*release)(struct device *dev);
69219820Sjeff	struct kobject	kobj;
70219820Sjeff	uint64_t	*dma_mask;
71219820Sjeff	void		*driver_data;
72219820Sjeff	unsigned int	irq;
73219820Sjeff	unsigned int	msix;
74219820Sjeff	unsigned int	msix_max;
75299933Shselasky	const struct attribute_group **groups;
76219820Sjeff};
77219820Sjeff
78292987Shselaskyextern struct device linux_root_device;
79292987Shselaskyextern struct kobject linux_class_root;
80292987Shselaskyextern const struct kobj_type linux_dev_ktype;
81292987Shselaskyextern const struct kobj_type linux_class_ktype;
82219820Sjeff
83219820Sjeffstruct class_attribute {
84270710Shselasky        struct attribute attr;
85270710Shselasky        ssize_t (*show)(struct class *, struct class_attribute *, char *);
86270710Shselasky        ssize_t (*store)(struct class *, struct class_attribute *, const char *, size_t);
87270710Shselasky        const void *(*namespace)(struct class *, const struct class_attribute *);
88219820Sjeff};
89270710Shselasky
90219820Sjeff#define	CLASS_ATTR(_name, _mode, _show, _store)				\
91219820Sjeff	struct class_attribute class_attr_##_name =			\
92219820Sjeff	    { { #_name, NULL, _mode }, _show, _store }
93219820Sjeff
94219820Sjeffstruct device_attribute {
95219820Sjeff	struct attribute	attr;
96219820Sjeff	ssize_t			(*show)(struct device *,
97270710Shselasky					struct device_attribute *, char *);
98219820Sjeff	ssize_t			(*store)(struct device *,
99270710Shselasky					struct device_attribute *, const char *,
100270710Shselasky					size_t);
101219820Sjeff};
102219820Sjeff
103219820Sjeff#define	DEVICE_ATTR(_name, _mode, _show, _store)			\
104219820Sjeff	struct device_attribute dev_attr_##_name =			\
105219820Sjeff	    { { #_name, NULL, _mode }, _show, _store }
106219820Sjeff
107270710Shselasky/* Simple class attribute that is just a static string */
108270710Shselaskystruct class_attribute_string {
109270710Shselasky	struct class_attribute attr;
110270710Shselasky	char *str;
111270710Shselasky};
112270710Shselasky
113270710Shselaskystatic inline ssize_t
114270710Shselaskyshow_class_attr_string(struct class *class,
115270710Shselasky				struct class_attribute *attr, char *buf)
116270710Shselasky{
117270710Shselasky	struct class_attribute_string *cs;
118270710Shselasky	cs = container_of(attr, struct class_attribute_string, attr);
119270710Shselasky	return snprintf(buf, PAGE_SIZE, "%s\n", cs->str);
120270710Shselasky}
121270710Shselasky
122270710Shselasky/* Currently read-only only */
123270710Shselasky#define _CLASS_ATTR_STRING(_name, _mode, _str) \
124270710Shselasky	{ __ATTR(_name, _mode, show_class_attr_string, NULL), _str }
125270710Shselasky#define CLASS_ATTR_STRING(_name, _mode, _str) \
126270710Shselasky	struct class_attribute_string class_attr_##_name = \
127270710Shselasky		_CLASS_ATTR_STRING(_name, _mode, _str)
128270710Shselasky
129219820Sjeff#define	dev_err(dev, fmt, ...)	device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
130219820Sjeff#define	dev_warn(dev, fmt, ...)	device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
131219820Sjeff#define	dev_info(dev, fmt, ...)	device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
132299933Shselasky#define	dev_notice(dev, fmt, ...)	device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
133219820Sjeff#define	dev_printk(lvl, dev, fmt, ...)					\
134219820Sjeff	    device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
135219820Sjeff
136219820Sjeffstatic inline void *
137299933Shselaskydev_get_drvdata(const struct device *dev)
138219820Sjeff{
139219820Sjeff
140219820Sjeff	return dev->driver_data;
141219820Sjeff}
142219820Sjeff
143219820Sjeffstatic inline void
144219820Sjeffdev_set_drvdata(struct device *dev, void *data)
145219820Sjeff{
146219820Sjeff
147219820Sjeff	dev->driver_data = data;
148219820Sjeff}
149219820Sjeff
150219820Sjeffstatic inline struct device *
151219820Sjeffget_device(struct device *dev)
152219820Sjeff{
153219820Sjeff
154219820Sjeff	if (dev)
155219820Sjeff		kobject_get(&dev->kobj);
156219820Sjeff
157219820Sjeff	return (dev);
158219820Sjeff}
159219820Sjeff
160219820Sjeffstatic inline char *
161219820Sjeffdev_name(const struct device *dev)
162219820Sjeff{
163219820Sjeff
164219820Sjeff 	return kobject_name(&dev->kobj);
165219820Sjeff}
166219820Sjeff
167219820Sjeff#define	dev_set_name(_dev, _fmt, ...)					\
168219820Sjeff	kobject_set_name(&(_dev)->kobj, (_fmt), ##__VA_ARGS__)
169219820Sjeff
170219820Sjeffstatic inline void
171219820Sjeffput_device(struct device *dev)
172219820Sjeff{
173219820Sjeff
174219820Sjeff	if (dev)
175219820Sjeff		kobject_put(&dev->kobj);
176219820Sjeff}
177219820Sjeff
178219820Sjeffstatic inline int
179219820Sjeffclass_register(struct class *class)
180219820Sjeff{
181219820Sjeff
182219820Sjeff	class->bsdclass = devclass_create(class->name);
183292987Shselasky	kobject_init(&class->kobj, &linux_class_ktype);
184219820Sjeff	kobject_set_name(&class->kobj, class->name);
185292987Shselasky	kobject_add(&class->kobj, &linux_class_root, class->name);
186219820Sjeff
187219820Sjeff	return (0);
188219820Sjeff}
189219820Sjeff
190219820Sjeffstatic inline void
191219820Sjeffclass_unregister(struct class *class)
192219820Sjeff{
193219820Sjeff
194219820Sjeff	kobject_put(&class->kobj);
195219820Sjeff}
196219820Sjeff
197299933Shselaskystatic inline struct device *kobj_to_dev(struct kobject *kobj)
198299933Shselasky{
199299933Shselasky	return container_of(kobj, struct device, kobj);
200299933Shselasky}
201299933Shselasky
202219820Sjeff/*
203299933Shselasky * Devices are registered and created for exporting to sysfs. Create
204219820Sjeff * implies register and register assumes the device fields have been
205219820Sjeff * setup appropriately before being called.
206219820Sjeff */
207299933Shselaskystatic inline void
208299933Shselaskydevice_initialize(struct device *dev)
209299933Shselasky{
210299933Shselasky	device_t bsddev;
211299933Shselasky
212299933Shselasky	bsddev = NULL;
213299933Shselasky	if (dev->devt) {
214299933Shselasky		int unit = MINOR(dev->devt);
215299933Shselasky		bsddev = devclass_get_device(dev->class->bsdclass, unit);
216299933Shselasky	}
217299933Shselasky	if (bsddev != NULL)
218299933Shselasky		device_set_softc(bsddev, dev);
219299933Shselasky
220299933Shselasky	dev->bsddev = bsddev;
221299933Shselasky	kobject_init(&dev->kobj, &linux_dev_ktype);
222299933Shselasky}
223299933Shselasky
224219820Sjeffstatic inline int
225299933Shselaskydevice_add(struct device *dev)
226299933Shselasky{
227299933Shselasky	if (dev->bsddev != NULL) {
228299933Shselasky		if (dev->devt == 0)
229299933Shselasky			dev->devt = makedev(0, device_get_unit(dev->bsddev));
230299933Shselasky	}
231299933Shselasky	kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev));
232299933Shselasky	return (0);
233299933Shselasky}
234299933Shselasky
235299933Shselaskystatic inline void
236299933Shselaskydevice_create_release(struct device *dev)
237299933Shselasky{
238299933Shselasky	kfree(dev);
239299933Shselasky}
240299933Shselasky
241299933Shselaskystatic inline struct device *
242299933Shselaskydevice_create_groups_vargs(struct class *class, struct device *parent,
243299933Shselasky    dev_t devt, void *drvdata, const struct attribute_group **groups,
244299933Shselasky    const char *fmt, va_list args)
245299933Shselasky{
246299933Shselasky	struct device *dev = NULL;
247299933Shselasky	int retval = -ENODEV;
248299933Shselasky
249299933Shselasky	if (class == NULL || IS_ERR(class))
250299933Shselasky		goto error;
251299933Shselasky
252299933Shselasky	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
253299933Shselasky	if (!dev) {
254299933Shselasky		retval = -ENOMEM;
255299933Shselasky		goto error;
256299933Shselasky	}
257299933Shselasky
258299933Shselasky	device_initialize(dev);
259299933Shselasky	dev->devt = devt;
260299933Shselasky	dev->class = class;
261299933Shselasky	dev->parent = parent;
262299933Shselasky	dev->groups = groups;
263299933Shselasky	dev->release = device_create_release;
264299933Shselasky	dev->bsddev = devclass_get_device(dev->class->bsdclass, MINOR(devt));
265299933Shselasky	dev_set_drvdata(dev, drvdata);
266299933Shselasky
267299933Shselasky	retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
268299933Shselasky	if (retval)
269299933Shselasky		goto error;
270299933Shselasky
271299933Shselasky	retval = device_add(dev);
272299933Shselasky	if (retval)
273299933Shselasky		goto error;
274299933Shselasky
275299933Shselasky	return dev;
276299933Shselasky
277299933Shselaskyerror:
278299933Shselasky	put_device(dev);
279299933Shselasky	return ERR_PTR(retval);
280299933Shselasky}
281299933Shselasky
282299933Shselaskystatic inline struct device *
283299933Shselaskydevice_create_with_groups(struct class *class,
284299933Shselasky    struct device *parent, dev_t devt, void *drvdata,
285299933Shselasky    const struct attribute_group **groups, const char *fmt, ...)
286299933Shselasky{
287299933Shselasky	va_list vargs;
288299933Shselasky	struct device *dev;
289299933Shselasky
290299933Shselasky	va_start(vargs, fmt);
291299933Shselasky	dev = device_create_groups_vargs(class, parent, devt, drvdata,
292299933Shselasky	    groups, fmt, vargs);
293299933Shselasky	va_end(vargs);
294299933Shselasky	return dev;
295299933Shselasky}
296299933Shselasky
297299933Shselaskystatic inline int
298219820Sjeffdevice_register(struct device *dev)
299219820Sjeff{
300219820Sjeff	device_t bsddev;
301219820Sjeff	int unit;
302219820Sjeff
303219820Sjeff	bsddev = NULL;
304299674Shselasky	unit = -1;
305299674Shselasky
306219820Sjeff	if (dev->devt) {
307219820Sjeff		unit = MINOR(dev->devt);
308219820Sjeff		bsddev = devclass_get_device(dev->class->bsdclass, unit);
309299674Shselasky	} else if (dev->parent == NULL) {
310299674Shselasky		bsddev = devclass_get_device(dev->class->bsdclass, 0);
311299674Shselasky	}
312299931Shselasky	if (bsddev == NULL && dev->parent != NULL) {
313219820Sjeff		bsddev = device_add_child(dev->parent->bsddev,
314219820Sjeff		    dev->class->kobj.name, unit);
315299931Shselasky	}
316299931Shselasky	if (bsddev != NULL) {
317219820Sjeff		if (dev->devt == 0)
318219820Sjeff			dev->devt = makedev(0, device_get_unit(bsddev));
319219820Sjeff		device_set_softc(bsddev, dev);
320219820Sjeff	}
321219820Sjeff	dev->bsddev = bsddev;
322292987Shselasky	kobject_init(&dev->kobj, &linux_dev_ktype);
323219820Sjeff	kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev));
324219820Sjeff
325219820Sjeff	return (0);
326219820Sjeff}
327219820Sjeff
328219820Sjeffstatic inline void
329219820Sjeffdevice_unregister(struct device *dev)
330219820Sjeff{
331219820Sjeff	device_t bsddev;
332219820Sjeff
333219820Sjeff	bsddev = dev->bsddev;
334299933Shselasky	dev->bsddev = NULL;
335299933Shselasky
336299960Shselasky	if (bsddev != NULL) {
337299960Shselasky		mtx_lock(&Giant);
338219820Sjeff		device_delete_child(device_get_parent(bsddev), bsddev);
339299960Shselasky		mtx_unlock(&Giant);
340299960Shselasky	}
341219820Sjeff	put_device(dev);
342219820Sjeff}
343219820Sjeff
344299933Shselaskystatic inline void
345299933Shselaskydevice_del(struct device *dev)
346299933Shselasky{
347299933Shselasky	device_t bsddev;
348299933Shselasky
349299933Shselasky	bsddev = dev->bsddev;
350299933Shselasky	dev->bsddev = NULL;
351299933Shselasky
352299960Shselasky	if (bsddev != NULL) {
353299960Shselasky		mtx_lock(&Giant);
354299933Shselasky		device_delete_child(device_get_parent(bsddev), bsddev);
355299960Shselasky		mtx_unlock(&Giant);
356299960Shselasky	}
357299933Shselasky}
358299933Shselasky
359219820Sjeffstruct device *device_create(struct class *class, struct device *parent,
360219820Sjeff	    dev_t devt, void *drvdata, const char *fmt, ...);
361219820Sjeff
362219820Sjeffstatic inline void
363219820Sjeffdevice_destroy(struct class *class, dev_t devt)
364219820Sjeff{
365219820Sjeff	device_t bsddev;
366219820Sjeff	int unit;
367219820Sjeff
368219820Sjeff	unit = MINOR(devt);
369219820Sjeff	bsddev = devclass_get_device(class->bsdclass, unit);
370299933Shselasky	if (bsddev != NULL)
371219820Sjeff		device_unregister(device_get_softc(bsddev));
372219820Sjeff}
373219820Sjeff
374219820Sjeffstatic inline void
375292987Shselaskylinux_class_kfree(struct class *class)
376219820Sjeff{
377219820Sjeff
378219820Sjeff	kfree(class);
379219820Sjeff}
380219820Sjeff
381219820Sjeffstatic inline struct class *
382219820Sjeffclass_create(struct module *owner, const char *name)
383219820Sjeff{
384219820Sjeff	struct class *class;
385219820Sjeff	int error;
386219820Sjeff
387219820Sjeff	class = kzalloc(sizeof(*class), M_WAITOK);
388219820Sjeff	class->owner = owner;
389219820Sjeff	class->name= name;
390292987Shselasky	class->class_release = linux_class_kfree;
391219820Sjeff	error = class_register(class);
392219820Sjeff	if (error) {
393219820Sjeff		kfree(class);
394219820Sjeff		return (NULL);
395219820Sjeff	}
396219820Sjeff
397219820Sjeff	return (class);
398219820Sjeff}
399219820Sjeff
400219820Sjeffstatic inline void
401219820Sjeffclass_destroy(struct class *class)
402219820Sjeff{
403219820Sjeff
404219820Sjeff	if (class == NULL)
405219820Sjeff		return;
406219820Sjeff	class_unregister(class);
407219820Sjeff}
408219820Sjeff
409219820Sjeffstatic inline int
410219820Sjeffdevice_create_file(struct device *dev, const struct device_attribute *attr)
411219820Sjeff{
412219820Sjeff
413219820Sjeff	if (dev)
414219820Sjeff		return sysfs_create_file(&dev->kobj, &attr->attr);
415219820Sjeff	return -EINVAL;
416219820Sjeff}
417219820Sjeff
418219820Sjeffstatic inline void
419219820Sjeffdevice_remove_file(struct device *dev, const struct device_attribute *attr)
420219820Sjeff{
421219820Sjeff
422219820Sjeff	if (dev)
423219820Sjeff		sysfs_remove_file(&dev->kobj, &attr->attr);
424219820Sjeff}
425219820Sjeff
426219820Sjeffstatic inline int
427219820Sjeffclass_create_file(struct class *class, const struct class_attribute *attr)
428219820Sjeff{
429219820Sjeff
430219820Sjeff	if (class)
431219820Sjeff		return sysfs_create_file(&class->kobj, &attr->attr);
432219820Sjeff	return -EINVAL;
433219820Sjeff}
434219820Sjeff
435219820Sjeffstatic inline void
436219820Sjeffclass_remove_file(struct class *class, const struct class_attribute *attr)
437219820Sjeff{
438219820Sjeff
439219820Sjeff	if (class)
440219820Sjeff		sysfs_remove_file(&class->kobj, &attr->attr);
441219820Sjeff}
442219820Sjeff
443292987Shselaskystatic inline int
444292987Shselaskydev_to_node(struct device *dev)
445255932Salfred{
446255932Salfred                return -1;
447255932Salfred}
448255932Salfred
449285088Shselaskychar *kvasprintf(gfp_t, const char *, va_list);
450278865Shselaskychar *kasprintf(gfp_t, const char *, ...);
451270710Shselasky
452219820Sjeff#endif	/* _LINUX_DEVICE_H_ */
453