adc驱动实例(工作队列+等待队列+设备树+属性文件)
来源:互联网 发布:oppo应用分身软件 编辑:程序博客网 时间:2024/06/05 21:12
驱动:
#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/platform_device.h>#include <asm/io.h>#include <linux/cdev.h>#include <linux/slab.h>#include <asm/uaccess.h> #include <linux/kobject.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/of.h>#include <linux/interrupt.h>#include <linux/highmem.h> #include <asm/kmap_types.h>#include <linux/wait.h>#define HIGH_RSL 4096 // 2^12#define LOW_RSL 1024 // 2^10/*DTSmyadc {compatible = "xadc";reg = <0x10010118 0x1>, <0x126C0000 0x20>;interrupt-parent = <&combiner>;interrupts = <10 3> ;};*/MODULE_LICENSE("Dual BSD/GPL");MODULE_DESCRIPTION("a simple adc_driver !");typedef struct {unsigned int ADCCON; //0unsigned int NOVAL; //4unsigned int ADCDLY; //8unsigned int ADCDAT; //12unsigned int NOVAL1; //16unsigned int NOVAL2; //20unsigned int CLRINTADC; //24unsigned int ADCMUX; //28 }adc_t;struct ADC{dev_t num;int val;//readvalint val_ok_flag;int available;//adc aviliable struct mutex lock;spinlock_t lock;int resolution;//ADC resolutionstruct cdev xadc_cdev; //for containor_of()struct resource *res;//create a platform driveradc_t *adcaddr; struct class *xadc_class;//support hotplug functionstruct device *xadc_device;struct work_struct *xadc_work; //irq_bottom_sectionwait_queue_head_t readqueue;//wait IOstruct kobject *xadc_kobj;//support attr_file op}adc;struct attribute xadc_attrs[] = {[0] = {"xadc3", S_IRUGO |S_IWUSR},{}};ssize_t xadc_kobj_show(struct kobject *kobj, struct attribute *attr, char *buffer){if(0 == strcmp(attr->name, "xadc3")){if(adc.resolution == HIGH_RSL)printk("adc_resolution: HIGH_RSL(2^12)\n");elseprintk("adc_resolution: LOW_RSL(2^10)\n");return 0;}elsereturn -1;}ssize_t xadc_kobj_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size){iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1<<0)) , &(adc.adcaddr->ADCCON) );///STOP转换if(0 == strcmp(attr->name, "xadc3")) {if(0 == strncmp(buffer, "low",3)) {adc.resolution = LOW_RSL;iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1 << 16)) ,&(adc.adcaddr->ADCCON) );//resolution 10bitprintk("low resolution set ok!\n");}else if(0 == strncmp(buffer, "high",4)) {adc.resolution = HIGH_RSL;iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) | (1 << 16) ,&(adc.adcaddr->ADCCON) );//resolution 12bitprintk("high resolution set ok!\n");}} return size;}void xadc_kobj_release(struct kobject * k){kfree(k);return ;}struct sysfs_ops xadc_sysfs_ops = {.show = xadc_kobj_show,.store = xadc_kobj_store};struct kobj_type xadc_ktype = {.release = xadc_kobj_release,.sysfs_ops = &xadc_sysfs_ops,};int xadc_open(struct inode *i, struct file *f){spin_lock(&adc.lock); //lockif(adc.available == 1) //userful{adc.available = 0;spin_unlock(&adc.lock); //unlockprintk("xadc open\n");return 0;}spin_unlock(&adc.lock); //unlockreturn -EBUSY;}//read waitqueuessize_t xadc_read (struct file *f, char __user *p, size_t n, loff_t *off){iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) | (1<<0) , &(adc.adcaddr->ADCCON) );///开始转换if(adc.val_ok_flag == 0){//let this procss go to sleepwait_event_interruptible(adc.readqueue, adc.val_ok_flag != 0);}if( copy_to_user(p, &(adc.val), sizeof(int)) ) //get val to userreturn -EFAULT;adc.val_ok_flag = 0;return sizeof(int);}ssize_t xadc_write (struct file *f, const char __user *p, size_t n, loff_t *off){//copy_from_user(buf, p, n);return n;}#define LOW 0#define HIGH 1long xadc_ioctl(struct file *f, unsigned int resolution, unsigned long arg){iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1<<0)) , &(adc.adcaddr->ADCCON) );///STOP转换if(resolution < LOW || resolution > HIGH){printk("error type!\n");return -1;}if(resolution == LOW) {adc.resolution = LOW_RSL;iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1 << 16)) ,&(adc.adcaddr->ADCCON) );//resolution 10bitprintk("low resolution set ok!\n");}else if(resolution == HIGH){adc.resolution = HIGH_RSL;iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) | (1 << 16) ,&(adc.adcaddr->ADCCON) );//resolution 12bitprintk("high resolution set ok!\n");}return 0;}int xadc_release(struct inode *inode, struct file *file){printk("xadc closed\n"); iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1<<0)) , &(adc.adcaddr->ADCCON) );///STOP转换adc.available = 1; //usefulreturn 0;}struct file_operations xadc_ops = {.owner = THIS_MODULE,.open = xadc_open,.unlocked_ioctl = xadc_ioctl,.read = xadc_read,.write = xadc_write ,.release = xadc_release};////////////////////////////////////////////////////////////////////irq_handler//deal_thingvoid adc_workfunc(struct work_struct *work){adc.val = ioread32( &(adc.adcaddr->ADCDAT) ) & 0xfff ;adc.val_ok_flag = 1; //ok//woke up processeswake_up_interruptible(&adc.readqueue);return;}//irqirqreturn_t xadc_handler(int n, void *dev){adc.xadc_work = kzalloc(GFP_ATOMIC, sizeof(struct work_struct)); //workstruct 将处理的事务交给内核线程中处理INIT_WORK(adc.xadc_work, adc_workfunc);schedule_work(adc.xadc_work);iowrite32( 0x12 , &(adc.adcaddr->CLRINTADC) ); //clear INTprintk("IRQ getval , adc3_val can be read!\n");return IRQ_HANDLED;}////////////////////////////////////////////////////////////////////driver int xadc_probe(struct platform_device *pdev){int ret = 0;printk("probe the adc_device!\n");//get adc_addradc.res = platform_get_resource(pdev, IORESOURCE_MEM, 1);printk("adc_baseaddr: %#x\n", adc.res->start);adc.adcaddr = ioremap(adc.res->start, adc.res->end-adc.res->start);//get adc_irqadc.res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); printk("adc_irqnum:: %#x\n", adc.res->start);ret = request_irq(adc.res->start, xadc_handler, IRQF_DISABLED, "xadc_IRQ", NULL); //申请一个中断服务(需要获取中断号) 最后一个是中断函数的参数pdevprintk("adc_device info get !\n");//request cdev numret = alloc_chrdev_region(&adc.num, 0, 1, "xadc3");if(ret) {printk("devnum alloc fail!\n");return ret;}printk("devnum: %d %d \n", MAJOR(adc.num) ,MINOR(adc.num));//init cdev fopscdev_init(&adc.xadc_cdev, &xadc_ops);//register cdev into kernelret = cdev_add(&adc.xadc_cdev, adc.num , 1);if(ret) {printk("add cdev fail!\n");goto cdev_add_out;}//support hotplug functionadc.xadc_class = class_create(THIS_MODULE, "xadc"); //sys/class/adc.xadc_device = device_create(adc.xadc_class , NULL, adc.num, NULL, "adc%d", 3); //dev///init device adc3iowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1 << 16)) ,&(adc.adcaddr->ADCCON) );//resolutioniowrite32( ioread32( &(adc.adcaddr->ADCCON) ) | (1 << 14) , &(adc.adcaddr->ADCCON) );//enable prescaleriowrite32( (ioread32( &(adc.adcaddr->ADCCON) ) & (~(0xFF << 6))) | (19<<6) , &(adc.adcaddr->ADCCON) );//prescaleriowrite32( ioread32( &(adc.adcaddr->ADCCON) ) & (~(1 << 2)) , &(adc.adcaddr->ADCCON) ); //normaliowrite32( ioread32( &(adc.adcaddr->ADCMUX) ) | 0x3 , &(adc.adcaddr->ADCMUX) ); //adc 第三通道 adc.resolution = LOW_RSL; //init resolutioninit_waitqueue_head(&adc.readqueue); //init wait queueadc.available = 1; //spin_lock_init(&adc.lock);spin_lock_init(&adc.lock);printk("adc.available!\n");//attr_fileadc.xadc_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);kobject_init(adc.xadc_kobj, &xadc_ktype);ret = kobject_add(adc.xadc_kobj, NULL, "xadc3");ret = sysfs_create_file(adc.xadc_kobj, &xadc_attrs[0]);//successreturn 0;cdev_add_out:unregister_chrdev_region(adc.num, 1); //release dev_num//errorreturn ret;}int xadc_remove(struct platform_device *pdev){//release remapiounmap(adc.adcaddr);///释放中断 free_irq(adc.res->start, NULL); //unregister cdev from kernelcdev_del(&adc.xadc_cdev);/*//release cdev objectkfree(&beep.xadc_cdev);*///release dev numunregister_chrdev_region(adc.num, 1); //support hotplug function//free devicedevice_del(adc.xadc_device);//free classclass_destroy(adc.xadc_class);//free attr_filesysfs_remove_file(adc.xadc_kobj, &xadc_attrs[0]);kobject_del(adc.xadc_kobj);kfree(adc.xadc_kobj);printk("adc_device remove !\n");return 0;}//multi_device tablestruct platform_device_id xadc_ids[] = {//support auto_install the driver[0] = {.name = "adc3"},[1] = {//null}};#ifdef CONFIG_OF//设备树匹配方式 struct of_device_id xadc_table[] = {{ .compatible = "xadc" }, //match adc3{ } //NULL};#endifstruct platform_driver xadc_driver = {.probe = xadc_probe,.remove = xadc_remove,.id_table = xadc_ids, //multi_device table.driver = {.name = "adc3",.of_match_table = of_match_ptr(xadc_table) //设备树匹配选项 }};MODULE_DEVICE_TABLE(platform, xadc_ids); //support auto_install the driver//driver install and release static int adcmodule_init(void){printk("xadc driver install\n");//add into platform busplatform_driver_register(&xadc_driver);return 0;}static void adcmodule_exit(void){printk("xad cdriver release\n");//del from platform busplatform_driver_unregister(&xadc_driver);return ;}module_init(adcmodule_init);module_exit(adcmodule_exit);
测试:
#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#define LOW 0#define HIGH 1int main(int argc,char **argv){int chose;int fd;int val;int RES;while(1){printf("1.open adc 2.close adc 3.set high_resolution 4.set low_resolution 5.read adc_val \n");scanf("%d",&chose);switch(chose){case 1: printf("open\n"); fd = open("/dev/adc3", O_RDWR);if(-1 == fd){perror("open fail EBUSY\n");return -1;}break;case 2: printf("close\n"); close(fd);break;case 3: printf("set high_resolution, ");ioctl(fd, HIGH);RES = HIGH;printf("set ok!\n");break;case 4: printf("set low_resolution, ");ioctl(fd, LOW);RES = LOW;printf("set ok!\n");break;case 5: read(fd,&val,sizeof(int));if(RES == LOW)val = 1000 * (1.8/1024 * val);elseval = 1000 * (1.8/4096 * val);printf("readval: %d mV \n",val);break;default: printf("err type\n"); }}close(fd);return 0;}
0 0
- adc驱动实例(工作队列+等待队列+设备树+属性文件)
- 按键驱动(等待队列+设备树+属性文件)
- 设备驱动-------工作队列
- Linux设备驱动,等待队列
- linux驱动---等待队列、工作队列、Tasklets
- 等待队列与工作队列实例
- 字符设备驱动之Buttons-等待队列
- 《Linux设备驱动开发详解》-- 等待队列
- linux设备驱动--等待队列实现
- Linux 设备驱动--- 内核等待队列
- 字符设备驱动第九课---等待队列
- Linux设备驱动六 (1)等待队列
- globalfifo驱动实例(等待队列)
- 等待队列和工作队列
- 等待队列 PK 工作队列
- 等待队列 PK 工作队列
- 等待队列和工作队列
- Linux设备驱动之工作队列
- [AC自动机 + DP] BZOJ1030: [JSOI2007]文本生成器
- [Python]浅拷贝与深拷贝
- 剑指offer--二叉搜索树的后序遍历序列
- 【mark】QQ 探测,爬取网页内容
- [数学期望]BZOJ 1415
- adc驱动实例(工作队列+等待队列+设备树+属性文件)
- Java入门学习-学会try/catch/throw的用法。做出一个计算器除法功能,除以0时程序必须给出提示。
- 字符串匹配
- 大数据时代的小数字感:数据再有价值,别人听不懂照样没用
- Unity3DGame学习笔记(6):粒子系统
- 集合框架-统计字符串中每个字符出现的次数案例图解
- JavaScript中的运算符
- 1024: 求1+2!+3!+...+N!的和
- 五一假第三天