This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How can I write a simple driver in Linux kernel(on dm8168 platform).

I want to write a simple linux driver to get our linux code version info.We use version_open function to set version num,and use version_get function  to send

info to APP.The attachement is an example and it works well on dm6467 linux.When I move it to dm8168 platform,it works error.I want to imitate omap_wdt.c,but

I have some doubts.Can someone give any help?

 4848.get_version.c

 

 

 

  • Hi,

    For basics of device driver development you can read ldd3 chapters 1 to 3

    http://lwn.net/Kernel/LDD3/

    pdev comes as a part of platform_device_register

  • Hi HardikShah,

    Thanks for your reply

    Could you run "cd /usr/share/ti/ti-psp-examples/ && ./saWatchdog".my software platform:ezsdk_5_05_01_04.

    it showed this error.

  • I tested 5.04 platform,it was the same error.

  • Hi bingyi cheng!

    Can you look to the http://lxr.free-electrons.com/source/Documentation/driver-model/?a=arm

    Here placed, basic information about platform device.

    You can create version string in sysfs filesystem via DEFINE_SIMPLE_ATTRIBUTE or DEVICE_ATTR(). Look to the arch/arm/mach-omap2/voltage.c or arch/arm/mach-omap2/serial.c for example. May it was bad and incorrect idea, but you can read it from userspace program directly.

  • Hi idle,

     thank you.

     Kernel version info is only one example.We must use read write ioctl etc. to control our others driver. When We run Ti's example saWatchdog,we got error info "Segmentation fault",it was the same error as our driver(attachment file 4848.get_version.c);

  • You should really read the Linux Device Drivers book as suggested by Hardik Shah. Your read function is probably getting a segmentation error because it is accessing user space memory directly from kernel space. It also does not update the parameters as required by the char driver. The get function should look something like this.

    static ssize_t version_get (struct file *file, char __user *buf, size_t count,
                                loff_t *offset)
    {
      ssize_t bytes_read = sizeof(version);

      if(count < bytes_read)
        bytes_read = count;

      copy_to_user(buf, &version, bytes_read);
      *offset += bytes_read;

      return(bytes_read);
    }

    The above assumes that the user space app will always read everthing in one read call.

  • thanks for all,

    I now can open the get_version in APP .I will get off work right now,I will test it tomorrow.

  • An example in dm6467 linux,there is existing "struct *inode",but in dm8168 linux,there is not existing.This will cause problems. Another problem,when we use "read" funcion in APP,it's not call in kernel. I added a "read" funcion in omap_wdt.c,and tested saWatchdog,the "read" function was not called in kernel.I don't know the reason. but we can get info by using "ioctl".

     

  • Can someone test "read" function?

    thanks.

  • In your open you can store some information in file->private_data and use it in ioctl and other system call.

    Here example from my driver:

    static struct pex_device *file_to_device( struct file *file )
    {
        return (struct pex_device*)file->private_data;
    }

    #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37)
    static struct pex_device *inode_to_device( struct list_head *head, struct inode *inode )
    {
        struct list_head *p;
        struct pex_device *entry;
        unsigned int minor = MINOR(inode->i_rdev);

        list_for_each(p, head) {
            entry = list_entry(p, struct pex_device, m_list);
            if(entry->m_BoardIndex == minor)
                return entry;
        }

        return NULL;
    }
    #endif

    static int pex_device_open( struct inode *inode, struct file *file )
    {
        struct pex_device *pDevice = container_of(inode->i_cdev, struct pex_device, m_cdev);
        if(!pDevice) {
            err_msg(err_trace, "%s(): Open device failed\n", __FUNCTION__);
            return -ENODEV;
        }

        file->private_data = (void*)pDevice;

        dbg_msg(dbg_trace, "%s(): Open device %s\n", __FUNCTION__, pDevice->m_name);

        return 0;
    }

    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
    static long pex_device_ioctl( struct file *file, unsigned int cmd, unsigned long arg )
    #else
    static int pex_device_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg )
    #endif
    {
        int error = 0;
    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
        struct pex_device *pDevice = file_to_device(file);
    #else
        struct pex_device *pDevice = inode_to_device(&device_list, inode);
    #endif
        if(!pDevice) {
            err_msg(err_trace, "%s(): ioctl device failed\n", __FUNCTION__);
            return -ENODEV;
        }

      ********************
    }