root / logic / trunk / driver / dev03 / dev_barometer_01.c @ 84
History | View | Annotate | Download (6.21 KB)
1 |
/*
|
---|---|
2 |
* chardev.c − Create an input/output character device
|
3 |
*/
|
4 |
#include <linux/kernel.h> /* We're doing kernel work */ |
5 |
#include <linux/module.h> /* Specifically, a module */ |
6 |
#include <linux/fs.h> /* for get_user and put_user */ |
7 |
#include <linux/i2c.h> /* for get_user and put_user */ |
8 |
#include <linux/hwmon.h> /* for get_user and put_user */ |
9 |
#include <linux/err.h> /* for get_user and put_user */ |
10 |
#include <asm/uaccess.h> |
11 |
#include "dev_barometer_01.h" |
12 |
|
13 |
#define SUCCESS 0 |
14 |
#define DEVICE_NAME "dev_thermometer_01" |
15 |
#define BUF_LEN 80 |
16 |
/*
|
17 |
* Is the device open right now? Used to prevent
|
18 |
* concurent access into the same device
|
19 |
*/
|
20 |
static int Device_Open = 0; |
21 |
/*
|
22 |
* The message the device will give when asked
|
23 |
*/
|
24 |
static char Message[BUF_LEN]; |
25 |
/*
|
26 |
* How far did the process reading the message get?
|
27 |
* Useful if the message is larger than the size of the
|
28 |
* buffer we get to fill in device_read.
|
29 |
*/
|
30 |
static char *Message_Ptr; |
31 |
/*
|
32 |
* This is called whenever a process attempts to open the device file
|
33 |
*/
|
34 |
static int device_open(struct inode *inode, struct file *file) |
35 |
{ |
36 |
#ifdef DEBUG
|
37 |
printk(KERN_INFO "device_open(%p)\n", file);
|
38 |
#endif
|
39 |
/*
|
40 |
* We don't want to talk to two processes at the same time
|
41 |
*/
|
42 |
if (Device_Open)
|
43 |
return -EBUSY;
|
44 |
Device_Open++; |
45 |
/*
|
46 |
* Initialize the message
|
47 |
*/
|
48 |
Message_Ptr = Message; |
49 |
try_module_get(THIS_MODULE); |
50 |
return SUCCESS;
|
51 |
} |
52 |
|
53 |
static int device_release(struct inode *inode, struct file *file) |
54 |
{ |
55 |
#ifdef DEBUG
|
56 |
printk(KERN_INFO "device_release(%p,%p)\n", inode, file);
|
57 |
#endif
|
58 |
/*
|
59 |
* We're now ready for our next caller
|
60 |
*/
|
61 |
Device_Open--; |
62 |
module_put(THIS_MODULE); |
63 |
return SUCCESS;
|
64 |
} |
65 |
|
66 |
/*
|
67 |
* This function is called whenever a process which has already opened the
|
68 |
* device file attempts to read from it.
|
69 |
*/
|
70 |
static ssize_t device_read(struct file *file, |
71 |
/* see include/linux/fs.h*/
|
72 |
char __user * buffer,
|
73 |
/* buffer to be
|
74 |
* filled with data */
|
75 |
size_t length, |
76 |
loff_t * offset) |
77 |
/* length of the buffer*/
|
78 |
{ |
79 |
/*
|
80 |
* Number of bytes actually written to the buffer
|
81 |
*/
|
82 |
int bytes_read = 0; |
83 |
#ifdef DEBUG
|
84 |
printk(KERN_INFO "device_read(%p,%p,%d)\n", file, buffer, length);
|
85 |
#endif
|
86 |
/*
|
87 |
* If we're at the end of the message, return 0
|
88 |
* (which signifies end of file)
|
89 |
*/
|
90 |
if (*Message_Ptr == 0) |
91 |
return 0; |
92 |
/*
|
93 |
* Actually put the data into the buffer
|
94 |
*/
|
95 |
while (length && *Message_Ptr) {
|
96 |
/*
|
97 |
* Because the buffer is in the user data segment,
|
98 |
* not the kernel data segment, assignment wouldn't
|
99 |
* work. Instead, we have to use put_user which
|
100 |
* copies data from the kernel data segment to the
|
101 |
* user data segment.
|
102 |
*/
|
103 |
put_user(*(Message_Ptr++), buffer++); |
104 |
length--; |
105 |
bytes_read++; |
106 |
} |
107 |
#ifdef DEBUG
|
108 |
printk(KERN_INFO "Read %d bytes, %d left\n", bytes_read, length);
|
109 |
#endif
|
110 |
/*
|
111 |
* Read functions are supposed to return the number
|
112 |
* of bytes actually inserted into the buffer
|
113 |
*/
|
114 |
return bytes_read;
|
115 |
} |
116 |
|
117 |
/*
|
118 |
* This function is called when somebody tries to
|
119 |
* write into our device file.
|
120 |
*/
|
121 |
static ssize_t
|
122 |
device_write(struct file *file,
|
123 |
const char __user * buffer, size_t length, loff_t * offset) |
124 |
{ |
125 |
int i;
|
126 |
#ifdef DEBUG
|
127 |
printk(KERN_INFO "device_write(%p,%s,%d)", file, buffer, length);
|
128 |
#endif
|
129 |
for (i = 0; i < length && i < BUF_LEN; i++) |
130 |
get_user(Message[i], buffer + i); |
131 |
Message_Ptr = Message; |
132 |
/*
|
133 |
* Again, return the number of input characters used
|
134 |
*/
|
135 |
return i;
|
136 |
} |
137 |
|
138 |
/*
|
139 |
* This function is called whenever a process tries to do an ioctl on our
|
140 |
* device file. We get two extra parameters (additional to the inode and file
|
141 |
* structures, which all device functions get): the number of the ioctl called
|
142 |
* and the parameter given to the ioctl function.
|
143 |
*
|
144 |
* If the ioctl is write or read/write (meaning output is returned to the
|
145 |
* calling process), the ioctl call returns the output of this function.
|
146 |
*
|
147 |
*/
|
148 |
int device_ioctl(struct inode *inode, |
149 |
/* see include/linux/fs.h */
|
150 |
struct file *file,
|
151 |
/* ditto */
|
152 |
unsigned int ioctl_num, |
153 |
/* number and param for ioctl */
|
154 |
unsigned long ioctl_param) |
155 |
{ |
156 |
int i;
|
157 |
char *temp;
|
158 |
char ch;
|
159 |
/*
|
160 |
* Switch according to the ioctl called
|
161 |
*/
|
162 |
switch (ioctl_num) {
|
163 |
case IOCTL_SET_MSG:
|
164 |
/*
|
165 |
* Receive a pointer to a message (in user space) and set that
|
166 |
* to be the device's message. Get the parameter given to
|
167 |
* ioctl by the process.
|
168 |
*/
|
169 |
temp = (char *)ioctl_param;
|
170 |
/*
|
171 |
* Find the length of the message
|
172 |
*/
|
173 |
get_user(ch, temp); |
174 |
for (i = 0; ch && i < BUF_LEN; i++, temp++) |
175 |
get_user(ch, temp); |
176 |
device_write(file, (char *)ioctl_param, i, 0); |
177 |
break;
|
178 |
case IOCTL_GET_MSG:
|
179 |
/*
|
180 |
* Give the current message to the calling process −
|
181 |
* the parameter we got is a pointer, fill it.
|
182 |
*/
|
183 |
i = device_read(file, (char *)ioctl_param, 99, 0); |
184 |
/*
|
185 |
* Put a zero at the end of the buffer, so it will be
|
186 |
* properly terminated
|
187 |
*/
|
188 |
put_user('\0', (char *)ioctl_param + i); |
189 |
break;
|
190 |
case IOCTL_GET_NTH_BYTE:
|
191 |
/*
|
192 |
* This ioctl is both input (ioctl_param) and
|
193 |
* output (the return value of this function)
|
194 |
*/
|
195 |
return Message[ioctl_param];
|
196 |
break;
|
197 |
} |
198 |
return SUCCESS;
|
199 |
} |
200 |
|
201 |
/* Module Declarations */
|
202 |
/*
|
203 |
* This structure will hold the functions to be called
|
204 |
* when a process does something to the device we
|
205 |
* created. Since a pointer to this structure is kept in
|
206 |
* the devices table, it can't be local to
|
207 |
* init_module. NULL is for unimplemented functions.
|
208 |
*/
|
209 |
struct file_operations Fops = {
|
210 |
.read = device_read, |
211 |
.write = device_write, |
212 |
.ioctl = device_ioctl, |
213 |
.open = device_open, |
214 |
.release = device_release, |
215 |
/* a.k.a. close */
|
216 |
}; |
217 |
|
218 |
/*
|
219 |
* Initialize the module − Register the character device
|
220 |
*/
|
221 |
int init_module()
|
222 |
{ |
223 |
int ret_val;
|
224 |
/*
|
225 |
* Register the character device (atleast try)
|
226 |
*/
|
227 |
ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops); |
228 |
/*
|
229 |
* Negative values signify an error
|
230 |
*/
|
231 |
if (ret_val < 0) { |
232 |
printk(KERN_ALERT "%s failed with %d\n",
|
233 |
"Sorry, registering the character device ", ret_val);
|
234 |
return ret_val;
|
235 |
} |
236 |
printk(KERN_INFO "%s The major device number is %d.\n",
|
237 |
"Registeration is a success", MAJOR_NUM);
|
238 |
return 0; |
239 |
} |
240 |
|
241 |
/*
|
242 |
* Cleanup − unregister the appropriate file from /proc
|
243 |
*/
|
244 |
void cleanup_module()
|
245 |
{ |
246 |
//int ret;
|
247 |
/*
|
248 |
* Unregister the device
|
249 |
*/
|
250 |
//ret = unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
|
251 |
printk(KERN_INFO "Unregistering module.\n");
|
252 |
unregister_chrdev(MAJOR_NUM, DEVICE_NAME); |
253 |
/*
|
254 |
* If there's an error, report it
|
255 |
*/
|
256 |
/*
|
257 |
if (ret < 0)
|
258 |
printk(KERN_ALERT "Error: unregister_chrdev: %d\n", ret);
|
259 |
/**/
|
260 |
} |
261 |
|