Commit a217968f authored by Frank Schaefer's avatar Frank Schaefer Committed by Mauro Carvalho Chehab

[media] em28xx: do not store eeprom content permanently

We currently reserve an array of 256 bytes for the eeprom content in the device
struct. For eeproms with 16 bit address width it might even be necessary to
increase the buffer size further.
Having such a big chunk of memory reserved even if the device has no eeprom and
keeping it after it has already been processed seems to be a waste of memory.
Change the code to allocate + free the eeprom memory dynamically.
This also makes it possible to handle different dataset sizes depending on what
is stored/found in the eeprom.
Signed-off-by: default avatarFrank Schäfer <fschaefer.oss@googlemail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent d832c5b2
...@@ -2739,6 +2739,9 @@ static void em28xx_card_setup(struct em28xx *dev) ...@@ -2739,6 +2739,9 @@ static void em28xx_card_setup(struct em28xx *dev)
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
{ {
struct tveeprom tv; struct tveeprom tv;
if (dev->eedata == NULL)
break;
#if defined(CONFIG_MODULES) && defined(MODULE) #if defined(CONFIG_MODULES) && defined(MODULE)
request_module("tveeprom"); request_module("tveeprom");
#endif #endif
...@@ -2792,7 +2795,7 @@ static void em28xx_card_setup(struct em28xx *dev) ...@@ -2792,7 +2795,7 @@ static void em28xx_card_setup(struct em28xx *dev)
em28xx_set_mode(dev, EM28XX_ANALOG_MODE); em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
break; break;
/* /*
* The Dikom DK300 is detected as an Kworld VS-DVB-T 323UR. * The Dikom DK300 is detected as an Kworld VS-DVB-T 323UR.
* *
* This occurs because they share identical USB vendor and * This occurs because they share identical USB vendor and
...@@ -2827,6 +2830,10 @@ static void em28xx_card_setup(struct em28xx *dev) ...@@ -2827,6 +2830,10 @@ static void em28xx_card_setup(struct em28xx *dev)
"addresses)\n\n"); "addresses)\n\n");
} }
/* Free eeprom data memory */
kfree(dev->eedata);
dev->eedata = NULL;
/* Allow override tuner type by a module parameter */ /* Allow override tuner type by a module parameter */
if (tuner >= 0) if (tuner >= 0)
dev->tuner_type = tuner; dev->tuner_type = tuner;
......
...@@ -409,27 +409,33 @@ static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16, ...@@ -409,27 +409,33 @@ static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16,
return len; return len;
} }
static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char **eedata, int len)
{ {
unsigned char buf, *p = eedata; u8 buf, *data;
struct em28xx_eeprom *em_eeprom = (void *)eedata; struct em28xx_eeprom *em_eeprom;
int i, err; int i, err;
*eedata = NULL;
dev->i2c_client.addr = 0xa0 >> 1; dev->i2c_client.addr = 0xa0 >> 1;
/* Check if board has eeprom */ /* Check if board has eeprom */
err = i2c_master_recv(&dev->i2c_client, &buf, 0); err = i2c_master_recv(&dev->i2c_client, &buf, 0);
if (err < 0) { if (err < 0) {
em28xx_info("board has no eeprom\n"); em28xx_info("board has no eeprom\n");
memset(eedata, 0, len);
return -ENODEV; return -ENODEV;
} }
data = kzalloc(len, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
/* Read EEPROM content */ /* Read EEPROM content */
err = em28xx_i2c_read_block(dev, 0x0000, dev->eeprom_addrwidth_16bit, err = em28xx_i2c_read_block(dev, 0x0000, dev->eeprom_addrwidth_16bit,
len, p); len, data);
if (err != len) { if (err != len) {
em28xx_errdev("failed to read eeprom (err=%d)\n", err); em28xx_errdev("failed to read eeprom (err=%d)\n", err);
kfree(data);
return err; return err;
} }
...@@ -441,19 +447,19 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) ...@@ -441,19 +447,19 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
else else
em28xx_info("i2c eeprom %02x:", i); em28xx_info("i2c eeprom %02x:", i);
} }
printk(" %02x", eedata[i]); printk(" %02x", data[i]);
if (15 == (i % 16)) if (15 == (i % 16))
printk("\n"); printk("\n");
} }
if (dev->eeprom_addrwidth_16bit && if (dev->eeprom_addrwidth_16bit &&
eedata[0] == 0x26 && eedata[3] == 0x00) { data[0] == 0x26 && data[3] == 0x00) {
/* new eeprom format; size 4-64kb */ /* new eeprom format; size 4-64kb */
dev->hash = em28xx_hash_mem(eedata, len, 32); dev->hash = em28xx_hash_mem(data, len, 32);
em28xx_info("EEPROM hash = 0x%08lx\n", dev->hash); em28xx_info("EEPROM hash = 0x%08lx\n", dev->hash);
em28xx_info("EEPROM info: boot page address = 0x%02x04, " em28xx_info("EEPROM info: boot page address = 0x%02x04, "
"boot configuration = 0x%02x\n", "boot configuration = 0x%02x\n",
eedata[1], eedata[2]); data[1], data[2]);
/* boot configuration (address 0x0002): /* boot configuration (address 0x0002):
* [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz
* [1] always selects 12 kb RAM * [1] always selects 12 kb RAM
...@@ -471,13 +477,16 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) ...@@ -471,13 +477,16 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
*/ */
return 0; return 0;
} else if (em_eeprom->id[0] != 0x1a || em_eeprom->id[1] != 0xeb || } else if (data[0] != 0x1a || data[1] != 0xeb ||
em_eeprom->id[2] != 0x67 || em_eeprom->id[3] != 0x95) { data[2] != 0x67 || data[3] != 0x95) {
em28xx_info("unknown eeprom format or eeprom corrupted !\n"); em28xx_info("unknown eeprom format or eeprom corrupted !\n");
return -ENODEV; return -ENODEV;
} }
dev->hash = em28xx_hash_mem(eedata, len, 32); *eedata = data;
em_eeprom = (void *)eedata;
dev->hash = em28xx_hash_mem(data, len, 32);
em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
em_eeprom->id[0], em_eeprom->id[1], em_eeprom->id[0], em_eeprom->id[1],
...@@ -635,7 +644,7 @@ int em28xx_i2c_register(struct em28xx *dev) ...@@ -635,7 +644,7 @@ int em28xx_i2c_register(struct em28xx *dev)
dev->i2c_client = em28xx_client_template; dev->i2c_client = em28xx_client_template;
dev->i2c_client.adapter = &dev->i2c_adap; dev->i2c_client.adapter = &dev->i2c_adap;
retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); retval = em28xx_i2c_eeprom(dev, &dev->eedata, 256);
if ((retval < 0) && (retval != -ENODEV)) { if ((retval < 0) && (retval != -ENODEV)) {
em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
__func__, retval); __func__, retval);
......
...@@ -562,7 +562,7 @@ struct em28xx { ...@@ -562,7 +562,7 @@ struct em28xx {
/* resources in use */ /* resources in use */
unsigned int resources; unsigned int resources;
unsigned char eedata[256]; u8 *eedata; /* currently always 256 bytes */
/* Isoc control struct */ /* Isoc control struct */
struct em28xx_dmaqueue vidq; struct em28xx_dmaqueue vidq;
......
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