| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 auxillary 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 |  * Auxillary 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> | 
| Ralf Baechle | 3367b99 | 2007-05-08 00:27:52 -0700 | [diff] [blame] | 25 | #include <linux/module.h> | 
| Pavel Machek | 438510f | 2005-04-16 15:25:24 -0700 | [diff] [blame] | 26 | #include <linux/pm.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 27 |  | 
 | 28 |  | 
 | 29 | struct sys_device; | 
| Andi Kleen | 38457ab | 2010-01-05 12:48:02 +0100 | [diff] [blame] | 30 | struct sysdev_class_attribute; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 |  | 
 | 32 | struct sysdev_class { | 
| Kay Sievers | af5ca3f | 2007-12-20 02:09:39 +0100 | [diff] [blame] | 33 | 	const char *name; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 34 | 	struct list_head	drivers; | 
| Andi Kleen | 38457ab | 2010-01-05 12:48:02 +0100 | [diff] [blame] | 35 | 	struct sysdev_class_attribute **attrs; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 |  | 
 | 37 | 	/* Default operations for these types of devices */ | 
 | 38 | 	int	(*shutdown)(struct sys_device *); | 
| Pavel Machek | 438510f | 2005-04-16 15:25:24 -0700 | [diff] [blame] | 39 | 	int	(*suspend)(struct sys_device *, pm_message_t state); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 40 | 	int	(*resume)(struct sys_device *); | 
 | 41 | 	struct kset		kset; | 
 | 42 | }; | 
 | 43 |  | 
| Shaohua Li | 670dd90 | 2006-05-08 13:45:57 +0800 | [diff] [blame] | 44 | struct sysdev_class_attribute { | 
 | 45 | 	struct attribute attr; | 
| Andi Kleen | c9be0a3 | 2010-01-05 12:47:58 +0100 | [diff] [blame] | 46 | 	ssize_t (*show)(struct sysdev_class *, struct sysdev_class_attribute *, | 
 | 47 | 			char *); | 
 | 48 | 	ssize_t (*store)(struct sysdev_class *, struct sysdev_class_attribute *, | 
 | 49 | 			 const char *, size_t); | 
| Shaohua Li | 670dd90 | 2006-05-08 13:45:57 +0800 | [diff] [blame] | 50 | }; | 
 | 51 |  | 
| Mike Travis | 9d1fe32 | 2008-04-08 11:43:04 -0700 | [diff] [blame] | 52 | #define _SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) 		\ | 
 | 53 | {					 			\ | 
| Shaohua Li | 670dd90 | 2006-05-08 13:45:57 +0800 | [diff] [blame] | 54 | 	.attr = {.name = __stringify(_name), .mode = _mode },	\ | 
 | 55 | 	.show	= _show,					\ | 
 | 56 | 	.store	= _store,					\ | 
| Mike Travis | 9d1fe32 | 2008-04-08 11:43:04 -0700 | [diff] [blame] | 57 | } | 
 | 58 |  | 
 | 59 | #define SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) 		\ | 
 | 60 | 	struct sysdev_class_attribute attr_##_name = 		\ | 
 | 61 | 		_SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) | 
| Shaohua Li | 670dd90 | 2006-05-08 13:45:57 +0800 | [diff] [blame] | 62 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 |  | 
 | 64 | extern int sysdev_class_register(struct sysdev_class *); | 
 | 65 | extern void sysdev_class_unregister(struct sysdev_class *); | 
 | 66 |  | 
