diff options
author | Guenter Roeck <guenter.roeck@ericsson.com> | 2011-09-30 14:53:25 -0400 |
---|---|---|
committer | Guenter Roeck <guenter.roeck@ericsson.com> | 2012-01-05 11:19:27 -0500 |
commit | 87102808d03948c825c3bdc48316e48f6422fd7e (patch) | |
tree | 77eeb38fcf21b2df9fb820b0c26a0e57054c1761 /drivers | |
parent | 805a6af8dba5dfdd35ec35dc52ec0122400b2610 (diff) |
hwmon: (pmbus/adm1275) Validate device ID
Since manufacturer and device ID are known, read and validate it.
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
[Dan Carpenter <dan.carpenter@oracle.com>: Fixed memory leak]
Reviewed-by: Robert Coulson <robert.coulson@ericsson.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hwmon/pmbus/adm1275.c | 71 |
1 files changed, 50 insertions, 21 deletions
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 980a4d9d5028..81c7c2ead6f3 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c | |||
@@ -170,35 +170,71 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) | |||
170 | return ret; | 170 | return ret; |
171 | } | 171 | } |
172 | 172 | ||
173 | static const struct i2c_device_id adm1275_id[] = { | ||
174 | { "adm1275", adm1275 }, | ||
175 | { "adm1276", adm1276 }, | ||
176 | { } | ||
177 | }; | ||
178 | MODULE_DEVICE_TABLE(i2c, adm1275_id); | ||
179 | |||
173 | static int adm1275_probe(struct i2c_client *client, | 180 | static int adm1275_probe(struct i2c_client *client, |
174 | const struct i2c_device_id *id) | 181 | const struct i2c_device_id *id) |
175 | { | 182 | { |
183 | u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; | ||
176 | int config, device_config; | 184 | int config, device_config; |
177 | int ret; | 185 | int ret; |
178 | struct pmbus_driver_info *info; | 186 | struct pmbus_driver_info *info; |
179 | struct adm1275_data *data; | 187 | struct adm1275_data *data; |
188 | const struct i2c_device_id *mid; | ||
180 | 189 | ||
181 | if (!i2c_check_functionality(client->adapter, | 190 | if (!i2c_check_functionality(client->adapter, |
182 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) | 191 | I2C_FUNC_SMBUS_READ_BYTE_DATA |
192 | | I2C_FUNC_SMBUS_BLOCK_DATA)) | ||
183 | return -ENODEV; | 193 | return -ENODEV; |
184 | 194 | ||
185 | data = kzalloc(sizeof(struct adm1275_data), GFP_KERNEL); | 195 | ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer); |
186 | if (!data) | 196 | if (ret < 0) { |
187 | return -ENOMEM; | 197 | dev_err(&client->dev, "Failed to read Manufacturer ID\n"); |
198 | return ret; | ||
199 | } | ||
200 | if (ret != 3 || strncmp(block_buffer, "ADI", 3)) { | ||
201 | dev_err(&client->dev, "Unsupported Manufacturer ID\n"); | ||
202 | return -ENODEV; | ||
203 | } | ||
188 | 204 | ||
189 | config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); | 205 | ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer); |
190 | if (config < 0) { | 206 | if (ret < 0) { |
191 | ret = config; | 207 | dev_err(&client->dev, "Failed to read Manufacturer Model\n"); |
192 | goto err_mem; | 208 | return ret; |
209 | } | ||
210 | for (mid = adm1275_id; mid->name[0]; mid++) { | ||
211 | if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) | ||
212 | break; | ||
213 | } | ||
214 | if (!mid->name[0]) { | ||
215 | dev_err(&client->dev, "Unsupported device\n"); | ||
216 | return -ENODEV; | ||
193 | } | 217 | } |
194 | 218 | ||
219 | if (id->driver_data != mid->driver_data) | ||
220 | dev_notice(&client->dev, | ||
221 | "Device mismatch: Configured %s, detected %s\n", | ||
222 | id->name, mid->name); | ||
223 | |||
224 | config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); | ||
225 | if (config < 0) | ||
226 | return config; | ||
227 | |||
195 | device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG); | 228 | device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG); |
196 | if (device_config < 0) { | 229 | if (device_config < 0) |
197 | ret = device_config; | 230 | return device_config; |
198 | goto err_mem; | 231 | |
199 | } | 232 | data = kzalloc(sizeof(struct adm1275_data), GFP_KERNEL); |
233 | if (!data) | ||
234 | return -ENOMEM; | ||
235 | |||
236 | data->id = mid->driver_data; | ||
200 | 237 | ||
201 | data->id = id->driver_data; | ||
202 | info = &data->info; | 238 | info = &data->info; |
203 | 239 | ||
204 | info->pages = 1; | 240 | info->pages = 1; |
@@ -233,7 +269,7 @@ static int adm1275_probe(struct i2c_client *client, | |||
233 | if (device_config & ADM1275_IOUT_WARN2_SELECT) | 269 | if (device_config & ADM1275_IOUT_WARN2_SELECT) |
234 | data->have_oc_fault = true; | 270 | data->have_oc_fault = true; |
235 | 271 | ||
236 | switch (id->driver_data) { | 272 | switch (data->id) { |
237 | case adm1275: | 273 | case adm1275: |
238 | if (config & ADM1275_VIN_VOUT_SELECT) | 274 | if (config & ADM1275_VIN_VOUT_SELECT) |
239 | info->func[0] |= | 275 | info->func[0] |= |
@@ -281,13 +317,6 @@ static int adm1275_remove(struct i2c_client *client) | |||
281 | return 0; | 317 | return 0; |
282 | } | 318 | } |
283 | 319 | ||
284 | static const struct i2c_device_id adm1275_id[] = { | ||
285 | { "adm1275", adm1275 }, | ||
286 | { "adm1276", adm1276 }, | ||
287 | { } | ||
288 | }; | ||
289 | MODULE_DEVICE_TABLE(i2c, adm1275_id); | ||
290 | |||
291 | static struct i2c_driver adm1275_driver = { | 320 | static struct i2c_driver adm1275_driver = { |
292 | .driver = { | 321 | .driver = { |
293 | .name = "adm1275", | 322 | .name = "adm1275", |