summaryrefslogtreecommitdiff
path: root/src/hdcp.c
blob: 170afbb219d0d680ebf9b1950f306ce530f76a36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/*
 * Copyright (C) ST-Ericsson SA 2011
 * Author: Per Persson per.xb.persson@stericsson.com for
 * ST-Ericsson.
 * License terms: <FOSS license>.
 */

#include <unistd.h>     /* Symbolic Constants */
#include <sys/types.h>  /* Primitive System Data Types */
#include <errno.h>      /* Errors */
#include <stdarg.h>
#include <stdio.h>      /* Input/Output */
#include <stdlib.h>     /* General Utilities */
#include <string.h>     /* String handling */
#include <fcntl.h>
#include <time.h>
#include <sys/ioctl.h>
#include <ctype.h>
#include <utils/Log.h>
#include "../include/hdmi_service_api.h"
#include "../include/hdmi_service_local.h"

const __u8 hdcp_auth_start_val[] = {0x01, 0x00}; /* Start authentication */
const __u8 hdcp_encr_start_val[] = {0x03, 0x01}; /* Start encryption */
const __u8 hdcp_encr_stop_val[] = {0x00, 0x00}; /* Stop encryption */
const __u8 hdcp_even_val[] = {0x01}; /* Enable HDCP events */

static char *dbg_otp(int value)
{
	switch (value) {
	case OTP_UNPROGGED:
		return "OTP IS NOT PROGRAMMED";
		break;
	case OTP_PROGGED:
		return "OTP IS PROGRAMMED";
		break;
	default:
		return "OTP status UNKNOWN";
		break;
	}
}

static char *dbg_loadaes(int value)
{
	switch (value) {
	case LOADAES_OK:
		return "LOAD AES OK\n";
		break;
	case LOADAES_NOT_OK:
		return "LOAD AES FAILED\n";
		break;
	case LOADAES_NOT_FUSED:
		return "LOAD AES FAILED NOT FUSED\n";
		break;
	case LOADAES_CRC_MISMATCH:
		return "LOAD AES FAILED CRC MISMATCH\n";
		break;
	default:
		return "LOAD AES result UNKNOWN\n";
		break;
	}
}

static char *dbg_hdcpstate(int value)
{
	switch (value) {
	case HDCP_STATE_NO_RECV:
		return "HDCP STATE NO_RECV";
		break;
	case HDCP_STATE_RECV_CONN:
		return "HDCP STATE RECV_CONN";
		break;
	case HDCP_STATE_NO_HDCP:
		return "HDCP STATE NO_HDCP";
		break;
	case HDCP_STATE_NO_ENCR:
		return "HDCP STATE NO_ENCR";
		break;
	case HDCP_STATE_AUTH_ONGOING:
		return "HDCP STATE AUTH_ONGOING";
		break;
	case HDCP_STATE_AUTH_FAIL:
		return "HDCP STATE AUTH_FAIL";
		break;
	case HDCP_STATE_AUTH_SUCCEDED:
		return "HDCP STATE AUTH_SUCCEDED";
		break;
	case HDCP_STATE_ENCR_ONGOING:
		return "HDCP STATE ENCR_ONGOING";
		break;
	default:
		return "HDCP STATE UNKNOWN";
		break;
	}
}

