Re: Closing/disabling a device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Le 14/12/2011 17:30, Frank Pagliughi a écrit :
Well, my immediate concern is CPU cycles, but I'm working on a low-power device, so I will start to worry about the battery in a few months when the basics are operational. My immediate concern is that the CPU is spending significant time servicing the interrupt (constantly) for a device that I intend to read for a few minutes once every six hours!

I could try to disable the interrupt for that serial port from the app, but it defeats the purpose of encapsulating everything in a device driver.

I think the solution would be a close function for devices:

   Cyg_ErrNo cyg_io_close(cyg_io_handle_t handle);

This can halt the device by disabling interrupts, etc. I suppose, though, that an empty, default implementation that does nothing would then have to be provided for every driver currently in the repository?

And then that creates the problem of being able to open the device again after it has been closed. Perhaps the lookup function can just be called again, but it seems that the device lookup function performs a "query", "initialize", and "open" function in one call. These could maybe be split into two or three separate functions?

As you mention, there is also the issue of power-saving modes. Even the eCos reference manual indicates future modifications:

   The lookup() function is called whenever the cyg_io_lookup()
   function is called with this device name. The lookup function may
   cause the device to come “on line” which would then allow I/O
   operations to proceed. Future versions of the I/O system will allow
   for other states, including power saving modes, etc.

Devices could offer optional callbacks for power-down and power-up, like the Linux suspend/resume callbacks. But there would probably need to be the system-wide power management API to orchestrate the whole thing. That sounds great, but way beyond what I was thinking at the moment.

I've followed exactly the same kind of thought and reached a similar conclusion. I've seen for instance the macro definition 'CYG_IO_SET_CONFIG_CLOSE' (in config_keys.h): a driver could implement it in [driver]_set_config() and detach from the hardware. There would be a small consumption spike at boot since all drivers would fire until they get closed but this would allow existing drivers to stay as much as they are today and it may be an acceptable solution.

A more complete solution would be to have macros like DEVTAB_ENTRY() to support more fields, typically pointers for a power_up() function because today all _init() functions both perform calls to eCos functions (like registering ISR/DSR) and perform hardware initialization. IMHO the _init() function should focus on calling eCos functions, and the hardware handling should be moved to _power_up(). ECos would call _init(), and eventually _power_up(flag) if the _power_up() function pointer is not NULL. The flag tells _power_up() if it's called from init phase or at a later time.

An improved driver would really power the peripheral when called from, for instance, _lookup(), with the flag set to tell it's not boot time. This way the changes are mainly in the way eCos calls the drivers at boot time, and each driver can be improved whenever someone has time to work on it.

To allow a driver to be powered down, _set_config() would process CYG_IO_SET_CONFIG_CLOSE: if ever cyg_io_close() is made, it would be a call to _set_config() with this option since the _set_config() system is already available.

There is may be a much better way to add real power control to each driver, but it is not documented yet :-)

However even if there is work to do, it's mainly a massage of the driver files: the functional changes seems to be small per involved driver, it's mainly a question of deciding/knowing how to organize things, not to change ISR/DSR code. The hardware register change is mainly to power things down (if power control is available) and to stop the concerned peripheral in a clean way since there is already the code to start it up correctly from _init(). Another problem (at least on my LPC target) is that peripheral powering is handled in [target]_misc.c, not in the drivers themselves.


Before posting, please read the FAQ:
and search the list archive:

[Linux Embedded]     [U-Boot V2]     [Linux Kernel]     [Linux MIPS]     [Linux ARM]     [Linux for the Blind]     [Linux Resources]     [Photo]     [Yosemite]     [ISDN Cause Codes]     [ECOS Home]

Add to Google Powered by Linux