root / logic / trunk / driver / dev01 / dev_thermometer_01.c @ 81
History | View | Annotate | Download (6.21 KB)
1 | 72 | Janez1 | /*
|
---|---|---|---|
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_thermometer_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 | } |