Commit 18b4b1d1 authored by Alessandro Rubini's avatar Alessandro Rubini

kernel/fmc-core: implement register_n and unregister_n

Additionally, this adds some checks that were missing. A device without
device_id is now refused, instead of receiving a sequential number.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 6a5bfab5
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/fmc.h> #include <linux/fmc.h>
...@@ -94,63 +95,138 @@ void fmc_driver_unregister(struct fmc_driver *drv) ...@@ -94,63 +95,138 @@ void fmc_driver_unregister(struct fmc_driver *drv)
} }
EXPORT_SYMBOL(fmc_driver_unregister); EXPORT_SYMBOL(fmc_driver_unregister);
/* When a device is registered, we must read the eeprom and parse FRU */ /*
int fmc_device_register(struct fmc_device *fmc) * When a device set is registered, all eeproms must be read
*and all FRU must be parsed
*/
int fmc_device_register_n(struct fmc_device *fmcs, int n)
{ {
static int fmc_index; /* a "unique" name for lame devices */ struct fmc_device *fmc, **devarray;
uint32_t device_id; uint32_t device_id;
int ret; int i, ret = 0;
if (fmc_check_version(fmc->version, fmc->carrier_name)) /* Check the version of the first data structure (function prints) */
if (fmc_check_version(fmcs->version, fmcs->carrier_name))
return -EINVAL; return -EINVAL;
/* make sure it is not initialized, or it complains */ devarray = kmalloc(n * sizeof(*devarray),GFP_KERNEL);
memset(&fmc->dev.kobj, 0, sizeof(struct kobject)); if (!devarray) return -ENOMEM;
/* Make all other checks before continuing, for all devices */
for (i = 0, fmc = fmcs; i < n; i++, fmc++) {
if (!fmc->hwdev) {
pr_err("%s: device has no hwdev pointer\n", __func__);
return -EINVAL;
}
if (!fmc->eeprom) {
dev_err(fmc->hwdev, "no eeprom provided to fmc bus\n");
ret = -EINVAL;
}
if (!fmc->eeprom_addr) {
dev_err(fmc->hwdev, "eeprom_addr must be set\n");
ret = -EINVAL;
}
if (!fmc->carrier_name || !fmc->carrier_data || \
!fmc->device_id) {
dev_err(fmc->hwdev, "carrier name and data, and dev_id"
"must all be set\n");
ret = -EINVAL;
}
if(ret)
break;
fmc->nr_slots = n;
devarray[i] = fmc;
}
if (ret) {
kfree(devarray);
return ret;
}
device_initialize(&fmc->dev); /* Validation is ok. Now init and register the devices */
if (!fmc->dev.release) for (i = 0, fmc = fmcs; i < n; i++, fmc++) {
fmc->dev.release = __fmc_release;
if (!fmc->dev.parent) fmc->devarray = devarray;
fmc->dev.parent = &fmc_bus;
/* make sure dev is not initialized, or it complains */
memset(&fmc->dev.kobj, 0, sizeof(struct kobject));
device_initialize(&fmc->dev);
if (!fmc->dev.release)
fmc->dev.release = __fmc_release;
if (!fmc->dev.parent)
fmc->dev.parent = &fmc_bus;
/* Fill the identification stuff (may fail) */
fmc_fill_id_info(fmc);
fmc->dev.bus = &fmc_bus_type;
/* Name from mezzanine info or carrier info. Or 0,1,2.. */
device_id = fmc->device_id;
if (!fmc->mezzanine_name) {
dev_warn(fmc->hwdev, "No mezzanine_name found\n");
dev_set_name(&fmc->dev, "fmc-%04x", device_id);
} else {
dev_set_name(&fmc->dev, "%s-%04x", fmc->mezzanine_name,
device_id);
}
ret = device_add(&fmc->dev);
if (ret < 0) {
dev_err(fmc->hwdev, "Failed in registering \"%s\"\n",
fmc->dev.kobj.name);
fmc_free_id_info(fmc);
goto out;
}
}
return 0;
/* Fill the identification stuff (may fail) */ out:
fmc_fill_id_info(fmc); for (i--, fmc--; i >= 0; i--, fmc--) {
device_del(&fmc->dev);
fmc_free_id_info(fmc);
put_device(&fmc->dev);
}
kfree(fmcs->devarray);
for (i = 0, fmc = fmcs; i < n; i++, fmc++)
fmc->devarray = NULL;
fmc_free_id_info(fmc);
return ret;
fmc->dev.bus = &fmc_bus_type; }
EXPORT_SYMBOL(fmc_device_register_n);
/* The name is from mezzanine info or carrier info. Or 0,1,2.. */ int fmc_device_register(struct fmc_device *fmc)
device_id = fmc->device_id; {
if (!device_id) { return fmc_device_register_n(fmc, 1);
dev_warn(fmc->hwdev, "No device_id filled, using index\n"); }
device_id = fmc_index++; EXPORT_SYMBOL(fmc_device_register);
}
if (!fmc->mezzanine_name) { void fmc_device_unregister_n(struct fmc_device *fmcs, int n)
dev_warn(fmc->hwdev, "No mezzanine_name found\n"); {
dev_set_name(&fmc->dev, "fmc-%04x", device_id); struct fmc_device *fmc;
} else { int i;
dev_set_name(&fmc->dev, "%s-%04x", fmc->mezzanine_name,
device_id); for (i = 0, fmc = fmcs; i < n; i++, fmc++) {
} device_del(&fmc->dev);
ret = device_add(&fmc->dev);
if (ret < 0) {
dev_err(fmc->hwdev, "Failed in registering \"%s\"\n",
fmc->dev.kobj.name);
fmc_free_id_info(fmc); fmc_free_id_info(fmc);
return ret; put_device(&fmc->dev);
}
/* Then, free the locally-allocated stuff */
for (i = 0, fmc = fmcs; i < n; i++, fmc++) {
if (i == 0)
kfree(fmc->devarray);
fmc->devarray = NULL;
} }
return 0;
} }
EXPORT_SYMBOL(fmc_device_register); EXPORT_SYMBOL(fmc_device_unregister_n);
void fmc_device_unregister(struct fmc_device *fmc) void fmc_device_unregister(struct fmc_device *fmc)
{ {
device_del(&fmc->dev); fmc_device_unregister_n(fmc, 1);
fmc_free_id_info(fmc);
put_device(&fmc->dev);
} }
EXPORT_SYMBOL(fmc_device_unregister); EXPORT_SYMBOL(fmc_device_unregister);
/* Init and exit are trivial */ /* Init and exit are trivial */
static int fmc_init(void) static int fmc_init(void)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment