TQ2440 GPIO驱动及测试代码,v2:将策略和机制分开,驱动只实现机制,应用层实现策略
下一步需要做的优化:
a. 打印优化
b. 错误处理--资源释放
driver src:
#include "gpio.h" // ref arch/arm/mach-s3c24xx/mach-mini2440.c how to set gpio MODULE_LICENSE("GPL"); /* datasheet: page274 — Port A(GPA): 25-output port — Port B(GPB): 11-input/out port — Port C(GPC): 16-input/output por — Port D(GPD): 16-input/output por — Port E(GPE): 16-input/output por — Port F(GPF): 8-input/output port — Port G(GPG): 16-input/output po — Port H(GPH): 9-input/output port — Port J(GPJ): 13-input/output port */ #define S3C_ADDR_BASE 0xF6000000 #define S3C_ADDR(x) (S3C_ADDR_BASE + (x)) #define S3C2410_PA_UART (0x50000000) #define S3C2410_PA_GPIO (0x56000000) #define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */ #define S3C24XX_PA_UART S3C2410_PA_UART #define S3C24XX_VA_UART S3C_VA_UART #define S3C24XX_PA_GPIO S3C2410_PA_GPIO #define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART) #define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO) #define S3C2410_GPBCON S3C2410_GPIOREG(0x10) #define S3C2410_GPBDAT S3C2410_GPIOREG(0x14) #define S3C2410_GPBUP S3C2410_GPIOREG(0x18) typedef struct { unsigned port; unsigned pin; unsigned val; }kobox_ioctl_st; #define KOBOX_GPIO_IOCTL_MAIGC 'g' #define KOBOX_GPIO_IOCTL_WRITE _IOWR(KOBOX_GPIO_IOCTL_MAIGC, 0, kobox_ioctl_st) #define KOBOX_GPIO_IOCTL_READ _IOWR(KOBOX_GPIO_IOCTL_MAIGC, 1, kobox_ioctl_st) static int kobox_gpio_open(struct inode *inode, struct file *file) { return 0; } static int kobox_gpio_release(struct inode *inode, struct file *file) { return 0; } static ssize_t kobox_gpio_read(struct file *file, __user char *buf, size_t count, loff_t *offp) { return 0; } static ssize_t kobox_gpio_write(struct file *file, const char __user *buf, size_t count, loff_t *offp) { return 0; } //set mux, set GPB_0 as gpio and output /* PORT CONFIGURATION REGISTER (GPACON-GPJCON) In S3C2440A, most of the pins are multiplexed pins. So, It is determined which function is selected for each pins. The PnCON(port control register) determines which function is used for each pin. GPBCON 0x56000010 R/W Configures the pins of port B 0x0 GPB0 [1:0] 00 = Input 01 = Output 10 = TOUT0 11 = reserved GPB1 [3:2] 00 = Input 01 = Output 10 = TOUT1 11 = reserved GPB2 [5:4] 00 = Input 01 = Output 10 = TOUT2 11 = reserved GPB3 [7:6] 00 = Input 01 = Output 10 = TOUT3 11 = reserved GPB4 [9:8] 00 = Input 01 = Output 10 = TCLK [0] 11 = reserved GPB5 [11:10] 00 = Input 01 = Output 10 = nXBACK 11 = reserved GPB6 [13:12] 00 = Input 01 = Output 10 = nXBREQ 11 = reserved GPB7 [15:14] 00 = Input 01 = Output 10 = nXDACK1 11 = Reserved GPB8 [17:16] 00 = Input 01 = Output 10 = nXDREQ1 11 = Reserved GPB9 [19:18] 00 = Input 01 = Output 10 = nXDACK0 11 = reserved GPB10 [21:20] 00 = Input 01 = Output 10 = nXDREQ0 11 = reserved */ static int gpio_portb_set_init(unsigned pin) { unsigned uiVal = 0; uiVal = readl(S3C2410_GPBCON); uiVal |= (0x01<<(2*pin)); uiVal &= ~(0x01 <<((2*pin)+1)) ; writel(uiVal, S3C2410_GPBCON); return 0; } /* GPB[10:0] [10:0] When the port is configured as input port, the corresponding bit is the pin state. When the port is configured as output port, the pin state is the same as the corresponding bit. When the port is configured as functional pin, the undefined value will be read. */ static int gpio_portb_set_val(unsigned pin, unsigned val) { unsigned uiVal = 0; printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__); printk("####[pin:%d][val:%d]\n", pin, val); if(0 == val) { uiVal = readl(S3C2410_GPBDAT); uiVal &= ~(0x01 << pin) ; writel(uiVal, S3C2410_GPBDAT); } else if(1 == val) { uiVal = readl(S3C2410_GPBDAT); uiVal |= (0x01 << pin); writel(uiVal, S3C2410_GPBDAT); } printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__); return 0; } static int set_gpio_portb_val(unsigned pin, unsigned val) { printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__); printk("####[pin:%d][val:%d]\n", pin, val); gpio_portb_set_init(pin); gpio_portb_set_val(pin, val); printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__); return 0; } /* GPA: port = 0 GPB: port = 1 GPC: port = 2 ... */ static int set_gpio_val(unsigned port, unsigned pin, unsigned val) { int ret; printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__); if(port == 1) { ret = set_gpio_portb_val(pin, val); if(ret < 0) { printk("set_gpio_portb_val failed!\n"); } } else { printk("not support other gpio ports now!\n"); return -1; } printk("####[func:%s][line:%d]\n",__FUNCTION__,__LINE__); return ret; } static long kobox_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { kobox_ioctl_st stGpioArg; unsigned port; unsigned pin; unsigned val; switch(cmd) { case KOBOX_GPIO_IOCTL_WRITE: printk("case KOBOX_GPIO_IOCTL_WRITE\n"); copy_from_user((void*)&stGpioArg, (const void*)arg, sizeof(kobox_ioctl_st)); port = stGpioArg.port; pin = stGpioArg.pin; val = stGpioArg.val; set_gpio_val(port, pin, val); break; case KOBOX_GPIO_IOCTL_READ: printk("case KOBOX_GPIO_IOCTL_READ\n"); break; default: printk("Invalid cmd:%x\n", cmd); return -1; } return 0; } struct file_operations kobox_gpio_operations = { .owner = THIS_MODULE, .open = kobox_gpio_open, .release = kobox_gpio_release, .read = kobox_gpio_read, .write = kobox_gpio_write, .unlocked_ioctl = kobox_gpio_ioctl, }; //GPB0 int __init gpio_drv_init(void) { int error; dev_t dev; int major; int minor; struct cdev cdev; struct class *kobox_gpio_class; printk("#####enter gpio_drv_init!\n"); major = register_chrdev(0, "kobox_gpio", &kobox_gpio_operations); if (major < 0) { printk(" can't register major number\n"); return major; } /* create class */ kobox_gpio_class = class_create(THIS_MODULE, "kobox_gpio"); if(IS_ERR(kobox_gpio_class)) { printk("class_create failed!\n"); goto fail; } /* create /dev/kobox_gpio */ device_create(kobox_gpio_class, NULL, MKDEV(major, 0), NULL, "kobox_gpio"); printk("#####gpio_drv_init ok!\n"); return 0; fail: unregister_chrdev_region(cdev.dev, 1); return -1; } void __exit gpio_drv_exit(void) { printk("exit gpio drv!\n"); // if(dev) // unregister_chrdev_region(cdev.dev, 1); return; } module_init(gpio_drv_init); module_exit(gpio_drv_exit);
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <unistd.h> #define GPIO_NAME "/dev/kobox_gpio" typedef struct { unsigned port; unsigned pin; unsigned val; }kobox_ioctl_st; #define KOBOX_GPIO_IOCTL_MAIGC 'g' #define KOBOX_GPIO_IOCTL_WRITE _IOWR(KOBOX_GPIO_IOCTL_MAIGC, 0, kobox_ioctl_st) #define KOBOX_GPIO_IOCTL_READ _IOWR(KOBOX_GPIO_IOCTL_MAIGC, 1, kobox_ioctl_st) int main(int argc, char *argv[]) { int i = 0; int fd = -1; int ret = 0; kobox_ioctl_st stGpioArg; fd = open(GPIO_NAME, O_RDWR); if(fd < 0) { printf("open /dev/kobox_gpio failed!\n"); return -1; } printf("fd=%d\n", fd); stGpioArg.port = 1;//GPB:port = 1 stGpioArg.pin = 0; for(i=0; i<=10;i++) { stGpioArg.val = i%2; printf("###port:%u, pin:%u, val:%u\n", stGpioArg.port, stGpioArg.pin, stGpioArg.val); ret = ioctl(fd, KOBOX_GPIO_IOCTL_WRITE, &stGpioArg); if(ret < 0) { printf("ioctl failed!\n"); return -1; } sleep(1); } close(fd); return 0; }
(1)蜂鸣器会每秒叫一次
(2)输出:
[\u@\h \W]# chmod 777 gpiotest [\u@\h \W]# ./gpiotest fd=3 case KOBOX_GPIO_IOCTL_WRITE ####[func:set_gpio_val][line:200] ####[func:set_gpio_portb_val][line:179] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:156] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:172] ####[func:set_gpio_portb_val][line:185] ####[func:set_gpio_val][line:216] ###port:1, pin:0, val:0 ###port:1, pin:0, val:1 case KOBOX_GPIO_IOCTL_WRITE ####[func:set_gpio_val][line:200] ####[func:set_gpio_portb_val][line:179] ####[pin:0][val:1] ####[func:gpio_portb_set_val][line:156] ####[pin:0][val:1] ####[func:gpio_portb_set_val][line:172] ####[func:set_gpio_portb_val][line:185] ####[func:set_gpio_val][line:216] ###port:1, pin:0, val:0 case KOBOX_GPIO_IOCTL_WRITE ####[func:set_gpio_val][line:200] ####[func:set_gpio_portb_val][line:179] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:156] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:172] ####[func:set_gpio_portb_val][line:185] ####[func:set_gpio_val][line:216] ###port:1, pin:0, val:1 case KOBOX_GPIO_IOCTL_WRITE ####[func:set_gpio_val][line:200] ####[func:set_gpio_portb_val][line:179] ####[pin:0][val:1] ####[func:gpio_portb_set_val][line:156] ####[pin:0][val:1] ####[func:gpio_portb_set_val][line:172] ####[func:set_gpio_portb_val][line:185] ####[func:set_gpio_val][line:216] ###port:1, pin:0, val:0 case KOBOX_GPIO_IOCTL_WRITE ####[func:set_gpio_val][line:200] ####[func:set_gpio_portb_val][line:179] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:156] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:172] ####[func:set_gpio_portb_val][line:185] ####[func:set_gpio_val][line:216] ###port:1, pin:0, val:1 case KOBOX_GPIO_IOCTL_WRITE ####[func:set_gpio_val][line:200] ####[func:set_gpio_portb_val][line:179] ####[pin:0][val:1] ####[func:gpio_portb_set_val][line:156] ####[pin:0][val:1] ####[func:gpio_portb_set_val][line:172] ####[func:set_gpio_portb_val][line:185] ####[func:set_gpio_val][line:216] ###port:1, pin:0, val:0 case KOBOX_GPIO_IOCTL_WRITE ####[func:set_gpio_val][line:200] ####[func:set_gpio_portb_val][line:179] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:156] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:172] ####[func:set_gpio_portb_val][line:185] ####[func:set_gpio_val][line:216] ###port:1, pin:0, val:1 case KOBOX_GPIO_IOCTL_WRITE ####[func:set_gpio_val][line:200] ####[func:set_gpio_portb_val][line:179] ####[pin:0][val:1] ####[func:gpio_portb_set_val][line:156] ####[pin:0][val:1] ####[func:gpio_portb_set_val][line:172] ####[func:set_gpio_portb_val][line:185] ####[func:set_gpio_val][line:216] ###port:1, pin:0, val:0 case KOBOX_GPIO_IOCTL_WRITE ####[func:set_gpio_val][line:200] ####[func:set_gpio_portb_val][line:179] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:156] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:172] ####[func:set_gpio_portb_val][line:185] ####[func:set_gpio_val][line:216] ###port:1, pin:0, val:1 case KOBOX_GPIO_IOCTL_WRITE ####[func:set_gpio_val][line:200] ####[func:set_gpio_portb_val][line:179] ####[pin:0][val:1] ####[func:gpio_portb_set_val][line:156] ####[pin:0][val:1] ####[func:gpio_portb_set_val][line:172] ####[func:set_gpio_portb_val][line:185] ####[func:set_gpio_val][line:216] ###port:1, pin:0, val:0 case KOBOX_GPIO_IOCTL_WRITE ####[func:set_gpio_val][line:200] ####[func:set_gpio_portb_val][line:179] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:156] ####[pin:0][val:0] ####[func:gpio_portb_set_val][line:172] ####[func:set_gpio_portb_val][line:185] ####[func:set_gpio_val][line:216]
a. 打印优化
b. 错误处理--资源释放