/* gpio_drv.c */ #include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/kernel.h> /* printk() */ #include <linux/slab.h> /* kmalloc() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/types.h> /* size_t */ #include <linux/mm.h> #include <linux/kdev_t.h> #include <linux/cdev.h> #include <linux/delay.h> #include <linux/device.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/arch-s3c2410/regs-gpio.h> //#include "gpio_drv.h" /**********************************************/ #ifndef FS2410_GPIO_SET_H #define FS2410_GPIO_SET_H #include <linux/ioctl.h> #define GPIO_DEVICE_NAME "gpio" #define GPIO_DEVICE_FILENAME "/dev/gpio" #define LED_NUM 4 #define GPIO_IOCTL_MAGIC 'G' #define LED_D09_SWT _IOW(GPIO_IOCTL_MAGIC, 0, unsigned int) #define LED_D10_SWT _IOW(GPIO_IOCTL_MAGIC, 1, unsigned int) #define LED_D11_SWT _IOW(GPIO_IOCTL_MAGIC, 2, unsigned int) #define LED_D12_SWT _IOW(GPIO_IOCTL_MAGIC, 3, unsigned int) #define BEEP_SWT _IOW(GPIO_IOCTL_MAGIC, 4, unsigned int) #define LED_SWT_ON 0 #define LED_SWT_OFF 1 #define BEEP_SWT_ON 1 #define BEEP_SWT_OFF 0 #endif /* FS2410_GPIO_SET_H */ /*********************************************/ static int major = 0; /* 采用字符设备号的动态分配*/ module_param(major, int, 0); /* 以参数的方式可以指定设备的主设备号*/ void s3c2410_gpio_cfgpin_led(unsigned int pin, unsigned int function) { /* 对某个管脚进行配置(输入/输出/其他功能)*/ unsigned long base = S3C2410_GPIO_BASE(pin); /* 获得端口的组基地址 unsigned long shift = 1; unsigned long mask = 0x03; /* 通常用配置寄存器的两位表示一个端口*/ unsigned long con; unsigned long flags; if (pin < S3C2410_GPIO_BANKB) { shift = 0; mask = 0x01; /* 在GPA端口中用配置寄存器的一位表示一个端口*/ } mask <<= (S3C2410_GPIO_OFFSET(pin) << shift); local_irq_save(flags); /* 保存现场,保证下面一段是原子操作*/ con = __raw_readl(base + 0x00); con &= ~mask; con |= function; __raw_writel(con, base + 0x00); /* 向配置寄存器写入新配置数据*/ local_irq_restore(flags); /* 恢复现场*/ } void s3c2410_gpio_pullup_led(unsigned int pin, unsigned int to) { /* 配置上拉功能*/ unsigned long base = S3C2410_GPIO_BASE(pin); /* 获得端口的组基地址*/ unsigned long offs = S3C2410_GPIO_OFFSET(pin);/* 获得端口的组内偏移地址*/ unsigned long flags; unsigned long up; if (pin < S3C2410_GPIO_BANKB) { return; } local_irq_save(flags); up = __raw_readl(base + 0x08); up &= ~(1 << offs); up |= to << offs; __raw_writel(up, base + 0x08); /* 向上拉功能寄存器写入新配置数据*/ local_irq_restore(flags); } void s3c2410_gpio_setpin_led(unsigned int pin, unsigned int to) { /* 向某个管脚进行输出*/ unsigned long base = S3C2410_GPIO_BASE(pin); unsigned long offs = S3C2410_GPIO_OFFSET(pin); unsigned long flags; unsigned long dat; local_irq_save(flags); dat = __raw_readl(base + 0x04); dat &= ~(1 << offs); dat |= to << offs; __raw_writel(dat, base + 0x04); /* 向数据寄存器写入新数据*/ local_irq_restore(flags); } int gpio_open (struct inode *inode, struct file *filp) { /* open操作函数:进行寄存器配置*/ s3c2410_gpio_pullup_led(S3C2410_GPB0, 1); /* BEEP*/ s3c2410_gpio_pullup_led(S3C2410_GPF4, 1); /* LED D12 */ s3c2410_gpio_pullup_led(S3C2410_GPF5, 1); /* LED D11 */ s3c2410_gpio_pullup_led(S3C2410_GPF6, 1); /* LED D10 */ s3c2410_gpio_pullup_led(S3C2410_GPF7, 1); /* LED D9 */ s3c2410_gpio_cfgpin_led(S3C2410_GPB0, S3C2410_GPB0_OUTP); s3c2410_gpio_cfgpin_led(S3C2410_GPF4, S3C2410_GPF4_OUTP); s3c2410_gpio_cfgpin_led(S3C2410_GPF4, S3C2410_GPF5_OUTP); s3c2410_gpio_cfgpin_led(S3C2410_GPF4, S3C2410_GPF6_OUTP); s3c2410_gpio_cfgpin_led(S3C2410_GPF4, S3C2410_GPF7_OUTP); return 0; } ssize_t gpio_read(struct file *file, char __user *buff,size_t count, loff_t *offp) { /* read操作函数:没有实际功能*/ return 0; } ssize_t gpio_write(struct file *file, const char __user *buff,size_t count, loff_t *offp) { /* write操作函数:没有实际功能*/ return 0; } int switch_gpio(unsigned int pin, unsigned int swt) { /* 向5个端口中的一个输出ON/OFF值*/ if (!((pin <= S3C2410_GPF7) && (pin >= S3C2410_GPF4)) && (pin != S3C2410_GPB0)) { printk("Unsupported pin"); return 1; } s3c2410_gpio_setpin_led(pin, swt); return 0; } static int gpio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg) { /* ioctl函数接口:主要接口的实现。对5个GPIO设备进行控制(发亮或发声) */ unsigned int swt = (unsigned int)arg; switch (cmd) { case LED_D09_SWT: { switch_gpio(S3C2410_GPF7, swt); break; } case LED_D10_SWT: { switch_gpio(S3C2410_GPF6, swt); break; } case LED_D11_SWT: { switch_gpio(S3C2410_GPF5, swt); break; } case LED_D12_SWT: { switch_gpio(S3C2410_GPF4, swt); break; } case BEEP_SWT: { switch_gpio(S3C2410_GPB0, swt); break; } default: { printk("Unsupported command\n"); break; } } return 0; } static int gpio_release(struct inode *node, struct file *file) { /* release操作函数,熄灭所有灯和关闭蜂鸣器*/ switch_gpio(S3C2410_GPB0, BEEP_SWT_OFF); switch_gpio(S3C2410_GPF4, LED_SWT_OFF); switch_gpio(S3C2410_GPF5, LED_SWT_OFF); switch_gpio(S3C2410_GPF6, LED_SWT_OFF); switch_gpio(S3C2410_GPF7, LED_SWT_OFF); return 0; } static void gpio_setup_cdev(struct cdev *dev, int minor,struct file_operations *fops) { /* 字符设备的创建和注册*/ int err, devno = MKDEV(major, minor); cdev_init(dev, fops); dev->owner = THIS_MODULE; dev->ops = fops; err = cdev_add (dev, devno, 1); if (err) { printk (KERN_NOTICE "Error %d adding gpio %d", err, minor); } } static struct file_operations gpio_fops = { /* gpio设备的file_operations结构定义*/ .owner = THIS_MODULE, .open = gpio_open, /* 进行初始化配置*/ .release = gpio_release, /* 关闭设备*/ .read = gpio_read, .write = gpio_write, .ioctl = gpio_ioctl, /* 实现主要控制功能*/ }; static struct cdev gpio_devs; static int gpio_init(void) { int result; dev_t dev = MKDEV(major, 0); if (major) { /* 设备号的动态分配*/ result = register_chrdev_region(dev, 1, GPIO_DEVICE_NAME); } else { /* 设备号的动态分配*/ result = alloc_chrdev_region(&dev, 0, 1, GPIO_DEVICE_NAME); major = MAJOR(dev); } if (result < 0) { printk(KERN_WARNING "Gpio: unable to get major %d\n", major); return result; } gpio_setup_cdev(&gpio_devs, 0, &gpio_fops); printk("The major of the gpio device is %d\n", major); return 0; } static void gpio_cleanup(void) { cdev_del(&gpio_devs); /* 字符设备的注销*/ unregister_chrdev_region(MKDEV(major, 0), 1); /* 设备号的注销*/ printk("Gpio device uninstalled\n"); } module_init(gpio_init); module_exit(gpio_cleanup);
测试程序:
/* gpio_test.c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include "gpio_drv.h" int led_timer(int dev_fd, int led_no, unsigned int time) { /*指定LED发亮一段时间之后熄灭它*/ led_no %= 4; ioctl(dev_fd, LED_D09_SWT + led_no, LED_SWT_ON); /* 发亮*/ sleep(time); ioctl(dev_fd, LED_D09_SWT + led_no, LED_SWT_OFF); /* 熄灭*/ } int beep_timer(int dev_fd, unsigned int time) {/* 开蜂鸣器一段时间之后关闭*/ ioctl(dev_fd, BEEP_SWT, BEEP_SWT_ON); /* 发声*/ sleep(time); ioctl(dev_fd, BEEP_SWT, BEEP_SWT_OFF); /* 关闭*/ } int main() { int i = 0; int dev_fd; /* 打开gpio设备*/ dev_fd = open(GPIO_DEVICE_FILENAME, O_RDWR | O_NONBLOCK); if ( dev_fd == -1 ) { printf("Cann't open gpio device file\n"); exit(1); } while(1) { i = (i + 1) % 4; led_timer(dev_fd, i, 1); beep_timer(dev_fd, 1); } close(dev_fd); return 0; }