Statistics
| Revision:

root / logic / trunk / src / kernel_modules / generic / chardev.c @ 71

History | View | Annotate | Download (6.61 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 "chardev.h"
12

    
13
#define SUCCESS 0
14
#define DEVICE_NAME "char_dev"
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
        printk(KERN_INFO "If you want to talk to the device driver,\n");
239
        printk(KERN_INFO "you'll have to create a device file. \n");
240
        printk(KERN_INFO "We suggest you use:\n");
241
        printk(KERN_INFO "mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
242
        printk(KERN_INFO "The device file name is important, because\n");
243
        printk(KERN_INFO "the ioctl program assumes that's the\n");
244
        printk(KERN_INFO "file you'll use.\n");
245
        return 0;
246
}
247

    
248
/*
249
* Cleanup − unregister the appropriate file from /proc
250
*/
251
void cleanup_module()
252
{
253
        //int ret;
254
        /*
255
        * Unregister the device
256
        */
257
        //ret = unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
258
    printk(KERN_INFO "Unregistering module.\n");
259
        unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
260
        /*
261
        * If there's an error, report it
262
        */
263
        /*
264
        if (ret < 0)
265
                printk(KERN_ALERT "Error: unregister_chrdev: %d\n", ret);
266
        /**/
267
}
268