日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

IO静态映射和动态映射

發(fā)布時(shí)間:2025/3/15 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IO静态映射和动态映射 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1:靜態(tài)映射方法的特點(diǎn):

? 內(nèi)核移植時(shí)以代碼的形式硬編碼,如果要更改必須改源代碼后重新編譯內(nèi)核在內(nèi)核啟動(dòng)時(shí)建立靜態(tài)映射表,到內(nèi)核關(guān)機(jī)時(shí)銷毀,中間一直有效對(duì)于移植好的內(nèi)核,你用不用他都在那里

?

2:動(dòng)態(tài)映射方法的特點(diǎn):

? 驅(qū)動(dòng)程序根據(jù)需要隨時(shí)動(dòng)態(tài)的建立映射、使用、銷毀映射映射是短期臨時(shí)的

?

3:如何選擇虛擬地址映射方法

? (1)2種映射并不排他,可以同時(shí)使用

? (2)靜態(tài)映射類似于C語(yǔ)言中全局變量,動(dòng)態(tài)方式類似于C語(yǔ)言中malloc堆內(nèi)存

? (3)靜態(tài)映射的好處是執(zhí)行效率高,壞處是始終占用虛擬地址空間;動(dòng)態(tài)映射的 好處是按需使用虛擬地址空間,壞處是每次使用前后都需要代碼去建立映射&銷毀映射(還得學(xué)會(huì)使用那些內(nèi)核函數(shù)的使用)

?

4:靜態(tài)映射表

? 不同版本的內(nèi)核,其靜態(tài)映射表的文件名以及文件路徑不一定相同,但是一般都在arch/arm/xxx/map_xx.h文件中

? (1)s5pv210的主映射表位于:arch/arm/plat-s5p/include/plat/map-s5p.h。

CPU在安排寄存器地址時(shí)不是隨意亂序分布的,而是按照模塊去區(qū)分的。每一個(gè)模塊內(nèi)部的很多個(gè)寄存器的地址是連續(xù)的。所以內(nèi)核在定義寄存器地址時(shí)都是先找到基地址,然后再用基地址+偏移量來(lái)尋找具體的一個(gè)寄存器。這個(gè)文件夾下面的虛擬地址基地址是不全的,原因是三星在移植的時(shí)候只是移植了自己需要的部分,將來(lái)我們需要添加其他基地址的時(shí)候直接添加就行了。map-s5p.h中定義的就是要用到的幾個(gè)模塊的寄存器基地址(虛擬地址)。

? (2)虛擬地址基地址定義在:arch/arm/plat-samsung/include/plat/map-base.h

#define S3C_ADDR_BASE (0xFD000000) //?三星移植時(shí)確定的靜態(tài)映射表的基地址,表中的所有虛擬地址都是以這個(gè)地址+偏移量來(lái)指定的。

? (3)GPIO相關(guān)的主映射表位于:arch/arm/machs5pv210/include/mach/regs-gpio.h

表中是GPIO的各個(gè)端口的基地址的定義

? (4)GPIO的具體寄存器定義位于:arch/arm/mach-s5pv210/include/mach/gpio-bank.h

