乙個簡單的Linux字元驅動

2021-06-20 02:45:19 字數 4085 閱讀 3159

這個是win驅動課的作業,題目是設計乙個通用的io埠讀寫驅動,因為我的電腦配置太低無法執行虛擬機器,就用linux完成了作業。

read和write的處理併發讀寫的部分來自ldd3。

1.驅動程式

/*通用io埠讀寫驅動*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

//ioctl的命令字定義

#define test_magic_num 'k'

#define port_set _iow(test_magic_num,1,int)

#define port_get _io(test_magic_num,2)

#define port_lock _io(test_magic_num,3)

#define port_unlock _io(test_magic_num,4)

#define maxbuf 512 //自定義資料區大小為512

#define device_name "/dev/test_device"

#define device_sccuess 0

#define port_locked -2

//全域性變數盡量採用static變數,避免「汙染」核心的變數的命名空間

static int major_number = 1000;

static int minor_number = 0;

static int port_number = 0x70;

module_param(major_number , int , s_irugo);

module_param(minor_number , int , s_irugo);

//module_param(port_number  , long , s_irugo);

static dev_t device_number;   //裝置號

static struct cdev *my_cdev=null;

static void *pdev=null;    //自定義區域,裝載模組的時候分配一片區域

//核心訊號量,等待佇列,用於實現讀寫的同步

static struct semaphore g_sem;

//static unsigned buf_flag=0;

static unsigned int port_flag = 0;

static declare_wait_queue_head(g_queue);

//開啟和讀寫操作,讀寫操作將實現阻塞i/o,為防止讀寫衝突,裝置只允許乙個程序的乙個操作

int test_open(struct inode * inode ,struct file *filp)

int test_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)

while(port_flag)//埠被占用,等待

//此時已經獲得鎖,且操作可以執行

//做標記,不允許修改埠

port_flag=1;

for(i=0;i((char*)pdev)[i]=inb(port_number);

port_flag=0;//不再占用埠

up(&g_sem);//釋放訊號量

wake_up_interruptible(&g_queue);//喚醒等待佇列中的程序

i=copy_to_user((void*)buf,pdev,count);//讀出的資料拷貝給應用程式

if(i<0)

return count-i;

}long test_ioctl(struct file *filp,unsigned int cmd, unsigned long arg)

else   //沒有其他程序在io

case port_get:

retval = port_number;

printk("port number returned\n");

break;

default: break;

}return retval;

}int test_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)

if(down_interruptible(&g_sem))//獲得鎖

while(port_flag)//操作無法執行,等待

//此時已經獲得鎖,且操作可以執行

port_flag=1;

for(j=0;joutb(((char*)pdev)[j],port_number);

port_flag=0;

up(&g_sem);

wake_up_interruptible(&g_queue);

return (count-i);

}//使用者空間程序裝置關閉時執行,也就是對應的close操作

int test_release(struct inode *inode, struct file* filp)

static struct file_operations test_ops = ;

int test_init(void) //核心裝載時執行,註冊裝置和分配自由儲存區

//註冊裝置

device_number = mkdev(major_number,minor_number);

err = register_chrdev_region(device_number,1,device_name);

if( 0 > err)

//分配乙個cdev

my_cdev = cdev_alloc();

if(null == my_cdev)

//新增裝置

my_cdev->ops= &test_ops;

my_cdev->owner = this_module;

err=cdev_add(my_cdev,device_number,1);//新增乙個裝置

if(0 > err)

//初始化訊號量,等待佇列已經初始化

sema_init(&g_sem,1);

//設定標誌

//buf_flag=0;

port_flag=0;

printk("init io driver ok\n");

return device_sccuess; 

}void test_exit(void) //核心解除安裝時候執行,登出裝置和釋放自由儲存區

module_init(test_init);

module_exit(test_exit);

module_license("gpl");

2. 應用測試

首先用make工具編譯然後用insmod裝載核心模組

然後執行下面的命令新增乙個裝置檔案

mknod /dev/test_device c 1000 0

然後把乙個發光二極體的兩個引腳和串列埠的4、7針接觸,再執行這個程式,可以

看到二極體的閃爍現象#include #include #include #include

#include //使用下面的巨集

#define device_name "/dev/test_device"#define test_magic_num 'k'#define port_set _iow(test_magic_num,1,int)#define port_get _io(test_magic_num,2)#define port_lock _io(test_magic_num,3)int main(void)

int i=0;

for(i=0;i<30;i++)

close(retcode);

return 0;}

乙個簡單的linux核心驅動

一,核心結構簡單概述 上層程式操作裝置驅動簡單概述 在使用者空間使用相關的c庫,比如open函式會造成乙個中斷,系統會去呼叫sys call函式 系統呼叫 然後會去呼叫相關的sys open函式,在核心空間的時候會去驅動鏈表裡面查詢對應的外設驅動,我們編寫完驅動程式,載入到核心,核心會去呼叫相關的驅...

字元裝置驅動1 乙個簡單的字元裝置驅動示例

1.註冊主次裝置號 register chrdev region 和 alloc chrdev region 2.註冊字元裝置驅動 cdev init 初始化,cdev add 新增,註冊裝置驅動,cdev alloc 申請空間,cdev del 登出驅動 3.建立驅動的裝置檔案 class cre...

乙個簡單的keyboard驅動

這個驅動使能了幾個cpld控制的按鍵,f1,f2,f3,f4,home,up,down,left,right,esc,enter。1.cpld kpd probe static int cpld kpd probe struct platform device pdev cpld input dev...