2005-04-17 02:20:36 +04:00
/*
* firmware_sample_firmware_class . c -
*
* Copyright ( c ) 2003 Manuel Estrada Sainz < ranty @ debian . org >
*
* NOTE : This is just a probe of concept , if you think that your driver would
* be well served by this mechanism please contact me first .
*
* DON ' T USE THIS CODE AS IS
*
*/
# include <linux/device.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/timer.h>
2005-10-31 02:03:48 +03:00
# include <linux/slab.h>
# include <linux/string.h>
2005-04-17 02:20:36 +04:00
# include <linux/firmware.h>
MODULE_AUTHOR ( " Manuel Estrada Sainz <ranty@debian.org> " ) ;
MODULE_DESCRIPTION ( " Hackish sample for using firmware class directly " ) ;
MODULE_LICENSE ( " GPL " ) ;
static inline struct class_device * to_class_dev ( struct kobject * obj )
{
return container_of ( obj , struct class_device , kobj ) ;
}
static inline
struct class_device_attribute * to_class_dev_attr ( struct attribute * _attr )
{
return container_of ( _attr , struct class_device_attribute , attr ) ;
}
int sysfs_create_bin_file ( struct kobject * kobj , struct bin_attribute * attr ) ;
int sysfs_remove_bin_file ( struct kobject * kobj , struct bin_attribute * attr ) ;
struct firmware_priv {
char fw_id [ FIRMWARE_NAME_MAX ] ;
s32 loading : 2 ;
u32 abort : 1 ;
} ;
extern struct class firmware_class ;
static ssize_t firmware_loading_show ( struct class_device * class_dev , char * buf )
{
struct firmware_priv * fw_priv = class_get_devdata ( class_dev ) ;
return sprintf ( buf , " %d \n " , fw_priv - > loading ) ;
}
static ssize_t firmware_loading_store ( struct class_device * class_dev ,
const char * buf , size_t count )
{
struct firmware_priv * fw_priv = class_get_devdata ( class_dev ) ;
int prev_loading = fw_priv - > loading ;
fw_priv - > loading = simple_strtol ( buf , NULL , 10 ) ;
switch ( fw_priv - > loading ) {
case - 1 :
/* abort load an panic */
break ;
case 1 :
/* setup load */
break ;
case 0 :
if ( prev_loading = = 1 ) {
/* finish load and get the device back to working
* state */
}
break ;
}
return count ;
}
static CLASS_DEVICE_ATTR ( loading , 0644 ,
firmware_loading_show , firmware_loading_store ) ;
static ssize_t firmware_data_read ( struct kobject * kobj ,
char * buffer , loff_t offset , size_t count )
{
struct class_device * class_dev = to_class_dev ( kobj ) ;
struct firmware_priv * fw_priv = class_get_devdata ( class_dev ) ;
/* read from the devices firmware memory */
return count ;
}
static ssize_t firmware_data_write ( struct kobject * kobj ,
char * buffer , loff_t offset , size_t count )
{
struct class_device * class_dev = to_class_dev ( kobj ) ;
struct firmware_priv * fw_priv = class_get_devdata ( class_dev ) ;
/* write to the devices firmware memory */
return count ;
}
static struct bin_attribute firmware_attr_data = {
. attr = { . name = " data " , . mode = 0644 } ,
. size = 0 ,
. read = firmware_data_read ,
. write = firmware_data_write ,
} ;
static int fw_setup_class_device ( struct class_device * class_dev ,
const char * fw_name ,
struct device * device )
{
int retval = 0 ;
struct firmware_priv * fw_priv = kmalloc ( sizeof ( struct firmware_priv ) ,
GFP_KERNEL ) ;
if ( ! fw_priv ) {
retval = - ENOMEM ;
goto out ;
}
memset ( fw_priv , 0 , sizeof ( * fw_priv ) ) ;
memset ( class_dev , 0 , sizeof ( * class_dev ) ) ;
strncpy ( fw_priv - > fw_id , fw_name , FIRMWARE_NAME_MAX ) ;
fw_priv - > fw_id [ FIRMWARE_NAME_MAX - 1 ] = ' \0 ' ;
strncpy ( class_dev - > class_id , device - > bus_id , BUS_ID_SIZE ) ;
class_dev - > class_id [ BUS_ID_SIZE - 1 ] = ' \0 ' ;
class_dev - > dev = device ;
class_dev - > class = & firmware_class ,
class_set_devdata ( class_dev , fw_priv ) ;
retval = class_device_register ( class_dev ) ;
if ( retval ) {
printk ( KERN_ERR " %s: class_device_register failed \n " ,
__FUNCTION__ ) ;
goto error_free_fw_priv ;
}
retval = sysfs_create_bin_file ( & class_dev - > kobj , & firmware_attr_data ) ;
if ( retval ) {
printk ( KERN_ERR " %s: sysfs_create_bin_file failed \n " ,
__FUNCTION__ ) ;
goto error_unreg_class_dev ;
}
retval = class_device_create_file ( class_dev ,
& class_device_attr_loading ) ;
if ( retval ) {
printk ( KERN_ERR " %s: class_device_create_file failed \n " ,
__FUNCTION__ ) ;
goto error_remove_data ;
}
goto out ;
error_remove_data :
sysfs_remove_bin_file ( & class_dev - > kobj , & firmware_attr_data ) ;
error_unreg_class_dev :
class_device_unregister ( class_dev ) ;
error_free_fw_priv :
kfree ( fw_priv ) ;
out :
return retval ;
}
static void fw_remove_class_device ( struct class_device * class_dev )
{
struct firmware_priv * fw_priv = class_get_devdata ( class_dev ) ;
class_device_remove_file ( class_dev , & class_device_attr_loading ) ;
sysfs_remove_bin_file ( & class_dev - > kobj , & firmware_attr_data ) ;
class_device_unregister ( class_dev ) ;
}
static struct class_device * class_dev ;
static struct device my_device = {
. name = " Sample Device " ,
. bus_id = " my_dev0 " ,
} ;
static int __init firmware_sample_init ( void )
{
int error ;
device_initialize ( & my_device ) ;
class_dev = kmalloc ( sizeof ( struct class_device ) , GFP_KERNEL ) ;
if ( ! class_dev )
return - ENOMEM ;
error = fw_setup_class_device ( class_dev , " my_firmware_image " ,
& my_device ) ;
if ( error ) {
kfree ( class_dev ) ;
return error ;
}
return 0 ;
}
static void __exit firmware_sample_exit ( void )
{
struct firmware_priv * fw_priv = class_get_devdata ( class_dev ) ;
fw_remove_class_device ( class_dev ) ;
kfree ( fw_priv ) ;
kfree ( class_dev ) ;
}
module_init ( firmware_sample_init ) ;
module_exit ( firmware_sample_exit ) ;