中断方式的驱动:
/*============================s3c2410-adc.h============================*/
#ifndef _S3C2410_ADC_H_
#define _S3C2410_ADC_H_
#define ADC_WRITE(ch, prescale) ((ch)<<16|(prescale))
#define ADC_WRITE_GETCH(data) (((data)>>16)&0x7)
#define ADC_WRITE_GETPRE(data) ((data)&0xff)
#endif /* _S3C2410_ADC_H_ */
/*==========================s3c2410-adc.c===============================*/
#include
#include
#include
#include
#include
#include
#include /* printk() */
#include /* kmalloc() */
#include /* everything... */
#include /* error codes */
#include /* size_t */
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "s3c2410-adc.h"
#define DEVICE_NAME "adc"
#define ADCRAW_MINOR 0
#define ADC_INPUT(x) ((x)<<3)
#define PRSCVL(x) ((x)<<6)
#define ADCCON 0x58000000
#define ADCDAT0 0x5800000c
#define CLKCON 0x4c00000c
static int adc_major = 244; //在0~255之间自由分配
static volatile unsigned int *adccon;
static volatile unsigned int *adcdat0;
static volatile unsigned int *clkcon;
typedef struct
{
struct semaphore lock; //声明一个信号量
wait_queue_head_t wait; //声明一个等待队列头
int channel;//选择哪一路AD转换器
int prescale;//预分频值
}ADC_DEV;
static ADC_DEV adcdev;
/*==中断处理函数==*/
static irqreturn_t adcdone_int_handler(int irq,void *dev_id,struct pt_regs *regs)
{
wake_up(&adcdev.wait);//唤醒等待队列
return IRQ_HANDLED ;
}
/*==打开设备==*/
static int s3c2410_adc_open(struct inode *inode, struct file *filp)
{
int ret;
printk("in adc open");
ret = request_irq(IRQ_ADC, adcdone_int_handler, SA_INTERRUPT, DEVICE_NAME, NULL);//注册中断例程
if (ret)
{
return ret;
}
init_MUTEX(&adcdev.lock);//初始化一个互斥的信号量,并设置为1
init_waitqueue_head(&(adcdev.wait));//初始化等待队列
adcdev.channel=0; //缺省为0通道
adcdev.prescale=0xff; //预分频的缺省为 0xff
printk(KERN_INFO"adc opened\n");
return 0;
}
/*==对设备进行写操作,buffer一定是用户空间的==*/
static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
int data;
if(count!=sizeof(data))
{
printk(KERN_INFO"the size of input data must be %d\n", sizeof(data));
return 0;
}
copy_from_user(&data, buffer, count); //从用户空间拷贝数据到内核空间
adcdev.channel=ADC_WRITE_GETCH(data); //得到哪一路AD转换器
adcdev.prescale=ADC_WRITE_GETPRE(data); //得到预分频值
// printk(KERN_INFO "adcdev.channel=%d\n",adcdev.channel);
// printk(KERN_INFO"set adc channel=%d, prescale=0x%x\n", adcdev.channel, adcdev.prescale);
return count;
}
/*==对设备进行读操作,buffer一定是用户空间的==*/
static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
int ret = 0;
if (down_interruptible(&adcdev.lock))//获得信号量
return -ERESTARTSYS;
writel(readl(adccon) &(~1), adccon);//对AD控制寄存器进行操作,具体参看s3c2410 datasheet
writel( (1<<14) | (255<<6) |(1<<0)|(1<<0)| ADC_INPUT(adcdev.channel), adccon);
sleep_on( &adcdev.wait );
ret = readl(adcdat0);
ret &= 0x3ff;
// printk(KERN_INFO "%d\n",adcdev.channel);
// printk(KERN_INFO"AIN[%d] = 0x%04x, %d\n", adcdev.channel, ret, readl(S3C2410_ADCCON) & 0x80 ? 1:0);
copy_to_user(buffer, (char *)&ret, sizeof(ret));//拷贝内核数据到用户空间
up(&adcdev.lock);
return sizeof(ret);
}
/*==关闭设备==*/
static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{
free_irq(IRQ_ADC, NULL);//释放中断资源
printk(KERN_INFO"adc closed\n");
return 0;
}
/*==初始化并添加结构提struct cdev到系统之中==*/
static void adc_setup_cdev(struct cdev *dev, int minor,struct file_operations *fops)
{
int err, devno = MKDEV(adc_major, minor);
cdev_init(dev, fops); //初始化结构体struct cdev
dev->owner = THIS_MODULE;
dev->ops = fops; //给结构体里的ops成员赋初值,这里是对设备操作的具体的实现函数
err = cdev_add (dev, devno, 1);//将结构提struct cdev添加到系统之中
/* Fail gracefully if need be */
if (err)
printk (KERN_NOTICE "Error %d adding adc %d", err, minor);
}
static struct cdev AdcDevs;
/*==定义一个file_operations结构体,来实现对设备的具体操作的功能==*/
static struct file_operations adc_remap_ops = {
owner: THIS_MODULE,
open: s3c2410_adc_open,
read: s3c2410_adc_read,
write: s3c2410_adc_write,
release: s3c2410_adc_release,
};
/*==初始化设备驱动模块,主要完成对字符设备结构体的初始化和添加到系统中,并得到一个设备的设备号==*/
static int adc_init(void)
{
// writel(0,S3C2410_ADCTSC); //XP_PST(NOP_MODE);
int result;
dev_t dev = MKDEV(adc_major, 0);//将主设备号和次设备号定义到一个dev_t数据类型的结构体之中
/* Figure out our device number. */
if (adc_major)
result = register_chrdev_region(dev, 1, "adc");//静态注册一个设备,设备号先前指定好,并得到一个设备名,cat /proc/device来查看信息
else
{
result = alloc_chrdev_region(&dev, 0, 1, "adc");//如果主设备号被占用,则由系统提供一个主设备号给设备驱动程序
adc_major = MAJOR(dev);//得到主设备号
}
if (result < 0)
{
return result;
}
if (adc_major == 0)
adc_major = result;//如果静态分配失败。把动态非配的设备号给设备驱动程序
adc_setup_cdev(&AdcDevs, 0, &adc_remap_ops);//初始化和添加结构体struct cdev到系统之中
//do ioremap
adccon = ioremap(ADCCON, 0x4);
adcdat0 = ioremap(ADCDAT0, 0x4);
clkcon = ioremap(CLKCON, 0x4);
printk(KERN_INFO"adc clock = %d\n", *clkcon & (0x1<<15));
*clkcon |= 0x1 << 15; //open clock for adc
printk(KERN_INFO"adc device installed, with major %d\n", adc_major);
return 0;
}
/*==卸载驱动模块==*/
static void adc_cleanup(void)
{
iounmap(adccon);
iounmap(adcdat0);
cdev_del(&AdcDevs);//删除结构体struct cdev
unregister_chrdev_region(MKDEV(adc_major, 0), 1);//卸载设备驱动所占有的资源
printk(KERN_INFO"adc device uninstalled\n");
}
module_init(adc_init);//初始化设备驱动程序的入口
module_exit(adc_cleanup);//卸载设备驱动程序的入口
MODULE_LICENSE("Dual BSD/GPL");//模块应该指定代码所使用的许可证
/*============================adc_test.c===============================*/
#include
#include
#include
#include
#include
#include
#include
#include "s3c2410-adc.h"
#define ADC_DEV "/dev/adc"
static int adc_fd = -1;
static int init_ADdevice(void)
{
printf(ADC_DEV);
if((adc_fd=open(ADC_DEV,O_RDWR))<0)//打开设备
{
printf("Error opening %d adc device\n", adc_fd);
return -1;
}
}
static int GetADresult(int channel)
{
int PRESCALE=0XFF;
int data=ADC_WRITE(channel, PRESCALE);
write(adc_fd, &data, sizeof(data));//对设备进行读操作
read(adc_fd, &data, sizeof(data));//对设备进行写操作
return data;
}
int main(void)
{
int i;
float d;
if(init_ADdevice()<0)
return -1;
while( 1 )
{
d=((float)GetADresult(0)*3.0)/1024.0;
printf("%8f\t",d);
printf("\n");
sleep(1);
printf("\r");
}
close(adc_fd);//关闭设备
return 0;
}
轮询方式的驱动:
/*====*/