forked from sharku/char_timer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchar_timer.c
More file actions
143 lines (115 loc) · 3.33 KB
/
char_timer.c
File metadata and controls
143 lines (115 loc) · 3.33 KB
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
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/workqueue.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#define DEVICE_NAME "char_timer"
MODULE_AUTHOR("padawan");
static int device_open(struct inode *inode, struct file *file);
static int device_release(struct inode *inode, struct file *file);
static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t * offset);
static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off);
static int major = 0; /* Major number assigned to our device
driver */
static int time = 0; /*We count this variable*/
static int die = 0; /* set this to 1 for shutdown */
static unsigned long onesec; /*Delay time*/
static void timer_interrupt_routine(void *); /*We will call this function*/
dev_t dev;
static struct workqueue_struct *wq = 0;
static DECLARE_DELAYED_WORK(mywork, timer_interrupt_routine);
static struct cdev *mychardev = 0;
struct class *char_class = 0;
static void timer_interrupt_routine(void *tm)
{
time++;
if (die == 0)
queue_delayed_work(wq, &mywork, onesec);
}
static int device_open(struct inode *inode, struct file *file)
{
return 0;
}
static int device_release(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
char *buffer, /* buffer to fill with data */
size_t length, /* length of the buffer */
loff_t * offset)
{
if (copy_to_user(buffer,&time,1) < 0)
return -1;
return 1;
}
static ssize_t
device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk(KERN_ALERT "We only want to read device\n");
return -EINVAL;
}
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
static int chartime_init()
{
int ret, err;
printk("module init!!\n\r");
onesec = msecs_to_jiffies(1000); /*HZ in i386 was changed to 1000, yeilding a jiffy interval of 1 ms. So 1000ms = 1 sec*/
dev = MKDEV(major, 0);
if (major)
ret = register_chrdev_region(dev, 1, "char_timer");
else {
printk("alloc_chrdev_region!!!\n\r");
ret = alloc_chrdev_region(&dev, 0, 1, "char_timer");
major = MAJOR(dev);
}
if (ret < 0)
{
printk("unable to get major %d\n\r", major);
return ret;
}
if (major == 0) {
major = ret;
printk("major num %d\n\r", ret);
}
char_class = class_create(THIS_MODULE, DEVICE_NAME);
mychardev = cdev_alloc();
cdev_init(mychardev, &fops);
mychardev->owner = THIS_MODULE;
mychardev->ops = &fops;
err = cdev_add(mychardev, dev, 1);
if (err)
printk("Error %d adding mychardev\n\r", err);
/* seend uevents to udev, so it'll create the /dev node*/
device_create(char_class, NULL, dev, NULL, "char_timer%d", 1);
if (!wq)
wq = create_singlethread_workqueue("char_timer_work");
if (wq)
queue_delayed_work(wq, &mywork, onesec);
return 0;
}
static void __exit chartime_exit()
{
die = 1;
if (wq){
cancel_delayed_work(&mywork);
flush_workqueue(wq);
destroy_workqueue(wq);
}
cdev_del(mychardev);
unregister_chrdev_region(MKDEV(major,0), 1);
device_destroy(char_class, dev);
class_destroy(char_class);
printk("module exit\n\r");
}
module_init(chartime_init);
module_exit(chartime_exit);
MODULE_DESCRIPTION("char_timer");
MODULE_LICENSE("GPL");