Exemple #1
0
int envy_bios_parse_mux (struct envy_bios *bios) {
	struct envy_bios_mux *mux = &bios->mux;
	if (!mux->offset)
		return 0;
	int err = 0;
	err |= bios_u8(bios, mux->offset, &mux->version);
	err |= bios_u8(bios, mux->offset+1, &mux->hlen);
	err |= bios_u8(bios, mux->offset+2, &mux->entriesnum);
	err |= bios_u8(bios, mux->offset+3, &mux->rlen);
	if (err)
		return -EFAULT;
	envy_bios_block(bios, mux->offset, mux->hlen + mux->rlen * mux->entriesnum, "MUX", -1);
	int wanthlen = 0;
	int wantrlen = 0;
	switch (mux->version) {
		case 0x10:
			wanthlen = 4;
			wantrlen = 5;
			break;
		default:
			ENVY_BIOS_ERR("Unknown MUX table version %x.%x\n", mux->version >> 4, mux->version & 0xf);
			return -EINVAL;
	}
	if (mux->hlen < wanthlen) {
		ENVY_BIOS_ERR("MUX table header too short [%d < %d]\n", mux->hlen, wanthlen);
		return -EINVAL;
	}
	if (mux->rlen < wantrlen) {
		ENVY_BIOS_ERR("MUX table record too short [%d < %d]\n", mux->rlen, wantrlen);
		return -EINVAL;
	}
	if (mux->hlen > wanthlen) {
		ENVY_BIOS_WARN("MUX table header longer than expected [%d > %d]\n", mux->hlen, wanthlen);
	}
	if (mux->rlen > wantrlen) {
		ENVY_BIOS_WARN("MUX table record longer than expected [%d > %d]\n", mux->rlen, wantrlen);
	}
	mux->entries = calloc(mux->entriesnum, sizeof *mux->entries);
	if (!mux->entries)
		return -ENOMEM;
	int i;
	for (i = 0; i < mux->entriesnum; i++) {
		struct envy_bios_mux_entry *entry = &mux->entries[i];
		entry->offset = mux->offset + mux->hlen + mux->rlen * i;
		uint8_t sub[4];
		err |= bios_u8(bios, entry->offset, &entry->idx);
		int j;
		for (j = 0; j < 4; j++) {
			err |= bios_u8(bios, entry->offset+j+1, &sub[j]);
			entry->sub_loc[j] = sub[j] & 1;
			entry->sub_line[j] = sub[j] >> 1 & 0x1f;
			entry->sub_val[j] = sub[j] >> 6 & 1;
			entry->sub_unk7[j] = sub[j] >> 7 & 1;
		}
		if (err)
			return -EFAULT;
	}
	mux->valid = 1;
	return 0;
}
Exemple #2
0
int envy_bios_parse_iunk21 (struct envy_bios *bios) {
	struct envy_bios_iunk21 *iunk21 = &bios->iunk21;
	if (!iunk21->offset)
		return 0;
	int err = 0;
	err |= bios_u8(bios, iunk21->offset, &iunk21->version);
	err |= bios_u8(bios, iunk21->offset+1, &iunk21->hlen);
	err |= bios_u8(bios, iunk21->offset+2, &iunk21->rlen);
	err |= bios_u8(bios, iunk21->offset+3, &iunk21->entriesnum);
	if (err)
		return -EFAULT;
	envy_bios_block(bios, iunk21->offset, iunk21->hlen + iunk21->rlen * iunk21->entriesnum, "IUNK21", -1);
	int wanthlen = 0;
	int wantrlen = 0;
	switch (iunk21->version) {
		case 0x10:
			wanthlen = 4;
			wantrlen = 3;
			break;
		default:
			ENVY_BIOS_ERR("Unknown IUNK21 table version %d.%d\n", iunk21->version >> 4, iunk21->version & 0xf);
			return -EINVAL;
	}
	if (iunk21->hlen < wanthlen) {
		ENVY_BIOS_ERR("IUNK21 table header too short [%d < %d]\n", iunk21->hlen, wanthlen);
		return -EINVAL;
	}
	if (iunk21->rlen < wantrlen) {
		ENVY_BIOS_ERR("IUNK21 table record too short [%d < %d]\n", iunk21->rlen, wantrlen);
		return -EINVAL;
	}
	if (iunk21->hlen > wanthlen) {
		ENVY_BIOS_WARN("IUNK21 table header longer than expected [%d > %d]\n", iunk21->hlen, wanthlen);
	}
	if (iunk21->rlen > wantrlen) {
		ENVY_BIOS_WARN("IUNK21 table record longer than expected [%d > %d]\n", iunk21->rlen, wantrlen);
	}
	iunk21->entries = calloc(iunk21->entriesnum, sizeof *iunk21->entries);
	if (!iunk21->entries)
		return -ENOMEM;
	int i;
	for (i = 0; i < iunk21->entriesnum; i++) {
		struct envy_bios_iunk21_entry *entry = &iunk21->entries[i];
		entry->offset = iunk21->offset + iunk21->hlen + iunk21->rlen * i;
		/* XXX */
		if (err)
			return -EFAULT;
	}
	iunk21->valid = 1;
	return 0;
}
Exemple #3
0
int envy_bios_parse_bit_2 (struct envy_bios *bios, struct envy_bios_bit_entry *bit) {
	struct envy_bios_i2cscript *i2cscript = &bios->i2cscript;
	i2cscript->bit = bit;
	int wantlen = 4;
	if (bit->t_len < wantlen) {
		ENVY_BIOS_ERR("I2C script table too short: %d < %d\n", bit->t_len, wantlen);
		return -EINVAL;
	}
	if (bit->t_len > wantlen)
		ENVY_BIOS_WARN("I2C script table longer than expected: %d > %d\n", bit->t_len, wantlen);
	int err = 0;
	err |= bios_u16(bios, bit->t_offset+0, &i2cscript->unk00);
	err |= bios_u16(bios, bit->t_offset+2, &i2cscript->script);
	if (err)
		return -EFAULT;
	i2cscript->valid = 1;
	return 0;
}
Exemple #4
0
int envy_bios_parse_bit (struct envy_bios *bios) {
	struct envy_bios_bit *bit = &bios->bit;
	if (!bit->offset)
		return 0;
	int err = 0;
	err |= bios_u8(bios, bit->offset+7, &bit->version);
	err |= bios_u8(bios, bit->offset+8, &bit->hlen);
	err |= bios_u8(bios, bit->offset+9, &bit->rlen);
	err |= bios_u8(bios, bit->offset+10, &bit->entriesnum);
	if (err)
		return -EFAULT;
	envy_bios_block(bios, bit->offset, bit->hlen + bit->rlen * bit->entriesnum, "BIT", -1);
	uint8_t checksum = 0;
	int i;
	for (i = 0; i < bit->hlen; i++) {
		uint8_t byte;
		err |= bios_u8(bios, bit->offset+i, &byte);
		if (err)
			return -EFAULT;
		checksum += byte;
	}
	if (checksum) {
		ENVY_BIOS_ERR("BIT table checksum mismatch\n");
		return -EINVAL;
	}
	int wanthlen = 12;
	int wantrlen = 6;
	switch (bit->version) {
		case 1:
			break;
		default:
			ENVY_BIOS_ERR("Unknown BIT table version %d\n", bit->version);
			return -EINVAL;
	}
	if (bit->hlen < wanthlen) {
		ENVY_BIOS_ERR("BIT table header too short [%d < %d]\n", bit->hlen, wanthlen);
		return -EINVAL;
	}
	if (bit->rlen < wantrlen) {
		ENVY_BIOS_ERR("BIT table record too short [%d < %d]\n", bit->rlen, wantrlen);
		return -EINVAL;
	}
	if (bit->hlen > wanthlen) {
		ENVY_BIOS_WARN("BIT table header longer than expected [%d > %d]\n", bit->hlen, wanthlen);
	}
	if (bit->rlen > wantrlen) {
		ENVY_BIOS_WARN("BIT table record longer than expected [%d > %d]\n", bit->rlen, wantrlen);
	}
	bit->entries = calloc(bit->entriesnum, sizeof *bit->entries);
	if (!bit->entries)
		return -ENOMEM;
	for (i = 0; i < bit->entriesnum; i++) {
		struct envy_bios_bit_entry *entry = &bit->entries[i];
		entry->offset = bit->offset + bit->hlen + bit->rlen * i;
		err |= bios_u8(bios, entry->offset+0, &entry->type);
		err |= bios_u8(bios, entry->offset+1, &entry->version);
		err |= bios_u16(bios, entry->offset+2, &entry->t_len);
		err |= bios_u16(bios, entry->offset+4, &entry->t_offset);
		if (err)
			return -EFAULT;
		entry->is_unk = 1;
		if (entry->type != 'b' && entry->t_len)
			envy_bios_block(bios, entry->t_offset, entry->t_len, "BIT", entry->type);
	}
	int j;
	/* iterate over BIT tables by type first - some types of tables have to be parsed before others, notably 'i'. */
	for (j = 0; bit_types[j].parse; j++) {
		for (i = 0; i < bit->entriesnum; i++) {
			struct envy_bios_bit_entry *entry = &bit->entries[i];
			if (entry->type == bit_types[j].type && entry->version == bit_types[j].version) {
				if (bit_types[j].parse(bios, entry))
					ENVY_BIOS_ERR("Failed to parse BIT table '%c' at 0x%04x version %d\n", entry->type, entry->t_offset, entry->version);
				else
					entry->is_unk = 0;
			}
		}
	}
	bit->valid = 1;
	return 0;
}
Exemple #5
0
int envy_bios_parse_conn (struct envy_bios *bios) {
	struct envy_bios_conn *conn = &bios->conn;
	if (!conn->offset)
		return 0;
	int err = 0;
	err |= bios_u8(bios, conn->offset, &conn->version);
	err |= bios_u8(bios, conn->offset+1, &conn->hlen);
	err |= bios_u8(bios, conn->offset+2, &conn->entriesnum);
	err |= bios_u8(bios, conn->offset+3, &conn->rlen);
	if (err)
		return -EFAULT;
	envy_bios_block(bios, conn->offset, conn->hlen + conn->rlen * conn->entriesnum, "CONN", -1);
	int wanthlen = 5;
	int wantrlen = 4;
	if (conn->rlen < 4)
		wantrlen = 2;
	switch (conn->version) {
		case 0x30:
		case 0x40:
			break;
		default:
			ENVY_BIOS_ERR("Unknown CONN table version %d.%d\n", conn->version >> 4, conn->version & 0xf);
			return -EINVAL;
	}
	if (conn->hlen < wanthlen) {
		ENVY_BIOS_ERR("CONN table header too short [%d < %d]\n", conn->hlen, wanthlen);
		return -EINVAL;
	}
	if (conn->rlen < wantrlen) {
		ENVY_BIOS_ERR("CONN table record too short [%d < %d]\n", conn->rlen, wantrlen);
		return -EINVAL;
	}
	if (conn->hlen > wanthlen) {
		ENVY_BIOS_WARN("CONN table header longer than expected [%d > %d]\n", conn->hlen, wanthlen);
	}
	if (conn->rlen > wantrlen) {
		ENVY_BIOS_WARN("CONN table record longer than expected [%d > %d]\n", conn->rlen, wantrlen);
	}
	conn->entries = calloc(conn->entriesnum, sizeof *conn->entries);
	if (!conn->entries)
		return -ENOMEM;
	int i;
	for (i = 0; i < conn->entriesnum; i++) {
		struct envy_bios_conn_entry *entry = &conn->entries[i];
		entry->offset = conn->offset + conn->hlen + conn->rlen * i;
		uint8_t bytes[4] = { 0 };
		uint32_t val = 0;
		int j;
		static const int hpds[7] = { 12, 13, 16, 17, 24, 25, 26 };
		entry->hpd = -1;
		entry->dp_ext = -1;
		for (j = 0; j < 4 && j < conn->rlen; j++) {
			err |= bios_u8(bios, entry->offset+j, &bytes[j]);
			if (err)
				return -EFAULT;
			val |= bytes[j] << j * 8;
		}
		entry->type = bytes[0];
		entry->tag = bytes[1] & 0xf;
		for (j = 0; j < 7; j++) {
			if (val & 1 << hpds[j]) {
				if (entry->hpd == -1)
					entry->hpd = j;
				else
					ENVY_BIOS_ERR("CONN %d: duplicate HPD bits\n", i);
			}
		}
		for (j = 0; j < 2; j++) {
			if (val & 1 << (j+14)) {
				if (entry->dp_ext == -1)
					entry->dp_ext = j;
				else
					ENVY_BIOS_ERR("CONN %d: duplicate DP_AUX bits\n", i);
			}
		}
		entry->unk02_2 = bytes[2] >> 2 & 3;
		entry->unk02_4 = bytes[2] >> 4 & 7;
		entry->unk02_7 = bytes[2] >> 7 & 1;
		entry->unk03_3 = bytes[3] >> 3 & 0x1f;
	}
	conn->valid = 1;
	return 0;
}