這個是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...