Linux Device Driver Program, where the program starts?

Linux Device Driver Program, where the program starts?

A device driver is not a program that has a main {} with a start point and exit point. Its more like an API or a library or a collection of routines. In this case, its a set of entry points declared by MODULE_INIT(), MODULE_EXIT(), perhaps EXPORT_SYMBOL() and structures that list entry points for operations.

For block devices, the driver is expected to provide the list of operations it can perform by declaring its functions for those operations in (from include/linux/blkdev.h):

struct block_device_operations {
        int (*open) ();
        int (*release) ();
        int (*ioctl) ();
        int (*compat_ioctl) ();
        int (*direct_access) ();
        unsigned int (*check_events) ();
        /* ->media_changed() is DEPRECATED, use ->check_events() instead */
        int (*media_changed) ();
        void (*unlock_native_capacity) ();
        int (*revalidate_disk) ();
        int (*getgeo)();
        /* this callback is with swap_lock and sometimes page table lock held */
        void (*swap_slot_free_notify) ();
        struct module *owner;
};

For char devices, the driver is expected to provide the list of operations it can perform by declaring its functions for those operations in (from include/linux/fs.h):

struct file_operations {
        struct module *owner;
        loff_t (*llseek) ();
        ssize_t (*read) ();
        ssize_t (*write) ();
        ssize_t (*aio_read) ();
        ssize_t (*aio_write) ();
        int (*readdir) ();
        unsigned int (*poll) ();
        long (*unlocked_ioctl) ();
        long (*compat_ioctl) ();
        int (*mmap) ();
        int (*open) ();
        int (*flush) ();
        int (*release) ();
        int (*fsync) ();
        int (*aio_fsync) ();
        int (*fasync) ();
        int (*lock) ();
        ssize_t (*sendpage) ();
        unsigned long (*get_unmapped_area)();
        int (*check_flags)();
        int (*flock) ();
        ssize_t (*splice_write)();
        ssize_t (*splice_read)();
        int (*setlease)();
        long (*fallocate)();
};

For platform devices, the driver is expected to provide the list of operations it can perform by declaring its functions for those operations in (from include/linux/platform_device.h):

struct platform_driver {
        int (*probe)();
        int (*remove)();
        void (*shutdown)();
        int (*suspend)();
        int (*resume)();
        struct device_driver driver;
        const struct platform_device_id *id_table;
};

The driver, especially char drivers, does not have to support every operation listed. Note that there are macros to facilitate the coding of these structures by naming the structure entries.

Does the driver program starts at the MOUDLUE_INIT() macro?

The drivers init() routine specified in MODULE_INIT() will be called during boot (when statically linked in) or when the module is dynamically loaded. The driver passes its structure of operations to the devices subsystem when it registers itself during its init().

These device driver entry points, e.g. open() or read(), are typically executed when the user app invokes a C library call (in user space) and after a switch to kernel space. Note that the i2c driver youre looking at is a platform driver for a bus that is used by leaf devices, and its functions exposed by EXPORT_SYMBOL() would be called by other drivers.

Only the drivers init() routine specified in MODULE_INIT() is guaranteed to be called. The drivers exit() routine specified in MODULE_EXIT() would only be executed if/when the module is dynamically unloaded. The drivers op routines will be called asynchronously (just like its interrupt service routine) in unknown order. Hopefully user programs will invoke an open() before issuing a read() or an ioctl() operation, and invoke other operations in a sensible fashion. A well-written and robust driver should accommodate any order or sequence of operations, and produce sane results to ensure system integrity.

It would probably help to stop thinking of a device driver as a program. Theyre completely different. A program has a specific starting point, does some stuff, and has one or more fairly well defined (well, they should, anyway) exit point. Drivers have some stuff to do when the first get loaded (e.g. MODULE_INIT() and other stuff), and may or may not ever do anything ever again (you can forcibly load a driver for hardware your system doesnt actually have), and may have some stuff that needs to be done if the driver is ever unloaded. Aside from that, a driver generally provides some specific entry points (system calls, ioctls, etc.) that user-land applications can access to request the driver to do something.

Horrible analogy, but think of a program kind of like a car – you get in, start it up, drive somewhere, and get out. A driver is more like a vending machine – you plug it in and make sure its stocked, but then people just come along occasionaly and push buttons to make it do something.

Linux Device Driver Program, where the program starts?

Actually you are taking about (I2C) platform (Native)driver first you need to understand how MOUDULE_INIT() of platform driver got called versus other loadable modules.

/*
* module_init() - driver initialization entry point
* @x: function to be run at kernel boot time or module insertion
* module_init() will either be called during do_initcalls() (if
* builtin) or at module insertion time (if a module).  There can only
* be one per module.*/

and for i2c driver you can refer this link http://www.linuxjournal.com/article/7136 and
http://www.embedded-bits.co.uk/2009/i2c-in-the-2632-linux-kernel/

Leave a Reply

Your email address will not be published.