首先:这是我第一次尝试为 Linux 内核做驱动程序,所以如果我完全错了,请告诉我。
在我当前的项目中,我们在板上添加了一个新设备(FPGA),我现在的任务是为该设备编写驱动程序。(我接受这个任务主要是因为我想学习,作为一个很大的挑战我)。
在 youtube 上花了几个小时后,我至少成功地完成了一个模块的框架,可以将其插入内核:
/* Match table for OF platform binding */
const struct of_device_id module_of_match[] = {
{ .compatible = "foo,testtest", },
{ /* end of list */},
};
MODULE_DEVICE_TABLE(of, module_of_match);
static int module_open(struct inode *inode, struct file *file_p) {
pr_notice("module_open is called\n");
return 0;
}
static int module_release(struct inode *inode, struct file *file_p) {
pr_notice("module_release is called\n");
return 0;
}
static ssize_t module_write(struct file *file_p, const char __user *user_buffer, size_t count, loff_t *f_pos) {
pr_notice("module_write is called\n");
return 0;
}
static ssize_t module_read(struct file *file_p, char __user *user_buffer, size_t count, loff_t *f_pos) {
pr_notice("module_read is called\n");
return 0;
}
static int module_probe(struct platform_device *pdev) {
int ret;
void __iomem *base_addr;
struct device *dev = &pdev->dev;
struct resource *res;
pr_notice("module_probe called...name: %s\n", pdev->name);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base_addr = devm_ioremap_resource(dev, res);
if(IS_ERR(base_addr)){
pr_err("module_probe: Error when calling devm_ioremap_resource\n");
return -1;
}
ret = misc_register(&module_dev);
if (ret) {
pr_err("module_probe: Failed to register module_dev\n");
return ret;
}
pr_notice("module_probe registered %s\n", &module_dev.name);
return 0;
}
static int module_remove(struct platform_device *pdev)
{
pr_info("module_remove called...\n");
misc_deregister(&module_dev);
return 0;
}
/* Driver operations */
struct platform_driver module_driver = {
.probe = module_probe,
.remove = module_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = module_of_match
},
};
/**
* @brief Structure holding configure file operations
*/
static struct file_operations module_fops = {
.owner = THIS_MODULE, ///< Owner of module
.open = module_open, ///< Open function
.release = module_release, ///< Release function
.read = module_read, ///< Read function
.write = module_write, ///< Write function
};
module_platform_driver(module_driver);
static struct miscdevice module_dev = {
.minor = MISC_DYNAMIC_MINOR, // Allocate a dynamic minor number
.name = DRIVER_NAME,
.fops = &module_fops,
};
设备树节点:
uart_dev: dev8@a0190000 {
compatible = "foo,testtest";
reg = <0x0 0xa0190000 0x0 0x10000>;
};
但现在我有点迷失在这里。 我想做的是能够使用设备中的寄存器0xa0190000,通过读写函数来读写一些值。 我发现一些 API 能够获取设备的资源,devm_ioremap_resource,但是之后我就迷失了。 我如何能够根据资源指针写入/读取寄存器?
或者这是错误的做法?
正如 0andriy 评论的那样,使用 readl 和 writel 读写寄存器效果很好:
u32 reg;
reg = readl(base_addr);
pr_notice("Reg read: %d\n", reg);
writel(0xff,base_addr);
reg = readl(base_addr);
pr_notice("Reg read: %d\n", reg);