X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fi2c%2Fchips%2Feeprom.c;h=cec3a0c3894dda7912024c769e04057d2a47c5ad;hb=refs%2Fheads%2Fvserver;hp=44a17f61eb591e62e3f58e9d08c9982b2089ce00;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index 44a17f61e..cec3a0c38 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -26,31 +26,22 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include #include #include +#include #include -#include +#include /* Addresses to scan */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static unsigned short normal_i2c_range[] = { 0x50, 0x57, I2C_CLIENT_END }; -static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END }; -static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; +static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, I2C_CLIENT_END }; /* Insmod parameters */ -SENSORS_INSMOD_1(eeprom); +I2C_CLIENT_INSMOD_1(eeprom); -static int checksum = 0; -module_param(checksum, bool, 0); -MODULE_PARM_DESC(checksum, "Only accept eeproms whose checksum is correct"); - - -/* EEPROM registers */ -#define EEPROM_REG_CHECKSUM 0x3f /* Size of EEPROM in bytes */ #define EEPROM_SIZE 256 @@ -64,7 +55,7 @@ enum eeprom_nature { /* Each client has this additional data */ struct eeprom_data { struct i2c_client client; - struct semaphore update_lock; + struct mutex update_lock; u8 valid; /* bitfield, bit!=0 if slice is valid */ unsigned long last_updated[8]; /* In jiffies, 8 slices */ u8 data[EEPROM_SIZE]; /* Register values */ @@ -78,31 +69,28 @@ static int eeprom_detach_client(struct i2c_client *client); /* This is the driver that will be inserted */ static struct i2c_driver eeprom_driver = { - .owner = THIS_MODULE, - .name = "eeprom", + .driver = { + .name = "eeprom", + }, .id = I2C_DRIVERID_EEPROM, - .flags = I2C_DF_NOTIFY, .attach_adapter = eeprom_attach_adapter, .detach_client = eeprom_detach_client, }; -static int eeprom_id = 0; - static void eeprom_update_client(struct i2c_client *client, u8 slice) { struct eeprom_data *data = i2c_get_clientdata(client); int i, j; - down(&data->update_lock); + mutex_lock(&data->update_lock); if (!(data->valid & (1 << slice)) || - (jiffies - data->last_updated[slice] > 300 * HZ) || - (jiffies < data->last_updated[slice])) { + time_after(jiffies, data->last_updated[slice] + 300 * HZ)) { dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice); if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - for (i = slice << 5; i < (slice + 1) << 5; i += I2C_SMBUS_I2C_BLOCK_MAX) - if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_I2C_BLOCK_MAX) + for (i = slice << 5; i < (slice + 1) << 5; i += I2C_SMBUS_BLOCK_MAX) + if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_BLOCK_MAX) goto exit; } else { if (i2c_smbus_write_byte(client, slice << 5)) { @@ -120,7 +108,7 @@ static void eeprom_update_client(struct i2c_client *client, u8 slice) data->valid |= (1 << slice); } exit: - up(&data->update_lock); + mutex_unlock(&data->update_lock); } static ssize_t eeprom_read(struct kobject *kobj, char *buf, loff_t off, size_t count) @@ -140,7 +128,8 @@ static ssize_t eeprom_read(struct kobject *kobj, char *buf, loff_t off, size_t c /* Hide Vaio security settings to regular users (16 first bytes) */ if (data->nature == VAIO && off < 16 && !capable(CAP_SYS_ADMIN)) { - int in_row1 = 16 - off; + size_t in_row1 = 16 - off; + in_row1 = min(in_row1, count); memset(buf, 0, in_row1); if (count - in_row1 > 0) memcpy(buf + in_row1, &data->data[16], count - in_row1); @@ -163,37 +152,30 @@ static struct bin_attribute eeprom_attr = { static int eeprom_attach_adapter(struct i2c_adapter *adapter) { - return i2c_detect(adapter, &addr_data, eeprom_detect); + return i2c_probe(adapter, &addr_data, eeprom_detect); } -/* This function is called by i2c_detect */ -int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) +/* This function is called by i2c_probe */ +static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) { - int i, cs; struct i2c_client *new_client; struct eeprom_data *data; int err = 0; - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - dev_dbg(&adapter->dev, " eeprom_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + /* There are three ways we can read the EEPROM data: + (1) I2C block reads (faster, but unsupported by most adapters) + (2) Consecutive byte reads (100% overhead) + (3) Regular byte data reads (200% overhead) + The third method is not implemented by this driver because all + known adapters support at least the second. */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA + | I2C_FUNC_SMBUS_BYTE)) goto exit; - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access eeprom_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { + if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - memset(data, 0, sizeof(struct eeprom_data)); new_client = &data->client; memset(data->data, 0xff, EEPROM_SIZE); @@ -203,46 +185,38 @@ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) new_client->driver = &eeprom_driver; new_client->flags = 0; - /* prevent 24RF08 corruption */ - i2c_smbus_write_quick(new_client, 0); - - /* Now, we do the remaining detection. It is not there, unless you force - the checksum to work out. */ - if (checksum) { - cs = 0; - for (i = 0; i <= 0x3e; i++) - cs += i2c_smbus_read_byte_data(new_client, i); - cs &= 0xff; - if (i2c_smbus_read_byte_data (new_client, EEPROM_REG_CHECKSUM) != cs) - goto exit_kfree; - } - - data->nature = UNKNOWN; - /* Detect the Vaio nature of EEPROMs. - We use the "PCG-" prefix as the signature. */ - if (address == 0x57) { - if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P' && - i2c_smbus_read_byte_data(new_client, 0x81) == 'C' && - i2c_smbus_read_byte_data(new_client, 0x82) == 'G' && - i2c_smbus_read_byte_data(new_client, 0x83) == '-') - data->nature = VAIO; - } - /* Fill in the remaining client fields */ - strncpy(new_client->name, "eeprom", I2C_NAME_SIZE); - new_client->id = eeprom_id++; + strlcpy(new_client->name, "eeprom", I2C_NAME_SIZE); data->valid = 0; - init_MUTEX(&data->update_lock); + mutex_init(&data->update_lock); + data->nature = UNKNOWN; /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) goto exit_kfree; + /* Detect the Vaio nature of EEPROMs. + We use the "PCG-" prefix as the signature. */ + if (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' + && i2c_smbus_read_byte(new_client) == '-') { + dev_info(&new_client->dev, "Vaio EEPROM detected, " + "enabling password protection\n"); + data->nature = VAIO; + } + } + /* create the sysfs eeprom file */ - sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr); + err = sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr); + if (err) + goto exit_detach; return 0; +exit_detach: + i2c_detach_client(new_client); exit_kfree: kfree(data); exit: @@ -253,11 +227,11 @@ static int eeprom_detach_client(struct i2c_client *client) { int err; + sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr); + err = i2c_detach_client(client); - if (err) { - dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); + if (err) return err; - } kfree(i2c_get_clientdata(client));