2013-06-05 71 views
2

我有兩個問題,因爲我試圖將設備驅動程序作爲初學者。使用舊設備文件的字符設備驅動程序

  1. 我創建了一個模塊,加載它,它動態地把主數251說了一遍。次要設備的數量只保留1,即只有次要數量0.爲了測試,我嘗試使用設備文件(使用mknod創建)上的echo和cat,並按預期工作。現在,如果卸載模塊但不刪除/ dev條目並再次加載具有相同主號碼的模塊,並嘗試對之前使用過的相同設備文件進行寫入/讀取,則內核崩潰。我知道我們不應該這樣做,但只是想了解在這種情況下會發生什麼事情導致這次崩潰。我認爲VFS所做的一切。

  2. 當我在設備文件上做貓時,讀取會一直髮生。爲什麼?停止需要使用偏移操作。這看起來是因爲緩衝區的長度是32768作爲默認讀取?

編輯:進一步在此我添加如下一個ioctl函數,然後我收到有關存儲類init和清理功能,如果沒有ioctl定義其正常工作的錯誤。沒有獲得ioctl和init/cleanup函數的存儲類之間的鏈接。更新的代碼已發佈。錯誤是下面:

/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:95:12: error: invalid storage class for function ‘flow_init’ 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_init’: 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:98:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_ioctl’: 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:112:13: error: invalid storage class for function ‘flow_terminate’ 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: error: invalid storage class for function ‘__inittest’ 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: warning: ‘alias’ attribute ignored [-Wattributes] 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: invalid storage class for function ‘__exittest’ 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ‘alias’ attribute ignored [-Wattributes] 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: expected declaration or statement at end of input 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: At top level: 
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:73:13: warning: ‘flow_ioctl’ defined but not used [-Wunused-function] 

下面是代碼:

#include <linux/init.h> 
#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/fs.h> 
#include <asm/uaccess.h> 
#include <linux/cdev.h> 
#include <linux/kdev_t.h> 
#include <linux/errno.h> 
#include <linux/ioctl.h> 

#define SUCCESS 0 
#define BUF_LEN 80 

#define FLOWTEST_MAGIC 'f' 
#define FLOW_QUERY _IOR(FLOWTEST_MAGIC,1,int) 

MODULE_LICENSE("GPL"); 
int minor_num=0,i; 
int num_devices=1; 
int fopen=0,counter=0,ioctl_test; 

static struct cdev ms_flow_cd; 
static char c; 

///// Open , close and rest of the things 

static int flow_open(struct inode *f_inode, struct file *f_file) 
{ 
printk(KERN_ALERT "flowtest device: OPEN\n"); 
return SUCCESS; 
} 

static ssize_t flow_read(struct file *f_file, char __user *buf, size_t 
    len, loff_t *off) 
{ 
    printk(KERN_INFO "flowtest Driver: READ()\nlength len=%d, Offset = %d\n",len,*off); 

/* Check to avoid the infinitely printing on screen. Return 1 on first read, and 0 on subsequent read */ 
if(*off==1) 
return 0; 

printk(KERN_INFO "Copying...\n"); 
copy_to_user(buf,&c,1); 
printk(KERN_INFO "Copied : %s\n",buf); 

*off = *off+1; 
return 1;  // Return 1 on first read 


} 

static ssize_t flow_write(struct file *f_file, const char __user *buf, 
    size_t len, loff_t *off) 
{ 
    printk(KERN_INFO "flowtest Driver: WRITE()\n"); 
if (copy_from_user(&c,buf+len-2,1) != 0) 
    return -EFAULT; 
else 
{ 
printk(KERN_INFO "Length len = %d\n\nLast character written is - %c\n",len,*(buf+len-2)); 
return len; 
} 
} 

static int flow_close(struct inode *i, struct file *f) 
{ 
    printk(KERN_INFO "ms_tty Device: CLOSE()\n"); 
    return 0; 
} 

///* ioctl commands */// 

static long flow_ioctl (struct file *filp,unsigned int cmd, unsigned long arg) 
{ 
    switch(cmd) { 
     case FLOW_QUERY: 
      ioctl_test=51; 
      return ioctl_test; 
     default: 
      return -ENOTTY; 
} 
///////////////////File operations structure below///////////////////////// 

struct file_operations flow_fops = { 
     .owner = THIS_MODULE, 
     .llseek = NULL, 
     .read =  flow_read, 
     .write = flow_write, 
     .unlocked_ioctl = flow_ioctl, 
     .open =  flow_open, 
     .release = flow_close 
}; 


static int flow_init(void) 
    { 
    printk(KERN_ALERT "Here with flowTest module ... loading...\n"); 
int result=0; 
dev_t dev=0; 
result = alloc_chrdev_region(&dev, minor_num, 
num_devices,"mod_flowtest");        // allocate major number dynamically. 

i=MAJOR(dev); 
printk(KERN_ALERT "Major allocated = %d",i); 

cdev_init(&ms_flow_cd,&flow_fops); 
cdev_add(&ms_flow_cd,dev,1); 

return 0; 
    } 

static void flow_terminate(void) 
    { 
    dev_t devno=MKDEV(i,0);   // wrap major/minor numbers in a dev_t structure , to pass for deassigning. 
    printk(KERN_ALERT "Going out... exiting...\n"); 
    unregister_chrdev_region(devno,num_devices);  //remove entry from the /proc/devices 
    } 

module_init(flow_init); 
module_exit(flow_terminate); 

回答

3

1 - 你是在爲你的清理功能缺失cdev_del()。這意味着設備保持註冊,但處理它的功能被卸載,從而導致崩潰。此外,cdev_add可能會在下次加載時失敗,但您不知道,因爲您沒有檢查返回值。

2-它看起來不錯...你修改偏移量,返回正確的字節數,然後返回0,如果偏移量爲1,這表明EOF。但你應該確實檢查* off> = 1.

EDIT- 傳遞到你的讀處理函數的長度一直來自用戶地read()。如果用戶打開設備文件並調用read(fd, buf, 32768);,那隻意味着用戶想要讀取直到 32768字節的數據。該長度一直傳遞到您的讀取處理程序。如果您沒有提供32768個字節的數據,則提供您所擁有的數據並返回該長度。現在,用戶代碼不確定文件是否結束,因此它會嘗試再次讀取32768。你真的現在沒有數據,所以你返回0,它告訴用戶代碼它已經命中EOF,所以它停止。

總之,作爲讀取處理程序的某種默認值,您看到的只是實用程序cat用於讀取任何內容的塊大小。如果您想要在讀取功能中看到不同的數字,請嘗試使用dd,因爲它允許您指定塊大小。

dd if=/dev/flowtest of=/dev/null bs=512 count=1 

此外,這應該讀取一個塊並停止,因爲您指定count = 1。如果您省略count = 1,它將看起來更像cat,並嘗試讀取直到EOF。

+0

對於2,我仍然懷疑。我的意思是爲什麼我們需要檢查偏移返回值?我們正在檢查它是否會無限期停止閱讀。但爲什麼閱讀調用認爲默認的len值爲32768? –

+0

我已經編輯了答案以擴展32768的來源。 – Peter

+0

現在這真的很有幫助,非常感謝.. !! –

0

對於2,確保在使用mknod時將模塊作爲char設備啓動。

mknod /dev/you_device c major_number minor_number