| Shaohua Li | 670dd90 | 2006-05-08 13:45:57 +0800 | [diff] [blame] | 67 | extern int sysdev_class_create_file(struct sysdev_class *, | 
 | 68 | 	struct sysdev_class_attribute *); | 
 | 69 | extern void sysdev_class_remove_file(struct sysdev_class *, | 
 | 70 | 	struct sysdev_class_attribute *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 71 | /** | 
 | 72 |  * Auxillary system device drivers. | 
 | 73 |  */ | 
 | 74 |  | 
 | 75 | struct sysdev_driver { | 
 | 76 | 	struct list_head	entry; | 
 | 77 | 	int	(*add)(struct sys_device *); | 
 | 78 | 	int	(*remove)(struct sys_device *); | 
 | 79 | 	int	(*shutdown)(struct sys_device *); | 
| Pavel Machek | 438510f | 2005-04-16 15:25:24 -0700 | [diff] [blame] | 80 | 	int	(*suspend)(struct sys_device *, pm_message_t state); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 | 	int	(*resume)(struct sys_device *); | 
 | 82 | }; | 
 | 83 |  | 
 | 84 |  | 
 | 85 | extern int sysdev_driver_register(struct sysdev_class *, struct sysdev_driver *); | 
 | 86 | extern void sysdev_driver_unregister(struct sysdev_class *, struct sysdev_driver *); | 
 | 87 |  | 
 | 88 |  | 
 | 89 | /** | 
 | 90 |  * sys_devices can be simplified a lot from regular devices, because they're | 
 | 91 |  * simply not as versatile.  | 
 | 92 |  */ | 
 | 93 |  | 
 | 94 | struct sys_device { | 
 | 95 | 	u32		id; | 
 | 96 | 	struct sysdev_class	* cls; | 
 | 97 | 	struct kobject		kobj; | 
 | 98 | }; | 
 | 99 |  | 
 | 100 | extern int sysdev_register(struct sys_device *); | 
 | 101 | extern void sysdev_unregister(struct sys_device *); | 
 | 102 |  | 
 | 103 |  | 
 | 104 | struct sysdev_attribute {  | 
 | 105 | 	struct attribute	attr; | 
| Andi Kleen | 4a0b2b4 | 2008-07-01 18:48:41 +0200 | [diff] [blame] | 106 | 	ssize_t (*show)(struct sys_device *, struct sysdev_attribute *, char *); | 
 | 107 | 	ssize_t (*store)(struct sys_device *, struct sysdev_attribute *, | 
 | 108 | 			 const char *, size_t); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 109 | }; | 
 | 110 |  | 
 | 111 |  | 
| Mike Travis | 9d1fe32 | 2008-04-08 11:43:04 -0700 | [diff] [blame] | 112 | #define _SYSDEV_ATTR(_name, _mode, _show, _store)		\ | 
| Olof Johansson | 7583b6e | 2007-01-28 21:24:57 -0600 | [diff] [blame] | 113 | {								\ | 
| Tejun Heo | 7b59575 | 2007-06-14 03:45:17 +0900 | [diff] [blame] | 114 | 	.attr = { .name = __stringify(_name), .mode = _mode },	\ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 115 | 	.show	= _show,					\ | 
 | 116 | 	.store	= _store,					\ | 
| Olof Johansson | 7583b6e | 2007-01-28 21:24:57 -0600 | [diff] [blame] | 117 | } | 
 | 118 |  | 
| Mike Travis | 9d1fe32 | 2008-04-08 11:43:04 -0700 | [diff] [blame] | 119 | #define SYSDEV_ATTR(_name, _mode, _show, _store)		\ | 
 | 120 | 	struct sysdev_attribute attr_##_name =			\ | 
 | 121 | 		_SYSDEV_ATTR(_name, _mode, _show, _store); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 |  | 
 | 123 | extern int sysdev_create_file(struct sys_device *, struct sysdev_attribute *); | 
 | 124 | extern void sysdev_remove_file(struct sys_device *, struct sysdev_attribute *); | 
 | 125 |  | 
| Andi Kleen | 1e395ab | 2010-01-05 12:48:05 +0100 | [diff] [blame] | 126 | /* Create/remove NULL terminated attribute list */ | 
 | 127 | static inline int | 
 | 128 | sysdev_create_files(struct sys_device *d, struct sysdev_attribute **a) | 
 | 129 | { | 
 | 130 | 	return sysfs_create_files(&d->kobj, (const struct attribute **)a); | 
 | 131 | } | 
 | 132 |  | 
 | 133 | static inline void | 
 | 134 | sysdev_remove_files(struct sys_device *d, struct sysdev_attribute **a) | 
 | 135 | { | 
 | 136 | 	return sysfs_remove_files(&d->kobj, (const struct attribute **)a); | 
 | 137 | } | 
 | 138 |  | 
| Andi Kleen | 9800794 | 2008-07-01 18:48:42 +0200 | [diff] [blame] | 139 | struct sysdev_ext_attribute { | 
 | 140 | 	struct sysdev_attribute attr; | 
 | 141 | 	void *var; | 
 | 142 | }; | 
 | 143 |  | 
 | 144 | /* | 
 | 145 |  * Support for simple variable sysdev attributes. | 
 | 146 |  * The pointer to the variable is stored in a sysdev_ext_attribute | 
 | 147 |  */ | 
 | 148 |  | 
 | 149 | /* Add more types as needed */ | 
 | 150 |  | 
 | 151 | extern ssize_t sysdev_show_ulong(struct sys_device *, struct sysdev_attribute *, | 
 | 152 | 				char *); | 
 | 153 | extern ssize_t sysdev_store_ulong(struct sys_device *, | 
 | 154 | 			struct sysdev_attribute *, const char *, size_t); | 
 | 155 | extern ssize_t sysdev_show_int(struct sys_device *, struct sysdev_attribute *, | 
 | 156 | 				char *); | 
 | 157 | extern ssize_t sysdev_store_int(struct sys_device *, | 
 | 158 | 			struct sysdev_attribute *, const char *, size_t); | 
 | 159 |  | 
 | 160 | #define _SYSDEV_ULONG_ATTR(_name, _mode, _var)				\ | 
 | 161 | 	{ _SYSDEV_ATTR(_name, _mode, sysdev_show_ulong, sysdev_store_ulong), \ | 
 | 162 | 	  &(_var) } | 
 | 163 | #define SYSDEV_ULONG_ATTR(_name, _mode, _var)			\ | 
 | 164 | 	struct sysdev_ext_attribute attr_##_name = 		\ | 
 | 165 | 		_SYSDEV_ULONG_ATTR(_name, _mode, _var); | 
 | 166 | #define _SYSDEV_INT_ATTR(_name, _mode, _var)				\ | 
 | 167 | 	{ _SYSDEV_ATTR(_name, _mode, sysdev_show_int, sysdev_store_int), \ | 
 | 168 | 	  &(_var) } | 
 | 169 | #define SYSDEV_INT_ATTR(_name, _mode, _var)			\ | 
 | 170 | 	struct sysdev_ext_attribute attr_##_name = 		\ | 
 | 171 | 		_SYSDEV_INT_ATTR(_name, _mode, _var); | 
 | 172 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 173 | #endif /* _SYSDEV_H_ */ |