Hello all,
A little context: I am writing support for Orinoco USB devices, and
they require some firmware to work. But I got the firmware from
communication dumps and a windows .sys file, which doesn't qualify for
redistribution.
After reading the linux-kernel thread started by Pavel Roskin I
implemented a little filesystem for this purpose. It was based on
ramfs. And after some feedback from Pavel Roskin and David Gibson it
became what it is now. I'll try to make a resume:
I couldn't find the blobs support patch that someone talked about, so I
did it myself. I called it 'fwfs' for obvious reasons, but I would
gladly change the name for something more general if required.
The idea is making the filesystem as simple as possible and making it
as easy and codeless as possible to be used from drivers.
From userspace it would be as simple as:
# mount -t fwfs fwfs /firmware/
# cp my_firmware_data /firmware/orinoco_ezusb_fw
# modprobe orinoco_usb
On the simplest case the usage could be:
static const struct fwfs_entry *fwfs_entry;
int init_module(void)
{
fwfs_entry = fwfs_get("orinoco_ezusb_fw")
if(!fwfs_entry)
-EAGAIN;
/* fwfs_entry->size holds the size of the firmware */
/* fwfs_entry->data holds a pointer to the firmware data */
/* Both will be there until we fwfs_put it so we don't
* even have to copy it */
}
void exit_module(void)
{
fwfs_put(fwfs_entry);
}
In its current implementation, to get dynamic firmware updates, what I
do in orinoco_usb.c is:
static const struct fwfs_entry *fwfs_entry;
static void * skel_probe(struct usb_device *udev, unsigned int
ifnum, const struct usb_device_id *id)
{
const struct fwfs_entry *fwfs_entry_new;
if((fwfs_entry_new = fwfs_get("orinoco_ezusb_fw"))){
fwfs_put(fwfs_entry);
if (fwfs_entry != fwfs_entry_new){
fwfs_entry = fwfs_entry_new;
firmware.size = fwfs_entry->size;
firmware.code = fwfs_entry->data;
find_fw_variant_offset(&firmware);
}
}
}
int init_module(void)
{
if(firmware.size)
fwfs_write_default("orinoco_ezusb_fw", firmware.code,
firmware.size);
}
void exit_module(void)
{
fwfs_put(fwfs_entry);
}
With the second, you can copy a new firmware from userspace and it
gets used for the next device you plug.
Interesting ideas:
- Integrate something like this with sysfs.
- It looks like sysfs is limited in size to PAGE_SIZE,
which wouldn't be appropriate here.
- allow registering a callback with fwfs to get informed when
the firmware gets loaded/updated from userspace.
- Transparently calling a userspace helper if there is no entry
with the specified name.
- implement a modified version of insmod that would load any
binary as module with any given name.
- Make the drivers read directly from the page cache, although
that would complicate the interface. An alternative interface
could be added, so drivers with huge firmwares could expend a
little more code and save some memory.
>From the linux-kernel thread:
> 1) Register a file on procfs and use "cat" to load the firmware into
> the
> kernel.
>
> 2) Register a device for the same purpose.
>
> 3) Register a device, but use ioctl().
>
> 4) Open a network socket and use ioctl() on it (like ifconfig does).
[snip]
> 7) Encode the firmware into a header file, add it to the driver and
> pretend that the copyright issue doesn't exist (like it's done in
> the
> Keyspan USB driver).
This implementation is equivalent to 1), 2), 3) and 4) but involves
less code on the driver. And has very simple userspace like 1) and 2).
7) A default firmware can be included in a header and registered via
fwfs_write_default(), this:
- gives userspace access to the inkernel image.
- makes it easy to update it at runtime.
- enables the Debian guys to remove the firmware without
removing the whole driver.
Pavel Roskin wrote:
> I believe the reply will be that it's 2.7 material. You could consider
> variants when an existing filesystem is reused as the file repository
> for drivers - it could increase chances that something will be done
> before 2.6 kernel.
I removed all the filesystem code, and used ramfs directly as storage,
just giving it the "fwfs" name for mounting from userspace.
David Gibson wrote:
> I think it would be better to leave the image in the page cache, and
> just put it together when the driver actually uses it. It might make
> the driver interface a bit more complicated, but I think it's worth
> it. And actually it shouldn't be too bad, because you could use
> vmalloc()-like methods to make a virtually contiguous mapping of the
> pages from the page cache.
All kinds of comments/suggestions/criticism are welcomed.
Have a nice day
ranty
-- --- Manuel Estrada Sainz <ranty@debian.org> <ranty@bigfoot.com> <ranty@users.sourceforge.net> ------------------------ <manuel.estrada@hispalinux.es> ------------------- Let us have the serenity to accept the things we cannot change, courage to change the things we can, and wisdom to know the difference.
This archive was generated by hypermail 2b29 : Tue Apr 15 2003 - 22:00:37 EST