$ git tag
deploy-2014-04-24
deploy-2015-11-25
deploy-2015-12-18
gen-certuma-0.v1
gen-certuma-0.v2
hotfix-2015-08-18
upstream-merge-2014-06-27
A když už máme představu, jakou verzi požadujeme, tak si ji prostřednictvím checkout můžeme stáhnout.
git checkout deploy-2015-12-18
Nyní necháme jádro přeložit, tak aby se nám stáhly všechny zdroje. Při tvorbě balíčku jsem vycházel z kmod-hwmon-sht21, ten je nutné povolil v make menuconfig (podmenu Kernel modules -> Hardware Monitoring Support).
Soubor příkladu by měl pro jedno zařízení vytvořit dva virtuální soubory, které při čtení vrací inkrementující se hodnoty, viz následující soubor pokus.c.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/jiffies.h>
/**
*
struct pokus - pokus device specific data
*
@hwmon_dev: device registered with hwmon
*
@lock: mutex to protect measurement values
*
@valid: only 0 before first measurement is taken
*
@last_update: time of last update (jiffies)
*
@number1:
*
@number2:
*/
struct pokus
{
struct device *hwmon_dev;
struct mutex lock;
char valid;
unsigned long last_update;
int number1;
int number2;
};
/**
*
pokus_show_number1() - return value in sysfs
*
@dev: device
*
@attr: device attribute
*
@buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
*
*
Will be called on read access to number1 sysfs attribute.
*
Returns number of bytes written into buffer, negative errno on error.
*/
static ssize_t pokus_show_number1(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pokus *pokus = dev_get_drvdata(dev);
/*int ret;
ret =
pokus_update_measurements(dev);
if (ret < 0) return ret;*/
return sprintf(buf, "%d\n", pokus->number1++);
}
/**
*
pokus_show_number2() - return value in sysfs
*
@dev: device
*
@attr: device attribute
*
@buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
*
*
Will be called on read access to number1 sysfs attribute.
*
Returns number of bytes written into buffer, negative errno on error.
*/
static ssize_t pokus_show_number2(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pokus *pokus = dev_get_drvdata(dev);
/*int ret;
ret =
pokus_update_measurements(dev);
if (ret < 0) return ret;*/
return sprintf(buf, "%d\n", pokus->number2++);
}
/* sysfs attributes */
static SENSOR_DEVICE_ATTR(number1, S_IRUGO, pokus_show_number1,
NULL, 0);
static SENSOR_DEVICE_ATTR(number2, S_IRUGO, pokus_show_number2,
NULL, 0);
static struct attribute *pokus_attributes[] =
{
&sensor_dev_attr_number1.dev_attr.attr,
&sensor_dev_attr_number2.dev_attr.attr,
NULL
};
static const struct attribute_group pokus_attr_group = {
.attrs = pokus_attributes,
};
static int pokus_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pokus *pokus;
int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
{
dev_err(&client->dev, "adapter does not
support SMBus word transactions\n");
return -ENODEV;
}
pokus = devm_kzalloc(&client->dev, sizeof(*pokus), GFP_KERNEL);
if (!pokus) return -ENOMEM;
i2c_set_clientdata(client, pokus);
mutex_init(&pokus->lock);
err = sysfs_create_group(&client->dev.kobj, &pokus_attr_group);
if (err) {
dev_dbg(&client->dev, "could not create
sysfs files\n");
return err;
}
pokus->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(pokus->hwmon_dev)) {
dev_dbg(&client->dev, "unable to register
hwmon device\n");
err = PTR_ERR(pokus->hwmon_dev);
goto fail_remove_sysfs;
}
dev_info(&client->dev, "initialized\n");
return 0;
fail_remove_sysfs:
sysfs_remove_group(&client->dev.kobj, &pokus_attr_group);
return err;
}
/**
* pokus_remove() - remove device
* @client: I2C client device
*/
static int pokus_remove(struct i2c_client *client)
{
struct pokus *pokus = i2c_get_clientdata(client);
hwmon_device_unregister(pokus->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &pokus_attr_group);
return 0;
}
/* Device ID table */
static const struct i2c_device_id pokus_id[] =
{
{ "pokus", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pokus_id);
static struct i2c_driver pokus_driver =
{
.driver.name = "pokus",
.probe = pokus_probe,
.remove = pokus_remove,
.id_table = pokus_id,
};
module_i2c_driver(pokus_driver);
MODULE_AUTHOR("JFila <jfila@xxx.cz>");
MODULE_DESCRIPTION("Pokus driver");
MODULE_LICENSE("GPL");
Do Kconfig doplnit následující definici (build_dir/target-powerpc_8540_uClibc-0.9.33.2/linux-mpc85xx_p2020-nand/linux-3.10.49/drivers/hwmon/Kconfig)
config SENSORS_POKUS
tristate "JFíla pokus driver."
depends on GPIOLIB
help
Pokusný balíček pro hwmon
Do Makefile (build_dir/target-powerpc_8540_uClibc-0.9.33.2/linux-mpc85xx_p2020-nand/linux-3.10.49/drivers/hwmon/Makefile) přidat binárku s názvem balíčku (pokus.o)
obj-$(CONFIG_SENSORS_POKUS) += pokus.o
A hwmon.mk také doplnit popis balíčku a jeho závislostí. (package/kernel/linux/modules/hwmon.mk)
define KernelPackage/hwmon-pokus
TITLE:=pokus device for test
KCONFIG:=CONFIG_SENSORS_POKUS
FILES:=$(LINUX_DIR)/drivers/hwmon/pokus.ko
AUTOLOAD:=$(call AutoProbe,pokus)
$(call AddDepends/hwmon,+kmod-i2c-core)
endef
define KernelPackage/hwmon-pokus/description
Kernel module for pokus device (for test only)
endef
$(eval $(call KernelPackage,hwmon-pokus))
Hotový modul můžeme instalovat jako balíček ale pozor na hash jádra, pro otestování stačí pokus.ko nakopírovat do /lib/modules/3.10.49-xxxxx
Zavedeme modul do jádra a je to:
root@JFila:/# insmod pokus.ko
root@JFila:/# lsmod | grep pokus
hwmon 990 3 pokus
pokus 1468 0
Nyní by již mělo stačit vytvořit nové zařízení:
root@JFila:/# echo pokus 0x27 > /sys/bus/i2c/devices/i2c-1/new_device
root@JFila:/# cd /sys/bus/i2c/devices/
0-004c/ 0-006f/ 1-0027/ 1-0040/ i2c-0/ i2c-1/ i2c-2/
root@JFila:/# cd /sys/bus/i2c/devices/1-0027/
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# ls
driver hwmon modalias name number1 number2 power subsystem uevent
A čtením number jedna bychom měli získávat inkrementující hodnotu:
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
0
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
1
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
2
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
3
https://blog.root.cz/posvic/jak-napsat-ovladac-pro-zarizeni-usb-pro-linux/
Nyní by již mělo stačit vytvořit nové zařízení:
root@JFila:/# echo pokus 0x27 > /sys/bus/i2c/devices/i2c-1/new_device
root@JFila:/# cd /sys/bus/i2c/devices/
0-004c/ 0-006f/ 1-0027/ 1-0040/ i2c-0/ i2c-1/ i2c-2/
root@JFila:/# cd /sys/bus/i2c/devices/1-0027/
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# ls
driver hwmon modalias name number1 number2 power subsystem uevent
A čtením number jedna bychom měli získávat inkrementující hodnotu:
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
0
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
1
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
2
root@JFila:/sys/devices/soc.0/ffe03100.i2c/i2c-1/1-0027# cat number1
3
https://blog.root.cz/posvic/jak-napsat-ovladac-pro-zarizeni-usb-pro-linux/