<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                驅動程序freg的目錄結構如下: ~~~ ~/Android/kernel/goldfish ----drivers ----freg ----freg.h ----freg.c ----Kconfig ----Makefile ~~~ 它由四個文件組成,其中freg.h和freg.c是源代碼文件,Kconfig是編譯選項配置文件,Makefile是編譯腳本文件。下面我們就分別介紹這四個文件的實現。 **freg.h** ~~~ #ifndef _FAKE_REG_H_ #define _FAKE_REG_H_ #include <linux/cdev.h> #include <linux/semaphore.h> #define FREG_DEVICE_NODE_NAME "freg" #define FREG_DEVICE_FILE_NAME "freg" #define FREG_DEVICE_PROC_NAME "freg" #define FREG_DEVICE_CLASS_NAME "freg" struct fake_reg_dev { int val; struct semaphore sem; struct cdev dev; }; #endif ~~~ 這個文件定義了四個字符串常量,分別用來描述虛擬硬件設備freg在設備文件系統中的名稱。此外,此文件還定義了一個結構體fake_reg_dev,用來描述虛擬硬件設備freg。在結構體fake_reg_dev中,成員變量val用來描述一個虛擬寄存器,它的類型為int;成員變量sem是一個信號量,用來同步訪問虛擬寄存器val;成員變量dev是一個標準的Linux字符設備結構體變量,用來標志該虛擬硬件設備freg的類型為字符設備。 **freg.c** 這個文件是驅動程序freg的實現文件,它向用戶空間提供了三個接口來訪問虛擬硬件設備freg中的寄存器val。第一個是proc文件系統接口,第二個是傳統的設備文件系統接口,第三個是devfs文件系統接口。下面我們就分段介紹該驅動程序的實現。 文件開頭包含了必要的頭文件,以及定義了一些相關的變量和函數原型,它們的含義可以參考代碼中的注釋。 ~~~ #include <linux/init.h> #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/proc_fs.h> #include <linux/device.h> #include <asm/uaccess.h> #include "freg.h" /*主設備號和從設備號變量*/ static int freg_major = 0; static int freg_minor = 0; /*設備類別和設備變量*/ static struct class* freg_class = NULL; static struct fake_reg_dev* freg_dev = NULL; /*傳統的設備文件操作方法*/ static int freg_open(struct inode* inode, struct file* filp); static int freg_release(struct inode* inode, struct file* filp); static ssize_t freg_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos); static ssize_t freg_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos); /*傳統的設備文件操作方法表*/ static struct file_operations freg_fops = { .owner = THIS_MODULE, .open = freg_open, .release = freg_release, .read = freg_read, .write = freg_write, }; /*devfs文件系統的設備屬性操作方法*/ static ssize_t freg_val_show(struct device* dev, struct device_attribute* attr, char* buf); static ssize_t freg_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count); /*devfs文件系統的設備屬性*/ static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, freg_val_show, freg_val_store); ~~~ 接下來,定義用來訪問虛擬硬件設備freg的傳統設備文件系統接口,主要是實現freg_open、freg_release、freg_read和freg_write四個函數,其中,前面兩個函數用來打開和關閉虛擬硬件設備freg,而后面兩個函數用來讀取和寫入虛擬硬件設備freg中的寄存器val。這些函數的實現細節可以參考代碼中的注釋,如下所示。 ~~~ /*打開設備方法*/ static int freg_open(struct inode* inode, struct file* filp) { struct fake_reg_dev* dev; /*將自定義設備結構體保存在文件指針的私有數據域中,以便訪問設備時可以直接拿來用*/ dev = container_of(inode->i_cdev, struct fake_reg_dev, dev); filp->private_data = dev; return 0; } /*設備文件釋放時調用,空實現*/ static int freg_release(struct inode* inode, struct file* filp) { return 0; } /*讀取設備的寄存器val的值*/ static ssize_t freg_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) { ssize_t err = 0; struct fake_reg_dev* dev = filp->private_data; /*同步訪問*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } if(count < sizeof(dev->val)) { goto out; } /*將寄存器val的值拷貝到用戶提供的緩沖區中*/ if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) { err = -EFAULT; goto out; } err = sizeof(dev->val); out: up(&(dev->sem)); return err; } /*寫設備的寄存器val的值*/ static ssize_t freg_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) { struct fake_reg_dev* dev = filp->private_data; ssize_t err = 0; /*同步訪問*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } if(count != sizeof(dev->val)) { goto out; } /*將用戶提供的緩沖區的值寫到設備寄存器中*/ if(copy_from_user(&(dev->val), buf, count)) { err = -EFAULT; goto out; } err = sizeof(dev->val); out: up(&(dev->sem)); return err; } ~~~ 接下來,我們繼續定義用來訪問虛擬硬件設備freg的devfs文件系統接口。這種硬件訪問接口將虛擬硬件設備freg的寄存器val當作設備的一個屬性,通過讀寫這個屬性就可以達到訪問設備的目的,這是通過調用freg_val_show和freg_val_store這兩個函數來實現的。為了方便后面編寫proc文件系統接口來訪問虛擬硬件設備freg,我們定義了兩個內部使用的函數__freg_get_val和__freg_set_val,它們分別用來讀寫虛擬硬件設備freg的寄存器val。它們的實現如下所示。 ~~~ /*將寄存器val的值讀取到緩沖區buf中,內部使用*/ static ssize_t __freg_get_val(struct fake_reg_dev* dev, char* buf) { int val = 0; /*同步訪問*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } val = dev->val; up(&(dev->sem)); return snprintf(buf, PAGE_SIZE, "%d\n", val); } /*把緩沖區buf的值寫到設備寄存器val中,內部使用*/ static ssize_t __freg_set_val(struct fake_reg_dev* dev, const char* buf, size_t count) { int val = 0; /*將字符串轉換成數字*/ val = simple_strtol(buf, NULL, 10); /*同步訪問*/ if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } dev->val = val; up(&(dev->sem)); return count; } /*讀設備屬性val的值*/ static ssize_t freg_val_show(struct device* dev, struct device_attribute* attr, char* buf) { struct fake_reg_dev* hdev = (struct fake_reg_dev*)dev_get_drvdata(dev); return __freg_get_val(hdev, buf); } /*寫設備屬性val的值*/ static ssize_t freg_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) { struct fake_reg_dev* hdev = (struct fake_reg_dev*)dev_get_drvdata(dev); return __freg_set_val(hdev, buf, count); } ~~~ 接下來,我們繼續定義用來訪問虛擬硬件設備freg的proc文件系統接口,主要是實現freg_proc_read和freg_proc_write這兩個函數。同時,我們還定義了用來在proc文件系統中創建和刪除/proc/freg文件的函數freg_create_proc和freg_remove_proc。它們的實現如下所示。 ~~~ /*讀取設備寄存器val的值,保存到page緩沖區中*/ static ssize_t freg_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) { if(off > 0) { *eof = 1; return 0; } return __freg_get_val(freg_dev, page); } /*把緩沖區的值buff保存到設備寄存器val中*/ static ssize_t freg_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) { int err = 0; char* page = NULL; if(len > PAGE_SIZE) { printk(KERN_ALERT"The buff is too large: %lu.\n", len); return -EFAULT; } page = (char*)__get_free_page(GFP_KERNEL); if(!page) { printk(KERN_ALERT"Failed to alloc page.\n"); return -ENOMEM; } /*先把用戶提供的緩沖區的值拷貝到內核緩沖區中*/ if(copy_from_user(page, buff, len)) { printk(KERN_ALERT"Failed to copy buff from user.\n"); err = -EFAULT; goto out; } err = __freg_set_val(freg_dev, page, len); out: free_page((unsigned long)page); return err; } /*創建/proc/freg文件*/ static void freg_create_proc(void) { struct proc_dir_entry* entry; entry = create_proc_entry(FREG_DEVICE_PROC_NAME, 0, NULL); if(entry) { entry->owner = THIS_MODULE; entry->read_proc = freg_proc_read; entry->write_proc = freg_proc_write; } } /*刪除/proc/freg文件*/ static void freg_remove_proc(void) { remove_proc_entry(FREG_DEVICE_PROC_NAME, NULL); } ~~~ 最后,我們定義驅動程序freg的模塊加載與卸載函數freg_init和freg_exit。函數freg_init主要用來注冊和初始化虛擬硬件設備freg,而函數freg_exit用來反注冊和釋放虛擬硬件設備freg。它們的實現如下所示。 ~~~ /*初始化設備*/ static int __freg_setup_dev(struct fake_reg_dev* dev) { int err; dev_t devno = MKDEV(freg_major, freg_minor); memset(dev, 0, sizeof(struct fake_reg_dev)); /*初始化字符設備*/ cdev_init(&(dev->dev), &freg_fops); dev->dev.owner = THIS_MODULE; dev->dev.ops = &freg_fops; /*注冊字符設備*/ err = cdev_add(&(dev->dev),devno, 1); if(err) { return err; } /*初始化信號量和寄存器val的值*/ init_MUTEX(&(dev->sem)); dev->val = 0; return 0; } /*模塊加載方法*/ static int __init freg_init(void) { int err = -1; dev_t dev = 0; struct device* temp = NULL; printk(KERN_ALERT"Initializing freg device.\n"); /*動態分配主設備號和從設備號*/ err = alloc_chrdev_region(&dev, 0, 1, FREG_DEVICE_NODE_NAME); if(err < 0) { printk(KERN_ALERT"Failed to alloc char dev region.\n"); goto fail; } freg_major = MAJOR(dev); freg_minor = MINOR(dev); /*分配freg設備結構體*/ freg_dev = kmalloc(sizeof(struct fake_reg_dev), GFP_KERNEL); if(!freg_dev) { err = -ENOMEM; printk(KERN_ALERT"Failed to alloc freg device.\n"); goto unregister; } /*初始化設備*/ err = __freg_setup_dev(freg_dev); if(err) { printk(KERN_ALERT"Failed to setup freg device: %d.\n", err); goto cleanup; } /*在/sys/class/目錄下創建設備類別目錄freg*/ freg_class = class_create(THIS_MODULE, FREG_DEVICE_CLASS_NAME); if(IS_ERR(freg_class)) { err = PTR_ERR(freg_class); printk(KERN_ALERT"Failed to create freg device class.\n"); goto destroy_cdev; } /*在/dev/目錄和/sys/class/freg目錄下分別創建設備文件freg*/ temp = device_create(freg_class, NULL, dev,NULL,"%s", FREG_DEVICE_FILE_NAME); if(IS_ERR(temp)) { err = PTR_ERR(temp); printk(KERN_ALERT"Failed to create freg device.\n"); goto destroy_class; } /*在/sys/class/freg/freg目錄下創建屬性文件val*/ err = device_create_file(temp, &dev_attr_val); if(err < 0) { printk(KERN_ALERT"Failed to create attribute val of freg device.\n"); goto destroy_device; } dev_set_drvdata(temp, freg_dev); /*創建/proc/freg文件*/ freg_create_proc(); printk(KERN_ALERT"Succeeded to initialize freg device.\n"); return 0; destroy_device: device_destroy(freg_class, dev); destroy_class: class_destroy(freg_class); destroy_cdev: cdev_del(&(freg_dev->dev)); cleanup: kfree(freg_dev); unregister: unregister_chrdev_region(MKDEV(freg_major, freg_minor), 1); fail: return err; } /*模塊卸載方法*/ static void __exit freg_exit(void) { dev_t devno = MKDEV(freg_major, freg_minor); printk(KERN_ALERT"Destroy freg device.\n"); /*刪除/proc/freg文件*/ freg_remove_proc(); /*銷毀設備類別和設備*/ if(freg_class) { device_destroy(freg_class, MKDEV(freg_major, freg_minor)); class_destroy(freg_class); } /*刪除字符設備和釋放設備內存*/ if(freg_dev) { cdev_del(&(freg_dev->dev)); kfree(freg_dev); } /*釋放設備號資源*/ unregister_chrdev_region(devno, 1); } MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Fake Register Driver"); module_init(freg_init); module_exit(freg_exit); ~~~ 驅動程序freg的源文件準備好之后,接下來就要為它編寫編譯選項配置文件和編譯腳本文件了。 **Kconfig** ~~~ config FREG tristate "Fake Register Driver" default n help This is the freg driver for android system. ~~~ 這個文件定義了驅動程序freg的編譯選項。在編譯驅動程序freg之前,我們可以通過執行make menuconfig命令來設置這些編譯選項,以便可以指定驅動程序freg的編譯方式。從這個配置文件就可以看出,驅動程序freg可以以三種方式來編譯。第一種方式是直接內建在內核中;第二種方式是編譯成內核模塊;第三種方式是不編譯到內核中。默認的編譯方式為n,即不編譯到內核中,因此,在編譯驅動程序freg之前,我們需要執行make menuconfig命令來修改它的編譯選項,以便可以將驅動程序freg內建到內核中或者以模塊的方式來編譯。 **Makefile** `obj-$(CONFIG_FREG) += freg.o` 這是驅動程序freg的編譯腳本文件,其中,$(CONFIG_FREG)是一個變量,它的值與驅動程序freg的編譯選項有關。如果選擇將驅動程序freg內建到內核中,那么變量$(CONFIG_FREG)的值為y;如果選擇以模塊的方式來編譯驅動程序freg,那么變量$(CONFIG_FREG)的值為m;如果變量$(CONFIG_FREG)的值既不為y,也不為m,那么驅動程序freg就不會被編譯。 至此,我們就為虛擬硬件設備freg開發了一個驅動程序。接下來,我們還需要修改內核中的Kconfig和Makefile文件來支持驅動程序freg的編譯。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看