177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini/* 277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * Copyright (C) 2012 CERN (www.cern.ch) 377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * Author: Alessandro Rubini <rubini@gnudd.com> 477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * 577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * Released according to the GNU GPL, version 2 or any later version. 677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * 777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * This work is part of the White Rabbit project, a research effort led 877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * by CERN, the European Institute for Nuclear Research. 977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini */ 109c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini#include <linux/kernel.h> 119c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini#include <linux/module.h> 1277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini#include <linux/slab.h> 139c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini#include <linux/init.h> 149c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini#include <linux/device.h> 1577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini#include <linux/fmc.h> 1677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 1777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic int fmc_check_version(unsigned long version, const char *name) 1877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 1977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (__FMC_MAJOR(version) != FMC_MAJOR) { 2077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini pr_err("%s: \"%s\" has wrong major (has %li, expected %i)\n", 2177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __func__, name, __FMC_MAJOR(version), FMC_MAJOR); 2277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return -EINVAL; 2377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 2477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 2577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (__FMC_MINOR(version) != FMC_MINOR) 2677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini pr_info("%s: \"%s\" has wrong minor (has %li, expected %i)\n", 2777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __func__, name, __FMC_MINOR(version), FMC_MINOR); 2877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return 0; 2977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 3077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 3177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic int fmc_uevent(struct device *dev, struct kobj_uevent_env *env) 3277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 3377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* struct fmc_device *fdev = to_fmc_device(dev); */ 3477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 3577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* FIXME: The MODALIAS */ 3677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini add_uevent_var(env, "MODALIAS=%s", "fmc"); 3777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return 0; 3877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 3977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 4077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic int fmc_probe(struct device *dev) 4177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 4277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct fmc_driver *fdrv = to_fmc_driver(dev->driver); 4377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct fmc_device *fdev = to_fmc_device(dev); 4477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 4577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return fdrv->probe(fdev); 4677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 4777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 4877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic int fmc_remove(struct device *dev) 4977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 5077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct fmc_driver *fdrv = to_fmc_driver(dev->driver); 5177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct fmc_device *fdev = to_fmc_device(dev); 5277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 5377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return fdrv->remove(fdev); 5477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 5577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 5677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic void fmc_shutdown(struct device *dev) 5777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 5877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* not implemented but mandatory */ 5977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 609c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini 619c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubinistatic struct bus_type fmc_bus_type = { 629c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini .name = "fmc", 6377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini .match = fmc_match, 6477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini .uevent = fmc_uevent, 6577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini .probe = fmc_probe, 6677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini .remove = fmc_remove, 6777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini .shutdown = fmc_shutdown, 689c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini}; 699c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini 7077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic void fmc_release(struct device *dev) 7177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 7277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct fmc_device *fmc = container_of(dev, struct fmc_device, dev); 7377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 7477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini kfree(fmc); 7577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 7677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 7777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini/* 7877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * The eeprom is exported in sysfs, through a binary attribute 7977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini */ 8077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 8177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic ssize_t fmc_read_eeprom(struct file *file, struct kobject *kobj, 8277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct bin_attribute *bin_attr, 8377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini char *buf, loff_t off, size_t count) 8477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 8577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct device *dev; 8677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct fmc_device *fmc; 8777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int eelen; 8877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 8977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev = container_of(kobj, struct device, kobj); 9077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc = container_of(dev, struct fmc_device, dev); 9177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini eelen = fmc->eeprom_len; 9277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (off > eelen) 9377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return -ESPIPE; 9477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (off == eelen) 9577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return 0; /* EOF */ 9677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (off + count > eelen) 9777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini count = eelen - off; 9877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini memcpy(buf, fmc->eeprom + off, count); 9977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return count; 10077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 10177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 1025c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubinistatic ssize_t fmc_write_eeprom(struct file *file, struct kobject *kobj, 1035c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini struct bin_attribute *bin_attr, 1045c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini char *buf, loff_t off, size_t count) 1055c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini{ 1065c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini struct device *dev; 1075c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini struct fmc_device *fmc; 1085c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini 1095c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini dev = container_of(kobj, struct device, kobj); 1105c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini fmc = container_of(dev, struct fmc_device, dev); 1115c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini return fmc->op->write_ee(fmc, off, buf, count); 1125c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini} 1135c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini 11477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic struct bin_attribute fmc_eeprom_attr = { 1155c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini .attr = { .name = "eeprom", .mode = S_IRUGO | S_IWUSR, }, 11677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini .size = 8192, /* more or less standard */ 11777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini .read = fmc_read_eeprom, 1185c9a87367daf292244bd9bb3e67516dfa0027516Alessandro Rubini .write = fmc_write_eeprom, 11977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini}; 12077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 12177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini/* 12277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * Functions for client modules follow 12377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini */ 12477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 12577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubiniint fmc_driver_register(struct fmc_driver *drv) 12677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 12777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (fmc_check_version(drv->version, drv->driver.name)) 12877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return -EINVAL; 12977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini drv->driver.bus = &fmc_bus_type; 13077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return driver_register(&drv->driver); 13177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 13277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_driver_register); 13377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 13477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinivoid fmc_driver_unregister(struct fmc_driver *drv) 13577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 13677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini driver_unregister(&drv->driver); 13777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 13877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_driver_unregister); 13977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 14077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini/* 14177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * When a device set is registered, all eeproms must be read 14277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * and all FRUs must be parsed 14377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini */ 14477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubiniint fmc_device_register_n(struct fmc_device **devs, int n) 14577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 14677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct fmc_device *fmc, **devarray; 14777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini uint32_t device_id; 14877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int i, ret = 0; 14977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 15077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (n < 1) 15177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return 0; 15277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 15377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* Check the version of the first data structure (function prints) */ 15477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (fmc_check_version(devs[0]->version, devs[0]->carrier_name)) 15577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return -EINVAL; 15677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 15777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini devarray = kmemdup(devs, n * sizeof(*devs), GFP_KERNEL); 15877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (!devarray) 15977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return -ENOMEM; 16077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 16177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* Make all other checks before continuing, for all devices */ 16277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (i = 0; i < n; i++) { 16377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc = devarray[i]; 16477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (!fmc->hwdev) { 16577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini pr_err("%s: device nr. %i has no hwdev pointer\n", 16677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __func__, i); 16777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini ret = -EINVAL; 16877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 16977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 170e4d6c4b79cc189c1b0d65f8e3875c4411e097beeAlessandro Rubini if (fmc->flags & FMC_DEVICE_NO_MEZZANINE) { 17177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev_info(fmc->hwdev, "absent mezzanine in slot %d\n", 17277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc->slot_id); 17377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini continue; 17477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 17577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (!fmc->eeprom) { 17677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev_err(fmc->hwdev, "no eeprom provided for slot %i\n", 17777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc->slot_id); 17877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini ret = -EINVAL; 17977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 18077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (!fmc->eeprom_addr) { 18177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev_err(fmc->hwdev, "no eeprom_addr for slot %i\n", 18277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc->slot_id); 18377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini ret = -EINVAL; 18477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 18577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (!fmc->carrier_name || !fmc->carrier_data || 18677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini !fmc->device_id) { 18777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev_err(fmc->hwdev, 18877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini "deivce nr %i: carrier name, " 18977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini "data or dev_id not set\n", i); 19077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini ret = -EINVAL; 19177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 19277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (ret) 19377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 19477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 19577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 19677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (ret) { 19777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini kfree(devarray); 19877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return ret; 19977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 20077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 20177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* Validation is ok. Now init and register the devices */ 20277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (i = 0; i < n; i++) { 20377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc = devarray[i]; 20477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 20577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc->nr_slots = n; /* each slot must know how many are there */ 20677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc->devarray = devarray; 20777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 20877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini device_initialize(&fmc->dev); 20977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc->dev.release = fmc_release; 21077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc->dev.parent = fmc->hwdev; 21177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 21277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* Fill the identification stuff (may fail) */ 21377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc_fill_id_info(fmc); 21477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 21577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc->dev.bus = &fmc_bus_type; 21677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 21777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* Name from mezzanine info or carrier info. Or 0,1,2.. */ 21877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini device_id = fmc->device_id; 21977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (!fmc->mezzanine_name) 22077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev_set_name(&fmc->dev, "fmc-%04x", device_id); 22177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini else 22277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev_set_name(&fmc->dev, "%s-%04x", fmc->mezzanine_name, 22377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini device_id); 22477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini ret = device_add(&fmc->dev); 22577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (ret < 0) { 22677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev_err(fmc->hwdev, "Slot %i: Failed in registering " 22777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini "\"%s\"\n", fmc->slot_id, fmc->dev.kobj.name); 22877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini goto out; 22977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 23077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini ret = sysfs_create_bin_file(&fmc->dev.kobj, &fmc_eeprom_attr); 23177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (ret < 0) { 23277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev_err(&fmc->dev, "Failed in registering eeprom\n"); 23377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini goto out1; 23477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 23577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* This device went well, give information to the user */ 23677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc_dump_eeprom(fmc); 23777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc_dump_sdb(fmc); 23877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 23977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return 0; 24077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 24177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubiniout1: 24277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini device_del(&fmc->dev); 24377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubiniout: 24477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc_free_id_info(fmc); 24577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini put_device(&fmc->dev); 24677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 24777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini kfree(devarray); 24877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (i--; i >= 0; i--) { 24977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); 25077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini device_del(&devs[i]->dev); 25177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc_free_id_info(devs[i]); 25277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini put_device(&devs[i]->dev); 25377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 25477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return ret; 25577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 25677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 25777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_device_register_n); 25877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 25977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubiniint fmc_device_register(struct fmc_device *fmc) 26077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 26177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return fmc_device_register_n(&fmc, 1); 26277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 26377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_device_register); 26477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 26577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinivoid fmc_device_unregister_n(struct fmc_device **devs, int n) 26677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 26777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int i; 26877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 26977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (n < 1) 27077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return; 27177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 27277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* Free devarray first, not used by the later loop */ 27377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini kfree(devs[0]->devarray); 27477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 27577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (i = 0; i < n; i++) { 27677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); 27777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini device_del(&devs[i]->dev); 27877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc_free_id_info(devs[i]); 27977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini put_device(&devs[i]->dev); 28077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 28177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 28277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_device_unregister_n); 28377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 28477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinivoid fmc_device_unregister(struct fmc_device *fmc) 28577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 28677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc_device_unregister_n(&fmc, 1); 28777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 28877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_device_unregister); 28977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 29077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini/* Init and exit are trivial */ 2919c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubinistatic int fmc_init(void) 2929c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini{ 2939c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini return bus_register(&fmc_bus_type); 2949c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini} 2959c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini 2969c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubinistatic void fmc_exit(void) 2979c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini{ 2989c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini bus_unregister(&fmc_bus_type); 2999c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini} 3009c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini 3019c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubinimodule_init(fmc_init); 3029c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubinimodule_exit(fmc_exit); 3039c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro Rubini 3049c9f32eddee56888c7acd0d69134a5dcae09e1a8Alessandro RubiniMODULE_LICENSE("GPL"); 305