/************************************************************************** * I.MX6 driver goto 使用 * 说明: * 在绝大多数地方,我们都被告诉尽可能不要用goto,甚至都没学过goto,但 * 这种语法却在内核驱动中普遍使用。 * * 2016-4-13 深圳 南山平山村 曾剑锋 *************************************************************************/ #include <linux/module.h> #include <linux/fs.h> #include <linux/gpio.h> #include <linux/miscdevice.h> #include <linux/delay.h> #define SABRESD_VO_PIN IMX_GPIO_NR(1, 4) #define SABRESD_AMPE_PIN IMX_GPIO_NR(1, 5) #define SABRESD_SD_PIN IMX_GPIO_NR(1, 19) #define SABRESD_DT_PIN IMX_GPIO_NR(3, 20) #define SPK_HEIGHT 66 #define SPK_LOW 67 #define AMP_HEIGHT 68 #define AMP_LOW 69 #define SD_HEIGHT 70 #define SD_LOW 71 #define DETECT 72 #define GPIO_CTRL_DEBUG #ifdef GPIO_CTRL_DEBUG #define mDebug(format, ...) printk("File:%s, Function:%s, Line:%d "format, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); #else #define mDebug(format, ...) #endif static int gpioCtrl_open(struct inode *inode, struct file *file) { mDebug("Dev open. "); return 0; } static int gpioCtrl_close(struct inode *inode, struct file *file) { mDebug("Dev close. "); return 0; } static ssize_t gpioCtrl_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { mDebug("Read data. "); return 0; } static long gpioCtrl_ioctl(struct file * file, unsigned int cmd, unsigned long arg) { int ret = 0; switch ( cmd ) { case SPK_HEIGHT : gpio_set_value(SABRESD_VO_PIN, 1); mDebug("SPK_HEIGHT. "); break; case SPK_LOW : gpio_set_value(SABRESD_VO_PIN, 0); mDebug("SPK_LOW. "); break; case AMP_HEIGHT : gpio_set_value(SABRESD_AMPE_PIN, 1); mDebug("AMP_HEIGHT. "); break; case AMP_LOW : gpio_set_value(SABRESD_AMPE_PIN, 0); mDebug("AMP_LOW. "); break; case SD_HEIGHT : gpio_set_value(SABRESD_SD_PIN, 1); mDebug("SD_HEIGHT. "); break; case SD_LOW : gpio_set_value(SABRESD_SD_PIN, 0); mDebug("SD_LOW. "); break; case DETECT : ret = gpio_get_value(SABRESD_DT_PIN); (*(int *)arg) = ret; mDebug("DETECT ret = %d. ", ret); ret = 0; break; default : mDebug("gpioCtrl control error. "); ret = -1; break; } return ret; } struct file_operations fops = { .owner = THIS_MODULE, .open = gpioCtrl_open, .release = gpioCtrl_close, .read = gpioCtrl_read, .unlocked_ioctl = gpioCtrl_ioctl, }; struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = "gpioCtrl", .fops = &fops, }; int __init gpioCtrl_init(void) { int ret; ret = gpio_request(SABRESD_VO_PIN, "SABRESD_VO_PIN"); if ( ret ) { mDebug("get SABRESD_VO_PIN gpio FAILED! "); return ret; } ret = gpio_request(SABRESD_AMPE_PIN, "SABRESD_AMPE_PIN"); if ( ret ) { mDebug("get SABRESD_AMPE_PIN gpio FAILED! "); goto fail1; } ret = gpio_request(SABRESD_SD_PIN, "SABRESD_SD_PIN"); if ( ret ) { mDebug("get SABRESD_SD_PIN gpio FAILED! "); goto fail2; } ret = gpio_request(SABRESD_DT_PIN, "SABRESD_DT_PIN"); if ( ret ) { mDebug("get SABRESD_DETECT gpio FAILED! "); goto fail3; } gpio_direction_output(SABRESD_VO_PIN, 0); gpio_direction_output(SABRESD_AMPE_PIN, 1); gpio_direction_output(SABRESD_SD_PIN, 1); gpio_direction_input(SABRESD_DT_PIN); ret = misc_register(&misc); if(ret) { mDebug("gpioCtrl_misc_register FAILED! "); goto fail4; } mDebug("gpioCtrl_misc_register over! "); return ret; fail4: gpio_free(SABRESD_DT_PIN); fail3: gpio_free(SABRESD_SD_PIN); fail2: gpio_free(SABRESD_AMPE_PIN); fail1: gpio_free(SABRESD_VO_PIN); return ret; } void __exit gpioCtrl_exit(void) { gpio_set_value(SABRESD_VO_PIN, 0); gpio_set_value(SABRESD_AMPE_PIN, 0); gpio_set_value(SABRESD_SD_PIN, 0); gpio_free(SABRESD_VO_PIN); gpio_free(SABRESD_AMPE_PIN); gpio_free(SABRESD_SD_PIN); gpio_free(SABRESD_DT_PIN); misc_deregister(&misc); } module_init(gpioCtrl_init); module_exit(gpioCtrl_exit); MODULE_LICENSE("GPL");