#include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <mach/regs-gpio.h> #include <mach/gpio-bank.h> #include <linux/io.h> #include <asm/uaccess.h>#define GPJ0CON S5PV210_GPJ0CON #define GPJ0DAT S5PV210_GPJ0DAT//#define MYMAJOR 200 #define MYCNT 1 #define MYNAME "testchar"char kbuf[100];static dev_t mydev; static struct cdev test_cdev; static struct class *test_class;static int test_chrdev_open(struct inode *inode, struct file *file) {printk(KERN_INFO "test_chrdev_open...\n");/* 配置IO為輸出 */writel((1 << 12) | (1 << 16) | (1 << 20), GPJ0CON);writel((1 << 3) | (1 << 4) | (1 << 5), GPJ0DAT);return 0; }static int test_chrdev_release(struct inode *inode, struct file *file) {printk(KERN_INFO "test_chrdev_release...\n");/* 關(guān)閉所有LED */writel((1 << 3) | (1 << 4) | (1 << 5), GPJ0DAT);return 0; }ssize_t test_chrdev_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) {printk(KERN_INFO "test_chrdev_read...\n");return 0; }static ssize_t test_chrdev_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) {int ret = -1;printk(KERN_INFO "test_chrdev_write...\n");/* 清空內(nèi)存 */memset(kbuf, 0, sizeof(kbuf));/* 將數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間 */ret = copy_from_user(kbuf, ubuf, count);if (ret){printk(KERN_ERR "copy_from_user fail\n");return -EINVAL;}/* 判斷LED打開(kāi)還是關(guān)閉 */if (kbuf[0] == '1')writel((0 << 3) | (0 << 4) | (0 << 5), GPJ0DAT);else if (kbuf[0] == '0')writel((1 << 3) | (1 << 4) | (1 << 5), GPJ0DAT);return 0; }static const struct file_operations test_fops = {.owner = THIS_MODULE,.open = test_chrdev_open,.release = test_chrdev_release,.write = test_chrdev_write,.read = test_chrdev_read, };static int __init chrdev_init(void) { int retval;printk(KERN_INFO "chrdev_init...\n");/* 分配主次設(shè)備號(hào) */ /*mydev = MKDEV(MYMAJOR, 0);retval = register_chrdev_region(mydev, MYCNT, MYNAME);if (retval) {printk(KERN_ERR "Unable to register minors for %s\n", MYNAME);return -EINVAL;} */retval = alloc_chrdev_region(&mydev, 12, MYCNT, MYNAME);if (retval < 0) {printk(KERN_ERR "Unable to alloc minors for %s\n", MYNAME);goto flag1;}printk(KERN_INFO "alloc_chrdev_region success\n");printk(KERN_INFO "major = %d, minor = %d.\n", MAJOR(mydev), MINOR(mydev));/* 注冊(cè)字符設(shè)備驅(qū)動(dòng) */cdev_init(&test_cdev, &test_fops);retval = cdev_add(&test_cdev, mydev, MYCNT);if (retval) {printk(KERN_ERR "Unable to cdev_add\n");goto flag2;}printk(KERN_INFO "cdev_add success\n");/* 創(chuàng)建設(shè)備類 */test_class = class_create(THIS_MODULE, "test_class");if (IS_ERR(test_class)) {printk(KERN_ERR "Unable to class_create\n");goto flag3;}/* 創(chuàng)建設(shè)備節(jié)點(diǎn) */device_create(test_class, NULL, mydev, NULL, "test");return 0;flag3:cdev_del(&test_cdev);flag2:unregister_chrdev_region(mydev, MYCNT); flag1: return -EINVAL; }static void __exit chrdev_exit(void) {printk(KERN_INFO "chrdev_exit...\n");/* 銷毀設(shè)備類節(jié)點(diǎn) */device_destroy(test_class, mydev);class_destroy(test_class);/* 注銷字符設(shè)備驅(qū)動(dòng) */cdev_del(&test_cdev);/* 注銷申請(qǐng)的主次設(shè)備號(hào) */unregister_chrdev_region(mydev, MYCNT); }module_init(chrdev_init); module_exit(chrdev_exit);MODULE_LICENSE("GPL"); // 描述模塊的許可證 MODULE_AUTHOR("lsm"); // 描述模塊的作者 MODULE_DESCRIPTION("module test"); // 描述模塊的介紹信息 MODULE_ALIAS("alias xxx"); // 描述模塊的別名信息

?

5:動(dòng)態(tài)映射操作LED

5.1:如何建立動(dòng)態(tài)映射

? (1)request_mem_region:向內(nèi)核申請(qǐng)(報(bào)告)需要映射的內(nèi)存資源。

? (2)ioremap:真正用來(lái)實(shí)現(xiàn)映射,傳給他物理地址他返回給你一個(gè)虛擬地址

? 返回值:成功返回一個(gè)虛擬地址(或者是一段虛擬地址的首地址,具體取決于我們需要映射的字節(jié)長(zhǎng)度),失敗返回0

5.2:如何銷毀動(dòng)態(tài)映射

? (1)iounmap:解除映射

? (2)release_mem_region:釋放映射

