diff options
author | David Woodhouse <dwmw2@infradead.org> | 2006-05-03 08:30:35 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2006-05-03 08:30:35 -0400 |
commit | edc4ff7c08e9885c40e60c4fb39fa42cc91a0602 (patch) | |
tree | f375d28043dd4457428a841167dc93d760ba9a46 /drivers/char/tpm/tpm.c | |
parent | cbb9a56177b16294ed347ba7fcb1c66c8adb5dc4 (diff) | |
parent | e17df688f7064dae1417ce425dd1e4b71d24d63b (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/char/tpm/tpm.c')
-rw-r--r-- | drivers/char/tpm/tpm.c | 786 |
1 files changed, 673 insertions, 113 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 5a3870477ef1..6889e7db3aff 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -32,12 +32,291 @@ enum tpm_const { | |||
32 | TPM_MINOR = 224, /* officially assigned */ | 32 | TPM_MINOR = 224, /* officially assigned */ |
33 | TPM_BUFSIZE = 2048, | 33 | TPM_BUFSIZE = 2048, |
34 | TPM_NUM_DEVICES = 256, | 34 | TPM_NUM_DEVICES = 256, |
35 | TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int)) | ||
36 | }; | 35 | }; |
37 | 36 | ||
37 | enum tpm_duration { | ||
38 | TPM_SHORT = 0, | ||
39 | TPM_MEDIUM = 1, | ||
40 | TPM_LONG = 2, | ||
41 | TPM_UNDEFINED, | ||
42 | }; | ||
43 | |||
44 | #define TPM_MAX_ORDINAL 243 | ||
45 | #define TPM_MAX_PROTECTED_ORDINAL 12 | ||
46 | #define TPM_PROTECTED_ORDINAL_MASK 0xFF | ||
47 | |||
38 | static LIST_HEAD(tpm_chip_list); | 48 | static LIST_HEAD(tpm_chip_list); |
39 | static DEFINE_SPINLOCK(driver_lock); | 49 | static DEFINE_SPINLOCK(driver_lock); |
40 | static int dev_mask[TPM_NUM_MASK_ENTRIES]; | 50 | static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); |
51 | |||
52 | /* | ||
53 | * Array with one entry per ordinal defining the maximum amount | ||
54 | * of time the chip could take to return the result. The ordinal | ||
55 | * designation of short, medium or long is defined in a table in | ||
56 | * TCG Specification TPM Main Part 2 TPM Structures Section 17. The | ||
57 | * values of the SHORT, MEDIUM, and LONG durations are retrieved | ||
58 | * from the chip during initialization with a call to tpm_get_timeouts. | ||
59 | */ | ||
60 | static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = { | ||
61 | TPM_UNDEFINED, /* 0 */ | ||
62 | TPM_UNDEFINED, | ||
63 | TPM_UNDEFINED, | ||
64 | TPM_UNDEFINED, | ||
65 | TPM_UNDEFINED, | ||
66 | TPM_UNDEFINED, /* 5 */ | ||
67 | TPM_UNDEFINED, | ||
68 | TPM_UNDEFINED, | ||
69 | TPM_UNDEFINED, | ||
70 | TPM_UNDEFINED, | ||
71 | TPM_SHORT, /* 10 */ | ||
72 | TPM_SHORT, | ||
73 | }; | ||
74 | |||
75 | static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { | ||
76 | TPM_UNDEFINED, /* 0 */ | ||
77 | TPM_UNDEFINED, | ||
78 | TPM_UNDEFINED, | ||
79 | TPM_UNDEFINED, | ||
80 | TPM_UNDEFINED, | ||
81 | TPM_UNDEFINED, /* 5 */ | ||
82 | TPM_UNDEFINED, | ||
83 | TPM_UNDEFINED, | ||
84 | TPM_UNDEFINED, | ||
85 | TPM_UNDEFINED, | ||
86 | TPM_SHORT, /* 10 */ | ||
87 | TPM_SHORT, | ||
88 | TPM_MEDIUM, | ||
89 | TPM_LONG, | ||
90 | TPM_LONG, | ||
91 | TPM_MEDIUM, /* 15 */ | ||
92 | TPM_SHORT, | ||
93 | TPM_SHORT, | ||
94 | TPM_MEDIUM, | ||
95 | TPM_LONG, | ||
96 | TPM_SHORT, /* 20 */ | ||
97 | TPM_SHORT, | ||
98 | TPM_MEDIUM, | ||
99 | TPM_MEDIUM, | ||
100 | TPM_MEDIUM, | ||
101 | TPM_SHORT, /* 25 */ | ||
102 | TPM_SHORT, | ||
103 | TPM_MEDIUM, | ||
104 | TPM_SHORT, | ||
105 | TPM_SHORT, | ||
106 | TPM_MEDIUM, /* 30 */ | ||
107 | TPM_LONG, | ||
108 | TPM_MEDIUM, | ||
109 | TPM_SHORT, | ||
110 | TPM_SHORT, | ||
111 | TPM_SHORT, /* 35 */ | ||
112 | TPM_MEDIUM, | ||
113 | TPM_MEDIUM, | ||
114 | TPM_UNDEFINED, | ||
115 | TPM_UNDEFINED, | ||
116 | TPM_MEDIUM, /* 40 */ | ||
117 | TPM_LONG, | ||
118 | TPM_MEDIUM, | ||
119 | TPM_SHORT, | ||
120 | TPM_SHORT, | ||
121 | TPM_SHORT, /* 45 */ | ||
122 | TPM_SHORT, | ||
123 | TPM_SHORT, | ||
124 | TPM_SHORT, | ||
125 | TPM_LONG, | ||
126 | TPM_MEDIUM, /* 50 */ | ||
127 | TPM_MEDIUM, | ||
128 | TPM_UNDEFINED, | ||
129 | TPM_UNDEFINED, | ||
130 | TPM_UNDEFINED, | ||
131 | TPM_UNDEFINED, /* 55 */ | ||
132 | TPM_UNDEFINED, | ||
133 | TPM_UNDEFINED, | ||
134 | TPM_UNDEFINED, | ||
135 | TPM_UNDEFINED, | ||
136 | TPM_MEDIUM, /* 60 */ | ||
137 | TPM_MEDIUM, | ||
138 | TPM_MEDIUM, | ||
139 | TPM_SHORT, | ||
140 | TPM_SHORT, | ||
141 | TPM_MEDIUM, /* 65 */ | ||
142 | TPM_UNDEFINED, | ||
143 | TPM_UNDEFINED, | ||
144 | TPM_UNDEFINED, | ||
145 | TPM_UNDEFINED, | ||
146 | TPM_SHORT, /* 70 */ | ||
147 | TPM_SHORT, | ||
148 | TPM_UNDEFINED, | ||
149 | TPM_UNDEFINED, | ||
150 | TPM_UNDEFINED, | ||
151 | TPM_UNDEFINED, /* 75 */ | ||
152 | TPM_UNDEFINED, | ||
153 | TPM_UNDEFINED, | ||
154 | TPM_UNDEFINED, | ||
155 | TPM_UNDEFINED, | ||
156 | TPM_LONG, /* 80 */ | ||
157 | TPM_UNDEFINED, | ||
158 | TPM_MEDIUM, | ||
159 | TPM_LONG, | ||
160 | TPM_SHORT, | ||
161 | TPM_UNDEFINED, /* 85 */ | ||
162 | TPM_UNDEFINED, | ||
163 | TPM_UNDEFINED, | ||
164 | TPM_UNDEFINED, | ||
165 | TPM_UNDEFINED, | ||
166 | TPM_SHORT, /* 90 */ | ||
167 | TPM_SHORT, | ||
168 | TPM_SHORT, | ||
169 | TPM_SHORT, | ||
170 | TPM_SHORT, | ||
171 | TPM_UNDEFINED, /* 95 */ | ||
172 | TPM_UNDEFINED, | ||
173 | TPM_UNDEFINED, | ||
174 | TPM_UNDEFINED, | ||
175 | TPM_UNDEFINED, | ||
176 | TPM_MEDIUM, /* 100 */ | ||
177 | TPM_SHORT, | ||
178 | TPM_SHORT, | ||
179 | TPM_UNDEFINED, | ||
180 | TPM_UNDEFINED, | ||
181 | TPM_UNDEFINED, /* 105 */ | ||
182 | TPM_UNDEFINED, | ||
183 | TPM_UNDEFINED, | ||
184 | TPM_UNDEFINED, | ||
185 | TPM_UNDEFINED, | ||
186 | TPM_SHORT, /* 110 */ | ||
187 | TPM_SHORT, | ||
188 | TPM_SHORT, | ||
189 | TPM_SHORT, | ||
190 | TPM_SHORT, | ||
191 | TPM_SHORT, /* 115 */ | ||
192 | TPM_SHORT, | ||
193 | TPM_SHORT, | ||
194 | TPM_UNDEFINED, | ||
195 | TPM_UNDEFINED, | ||
196 | TPM_LONG, /* 120 */ | ||
197 | TPM_LONG, | ||
198 | TPM_MEDIUM, | ||
199 | TPM_UNDEFINED, | ||
200 | TPM_SHORT, | ||
201 | TPM_SHORT, /* 125 */ | ||
202 | TPM_SHORT, | ||
203 | TPM_LONG, | ||
204 | TPM_SHORT, | ||
205 | TPM_SHORT, | ||
206 | TPM_SHORT, /* 130 */ | ||
207 | TPM_MEDIUM, | ||
208 | TPM_UNDEFINED, | ||
209 | TPM_SHORT, | ||
210 | TPM_MEDIUM, | ||
211 | TPM_UNDEFINED, /* 135 */ | ||
212 | TPM_UNDEFINED, | ||
213 | TPM_UNDEFINED, | ||
214 | TPM_UNDEFINED, | ||
215 | TPM_UNDEFINED, | ||
216 | TPM_SHORT, /* 140 */ | ||
217 | TPM_SHORT, | ||
218 | TPM_UNDEFINED, | ||
219 | TPM_UNDEFINED, | ||
220 | TPM_UNDEFINED, | ||
221 | TPM_UNDEFINED, /* 145 */ | ||
222 | TPM_UNDEFINED, | ||
223 | TPM_UNDEFINED, | ||
224 | TPM_UNDEFINED, | ||
225 | TPM_UNDEFINED, | ||
226 | TPM_SHORT, /* 150 */ | ||
227 | TPM_MEDIUM, | ||
228 | TPM_MEDIUM, | ||
229 | TPM_SHORT, | ||
230 | TPM_SHORT, | ||
231 | TPM_UNDEFINED, /* 155 */ | ||
232 | TPM_UNDEFINED, | ||
233 | TPM_UNDEFINED, | ||
234 | TPM_UNDEFINED, | ||
235 | TPM_UNDEFINED, | ||
236 | TPM_SHORT, /* 160 */ | ||
237 | TPM_SHORT, | ||
238 | TPM_SHORT, | ||
239 | TPM_SHORT, | ||
240 | TPM_UNDEFINED, | ||
241 | TPM_UNDEFINED, /* 165 */ | ||
242 | TPM_UNDEFINED, | ||
243 | TPM_UNDEFINED, | ||
244 | TPM_UNDEFINED, | ||
245 | TPM_UNDEFINED, | ||
246 | TPM_LONG, /* 170 */ | ||
247 | TPM_UNDEFINED, | ||
248 | TPM_UNDEFINED, | ||
249 | TPM_UNDEFINED, | ||
250 | TPM_UNDEFINED, | ||
251 | TPM_UNDEFINED, /* 175 */ | ||
252 | TPM_UNDEFINED, | ||
253 | TPM_UNDEFINED, | ||
254 | TPM_UNDEFINED, | ||
255 | TPM_UNDEFINED, | ||
256 | TPM_MEDIUM, /* 180 */ | ||
257 | TPM_SHORT, | ||
258 | TPM_MEDIUM, | ||
259 | TPM_MEDIUM, | ||
260 | TPM_MEDIUM, | ||
261 | TPM_MEDIUM, /* 185 */ | ||
262 | TPM_SHORT, | ||
263 | TPM_UNDEFINED, | ||
264 | TPM_UNDEFINED, | ||
265 | TPM_UNDEFINED, | ||
266 | TPM_UNDEFINED, /* 190 */ | ||
267 | TPM_UNDEFINED, | ||
268 | TPM_UNDEFINED, | ||
269 | TPM_UNDEFINED, | ||
270 | TPM_UNDEFINED, | ||
271 | TPM_UNDEFINED, /* 195 */ | ||
272 | TPM_UNDEFINED, | ||
273 | TPM_UNDEFINED, | ||
274 | TPM_UNDEFINED, | ||
275 | TPM_UNDEFINED, | ||
276 | TPM_SHORT, /* 200 */ | ||
277 | TPM_UNDEFINED, | ||
278 | TPM_UNDEFINED, | ||
279 | TPM_UNDEFINED, | ||
280 | TPM_SHORT, | ||
281 | TPM_SHORT, /* 205 */ | ||
282 | TPM_SHORT, | ||
283 | TPM_SHORT, | ||
284 | TPM_SHORT, | ||
285 | TPM_SHORT, | ||
286 | TPM_MEDIUM, /* 210 */ | ||
287 | TPM_UNDEFINED, | ||
288 | TPM_MEDIUM, | ||
289 | TPM_MEDIUM, | ||
290 | TPM_MEDIUM, | ||
291 | TPM_UNDEFINED, /* 215 */ | ||
292 | TPM_MEDIUM, | ||
293 | TPM_UNDEFINED, | ||
294 | TPM_UNDEFINED, | ||
295 | TPM_SHORT, | ||
296 | TPM_SHORT, /* 220 */ | ||
297 | TPM_SHORT, | ||
298 | TPM_SHORT, | ||
299 | TPM_SHORT, | ||
300 | TPM_SHORT, | ||
301 | TPM_UNDEFINED, /* 225 */ | ||
302 | TPM_UNDEFINED, | ||
303 | TPM_UNDEFINED, | ||
304 | TPM_UNDEFINED, | ||
305 | TPM_UNDEFINED, | ||
306 | TPM_SHORT, /* 230 */ | ||
307 | TPM_LONG, | ||
308 | TPM_MEDIUM, | ||
309 | TPM_UNDEFINED, | ||
310 | TPM_UNDEFINED, | ||
311 | TPM_UNDEFINED, /* 235 */ | ||
312 | TPM_UNDEFINED, | ||
313 | TPM_UNDEFINED, | ||
314 | TPM_UNDEFINED, | ||
315 | TPM_UNDEFINED, | ||
316 | TPM_SHORT, /* 240 */ | ||
317 | TPM_UNDEFINED, | ||
318 | TPM_MEDIUM, | ||
319 | }; | ||
41 | 320 | ||
42 | static void user_reader_timeout(unsigned long ptr) | 321 | static void user_reader_timeout(unsigned long ptr) |
43 | { | 322 | { |
@@ -46,7 +325,7 @@ static void user_reader_timeout(unsigned long ptr) | |||
46 | schedule_work(&chip->work); | 325 | schedule_work(&chip->work); |
47 | } | 326 | } |
48 | 327 | ||
49 | static void timeout_work(void * ptr) | 328 | static void timeout_work(void *ptr) |
50 | { | 329 | { |
51 | struct tpm_chip *chip = ptr; | 330 | struct tpm_chip *chip = ptr; |
52 | 331 | ||
@@ -57,17 +336,43 @@ static void timeout_work(void * ptr) | |||
57 | } | 336 | } |
58 | 337 | ||
59 | /* | 338 | /* |
339 | * Returns max number of jiffies to wait | ||
340 | */ | ||
341 | unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, | ||
342 | u32 ordinal) | ||
343 | { | ||
344 | int duration_idx = TPM_UNDEFINED; | ||
345 | int duration = 0; | ||
346 | |||
347 | if (ordinal < TPM_MAX_ORDINAL) | ||
348 | duration_idx = tpm_ordinal_duration[ordinal]; | ||
349 | else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) < | ||
350 | TPM_MAX_PROTECTED_ORDINAL) | ||
351 | duration_idx = | ||
352 | tpm_protected_ordinal_duration[ordinal & | ||
353 | TPM_PROTECTED_ORDINAL_MASK]; | ||
354 | |||
355 | if (duration_idx != TPM_UNDEFINED) | ||
356 | duration = chip->vendor.duration[duration_idx]; | ||
357 | if (duration <= 0) | ||
358 | return 2 * 60 * HZ; | ||
359 | else | ||
360 | return duration; | ||
361 | } | ||
362 | EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); | ||
363 | |||
364 | /* | ||
60 | * Internal kernel interface to transmit TPM commands | 365 | * Internal kernel interface to transmit TPM commands |
61 | */ | 366 | */ |
62 | static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | 367 | static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, |
63 | size_t bufsiz) | 368 | size_t bufsiz) |
64 | { | 369 | { |
65 | ssize_t rc; | 370 | ssize_t rc; |
66 | u32 count; | 371 | u32 count, ordinal; |
67 | unsigned long stop; | 372 | unsigned long stop; |
68 | 373 | ||
69 | count = be32_to_cpu(*((__be32 *) (buf + 2))); | 374 | count = be32_to_cpu(*((__be32 *) (buf + 2))); |
70 | 375 | ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); | |
71 | if (count == 0) | 376 | if (count == 0) |
72 | return -ENODATA; | 377 | return -ENODATA; |
73 | if (count > bufsiz) { | 378 | if (count > bufsiz) { |
@@ -78,21 +383,23 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | |||
78 | 383 | ||
79 | down(&chip->tpm_mutex); | 384 | down(&chip->tpm_mutex); |
80 | 385 | ||
81 | if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) { | 386 | if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) { |
82 | dev_err(chip->dev, | 387 | dev_err(chip->dev, |
83 | "tpm_transmit: tpm_send: error %zd\n", rc); | 388 | "tpm_transmit: tpm_send: error %zd\n", rc); |
84 | goto out; | 389 | goto out; |
85 | } | 390 | } |
86 | 391 | ||
87 | stop = jiffies + 2 * 60 * HZ; | 392 | if (chip->vendor.irq) |
393 | goto out_recv; | ||
394 | |||
395 | stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); | ||
88 | do { | 396 | do { |
89 | u8 status = chip->vendor->status(chip); | 397 | u8 status = chip->vendor.status(chip); |
90 | if ((status & chip->vendor->req_complete_mask) == | 398 | if ((status & chip->vendor.req_complete_mask) == |
91 | chip->vendor->req_complete_val) { | 399 | chip->vendor.req_complete_val) |
92 | goto out_recv; | 400 | goto out_recv; |
93 | } | ||
94 | 401 | ||
95 | if ((status == chip->vendor->req_canceled)) { | 402 | if ((status == chip->vendor.req_canceled)) { |
96 | dev_err(chip->dev, "Operation Canceled\n"); | 403 | dev_err(chip->dev, "Operation Canceled\n"); |
97 | rc = -ECANCELED; | 404 | rc = -ECANCELED; |
98 | goto out; | 405 | goto out; |
@@ -102,14 +409,13 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | |||
102 | rmb(); | 409 | rmb(); |
103 | } while (time_before(jiffies, stop)); | 410 | } while (time_before(jiffies, stop)); |
104 | 411 | ||
105 | 412 | chip->vendor.cancel(chip); | |
106 | chip->vendor->cancel(chip); | ||
107 | dev_err(chip->dev, "Operation Timed out\n"); | 413 | dev_err(chip->dev, "Operation Timed out\n"); |
108 | rc = -ETIME; | 414 | rc = -ETIME; |
109 | goto out; | 415 | goto out; |
110 | 416 | ||
111 | out_recv: | 417 | out_recv: |
112 | rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz); | 418 | rc = chip->vendor.recv(chip, (u8 *) buf, bufsiz); |
113 | if (rc < 0) | 419 | if (rc < 0) |
114 | dev_err(chip->dev, | 420 | dev_err(chip->dev, |
115 | "tpm_transmit: tpm_recv: error %zd\n", rc); | 421 | "tpm_transmit: tpm_recv: error %zd\n", rc); |
@@ -119,17 +425,247 @@ out: | |||
119 | } | 425 | } |
120 | 426 | ||
121 | #define TPM_DIGEST_SIZE 20 | 427 | #define TPM_DIGEST_SIZE 20 |
122 | #define CAP_PCR_RESULT_SIZE 18 | 428 | #define TPM_ERROR_SIZE 10 |
123 | static const u8 cap_pcr[] = { | 429 | #define TPM_RET_CODE_IDX 6 |
430 | #define TPM_GET_CAP_RET_SIZE_IDX 10 | ||
431 | #define TPM_GET_CAP_RET_UINT32_1_IDX 14 | ||
432 | #define TPM_GET_CAP_RET_UINT32_2_IDX 18 | ||
433 | #define TPM_GET_CAP_RET_UINT32_3_IDX 22 | ||
434 | #define TPM_GET_CAP_RET_UINT32_4_IDX 26 | ||
435 | #define TPM_GET_CAP_PERM_DISABLE_IDX 16 | ||
436 | #define TPM_GET_CAP_PERM_INACTIVE_IDX 18 | ||
437 | #define TPM_GET_CAP_RET_BOOL_1_IDX 14 | ||
438 | #define TPM_GET_CAP_TEMP_INACTIVE_IDX 16 | ||
439 | |||
440 | #define TPM_CAP_IDX 13 | ||
441 | #define TPM_CAP_SUBCAP_IDX 21 | ||
442 | |||
443 | enum tpm_capabilities { | ||
444 | TPM_CAP_FLAG = 4, | ||
445 | TPM_CAP_PROP = 5, | ||
446 | }; | ||
447 | |||
448 | enum tpm_sub_capabilities { | ||
449 | TPM_CAP_PROP_PCR = 0x1, | ||
450 | TPM_CAP_PROP_MANUFACTURER = 0x3, | ||
451 | TPM_CAP_FLAG_PERM = 0x8, | ||
452 | TPM_CAP_FLAG_VOL = 0x9, | ||
453 | TPM_CAP_PROP_OWNER = 0x11, | ||
454 | TPM_CAP_PROP_TIS_TIMEOUT = 0x15, | ||
455 | TPM_CAP_PROP_TIS_DURATION = 0x20, | ||
456 | }; | ||
457 | |||
458 | /* | ||
459 | * This is a semi generic GetCapability command for use | ||
460 | * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG | ||
461 | * and their associated sub_capabilities. | ||
462 | */ | ||
463 | |||
464 | static const u8 tpm_cap[] = { | ||
124 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 465 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
125 | 0, 0, 0, 22, /* length */ | 466 | 0, 0, 0, 22, /* length */ |
126 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | 467 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ |
127 | 0, 0, 0, 5, | 468 | 0, 0, 0, 0, /* TPM_CAP_<TYPE> */ |
128 | 0, 0, 0, 4, | 469 | 0, 0, 0, 4, /* TPM_CAP_SUB_<TYPE> size */ |
129 | 0, 0, 1, 1 | 470 | 0, 0, 1, 0 /* TPM_CAP_SUB_<TYPE> */ |
130 | }; | 471 | }; |
131 | 472 | ||
132 | #define READ_PCR_RESULT_SIZE 30 | 473 | static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, |
474 | char *desc) | ||
475 | { | ||
476 | int err; | ||
477 | |||
478 | len = tpm_transmit(chip, data, len); | ||
479 | if (len < 0) | ||
480 | return len; | ||
481 | if (len == TPM_ERROR_SIZE) { | ||
482 | err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))); | ||
483 | dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); | ||
484 | return err; | ||
485 | } | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | void tpm_gen_interrupt(struct tpm_chip *chip) | ||
490 | { | ||
491 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; | ||
492 | ssize_t rc; | ||
493 | |||
494 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
495 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
496 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; | ||
497 | |||
498 | rc = transmit_cmd(chip, data, sizeof(data), | ||
499 | "attempting to determine the timeouts"); | ||
500 | } | ||
501 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); | ||
502 | |||
503 | void tpm_get_timeouts(struct tpm_chip *chip) | ||
504 | { | ||
505 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; | ||
506 | ssize_t rc; | ||
507 | u32 timeout; | ||
508 | |||
509 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
510 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
511 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; | ||
512 | |||
513 | rc = transmit_cmd(chip, data, sizeof(data), | ||
514 | "attempting to determine the timeouts"); | ||
515 | if (rc) | ||
516 | goto duration; | ||
517 | |||
518 | if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) | ||
519 | != 4 * sizeof(u32)) | ||
520 | goto duration; | ||
521 | |||
522 | /* Don't overwrite default if value is 0 */ | ||
523 | timeout = | ||
524 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); | ||
525 | if (timeout) | ||
526 | chip->vendor.timeout_a = msecs_to_jiffies(timeout); | ||
527 | timeout = | ||
528 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); | ||
529 | if (timeout) | ||
530 | chip->vendor.timeout_b = msecs_to_jiffies(timeout); | ||
531 | timeout = | ||
532 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); | ||
533 | if (timeout) | ||
534 | chip->vendor.timeout_c = msecs_to_jiffies(timeout); | ||
535 | timeout = | ||
536 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX))); | ||
537 | if (timeout) | ||
538 | chip->vendor.timeout_d = msecs_to_jiffies(timeout); | ||
539 | |||
540 | duration: | ||
541 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
542 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
543 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION; | ||
544 | |||
545 | rc = transmit_cmd(chip, data, sizeof(data), | ||
546 | "attempting to determine the durations"); | ||
547 | if (rc) | ||
548 | return; | ||
549 | |||
550 | if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) | ||
551 | != 3 * sizeof(u32)) | ||
552 | return; | ||
553 | |||
554 | chip->vendor.duration[TPM_SHORT] = | ||
555 | msecs_to_jiffies(be32_to_cpu | ||
556 | (*((__be32 *) (data + | ||
557 | TPM_GET_CAP_RET_UINT32_1_IDX)))); | ||
558 | chip->vendor.duration[TPM_MEDIUM] = | ||
559 | msecs_to_jiffies(be32_to_cpu | ||
560 | (*((__be32 *) (data + | ||
561 | TPM_GET_CAP_RET_UINT32_2_IDX)))); | ||
562 | chip->vendor.duration[TPM_LONG] = | ||
563 | msecs_to_jiffies(be32_to_cpu | ||
564 | (*((__be32 *) (data + | ||
565 | TPM_GET_CAP_RET_UINT32_3_IDX)))); | ||
566 | } | ||
567 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); | ||
568 | |||
569 | void tpm_continue_selftest(struct tpm_chip *chip) | ||
570 | { | ||
571 | u8 data[] = { | ||
572 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | ||
573 | 0, 0, 0, 10, /* length */ | ||
574 | 0, 0, 0, 83, /* TPM_ORD_GetCapability */ | ||
575 | }; | ||
576 | |||
577 | tpm_transmit(chip, data, sizeof(data)); | ||
578 | } | ||
579 | EXPORT_SYMBOL_GPL(tpm_continue_selftest); | ||
580 | |||
581 | ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, | ||
582 | char *buf) | ||
583 | { | ||
584 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)]; | ||
585 | ssize_t rc; | ||
586 | |||
587 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
588 | if (chip == NULL) | ||
589 | return -ENODEV; | ||
590 | |||
591 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
592 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | ||
593 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; | ||
594 | |||
595 | rc = transmit_cmd(chip, data, sizeof(data), | ||
596 | "attemtping to determine the permanent state"); | ||
597 | if (rc) | ||
598 | return 0; | ||
599 | return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]); | ||
600 | } | ||
601 | EXPORT_SYMBOL_GPL(tpm_show_enabled); | ||
602 | |||
603 | ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, | ||
604 | char *buf) | ||
605 | { | ||
606 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 35)]; | ||
607 | ssize_t rc; | ||
608 | |||
609 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
610 | if (chip == NULL) | ||
611 | return -ENODEV; | ||
612 | |||
613 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
614 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | ||
615 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; | ||
616 | |||
617 | rc = transmit_cmd(chip, data, sizeof(data), | ||
618 | "attemtping to determine the permanent state"); | ||
619 | if (rc) | ||
620 | return 0; | ||
621 | return sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]); | ||
622 | } | ||
623 | EXPORT_SYMBOL_GPL(tpm_show_active); | ||
624 | |||
625 | ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, | ||
626 | char *buf) | ||
627 | { | ||
628 | u8 data[sizeof(tpm_cap)]; | ||
629 | ssize_t rc; | ||
630 | |||
631 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
632 | if (chip == NULL) | ||
633 | return -ENODEV; | ||
634 | |||
635 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
636 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
637 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER; | ||
638 | |||
639 | rc = transmit_cmd(chip, data, sizeof(data), | ||
640 | "attempting to determine the owner state"); | ||
641 | if (rc) | ||
642 | return 0; | ||
643 | return sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]); | ||
644 | } | ||
645 | EXPORT_SYMBOL_GPL(tpm_show_owned); | ||
646 | |||
647 | ssize_t tpm_show_temp_deactivated(struct device * dev, | ||
648 | struct device_attribute * attr, char *buf) | ||
649 | { | ||
650 | u8 data[sizeof(tpm_cap)]; | ||
651 | ssize_t rc; | ||
652 | |||
653 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
654 | if (chip == NULL) | ||
655 | return -ENODEV; | ||
656 | |||
657 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
658 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | ||
659 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL; | ||
660 | |||
661 | rc = transmit_cmd(chip, data, sizeof(data), | ||
662 | "attempting to determine the temporary state"); | ||
663 | if (rc) | ||
664 | return 0; | ||
665 | return sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); | ||
666 | } | ||
667 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); | ||
668 | |||
133 | static const u8 pcrread[] = { | 669 | static const u8 pcrread[] = { |
134 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 670 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
135 | 0, 0, 0, 14, /* length */ | 671 | 0, 0, 0, 14, /* length */ |
@@ -140,8 +676,8 @@ static const u8 pcrread[] = { | |||
140 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | 676 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, |
141 | char *buf) | 677 | char *buf) |
142 | { | 678 | { |
143 | u8 data[READ_PCR_RESULT_SIZE]; | 679 | u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(pcrread)), 30)]; |
144 | ssize_t len; | 680 | ssize_t rc; |
145 | int i, j, num_pcrs; | 681 | int i, j, num_pcrs; |
146 | __be32 index; | 682 | __be32 index; |
147 | char *str = buf; | 683 | char *str = buf; |
@@ -150,29 +686,24 @@ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | |||
150 | if (chip == NULL) | 686 | if (chip == NULL) |
151 | return -ENODEV; | 687 | return -ENODEV; |
152 | 688 | ||
153 | memcpy(data, cap_pcr, sizeof(cap_pcr)); | 689 | memcpy(data, tpm_cap, sizeof(tpm_cap)); |
154 | if ((len = tpm_transmit(chip, data, sizeof(data))) | 690 | data[TPM_CAP_IDX] = TPM_CAP_PROP; |
155 | < CAP_PCR_RESULT_SIZE) { | 691 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR; |
156 | dev_dbg(chip->dev, "A TPM error (%d) occurred " | 692 | |
157 | "attempting to determine the number of PCRS\n", | 693 | rc = transmit_cmd(chip, data, sizeof(data), |
158 | be32_to_cpu(*((__be32 *) (data + 6)))); | 694 | "attempting to determine the number of PCRS"); |
695 | if (rc) | ||
159 | return 0; | 696 | return 0; |
160 | } | ||
161 | 697 | ||
162 | num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); | 698 | num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); |
163 | |||
164 | for (i = 0; i < num_pcrs; i++) { | 699 | for (i = 0; i < num_pcrs; i++) { |
165 | memcpy(data, pcrread, sizeof(pcrread)); | 700 | memcpy(data, pcrread, sizeof(pcrread)); |
166 | index = cpu_to_be32(i); | 701 | index = cpu_to_be32(i); |
167 | memcpy(data + 10, &index, 4); | 702 | memcpy(data + 10, &index, 4); |
168 | if ((len = tpm_transmit(chip, data, sizeof(data))) | 703 | rc = transmit_cmd(chip, data, sizeof(data), |
169 | < READ_PCR_RESULT_SIZE){ | 704 | "attempting to read a PCR"); |
170 | dev_dbg(chip->dev, "A TPM error (%d) occurred" | 705 | if (rc) |
171 | " attempting to read PCR %d of %d\n", | ||
172 | be32_to_cpu(*((__be32 *) (data + 6))), | ||
173 | i, num_pcrs); | ||
174 | goto out; | 706 | goto out; |
175 | } | ||
176 | str += sprintf(str, "PCR-%02d: ", i); | 707 | str += sprintf(str, "PCR-%02d: ", i); |
177 | for (j = 0; j < TPM_DIGEST_SIZE; j++) | 708 | for (j = 0; j < TPM_DIGEST_SIZE; j++) |
178 | str += sprintf(str, "%02X ", *(data + 10 + j)); | 709 | str += sprintf(str, "%02X ", *(data + 10 + j)); |
@@ -194,7 +725,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
194 | char *buf) | 725 | char *buf) |
195 | { | 726 | { |
196 | u8 *data; | 727 | u8 *data; |
197 | ssize_t len; | 728 | ssize_t err; |
198 | int i, rc; | 729 | int i, rc; |
199 | char *str = buf; | 730 | char *str = buf; |
200 | 731 | ||
@@ -208,14 +739,10 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
208 | 739 | ||
209 | memcpy(data, readpubek, sizeof(readpubek)); | 740 | memcpy(data, readpubek, sizeof(readpubek)); |
210 | 741 | ||
211 | if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) < | 742 | err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE, |
212 | READ_PUBEK_RESULT_SIZE) { | 743 | "attempting to read the PUBEK"); |
213 | dev_dbg(chip->dev, "A TPM error (%d) occurred " | 744 | if (err) |
214 | "attempting to read the PUBEK\n", | ||
215 | be32_to_cpu(*((__be32 *) (data + 6)))); | ||
216 | rc = 0; | ||
217 | goto out; | 745 | goto out; |
218 | } | ||
219 | 746 | ||
220 | /* | 747 | /* |
221 | ignore header 10 bytes | 748 | ignore header 10 bytes |
@@ -245,67 +772,110 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
245 | if ((i + 1) % 16 == 0) | 772 | if ((i + 1) % 16 == 0) |
246 | str += sprintf(str, "\n"); | 773 | str += sprintf(str, "\n"); |
247 | } | 774 | } |
248 | rc = str - buf; | ||
249 | out: | 775 | out: |
776 | rc = str - buf; | ||
250 | kfree(data); | 777 | kfree(data); |
251 | return rc; | 778 | return rc; |
252 | } | 779 | } |
253 | EXPORT_SYMBOL_GPL(tpm_show_pubek); | 780 | EXPORT_SYMBOL_GPL(tpm_show_pubek); |
254 | 781 | ||
255 | #define CAP_VER_RESULT_SIZE 18 | 782 | #define CAP_VERSION_1_1 6 |
783 | #define CAP_VERSION_1_2 0x1A | ||
784 | #define CAP_VERSION_IDX 13 | ||
256 | static const u8 cap_version[] = { | 785 | static const u8 cap_version[] = { |
257 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 786 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
258 | 0, 0, 0, 18, /* length */ | 787 | 0, 0, 0, 18, /* length */ |
259 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | 788 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ |
260 | 0, 0, 0, 6, | 789 | 0, 0, 0, 0, |
261 | 0, 0, 0, 0 | 790 | 0, 0, 0, 0 |
262 | }; | 791 | }; |
263 | 792 | ||
264 | #define CAP_MANUFACTURER_RESULT_SIZE 18 | ||
265 | static const u8 cap_manufacturer[] = { | ||
266 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | ||
267 | 0, 0, 0, 22, /* length */ | ||
268 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | ||
269 | 0, 0, 0, 5, | ||
270 | 0, 0, 0, 4, | ||
271 | 0, 0, 1, 3 | ||
272 | }; | ||
273 | |||
274 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, | 793 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, |
275 | char *buf) | 794 | char *buf) |
276 | { | 795 | { |
277 | u8 data[sizeof(cap_manufacturer)]; | 796 | u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)]; |
278 | ssize_t len; | 797 | ssize_t rc; |
279 | char *str = buf; | 798 | char *str = buf; |
280 | 799 | ||
281 | struct tpm_chip *chip = dev_get_drvdata(dev); | 800 | struct tpm_chip *chip = dev_get_drvdata(dev); |
282 | if (chip == NULL) | 801 | if (chip == NULL) |
283 | return -ENODEV; | 802 | return -ENODEV; |
284 | 803 | ||
285 | memcpy(data, cap_manufacturer, sizeof(cap_manufacturer)); | 804 | memcpy(data, tpm_cap, sizeof(tpm_cap)); |
805 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
806 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; | ||
286 | 807 | ||
287 | if ((len = tpm_transmit(chip, data, sizeof(data))) < | 808 | rc = transmit_cmd(chip, data, sizeof(data), |
288 | CAP_MANUFACTURER_RESULT_SIZE) | 809 | "attempting to determine the manufacturer"); |
289 | return len; | 810 | if (rc) |
811 | return 0; | ||
290 | 812 | ||
291 | str += sprintf(str, "Manufacturer: 0x%x\n", | 813 | str += sprintf(str, "Manufacturer: 0x%x\n", |
292 | be32_to_cpu(*((__be32 *) (data + 14)))); | 814 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); |
293 | 815 | ||
294 | memcpy(data, cap_version, sizeof(cap_version)); | 816 | memcpy(data, cap_version, sizeof(cap_version)); |
817 | data[CAP_VERSION_IDX] = CAP_VERSION_1_1; | ||
818 | rc = transmit_cmd(chip, data, sizeof(data), | ||
819 | "attempting to determine the 1.1 version"); | ||
820 | if (rc) | ||
821 | goto out; | ||
295 | 822 | ||
296 | if ((len = tpm_transmit(chip, data, sizeof(data))) < | 823 | str += sprintf(str, |
297 | CAP_VER_RESULT_SIZE) | 824 | "TCG version: %d.%d\nFirmware version: %d.%d\n", |
298 | return len; | 825 | (int) data[14], (int) data[15], (int) data[16], |
299 | 826 | (int) data[17]); | |
300 | str += | ||
301 | sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n", | ||
302 | (int) data[14], (int) data[15], (int) data[16], | ||
303 | (int) data[17]); | ||
304 | 827 | ||
828 | out: | ||
305 | return str - buf; | 829 | return str - buf; |
306 | } | 830 | } |
307 | EXPORT_SYMBOL_GPL(tpm_show_caps); | 831 | EXPORT_SYMBOL_GPL(tpm_show_caps); |
308 | 832 | ||
833 | ssize_t tpm_show_caps_1_2(struct device * dev, | ||
834 | struct device_attribute * attr, char *buf) | ||
835 | { | ||
836 | u8 data[max_t(int, max(ARRAY_SIZE(tpm_cap), ARRAY_SIZE(cap_version)), 30)]; | ||
837 | ssize_t len; | ||
838 | char *str = buf; | ||
839 | |||
840 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
841 | if (chip == NULL) | ||
842 | return -ENODEV; | ||
843 | |||
844 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
845 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
846 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; | ||
847 | |||
848 | if ((len = tpm_transmit(chip, data, sizeof(data))) <= | ||
849 | TPM_ERROR_SIZE) { | ||
850 | dev_dbg(chip->dev, "A TPM error (%d) occurred " | ||
851 | "attempting to determine the manufacturer\n", | ||
852 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); | ||
853 | return 0; | ||
854 | } | ||
855 | |||
856 | str += sprintf(str, "Manufacturer: 0x%x\n", | ||
857 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); | ||
858 | |||
859 | memcpy(data, cap_version, sizeof(cap_version)); | ||
860 | data[CAP_VERSION_IDX] = CAP_VERSION_1_2; | ||
861 | |||
862 | if ((len = tpm_transmit(chip, data, sizeof(data))) <= | ||
863 | TPM_ERROR_SIZE) { | ||
864 | dev_err(chip->dev, "A TPM error (%d) occurred " | ||
865 | "attempting to determine the 1.2 version\n", | ||
866 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); | ||
867 | goto out; | ||
868 | } | ||
869 | str += sprintf(str, | ||
870 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | ||
871 | (int) data[16], (int) data[17], (int) data[18], | ||
872 | (int) data[19]); | ||
873 | |||
874 | out: | ||
875 | return str - buf; | ||
876 | } | ||
877 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); | ||
878 | |||
309 | ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, | 879 | ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, |
310 | const char *buf, size_t count) | 880 | const char *buf, size_t count) |
311 | { | 881 | { |
@@ -313,7 +883,7 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, | |||
313 | if (chip == NULL) | 883 | if (chip == NULL) |
314 | return 0; | 884 | return 0; |
315 | 885 | ||
316 | chip->vendor->cancel(chip); | 886 | chip->vendor.cancel(chip); |
317 | return count; | 887 | return count; |
318 | } | 888 | } |
319 | EXPORT_SYMBOL_GPL(tpm_store_cancel); | 889 | EXPORT_SYMBOL_GPL(tpm_store_cancel); |
@@ -329,7 +899,7 @@ int tpm_open(struct inode *inode, struct file *file) | |||
329 | spin_lock(&driver_lock); | 899 | spin_lock(&driver_lock); |
330 | 900 | ||
331 | list_for_each_entry(pos, &tpm_chip_list, list) { | 901 | list_for_each_entry(pos, &tpm_chip_list, list) { |
332 | if (pos->vendor->miscdev.minor == minor) { | 902 | if (pos->vendor.miscdev.minor == minor) { |
333 | chip = pos; | 903 | chip = pos; |
334 | break; | 904 | break; |
335 | } | 905 | } |
@@ -387,7 +957,7 @@ int tpm_release(struct inode *inode, struct file *file) | |||
387 | EXPORT_SYMBOL_GPL(tpm_release); | 957 | EXPORT_SYMBOL_GPL(tpm_release); |
388 | 958 | ||
389 | ssize_t tpm_write(struct file *file, const char __user *buf, | 959 | ssize_t tpm_write(struct file *file, const char __user *buf, |
390 | size_t size, loff_t * off) | 960 | size_t size, loff_t *off) |
391 | { | 961 | { |
392 | struct tpm_chip *chip = file->private_data; | 962 | struct tpm_chip *chip = file->private_data; |
393 | int in_size = size, out_size; | 963 | int in_size = size, out_size; |
@@ -419,11 +989,10 @@ ssize_t tpm_write(struct file *file, const char __user *buf, | |||
419 | 989 | ||
420 | return in_size; | 990 | return in_size; |
421 | } | 991 | } |
422 | |||
423 | EXPORT_SYMBOL_GPL(tpm_write); | 992 | EXPORT_SYMBOL_GPL(tpm_write); |
424 | 993 | ||
425 | ssize_t tpm_read(struct file * file, char __user *buf, | 994 | ssize_t tpm_read(struct file *file, char __user *buf, |
426 | size_t size, loff_t * off) | 995 | size_t size, loff_t *off) |
427 | { | 996 | { |
428 | struct tpm_chip *chip = file->private_data; | 997 | struct tpm_chip *chip = file->private_data; |
429 | int ret_size; | 998 | int ret_size; |
@@ -462,14 +1031,13 @@ void tpm_remove_hardware(struct device *dev) | |||
462 | spin_unlock(&driver_lock); | 1031 | spin_unlock(&driver_lock); |
463 | 1032 | ||
464 | dev_set_drvdata(dev, NULL); | 1033 | dev_set_drvdata(dev, NULL); |
465 | misc_deregister(&chip->vendor->miscdev); | 1034 | misc_deregister(&chip->vendor.miscdev); |
466 | kfree(chip->vendor->miscdev.name); | 1035 | kfree(chip->vendor.miscdev.name); |
467 | 1036 | ||
468 | sysfs_remove_group(&dev->kobj, chip->vendor->attr_group); | 1037 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); |
469 | tpm_bios_log_teardown(chip->bios_dir); | 1038 | tpm_bios_log_teardown(chip->bios_dir); |
470 | 1039 | ||
471 | dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= | 1040 | clear_bit(chip->dev_num, dev_mask); |
472 | ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); | ||
473 | 1041 | ||
474 | kfree(chip); | 1042 | kfree(chip); |
475 | 1043 | ||
@@ -520,18 +1088,18 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume); | |||
520 | * upon errant exit from this function specific probe function should call | 1088 | * upon errant exit from this function specific probe function should call |
521 | * pci_disable_device | 1089 | * pci_disable_device |
522 | */ | 1090 | */ |
523 | int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry) | 1091 | struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific |
1092 | *entry) | ||
524 | { | 1093 | { |
525 | #define DEVNAME_SIZE 7 | 1094 | #define DEVNAME_SIZE 7 |
526 | 1095 | ||
527 | char *devname; | 1096 | char *devname; |
528 | struct tpm_chip *chip; | 1097 | struct tpm_chip *chip; |
529 | int i, j; | ||
530 | 1098 | ||
531 | /* Driver specific per-device data */ | 1099 | /* Driver specific per-device data */ |
532 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 1100 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
533 | if (chip == NULL) | 1101 | if (chip == NULL) |
534 | return -ENOMEM; | 1102 | return NULL; |
535 | 1103 | ||
536 | init_MUTEX(&chip->buffer_mutex); | 1104 | init_MUTEX(&chip->buffer_mutex); |
537 | init_MUTEX(&chip->tpm_mutex); | 1105 | init_MUTEX(&chip->tpm_mutex); |
@@ -543,45 +1111,37 @@ int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry) | |||
543 | chip->user_read_timer.function = user_reader_timeout; | 1111 | chip->user_read_timer.function = user_reader_timeout; |
544 | chip->user_read_timer.data = (unsigned long) chip; | 1112 | chip->user_read_timer.data = (unsigned long) chip; |
545 | 1113 | ||
546 | chip->vendor = entry; | 1114 | memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); |
547 | |||
548 | chip->dev_num = -1; | ||
549 | 1115 | ||
550 | for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++) | 1116 | chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); |
551 | for (j = 0; j < 8 * sizeof(int); j++) | ||
552 | if ((dev_mask[i] & (1 << j)) == 0) { | ||
553 | chip->dev_num = | ||
554 | i * TPM_NUM_MASK_ENTRIES + j; | ||
555 | dev_mask[i] |= 1 << j; | ||
556 | goto dev_num_search_complete; | ||
557 | } | ||
558 | 1117 | ||
559 | dev_num_search_complete: | 1118 | if (chip->dev_num >= TPM_NUM_DEVICES) { |
560 | if (chip->dev_num < 0) { | ||
561 | dev_err(dev, "No available tpm device numbers\n"); | 1119 | dev_err(dev, "No available tpm device numbers\n"); |
562 | kfree(chip); | 1120 | kfree(chip); |
563 | return -ENODEV; | 1121 | return NULL; |
564 | } else if (chip->dev_num == 0) | 1122 | } else if (chip->dev_num == 0) |
565 | chip->vendor->miscdev.minor = TPM_MINOR; | 1123 | chip->vendor.miscdev.minor = TPM_MINOR; |
566 | else | 1124 | else |
567 | chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR; | 1125 | chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; |
1126 | |||
1127 | set_bit(chip->dev_num, dev_mask); | ||
568 | 1128 | ||
569 | devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); | 1129 | devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); |
570 | scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); | 1130 | scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); |
571 | chip->vendor->miscdev.name = devname; | 1131 | chip->vendor.miscdev.name = devname; |
572 | 1132 | ||
573 | chip->vendor->miscdev.dev = dev; | 1133 | chip->vendor.miscdev.dev = dev; |
574 | chip->dev = get_device(dev); | 1134 | chip->dev = get_device(dev); |
575 | 1135 | ||
576 | if (misc_register(&chip->vendor->miscdev)) { | 1136 | if (misc_register(&chip->vendor.miscdev)) { |
577 | dev_err(chip->dev, | 1137 | dev_err(chip->dev, |
578 | "unable to misc_register %s, minor %d\n", | 1138 | "unable to misc_register %s, minor %d\n", |
579 | chip->vendor->miscdev.name, | 1139 | chip->vendor.miscdev.name, |
580 | chip->vendor->miscdev.minor); | 1140 | chip->vendor.miscdev.minor); |
581 | put_device(dev); | 1141 | put_device(dev); |
1142 | clear_bit(chip->dev_num, dev_mask); | ||
582 | kfree(chip); | 1143 | kfree(chip); |
583 | dev_mask[i] &= !(1 << j); | 1144 | return NULL; |
584 | return -ENODEV; | ||
585 | } | 1145 | } |
586 | 1146 | ||
587 | spin_lock(&driver_lock); | 1147 | spin_lock(&driver_lock); |
@@ -592,11 +1152,11 @@ dev_num_search_complete: | |||
592 | 1152 | ||
593 | spin_unlock(&driver_lock); | 1153 | spin_unlock(&driver_lock); |
594 | 1154 | ||
595 | sysfs_create_group(&dev->kobj, chip->vendor->attr_group); | 1155 | sysfs_create_group(&dev->kobj, chip->vendor.attr_group); |
596 | 1156 | ||
597 | chip->bios_dir = tpm_bios_log_setup(devname); | 1157 | chip->bios_dir = tpm_bios_log_setup(devname); |
598 | 1158 | ||
599 | return 0; | 1159 | return chip; |
600 | } | 1160 | } |
601 | EXPORT_SYMBOL_GPL(tpm_register_hardware); | 1161 | EXPORT_SYMBOL_GPL(tpm_register_hardware); |
602 | 1162 | ||