-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkset_sys_code.c
240 lines (185 loc) · 7.84 KB
/
kset_sys_code.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
//device driver's model code {kset sample}
//headers/libraries required
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
//container object or object for device instance
struct device_instance{
struct kobject dev_kobj; //it repersents the device instance in the kernel space
//and is used to register the device instance to the
//sysfs/device model file system
//following are the device instance specific attributes
int dev_attr1;
int dev_attr2;
int dev_attr3;
};
//the following is a container for device instance specific attribute
struct dev_inst_attr{
struct attribute attr; //an attribute object used to manage the device instance
//specific attribute
//following are the device specific instance's attribute's callbacks/methods
ssize_t (*show)(struct device_instance *device,struct dev_inst_attr *attr,char *buf);
ssize_t (*store)(struct device_instance *device,struct dev_inst_attr *attr,const char *buf,size_t count);
};
//the following are container_of macros used to get the corresponding structure related to the current
//object passed as a parameter
#define get_device_instance(x) container_of(x,struct device_instance,dev_kobj); //for device instance
#define get_dev_inst_attr(x) container_of(x,struct dev_inst_attr,attr); //for device instance attribute
//following are the callbacks used by the sysfs operations
//here, we need to get the device instance from its kobject
//and its device instance specific attributes from its attribute
//this can be done using the container_of macros defined initially
//after the above then call the show/store functions
//it returns the setup for the system object, its attributes & attributes specific callbacks
static ssize_t link_sys_dev_show(struct kobject *kobj,struct attribute *attr,char *buf){
//the parameters are passed to the API by the sysfs for the setup
//define two pointers to the device instance and device instance attribute
struct device_instance *device;
struct dev_inst_attr *dev_attr;
//transpose to the device container & its attributes using the macros
device = get_device_instance(kobj);
dev_attr = get_dev_inst_attr(attr);
//check if the correct device is accessed
if(!dev_attr->show) return -EIO;
return dev_attr->show(device,dev_attr,buf);
}
//the following is for the store similar to the show as above it is also setup when the store SCAPI
//is accessed in the user space code
static ssize_t link_sys_dev_store(struct kobject *kobj,struct attribute *attr,const char *buf,size_t count){
//defining the pointer to have the corresponding setup
struct device_instance *device;
struct dev_inst_attr *dev_attr;
device = get_device_instance(kobj);
dev_attr = get_dev_inst_attr(attr);
//check for errors
if(!dev_attr->store) return -EIO;
return dev_attr->store(device,dev_attr,buf,count);
}
//creating the operation table for the sysfs operations to link
//the above callbacks to the sysfs/device model
static struct sysfs_ops dev_sys_ops = {
.show = link_sys_dev_show,
.store = link_sys_dev_store,
};
//the following is release callback to free the memory held by our device related kobjects
//this is required by the framework
static void device_release(struct kobject *kobj){
//to remove the device we need to get the device_instance related to the kobject
//this is again done using the macros
struct device_instance *device;
device = get_device_instance(kobj);
//kfree is a slab allocators api which can be used to remove the allocated memory
kfree(device);
}
//following are the device specific callbacks which will be accessed further after the above setup
//of the device_instance and its attributes are complete the device will further invoke the following
//callbacks as per the framework
static ssize_t dev_attr_show(struct device_instance *device,struct dev_inst_attr *dev_attr,char *buf){
//these parameters are passed to the callback by the link_sys_dev_show()
if(strcmp(dev_attr->attr.name,"dev_attr1")==0)
return sprintf(buf,"%d\n",device->dev_attr1);
else if(strcmp(dev_attr->attr.name,"dev_attr2")==0)
return sprintf(buf,"%d\n",device->dev_attr2);
else
return sprintf(buf,"%d\n",device->dev_attr3);
}
static ssize_t dev_attr_store(struct device_instance *device, struct dev_inst_attr *dev_attr,const char *buf, size_t count){
//copying the data into the private variable from the buffer and then accessing it
int parameter;
sscanf(buf,"%du",parameter);
if(strcmp(dev_attr->attr.name,"dev_attr1")==0)
device->dev_attr1 = parameter;
else if(strcmp(dev_attr->attr.name,"dev_attr2")==0)
device->dev_attr2 = parameter;
else
device->dev_attr3 = parameter;
return count;
}
//following is for associating the attributes to their attributes objects
//this is part of the framework
static struct dev_inst_attr assoc_dev_attr1 = __ATTR(dev_attr1,0644,dev_attr_show,dev_attr_store);
static struct dev_inst_attr assoc_dev_attr2 = __ATTR(dev_attr2,0644,dev_attr_show,dev_attr_store);
static struct dev_inst_attr assoc_dev_attr3 = __ATTR(dev_attr3,0644,dev_attr_show,dev_attr_store);
//grouping the attributes together
//this is done so that the attributes can be created as well as destroyed
//all at once
static struct attribute *dev_attr_group[] = {
&assoc_dev_attr1.attr,
&assoc_dev_attr2.attr,
&assoc_dev_attr3.attr,
NULL,
};
//now, for kset we have to initialise the kobj_type accordingly
//as it will link our kset and its kobjects and related device specific attributes
//to the user space via several layers of vfs and system interface layer
static struct kobj_type device_type = {
.sysfs_ops = &dev_sys_ops,
.release = device_release,
.default_attrs = dev_attr_group,
};
//the following pointer are initialised to setup the kset and its various device instances
static struct kset *kset_ptr;
static struct device_instance *device1;
static struct device_instance *device2;
static struct device_instance *device3;
//the following callback/method is used to create a device instance
//it is used by the init method to create multiple device instances
static struct device_instance *create_device(const char *dev_name){
struct device_instance *device;
int ret;
device = kzalloc(sizeof(struct device_instance),GFP_KERNEL);
if(!device) return NULL;
//associating the kobject of the current device instance to the kset
//this kset, will be initialised in the init method of the module
device->dev_kobj.kset = kset_ptr;
//initialise and add the current device specific kobj to the kernel
//here the parent need not be specified as we have already linked it to the kset
//also the registration is done by the following api
ret = kobject_init_and_add(&device->dev_kobj,&device_type,NULL,"%s",dev_name);
if(ret){
kobject_put(&device->dev_kobj);
return NULL;
}
//this is to inform about the created kobject
kobject_uevent(&device->dev_kobj,KOBJ_ADD);
return device;
}
//this is to destroy the created device related objects
static void destroy_device_instance(struct device_instance *device){
kobject_put(&device->dev_kobj);
}
//the modules init method/callback
static int device_init(void){
kset_ptr = kset_create_and_add("kset_devices",NULL,kernel_kobj);
if(!kset_ptr) return -ENOMEM;
device1 = create_device("device_1");
if(!device1){
destroy_device_instance(device1);
return -EINVAL;
}
device2 = create_device("device_2");
if(!device2){
destroy_device_instance(device2);
return -EINVAL;
}
device3 = create_device("device_3");
if(!device3){
destroy_device_instance(device3);
return -EINVAL;
}
return 0;
}
//the modules exit method
static void device_exit(void){
destroy_device_instance(device1);
destroy_device_instance(device2);
destroy_device_instance(device3);
kset_unregister(kset_ptr);
}
module_init(device_init);
module_exit(device_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Akshay Ramteke<[email protected]>");