国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
字符驅動學習
Linux下的設備驅動程序被組織為一組完成不同任務的函數(shù)的集合,通過這些函數(shù)使得Windows的設備操作猶如文件一般。在應用程序看來,硬件設備只是一個設備文件,應用程序可以象操作普通文件一樣對硬件設備進行操作,如open ()、close ()、read ()、write () 等。
Linux主要將設備分為二類:字符設備和塊設備。字符設備是指設備發(fā)送和接收數(shù)據(jù)以字符的形式進行;而塊設備則以整個數(shù)據(jù)緩沖區(qū)的形式進行。字符設備的驅動相對比較簡單。

  下面我們來假設一個非常簡單的虛擬字符設備:這個設備中只有一個4個字節(jié)的全局變量int global_var,而這個設備的名字叫做"gobalvar"。對"gobalvar"設備的讀寫等操作即是對其中全局變量global_var的操作。

  驅動程序是內核的一部分,因此我們需要給其添加模塊初始化函數(shù),該函數(shù)用來完成對所控設備的初始化工作,并調用register_chrdev() 函數(shù)注冊字符設備:

static int __init gobalvar_init(void)
{
 if (register_chrdev(MAJOR_NUM, " gobalvar ", &gobalvar_fops))
 {
  //…注冊失敗
 }
 else
 {
  //…注冊成功
 }
}

  其中,register_chrdev函數(shù)中的參數(shù)MAJOR_NUM為主設備號,"gobalvar"為設備名,gobalvar_fops為包含基本函數(shù)入口點的結構體,類型為file_operations。當gobalvar模塊被加載時,gobalvar_init被執(zhí)行,它將調用內核函數(shù)register_chrdev,把驅動程序的基本入口點指針存放在內核的字符設備地址表中,在用戶進程對該設備執(zhí)行系統(tǒng)調用時提供入口地址。

  與模塊初始化函數(shù)對應的就是模塊卸載函數(shù),需要調用register_chrdev()的"反函數(shù)" unregister_chrdev():

static void __exit gobalvar_exit(void)
{
 if (unregister_chrdev(MAJOR_NUM, " gobalvar "))
 {
  //…卸載失敗
 }
 else
 {
  //…卸載成功
 }
}

  隨著內核不斷增加新的功能,file_operations結構體已逐漸變得越來越大,但是大多數(shù)的驅動程序只是利用了其中的一部分。對于字符設備來說,要提供的主要入口有:open ()、release ()、read ()、write ()、ioctl ()、llseek()、poll()等。

  open()函數(shù) 對設備特殊文件進行open()系統(tǒng)調用時,將調用驅動程序的open () 函數(shù):

int (*open)(struct inode * ,struct file *);

  其中參數(shù)inode為設備特殊文件的inode (索引結點) 結構的指針,參數(shù)file是指向這一設備的文件結構的指針。open()的主要任務是確定硬件處在就緒狀態(tài)、驗證次設備號的合法性(次設備號可以用MINOR(inode-> i - rdev) 取得)、控制使用設備的進程數(shù)、根據(jù)執(zhí)行情況返回狀態(tài)碼(0表示成功,負數(shù)表示存在錯誤) 等;

  release()函數(shù) 當最后一個打開設備的用戶進程執(zhí)行close ()系統(tǒng)調用時,內核將調用驅動程序的release () 函數(shù):

void (*release) (struct inode * ,struct file *) ;

  release 函數(shù)的主要任務是清理未結束的輸入/輸出操作、釋放資源、用戶自定義排他標志的復位等。

  read()函數(shù) 當對設備特殊文件進行read() 系統(tǒng)調用時,將調用驅動程序read() 函數(shù):

ssize_t (*read) (struct file *, char *, size_t, loff_t *);

  用來從設備中讀取數(shù)據(jù)。當該函數(shù)指針被賦為NULL 值時,將導致read 系統(tǒng)調用出錯并返回-EINVAL("Invalid argument,非法參數(shù)")。函數(shù)返回非負值表示成功讀取的字節(jié)數(shù)(返回值為"signed size"數(shù)據(jù)類型,通常就是目標平臺上的固有整數(shù)類型)。

  globalvar_read函數(shù)中內核空間與用戶空間的內存交互需要借助第2節(jié)所介紹的函數(shù):

static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
 …
 copy_to_user(buf, &global_var, sizeof(int));
 …
}

  write( ) 函數(shù) 當設備特殊文件進行write () 系統(tǒng)調用時,將調用驅動程序的write () 函數(shù):

ssize_t (*write) (struct file *, const char *, size_t, loff_t *);

  向設備發(fā)送數(shù)據(jù)。如果沒有這個函數(shù),write 系統(tǒng)調用會向調用程序返回一個-EINVAL。如果返回值非負,則表示成功寫入的字節(jié)數(shù)。
globalvar_write函數(shù)中內核空間與用戶空間的內存交互需要借助第2節(jié)所介紹的函數(shù):

static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{

copy_from_user(&global_var, buf, sizeof(int));

}

  ioctl() 函數(shù) 該函數(shù)是特殊的控制函數(shù),可以通過它向設備傳遞控制信息或從設備取得狀態(tài)信息,函數(shù)原型為:

