| 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>
|
| 25 | #include <linux/module.h>
|
| 26 | #include <linux/pm.h>
|
| 27 |
|
| 28 |
|
| 29 | struct sys_device;
|
| 30 |
|
| 31 | struct sysdev_class {
|
| 32 | const char *name;
|
| 33 | struct list_head drivers;
|
| 34 |
|
| 35 |
|
| 36 | int (*shutdown)(struct sys_device *);
|
| 37 | int (*suspend)(struct sys_device *, pm_message_t state);
|
| 38 | int (*resume)(struct sys_device *);
|
| 39 | struct kset kset;
|
| 40 | };
|
| 41 |
|
| 42 | struct sysdev_class_attribute {
|
| 43 | struct attribute attr;
|
| 44 | ssize_t (*show)(struct sysdev_class *, char *);
|
| 45 | ssize_t (*store)(struct sysdev_class *, const char *, size_t);
|
| 46 | };
|
| 47 |
|
| 48 | #define _SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) \
|
| 49 | { \
|
| 50 | .attr = {.name = __stringify(_name), .mode = _mode }, \
|
| 51 | .show = _show, \
|
| 52 | .store = _store, \
|
| 53 | }
|
| 54 |
|
| 55 | #define SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) \
|
| 56 | struct sysdev_class_attribute attr_##_name = \
|
| 57 | _SYSDEV_CLASS_ATTR(_name,_mode,_show,_store)
|
| 58 |
|
| 59 |
|
| 60 | extern int sysdev_class_register(struct sysdev_class *);
|
| 61 | extern void sysdev_class_unregister(struct sysdev_class *);
|
| 62 |
|
| 63 | extern int sysdev_class_create_file(struct sysdev_class *,
|
| 64 | struct sysdev_class_attribute *);
|
| 65 | extern void sysdev_class_remove_file(struct sysdev_class *,
|
| 66 | struct sysdev_class_attribute *);
|
| 67 | |
| 68 | * Auxillary system device drivers.
|
| 69 |
|
| 70 |
|
| 71 | struct sysdev_driver {
|
| 72 | struct list_head entry;
|
| 73 | int (*add)(struct sys_device *);
|
| 74 | int (*remove)(struct sys_device *);
|
| 75 | int (*shutdown)(struct sys_device *);
|
| 76 | int (*suspend)(struct sys_device *, pm_message_t state);
|
| 77 | int (*resume)(struct sys_device *);
|
| 78 | };
|
| 79 |
|
| 80 |
|
| 81 | extern int sysdev_driver_register(struct sysdev_class *, struct sysdev_driver *);
|
| 82 | extern void sysdev_driver_unregister(struct sysdev_class *, struct sysdev_driver *);
|
| 83 |
|
| 84 |
|
| 85 | |
| 86 | * sys_devices can be simplified a lot from regular devices, because they're
|
| 87 | * simply not as versatile.
|
| 88 |
|
| 89 |
|
| 90 | struct sys_device {
|
| 91 | u32 id;
|
| 92 | struct sysdev_class * cls;
|
| 93 | struct kobject kobj;
|
| 94 | };
|
| 95 |
|
| 96 | extern int sysdev_register(struct sys_device *);
|
| 97 | extern void sysdev_unregister(struct sys_device *);
|
| 98 |
|
| 99 |
|
| 100 | struct sysdev_attribute {
|
| 101 | struct attribute attr;
|
| 102 | ssize_t (*show)(struct sys_device *, struct sysdev_attribute *, char *);
|
| 103 | ssize_t (*store)(struct sys_device *, struct sysdev_attribute *,
|
| 104 | const char *, size_t);
|
| 105 | };
|
| 106 |
|
| 107 |
|
| 108 | #define _SYSDEV_ATTR(_name, _mode, _show, _store) \
|
| 109 | { \
|
| 110 | .attr = { .name = __stringify(_name), .mode = _mode }, \
|
| 111 | .show = _show, \
|
| 112 | .store = _store, \
|
| 113 | }
|
| 114 |
|
| 115 | #define SYSDEV_ATTR(_name, _mode, _show, _store) \
|
| 116 | struct sysdev_attribute attr_##_name = \
|
| 117 | _SYSDEV_ATTR(_name, _mode, _show, _store);
|
| 118 |
|
| 119 | extern int sysdev_create_file(struct sys_device *, struct sysdev_attribute *);
|
| 120 | extern void sysdev_remove_file(struct sys_device *, struct sysdev_attribute *);
|
| 121 |
|
| 122 | struct sysdev_ext_attribute {
|
| 123 | struct sysdev_attribute attr;
|
| 124 | void *var;
|
| 125 | };
|
| 126 |
|
| 127 | |
| 128 | * Support for simple variable sysdev attributes.
|
| 129 | * The pointer to the variable is stored in a sysdev_ext_attribute
|
| 130 |
|
| 131 |
|
| 132 |
|
| 133 |
|
| 134 | extern ssize_t sysdev_show_ulong(struct sys_device *, struct sysdev_attribute *,
|
| 135 | char *);
|
| 136 | extern ssize_t sysdev_store_ulong(struct sys_device *,
|
| 137 | struct sysdev_attribute *, const char *, size_t);
|
| 138 | extern ssize_t sysdev_show_int(struct sys_device *, struct sysdev_attribute *,
|
| 139 | char *);
|
| 140 | extern ssize_t sysdev_store_int(struct sys_device *,
|
| 141 | struct sysdev_attribute *, const char *, size_t);
|
| 142 |
|
| 143 | #define _SYSDEV_ULONG_ATTR(_name, _mode, _var) \
|
| 144 | { _SYSDEV_ATTR(_name, _mode, sysdev_show_ulong, sysdev_store_ulong), \
|
| 145 | &(_var) }
|
| 146 | #define SYSDEV_ULONG_ATTR(_name, _mode, _var) \
|
| 147 | struct sysdev_ext_attribute attr_##_name = \
|
| 148 | _SYSDEV_ULONG_ATTR(_name, _mode, _var);
|
| 149 | #define _SYSDEV_INT_ATTR(_name, _mode, _var) \
|
| 150 | { _SYSDEV_ATTR(_name, _mode, sysdev_show_int, sysdev_store_int), \
|
| 151 | &(_var) }
|
| 152 | #define SYSDEV_INT_ATTR(_name, _mode, _var) \
|
| 153 | struct sysdev_ext_attribute attr_##_name = \
|
| 154 | _SYSDEV_INT_ATTR(_name, _mode, _var);
|
| 155 |
|
| 156 | #endif
|