From patchwork Fri Mar 1 23:12:11 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Frank Schaefer X-Patchwork-Id: 17021 Received: from mail.tu-berlin.de ([130.149.7.33]) by www.linuxtv.org with esmtp (Exim 4.72) (envelope-from ) id 1UBZ7J-0006mO-9q; Sat, 02 Mar 2013 00:11:53 +0100 X-tubIT-Incoming-IP: 209.132.180.67 Received: from vger.kernel.org ([209.132.180.67]) by mail.tu-berlin.de (exim-4.75/mailfrontend-3) with esmtp id 1UBZ7I-0006Xd-E6; Sat, 02 Mar 2013 00:11:53 +0100 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752082Ab3CAXLu (ORCPT + 1 other); Fri, 1 Mar 2013 18:11:50 -0500 Received: from mail-ee0-f53.google.com ([74.125.83.53]:58670 "EHLO mail-ee0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752060Ab3CAXLt (ORCPT ); Fri, 1 Mar 2013 18:11:49 -0500 Received: by mail-ee0-f53.google.com with SMTP id e53so2675630eek.26 for ; Fri, 01 Mar 2013 15:11:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:mime-version:content-type:content-transfer-encoding; bh=DlmojUYgXQw3Hx8o+W/wTzLIEV9mf66jyZQkfB90tDU=; b=DubzGH3DnyRV0KlVjLOe5+qbdwh1cN2ndFV2z6+21MAwitLLDX5ARPCCuwlwrIPctM pmRrt4YDaIbajEaCI7WVdzoebaaq5tkbXlzSVj0qrTY1XgcRrQwje0nDnwJA5H5Z4mO1 fqqG5Pe0nUHpEwAsy1k5OoQOWD5fwXQ807rvULhLsorWbRvPUS7OvoxG/RAsm9FMKL2r fjSPUs2DdVVqiA0E3ozrZ8Olh23XDh115UD69FLjQAzLdlAEWS33+6fGAWa5DFFAaKHe INcwQOI7vmJpkcCNDqJ8e/+maGAwv+9FYDmIVWl4x5SYqKgvhzNVtFjmnkrD6S43NYtz rpYw== X-Received: by 10.14.202.71 with SMTP id c47mr18119355eeo.39.1362179508023; Fri, 01 Mar 2013 15:11:48 -0800 (PST) Received: from Athlon64X2-5000.site (ip-178-201-83-213.unitymediagroup.de. [178.201.83.213]) by mx.google.com with ESMTPS id d47sm19488041eem.9.2013.03.01.15.11.45 (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 01 Mar 2013 15:11:46 -0800 (PST) From: =?UTF-8?q?Frank=20Sch=C3=A4fer?= To: mchehab@redhat.com Cc: linux-media@vger.kernel.org, =?UTF-8?q?Frank=20Sch=C3=A4fer?= Subject: [PATCH 07/11] em28xx: add basic support for eeproms with 16 bit address width Date: Sat, 2 Mar 2013 00:12:11 +0100 Message-Id: <1362179535-18929-8-git-send-email-fschaefer.oss@googlemail.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1362179535-18929-1-git-send-email-fschaefer.oss@googlemail.com> References: <1362179535-18929-1-git-send-email-fschaefer.oss@googlemail.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-PMX-Version: 5.6.1.2065439, Antispam-Engine: 2.7.2.376379, Antispam-Data: 2013.3.1.230018 X-PMX-Spam: Gauge=IIIIIIII, Probability=8%, Report=' MULTIPLE_RCPTS 0.1, HTML_00_01 0.05, HTML_00_10 0.05, BODY_SIZE_6000_6999 0, BODY_SIZE_7000_LESS 0, CT_TEXT_PLAIN_UTF8_CAPS 0, DKIM_SIGNATURE 0, URI_ENDS_IN_HTML 0, __ANY_URI 0, __C230066_P3_4 0, __CP_MEDIA_BODY 0, __CP_URI_IN_BODY 0, __CT 0, __CTE 0, __CT_TEXT_PLAIN 0, __FRAUD_BODY_WEBMAIL 0, __FRAUD_WEBMAIL 0, __FRAUD_WEBMAIL_FROM 0, __HAS_FROM 0, __HAS_MSGID 0, __HAS_X_MAILER 0, __HAS_X_MAILING_LIST 0, __IN_REP_TO 0, __MIME_TEXT_ONLY 0, __MIME_VERSION 0, __MULTIPLE_RCPTS_CC_X2 0, __PHISH_SPEAR_STRUCTURE_1 0, __SANE_MSGID 0, __STOCK_PHRASE_7 0, __SUBJ_ALPHA_END 0, __TO_MALFORMED_2 0, __TO_NO_NAME 0, __URI_NO_WWW 0, __URI_NS , __YOUTUBE_RCVD 0' Newer devices (em2874, em2884, em28174, em25xx, em27[6,7,8]x) use eeproms with 16 bit instead of 8 bit address width. The used eeprom type depends on the chip type, which makes sure eeproms can't be damaged. This patch adds basic support for 16 bit eeproms only, which includes - reading the content - calculating the eeprom hash - displaying the content The eeprom content uses a different format, for which support will be added with subsequent patches. Tested with the "Hauppauge HVR-930C" and the "Speedlink VAD Laplace webcam" (with additional experimental patches). Signed-off-by: Frank Schäfer --- drivers/media/usb/em28xx/em28xx-cards.c | 4 ++ drivers/media/usb/em28xx/em28xx-i2c.c | 69 ++++++++++++++++++++----------- drivers/media/usb/em28xx/em28xx.h | 1 + 3 Dateien geändert, 49 Zeilen hinzugefügt(+), 25 Zeilen entfernt(-) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 0d74734..fa51f81 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2187,6 +2187,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = { {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF}, {0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT}, }; +/* NOTE: introduce a separate hash table for devices with 16 bit eeproms */ /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ static unsigned short saa711x_addrs[] = { @@ -3023,11 +3024,13 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, chip_name = "em2874"; dev->reg_gpio_num = EM2874_R80_GPIO; dev->wait_after_write = 0; + dev->eeprom_addrwidth_16bit = 1; break; case CHIP_ID_EM28174: chip_name = "em28174"; dev->reg_gpio_num = EM2874_R80_GPIO; dev->wait_after_write = 0; + dev->eeprom_addrwidth_16bit = 1; break; case CHIP_ID_EM2883: chip_name = "em2882/3"; @@ -3037,6 +3040,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, chip_name = "em2884"; dev->reg_gpio_num = EM2874_R80_GPIO; dev->wait_after_write = 0; + dev->eeprom_addrwidth_16bit = 1; break; default: printk(KERN_INFO DRIVER_NAME diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index ebe4b20..7185812 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -368,46 +368,34 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) { - unsigned char buf, *p = eedata; + unsigned char buf[2], *p = eedata; struct em28xx_eeprom *em_eeprom = (void *)eedata; int i, err, size = len, block, block_max; - if (dev->chip_id == CHIP_ID_EM2874 || - dev->chip_id == CHIP_ID_EM28174 || - dev->chip_id == CHIP_ID_EM2884) { - /* Empia switched to a 16-bit addressable eeprom in newer - devices. While we could certainly write a routine to read - the eeprom, there is nothing of use in there that cannot be - accessed through registers, and there is the risk that we - could corrupt the eeprom (since a 16-bit read call is - interpreted as a write call by 8-bit eeproms). - */ - return 0; - } - dev->i2c_client.addr = 0xa0 >> 1; /* 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) { em28xx_info("board has no eeprom\n"); memset(eedata, 0, len); return -ENODEV; } - buf = 0; - - err = i2c_master_send(&dev->i2c_client, &buf, 1); - if (err != 1) { + /* Select address memory address 0x00(00) */ + buf[0] = 0; + buf[1] = 0; + err = i2c_master_send(&dev->i2c_client, buf, 1 + dev->eeprom_addrwidth_16bit); + if (err != 1 + dev->eeprom_addrwidth_16bit) { em28xx_errdev("failed to read eeprom (err=%d)\n", err); return err; } + /* Read eeprom content */ if (dev->board.is_em2800) block_max = 4; else block_max = 64; - while (size > 0) { if (size > block_max) block = block_max; @@ -422,17 +410,48 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) size -= block; p += block; } + + /* Display eeprom content */ for (i = 0; i < len; i++) { - if (0 == (i % 16)) - em28xx_info("i2c eeprom %02x:", i); + if (0 == (i % 16)) { + if (dev->eeprom_addrwidth_16bit) + em28xx_info("i2c eeprom %04x:", i); + else + em28xx_info("i2c eeprom %02x:", i); + } printk(" %02x", eedata[i]); if (15 == (i % 16)) printk("\n"); } - if (em_eeprom->id[0] != 0x1a || em_eeprom->id[1] != 0xeb || - em_eeprom->id[2] != 0x67 || em_eeprom->id[3] != 0x95 ) { - em28xx_errdev("Unknown eeprom type or eeprom corrupted !"); + if (dev->eeprom_addrwidth_16bit && + eedata[0] == 0x26 && eedata[3] == 0x00) { + /* new eeprom format; size 4-64kb */ + dev->hash = em28xx_hash_mem(eedata, len, 32); + em28xx_info("EEPROM hash = 0x%08lx\n", dev->hash); + em28xx_info("EEPROM info: boot page address = 0x%02x04, " + "boot configuration = 0x%02x\n", + eedata[1], eedata[2]); + /* boot configuration (address 0x0002): + * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz + * [1] always selects 12 kb RAM + * [2] USB device speed: 1 = force Full Speed; 0 = auto detect + * [4] 1 = force fast mode and no suspend for device testing + * [5:7] USB PHY tuning registers; determined by device + * characterization + */ + + /* FIXME: + * - read more than 256 bytes / addresses above 0x00ff + * - find offset for device config dataset and extract it + * - decrypt eeprom data for camera bridges (em25xx, em276x+) + * - use separate/different eeprom hashes (not yet used) + */ + + return 0; + } else if (em_eeprom->id[0] != 0x1a || em_eeprom->id[1] != 0xeb || + em_eeprom->id[2] != 0x67 || em_eeprom->id[3] != 0x95 ) { + em28xx_info("unknown eeprom format or eeprom corrupted !\n"); return -ENODEV; } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 90266a1..139dfe5 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -510,6 +510,7 @@ struct em28xx { /* i2c i/o */ struct i2c_adapter i2c_adap; struct i2c_client i2c_client; + unsigned char eeprom_addrwidth_16bit:1; /* video for linux */ int users; /* user count for exclusive use */ int streaming_users; /* Number of actively streaming users */