#include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/io.h> #include <asm/uaccess.h>#define GPJ0CON_PA 0xe0200240 #define GPJ0DAT_PA 0xe0200244unsigned int *pGPJ0CON; unsigned int *pGPJ0DAT;//#define MYMAJOR 200 #define MYCNT 1 #define MYNAME "testchar"char kbuf[100];static dev_t mydev; static struct cdev test_cdev; static struct class *test_class;static int test_chrdev_open(struct inode *inode, struct file *file) {printk(KERN_INFO "test_chrdev_open...\n");/* 配置IO為輸出 */writel((1 << 12) | (1 << 16) | (1 << 20), pGPJ0CON);writel((1 << 3) | (1 << 4) | (1 << 5), pGPJ0DAT);return 0; }static int test_chrdev_release(struct inode *inode, struct file *file) {printk(KERN_INFO "test_chrdev_release...\n");/* 關(guān)閉所有LED */writel((1 << 3) | (1 << 4) | (1 << 5), pGPJ0DAT);return 0; }ssize_t test_chrdev_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) {printk(KERN_INFO "test_chrdev_read...\n");return 0; }static ssize_t test_chrdev_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) {int ret = -1;printk(KERN_INFO "test_chrdev_write...\n");/* 清空內(nèi)存 */memset(kbuf, 0, sizeof(kbuf));/* 將數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間 */ret = copy_from_user(kbuf, ubuf, count);if (ret){printk(KERN_ERR "copy_from_user fail\n");return -EINVAL;}/* 判斷LED打開(kāi)還是關(guān)閉 */if (kbuf[0] == '1')writel((0 << 3) | (0 << 4) | (0 << 5), pGPJ0DAT);else if (kbuf[0] == '0')writel((1 << 3) | (1 << 4) | (1 << 5), pGPJ0DAT);return 0; }static const struct file_operations test_fops = {.owner = THIS_MODULE,.open = test_chrdev_open,.release = test_chrdev_release,.write = test_chrdev_write,.read = test_chrdev_read, };static int __init chrdev_init(void) { int retval;printk(KERN_INFO "chrdev_init...\n");/* 分配主次設(shè)備號(hào) */ /*mydev = MKDEV(MYMAJOR, 0);retval = register_chrdev_region(mydev, MYCNT, MYNAME);if (retval) {printk(KERN_ERR "Unable to register minors for %s\n", MYNAME);return -EINVAL;} */retval = alloc_chrdev_region(&mydev, 12, MYCNT, MYNAME);if (retval < 0) {printk(KERN_ERR "Unable to alloc minors for %s\n", MYNAME);goto flag1;}printk(KERN_INFO "alloc_chrdev_region success\n");printk(KERN_INFO "major = %d, minor = %d.\n", MAJOR(mydev), MINOR(mydev));/* 注冊(cè)字符設(shè)備驅(qū)動(dòng) */cdev_init(&test_cdev, &test_fops);retval = cdev_add(&test_cdev, mydev, MYCNT);if (retval) {printk(KERN_ERR "Unable to cdev_add\n");goto flag2;}printk(KERN_INFO "cdev_add success\n");/* 創(chuàng)建設(shè)備類 */test_class = class_create(THIS_MODULE, "test_class");if (IS_ERR(test_class)) {printk(KERN_ERR "Unable to class_create\n");goto flag3;}/* 創(chuàng)建設(shè)備節(jié)點(diǎn) */device_create(test_class, NULL, mydev, NULL, "test");/* 申請(qǐng)內(nèi)存 */if (!request_mem_region(GPJ0CON_PA, 4, "GPJ0CON"))goto err4;if (!request_mem_region(GPJ0DAT_PA, 4, "GPJ0DAT"))goto err5; /* 內(nèi)存映射 */pGPJ0CON = ioremap(GPJ0CON_PA, 4);pGPJ0DAT = ioremap(GPJ0DAT_PA, 4);return 0;err5:release_mem_region(GPJ0CON_PA, 4); err4:device_destroy(test_class, mydev);class_destroy(test_class);flag3:cdev_del(&test_cdev);flag2:unregister_chrdev_region(mydev, MYCNT); flag1: return -EINVAL; }static void __exit chrdev_exit(void) {printk(KERN_INFO "chrdev_exit...\n");iounmap(pGPJ0CON);iounmap(pGPJ0DAT);release_mem_region(GPJ0CON_PA, 4);release_mem_region(GPJ0DAT_PA, 4);/* 銷毀設(shè)備類節(jié)點(diǎn) */device_destroy(test_class, mydev);class_destroy(test_class);/* 注銷字符設(shè)備驅(qū)動(dòng) */cdev_del(&test_cdev);/* 注銷申請(qǐng)的主次設(shè)備號(hào) */unregister_chrdev_region(mydev, MYCNT); }module_init(chrdev_init); module_exit(chrdev_exit);MODULE_LICENSE("GPL"); // 描述模塊的許可證 MODULE_AUTHOR("lsm"); // 描述模塊的作者 MODULE_DESCRIPTION("module test"); // 描述模塊的介紹信息 MODULE_ALIAS("alias xxx"); // 描述模塊的別名信息

?

總結(jié)

以上是生活随笔為你收集整理的IO静态映射和动态映射的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。