Driver:/** a ADC Driver as an example of char device drivers ** the initial developer of the original code is Barry song * <author@linuxdriver.cn>. all rights reserved. */# include <Linux/module. h> # include <Linux/types. h> # include <Linux/Fs. h> # include <Linux/errno. h> # include <Linux/mm. h> # include <Linux/sched. h> # include <Linux/init. h> # include <Linux/cdev. h> # include <ASM/Io. h> # include <ASM/system. h> # In Clude <ASM/uaccess. h> # include <Linux/device. h>/* device_create () */# include <ASM/Io. h> # include <ASM/IRQ. h> # include <ASM/uaccess. h> # include <Mach/map. h> # include <plat/regs-adc.h> # include <Mach/map. h> static void _ iomem * base_addr;/* Control Address of the ADC register of */# DEFINE _ adcreg (name) (* (volatile unsigned long *) (base_addr + name) # define adccon _ adcreg (cloud_adccon) // ADC control # define adctsc _ ADC Reg (cloud_adctsc) // ADC touch screen control # define adcdly _ adcreg (cloud_adcdly) // ADC start or interval delay # define adcdat0 _ adcreg (cloud_adcdat0) // ADC conversion data 0 # define adcdat1 _ adcreg (cloud_adcdat1) // ADC conversion data 1 # define adcupdn _ adcreg (cloud_adcupdn) // stylus up/down interrupt status/* ADC register bit configuration */# define prescale_dis (0 <14) # define prescale_en (1 <14) # define prscvl (X) <6) # define adc_input (x) <3) # define adc_start (1 <0) # define adc_endcvt (1 <15) # define adc_size 0x1000/* maximum global memory 4 K Bytes */# define mem_clear 0x1/* clear 0 global memory */# define adc_major 250/* master device of the preset ADC no. */static int adc_major = adc_major; /* ADC device struct */struct adc_dev {struct cdev;/* cdev struct */unsigned char mem [adc_size];/* Global memory */}; struct adc_dev * adc_devp; /* Device struct pointer * // * initialize the ADC control register in the case * /Static int adc_init (void) {unsigned int prescaler = 0xff; adccon = (1 <14) | (prescaler <6) | (0 <3) | (0 <2); adccon | = adc_start; return 0;}/* file opening function */INT adc_open (struct inode * inode, struct file * filp) {/* ADC initialization */adc_init (); printk ("<0> adc_drv_open and adc_init () \ n"); Return 0 ;} /* file release function */INT adc_release (struct inode * inode, struct file * filp) {return 0;}/* read function */static ssize_t adc_read (struct File * Filp, char _ User * Buf, size_t size, loff_t * PPOs) {unsigned long P = * PPOs; unsigned int COUNT = size; int ret = 0; int COUNT = 0; adccon | = adc_start; while (adccon & 0x01); // check if enable_start is low while (! (Adccon & 0x8000);/* check whether the conversion is complete */ret = adcdat0 & 0x3ff; Count = copy_to_user (buff, (char *) & ret, sizeof (RET); Return sizeof (RET);}/* file operation struct */static const struct file_operations adc_fops = {. owner = this_module ,. read = adc_read ,. open = adc_open ,. release = adc_release,};/* initialize and register cdev */static void adc_setup_cdev (struct adc_dev * Dev, int index) {int err, devno = mkdev (adc_major, index ); cdev_init (& Dev-> C Dev, & adc_fops); Dev-> cdev. owner = this_module; err = cdev_add (& Dev-> cdev, devno, 1); If (ERR) printk (kern_notice "error % d adding led % d", err, index);} struct class * myclass;/* Device Driver Module Loading Function */INT adc_dev_init (void) {int result; dev_t devno = mkdev (adc_major, 0 ); /* apply for the device Number */If (adc_major) Result = register_chrdev_region (devno, 1, "ADC "); else {/* dynamically apply for the device Number */result = alloc_chrdev_region (& devno, 0, 1 ," ADC "); adc_major = major (devno);} If (result <0) return result; /* dynamically apply the memory of the device struct */adc_devp = kmalloc (sizeof (struct adc_dev), gfp_kernel); If (! Adc_devp) {/* application failed */result =-enomem; goto fail_malloc;} memset (adc_devp, 0, sizeof (struct adc_dev); adc_setup_cdev (adc_devp, 0 ); /* automatically create the device file */myclass = class_create (this_module, "test_char");/* Create the class directory/sys/class/test_char */device_create (myclass, null, mkdev (adc_major, 0), null, "ADC"); base_addr = ioremap (0x7e00b000, 0x20); // address if ing if (base_addr = NULL) {printk ("<0> failed to remap \ n"); Return-enomem;} return 0; fail_malloc: unregister_chrdev_region (devno, 1); return result ;} /* module unmount function */void adc_dev_exit (void) {cdev_del (& adc_devp-> cdev);/* cancel cdev */kfree (adc_devp ); /* release the device struct memory */unregister_chrdev_region (mkdev (adc_major, 0), 1);/* release the device Number */class_destroy (myclass); device_destroy (myclass, mkdev, 0); iounmap (base_addr); // cancel ing} module_author ("Barry song <21cnbao@gmail.com>"); module_license ("dual BSD/GPL"); module_param (adc_major, int, s_irugo); module_init (adc_dev_init); module_exit (adc_dev_exit );
Application: # include <stdio. h> # include <fcntl. h> # include <unistd. h> int main () {int FP, adc_data, I; int ret; FP = open ("/dev/adc_dev", o_rdwr); If (FP <0) printf ("Open failed! \ N "); printf (" Open sucessed! \ N "); for (I = 0; I <100; I ++) {ret = read (FP, & adc_data, sizeof (adc_data )); printf ("read sucessed! \ N "); If (Ret <0) {printf (" read ADC failed! \ N "); Return-1;} else printf (" read ADC value is: % d \ n ", adc_data); sleep (1);} Close (FP ); return 0 ;}
Makefile:ifneq ($(KERNELRELEASE),)obj-m := adc.oelseKDIR := /home/OK6410/linux2.6.28all: make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=arm-linux-clean: rm -f *.ko *.o *.mod.o *.mod.c *.symversendif