Hi,
Thank you very much for the code. I am testing it now. I will let you know any
change i will make in the driver.
Pablo
--- In "dan" <> wrote:
>
> Hello,
>
> Below the driver source and header file.
> to make it work:
>
> 1. compile it
> 2. enable PC104 bus
> 3. load driver
> 4. create filesystem node acording to major/minor number
> 5. build an user land application to send basic IOCTLs to the board(also
> check board ID)
>
> For sure the driver can be improved and I would be happy with any
> sugestions/fixes for it.
> In case of trouble I'll try to respond to your
>
> I don't have any better ideea to post it, than listing below the files:
> adc_drv.c
>
> #include <linux/module.h>
> #include <linux/init.h>
> #include <linux/kernel.h>
> #include <linux/fs.h>
> #include <linux/cdev.h>
> #include <linux/string.h>
> #include <asm/uaccess.h>
> //#include <asm/arch/regmap.h>
> #include <linux/proc_fs.h>
> #include <asm/io.h>
> #include "/usr/src/linux/include/linux/ioport.h"
> #include </usr/src/linux/include/linux/ioport.h>
> #include <linux/interrupt.h>
>
> #include "adc_drv.h"
>
> MODULE_DESCRIPTION("ADC character dev");
> MODULE_AUTHOR("Dan Lupu");
> MODULE_LICENSE("GPL");
>
> #define LOG_LEVEL KERN_DEBUG
>
> struct my_adc_data {
> struct cdev cdev;
> /* my data starts here */
> int size;
> int* buffer; // buffer to store FIFO data
> volatile char* ptr; /* board addr from k*/
> unsigned int irq7Show;
> };
>
> irqreturn_t adc_irqHnd(int irq_no, void *dev_id)
> {
> struct my_adc_data *my_data = (struct my_adc_data *) dev_id;
>
> printk("ADC IRQ Hnd called\n");
>
> if(irq_no==0x07)
> {
> my_data->irq7Show = my_data->irq7Show + 1;
> return IRQ_HANDLED;
> }
>
> return IRQ_NONE;
> }
>
> struct my_adc_data my_adc;
>
> static int my_open(struct inode *inode, struct file *file);
> static int my_read(struct file *file, char __user *user_buffer,
> size_t size, loff_t *offset);
>
> static int my_write (struct file *file, const char __user * user_buffer,
> size_t size, loff_t *offset);
> static int adc_ioctl (struct inode *inode,struct file *file,unsigned int cmd,
> unsigned long arg);
> static int my_release (struct inode *inode, struct file *file);
>
>
> struct file_operations my_fops = {
> .owner = THIS_MODULE,
> .open = my_open,
> .read = my_read,
> .write = my_write,
> .release = my_release,
> .ioctl = adc_ioctl
> };
>
>
> static int my_init(void)
> {
> int err;
> //printk(LOG_LEVEL "Init ADC module\n");
> // offset adaugat isa_regbase.
> my_adc.size=0;
> my_adc.ptr = NULL;
> my_adc.irq7Show=0;
> err = register_chrdev_region(MKDEV(MY_MAJOR, MY_MINOR),1,MODULE_NAME);
>
> if (err != 0) {
> /* report error */
> return err;
> }
>
> /* initialize my_dev fields */
> cdev_init(&my_adc.cdev, &my_fops);
> cdev_add(&my_adc.cdev, MKDEV(MY_MAJOR, MY_MINOR), 1);
>
> //printk(LOG_LEVEL "Open ADC device\n");
>
> if(check_mem_region(ADC_BASE,8))
> {
> printk("ADC_BASE space in use!");
> return -EBUSY;
> }
>
> request_mem_region(ADC_BASE,0x1E,"adc_drv");
> my_adc.ptr=__ioremap(ADC_BASE,0x1E,0);
>
> if(my_adc.ptr == NULL)
> {
> printk("no IOREMAP success!\n");
> }
> // board ID
> if(0x3e!=readb(my_adc.ptr))
> {
> printk("no ID from board 1");
> if(0x3e!=inb(my_adc.ptr))
> {
> printk("no ID from board 2");
> return -EBUSY;
> }
> }
>
> // request IRQs
> if ((err = request_irq(MY_IRQ1, adc_irqHnd, IRQF_SAMPLE_RANDOM |
> IRQF_SHARED,
> "adc", &my_adc))) {
> /* handle error*/
> printk("alocate IRQ7 not possible");
> return err;
> }
>
> //allocate mem for ADC FIFO
> my_adc.buffer=kmalloc(BUFFER_SIZE * sizeof(unsigned int),GFP_KERNEL);
>
> return 0;
> }
>
> static void my_exit(void)
> {
> //printk(LOG_LEVEL "Exit\n");
>
> release_mem_region(ADC_BASE,0x1E);
> __iounmap(my_adc.ptr);
>
> free_irq(MY_IRQ1, &my_adc);
>
> cdev_del(&my_adc.cdev);
> kfree(my_adc.buffer);
>
> unregister_chrdev_region(MKDEV(MY_MAJOR, MY_MINOR), 1);
> }
>
> static int my_open(struct inode *inode, struct file *file)
> {
> struct my_adc_data *my_adc;
> //printk(LOG_LEVEL "Open DIO device\n");
> my_adc = container_of(inode->i_cdev, struct my_adc_data, cdev);
> file->private_data = my_adc;
> my_adc->size=0;
> // writeb(0x00,my_adc->ptr+DDR);
> return 0;
> }
>
> static int my_read(struct file *file, char __user *user_buffer,
> size_t size, loff_t *offset)
> {
> struct my_adc_data *my_data =
> (struct my_adc_data*) file->private_data;
> size_t toberead;
> unsigned int ind;
>
> if(size >= BUFFER_SIZE)
> return 0;
> if(*offset >= BUFFER_SIZE)
> return 0;
> //printk(LOG_LEVEL "[my_read] Trying to read %d bytes\n", size);
>
> // first read in the buffer
> for(ind=0;ind<size;ind++){
> my_data->buffer[ind]=readw(my_data->ptr+ADCFIFO);
> }
> // toberead = (size < my_data->size - *offset) ? size : my_data->size -
> *offset;
> if(copy_to_user(user_buffer, my_data->buffer, size))
> return -EFAULT;
>
> return size;
> }
>
>
> static int my_write (struct file *file, const char __user * user_buffer,
> size_t size, loff_t *offset)
> {
> // struct my_adc_data *my_adc = (struct my_adc_data*)
> file->private_data;
> size_t tobewritten;
>
> return tobewritten;
> }
>
> static int adc_ioctl (struct inode *inode, struct file *file,
> unsigned int cmd, unsigned long arg)
> {
> unsigned int adccfg,adcstat,count,temp;
> unsigned int retval=0;
> struct my_adc_data *my_adc = (struct my_adc_data*) file->private_data;
>
> switch(cmd) {
> case ADC_BID_IOCTL:
> retval=ioread16(my_adc->ptr);
> break;
> case ADC_CFG_IOCTL:
> //printk(LOG_LEVEL "set ADCCFG %d\n",arg);
> iowrite16(0x167, my_adc->ptr+ADCCFG);
> //writeb(0x67, my_adc->ptr+ADCCFG+1);
> break;
> case ADC_GETCFG_IOCTL:
> //get by pointer.
> // cal this from user space
> ioctl(fd,ADC_GETCFG_IOCTL,&adccfg);uint adccfg;
> adccfg = ioread16( my_adc->ptr+ADCCFG);
> retval = put_user(adccfg, (int __user *)arg);
> //printk(LOG_LEVEL "get ADCCFG W %d\n",adccfg);
> //printk(LOG_LEVEL "get ADCCFG MSB %d\n",ioread8( my_adc->ptr +
> ADCCFG ));
> //printk(LOG_LEVEL "get ADCCFG LSB %d\n",ioread8( my_adc->ptr +
> ADCCFG+1 ));
> break;
> case ADC_DLYLSW_IOCTL:
> iowrite16(arg, my_adc->ptr + ADC_DLY_LSW);
> break;
> case ADC_DLYLSWR_IOCTL:
> temp =ioread16(my_adc->ptr + ADC_DLY_LSW);
> retval = __put_user(temp, (int __user *)arg);
> break;
> case ADC_DLYMSW_IOCTL:
> writew(arg, my_adc->ptr + ADC_DLY_MSW);
> break;
> case ADC_STAT_IOCTL:
> writew(arg, my_adc->ptr + ADCSTAT);
> break;
> case ADC_GETSTAT_IOCTL:
> adcstat=readw(my_adc->ptr + ADCSTAT);
> retval = __put_user(adcstat, (int __user *)arg);
> break;
>
> case ADC_DACCFG_IOCTL:
> //printk(LOG_LEVEL "[my_ioctl] [MY_IOCTL_PRINT] Hello ioctl
> DDRB SET\n");
> writew(arg, my_adc->ptr + DACCFG);
> break;
>
> case ADC_DACCMDR_IOCTL:
> //printk(LOG_LEVEL "[my_ioctl] [MY_IOCTL_PRINT] Hello ioctl
> DDRB SET\n");
> retval=readw(my_adc->ptr + DACCMD);
> break;
> case ADC_DACCMDRP_IOCTL:
> //printk(LOG_LEVEL "[my_ioctl] [MY_IOCTL_PRINT] Hello ioctl
> DDRB SET\n");
> temp=readw(my_adc->ptr + DACCMD);
> retval=__put_user(temp, (int __user *)arg);
> break;
> case ADC_DACCMD_IOCTL:
> //printk(LOG_LEVEL "[my_ioctl] [MY_IOCTL_PRINT] Hello ioctl
> DDRB SET\n");
> writew(arg, my_adc->ptr + DACCMD);
> break;
> case ADC_DACSTART_IOCTL:
> writeb((unsigned char)arg, my_adc->ptr + DACCMD+1);
> break;
>
> // count 0-3
> case ADC_COUNT0_IOCTL:
> count=readw(my_adc->ptr + COUNT0);
> retval = __put_user(count, (int __user *)arg);
> break;
> case ADC_COUNT1_IOCTL:
> count=readw(my_adc->ptr + COUNT1);
> retval = __put_user(count, (int __user *)arg);
> break;
> case ADC_COUNT2_IOCTL:
> count=readw( my_adc->ptr + COUNT2);
> retval = __put_user(count, (int __user *)arg);
> break;
> case ADC_COUNT3_IOCTL:
> count=readw( my_adc->ptr + COUNT3);
> retval = __put_user(count, (int __user *)arg);
> break;
>
> case ADC_DIGIO_IOCTL:
> writew(arg, my_adc->ptr + DIGIO);
> break;
>
>
> }//switch
>
> return retval;
> }
>
>
> static int my_release (struct inode *inode, struct file *file)
>
> {
> //printk(LOG_LEVEL "[my_release] Device released.\n");
> return 0;
> }
>
>
> module_init(my_init);
> module_exit(my_exit);
>
>
>
> adc_drv.h
>
> #define MY_MAJOR 43
> #define MY_MINOR 0
> #define MODULE_NAME "adc"
>
> #define ISAREGSBASE (0xE8000000)
> #define ISABASE (0xEE000000)
> #define IOPOFFSET 0x120 // JP1-ON JP2-OFF
>
> #define ADCCFG 0x02
> #define ADC_DLY_MSW 0x04
> #define ADC_DLY_LSW 0x06
> #define ADCSTAT 0x08
> #define ADCFIFO 0x0A
> #define DACCFG 0x0C
> #define DACCMD 0x0E
> #define COUNT0 0x10
> #define COUNT1 0x12
> #define COUNT2 0x14
> #define COUNT3 0x16
> #define DIGIO 0x18
>
>
> #define EXTRIG_BIT 0x09
> #define SEDIF_BIT 0x08
>
>
> // isa base + 0x120. JP1=on,JP2=off
> #define ADC_BASE (0xEE000120)
> #define BUFFER_SIZE 512
>
> //#define BOARD_ID ((volatile char*)(my_data->ptr))
> //#define RO1 ((volatile char*)(my_data->ptr+1))
>
> #define BOARD_ID 0
>
> #define ADC_DRV_IOC_MAGIC 141
>
> #define ADC_CFG_IOCTL _IOWR (ADC_DRV_IOC_MAGIC, 1, int)
> #define ADC_DLYMSW_IOCTL _IOW (ADC_DRV_IOC_MAGIC, 2, int)
> #define ADC_DLYLSW_IOCTL _IOW (ADC_DRV_IOC_MAGIC, 3, int)
> #define ADC_STAT_IOCTL _IOWR (ADC_DRV_IOC_MAGIC, 4, int)
> #define ADC_FIFO_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 5, int)
> #define ADC_DACCFG_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 6, int)
> #define ADC_DACCMD_IOCTL _IOW (ADC_DRV_IOC_MAGIC, 7, int)
> #define ADC_COUNT0_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 8, int)
> #define ADC_COUNT1_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 9, int)
> #define ADC_COUNT2_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 10, int)
> #define ADC_COUNT3_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 11, int)
> #define ADC_DIGIO_IOCTL _IOWR (ADC_DRV_IOC_MAGIC, 12, int)
> #define ADC_BOARD_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 13, int)
> #define ADC_GETCFG_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 14, int)
> #define ADC_GETSTAT_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 15, int)
> #define ADC_BID_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 16, int)
> #define ADC_DACCMDR_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 17, int)
> #define ADC_DACCMDRP_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 18, int)
> #define ADC_DLYLSWR_IOCTL _IOR (ADC_DRV_IOC_MAGIC, 19, int)
> #define ADC_DACSTART_IOCTL _IOW (ADC_DRV_IOC_MAGIC, 20, unsigned char)
> #define MY_IRQ1 7
>
------------------------------------
Yahoo! Groups Links
<*> To visit your group on the web, go to:
http://groups.yahoo.com/group/ts-7000/
<*> Your email settings:
Individual Email | Traditional
<*> To change settings online go to:
http://groups.yahoo.com/group/ts-7000/join
(Yahoo! ID required)
<*> To change settings via email:
<*> To unsubscribe from this group, send an email to:
<*> Your use of Yahoo! Groups is subject to:
http://docs.yahoo.com/info/terms/
|