device.h revision 219820
1219820Sjeff/*-
2219820Sjeff * Copyright (c) 2010 Isilon Systems, Inc.
3219820Sjeff * Copyright (c) 2010 iX Systems, Inc.
4219820Sjeff * Copyright (c) 2010 Panasas, Inc.
5219820Sjeff * All rights reserved.
6219820Sjeff *
7219820Sjeff * Redistribution and use in source and binary forms, with or without
8219820Sjeff * modification, are permitted provided that the following conditions
9219820Sjeff * are met:
10219820Sjeff * 1. Redistributions of source code must retain the above copyright
11219820Sjeff *    notice unmodified, this list of conditions, and the following
12219820Sjeff *    disclaimer.
13219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
14219820Sjeff *    notice, this list of conditions and the following disclaimer in the
15219820Sjeff *    documentation and/or other materials provided with the distribution.
16219820Sjeff *
17219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27219820Sjeff */
28219820Sjeff#ifndef	_LINUX_DEVICE_H_
29219820Sjeff#define	_LINUX_DEVICE_H_
30219820Sjeff
31219820Sjeff#include <linux/types.h>
32219820Sjeff#include <linux/kobject.h>
33219820Sjeff#include <linux/list.h>
34219820Sjeff#include <linux/compiler.h>
35219820Sjeff#include <linux/types.h>
36219820Sjeff#include <linux/module.h>
37219820Sjeff#include <linux/workqueue.h>
38219820Sjeff#include <linux/sysfs.h>
39219820Sjeff#include <linux/kdev_t.h>
40219820Sjeff#include <asm/atomic.h>
41219820Sjeff
42219820Sjeff#include <sys/bus.h>
43219820Sjeff
44219820Sjeffenum irqreturn	{ IRQ_NONE = 0, IRQ_HANDLED, IRQ_WAKE_THREAD, };
45219820Sjefftypedef enum irqreturn	irqreturn_t;
46219820Sjeff
47219820Sjeffstruct class {
48219820Sjeff	const char	*name;
49219820Sjeff	struct module	*owner;
50219820Sjeff	struct kobject	kobj;
51219820Sjeff	devclass_t	bsdclass;
52219820Sjeff	void		(*class_release)(struct class *class);
53219820Sjeff	void		(*dev_release)(struct device *dev);
54219820Sjeff};
55219820Sjeff
56219820Sjeffstruct device {
57219820Sjeff	struct device	*parent;
58219820Sjeff	struct list_head irqents;
59219820Sjeff	device_t	bsddev;
60219820Sjeff	dev_t		devt;
61219820Sjeff	struct class	*class;
62219820Sjeff	void		(*release)(struct device *dev);
63219820Sjeff	struct kobject	kobj;
64219820Sjeff	uint64_t	*dma_mask;
65219820Sjeff	void		*driver_data;
66219820Sjeff	unsigned int	irq;
67219820Sjeff	unsigned int	msix;
68219820Sjeff	unsigned int	msix_max;
69219820Sjeff};
70219820Sjeff
71219820Sjeffextern struct device linux_rootdev;
72219820Sjeffextern struct kobject class_root;
73219820Sjeff
74219820Sjeffstruct class_attribute {
75219820Sjeff	struct attribute	attr;
76219820Sjeff        ssize_t			(*show)(struct class *, char *);
77219820Sjeff        ssize_t			(*store)(struct class *, const char *, size_t);
78219820Sjeff};
79219820Sjeff#define	CLASS_ATTR(_name, _mode, _show, _store)				\
80219820Sjeff	struct class_attribute class_attr_##_name =			\
81219820Sjeff	    { { #_name, NULL, _mode }, _show, _store }
82219820Sjeff
83219820Sjeffstruct device_attribute {
84219820Sjeff	struct attribute	attr;
85219820Sjeff	ssize_t			(*show)(struct device *,
86219820Sjeff				    struct device_attribute *, char *);
87219820Sjeff	ssize_t			(*store)(struct device *,
88219820Sjeff				    struct device_attribute *, const char *,
89219820Sjeff				    size_t);
90219820Sjeff};
91219820Sjeff
92219820Sjeff#define	DEVICE_ATTR(_name, _mode, _show, _store)			\
93219820Sjeff	struct device_attribute dev_attr_##_name =			\
94219820Sjeff	    { { #_name, NULL, _mode }, _show, _store }
95219820Sjeff
96219820Sjeff#define	dev_err(dev, fmt, ...)	device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
97219820Sjeff#define	dev_warn(dev, fmt, ...)	device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
98219820Sjeff#define	dev_info(dev, fmt, ...)	device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
99219820Sjeff#define	dev_printk(lvl, dev, fmt, ...)					\
100219820Sjeff	    device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
101219820Sjeff
102219820Sjeffstatic inline void *
103219820Sjeffdev_get_drvdata(struct device *dev)
104219820Sjeff{
105219820Sjeff
106219820Sjeff	return dev->driver_data;
107219820Sjeff}
108219820Sjeff
109219820Sjeffstatic inline void
110219820Sjeffdev_set_drvdata(struct device *dev, void *data)
111219820Sjeff{
112219820Sjeff
113219820Sjeff	dev->driver_data = data;
114219820Sjeff}
115219820Sjeff
116219820Sjeffstatic inline struct device *
117219820Sjeffget_device(struct device *dev)
118219820Sjeff{
119219820Sjeff
120219820Sjeff	if (dev)
121219820Sjeff		kobject_get(&dev->kobj);
122219820Sjeff
123219820Sjeff	return (dev);
124219820Sjeff}
125219820Sjeff
126219820Sjeffstatic inline char *
127219820Sjeffdev_name(const struct device *dev)
128219820Sjeff{
129219820Sjeff
130219820Sjeff 	return kobject_name(&dev->kobj);
131219820Sjeff}
132219820Sjeff
133219820Sjeff#define	dev_set_name(_dev, _fmt, ...)					\
134219820Sjeff	kobject_set_name(&(_dev)->kobj, (_fmt), ##__VA_ARGS__)
135219820Sjeff
136219820Sjeffstatic inline void
137219820Sjeffput_device(struct device *dev)
138219820Sjeff{
139219820Sjeff
140219820Sjeff	if (dev)
141219820Sjeff		kobject_put(&dev->kobj);
142219820Sjeff}
143219820Sjeff
144219820Sjeffstatic inline ssize_t
145219820Sjeffclass_show(struct kobject *kobj, struct attribute *attr, char *buf)
146219820Sjeff{
147219820Sjeff	struct class_attribute *dattr;
148219820Sjeff	ssize_t error;
149219820Sjeff
150219820Sjeff	dattr = container_of(attr, struct class_attribute, attr);
151219820Sjeff	error = -EIO;
152219820Sjeff	if (dattr->show)
153219820Sjeff		error = dattr->show(container_of(kobj, struct class, kobj),
154219820Sjeff		    buf);
155219820Sjeff	return (error);
156219820Sjeff}
157219820Sjeff
158219820Sjeffstatic inline ssize_t
159219820Sjeffclass_store(struct kobject *kobj, struct attribute *attr, const char *buf,
160219820Sjeff    size_t count)
161219820Sjeff{
162219820Sjeff	struct class_attribute *dattr;
163219820Sjeff	ssize_t error;
164219820Sjeff
165219820Sjeff	dattr = container_of(attr, struct class_attribute, attr);
166219820Sjeff	error = -EIO;
167219820Sjeff	if (dattr->store)
168219820Sjeff		error = dattr->store(container_of(kobj, struct class, kobj),
169219820Sjeff		    buf, count);
170219820Sjeff	return (error);
171219820Sjeff}
172219820Sjeff
173219820Sjeffstatic inline void
174219820Sjeffclass_release(struct kobject *kobj)
175219820Sjeff{
176219820Sjeff	struct class *class;
177219820Sjeff
178219820Sjeff	class = container_of(kobj, struct class, kobj);
179219820Sjeff	if (class->class_release)
180219820Sjeff		class->class_release(class);
181219820Sjeff}
182219820Sjeff
183219820Sjeffstatic struct sysfs_ops class_sysfs = {
184219820Sjeff	.show  = class_show,
185219820Sjeff	.store = class_store,
186219820Sjeff};
187219820Sjeffstatic struct kobj_type class_ktype = {
188219820Sjeff	.release = class_release,
189219820Sjeff	.sysfs_ops = &class_sysfs
190219820Sjeff};
191219820Sjeff
192219820Sjeffstatic inline int
193219820Sjeffclass_register(struct class *class)
194219820Sjeff{
195219820Sjeff
196219820Sjeff	class->bsdclass = devclass_create(class->name);
197219820Sjeff	kobject_init(&class->kobj, &class_ktype);
198219820Sjeff	kobject_set_name(&class->kobj, class->name);
199219820Sjeff	kobject_add(&class->kobj, &class_root, class->name);
200219820Sjeff
201219820Sjeff	return (0);
202219820Sjeff}
203219820Sjeff
204219820Sjeffstatic inline void
205219820Sjeffclass_unregister(struct class *class)
206219820Sjeff{
207219820Sjeff
208219820Sjeff	kobject_put(&class->kobj);
209219820Sjeff}
210219820Sjeff
211219820Sjeffstatic inline void
212219820Sjeffdevice_release(struct kobject *kobj)
213219820Sjeff{
214219820Sjeff	struct device *dev;
215219820Sjeff
216219820Sjeff	dev = container_of(kobj, struct device, kobj);
217219820Sjeff	/* This is the precedence defined by linux. */
218219820Sjeff	if (dev->release)
219219820Sjeff		dev->release(dev);
220219820Sjeff	else if (dev->class && dev->class->dev_release)
221219820Sjeff		dev->class->dev_release(dev);
222219820Sjeff}
223219820Sjeff
224219820Sjeffstatic inline ssize_t
225219820Sjeffdev_show(struct kobject *kobj, struct attribute *attr, char *buf)
226219820Sjeff{
227219820Sjeff	struct device_attribute *dattr;
228219820Sjeff	ssize_t error;
229219820Sjeff
230219820Sjeff	dattr = container_of(attr, struct device_attribute, attr);
231219820Sjeff	error = -EIO;
232219820Sjeff	if (dattr->show)
233219820Sjeff		error = dattr->show(container_of(kobj, struct device, kobj),
234219820Sjeff		    dattr, buf);
235219820Sjeff	return (error);
236219820Sjeff}
237219820Sjeff
238219820Sjeffstatic inline ssize_t
239219820Sjeffdev_store(struct kobject *kobj, struct attribute *attr, const char *buf,
240219820Sjeff    size_t count)
241219820Sjeff{
242219820Sjeff	struct device_attribute *dattr;
243219820Sjeff	ssize_t error;
244219820Sjeff
245219820Sjeff	dattr = container_of(attr, struct device_attribute, attr);
246219820Sjeff	error = -EIO;
247219820Sjeff	if (dattr->store)
248219820Sjeff		error = dattr->store(container_of(kobj, struct device, kobj),
249219820Sjeff		    dattr, buf, count);
250219820Sjeff	return (error);
251219820Sjeff}
252219820Sjeff
253219820Sjeffstatic struct sysfs_ops dev_sysfs = { .show  = dev_show, .store = dev_store, };
254219820Sjeffstatic struct kobj_type dev_ktype = {
255219820Sjeff	.release = device_release,
256219820Sjeff	.sysfs_ops = &dev_sysfs
257219820Sjeff};
258219820Sjeff
259219820Sjeff/*
260219820Sjeff * Devices are registered and created for exporting to sysfs.  create
261219820Sjeff * implies register and register assumes the device fields have been
262219820Sjeff * setup appropriately before being called.
263219820Sjeff */
264219820Sjeffstatic inline int
265219820Sjeffdevice_register(struct device *dev)
266219820Sjeff{
267219820Sjeff	device_t bsddev;
268219820Sjeff	int unit;
269219820Sjeff
270219820Sjeff	bsddev = NULL;
271219820Sjeff	if (dev->devt) {
272219820Sjeff		unit = MINOR(dev->devt);
273219820Sjeff		bsddev = devclass_get_device(dev->class->bsdclass, unit);
274219820Sjeff	} else
275219820Sjeff		unit = -1;
276219820Sjeff	if (bsddev == NULL)
277219820Sjeff		bsddev = device_add_child(dev->parent->bsddev,
278219820Sjeff		    dev->class->kobj.name, unit);
279219820Sjeff	if (bsddev) {
280219820Sjeff		if (dev->devt == 0)
281219820Sjeff			dev->devt = makedev(0, device_get_unit(bsddev));
282219820Sjeff		device_set_softc(bsddev, dev);
283219820Sjeff	}
284219820Sjeff	dev->bsddev = bsddev;
285219820Sjeff	kobject_init(&dev->kobj, &dev_ktype);
286219820Sjeff	kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev));
287219820Sjeff
288219820Sjeff	return (0);
289219820Sjeff}
290219820Sjeff
291219820Sjeffstatic inline void
292219820Sjeffdevice_unregister(struct device *dev)
293219820Sjeff{
294219820Sjeff	device_t bsddev;
295219820Sjeff
296219820Sjeff	bsddev = dev->bsddev;
297219820Sjeff	mtx_lock(&Giant);
298219820Sjeff	if (bsddev)
299219820Sjeff		device_delete_child(device_get_parent(bsddev), bsddev);
300219820Sjeff	mtx_unlock(&Giant);
301219820Sjeff	put_device(dev);
302219820Sjeff}
303219820Sjeff
304219820Sjeffstruct device *device_create(struct class *class, struct device *parent,
305219820Sjeff	    dev_t devt, void *drvdata, const char *fmt, ...);
306219820Sjeff
307219820Sjeffstatic inline void
308219820Sjeffdevice_destroy(struct class *class, dev_t devt)
309219820Sjeff{
310219820Sjeff	device_t bsddev;
311219820Sjeff	int unit;
312219820Sjeff
313219820Sjeff	unit = MINOR(devt);
314219820Sjeff	bsddev = devclass_get_device(class->bsdclass, unit);
315219820Sjeff	if (bsddev)
316219820Sjeff		device_unregister(device_get_softc(bsddev));
317219820Sjeff}
318219820Sjeff
319219820Sjeffstatic inline void
320219820Sjeffclass_kfree(struct class *class)
321219820Sjeff{
322219820Sjeff
323219820Sjeff	kfree(class);
324219820Sjeff}
325219820Sjeff
326219820Sjeffstatic inline struct class *
327219820Sjeffclass_create(struct module *owner, const char *name)
328219820Sjeff{
329219820Sjeff	struct class *class;
330219820Sjeff	int error;
331219820Sjeff
332219820Sjeff	class = kzalloc(sizeof(*class), M_WAITOK);
333219820Sjeff	class->owner = owner;
334219820Sjeff	class->name= name;
335219820Sjeff	class->class_release = class_kfree;
336219820Sjeff	error = class_register(class);
337219820Sjeff	if (error) {
338219820Sjeff		kfree(class);
339219820Sjeff		return (NULL);
340219820Sjeff	}
341219820Sjeff
342219820Sjeff	return (class);
343219820Sjeff}
344219820Sjeff
345219820Sjeffstatic inline void
346219820Sjeffclass_destroy(struct class *class)
347219820Sjeff{
348219820Sjeff
349219820Sjeff	if (class == NULL)
350219820Sjeff		return;
351219820Sjeff	class_unregister(class);
352219820Sjeff}
353219820Sjeff
354219820Sjeffstatic inline int
355219820Sjeffdevice_create_file(struct device *dev, const struct device_attribute *attr)
356219820Sjeff{
357219820Sjeff
358219820Sjeff	if (dev)
359219820Sjeff		return sysfs_create_file(&dev->kobj, &attr->attr);
360219820Sjeff	return -EINVAL;
361219820Sjeff}
362219820Sjeff
363219820Sjeffstatic inline void
364219820Sjeffdevice_remove_file(struct device *dev, const struct device_attribute *attr)
365219820Sjeff{
366219820Sjeff
367219820Sjeff	if (dev)
368219820Sjeff		sysfs_remove_file(&dev->kobj, &attr->attr);
369219820Sjeff}
370219820Sjeff
371219820Sjeffstatic inline int
372219820Sjeffclass_create_file(struct class *class, const struct class_attribute *attr)
373219820Sjeff{
374219820Sjeff
375219820Sjeff	if (class)
376219820Sjeff		return sysfs_create_file(&class->kobj, &attr->attr);
377219820Sjeff	return -EINVAL;
378219820Sjeff}
379219820Sjeff
380219820Sjeffstatic inline void
381219820Sjeffclass_remove_file(struct class *class, const struct class_attribute *attr)
382219820Sjeff{
383219820Sjeff
384219820Sjeff	if (class)
385219820Sjeff		sysfs_remove_file(&class->kobj, &attr->attr);
386219820Sjeff}
387219820Sjeff
388219820Sjeff#endif	/* _LINUX_DEVICE_H_ */
389