2005-04-17 02:20:36 +04:00
/*
* firmware_class . c - Multi purpose firmware loading support
*
2007-06-04 20:45:44 +04:00
* Copyright ( c ) 2003 Manuel Estrada Sainz
2005-04-17 02:20:36 +04:00
*
* Please see Documentation / firmware_class / for more information .
*
*/
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/device.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/timer.h>
# include <linux/vmalloc.h>
# include <linux/interrupt.h>
# include <linux/bitops.h>
2006-05-24 01:22:38 +04:00
# include <linux/mutex.h>
2006-09-29 12:59:31 +04:00
# include <linux/kthread.h>
2009-04-10 09:04:07 +04:00
# include <linux/highmem.h>
2005-04-17 02:20:36 +04:00
# include <linux/firmware.h>
# include "base.h"
2006-09-14 18:30:59 +04:00
# define to_dev(obj) container_of(obj, struct device, kobj)
2007-06-04 20:45:44 +04:00
MODULE_AUTHOR ( " Manuel Estrada Sainz " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " Multi purpose firmware loading support " ) ;
MODULE_LICENSE ( " GPL " ) ;
enum {
FW_STATUS_LOADING ,
FW_STATUS_DONE ,
FW_STATUS_ABORT ,
} ;
2007-01-25 23:56:15 +03:00
static int loading_timeout = 60 ; /* In seconds */
2005-04-17 02:20:36 +04:00
/* fw_lock could be moved to 'struct firmware_priv' but since it is just
* guarding for corner cases a global lock should be OK */
2006-05-24 01:22:38 +04:00
static DEFINE_MUTEX ( fw_lock ) ;
2005-04-17 02:20:36 +04:00
struct firmware_priv {
2009-05-27 02:49:31 +04:00
char * fw_id ;
2005-04-17 02:20:36 +04:00
struct completion completion ;
struct bin_attribute attr_data ;
struct firmware * fw ;
unsigned long status ;
2009-04-10 09:04:07 +04:00
struct page * * pages ;
int nr_pages ;
int page_array_size ;
const char * vdata ;
2005-04-17 02:20:36 +04:00
struct timer_list timeout ;
} ;
2008-05-23 16:52:42 +04:00
# ifdef CONFIG_FW_LOADER
extern struct builtin_fw __start_builtin_fw [ ] ;
extern struct builtin_fw __end_builtin_fw [ ] ;
# else /* Module case. Avoid ifdefs later; it'll all optimise out */
static struct builtin_fw * __start_builtin_fw ;
static struct builtin_fw * __end_builtin_fw ;
# endif
2006-01-15 00:20:43 +03:00
static void
2005-04-17 02:20:36 +04:00
fw_load_abort ( struct firmware_priv * fw_priv )
{
set_bit ( FW_STATUS_ABORT , & fw_priv - > status ) ;
wmb ( ) ;
complete ( & fw_priv - > completion ) ;
}
static ssize_t
firmware_timeout_show ( struct class * class , char * buf )
{
return sprintf ( buf , " %d \n " , loading_timeout ) ;
}
/**
2005-10-31 02:03:01 +03:00
* firmware_timeout_store - set number of seconds to wait for firmware
* @ class : device class pointer
* @ buf : buffer to scan for timeout value
* @ count : number of bytes in @ buf
*
2005-04-17 02:20:36 +04:00
* Sets the number of seconds to wait for the firmware . Once
2005-10-31 02:03:01 +03:00
* this expires an error will be returned to the driver and no
2005-04-17 02:20:36 +04:00
* firmware will be provided .
*
2005-10-31 02:03:01 +03:00
* Note : zero means ' wait forever ' .
2005-04-17 02:20:36 +04:00
* */
static ssize_t
firmware_timeout_store ( struct class * class , const char * buf , size_t count )
{
loading_timeout = simple_strtol ( buf , NULL , 10 ) ;
2005-06-29 07:44:51 +04:00
if ( loading_timeout < 0 )
loading_timeout = 0 ;
2005-04-17 02:20:36 +04:00
return count ;
}
static CLASS_ATTR ( timeout , 0644 , firmware_timeout_show , firmware_timeout_store ) ;
2006-09-14 18:30:59 +04:00
static void fw_dev_release ( struct device * dev ) ;
2005-04-17 02:20:36 +04:00
2007-08-14 17:15:12 +04:00
static int firmware_uevent ( struct device * dev , struct kobj_uevent_env * env )
2005-04-17 02:20:36 +04:00
{
2006-09-14 18:30:59 +04:00
struct firmware_priv * fw_priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
2007-08-14 17:15:12 +04:00
if ( add_uevent_var ( env , " FIRMWARE=%s " , fw_priv - > fw_id ) )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2007-08-14 17:15:12 +04:00
if ( add_uevent_var ( env , " TIMEOUT=%i " , loading_timeout ) )
2005-04-19 08:57:31 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-05-21 02:00:16 +04:00
static struct class firmware_class = {
. name = " firmware " ,
2006-09-14 18:30:59 +04:00
. dev_uevent = firmware_uevent ,
. dev_release = fw_dev_release ,
2006-05-21 02:00:16 +04:00
} ;
2006-09-14 18:30:59 +04:00
static ssize_t firmware_loading_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2006-09-14 18:30:59 +04:00
struct firmware_priv * fw_priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
int loading = test_bit ( FW_STATUS_LOADING , & fw_priv - > status ) ;
return sprintf ( buf , " %d \n " , loading ) ;
}
2009-04-10 09:04:07 +04:00
/* Some architectures don't have PAGE_KERNEL_RO */
# ifndef PAGE_KERNEL_RO
# define PAGE_KERNEL_RO PAGE_KERNEL
# endif
2005-04-17 02:20:36 +04:00
/**
2005-10-31 02:03:01 +03:00
* firmware_loading_store - set value in the ' loading ' control file
2006-09-14 18:30:59 +04:00
* @ dev : device pointer
2006-12-22 12:06:52 +03:00
* @ attr : device attribute pointer
2005-10-31 02:03:01 +03:00
* @ buf : buffer to scan for loading control value
* @ count : number of bytes in @ buf
*
2005-04-17 02:20:36 +04:00
* The relevant values are :
*
* 1 : Start a load , discarding any previous partial load .
2005-10-31 02:03:01 +03:00
* 0 : Conclude the load and hand the data to the driver code .
2005-04-17 02:20:36 +04:00
* - 1 : Conclude the load with an error and discard any written data .
* */
2006-09-14 18:30:59 +04:00
static ssize_t firmware_loading_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2006-09-14 18:30:59 +04:00
struct firmware_priv * fw_priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
int loading = simple_strtol ( buf , NULL , 10 ) ;
2009-04-10 09:04:07 +04:00
int i ;
2005-04-17 02:20:36 +04:00
switch ( loading ) {
case 1 :
2006-05-24 01:22:38 +04:00
mutex_lock ( & fw_lock ) ;
2005-06-29 07:44:51 +04:00
if ( ! fw_priv - > fw ) {
2006-05-24 01:22:38 +04:00
mutex_unlock ( & fw_lock ) ;
2005-06-29 07:44:51 +04:00
break ;
}
2005-04-17 02:20:36 +04:00
vfree ( fw_priv - > fw - > data ) ;
fw_priv - > fw - > data = NULL ;
2009-04-10 09:04:07 +04:00
for ( i = 0 ; i < fw_priv - > nr_pages ; i + + )
__free_page ( fw_priv - > pages [ i ] ) ;
kfree ( fw_priv - > pages ) ;
fw_priv - > pages = NULL ;
fw_priv - > page_array_size = 0 ;
fw_priv - > nr_pages = 0 ;
2005-04-17 02:20:36 +04:00
fw_priv - > fw - > size = 0 ;
set_bit ( FW_STATUS_LOADING , & fw_priv - > status ) ;
2006-05-24 01:22:38 +04:00
mutex_unlock ( & fw_lock ) ;
2005-04-17 02:20:36 +04:00
break ;
case 0 :
if ( test_bit ( FW_STATUS_LOADING , & fw_priv - > status ) ) {
2009-04-10 09:04:07 +04:00
vfree ( fw_priv - > fw - > data ) ;
fw_priv - > fw - > data = vmap ( fw_priv - > pages ,
fw_priv - > nr_pages ,
0 , PAGE_KERNEL_RO ) ;
if ( ! fw_priv - > fw - > data ) {
dev_err ( dev , " %s: vmap() failed \n " , __func__ ) ;
goto err ;
}
/* Pages will be freed by vfree() */
fw_priv - > pages = NULL ;
fw_priv - > page_array_size = 0 ;
fw_priv - > nr_pages = 0 ;
2005-04-17 02:20:36 +04:00
complete ( & fw_priv - > completion ) ;
clear_bit ( FW_STATUS_LOADING , & fw_priv - > status ) ;
break ;
}
/* fallthrough */
default :
2008-10-16 09:04:20 +04:00
dev_err ( dev , " %s: unexpected value (%d) \n " , __func__ , loading ) ;
2005-04-17 02:20:36 +04:00
/* fallthrough */
case - 1 :
2009-04-10 09:04:07 +04:00
err :
2005-04-17 02:20:36 +04:00
fw_load_abort ( fw_priv ) ;
break ;
}
return count ;
}
2006-09-14 18:30:59 +04:00
static DEVICE_ATTR ( loading , 0644 , firmware_loading_show , firmware_loading_store ) ;
2005-04-17 02:20:36 +04:00
static ssize_t
2007-06-09 09:57:22 +04:00
firmware_data_read ( struct kobject * kobj , struct bin_attribute * bin_attr ,
2005-04-17 02:20:36 +04:00
char * buffer , loff_t offset , size_t count )
{
2006-09-14 18:30:59 +04:00
struct device * dev = to_dev ( kobj ) ;
struct firmware_priv * fw_priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
struct firmware * fw ;
2008-07-25 12:48:23 +04:00
ssize_t ret_count ;
2005-04-17 02:20:36 +04:00
2006-05-24 01:22:38 +04:00
mutex_lock ( & fw_lock ) ;
2005-04-17 02:20:36 +04:00
fw = fw_priv - > fw ;
2005-06-29 07:44:51 +04:00
if ( ! fw | | test_bit ( FW_STATUS_DONE , & fw_priv - > status ) ) {
2005-04-17 02:20:36 +04:00
ret_count = - ENODEV ;
goto out ;
}
2009-04-10 09:04:07 +04:00
if ( offset > fw - > size )
return 0 ;
if ( count > fw - > size - offset )
count = fw - > size - offset ;
ret_count = count ;
while ( count ) {
void * page_data ;
int page_nr = offset > > PAGE_SHIFT ;
int page_ofs = offset & ( PAGE_SIZE - 1 ) ;
int page_cnt = min_t ( size_t , PAGE_SIZE - page_ofs , count ) ;
page_data = kmap ( fw_priv - > pages [ page_nr ] ) ;
memcpy ( buffer , page_data + page_ofs , page_cnt ) ;
kunmap ( fw_priv - > pages [ page_nr ] ) ;
buffer + = page_cnt ;
offset + = page_cnt ;
count - = page_cnt ;
}
2005-04-17 02:20:36 +04:00
out :
2006-05-24 01:22:38 +04:00
mutex_unlock ( & fw_lock ) ;
2005-04-17 02:20:36 +04:00
return ret_count ;
}
2005-10-31 02:03:01 +03:00
2005-04-17 02:20:36 +04:00
static int
fw_realloc_buffer ( struct firmware_priv * fw_priv , int min_size )
{
2009-04-10 09:04:07 +04:00
int pages_needed = ALIGN ( min_size , PAGE_SIZE ) > > PAGE_SHIFT ;
/* If the array of pages is too small, grow it... */
if ( fw_priv - > page_array_size < pages_needed ) {
int new_array_size = max ( pages_needed ,
fw_priv - > page_array_size * 2 ) ;
struct page * * new_pages ;
new_pages = kmalloc ( new_array_size * sizeof ( void * ) ,
GFP_KERNEL ) ;
if ( ! new_pages ) {
fw_load_abort ( fw_priv ) ;
return - ENOMEM ;
}
memcpy ( new_pages , fw_priv - > pages ,
fw_priv - > page_array_size * sizeof ( void * ) ) ;
memset ( & new_pages [ fw_priv - > page_array_size ] , 0 , sizeof ( void * ) *
( new_array_size - fw_priv - > page_array_size ) ) ;
kfree ( fw_priv - > pages ) ;
fw_priv - > pages = new_pages ;
fw_priv - > page_array_size = new_array_size ;
}
2005-04-17 02:20:36 +04:00
2009-04-10 09:04:07 +04:00
while ( fw_priv - > nr_pages < pages_needed ) {
fw_priv - > pages [ fw_priv - > nr_pages ] =
alloc_page ( GFP_KERNEL | __GFP_HIGHMEM ) ;
2005-04-17 02:20:36 +04:00
2009-04-10 09:04:07 +04:00
if ( ! fw_priv - > pages [ fw_priv - > nr_pages ] ) {
fw_load_abort ( fw_priv ) ;
return - ENOMEM ;
}
fw_priv - > nr_pages + + ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
/**
2005-10-31 02:03:01 +03:00
* firmware_data_write - write method for firmware
2006-09-14 18:30:59 +04:00
* @ kobj : kobject for the device
2007-07-24 08:42:11 +04:00
* @ bin_attr : bin_attr structure
2005-10-31 02:03:01 +03:00
* @ buffer : buffer being written
* @ offset : buffer offset for write in total data store area
* @ count : buffer size
2005-04-17 02:20:36 +04:00
*
2005-10-31 02:03:01 +03:00
* Data written to the ' data ' attribute will be later handed to
2005-04-17 02:20:36 +04:00
* the driver as a firmware image .
* */
static ssize_t
2007-06-09 09:57:22 +04:00
firmware_data_write ( struct kobject * kobj , struct bin_attribute * bin_attr ,
2005-04-17 02:20:36 +04:00
char * buffer , loff_t offset , size_t count )
{
2006-09-14 18:30:59 +04:00
struct device * dev = to_dev ( kobj ) ;
struct firmware_priv * fw_priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
struct firmware * fw ;
ssize_t retval ;
if ( ! capable ( CAP_SYS_RAWIO ) )
return - EPERM ;
2005-06-29 07:44:51 +04:00
2006-05-24 01:22:38 +04:00
mutex_lock ( & fw_lock ) ;
2005-04-17 02:20:36 +04:00
fw = fw_priv - > fw ;
2005-06-29 07:44:51 +04:00
if ( ! fw | | test_bit ( FW_STATUS_DONE , & fw_priv - > status ) ) {
2005-04-17 02:20:36 +04:00
retval = - ENODEV ;
goto out ;
}
retval = fw_realloc_buffer ( fw_priv , offset + count ) ;
if ( retval )
goto out ;
retval = count ;
2009-04-10 09:04:07 +04:00
while ( count ) {
void * page_data ;
int page_nr = offset > > PAGE_SHIFT ;
int page_ofs = offset & ( PAGE_SIZE - 1 ) ;
int page_cnt = min_t ( size_t , PAGE_SIZE - page_ofs , count ) ;
page_data = kmap ( fw_priv - > pages [ page_nr ] ) ;
memcpy ( page_data + page_ofs , buffer , page_cnt ) ;
kunmap ( fw_priv - > pages [ page_nr ] ) ;
buffer + = page_cnt ;
offset + = page_cnt ;
count - = page_cnt ;
}
fw - > size = max_t ( size_t , offset , fw - > size ) ;
2005-04-17 02:20:36 +04:00
out :
2006-05-24 01:22:38 +04:00
mutex_unlock ( & fw_lock ) ;
2005-04-17 02:20:36 +04:00
return retval ;
}
2005-10-31 02:03:01 +03:00
2005-04-17 02:20:36 +04:00
static struct bin_attribute firmware_attr_data_tmpl = {
2007-06-13 22:45:17 +04:00
. attr = { . name = " data " , . mode = 0644 } ,
2005-04-17 02:20:36 +04:00
. size = 0 ,
. read = firmware_data_read ,
. write = firmware_data_write ,
} ;
2006-09-14 18:30:59 +04:00
static void fw_dev_release ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
2006-09-14 18:30:59 +04:00
struct firmware_priv * fw_priv = dev_get_drvdata ( dev ) ;
2009-04-10 09:04:07 +04:00
int i ;
2005-04-17 02:20:36 +04:00
2009-04-10 09:04:07 +04:00
for ( i = 0 ; i < fw_priv - > nr_pages ; i + + )
__free_page ( fw_priv - > pages [ i ] ) ;
kfree ( fw_priv - > pages ) ;
2009-05-27 02:49:31 +04:00
kfree ( fw_priv - > fw_id ) ;
2005-04-17 02:20:36 +04:00
kfree ( fw_priv ) ;
2009-07-08 14:17:40 +04:00
kfree ( dev ) ;
2005-04-17 02:20:36 +04:00
module_put ( THIS_MODULE ) ;
}
static void
firmware_class_timeout ( u_long data )
{
struct firmware_priv * fw_priv = ( struct firmware_priv * ) data ;
fw_load_abort ( fw_priv ) ;
}
2006-09-14 18:30:59 +04:00
static int fw_register_device ( struct device * * dev_p , const char * fw_name ,
struct device * device )
2005-04-17 02:20:36 +04:00
{
int retval ;
2005-09-13 12:25:01 +04:00
struct firmware_priv * fw_priv = kzalloc ( sizeof ( * fw_priv ) ,
2005-04-17 02:20:36 +04:00
GFP_KERNEL ) ;
2006-09-14 18:30:59 +04:00
struct device * f_dev = kzalloc ( sizeof ( * f_dev ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
2006-09-14 18:30:59 +04:00
* dev_p = NULL ;
2005-04-17 02:20:36 +04:00
2006-09-14 18:30:59 +04:00
if ( ! fw_priv | | ! f_dev ) {
2008-10-16 09:04:20 +04:00
dev_err ( device , " %s: kmalloc failed \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
retval = - ENOMEM ;
goto error_kfree ;
}
init_completion ( & fw_priv - > completion ) ;
fw_priv - > attr_data = firmware_attr_data_tmpl ;
2009-05-27 02:49:31 +04:00
fw_priv - > fw_id = kstrdup ( fw_name , GFP_KERNEL ) ;
if ( ! fw_priv - > fw_id ) {
dev_err ( device , " %s: Firmware name allocation failed \n " ,
__func__ ) ;
retval = - ENOMEM ;
goto error_kfree ;
}
2005-04-17 02:20:36 +04:00
fw_priv - > timeout . function = firmware_class_timeout ;
fw_priv - > timeout . data = ( u_long ) fw_priv ;
init_timer ( & fw_priv - > timeout ) ;
2009-06-03 02:39:55 +04:00
dev_set_name ( f_dev , " %s " , dev_name ( device ) ) ;
2006-09-14 18:30:59 +04:00
f_dev - > parent = device ;
f_dev - > class = & firmware_class ;
dev_set_drvdata ( f_dev , fw_priv ) ;
2009-03-01 16:10:49 +03:00
dev_set_uevent_suppress ( f_dev , 1 ) ;
2006-09-14 18:30:59 +04:00
retval = device_register ( f_dev ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
2008-10-16 09:04:20 +04:00
dev_err ( device , " %s: device_register failed \n " , __func__ ) ;
2009-04-23 18:31:52 +04:00
put_device ( f_dev ) ;
2009-07-08 14:17:40 +04:00
return retval ;
2005-04-17 02:20:36 +04:00
}
2006-09-14 18:30:59 +04:00
* dev_p = f_dev ;
2005-04-17 02:20:36 +04:00
return 0 ;
error_kfree :
2006-09-14 18:30:59 +04:00
kfree ( f_dev ) ;
2009-04-23 18:31:52 +04:00
kfree ( fw_priv ) ;
2005-04-17 02:20:36 +04:00
return retval ;
}
2006-09-14 18:30:59 +04:00
static int fw_setup_device ( struct firmware * fw , struct device * * dev_p ,
const char * fw_name , struct device * device ,
int uevent )
2005-04-17 02:20:36 +04:00
{
2006-09-14 18:30:59 +04:00
struct device * f_dev ;
2005-04-17 02:20:36 +04:00
struct firmware_priv * fw_priv ;
int retval ;
2006-09-14 18:30:59 +04:00
* dev_p = NULL ;
retval = fw_register_device ( & f_dev , fw_name , device ) ;
2005-04-17 02:20:36 +04:00
if ( retval )
goto out ;
/* Need to pin this module until class device is destroyed */
__module_get ( THIS_MODULE ) ;
2006-09-14 18:30:59 +04:00
fw_priv = dev_get_drvdata ( f_dev ) ;
2005-04-17 02:20:36 +04:00
fw_priv - > fw = fw ;
2006-09-14 18:30:59 +04:00
retval = sysfs_create_bin_file ( & f_dev - > kobj , & fw_priv - > attr_data ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
2008-10-16 09:04:20 +04:00
dev_err ( device , " %s: sysfs_create_bin_file failed \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
goto error_unreg ;
}
2006-09-14 18:30:59 +04:00
retval = device_create_file ( f_dev , & dev_attr_loading ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
2008-10-16 09:04:20 +04:00
dev_err ( device , " %s: device_create_file failed \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
goto error_unreg ;
}
2005-11-16 11:00:00 +03:00
if ( uevent )
2009-03-01 16:10:49 +03:00
dev_set_uevent_suppress ( f_dev , 0 ) ;
2006-09-14 18:30:59 +04:00
* dev_p = f_dev ;
2005-04-17 02:20:36 +04:00
goto out ;
error_unreg :
2006-09-14 18:30:59 +04:00
device_unregister ( f_dev ) ;
2005-04-17 02:20:36 +04:00
out :
return retval ;
}
2005-09-07 02:17:13 +04:00
static int
_request_firmware ( const struct firmware * * firmware_p , const char * name ,
2005-11-16 11:00:00 +03:00
struct device * device , int uevent )
2005-04-17 02:20:36 +04:00
{
2006-09-14 18:30:59 +04:00
struct device * f_dev ;
2005-04-17 02:20:36 +04:00
struct firmware_priv * fw_priv ;
struct firmware * firmware ;
2008-05-23 16:52:42 +04:00
struct builtin_fw * builtin ;
2005-04-17 02:20:36 +04:00
int retval ;
if ( ! firmware_p )
return - EINVAL ;
2005-09-13 12:25:01 +04:00
* firmware_p = firmware = kzalloc ( sizeof ( * firmware ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! firmware ) {
2008-10-16 09:04:20 +04:00
dev_err ( device , " %s: kmalloc(struct firmware) failed \n " ,
__func__ ) ;
2005-04-17 02:20:36 +04:00
retval = - ENOMEM ;
goto out ;
}
2008-05-23 16:52:42 +04:00
for ( builtin = __start_builtin_fw ; builtin ! = __end_builtin_fw ;
builtin + + ) {
if ( strcmp ( name , builtin - > name ) )
continue ;
2008-10-16 09:04:20 +04:00
dev_info ( device , " firmware: using built-in firmware %s \n " ,
name ) ;
2008-05-23 16:52:42 +04:00
firmware - > size = builtin - > size ;
firmware - > data = builtin - > data ;
return 0 ;
}
if ( uevent )
2008-10-16 09:04:20 +04:00
dev_info ( device , " firmware: requesting %s \n " , name ) ;
2008-05-23 16:52:42 +04:00
2006-09-14 18:30:59 +04:00
retval = fw_setup_device ( firmware , & f_dev , name , device , uevent ) ;
2005-04-17 02:20:36 +04:00
if ( retval )
goto error_kfree_fw ;
2006-09-14 18:30:59 +04:00
fw_priv = dev_get_drvdata ( f_dev ) ;
2005-04-17 02:20:36 +04:00
2005-11-16 11:00:00 +03:00
if ( uevent ) {
2005-09-07 02:17:13 +04:00
if ( loading_timeout > 0 ) {
fw_priv - > timeout . expires = jiffies + loading_timeout * HZ ;
add_timer ( & fw_priv - > timeout ) ;
}
2005-04-17 02:20:36 +04:00
2006-09-14 18:30:59 +04:00
kobject_uevent ( & f_dev - > kobj , KOBJ_ADD ) ;
2005-09-07 02:17:13 +04:00
wait_for_completion ( & fw_priv - > completion ) ;
set_bit ( FW_STATUS_DONE , & fw_priv - > status ) ;
del_timer_sync ( & fw_priv - > timeout ) ;
} else
wait_for_completion ( & fw_priv - > completion ) ;
2005-04-17 02:20:36 +04:00
2006-05-24 01:22:38 +04:00
mutex_lock ( & fw_lock ) ;
2005-04-17 02:20:36 +04:00
if ( ! fw_priv - > fw - > size | | test_bit ( FW_STATUS_ABORT , & fw_priv - > status ) ) {
retval = - ENOENT ;
release_firmware ( fw_priv - > fw ) ;
* firmware_p = NULL ;
}
fw_priv - > fw = NULL ;
2006-05-24 01:22:38 +04:00
mutex_unlock ( & fw_lock ) ;
2006-09-14 18:30:59 +04:00
device_unregister ( f_dev ) ;
2005-04-17 02:20:36 +04:00
goto out ;
error_kfree_fw :
kfree ( firmware ) ;
* firmware_p = NULL ;
out :
return retval ;
}
2005-09-07 02:17:13 +04:00
/**
2005-11-16 11:00:00 +03:00
* request_firmware : - send firmware request and wait for it
2005-10-31 02:03:01 +03:00
* @ firmware_p : pointer to firmware image
* @ name : name of firmware file
* @ device : device for which firmware is being loaded
*
* @ firmware_p will be used to return a firmware image by the name
2005-09-07 02:17:13 +04:00
* of @ name for device @ device .
*
* Should be called from user context where sleeping is allowed .
*
2005-11-16 11:00:00 +03:00
* @ name will be used as $ FIRMWARE in the uevent environment and
2005-09-07 02:17:13 +04:00
* should be distinctive enough not to be confused with any other
* firmware image for this or any other device .
* */
int
request_firmware ( const struct firmware * * firmware_p , const char * name ,
struct device * device )
{
2005-11-16 11:00:00 +03:00
int uevent = 1 ;
return _request_firmware ( firmware_p , name , device , uevent ) ;
2005-09-07 02:17:13 +04:00
}
2005-04-17 02:20:36 +04:00
/**
* release_firmware : - release the resource associated with a firmware image
2005-10-31 02:03:01 +03:00
* @ fw : firmware resource to release
2005-04-17 02:20:36 +04:00
* */
void
release_firmware ( const struct firmware * fw )
{
2008-05-23 16:52:42 +04:00
struct builtin_fw * builtin ;
2005-04-17 02:20:36 +04:00
if ( fw ) {
2008-05-23 16:52:42 +04:00
for ( builtin = __start_builtin_fw ; builtin ! = __end_builtin_fw ;
builtin + + ) {
if ( fw - > data = = builtin - > data )
goto free_fw ;
}
2005-04-17 02:20:36 +04:00
vfree ( fw - > data ) ;
2008-05-23 16:52:42 +04:00
free_fw :
2005-04-17 02:20:36 +04:00
kfree ( fw ) ;
}
}
/* Async support */
struct firmware_work {
struct work_struct work ;
struct module * module ;
const char * name ;
struct device * device ;
void * context ;
void ( * cont ) ( const struct firmware * fw , void * context ) ;
2005-11-16 11:00:00 +03:00
int uevent ;
2005-04-17 02:20:36 +04:00
} ;
static int
request_firmware_work_func ( void * arg )
{
struct firmware_work * fw_work = arg ;
const struct firmware * fw ;
2005-11-14 03:07:39 +03:00
int ret ;
2005-04-17 02:20:36 +04:00
if ( ! arg ) {
WARN_ON ( 1 ) ;
return 0 ;
}
2005-11-14 03:07:39 +03:00
ret = _request_firmware ( & fw , fw_work - > name , fw_work - > device ,
2005-11-16 11:00:00 +03:00
fw_work - > uevent ) ;
2005-11-14 03:07:39 +03:00
if ( ret < 0 )
fw_work - > cont ( NULL , fw_work - > context ) ;
else {
fw_work - > cont ( fw , fw_work - > context ) ;
release_firmware ( fw ) ;
}
2005-04-17 02:20:36 +04:00
module_put ( fw_work - > module ) ;
kfree ( fw_work ) ;
2005-11-14 03:07:39 +03:00
return ret ;
2005-04-17 02:20:36 +04:00
}
/**
2005-10-31 02:03:01 +03:00
* request_firmware_nowait : asynchronous version of request_firmware
* @ module : module requesting the firmware
2005-11-16 11:00:00 +03:00
* @ uevent : sends uevent to copy the firmware image if this flag
2005-10-31 02:03:01 +03:00
* is non - zero else the firmware copy must be done manually .
* @ name : name of firmware file
* @ device : device for which firmware is being loaded
* @ context : will be passed over to @ cont , and
* @ fw may be % NULL if firmware request fails .
* @ cont : function will be called asynchronously when the firmware
* request is over .
2005-04-17 02:20:36 +04:00
*
2009-05-29 07:33:19 +04:00
* Asynchronous variant of request_firmware ( ) for user contexts where
* it is not possible to sleep for long time . It can ' t be called
* in atomic contexts .
2005-04-17 02:20:36 +04:00
* */
int
request_firmware_nowait (
2005-11-16 11:00:00 +03:00
struct module * module , int uevent ,
2005-04-17 02:20:36 +04:00
const char * name , struct device * device , void * context ,
void ( * cont ) ( const struct firmware * fw , void * context ) )
{
2006-09-29 12:59:31 +04:00
struct task_struct * task ;
2005-04-17 02:20:36 +04:00
struct firmware_work * fw_work = kmalloc ( sizeof ( struct firmware_work ) ,
GFP_ATOMIC ) ;
if ( ! fw_work )
return - ENOMEM ;
if ( ! try_module_get ( module ) ) {
kfree ( fw_work ) ;
return - EFAULT ;
}
* fw_work = ( struct firmware_work ) {
. module = module ,
. name = name ,
. device = device ,
. context = context ,
. cont = cont ,
2005-11-16 11:00:00 +03:00
. uevent = uevent ,
2005-04-17 02:20:36 +04:00
} ;
2006-09-29 12:59:31 +04:00
task = kthread_run ( request_firmware_work_func , fw_work ,
" firmware/%s " , name ) ;
2005-04-17 02:20:36 +04:00
2006-09-29 12:59:31 +04:00
if ( IS_ERR ( task ) ) {
2005-04-17 02:20:36 +04:00
fw_work - > cont ( NULL , fw_work - > context ) ;
2005-11-14 03:07:39 +03:00
module_put ( fw_work - > module ) ;
kfree ( fw_work ) ;
2006-09-29 12:59:31 +04:00
return PTR_ERR ( task ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
static int __init
firmware_class_init ( void )
{
int error ;
error = class_register ( & firmware_class ) ;
if ( error ) {
2008-03-05 03:41:05 +03:00
printk ( KERN_ERR " %s: class_register failed \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
error = class_create_file ( & firmware_class , & class_attr_timeout ) ;
if ( error ) {
printk ( KERN_ERR " %s: class_create_file failed \n " ,
2008-03-05 03:41:05 +03:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
class_unregister ( & firmware_class ) ;
}
return error ;
}
static void __exit
firmware_class_exit ( void )
{
class_unregister ( & firmware_class ) ;
}
2006-09-27 12:50:52 +04:00
fs_initcall ( firmware_class_init ) ;
2005-04-17 02:20:36 +04:00
module_exit ( firmware_class_exit ) ;
EXPORT_SYMBOL ( release_firmware ) ;
EXPORT_SYMBOL ( request_firmware ) ;
EXPORT_SYMBOL ( request_firmware_nowait ) ;