本文学习Linux内核源码中的驱动对于错误的一种处理方法。使用 goto语句来处理错误。
本文以前面的驱动代码为例,即 3_newchrled工程代码为例,在此基础上进行举例说明。
3_newchrled工程中,newchrled.c文件中的函数,一般出错处理是直接 return 返回一个错误码。
如果在 Linux内核源码中搜索可以发现, 是使用了 goto语法进行的另一种处理方法。
这里以 newchrled.c文件中的入口函数为例,在此基础上使用 goto语法来处理错误:
/*驱动模块入口函数 */
static int __init newchrled_init(void)
{
int ret = 0;
unsigned int value = 0;
printk("newchrled_init!\r\n");
/* 1. Led灯的IO初始化 */
//地址映射
IMX6ULL_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);
IMX6ULL_SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);
IMX6ULL_SW_PAD_GPIO01_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);
IMX6ULL_GDIR = ioremap(GPIO1_GDIR_BASE, 4);
IMX6ULL_DR = ioremap(GPIO1_DR_BASE, 4);
.......................................................
/* 2. 注册字符设备 */
//设备号的分配
newchrled.major = 0;
if(newchrled.major) //给定主设备号
{
newchrled.devid = MKDEV(newchrled.major, 0);
ret = register_chrdev_region(newchrled.devid, NEWCHRLED_COUNT, NEWCHRLED);
}
else{ //没有给定主设备号
ret = alloc_chrdev_region(&(newchrled.devid), 0, NEWCHRLED_COUNT, NEWCHRLED);
newchrled.major = MAJOR(newchrled.devid);
newchrled.minor = MINOR(newchrled.devid);
}
if (ret < 0) {
printk("register-chrdev failed!\n");
goto fail_devid;
}
//初始化设备
cdev_init(&newchrled.led_cdev, &fops);
//注册设备
ret = cdev_add(&newchrled.led_cdev, newchrled.devid, NEWCHRLED_COUNT);
if(ret < 0)
{
printk("cdev_add failed!\r\n");
goto fail_adddev;
}
/* 3.自动创建设备节点 */
//创建类
newchrled.led_class = class_create(THIS_MODULE, NEWCHRLED);
if (IS_ERR(newchrled.led_class)) {
ret = PTR_ERR(newchrled.led_class);
goto fail_class;
}
//创建设备
newchrled.led_device = device_create(newchrled.led_class, NULL, newchrled.devid, NULL, NEWCHRLED);
if (IS_ERR(newchrled.led_device)) {
ret = PTR_ERR(newchrled.led_device);
goto fail_dev_create;
}
return 0;
fail_dev_create:
class_destroy(newchrled.led_class);
fail_class:
cdev_del(&newchrled.led_cdev);
fail_adddev:
unregister_chrdev_region(newchrled.devid, NEWCHRLED_COUNT);
fail_devid:
return ret;
}
可以看出,当出现错误的时候,直接使用 goto语句进行跳转,直接跳转到函数的末尾。
对于不同层级的错误,跳转到不同的错误项。而错误项的存放位置也是有前后顺序的,因为越是2、3、4等越深层级的错误,需要释放前面的一些资源后,才能返回。