/
/
/
kernel
static
int
second_major
=
SECOND_MAJOR;
/
/
can be
input
by user,default value
is
0
struct second_dev
{
struct cdev cdev;
atomic_t counter;
struct timer_list s_timer;
};
struct second_dev
*
second_devp;
/
/
global
data to store cdev,counter,timer
static void second_timer_handle(unsigned
long
arg)
/
/
timer handler
{
mod_timer(&second_devp
-
>s_timer, jiffies
+
HZ);
atomic_inc(&second_devp
-
>counter);
/
/
/
inc the counter,原子操作
printk(KERN_INFO
"current jiffies is %ld\n"
, jiffies);
}
int
second_open(struct inode
*
inode, struct
file
*
filp)
{
init_timer(&second_devp
-
>s_timer);
/
/
/
注册一个定时器
second_devp
-
>s_timer.function
=
&second_timer_handle;
/
/
/
每隔
1s
就对counter进行
+
1
second_devp
-
>s_timer.expires
=
jiffies
+
HZ;
/
/
中断每秒钟产生多少次,即Hz(赫兹)jiffies用来统计系统启动以来系统中产生的总节拍数
/
/
节拍就是指系统中连续两次时钟中断的间隔时间,该值等于节拍率分之一,即
1
/
Hz
/
/
系统的运行时间(jiffies
/
Hz)
add_timer(&second_devp
-
>s_timer);
/
/
add a timer
atomic_set(&second_devp
-
>counter,
0
);
return
0
;
}
int
second_release(struct inode
*
inode, struct
file
*
filp)
{
del_timer(&second_devp
-
>s_timer);
return
0
;
}
static ssize_t second_read(struct
file
*
filp, char __user
*
buf, size_t count,
loff_t
*
ppos)
{
int
counter;
counter
=
atomic_read(&second_devp
-
>counter);
/
/
/
原子读
if
(put_user(counter, (
int
*
)buf))
/
/
put value of counter to buf
{
return
-
EFAULT;
}
else
{
return
sizeof(unsigned
int
);
}
}
static const struct file_operations second_fops
=
{
.owner
=
THIS_MODULE,
.
open
=
second_open,
.release
=
second_release,
.read
=
second_read,
};
static void second_setup_cdev(struct second_dev
*
dev,
int
index)
{
int
err, devno
=
MKDEV(second_major, index);
/
/
get dev no.
cdev_init(&dev
-
>cdev, &second_fops);
dev
-
>cdev.owner
=
THIS_MODULE;
dev
-
>cdev.ops
=
&second_fops;
/
/
open
,read,write....functions
for
the dev
err
=
cdev_add(&dev
-
>cdev, devno,
1
);
/
/
register the dev
if
(err)
{
printk(KERN_NOTICE
"Error %d add second%d"
, err, index);
}
}
int
second_init(void)
{
int
ret;
dev_t devno
=
MKDEV(second_major,
0
);
/
/
make dev no. with major
and
minor(
0
)
if
(second_major)
/
/
device no.
is
configured which
is
not
zero
from
user
input
{
ret
=
register_chrdev_region(devno,
1
,
"second"
);
/
/
second
is
the device name
}
else
{
ret
=
alloc_chrdev_region(&devno,
0
,
1
,
"second"
);
/
/
request a dev no inside.
second_major
=
MAJOR(devno);
}
if
(ret <
0
)
{
return
ret;
}
/
/
second_devp
is
a
global
structure to save cdev,counter,timer
second_devp
=
kmalloc(sizeof(struct second_dev), GFP_KERNEL);
if
(!second_devp)
{
ret
=
-
ENOMEM;
goto fail_malloc;
}
memset(second_devp,
0
, sizeof(struct second_dev));
second_setup_cdev(second_devp,
0
);
/
/
register the dev
return
0
;
fail_malloc:
unregister_chrdev_region(devno,
1
);
return
ret;
}
void second_exit(void)
{
cdev_del(&second_devp
-
>cdev);
/
/
del
the dev
kfree(second_devp);
unregister_chrdev_region(MKDEV(second_major,
0
),
1
);
/
/
unregister the dev
}
MODULE_AUTHOR(
"reversefish"
);
MODULE_LICENSE(
"Dual BSD/GPL"
);
module_param(second_major,
int
, S_IRUGO);
/
/
got a second_major no.
from
user
input
module_init(second_init);
module_exit(second_exit);