int (*ioctl) (struct inode * ,struct file * ,unsigned int ,unsigned long);

  unsigned int參數(shù)為設備驅動程序要執(zhí)行的命令的代碼,由用戶自定義,unsigned long參數(shù)為相應的命令提供參數(shù),類型可以是整型、指針等。如果設備不提供ioctl 入口點,則對于任何內核未預先定義的請求,ioctl 系統(tǒng)調用將返回錯誤(-ENOTTY,"No such ioctl fordevice,該設備無此ioctl 命令")。如果該設備方法返回一個非負值,那么該值會被返回給調用程序以表示調用成功。

  llseek()函數(shù) 該函數(shù)用來修改文件的當前讀寫位置,并將新位置作為(正的)返回值返回,原型為:

loff_t (*llseek) (struct file *, loff_t, int);

  poll()函數(shù) poll 方法是poll 和select 這兩個系統(tǒng)調用的后端實現(xiàn),用來查詢設備是否可讀或可寫,或是否處于某種特殊狀態(tài),原型為:

unsigned int (*poll) (struct file *, struct poll_table_struct *);


  我們將在"設備的阻塞與非阻塞操作"一節(jié)對該函數(shù)進行更深入的介紹。

設備"gobalvar"的驅動程序的這些函數(shù)應分別命名為gobalvar_open、gobalvar_ release、gobalvar_read、gobalvar_write、gobalvar_ioctl,因此設備"gobalvar"的基本入口點結構變量gobalvar_fops 賦值如下:

struct file_operations gobalvar_fops = {
 read: gobalvar_read,
 write: gobalvar_write,
};

  上述代碼中對gobalvar_fops的初始化方法并不是標準C所支持的,屬于GNU擴展語法。

  完整的globalvar.c文件源代碼如下:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");

#define MAJOR_NUM 254 //主設備號

static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*);
static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);

//初始化字符設備驅動的file_operations結構體
struct file_operations globalvar_fops =
{
 read: globalvar_read,

   write: globalvar_write,
};
static int global_var = 0; //"globalvar"設備的全局變量

static int __init globalvar_init(void)
{
 int ret;

 //注冊設備驅動
 ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops);
 if (ret)
 {
  printk("globalvar register failure");
 }
 else
 {
  printk("globalvar register success");
 }
 return ret;
}

static void __exit globalvar_exit(void)
{
 int ret;

 //注銷設備驅動
 ret = unregister_chrdev(MAJOR_NUM, "globalvar");
 if (ret)
 {
  printk("globalvar unregister failure");
 }
 else
 {
  printk("globalvar unregister success");
 }
}

static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
 //將global_var從內核空間復制到用戶空間
 if (copy_to_user(buf, &global_var, sizeof(int)))
 {
  return - EFAULT;
 }
 return sizeof(int);
}

static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
 //將用戶空間的數(shù)據(jù)復制到內核空間的global_var
 if (copy_from_user(&global_var, buf, sizeof(int)))
 {
  return - EFAULT;
 }
 return sizeof(int);
}

module_init(globalvar_init);
module_exit(globalvar_exit);


  運行:

gcc -D__KERNEL__ -DMODULE -DLINUX -I /usr/local/src/linux2.4/include -c -o globalvar.o globalvar.c

  編譯代碼,運行:

inmod globalvar.o

  加載globalvar模塊,再運行:

cat /proc/devices

  發(fā)現(xiàn)其中多出了"254 globalvar"一行,如下圖:


  接著我們可以運行:

mknod /dev/globalvar c 254 0

  創(chuàng)建設備節(jié)點,用戶進程通過/dev/globalvar這個路徑就可以訪問到這個全局變量虛擬設備了。我們寫一個用戶態(tài)的程序globalvartest.c來驗證上述設備:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
main()
{
 int fd, num;
 //打開"/dev/globalvar"
 fd = open("/dev/globalvar", O_RDWR, S_IRUSR | S_IWUSR);
 if (fd != -1 )
 {
  //初次讀globalvar
  read(fd, &num, sizeof(int));
  printf("The globalvar is %d\n", num);

  //寫globalvar
  printf("Please input the num written to globalvar\n");
  scanf("%d", &num);
  write(fd, &num, sizeof(int));

  //再次讀globalvar
  read(fd, &num, sizeof(int));
  printf("The globalvar is %d\n", num);

  //關閉"/dev/globalvar"
  close(fd);
 }
 else
 {
  printf("Device open failure\n");
 }
}

  編譯上述文件:

gcc -o globalvartest.o globalvartest.c

  運行

./globalvartest.o

  可以發(fā)現(xiàn)"globalvar"設備可以正確的讀寫。

本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
深入淺出Linux設備驅動之字符設備驅動程序
linux字符設備文件的打開操作
Linux字符設備驅動程序編寫基本流程
第三章 字符設備驅動程序|Linux.CN
深入淺出:Linux設備驅動之字符設備驅動 - 博客 - 伯樂在線
Linux內核分析(五)
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服