/* Load aes keys and start hdcp encryption */
int hdcp_init(__u8 *aes)
{
	int hdcpchkaesotp;
	int hdcploadaes;
	int hdcpauthencr;
	int hdcpeven;
	int res;
	int value = 0;
	char buf[128];
	int result = HDCP_OK;
	int events;

	/* Check if OTP is fused */
	hdcpchkaesotp = open(HDCPCHKAESOTP_FILE, O_RDONLY);
	if (hdcpchkaesotp < 0) {
		LOGHDMILIB("***** Failed to open %s *****", HDCPCHKAESOTP_FILE);
		result = SYSFS_FILE_FAILED;
		goto hdcp_end;
	}
	res = read(hdcpchkaesotp, buf, sizeof(buf));
	close(hdcpchkaesotp);
	if (res != 1) {
		LOGHDMILIB("***** %s read error *****", HDCPCHKAESOTP_FILE);
		result = SYSFS_FILE_FAILED;
		goto hdcp_end;
	}
	value = *buf;
	LOGHDMILIB("%s", dbg_otp(value));

	if (value == OTP_PROGGED) {
		/* Subscribe for hdcp events */
		hdcpeven = open(HDCPEVEN_FILE, O_WRONLY);
		if (hdcpeven < 0) {
			LOGHDMILIB("***** Failed to open %s *****",
					HDCPEVEN_FILE);
			result = SYSFS_FILE_FAILED;
			goto hdcp_end;
		}
		write(hdcpeven, hdcp_even_val, sizeof(hdcp_even_val));
		close(hdcpeven);

		/* Write aes keys */
		hdcploadaes = open(HDCPLOADAES_FILE, O_WRONLY);
		if (hdcploadaes < 0) {
			LOGHDMILIB("***** Failed to open %s *****",
					HDCPLOADAES_FILE);
			result = SYSFS_FILE_FAILED;
			goto hdcp_end;
		}
		res = write(hdcploadaes, aes, AES_KEYS_SIZE);
		close(hdcploadaes);
		if (res != AES_KEYS_SIZE) {
			LOGHDMILIB("***** Failed to write hdcploadaes %d "
					"*****", res);
			result = SYSFS_FILE_FAILED;
			goto hdcp_end;
		}

		usleep(LOADAES_WAITTIME);

		/* Check result */
		hdcploadaes = open(HDCPLOADAES_FILE, O_RDONLY);
		if (hdcploadaes < 0) {
			LOGHDMILIB("***** Failed to open %s *****",
					HDCPLOADAES_FILE);
			result = SYSFS_FILE_FAILED;
			goto hdcp_end;
		}
		res = read(hdcploadaes, buf, sizeof(buf));
		close(hdcploadaes);
		if (res != 1) {
			LOGHDMILIB("***** %s read error *****",
						HDCPLOADAES_FILE);
			result = SYSFS_FILE_FAILED;
			goto hdcp_end;
		}
		value = *buf;
		LOGHDMILIB("%s", dbg_loadaes(value));
		if (value == LOADAES_OK) {
			LOGHDMILIB("%s", "--- LOAD AES keys OK ---");
		} else {
			result = AESKEYS_FAIL;
			goto hdcp_end;
		}

		usleep(LOADAES_WAITTIME);

		/* Start HDCP encryption */
		hdcpauthencr = open(HDCPAUTH_FILE, O_WRONLY);
		if (hdcpauthencr < 0) {
			LOGHDMILIB("***** Failed to open %s *****",
					HDCPAUTH_FILE);
			result = HDCPAUTHENCR_FAIL;
			goto hdcp_end;
		}
		res = write(hdcpauthencr, hdcp_encr_start_val,
				sizeof(hdcp_encr_start_val));
		close(hdcpauthencr);
		if (res != sizeof(hdcp_encr_start_val)) {
			LOGHDMILIB("***** Failed to write hdcpauthencr %d "
					"*****", res);
			result = HDCPAUTHENCR_FAIL;
			goto hdcp_end;
		}
		usleep(HDCPAUTH_WAITTIME);

	} else {
		printf("***** Missing aes file or HDCP AES OTP is not fused."
				" *****\n");
	}

hdcp_end:
	return result;
}

/* Get current hdcp state */
int hdcp_state(void)
{
	int hdcpstateget;
	int result = HDCP_OK;
	int res;
	__u8 buf[128];
	int val;
	__u32 cmd_id;

	cmd_id = get_new_cmd_id_ind();

	/* Check hdcpstate */
	hdcpstateget = open(HDCPSTATEGET_FILE, O_RDONLY);
	if (hdcpstateget < 0) {
		LOGHDMILIB("***** Failed to open %s *****",
				HDCPSTATEGET_FILE);
		result = SYSFS_FILE_FAILED;
		goto hdcp_state_end;
	}
	res = read(hdcpstateget, buf, sizeof(buf));
	close(hdcpstateget);
	if (res != 1) {
		LOGHDMILIB("***** %s read error *****",
				HDCPSTATEGET_FILE);
		result = HDCPSTATE_FAIL;
		goto hdcp_state_end;
	}

	val = HDMI_HDCPSTATE;
	memcpy(&buf[CMD_OFFSET], &val, 4);
	memcpy(&buf[CMDID_OFFSET], &cmd_id, 4);
	val = 1;
	memcpy(&buf[CMDLEN_OFFSET], &val, 4);
	memcpy(&buf[CMDBUF_OFFSET], buf, val);

	/* Send on socket */
	if (clientsocket_send(buf, CMDBUF_OFFSET + val) != 0)
		result = HDCPSTATE_FAIL;

	LOGHDMILIB("%s", dbg_hdcpstate(val));

hdcp_state_end:
	return result;
}