在Linux裝置驅動之《點亮一盞LED》 中,編寫了ioctl_c.h這樣的標頭檔,在本文中將繼續使用這一標頭檔,代碼如下:
#ifndef __IOCTL_C_H__<br />#define __IOCTL_C_H__<br />typedef struct GPIO_Data_t<br />{<br />unsigned int port;<br />unsigned int bit;<br />unsigned int value;<br />unsigned int v;<br />}GPIO_Data_S;<br />#define GPIO_IOC_MAGIC 12 //Documentation/ioctl-number.txt<br />#define GPIO_IO_SET _IOW(GPIO_IOC_MAGIC,0,sizeof(GPIO_Data_S))<br />#define GPIO_IO_GET _IOWR(GPIO_IOC_MAGIC,1,sizeof(GPIO_Data_S))<br />#define GPIO_IO_WRITE _IOW(GPIO_IOC_MAGIC,2,sizeof(GPIO_Data_S))<br />#define GPIO_IO_READ _IOWR(GPIO_IOC_MAGIC,3,sizeof(GPIO_Data_S))<br />#endif
然後則是驅動模組程式,代碼如下所示:
#include <linux/types.h><br />#include <linux/fs.h><br />#include <linux/mm.h><br />#include <linux/errno.h><br />#include <linux/module.h><br />#include <linux/moduleparam.h><br />#include <linux/kernel.h><br />#include <asm/uaccess.h><br />#include <linux/cdev.h><br />#include <linux/ioctl.h><br />#include <linux/slab.h><br />#include <linux/fcntl.h><br />#include <asm/segment.h><br />#include <asm/io.h><br />#include <asm/arch/regs-gpio.h><br />#include "ioctl_c.h"<br />unsigned int test_major=253;<br />unsigned int test_minor=0;<br />struct cdev cdevc;<br />MODULE_LICENSE("Dual BSD/GPL");<br />GPIO_Data_S ioctl;<br />static int read_test(struct file *file,char *buf,int count ,loff_t *f_pos)<br />{<br />printk("/n read_test");<br />printk("%d",count);<br />return count;<br />}<br />static int write_test(struct file *file,const char *buf,int count, loff_t *f_pos)<br />{<br />printk("/n write_test");<br />return count;<br />}<br />static void gpio_cfg()<br />{<br />size_t Data;<br />printk("gpio_cfg start!/n");<br />Data = __raw_readl(ioctl.port*0x10+S3C2410_GPACON);<br />Data &= ~(3<<2*ioctl.bit);<br />Data |= (ioctl.value<<2*ioctl.bit);<br />__raw_writel(Data,ioctl.port*0x10+S3C2410_GPACON);<br />}<br />static void gpio_read()<br />{<br />printk("gpio_read start!!/n");<br />size_t Data_con,Data_dat;<br />Data_con = __raw_readl(ioctl.port*0x10+S3C2410_GPACON);<br />Data_dat = __raw_readl(ioctl.port*0x10+S3C2410_GPADAT);<br />printk("%ld/n%ld/n",Data_con,Data_dat);<br />}<br />static void gpio_write()<br />{<br />printk("gpio-write start!!/n");<br />size_t Data;<br />Data = __raw_readl(ioctl.port*0x10+S3C2410_GPADAT);<br />Data &= ~(1<<ioctl.bit);<br />Data |=(ioctl.v<<ioctl.bit);<br />__raw_writel(Data,ioctl.port*0x10+S3C2410_GPADAT);<br />}<br />static int ioctl_test(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)<br />{<br />if(copy_from_user(&ioctl,arg,sizeof(GPIO_Data_S)))<br />{<br />return - EFAULT;<br />}<br />printk("/n ioctl_test");<br />switch(cmd)<br />{<br />case GPIO_IO_SET:gpio_cfg();break;<br />//case GPIO_IO_GET:;break;<br />case GPIO_IO_WRITE:gpio_write();break;<br />case GPIO_IO_READ:gpio_read();break;<br />default:break;<br />}<br />return cmd;<br />}<br />static int open_test(struct inode *inode,struct file *file)<br />{<br />printk("/n open_test");<br />return 0;<br />}<br />static void release_test(struct inode *inode,struct file *file)<br />{<br />printk("/n release_test");<br />}<br />struct file_operations test_fops = {<br />.owner=THIS_MODULE,<br />.read=read_test,<br />.write=write_test,<br />.open=open_test,<br />.ioctl=ioctl_test,<br />.release=release_test,<br />};<br />int simple_c_init_module(void)<br />{<br />int result;<br />dev_t dev = 0;</p><p>dev=MKDEV(test_major,test_minor);<br />result = register_chrdev_region(dev,1,"test");</p><p>printk("major= %d,minor=%d /n",test_major,test_minor);</p><p>if(result < 0)<br />{<br />printk(KERN_INFO "test : can't get major number/n");<br />return result;<br />}</p><p>cdev_init(&cdevc,&test_fops);<br />cdevc.owner= THIS_MODULE;<br />cdevc.ops=&test_fops;<br />result=cdev_add(&cdevc,dev,1);<br />if(result)<br />printk("Error %d adding test",result);<br />return 0;<br />}<br />void simple_c_cleanup_module(void)<br />{<br />dev_t dev=0;<br />dev = MKDEV(test_major,test_minor);<br />cdev_del(&cdevc);<br />unregister_chrdev_region(dev,1);<br />}<br />module_init(simple_c_init_module);<br />module_exit(simple_c_cleanup_module);
這裡只說明與前面模組程式的區別,首先是ioctl_test函數
static int ioctl_test(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
if(copy_from_user(&ioctl,arg,sizeof(GPIO_Data_S)))
{
return - EFAULT;
}
printk("/n ioctl_test");
switch(cmd)
{
case GPIO_IO_SET:gpio_cfg();break;
// case GPIO_IO_GET:;break;
case GPIO_IO_WRITE:gpio_write();break;
case GPIO_IO_READ:gpio_read();break;
default:break;
}
return cmd;
}
這裡多出了
case GPIO_IO_SET:gpio_cfg();break;
case GPIO_IO_WRITE:gpio_write();break;
case GPIO_IO_READ:gpio_read();break;
三個函數,從名稱上可以得知分別是對IO的配置和讀寫操作,具體是怎麼實現的呢,那麼馬上轉移到這三個函數去瞅瞅
static void gpio_cfg()
{
size_t Data;
printk("gpio_cfg start!/n");
Data = __raw_readl(ioctl.port*0x10+S3C2410_GPACON);
Data &= ~(3<<2*ioctl.bit);
Data |= (ioctl.value<<2*ioctl.bit);
__raw_writel(Data,ioctl.port*0x10+S3C2410_GPACON);
}
函數說明:這個函數是用來配置GPGCON的函數。
static void gpio_read()
{
printk("gpio_read start!!/n");
size_t Data_con,Data_dat;
Data_con = __raw_readl(ioctl.port*0x10+S3C2410_GPACON);
Data_dat = __raw_readl(ioctl.port*0x10+S3C2410_GPADAT);
printk("%ld/n%ld/n",Data_con,Data_dat);
}
函數說明:讀取GPIO函數。
static void gpio_write()
{
printk("gpio-write start!!/n");
size_t Data;
Data = __raw_readl(ioctl.port*0x10+S3C2410_GPADAT);
Data &= ~(1<<ioctl.bit);
Data |= (ioctl.v<<ioctl.bit);
__raw_writel(Data,ioctl.port*0x10+S3C2410_GPADAT);
}
函數說明:寫GPIO函數。
下面是應用程式,這裡編寫應用程式就變得方便多了,需要什麼IO就先配置,再讀寫
#include <stdio.h><br />#include <sys/types.h><br />#include <sys/stat.h><br />#include <fcntl.h><br />#include <unistd.h><br />#include <linux/ioctl.h><br />#include "../ioctl_c.h"<br />GPIO_Data_S io_ctl;<br />void main(void)<br />{<br />int testdev;<br />int i;<br />char buf[10];<br />testdev = open ("/dev/test",O_RDWR);<br />if(testdev == -1)<br />{<br />printf("Cann't open file...../n");<br />exit(0);<br />}<br />printf("buf = 0x%x/n",buf);<br />read(testdev,buf,10);<br />write(testdev,buf,1);<br />while(1)<br />{<br />io_ctl.port=6;<br />io_ctl.bit=5;<br />io_ctl.value=1;<br />io_ctl.v=0;<br />ioctl(testdev,GPIO_IO_SET,&io_ctl);<br />ioctl(testdev,GPIO_IO_WRITE,&io_ctl);<br />ioctl(testdev,GPIO_IO_READ,&io_ctl);<br />io_ctl.port=6;<br /> io_ctl.bit=6;<br /> io_ctl.value=1;<br /> io_ctl.v=1;<br /> ioctl(testdev,GPIO_IO_SET,&io_ctl);<br /> ioctl(testdev,GPIO_IO_WRITE,&io_ctl);<br /> ioctl(testdev,GPIO_IO_READ,&io_ctl);<br />sleep(1);<br />io_ctl.port=6;<br />io_ctl.bit=6;<br />io_ctl.value=1;<br />io_ctl.v=0;<br />ioctl(testdev,GPIO_IO_SET,&io_ctl);<br />ioctl(testdev,GPIO_IO_WRITE,&io_ctl);<br />ioctl(testdev,GPIO_IO_READ,&io_ctl);<br />io_ctl.port=6;<br /> io_ctl.bit=5;<br /> io_ctl.value=1;<br /> io_ctl.v=1;<br /> ioctl(testdev,GPIO_IO_SET,&io_ctl);<br /> ioctl(testdev,GPIO_IO_WRITE,&io_ctl);<br /> ioctl(testdev,GPIO_IO_READ,&io_ctl);<br />sleep(1);<br />}<br />//ioctl(testdev,GPIO_IO_WRITE,sizeof(GPIO_Data_S));<br />//ioctl(testdev,GPIO_IO_READ,sizeof(GPIO_Data_S));<br />printf("%s",buf);<br />//for(i = 0;i<10;i++)<br />//printf("[%d]/n",buf[i]);<br />close(testdev);<br />}<br />/*<br />mknod /dev/test c 253 0<br />*/