1 /**
2  * System devices follow a slightly different driver model.
3  * They don't need to do dynammic driver binding, can't be probed,
4  * and don't reside on any type of peripheral bus.
5  * So, we represent and treat them a little differently.
6  *
7  * We still have a notion of a driver for a system device, because we still
8  * want to perform basic operations on these devices.
9  *
10  * We also support auxiliary drivers binding to devices of a certain class.
11  *
12  * This allows configurable drivers to register themselves for devices of
13  * a certain type. And, it allows class definitions to reside in generic
14  * code while arch-specific code can register specific drivers.
15  *
16  * Auxiliary drivers registered with a NULL cls are registered as drivers
17  * for all system devices, and get notification calls for each device.
18  */
19 
20 
21 #ifndef _SYSDEV_H_
22 #define _SYSDEV_H_
23 
24 #include <linux/kobject.h>
25 #include <linux/module.h>
26 #include <linux/pm.h>
27 
28 
29 struct sys_device;
30 struct sysdev_class_attribute;
31 
32 struct sysdev_class {
33 	const char *name;
34 	struct list_head	drivers;
35 	struct sysdev_class_attribute **attrs;
36 	struct kset		kset;
37 #ifndef CONFIG_ARCH_NO_SYSDEV_OPS
38 	/* Default operations for these types of devices */
39 	int	(*shutdown)(struct sys_device *);
40 	int	(*suspend)(struct sys_device *, pm_message_t state);
41 	int	(*resume)(struct sys_device *);
42 #endif
43 };
44 
45 struct sysdev_class_attribute {
46 	struct attribute attr;
47 	ssize_t (*show)(struct sysdev_class *, struct sysdev_class_attribute *,
48 			char *);
49 	ssize_t (*store)(struct sysdev_class *, struct sysdev_class_attribute *,
50 			 const char *, size_t);
51 };
52 
53 #define _SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) 		\
54 {					 			\
55 	.attr = {.name = __stringify(_name), .mode = _mode },	\
56 	.show	= _show,					\
57 	.store	= _store,					\
58 }
59 
60 #define SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) 		\
61 	struct sysdev_class_attribute attr_##_name = 		\
62 		_SYSDEV_CLASS_ATTR(_name,_mode,_show,_store)
63 
64 
65 extern int sysdev_class_register(struct sysdev_class *);
66 extern void sysdev_class_unregister(struct sysdev_class *);
67 
68 extern int sysdev_class_create_file(struct sysdev_class *,
69 	struct sysdev_class_attribute *);
70 extern void sysdev_class_remove_file(struct sysdev_class *,
71 	struct sysdev_class_attribute *);
72 /**
73  * Auxiliary system device drivers.
74  */
75 
76 struct sysdev_driver {
77 	struct list_head	entry;
78 	int	(*add)(struct sys_device *);
79 	int	(*remove)(struct sys_device *);
80 #ifndef CONFIG_ARCH_NO_SYSDEV_OPS
81 	int	(*shutdown)(struct sys_device *);
82 	int	(*suspend)(struct sys_device *, pm_message_t state);
83 	int	(*resume)(struct sys_device *);
84 #endif
85 };
86 
87 
88 extern int sysdev_driver_register(struct sysdev_class *, struct sysdev_driver *);
89 extern void sysdev_driver_unregister(struct sysdev_class *, struct sysdev_driver *);
90 
91 
92 /**
93  * sys_devices can be simplified a lot from regular devices, because they're
94  * simply not as versatile.
95  */
96 
97 struct sys_device {
98 	u32		id;
99 	struct sysdev_class	* cls;
100 	struct kobject		kobj;
101 };
102 
103 extern int sysdev_register(struct sys_device *);
104 extern void sysdev_unregister(struct sys_device *);
105 
106 
107 struct sysdev_attribute {
108 	struct attribute	attr;
109 	ssize_t (*show)(struct sys_device *, struct sysdev_attribute *, char *);
110 	ssize_t (*store)(struct sys_device *, struct sysdev_attribute *,
111 			 const char *, size_t);
112 };
113 
114 
115 #define _SYSDEV_ATTR(_name, _mode, _show, _store)		\
116 {								\
117 	.attr = { .name = __stringify(_name), .mode = _mode },	\
118 	.show	= _show,					\
119 	.store	= _store,					\
120 }
121 
122 #define SYSDEV_ATTR(_name, _mode, _show, _store)		\
123 	struct sysdev_attribute attr_##_name =			\
124 		_SYSDEV_ATTR(_name, _mode, _show, _store);
125 
126 extern int sysdev_create_file(struct sys_device *, struct sysdev_attribute *);
127 extern void sysdev_remove_file(struct sys_device *, struct sysdev_attribute *);
128 
129 /* Create/remove NULL terminated attribute list */
130 static inline int
sysdev_create_files(struct sys_device * d,struct sysdev_attribute ** a)131 sysdev_create_files(struct sys_device *d, struct sysdev_attribute **a)
132 {
133 	return sysfs_create_files(&d->kobj, (const struct attribute **)a);
134 }
135 
136 static inline void
sysdev_remove_files(struct sys_device * d,struct sysdev_attribute ** a)137 sysdev_remove_files(struct sys_device *d, struct sysdev_attribute **a)
138 {
139 	return sysfs_remove_files(&d->kobj, (const struct attribute **)a);
140 }
141 
142 struct sysdev_ext_attribute {
143 	struct sysdev_attribute attr;
144 	void *var;
145 };
146 
147 /*
148  * Support for simple variable sysdev attributes.
149  * The pointer to the variable is stored in a sysdev_ext_attribute
150  */
151 
152 /* Add more types as needed */
153 
154 extern ssize_t sysdev_show_ulong(struct sys_device *, struct sysdev_attribute *,
155 				char *);
156 extern ssize_t sysdev_store_ulong(struct sys_device *,
157 			struct sysdev_attribute *, const char *, size_t);
158 extern ssize_t sysdev_show_int(struct sys_device *, struct sysdev_attribute *,
159 				char *);
160 extern ssize_t sysdev_store_int(struct sys_device *,
161 			struct sysdev_attribute *, const char *, size_t);
162 
163 #define _SYSDEV_ULONG_ATTR(_name, _mode, _var)				\
164 	{ _SYSDEV_ATTR(_name, _mode, sysdev_show_ulong, sysdev_store_ulong), \
165 	  &(_var) }
166 #define SYSDEV_ULONG_ATTR(_name, _mode, _var)			\
167 	struct sysdev_ext_attribute attr_##_name = 		\
168 		_SYSDEV_ULONG_ATTR(_name, _mode, _var);
169 #define _SYSDEV_INT_ATTR(_name, _mode, _var)				\
170 	{ _SYSDEV_ATTR(_name, _mode, sysdev_show_int, sysdev_store_int), \
171 	  &(_var) }
172 #define SYSDEV_INT_ATTR(_name, _mode, _var)			\
173 	struct sysdev_ext_attribute attr_##_name = 		\
174 		_SYSDEV_INT_ATTR(_name, _mode, _var);
175 
176 #endif /* _SYSDEV_H_ */
177