firmware_sample_firmware_class.c 4.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * firmware_sample_firmware_class.c -
 *
4
 * Copyright (c) 2003 Manuel Estrada Sainz
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * 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>
T
Tim Schmielau 已提交
17 18
#include <linux/slab.h>
#include <linux/string.h>
L
Linus Torvalds 已提交
19 20 21
#include <linux/firmware.h>


22
MODULE_AUTHOR("Manuel Estrada Sainz");
L
Linus Torvalds 已提交
23 24 25 26 27
MODULE_DESCRIPTION("Hackish sample for using firmware class directly");
MODULE_LICENSE("GPL");

static inline struct class_device *to_class_dev(struct kobject *obj)
{
28
	return container_of(obj, struct class_device, kobj);
L
Linus Torvalds 已提交
29
}
30

L
Linus Torvalds 已提交
31 32 33
static inline
struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
{
34
	return container_of(_attr, struct class_device_attribute, attr);
L
Linus Torvalds 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47
}

struct firmware_priv {
	char fw_id[FIRMWARE_NAME_MAX];
	s32 loading:2;
	u32 abort:1;
};

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);
}
48

L
Linus Torvalds 已提交
49 50 51 52 53 54 55
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);
56

57
	switch (fw_priv->loading) {
L
Linus Torvalds 已提交
58 59 60 61 62 63 64
	case -1:
		/* abort load an panic */
		break;
	case 1:
		/* setup load */
		break;
	case 0:
65
		if (prev_loading == 1) {
L
Linus Torvalds 已提交
66 67 68 69 70 71 72 73 74 75 76 77
			/* 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,
78
				  struct bin_attribute *bin_attr,
L
Linus Torvalds 已提交
79 80 81 82 83 84 85 86 87 88
				  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,
89
				   struct bin_attribute *bin_attr,
L
Linus Torvalds 已提交
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
				   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)
{
109 110
	int retval;
	struct firmware_priv *fw_priv;
L
Linus Torvalds 已提交
111

112 113
	fw_priv = kzalloc(sizeof(struct firmware_priv),	GFP_KERNEL);
	if (!fw_priv) {
L
Linus Torvalds 已提交
114 115 116
		retval = -ENOMEM;
		goto out;
	}
117

L
Linus Torvalds 已提交
118 119 120 121 122 123 124 125 126
	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;

127
	class_dev->class = &firmware_class;
L
Linus Torvalds 已提交
128 129
	class_set_devdata(class_dev, fw_priv);
	retval = class_device_register(class_dev);
130
	if (retval) {
L
Linus Torvalds 已提交
131
		printk(KERN_ERR "%s: class_device_register failed\n",
132
		       __func__);
L
Linus Torvalds 已提交
133 134 135 136
		goto error_free_fw_priv;
	}

	retval = sysfs_create_bin_file(&class_dev->kobj, &firmware_attr_data);
137
	if (retval) {
L
Linus Torvalds 已提交
138
		printk(KERN_ERR "%s: sysfs_create_bin_file failed\n",
139
		       __func__);
L
Linus Torvalds 已提交
140 141 142 143 144
		goto error_unreg_class_dev;
	}

	retval = class_device_create_file(class_dev,
					  &class_device_attr_loading);
145
	if (retval) {
L
Linus Torvalds 已提交
146
		printk(KERN_ERR "%s: class_device_create_file failed\n",
147
		       __func__);
L
Linus Torvalds 已提交
148 149 150 151
		goto error_remove_data;
	}

	goto out;
152

L
Linus Torvalds 已提交
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
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 = {
	.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);
183
	if (!class_dev)
L
Linus Torvalds 已提交
184 185 186 187
		return -ENOMEM;

	error = fw_setup_class_device(class_dev, "my_firmware_image",
				      &my_device);
188
	if (error) {
L
Linus Torvalds 已提交
189 190 191
		kfree(class_dev);
		return error;
	}
192
	return 0;
L
Linus Torvalds 已提交
193 194 195 196 197 198 199 200 201

}
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);
}
202

L
Linus Torvalds 已提交
203 204
module_init(firmware_sample_init);
module_exit(firmware_sample_exit);