📄 tveeprom.c
字号:
case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */ case 58: /* PNPEnv_TUNER_FM1236_MK3 */ case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */ case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */ case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */ case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */ case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */ case 105: return 1; } return 0;}void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, unsigned char *eeprom_data){ /* ---------------------------------------------- ** The hauppauge eeprom format is tagged ** ** if packet[0] == 0x84, then packet[0..1] == length ** else length = packet[0] & 3f; ** if packet[0] & f8 == f8, then EOD and packet[1] == checksum ** ** In our (ivtv) case we're interested in the following: ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into ** hauppauge_tuner_fmt) ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) ** audio proc: tag [02].01 or [05].00 (mask with 0x7f) ** decoder proc: tag [09].01) ** Fun info: ** model: tag [00].07-08 or [06].00-01 ** revision: tag [00].09-0b or [06].04-06 ** serial#: tag [01].05-07 or [04].04-06 ** # of inputs/outputs ??? */ int i, j, len, done, beenhere, tag, start; int tuner1 = 0, t_format1 = 0, audioic = -1; char *t_name1 = NULL; const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" }; int tuner2 = 0, t_format2 = 0; char *t_name2 = NULL; const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" }; memset(tvee, 0, sizeof(*tvee)); done = len = beenhere = 0; /* Different eeprom start offsets for em28xx, cx2388x and cx23418 */ if (eeprom_data[0] == 0x1a && eeprom_data[1] == 0xeb && eeprom_data[2] == 0x67 && eeprom_data[3] == 0x95) start = 0xa0; /* Generic em28xx offset */ else if ((eeprom_data[0] & 0xe1) == 0x01 && eeprom_data[1] == 0x00 && eeprom_data[2] == 0x00 && eeprom_data[8] == 0x84) start = 8; /* Generic cx2388x offset */ else if (eeprom_data[1] == 0x70 && eeprom_data[2] == 0x00 && eeprom_data[4] == 0x74 && eeprom_data[8] == 0x84) start = 8; /* Generic cx23418 offset (models 74xxx) */ else start = 0; for (i = start; !done && i < 256; i += len) { if (eeprom_data[i] == 0x84) { len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8); i += 3; } else if ((eeprom_data[i] & 0xf0) == 0x70) { if (eeprom_data[i] & 0x08) { /* verify checksum! */ done = 1; break; } len = eeprom_data[i] & 0x07; ++i; } else { tveeprom_warn("Encountered bad packet header [%02x]. " "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]); return; } if (debug) { tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1); for (j = 1; j < len; j++) printk(KERN_CONT " %02x", eeprom_data[i + j]); printk(KERN_CONT "\n"); } /* process by tag */ tag = eeprom_data[i]; switch (tag) { case 0x00: /* tag: 'Comprehensive' */ tuner1 = eeprom_data[i+6]; t_format1 = eeprom_data[i+5]; tvee->has_radio = eeprom_data[i+len-1]; /* old style tag, don't know how to detect IR presence, mark as unknown. */ tvee->has_ir = 0; tvee->model = eeprom_data[i+8] + (eeprom_data[i+9] << 8); tvee->revision = eeprom_data[i+10] + (eeprom_data[i+11] << 8) + (eeprom_data[i+12] << 16); break; case 0x01: /* tag: 'SerialID' */ tvee->serial_number = eeprom_data[i+6] + (eeprom_data[i+7] << 8) + (eeprom_data[i+8] << 16); break; case 0x02: /* tag 'AudioInfo' Note mask with 0x7F, high bit used on some older models to indicate 4052 mux was removed in favor of using MSP inputs directly. */ audioic = eeprom_data[i+2] & 0x7f; if (audioic < ARRAY_SIZE(audioIC)) tvee->audio_processor = audioIC[audioic].id; else tvee->audio_processor = V4L2_IDENT_UNKNOWN; break; /* case 0x03: tag 'EEInfo' */ case 0x04: /* tag 'SerialID2' */ tvee->serial_number = eeprom_data[i+5] + (eeprom_data[i+6] << 8) + (eeprom_data[i+7] << 16); if ((eeprom_data[i + 8] & 0xf0) && (tvee->serial_number < 0xffffff)) { tvee->MAC_address[0] = 0x00; tvee->MAC_address[1] = 0x0D; tvee->MAC_address[2] = 0xFE; tvee->MAC_address[3] = eeprom_data[i + 7]; tvee->MAC_address[4] = eeprom_data[i + 6]; tvee->MAC_address[5] = eeprom_data[i + 5]; tvee->has_MAC_address = 1; } break; case 0x05: /* tag 'Audio2' Note mask with 0x7F, high bit used on some older models to indicate 4052 mux was removed in favor of using MSP inputs directly. */ audioic = eeprom_data[i+1] & 0x7f; if (audioic < ARRAY_SIZE(audioIC)) tvee->audio_processor = audioIC[audioic].id; else tvee->audio_processor = V4L2_IDENT_UNKNOWN; break; case 0x06: /* tag 'ModelRev' */ tvee->model = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8) + (eeprom_data[i + 3] << 16) + (eeprom_data[i + 4] << 24); tvee->revision = eeprom_data[i + 5] + (eeprom_data[i + 6] << 8) + (eeprom_data[i + 7] << 16); break; case 0x07: /* tag 'Details': according to Hauppauge not interesting on any PCI-era or later boards. */ break; /* there is no tag 0x08 defined */ case 0x09: /* tag 'Video' */ tvee->decoder_processor = eeprom_data[i + 1]; break; case 0x0a: /* tag 'Tuner' */ if (beenhere == 0) { tuner1 = eeprom_data[i + 2]; t_format1 = eeprom_data[i + 1]; beenhere = 1; } else { /* a second (radio) tuner may be present */ tuner2 = eeprom_data[i + 2]; t_format2 = eeprom_data[i + 1]; /* not a TV tuner? */ if (t_format2 == 0) tvee->has_radio = 1; /* must be radio */ } break; case 0x0b: /* tag 'Inputs': according to Hauppauge this is specific to each driver family, so no good assumptions can be made. */ break; /* case 0x0c: tag 'Balun' */ /* case 0x0d: tag 'Teletext' */ case 0x0e: /* tag: 'Radio' */ tvee->has_radio = eeprom_data[i+1]; break; case 0x0f: /* tag 'IRInfo' */ tvee->has_ir = 1 | (eeprom_data[i+1] << 1); break; /* case 0x10: tag 'VBIInfo' */ /* case 0x11: tag 'QCInfo' */ /* case 0x12: tag 'InfoBits' */ default: tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag); /* dump the rest of the packet? */ } } if (!done) { tveeprom_warn("Ran out of data!\n"); return; } if (tvee->revision != 0) { tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f); tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f); tvee->rev_str[2] = 32 + ((tvee->revision >> 6) & 0x3f); tvee->rev_str[3] = 32 + (tvee->revision & 0x3f); tvee->rev_str[4] = 0; } if (hasRadioTuner(tuner1) && !tvee->has_radio) { tveeprom_info("The eeprom says no radio is present, but the tuner type\n"); tveeprom_info("indicates otherwise. I will assume that radio is present.\n"); tvee->has_radio = 1; } if (tuner1 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { tvee->tuner_type = hauppauge_tuner[tuner1].id; t_name1 = hauppauge_tuner[tuner1].name; } else { t_name1 = "unknown"; } if (tuner2 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { tvee->tuner2_type = hauppauge_tuner[tuner2].id; t_name2 = hauppauge_tuner[tuner2].name; } else { t_name2 = "unknown"; } tvee->tuner_hauppauge_model = tuner1; tvee->tuner2_hauppauge_model = tuner2; tvee->tuner_formats = 0; tvee->tuner2_formats = 0; for (i = j = 0; i < 8; i++) { if (t_format1 & (1 << i)) { tvee->tuner_formats |= hauppauge_tuner_fmt[i].id; t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name; } } for (i = j = 0; i < 8; i++) { if (t_format2 & (1 << i)) { tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id; t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name; } } tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n", tvee->model, tvee->rev_str, tvee->serial_number); if (tvee->has_MAC_address == 1) tveeprom_info("MAC address is %02X-%02X-%02X-%02X-%02X-%02X\n", tvee->MAC_address[0], tvee->MAC_address[1], tvee->MAC_address[2], tvee->MAC_address[3], tvee->MAC_address[4], tvee->MAC_address[5]); tveeprom_info("tuner model is %s (idx %d, type %d)\n", t_name1, tuner1, tvee->tuner_type); tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3], t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7], t_format1); if (tuner2) tveeprom_info("second tuner model is %s (idx %d, type %d)\n", t_name2, tuner2, tvee->tuner2_type); if (t_format2) tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3], t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7], t_format2); if (audioic < 0) { tveeprom_info("audio processor is unknown (no idx)\n"); tvee->audio_processor = V4L2_IDENT_UNKNOWN; } else { if (audioic < ARRAY_SIZE(audioIC)) tveeprom_info("audio processor is %s (idx %d)\n", audioIC[audioic].name, audioic); else tveeprom_info("audio processor is unknown (idx %d)\n", audioic); } if (tvee->decoder_processor) tveeprom_info("decoder processor is %s (idx %d)\n", STRM(decoderIC, tvee->decoder_processor), tvee->decoder_processor); if (tvee->has_ir) tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n", tvee->has_radio ? "" : "no ", (tvee->has_ir & 2) ? "" : "no ", (tvee->has_ir & 4) ? "" : "no "); else tveeprom_info("has %sradio\n", tvee->has_radio ? "" : "no ");}EXPORT_SYMBOL(tveeprom_hauppauge_analog);/* ----------------------------------------------------------------------- *//* generic helper functions */int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len){ unsigned char buf; int err; buf = 0; err = i2c_master_send(c, &buf, 1); if (err != 1) { tveeprom_info("Huh, no eeprom present (err=%d)?\n", err); return -1; } err = i2c_master_recv(c, eedata, len); if (err != len) { tveeprom_warn("i2c eeprom read error (err=%d)\n", err); return -1; } if (debug) { int i; tveeprom_info("full 256-byte eeprom dump:\n"); for (i = 0; i < len; i++) { if (0 == (i % 16)) tveeprom_info("%02x:", i); printk(KERN_CONT " %02x", eedata[i]); if (15 == (i % 16)) printk(KERN_CONT "\n"); } } return 0;}EXPORT_SYMBOL(tveeprom_read);/* * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -