Add EEPROM notifiers These help board level code by allowing a callback when EEPROMs are loaded, this permits system level configuration to be loaded from the EEPROM. This is particularly useful when the ethernet MAC ids are stored in EEPROM and when the ethernet hardware is generic (so it has no board level knowledge), then the MACs can be loaded into the 'maclist' code and read out by the ethernet config. Signed-off-by: John Bowler --- linux-2.6.15/drivers/i2c/chips/eeprom.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.15/drivers/i2c/chips/eeprom.c 1970-01-01 00:00:00.000000000 +0000 @@ -25,7 +25,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - #include #include #include @@ -33,6 +32,9 @@ #include #include #include +#include + +#include /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54, @@ -41,6 +43,9 @@ static unsigned short normal_i2c[] = { 0 /* Insmod parameters */ I2C_CLIENT_INSMOD_1(eeprom); +/* Notifier list */ +static DECLARE_MUTEX(eeprom_notifier_mutex); +static LIST_HEAD(eeprom_notifiers); /* Size of EEPROM in bytes */ #define EEPROM_SIZE 256 @@ -160,6 +165,7 @@ static int eeprom_detect(struct i2c_adap struct i2c_client *new_client; struct eeprom_data *data; int err = 0; + struct list_head *this; /* There are three ways we can read the EEPROM data: (1) I2C block reads (faster, but unsupported by most adapters) @@ -196,7 +202,7 @@ static int eeprom_detect(struct i2c_adap /* Detect the Vaio nature of EEPROMs. We use the "PCG-" prefix as the signature. */ - if (address == 0x57) { + if (list_empty(&eeprom_notifiers) && address == 0x57) { if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P' && i2c_smbus_read_byte(new_client) == 'C' && i2c_smbus_read_byte(new_client) == 'G' @@ -210,6 +216,14 @@ static int eeprom_detect(struct i2c_adap /* create the sysfs eeprom file */ sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr); + /* Call each notifier callback */ + down(&eeprom_notifier_mutex); + list_for_each(this, &eeprom_notifiers) { + struct eeprom_notifier *not = list_entry(this, struct eeprom_notifier, list); + not->add(address, kind, &new_client->dev.kobj, &eeprom_attr); + } + up(&eeprom_notifier_mutex); + return 0; exit_kfree: @@ -231,6 +245,51 @@ static int eeprom_detach_client(struct i return 0; } +/** + * register_eeprom_user - register a 'user' of EEPROM devices. + * @new: pointer to notifier info structure + * + * Registers a callback function to be called upon detection + * of an EEPROM device. Detection invokes the 'add' callback + * with the kobj of the mutex and a bin_attribute which allows + * read from the EEPROM. The intention is that the notifier + * will be able to read system configuration from the notifier. + * + * Only EEPROMs detected *after* the addition of the notifier + * are notified. I.e. EEPROMs already known to the system + * will not be notified - add the notifier from board level + * code! + */ +void register_eeprom_user (struct eeprom_notifier *new) +{ + down(&eeprom_notifier_mutex); + + list_add(&new->list, &eeprom_notifiers); + + up(&eeprom_notifier_mutex); +} + +/** + * unregister_eeprom_user - unregister a 'user' of EEPROM devices. + * @old: pointer to notifier info structure + * + * Removes a callback function from the list of 'users' to be + * notified upon detection of EEPROM devices. + */ +void unregister_eeprom_user (struct eeprom_notifier *old) +{ + down(&eeprom_notifier_mutex); + + list_del(&old->list); + + up(&eeprom_notifier_mutex); +} + + +EXPORT_SYMBOL(register_eeprom_user); +EXPORT_SYMBOL(unregister_eeprom_user); + + static int __init eeprom_init(void) { return i2c_add_driver(&eeprom_driver); --- linux-2.6.15/include/linux/eeprom.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.15/include/linux/eeprom.h 1970-01-01 00:00:00.000000000 +0000 @@ -0,0 +1,56 @@ +#ifndef _LINUX_EEPROM_H +#define _LINUX_EEPROM_H +/* + * $Id: 45-eeprom-notifier.patch,v 1.1 2006/01/16 05:21:31 jbowler Exp $ + * + * Copyright (C) 2006 John Bowler + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __KERNEL__ +#error This is a kernel header +#endif + +#include +#include +#include + +/* + * This is very basic. + * + * If an EEPROM is detected on the I2C bus (this only works for + * I2C EEPROMs) the eeprom_notifier::add method is called with + * both the I2C information and the kobject for the sysfs + * device which has been registers. It is then possible to + * read from the device via the bin_attribute::read method + * to extract configuration information. + * + * Register the notifier in the board level code, there is no + * need to unregister it but you can if you want (it will save + * a little bit or kernel memory to do so). + */ +struct eeprom_notifier { + void (*add)(int address, int kind, struct kobject *kobj, + struct bin_attribute *eeprom_attr); + struct list_head list; +}; + +extern void register_eeprom_user (struct eeprom_notifier *new); +extern void unregister_eeprom_user (struct eeprom_notifier *old); + +#endif /* _LINUX_EEPROM_H */