firmware_sample_firmware_class.c 5.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
/*
 * 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>
#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);