Dynamic power management may require devices and drivers to transition
between various physical and logical states.  I would like to start a
discussion on how these might be defined at the bus, driver, and class
levels.

Bus Level
=========
At the bus level, there are two state attributes, power and
enable/disable.  Enable/disable may mean different things on different
buses, but they generally refer to resource decoding.  A device can only
be enabled during a non-off power state.

A possible API:

struct bus_type {
        char                    * name;

        struct subsystem        subsys;
        struct kset             drivers;
        struct kset             devices;

        struct bus_attribute    * bus_attrs;
        struct device_attribute * dev_attrs;
        struct driver_attribute * drv_attrs;

        int             (*match)(struct device * dev, struct device_driver * 
drv);
        int             (*hotplug) (struct device *dev, char **envp, 
                                    int num_envp, char *buffer, int 
buffer_size);
        int             (*suspend)(struct device * dev, pm_message_t state);
        int             (*resume)(struct device * dev);
        int             (*enable)(struct device * dev);
        int             (*disable)(struct device * dev);
};

Driver Level
============
At the driver level there are two areas of interest, physical and
logical state.  There is an additional concern of transitioning between
these states multiple times.  Because a driver acts as a bridge between
physical and logical components, I think separating these steps seems
natural.

A possible API:

struct device_driver {
        char                    * name;
        struct bus_type         * bus;

        struct semaphore        unload_sem;
        struct kobject          kobj;
        struct list_head        devices;

        struct module           * owner;

        int     (*attach)       (struct device * dev);
        int     (*start)        (struct device * dev);
        int     (*open)         (struct device * dev);
        int     (*close)        (struct device * dev);
        void    (*stop)         (struct device * dev);
        void    (*detach)       (struct device * dev);
        void    (*shutdown)     (struct device * dev);
        int     (*suspend)      (struct device * dev, u32 state, u32 level);
        int     (*resume)       (struct device * dev, u32 level);
};

*attach - allocates data structures, creates sysfs entries, prepares driver
       to handle the hardware.
 
*start -  Sets up device resources and configures the hardware.  Loads
firmware, etc.
(physical)
 
*open -   engages the hardware, and makes it usable by the class device.
(logical and physical)
 
*close -  disengages the hardware, and stops class level access
(logical and physical)
 
*stop -   physically disables the hardware
(physical)
 
*detach - tears down the driver and releases it from the "struct device"

The idea behind *attach and *detach is to move code that would only need
to be called once out of *probe and *remove.

A table could be defined that indicates what should be called for each
power level transition.  *suspend and *resume could handle any extra
steps (ex. saving state).  As an example, *start and *stop may only be
called when power is going to be lost entirely.

Additional states are class specific and would only be used after *open
is called.

Class Level
===========
At the class level, we could have a simple start/stop mechanism.

A possible API:

struct class_device {
        struct list_head        node;

        struct kobject          kobj;
        struct class            * class;
        struct device           * dev;
        void                    * class_data;

        char    class_id[BUS_ID_SIZE];

        int     (*attach)       (struct device * dev);
        int     (*start)        (struct device * dev);
        void    (*stop)         (struct device * dev);
        void    (*detach)       (struct device * dev);
};

*attach - allocates data structures, creates sysfs entries, prepares
class to handle the device.

*start - start the logical class device, accept userspace interaction

*stop - stop the logical class device, deny userspace interaction

*detach - tear down the class driver's bindings with this class device


These are just rough ideas.  I look forward to any comments or
alternative approaches.

Thanks,
Adam


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to