?? linux字符驅動.c
字號:
dev.c 代碼
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
//#include <linux/config.h>
#include <linux/proc_fs.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/seq_file.h>
#include <linux/ioctl.h>
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/slab.h>
MODULE_LICENSE("GPL");
// 常量定義
#define BUFFERLENS 1024*1024;
// 函數申明
ssize_t chuan_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t chuan_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
int chuan_open(struct inode *inode, struct file *filp);
int chuan_release(struct inode *inode, struct file *filp);
// 初始化字符設備驅動的file_operations結構體
// 很奇怪的語法……
struct file_operations chuan_fops = {
.owner = THIS_MODULE,
.read = chuan_read,
.write = chuan_write,
.open = chuan_open,
.release = chuan_release,
};
// 主力結構————表示設備結構
struct chuan_dev {
char * rer;
unsigned int buffersize;// 緩沖區大小
unsigned int len;// 緩沖區已有長度
unsigned int start;// 起始數據偏移量
struct semaphore sem;// 信號量,用于互斥訪問
struct cdev cdev;// 字符型設備結構
};
// 全局變量
struct chuan_dev chuan_device;
dev_t dev_no = 0;
// 初始化
int chuan_init(void)
{
int err=0;
// 初始化cdev
cdev_init(&chuan_device.cdev, &chuan_fops);
chuan_device.cdev.owner = THIS_MODULE;
chuan_device.cdev.ops = &chuan_fops;
// 動態分配一個設備號
alloc_chrdev_region(&dev_no, 0, 1, "Rer'sPersonalDevices v1.11");
// 字符設備注冊
err = cdev_add(&chuan_device.cdev, dev_no, 1);
if (err){
printk(KERN_NOTICE "Error %d adding device\n", err);
return -1;
}
else{
// 初始化互斥信號量
init_MUTEX(&chuan_device.sem);
//printk("互斥信號量初始化成功\n");
printk(KERN_NOTICE "Device Initilize success.\n");
return 0; /* succeed */
}
}
// 注銷
void chuan_exit(void)
{
unregister_chrdev_region(dev_no, 1);
cdev_del(&chuan_device.cdev);
}
// 打開
int chuan_open(struct inode *inode, struct file *filp)
{
struct chuan_dev *mydev;
// 高級技巧,,我不是很明白
mydev = container_of(inode->i_cdev,struct chuan_dev,cdev);
// 將private_data保存chuan_dev指針
filp->private_data = mydev;
// 信號量,如果已經無資源了,就不打開
if (down_interruptible(&mydev->sem))
return -ERESTARTSYS;
up(&mydev->sem);
if(!mydev->rer){
// 如果緩沖區是空的,那么分配1k的內容給它
//printk("緩沖區還是空的.\n");
mydev->rer = (char *)kmalloc(1024, GFP_KERNEL);
memset(mydev->rer, 0, 1024);
// 初始化參數
mydev->buffersize = 1024;
mydev->len = mydev->start = 0;
}
else{
//printk("緩沖區已經有東西了.現將其初始化\n");
}
return 0;
}
// 關閉
int chuan_release(struct inode *inode, struct file *filp)
{
return 0;
}
// 讀取
ssize_t chuan_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos)
{
// int i;
struct chuan_dev *mydev;
//printk("讀取\n");
// 讀取數據
mydev = filp->private_data;
// 信號量,如果已經無資源了,就不打開
if (down_interruptible(&mydev->sem))
return -ERESTARTSYS;
/* printk("緩沖區數據量長度: %d\n",mydev->len);
printk("緩沖區起始位置: %d\n",mydev->start);
for(i=0;i<mydev->len+mydev->start;++i)
printk("緩沖區: %d values %c\n",i,*(mydev->rer+i));
*/
if(mydev->len>0){
if(count > mydev->len-mydev->start)
count = mydev->len-mydev->start;
if(copy_to_user(buf,mydev->rer+mydev->start,count)){
printk("拷貝失敗.\n");
}
else{
mydev->start += count;
if(mydev->start>=mydev->buffersize){
mydev->start = 0;
mydev->len = 0;
}
printk("拷貝成功.\n");
printk("start = %d\n",mydev->start);
printk("len = %d\n",mydev->len);
}
}
else{
printk("緩沖區還沒有東西,,無法進行讀取.\n");
goto end;
}
end:
// 將訪問信號釋放
up(&mydev->sem);
return 0;
}
// 寫入
ssize_t chuan_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
struct chuan_dev *mydev;
// 寫入數據
mydev = filp->private_data;
// 信號量,如果已經無資源了,就不打開
if (down_interruptible(&mydev->sem))
return -ERESTARTSYS;
if(!mydev->rer){
//printk(KERN_NOTICE "寫入過程,《, 空的。.\n");
}
else{
//printk(KERN_NOTICE "寫入過程, 已經有東西了。.\n");
// 向緩沖區中寫數據
if(mydev->start+mydev->len+count > mydev->buffersize){
// 如果預感到要溢出,那么就從頭寫 并且舍棄已有數據(這樣很不好)
memset(mydev->rer, 0, mydev->buffersize);
if(count > mydev->buffersize)
count = mydev->buffersize;
mydev->start = mydev->len = 0;
}
if(copy_from_user(mydev->rer+mydev->len,buf,count)){
printk(KERN_NOTICE "寫入失敗.\n");
}
else{
mydev->len += count;
printk(KERN_NOTICE "寫入成功,當前緩沖區的大小為: %d.\n",mydev->len);
}
}
up(&mydev->sem);
return 0;
}
module_init(chuan_init);
module_exit(chuan_exit);use.c 測試驅動代碼
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
main()
{
int testdev;
int i;
char buf[10];
char redbuf[10];
// 先打開/dev/lala(從設備號為0),進行寫入操作
testdev = open("/dev/lala",O_RDWR);
if ( testdev == -1 ){
printf("Cann't open file \n");
}else{
printf("Open file Success.\n");
for(i=0;i<10;++i)
buf[i] = i+'a';
write(testdev,buf,10);
write(testdev,buf,10);
printf("寫入設備成功/dev/lala\n");
memset(buf,0,10);
read(testdev,redbuf,5);
printf("讀取設備成功/dev/lala\n");
for (i = 0; i < 5;i++)
printf("收到數據: %c\n",redbuf[i]);
printf("\n");
memset(buf,0,10);
read(testdev,redbuf,5);
printf("讀取設備成功/dev/lala\n");
for (i = 0; i < 5;i++)
printf("收到數據: %c\n",redbuf[i]);
printf("\n");
close(testdev);
}
}
ac.sh 和 wa.sh,掛載和卸載驅動的shell
#!/bin/bash
insmod dev.ko
mknod /dev/lala c 253 0
chmod 777 /dev/lala
mknod /dev/lala2 c 253 1
chmod 777 /dev/lala2
#!/bin/bash
rm /dev/lala
rm /dev/lala2
rmmod dev
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -