]>
Commit | Line | Data |
---|---|---|
f6267998 RC |
1 | /* |
2 | * Copyright (C) 2011 Infineon Technologies | |
3 | * | |
4 | * Authors: | |
5 | * Peter Huewe <huewe.external@infineon.com> | |
6 | * | |
7 | * Description: | |
8 | * Device driver for TCG/TCPA TPM (trusted platform module). | |
9 | * Specifications at www.trustedcomputinggroup.org | |
10 | * | |
11 | * It is based on the Linux kernel driver tpm.c from Leendert van | |
12 | * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall. | |
13 | * | |
14 | * Version: 2.1.1 | |
15 | * | |
16 | * See file CREDITS for list of people who contributed to this | |
17 | * project. | |
18 | * | |
19 | * This program is free software; you can redistribute it and/or | |
20 | * modify it under the terms of the GNU General Public License as | |
21 | * published by the Free Software Foundation, version 2 of the | |
22 | * License. | |
23 | * | |
24 | * This program is distributed in the hope that it will be useful, | |
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
27 | * GNU General Public License for more details. | |
28 | * | |
29 | * You should have received a copy of the GNU General Public License | |
30 | * along with this program; if not, write to the Free Software | |
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
32 | * MA 02111-1307 USA | |
33 | */ | |
34 | ||
1b393db5 TWHT |
35 | #include <config.h> |
36 | #include <common.h> | |
afc366f0 | 37 | #include <linux/compiler.h> |
1b393db5 TWHT |
38 | #include <fdtdec.h> |
39 | #include <i2c.h> | |
40 | #include <tpm.h> | |
41 | #include <asm-generic/errno.h> | |
42 | #include <linux/types.h> | |
43 | #include <linux/unaligned/be_byteshift.h> | |
f6267998 | 44 | |
1b393db5 TWHT |
45 | #include "tpm_private.h" |
46 | ||
47 | DECLARE_GLOBAL_DATA_PTR; | |
48 | ||
49 | /* TPM configuration */ | |
50 | struct tpm { | |
51 | int i2c_bus; | |
52 | int slave_addr; | |
53 | char inited; | |
54 | int old_bus; | |
55 | } tpm; | |
56 | ||
57 | /* Global structure for tpm chip data */ | |
58 | static struct tpm_chip g_chip; | |
f6267998 RC |
59 | |
60 | enum tpm_duration { | |
61 | TPM_SHORT = 0, | |
62 | TPM_MEDIUM = 1, | |
63 | TPM_LONG = 2, | |
64 | TPM_UNDEFINED, | |
65 | }; | |
66 | ||
1b393db5 TWHT |
67 | /* Extended error numbers from linux (see errno.h) */ |
68 | #define ECANCELED 125 /* Operation Canceled */ | |
69 | ||
70 | /* Timer frequency. Corresponds to msec timer resolution*/ | |
71 | #define HZ 1000 | |
72 | ||
73 | #define TPM_MAX_ORDINAL 243 | |
74 | #define TPM_MAX_PROTECTED_ORDINAL 12 | |
75 | #define TPM_PROTECTED_ORDINAL_MASK 0xFF | |
76 | ||
77 | #define TPM_CMD_COUNT_BYTE 2 | |
78 | #define TPM_CMD_ORDINAL_BYTE 6 | |
f6267998 RC |
79 | |
80 | /* | |
81 | * Array with one entry per ordinal defining the maximum amount | |
82 | * of time the chip could take to return the result. The ordinal | |
83 | * designation of short, medium or long is defined in a table in | |
84 | * TCG Specification TPM Main Part 2 TPM Structures Section 17. The | |
85 | * values of the SHORT, MEDIUM, and LONG durations are retrieved | |
86 | * from the chip during initialization with a call to tpm_get_timeouts. | |
87 | */ | |
88 | static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = { | |
89 | TPM_UNDEFINED, /* 0 */ | |
90 | TPM_UNDEFINED, | |
91 | TPM_UNDEFINED, | |
92 | TPM_UNDEFINED, | |
93 | TPM_UNDEFINED, | |
94 | TPM_UNDEFINED, /* 5 */ | |
95 | TPM_UNDEFINED, | |
96 | TPM_UNDEFINED, | |
97 | TPM_UNDEFINED, | |
98 | TPM_UNDEFINED, | |
99 | TPM_SHORT, /* 10 */ | |
100 | TPM_SHORT, | |
101 | }; | |
102 | ||
103 | static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { | |
104 | TPM_UNDEFINED, /* 0 */ | |
105 | TPM_UNDEFINED, | |
106 | TPM_UNDEFINED, | |
107 | TPM_UNDEFINED, | |
108 | TPM_UNDEFINED, | |
109 | TPM_UNDEFINED, /* 5 */ | |
110 | TPM_UNDEFINED, | |
111 | TPM_UNDEFINED, | |
112 | TPM_UNDEFINED, | |
113 | TPM_UNDEFINED, | |
114 | TPM_SHORT, /* 10 */ | |
115 | TPM_SHORT, | |
116 | TPM_MEDIUM, | |
117 | TPM_LONG, | |
118 | TPM_LONG, | |
119 | TPM_MEDIUM, /* 15 */ | |
120 | TPM_SHORT, | |
121 | TPM_SHORT, | |
122 | TPM_MEDIUM, | |
123 | TPM_LONG, | |
124 | TPM_SHORT, /* 20 */ | |
125 | TPM_SHORT, | |
126 | TPM_MEDIUM, | |
127 | TPM_MEDIUM, | |
128 | TPM_MEDIUM, | |
129 | TPM_SHORT, /* 25 */ | |
130 | TPM_SHORT, | |
131 | TPM_MEDIUM, | |
132 | TPM_SHORT, | |
133 | TPM_SHORT, | |
134 | TPM_MEDIUM, /* 30 */ | |
135 | TPM_LONG, | |
136 | TPM_MEDIUM, | |
137 | TPM_SHORT, | |
138 | TPM_SHORT, | |
139 | TPM_SHORT, /* 35 */ | |
140 | TPM_MEDIUM, | |
141 | TPM_MEDIUM, | |
142 | TPM_UNDEFINED, | |
143 | TPM_UNDEFINED, | |
144 | TPM_MEDIUM, /* 40 */ | |
145 | TPM_LONG, | |
146 | TPM_MEDIUM, | |
147 | TPM_SHORT, | |
148 | TPM_SHORT, | |
149 | TPM_SHORT, /* 45 */ | |
150 | TPM_SHORT, | |
151 | TPM_SHORT, | |
152 | TPM_SHORT, | |
153 | TPM_LONG, | |
154 | TPM_MEDIUM, /* 50 */ | |
155 | TPM_MEDIUM, | |
156 | TPM_UNDEFINED, | |
157 | TPM_UNDEFINED, | |
158 | TPM_UNDEFINED, | |
159 | TPM_UNDEFINED, /* 55 */ | |
160 | TPM_UNDEFINED, | |
161 | TPM_UNDEFINED, | |
162 | TPM_UNDEFINED, | |
163 | TPM_UNDEFINED, | |
164 | TPM_MEDIUM, /* 60 */ | |
165 | TPM_MEDIUM, | |
166 | TPM_MEDIUM, | |
167 | TPM_SHORT, | |
168 | TPM_SHORT, | |
169 | TPM_MEDIUM, /* 65 */ | |
170 | TPM_UNDEFINED, | |
171 | TPM_UNDEFINED, | |
172 | TPM_UNDEFINED, | |
173 | TPM_UNDEFINED, | |
174 | TPM_SHORT, /* 70 */ | |
175 | TPM_SHORT, | |
176 | TPM_UNDEFINED, | |
177 | TPM_UNDEFINED, | |
178 | TPM_UNDEFINED, | |
179 | TPM_UNDEFINED, /* 75 */ | |
180 | TPM_UNDEFINED, | |
181 | TPM_UNDEFINED, | |
182 | TPM_UNDEFINED, | |
183 | TPM_UNDEFINED, | |
184 | TPM_LONG, /* 80 */ | |
185 | TPM_UNDEFINED, | |
186 | TPM_MEDIUM, | |
187 | TPM_LONG, | |
188 | TPM_SHORT, | |
189 | TPM_UNDEFINED, /* 85 */ | |
190 | TPM_UNDEFINED, | |
191 | TPM_UNDEFINED, | |
192 | TPM_UNDEFINED, | |
193 | TPM_UNDEFINED, | |
194 | TPM_SHORT, /* 90 */ | |
195 | TPM_SHORT, | |
196 | TPM_SHORT, | |
197 | TPM_SHORT, | |
198 | TPM_SHORT, | |
199 | TPM_UNDEFINED, /* 95 */ | |
200 | TPM_UNDEFINED, | |
201 | TPM_UNDEFINED, | |
202 | TPM_UNDEFINED, | |
203 | TPM_UNDEFINED, | |
204 | TPM_MEDIUM, /* 100 */ | |
205 | TPM_SHORT, | |
206 | TPM_SHORT, | |
207 | TPM_UNDEFINED, | |
208 | TPM_UNDEFINED, | |
209 | TPM_UNDEFINED, /* 105 */ | |
210 | TPM_UNDEFINED, | |
211 | TPM_UNDEFINED, | |
212 | TPM_UNDEFINED, | |
213 | TPM_UNDEFINED, | |
214 | TPM_SHORT, /* 110 */ | |
215 | TPM_SHORT, | |
216 | TPM_SHORT, | |
217 | TPM_SHORT, | |
218 | TPM_SHORT, | |
219 | TPM_SHORT, /* 115 */ | |
220 | TPM_SHORT, | |
221 | TPM_SHORT, | |
222 | TPM_UNDEFINED, | |
223 | TPM_UNDEFINED, | |
224 | TPM_LONG, /* 120 */ | |
225 | TPM_LONG, | |
226 | TPM_MEDIUM, | |
227 | TPM_UNDEFINED, | |
228 | TPM_SHORT, | |
229 | TPM_SHORT, /* 125 */ | |
230 | TPM_SHORT, | |
231 | TPM_LONG, | |
232 | TPM_SHORT, | |
233 | TPM_SHORT, | |
234 | TPM_SHORT, /* 130 */ | |
235 | TPM_MEDIUM, | |
236 | TPM_UNDEFINED, | |
237 | TPM_SHORT, | |
238 | TPM_MEDIUM, | |
239 | TPM_UNDEFINED, /* 135 */ | |
240 | TPM_UNDEFINED, | |
241 | TPM_UNDEFINED, | |
242 | TPM_UNDEFINED, | |
243 | TPM_UNDEFINED, | |
244 | TPM_SHORT, /* 140 */ | |
245 | TPM_SHORT, | |
246 | TPM_UNDEFINED, | |
247 | TPM_UNDEFINED, | |
248 | TPM_UNDEFINED, | |
249 | TPM_UNDEFINED, /* 145 */ | |
250 | TPM_UNDEFINED, | |
251 | TPM_UNDEFINED, | |
252 | TPM_UNDEFINED, | |
253 | TPM_UNDEFINED, | |
254 | TPM_SHORT, /* 150 */ | |
255 | TPM_MEDIUM, | |
256 | TPM_MEDIUM, | |
257 | TPM_SHORT, | |
258 | TPM_SHORT, | |
259 | TPM_UNDEFINED, /* 155 */ | |
260 | TPM_UNDEFINED, | |
261 | TPM_UNDEFINED, | |
262 | TPM_UNDEFINED, | |
263 | TPM_UNDEFINED, | |
264 | TPM_SHORT, /* 160 */ | |
265 | TPM_SHORT, | |
266 | TPM_SHORT, | |
267 | TPM_SHORT, | |
268 | TPM_UNDEFINED, | |
269 | TPM_UNDEFINED, /* 165 */ | |
270 | TPM_UNDEFINED, | |
271 | TPM_UNDEFINED, | |
272 | TPM_UNDEFINED, | |
273 | TPM_UNDEFINED, | |
274 | TPM_LONG, /* 170 */ | |
275 | TPM_UNDEFINED, | |
276 | TPM_UNDEFINED, | |
277 | TPM_UNDEFINED, | |
278 | TPM_UNDEFINED, | |
279 | TPM_UNDEFINED, /* 175 */ | |
280 | TPM_UNDEFINED, | |
281 | TPM_UNDEFINED, | |
282 | TPM_UNDEFINED, | |
283 | TPM_UNDEFINED, | |
284 | TPM_MEDIUM, /* 180 */ | |
285 | TPM_SHORT, | |
286 | TPM_MEDIUM, | |
287 | TPM_MEDIUM, | |
288 | TPM_MEDIUM, | |
289 | TPM_MEDIUM, /* 185 */ | |
290 | TPM_SHORT, | |
291 | TPM_UNDEFINED, | |
292 | TPM_UNDEFINED, | |
293 | TPM_UNDEFINED, | |
294 | TPM_UNDEFINED, /* 190 */ | |
295 | TPM_UNDEFINED, | |
296 | TPM_UNDEFINED, | |
297 | TPM_UNDEFINED, | |
298 | TPM_UNDEFINED, | |
299 | TPM_UNDEFINED, /* 195 */ | |
300 | TPM_UNDEFINED, | |
301 | TPM_UNDEFINED, | |
302 | TPM_UNDEFINED, | |
303 | TPM_UNDEFINED, | |
304 | TPM_SHORT, /* 200 */ | |
305 | TPM_UNDEFINED, | |
306 | TPM_UNDEFINED, | |
307 | TPM_UNDEFINED, | |
308 | TPM_SHORT, | |
309 | TPM_SHORT, /* 205 */ | |
310 | TPM_SHORT, | |
311 | TPM_SHORT, | |
312 | TPM_SHORT, | |
313 | TPM_SHORT, | |
314 | TPM_MEDIUM, /* 210 */ | |
315 | TPM_UNDEFINED, | |
316 | TPM_MEDIUM, | |
317 | TPM_MEDIUM, | |
318 | TPM_MEDIUM, | |
319 | TPM_UNDEFINED, /* 215 */ | |
320 | TPM_MEDIUM, | |
321 | TPM_UNDEFINED, | |
322 | TPM_UNDEFINED, | |
323 | TPM_SHORT, | |
324 | TPM_SHORT, /* 220 */ | |
325 | TPM_SHORT, | |
326 | TPM_SHORT, | |
327 | TPM_SHORT, | |
328 | TPM_SHORT, | |
329 | TPM_UNDEFINED, /* 225 */ | |
330 | TPM_UNDEFINED, | |
331 | TPM_UNDEFINED, | |
332 | TPM_UNDEFINED, | |
333 | TPM_UNDEFINED, | |
334 | TPM_SHORT, /* 230 */ | |
335 | TPM_LONG, | |
336 | TPM_MEDIUM, | |
337 | TPM_UNDEFINED, | |
338 | TPM_UNDEFINED, | |
339 | TPM_UNDEFINED, /* 235 */ | |
340 | TPM_UNDEFINED, | |
341 | TPM_UNDEFINED, | |
342 | TPM_UNDEFINED, | |
343 | TPM_UNDEFINED, | |
344 | TPM_SHORT, /* 240 */ | |
345 | TPM_UNDEFINED, | |
346 | TPM_MEDIUM, | |
347 | }; | |
348 | ||
1b393db5 TWHT |
349 | /* Returns max number of milliseconds to wait */ |
350 | static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, | |
351 | u32 ordinal) | |
f6267998 RC |
352 | { |
353 | int duration_idx = TPM_UNDEFINED; | |
354 | int duration = 0; | |
355 | ||
1b393db5 | 356 | if (ordinal < TPM_MAX_ORDINAL) { |
f6267998 | 357 | duration_idx = tpm_ordinal_duration[ordinal]; |
1b393db5 TWHT |
358 | } else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) < |
359 | TPM_MAX_PROTECTED_ORDINAL) { | |
360 | duration_idx = tpm_protected_ordinal_duration[ | |
361 | ordinal & TPM_PROTECTED_ORDINAL_MASK]; | |
362 | } | |
f6267998 RC |
363 | |
364 | if (duration_idx != TPM_UNDEFINED) | |
365 | duration = chip->vendor.duration[duration_idx]; | |
1b393db5 | 366 | |
f6267998 | 367 | if (duration <= 0) |
1b393db5 | 368 | return 2 * 60 * HZ; /* Two minutes timeout */ |
f6267998 RC |
369 | else |
370 | return duration; | |
371 | } | |
372 | ||
1b393db5 | 373 | static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) |
f6267998 RC |
374 | { |
375 | ssize_t rc; | |
376 | u32 count, ordinal; | |
377 | unsigned long start, stop; | |
378 | ||
379 | struct tpm_chip *chip = &g_chip; | |
380 | ||
381 | /* switch endianess: big->little */ | |
382 | count = get_unaligned_be32(buf + TPM_CMD_COUNT_BYTE); | |
383 | ordinal = get_unaligned_be32(buf + TPM_CMD_ORDINAL_BYTE); | |
384 | ||
385 | if (count == 0) { | |
1b393db5 | 386 | error("no data\n"); |
f6267998 RC |
387 | return -ENODATA; |
388 | } | |
389 | if (count > bufsiz) { | |
1b393db5 | 390 | error("invalid count value %x %zx\n", count, bufsiz); |
f6267998 RC |
391 | return -E2BIG; |
392 | } | |
393 | ||
394 | rc = chip->vendor.send(chip, (u8 *)buf, count); | |
395 | if (rc < 0) { | |
1b393db5 | 396 | error("tpm_transmit: tpm_send: error %zd\n", rc); |
f6267998 RC |
397 | goto out; |
398 | } | |
399 | ||
400 | if (chip->vendor.irq) | |
401 | goto out_recv; | |
402 | ||
403 | start = get_timer(0); | |
404 | stop = tpm_calc_ordinal_duration(chip, ordinal); | |
405 | do { | |
1b393db5 | 406 | debug("waiting for status...\n"); |
f6267998 RC |
407 | u8 status = chip->vendor.status(chip); |
408 | if ((status & chip->vendor.req_complete_mask) == | |
409 | chip->vendor.req_complete_val) { | |
1b393db5 | 410 | debug("...got it;\n"); |
f6267998 RC |
411 | goto out_recv; |
412 | } | |
413 | ||
49f93379 | 414 | if (status == chip->vendor.req_canceled) { |
1b393db5 | 415 | error("Operation Canceled\n"); |
f6267998 RC |
416 | rc = -ECANCELED; |
417 | goto out; | |
418 | } | |
1b393db5 | 419 | udelay(TPM_TIMEOUT * 1000); |
f6267998 RC |
420 | } while (get_timer(start) < stop); |
421 | ||
422 | chip->vendor.cancel(chip); | |
1b393db5 | 423 | error("Operation Timed out\n"); |
f6267998 RC |
424 | rc = -ETIME; |
425 | goto out; | |
426 | ||
427 | out_recv: | |
1b393db5 | 428 | debug("out_recv: reading response...\n"); |
f6267998 RC |
429 | rc = chip->vendor.recv(chip, (u8 *)buf, TPM_BUFSIZE); |
430 | if (rc < 0) | |
1b393db5 TWHT |
431 | error("tpm_transmit: tpm_recv: error %zd\n", rc); |
432 | ||
f6267998 RC |
433 | out: |
434 | return rc; | |
435 | } | |
436 | ||
1b393db5 TWHT |
437 | static int tpm_open(uint32_t dev_addr) |
438 | { | |
439 | int rc; | |
440 | if (g_chip.is_open) | |
441 | return -EBUSY; | |
442 | rc = tpm_vendor_init(dev_addr); | |
443 | if (rc < 0) | |
444 | g_chip.is_open = 0; | |
445 | return rc; | |
446 | } | |
f6267998 | 447 | |
1b393db5 TWHT |
448 | static void tpm_close(void) |
449 | { | |
450 | if (g_chip.is_open) { | |
451 | tpm_vendor_cleanup(&g_chip); | |
452 | g_chip.is_open = 0; | |
453 | } | |
454 | } | |
f6267998 | 455 | |
1b393db5 TWHT |
456 | static int tpm_select(void) |
457 | { | |
458 | int ret; | |
459 | ||
460 | tpm.old_bus = i2c_get_bus_num(); | |
461 | if (tpm.old_bus != tpm.i2c_bus) { | |
462 | ret = i2c_set_bus_num(tpm.i2c_bus); | |
463 | if (ret) { | |
464 | debug("%s: Fail to set i2c bus %d\n", __func__, | |
465 | tpm.i2c_bus); | |
466 | return -1; | |
467 | } | |
468 | } | |
469 | return 0; | |
470 | } | |
471 | ||
472 | static int tpm_deselect(void) | |
473 | { | |
474 | int ret; | |
475 | ||
476 | if (tpm.old_bus != i2c_get_bus_num()) { | |
477 | ret = i2c_set_bus_num(tpm.old_bus); | |
478 | if (ret) { | |
479 | debug("%s: Fail to restore i2c bus %d\n", | |
480 | __func__, tpm.old_bus); | |
481 | return -1; | |
482 | } | |
483 | } | |
484 | tpm.old_bus = -1; | |
485 | return 0; | |
486 | } | |
487 | ||
488 | /** | |
489 | * Decode TPM configuration. | |
490 | * | |
491 | * @param dev Returns a configuration of TPM device | |
492 | * @return 0 if ok, -1 on error | |
493 | */ | |
494 | static int tpm_decode_config(struct tpm *dev) | |
495 | { | |
496 | #ifdef CONFIG_OF_CONTROL | |
497 | const void *blob = gd->fdt_blob; | |
498 | int node, parent; | |
499 | int i2c_bus; | |
500 | ||
501 | node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM); | |
502 | if (node < 0) { | |
503 | node = fdtdec_next_compatible(blob, 0, | |
504 | COMPAT_INFINEON_SLB9645_TPM); | |
505 | } | |
506 | if (node < 0) { | |
507 | debug("%s: Node not found\n", __func__); | |
508 | return -1; | |
509 | } | |
510 | parent = fdt_parent_offset(blob, node); | |
511 | if (parent < 0) { | |
512 | debug("%s: Cannot find node parent\n", __func__); | |
513 | return -1; | |
514 | } | |
515 | i2c_bus = i2c_get_bus_num_fdt(parent); | |
516 | if (i2c_bus < 0) | |
517 | return -1; | |
518 | dev->i2c_bus = i2c_bus; | |
519 | dev->slave_addr = fdtdec_get_addr(blob, node, "reg"); | |
520 | #else | |
521 | dev->i2c_bus = CONFIG_TPM_TIS_I2C_BUS_NUMBER; | |
522 | dev->slave_addr = CONFIG_TPM_TIS_I2C_SLAVE_ADDRESS; | |
523 | #endif | |
524 | return 0; | |
525 | } | |
f6267998 RC |
526 | |
527 | struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *entry) | |
528 | { | |
529 | struct tpm_chip *chip; | |
530 | ||
531 | /* Driver specific per-device data */ | |
532 | chip = &g_chip; | |
533 | memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); | |
534 | chip->is_open = 1; | |
535 | ||
536 | return chip; | |
537 | } | |
538 | ||
1b393db5 TWHT |
539 | int tis_init(void) |
540 | { | |
541 | if (tpm.inited) | |
542 | return 0; | |
543 | ||
544 | if (tpm_decode_config(&tpm)) | |
545 | return -1; | |
546 | ||
547 | if (tpm_select()) | |
548 | return -1; | |
549 | ||
550 | /* | |
551 | * Probe TPM twice; the first probing might fail because TPM is asleep, | |
552 | * and the probing can wake up TPM. | |
553 | */ | |
554 | if (i2c_probe(tpm.slave_addr) && i2c_probe(tpm.slave_addr)) { | |
555 | debug("%s: fail to probe i2c addr 0x%x\n", __func__, | |
556 | tpm.slave_addr); | |
557 | return -1; | |
558 | } | |
559 | ||
560 | tpm_deselect(); | |
561 | ||
562 | tpm.inited = 1; | |
563 | ||
564 | return 0; | |
565 | } | |
566 | ||
567 | int tis_open(void) | |
f6267998 RC |
568 | { |
569 | int rc; | |
1b393db5 TWHT |
570 | |
571 | if (!tpm.inited) | |
572 | return -1; | |
573 | ||
574 | if (tpm_select()) | |
575 | return -1; | |
576 | ||
577 | rc = tpm_open(tpm.slave_addr); | |
578 | ||
579 | tpm_deselect(); | |
580 | ||
f6267998 RC |
581 | return rc; |
582 | } | |
583 | ||
1b393db5 | 584 | int tis_close(void) |
f6267998 | 585 | { |
1b393db5 TWHT |
586 | if (!tpm.inited) |
587 | return -1; | |
588 | ||
589 | if (tpm_select()) | |
590 | return -1; | |
591 | ||
592 | tpm_close(); | |
593 | ||
594 | tpm_deselect(); | |
595 | ||
596 | return 0; | |
597 | } | |
598 | ||
599 | int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, | |
600 | uint8_t *recvbuf, size_t *rbuf_len) | |
601 | { | |
602 | int len; | |
603 | uint8_t buf[4096]; | |
604 | ||
605 | if (!tpm.inited) | |
606 | return -1; | |
607 | ||
608 | if (sizeof(buf) < sbuf_size) | |
609 | return -1; | |
610 | ||
611 | memcpy(buf, sendbuf, sbuf_size); | |
612 | ||
613 | if (tpm_select()) | |
614 | return -1; | |
615 | ||
616 | len = tpm_transmit(buf, sbuf_size); | |
617 | ||
618 | tpm_deselect(); | |
619 | ||
620 | if (len < 10) { | |
621 | *rbuf_len = 0; | |
622 | return -1; | |
f6267998 | 623 | } |
1b393db5 TWHT |
624 | |
625 | memcpy(recvbuf, buf, len); | |
626 | *rbuf_len = len; | |
627 | ||
628 | return 0; | |
f6267998 | 629 | } |