Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
48f0ed1b MH |
2 | /* |
3 | * | |
4 | * Bluetooth support for Intel devices | |
5 | * | |
6 | * Copyright (C) 2015 Intel Corporation | |
48f0ed1b MH |
7 | */ |
8 | ||
9 | #include <linux/module.h> | |
145f2368 | 10 | #include <linux/firmware.h> |
d06f107b | 11 | #include <linux/regmap.h> |
fbbe83c5 | 12 | #include <asm/unaligned.h> |
48f0ed1b MH |
13 | |
14 | #include <net/bluetooth/bluetooth.h> | |
15 | #include <net/bluetooth/hci_core.h> | |
16 | ||
17 | #include "btintel.h" | |
18 | ||
19 | #define VERSION "0.1" | |
20 | ||
81ebea53 K |
21 | #define BDADDR_INTEL (&(bdaddr_t){{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}}) |
22 | #define RSA_HEADER_LEN 644 | |
23 | #define CSS_HEADER_OFFSET 8 | |
24 | #define ECDSA_OFFSET 644 | |
25 | #define ECDSA_HEADER_LEN 320 | |
48f0ed1b MH |
26 | |
27 | int btintel_check_bdaddr(struct hci_dev *hdev) | |
28 | { | |
29 | struct hci_rp_read_bd_addr *bda; | |
30 | struct sk_buff *skb; | |
31 | ||
32 | skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, | |
33 | HCI_INIT_TIMEOUT); | |
34 | if (IS_ERR(skb)) { | |
35 | int err = PTR_ERR(skb); | |
2064ee33 MH |
36 | bt_dev_err(hdev, "Reading Intel device address failed (%d)", |
37 | err); | |
48f0ed1b MH |
38 | return err; |
39 | } | |
40 | ||
41 | if (skb->len != sizeof(*bda)) { | |
2064ee33 | 42 | bt_dev_err(hdev, "Intel device address length mismatch"); |
48f0ed1b MH |
43 | kfree_skb(skb); |
44 | return -EIO; | |
45 | } | |
46 | ||
47 | bda = (struct hci_rp_read_bd_addr *)skb->data; | |
48f0ed1b MH |
48 | |
49 | /* For some Intel based controllers, the default Bluetooth device | |
50 | * address 00:03:19:9E:8B:00 can be found. These controllers are | |
51 | * fully operational, but have the danger of duplicate addresses | |
52 | * and that in turn can cause problems with Bluetooth operation. | |
53 | */ | |
54 | if (!bacmp(&bda->bdaddr, BDADDR_INTEL)) { | |
2064ee33 MH |
55 | bt_dev_err(hdev, "Found Intel default device address (%pMR)", |
56 | &bda->bdaddr); | |
48f0ed1b MH |
57 | set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); |
58 | } | |
59 | ||
60 | kfree_skb(skb); | |
61 | ||
62 | return 0; | |
63 | } | |
64 | EXPORT_SYMBOL_GPL(btintel_check_bdaddr); | |
65 | ||
28dc4b92 LP |
66 | int btintel_enter_mfg(struct hci_dev *hdev) |
67 | { | |
948c7ca0 | 68 | static const u8 param[] = { 0x01, 0x00 }; |
28dc4b92 LP |
69 | struct sk_buff *skb; |
70 | ||
71 | skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT); | |
72 | if (IS_ERR(skb)) { | |
73 | bt_dev_err(hdev, "Entering manufacturer mode failed (%ld)", | |
74 | PTR_ERR(skb)); | |
75 | return PTR_ERR(skb); | |
76 | } | |
77 | kfree_skb(skb); | |
78 | ||
79 | return 0; | |
80 | } | |
81 | EXPORT_SYMBOL_GPL(btintel_enter_mfg); | |
82 | ||
83 | int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched) | |
84 | { | |
85 | u8 param[] = { 0x00, 0x00 }; | |
86 | struct sk_buff *skb; | |
87 | ||
88 | /* The 2nd command parameter specifies the manufacturing exit method: | |
89 | * 0x00: Just disable the manufacturing mode (0x00). | |
90 | * 0x01: Disable manufacturing mode and reset with patches deactivated. | |
91 | * 0x02: Disable manufacturing mode and reset with patches activated. | |
92 | */ | |
93 | if (reset) | |
94 | param[1] |= patched ? 0x02 : 0x01; | |
95 | ||
96 | skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT); | |
97 | if (IS_ERR(skb)) { | |
98 | bt_dev_err(hdev, "Exiting manufacturer mode failed (%ld)", | |
99 | PTR_ERR(skb)); | |
100 | return PTR_ERR(skb); | |
101 | } | |
102 | kfree_skb(skb); | |
103 | ||
104 | return 0; | |
105 | } | |
106 | EXPORT_SYMBOL_GPL(btintel_exit_mfg); | |
107 | ||
48f0ed1b MH |
108 | int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) |
109 | { | |
110 | struct sk_buff *skb; | |
111 | int err; | |
112 | ||
113 | skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); | |
114 | if (IS_ERR(skb)) { | |
115 | err = PTR_ERR(skb); | |
2064ee33 MH |
116 | bt_dev_err(hdev, "Changing Intel device address failed (%d)", |
117 | err); | |
48f0ed1b MH |
118 | return err; |
119 | } | |
120 | kfree_skb(skb); | |
121 | ||
122 | return 0; | |
123 | } | |
124 | EXPORT_SYMBOL_GPL(btintel_set_bdaddr); | |
125 | ||
6d2e50d2 MH |
126 | int btintel_set_diag(struct hci_dev *hdev, bool enable) |
127 | { | |
128 | struct sk_buff *skb; | |
129 | u8 param[3]; | |
130 | int err; | |
131 | ||
6d2e50d2 MH |
132 | if (enable) { |
133 | param[0] = 0x03; | |
134 | param[1] = 0x03; | |
135 | param[2] = 0x03; | |
136 | } else { | |
137 | param[0] = 0x00; | |
138 | param[1] = 0x00; | |
139 | param[2] = 0x00; | |
140 | } | |
141 | ||
142 | skb = __hci_cmd_sync(hdev, 0xfc43, 3, param, HCI_INIT_TIMEOUT); | |
143 | if (IS_ERR(skb)) { | |
144 | err = PTR_ERR(skb); | |
d8270fbb | 145 | if (err == -ENODATA) |
213445b2 | 146 | goto done; |
2064ee33 MH |
147 | bt_dev_err(hdev, "Changing Intel diagnostic mode failed (%d)", |
148 | err); | |
6d2e50d2 MH |
149 | return err; |
150 | } | |
151 | kfree_skb(skb); | |
152 | ||
213445b2 MH |
153 | done: |
154 | btintel_set_event_mask(hdev, enable); | |
6d2e50d2 MH |
155 | return 0; |
156 | } | |
157 | EXPORT_SYMBOL_GPL(btintel_set_diag); | |
158 | ||
3e24767b MH |
159 | int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable) |
160 | { | |
28dc4b92 | 161 | int err, ret; |
3e24767b | 162 | |
28dc4b92 LP |
163 | err = btintel_enter_mfg(hdev); |
164 | if (err) | |
165 | return err; | |
3e24767b | 166 | |
28dc4b92 | 167 | ret = btintel_set_diag(hdev, enable); |
3e24767b | 168 | |
28dc4b92 LP |
169 | err = btintel_exit_mfg(hdev, false, false); |
170 | if (err) | |
171 | return err; | |
3e24767b | 172 | |
28dc4b92 | 173 | return ret; |
3e24767b MH |
174 | } |
175 | EXPORT_SYMBOL_GPL(btintel_set_diag_mfg); | |
176 | ||
973bb97e MH |
177 | void btintel_hw_error(struct hci_dev *hdev, u8 code) |
178 | { | |
179 | struct sk_buff *skb; | |
180 | u8 type = 0x00; | |
181 | ||
2064ee33 | 182 | bt_dev_err(hdev, "Hardware error 0x%2.2x", code); |
973bb97e MH |
183 | |
184 | skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); | |
185 | if (IS_ERR(skb)) { | |
2064ee33 MH |
186 | bt_dev_err(hdev, "Reset after hardware error failed (%ld)", |
187 | PTR_ERR(skb)); | |
973bb97e MH |
188 | return; |
189 | } | |
190 | kfree_skb(skb); | |
191 | ||
192 | skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT); | |
193 | if (IS_ERR(skb)) { | |
2064ee33 MH |
194 | bt_dev_err(hdev, "Retrieving Intel exception info failed (%ld)", |
195 | PTR_ERR(skb)); | |
973bb97e MH |
196 | return; |
197 | } | |
198 | ||
199 | if (skb->len != 13) { | |
2064ee33 | 200 | bt_dev_err(hdev, "Exception info size mismatch"); |
973bb97e MH |
201 | kfree_skb(skb); |
202 | return; | |
203 | } | |
204 | ||
2064ee33 | 205 | bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1)); |
973bb97e MH |
206 | |
207 | kfree_skb(skb); | |
208 | } | |
209 | EXPORT_SYMBOL_GPL(btintel_hw_error); | |
210 | ||
7feb99e1 MH |
211 | void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver) |
212 | { | |
213 | const char *variant; | |
214 | ||
215 | switch (ver->fw_variant) { | |
216 | case 0x06: | |
217 | variant = "Bootloader"; | |
218 | break; | |
219 | case 0x23: | |
220 | variant = "Firmware"; | |
221 | break; | |
222 | default: | |
223 | return; | |
224 | } | |
225 | ||
2064ee33 MH |
226 | bt_dev_info(hdev, "%s revision %u.%u build %u week %u %u", |
227 | variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, | |
228 | ver->fw_build_num, ver->fw_build_ww, | |
229 | 2000 + ver->fw_build_yy); | |
7feb99e1 MH |
230 | } |
231 | EXPORT_SYMBOL_GPL(btintel_version_info); | |
232 | ||
09df123d MH |
233 | int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, |
234 | const void *param) | |
235 | { | |
236 | while (plen > 0) { | |
237 | struct sk_buff *skb; | |
238 | u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; | |
239 | ||
240 | cmd_param[0] = fragment_type; | |
241 | memcpy(cmd_param + 1, param, fragment_len); | |
242 | ||
243 | skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1, | |
244 | cmd_param, HCI_INIT_TIMEOUT); | |
245 | if (IS_ERR(skb)) | |
246 | return PTR_ERR(skb); | |
247 | ||
248 | kfree_skb(skb); | |
249 | ||
250 | plen -= fragment_len; | |
251 | param += fragment_len; | |
252 | } | |
253 | ||
254 | return 0; | |
255 | } | |
256 | EXPORT_SYMBOL_GPL(btintel_secure_send); | |
257 | ||
145f2368 LP |
258 | int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name) |
259 | { | |
260 | const struct firmware *fw; | |
261 | struct sk_buff *skb; | |
262 | const u8 *fw_ptr; | |
263 | int err; | |
264 | ||
265 | err = request_firmware_direct(&fw, ddc_name, &hdev->dev); | |
266 | if (err < 0) { | |
267 | bt_dev_err(hdev, "Failed to load Intel DDC file %s (%d)", | |
268 | ddc_name, err); | |
269 | return err; | |
270 | } | |
271 | ||
272 | bt_dev_info(hdev, "Found Intel DDC parameters: %s", ddc_name); | |
273 | ||
274 | fw_ptr = fw->data; | |
275 | ||
276 | /* DDC file contains one or more DDC structure which has | |
277 | * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2). | |
278 | */ | |
279 | while (fw->size > fw_ptr - fw->data) { | |
280 | u8 cmd_plen = fw_ptr[0] + sizeof(u8); | |
281 | ||
282 | skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr, | |
283 | HCI_INIT_TIMEOUT); | |
284 | if (IS_ERR(skb)) { | |
285 | bt_dev_err(hdev, "Failed to send Intel_Write_DDC (%ld)", | |
286 | PTR_ERR(skb)); | |
287 | release_firmware(fw); | |
288 | return PTR_ERR(skb); | |
289 | } | |
290 | ||
291 | fw_ptr += cmd_plen; | |
292 | kfree_skb(skb); | |
293 | } | |
294 | ||
295 | release_firmware(fw); | |
296 | ||
297 | bt_dev_info(hdev, "Applying Intel DDC parameters completed"); | |
298 | ||
299 | return 0; | |
300 | } | |
301 | EXPORT_SYMBOL_GPL(btintel_load_ddc_config); | |
302 | ||
213445b2 MH |
303 | int btintel_set_event_mask(struct hci_dev *hdev, bool debug) |
304 | { | |
305 | u8 mask[8] = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
306 | struct sk_buff *skb; | |
307 | int err; | |
308 | ||
309 | if (debug) | |
310 | mask[1] |= 0x62; | |
311 | ||
312 | skb = __hci_cmd_sync(hdev, 0xfc52, 8, mask, HCI_INIT_TIMEOUT); | |
313 | if (IS_ERR(skb)) { | |
314 | err = PTR_ERR(skb); | |
2064ee33 | 315 | bt_dev_err(hdev, "Setting Intel event mask failed (%d)", err); |
213445b2 MH |
316 | return err; |
317 | } | |
318 | kfree_skb(skb); | |
319 | ||
320 | return 0; | |
321 | } | |
322 | EXPORT_SYMBOL_GPL(btintel_set_event_mask); | |
323 | ||
324 | int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug) | |
325 | { | |
28dc4b92 | 326 | int err, ret; |
213445b2 | 327 | |
28dc4b92 LP |
328 | err = btintel_enter_mfg(hdev); |
329 | if (err) | |
330 | return err; | |
213445b2 | 331 | |
28dc4b92 | 332 | ret = btintel_set_event_mask(hdev, debug); |
213445b2 | 333 | |
28dc4b92 LP |
334 | err = btintel_exit_mfg(hdev, false, false); |
335 | if (err) | |
336 | return err; | |
213445b2 | 337 | |
28dc4b92 | 338 | return ret; |
213445b2 MH |
339 | } |
340 | EXPORT_SYMBOL_GPL(btintel_set_event_mask_mfg); | |
341 | ||
6c483de1 LP |
342 | int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver) |
343 | { | |
344 | struct sk_buff *skb; | |
345 | ||
346 | skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_CMD_TIMEOUT); | |
347 | if (IS_ERR(skb)) { | |
348 | bt_dev_err(hdev, "Reading Intel version information failed (%ld)", | |
349 | PTR_ERR(skb)); | |
350 | return PTR_ERR(skb); | |
351 | } | |
352 | ||
353 | if (skb->len != sizeof(*ver)) { | |
354 | bt_dev_err(hdev, "Intel version event size mismatch"); | |
355 | kfree_skb(skb); | |
356 | return -EILSEQ; | |
357 | } | |
358 | ||
359 | memcpy(ver, skb->data, sizeof(*ver)); | |
360 | ||
361 | kfree_skb(skb); | |
362 | ||
363 | return 0; | |
364 | } | |
365 | EXPORT_SYMBOL_GPL(btintel_read_version); | |
366 | ||
57375bee K |
367 | void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version) |
368 | { | |
369 | const char *variant; | |
370 | ||
371 | switch (version->img_type) { | |
372 | case 0x01: | |
373 | variant = "Bootloader"; | |
374 | bt_dev_info(hdev, "Device revision is %u", version->dev_rev_id); | |
375 | bt_dev_info(hdev, "Secure boot is %s", | |
376 | version->secure_boot ? "enabled" : "disabled"); | |
377 | bt_dev_info(hdev, "OTP lock is %s", | |
378 | version->otp_lock ? "enabled" : "disabled"); | |
379 | bt_dev_info(hdev, "API lock is %s", | |
380 | version->api_lock ? "enabled" : "disabled"); | |
381 | bt_dev_info(hdev, "Debug lock is %s", | |
382 | version->debug_lock ? "enabled" : "disabled"); | |
383 | bt_dev_info(hdev, "Minimum firmware build %u week %u %u", | |
384 | version->min_fw_build_nn, version->min_fw_build_cw, | |
385 | 2000 + version->min_fw_build_yy); | |
386 | break; | |
387 | case 0x03: | |
388 | variant = "Firmware"; | |
389 | break; | |
390 | default: | |
391 | bt_dev_err(hdev, "Unsupported image type(%02x)", version->img_type); | |
392 | goto done; | |
393 | } | |
394 | ||
395 | bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant, | |
396 | 2000 + (version->timestamp >> 8), version->timestamp & 0xff, | |
397 | version->build_type, version->build_num); | |
398 | ||
399 | done: | |
400 | return; | |
401 | } | |
402 | EXPORT_SYMBOL_GPL(btintel_version_info_tlv); | |
403 | ||
404 | int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *version) | |
405 | { | |
406 | struct sk_buff *skb; | |
407 | const u8 param[1] = { 0xFF }; | |
408 | ||
409 | if (!version) | |
410 | return -EINVAL; | |
411 | ||
412 | skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT); | |
413 | if (IS_ERR(skb)) { | |
414 | bt_dev_err(hdev, "Reading Intel version information failed (%ld)", | |
415 | PTR_ERR(skb)); | |
416 | return PTR_ERR(skb); | |
417 | } | |
418 | ||
419 | if (skb->data[0]) { | |
420 | bt_dev_err(hdev, "Intel Read Version command failed (%02x)", | |
421 | skb->data[0]); | |
422 | kfree_skb(skb); | |
423 | return -EIO; | |
424 | } | |
425 | ||
426 | /* Consume Command Complete Status field */ | |
427 | skb_pull(skb, 1); | |
428 | ||
429 | /* Event parameters contatin multiple TLVs. Read each of them | |
430 | * and only keep the required data. Also, it use existing legacy | |
431 | * version field like hw_platform, hw_variant, and fw_variant | |
432 | * to keep the existing setup flow | |
433 | */ | |
434 | while (skb->len) { | |
435 | struct intel_tlv *tlv; | |
436 | ||
437 | tlv = (struct intel_tlv *)skb->data; | |
438 | switch (tlv->type) { | |
439 | case INTEL_TLV_CNVI_TOP: | |
66500bbc K |
440 | version->cnvi_top = |
441 | __le32_to_cpu(get_unaligned_le32(tlv->val)); | |
57375bee K |
442 | break; |
443 | case INTEL_TLV_CNVR_TOP: | |
66500bbc K |
444 | version->cnvr_top = |
445 | __le32_to_cpu(get_unaligned_le32(tlv->val)); | |
57375bee K |
446 | break; |
447 | case INTEL_TLV_CNVI_BT: | |
66500bbc K |
448 | version->cnvi_bt = |
449 | __le32_to_cpu(get_unaligned_le32(tlv->val)); | |
57375bee K |
450 | break; |
451 | case INTEL_TLV_CNVR_BT: | |
66500bbc K |
452 | version->cnvr_bt = |
453 | __le32_to_cpu(get_unaligned_le32(tlv->val)); | |
57375bee K |
454 | break; |
455 | case INTEL_TLV_DEV_REV_ID: | |
66500bbc K |
456 | version->dev_rev_id = |
457 | __le16_to_cpu(get_unaligned_le16(tlv->val)); | |
57375bee K |
458 | break; |
459 | case INTEL_TLV_IMAGE_TYPE: | |
460 | version->img_type = tlv->val[0]; | |
461 | break; | |
462 | case INTEL_TLV_TIME_STAMP: | |
66500bbc K |
463 | version->timestamp = |
464 | __le16_to_cpu(get_unaligned_le16(tlv->val)); | |
57375bee K |
465 | break; |
466 | case INTEL_TLV_BUILD_TYPE: | |
467 | version->build_type = tlv->val[0]; | |
468 | break; | |
469 | case INTEL_TLV_BUILD_NUM: | |
66500bbc K |
470 | version->build_num = |
471 | __le32_to_cpu(get_unaligned_le32(tlv->val)); | |
57375bee K |
472 | break; |
473 | case INTEL_TLV_SECURE_BOOT: | |
474 | version->secure_boot = tlv->val[0]; | |
475 | break; | |
476 | case INTEL_TLV_OTP_LOCK: | |
477 | version->otp_lock = tlv->val[0]; | |
478 | break; | |
479 | case INTEL_TLV_API_LOCK: | |
480 | version->api_lock = tlv->val[0]; | |
481 | break; | |
482 | case INTEL_TLV_DEBUG_LOCK: | |
483 | version->debug_lock = tlv->val[0]; | |
484 | break; | |
485 | case INTEL_TLV_MIN_FW: | |
486 | version->min_fw_build_nn = tlv->val[0]; | |
487 | version->min_fw_build_cw = tlv->val[1]; | |
488 | version->min_fw_build_yy = tlv->val[2]; | |
489 | break; | |
490 | case INTEL_TLV_LIMITED_CCE: | |
491 | version->limited_cce = tlv->val[0]; | |
492 | break; | |
493 | case INTEL_TLV_SBE_TYPE: | |
494 | version->sbe_type = tlv->val[0]; | |
495 | break; | |
496 | case INTEL_TLV_OTP_BDADDR: | |
497 | memcpy(&version->otp_bd_addr, tlv->val, tlv->len); | |
498 | break; | |
499 | default: | |
500 | /* Ignore rest of information */ | |
501 | break; | |
502 | } | |
503 | /* consume the current tlv and move to next*/ | |
504 | skb_pull(skb, tlv->len + sizeof(*tlv)); | |
505 | } | |
506 | ||
507 | kfree_skb(skb); | |
508 | return 0; | |
509 | } | |
510 | EXPORT_SYMBOL_GPL(btintel_read_version_tlv); | |
511 | ||
d06f107b LP |
512 | /* ------- REGMAP IBT SUPPORT ------- */ |
513 | ||
514 | #define IBT_REG_MODE_8BIT 0x00 | |
515 | #define IBT_REG_MODE_16BIT 0x01 | |
516 | #define IBT_REG_MODE_32BIT 0x02 | |
517 | ||
518 | struct regmap_ibt_context { | |
519 | struct hci_dev *hdev; | |
520 | __u16 op_write; | |
521 | __u16 op_read; | |
522 | }; | |
523 | ||
524 | struct ibt_cp_reg_access { | |
525 | __le32 addr; | |
526 | __u8 mode; | |
527 | __u8 len; | |
683cc86d | 528 | __u8 data[]; |
d06f107b LP |
529 | } __packed; |
530 | ||
531 | struct ibt_rp_reg_access { | |
532 | __u8 status; | |
533 | __le32 addr; | |
683cc86d | 534 | __u8 data[]; |
d06f107b LP |
535 | } __packed; |
536 | ||
537 | static int regmap_ibt_read(void *context, const void *addr, size_t reg_size, | |
538 | void *val, size_t val_size) | |
539 | { | |
540 | struct regmap_ibt_context *ctx = context; | |
541 | struct ibt_cp_reg_access cp; | |
542 | struct ibt_rp_reg_access *rp; | |
543 | struct sk_buff *skb; | |
544 | int err = 0; | |
545 | ||
546 | if (reg_size != sizeof(__le32)) | |
547 | return -EINVAL; | |
548 | ||
549 | switch (val_size) { | |
550 | case 1: | |
551 | cp.mode = IBT_REG_MODE_8BIT; | |
552 | break; | |
553 | case 2: | |
554 | cp.mode = IBT_REG_MODE_16BIT; | |
555 | break; | |
556 | case 4: | |
557 | cp.mode = IBT_REG_MODE_32BIT; | |
558 | break; | |
559 | default: | |
560 | return -EINVAL; | |
561 | } | |
562 | ||
563 | /* regmap provides a little-endian formatted addr */ | |
564 | cp.addr = *(__le32 *)addr; | |
565 | cp.len = val_size; | |
566 | ||
567 | bt_dev_dbg(ctx->hdev, "Register (0x%x) read", le32_to_cpu(cp.addr)); | |
568 | ||
569 | skb = hci_cmd_sync(ctx->hdev, ctx->op_read, sizeof(cp), &cp, | |
570 | HCI_CMD_TIMEOUT); | |
571 | if (IS_ERR(skb)) { | |
572 | err = PTR_ERR(skb); | |
573 | bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error (%d)", | |
574 | le32_to_cpu(cp.addr), err); | |
575 | return err; | |
576 | } | |
577 | ||
578 | if (skb->len != sizeof(*rp) + val_size) { | |
579 | bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error, bad len", | |
580 | le32_to_cpu(cp.addr)); | |
581 | err = -EINVAL; | |
582 | goto done; | |
583 | } | |
584 | ||
585 | rp = (struct ibt_rp_reg_access *)skb->data; | |
586 | ||
587 | if (rp->addr != cp.addr) { | |
588 | bt_dev_err(ctx->hdev, "regmap: Register (0x%x) read error, bad addr", | |
589 | le32_to_cpu(rp->addr)); | |
590 | err = -EINVAL; | |
591 | goto done; | |
592 | } | |
593 | ||
594 | memcpy(val, rp->data, val_size); | |
595 | ||
596 | done: | |
597 | kfree_skb(skb); | |
598 | return err; | |
599 | } | |
600 | ||
601 | static int regmap_ibt_gather_write(void *context, | |
602 | const void *addr, size_t reg_size, | |
603 | const void *val, size_t val_size) | |
604 | { | |
605 | struct regmap_ibt_context *ctx = context; | |
606 | struct ibt_cp_reg_access *cp; | |
607 | struct sk_buff *skb; | |
608 | int plen = sizeof(*cp) + val_size; | |
609 | u8 mode; | |
610 | int err = 0; | |
611 | ||
612 | if (reg_size != sizeof(__le32)) | |
613 | return -EINVAL; | |
614 | ||
615 | switch (val_size) { | |
616 | case 1: | |
617 | mode = IBT_REG_MODE_8BIT; | |
618 | break; | |
619 | case 2: | |
620 | mode = IBT_REG_MODE_16BIT; | |
621 | break; | |
622 | case 4: | |
623 | mode = IBT_REG_MODE_32BIT; | |
624 | break; | |
625 | default: | |
626 | return -EINVAL; | |
627 | } | |
628 | ||
629 | cp = kmalloc(plen, GFP_KERNEL); | |
630 | if (!cp) | |
631 | return -ENOMEM; | |
632 | ||
633 | /* regmap provides a little-endian formatted addr/value */ | |
634 | cp->addr = *(__le32 *)addr; | |
635 | cp->mode = mode; | |
636 | cp->len = val_size; | |
637 | memcpy(&cp->data, val, val_size); | |
638 | ||
639 | bt_dev_dbg(ctx->hdev, "Register (0x%x) write", le32_to_cpu(cp->addr)); | |
640 | ||
641 | skb = hci_cmd_sync(ctx->hdev, ctx->op_write, plen, cp, HCI_CMD_TIMEOUT); | |
642 | if (IS_ERR(skb)) { | |
643 | err = PTR_ERR(skb); | |
644 | bt_dev_err(ctx->hdev, "regmap: Register (0x%x) write error (%d)", | |
645 | le32_to_cpu(cp->addr), err); | |
646 | goto done; | |
647 | } | |
648 | kfree_skb(skb); | |
649 | ||
650 | done: | |
651 | kfree(cp); | |
652 | return err; | |
653 | } | |
654 | ||
655 | static int regmap_ibt_write(void *context, const void *data, size_t count) | |
656 | { | |
657 | /* data contains register+value, since we only support 32bit addr, | |
658 | * minimum data size is 4 bytes. | |
659 | */ | |
660 | if (WARN_ONCE(count < 4, "Invalid register access")) | |
661 | return -EINVAL; | |
662 | ||
663 | return regmap_ibt_gather_write(context, data, 4, data + 4, count - 4); | |
664 | } | |
665 | ||
666 | static void regmap_ibt_free_context(void *context) | |
667 | { | |
668 | kfree(context); | |
669 | } | |
670 | ||
671 | static struct regmap_bus regmap_ibt = { | |
672 | .read = regmap_ibt_read, | |
673 | .write = regmap_ibt_write, | |
674 | .gather_write = regmap_ibt_gather_write, | |
675 | .free_context = regmap_ibt_free_context, | |
676 | .reg_format_endian_default = REGMAP_ENDIAN_LITTLE, | |
677 | .val_format_endian_default = REGMAP_ENDIAN_LITTLE, | |
678 | }; | |
679 | ||
680 | /* Config is the same for all register regions */ | |
681 | static const struct regmap_config regmap_ibt_cfg = { | |
682 | .name = "btintel_regmap", | |
683 | .reg_bits = 32, | |
684 | .val_bits = 32, | |
685 | }; | |
686 | ||
687 | struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read, | |
688 | u16 opcode_write) | |
689 | { | |
690 | struct regmap_ibt_context *ctx; | |
691 | ||
692 | bt_dev_info(hdev, "regmap: Init R%x-W%x region", opcode_read, | |
693 | opcode_write); | |
694 | ||
695 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | |
696 | if (!ctx) | |
697 | return ERR_PTR(-ENOMEM); | |
698 | ||
699 | ctx->op_read = opcode_read; | |
700 | ctx->op_write = opcode_write; | |
701 | ctx->hdev = hdev; | |
702 | ||
703 | return regmap_init(&hdev->dev, ®map_ibt, ctx, ®map_ibt_cfg); | |
704 | } | |
705 | EXPORT_SYMBOL_GPL(btintel_regmap_init); | |
706 | ||
e5889af6 THJA |
707 | int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param) |
708 | { | |
709 | struct intel_reset params = { 0x00, 0x01, 0x00, 0x01, 0x00000000 }; | |
710 | struct sk_buff *skb; | |
711 | ||
712 | params.boot_param = cpu_to_le32(boot_param); | |
713 | ||
714 | skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), ¶ms, | |
715 | HCI_INIT_TIMEOUT); | |
716 | if (IS_ERR(skb)) { | |
717 | bt_dev_err(hdev, "Failed to send Intel Reset command"); | |
718 | return PTR_ERR(skb); | |
719 | } | |
720 | ||
721 | kfree_skb(skb); | |
722 | ||
723 | return 0; | |
724 | } | |
725 | EXPORT_SYMBOL_GPL(btintel_send_intel_reset); | |
726 | ||
faf174d2 THJA |
727 | int btintel_read_boot_params(struct hci_dev *hdev, |
728 | struct intel_boot_params *params) | |
729 | { | |
730 | struct sk_buff *skb; | |
731 | ||
732 | skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT); | |
733 | if (IS_ERR(skb)) { | |
734 | bt_dev_err(hdev, "Reading Intel boot parameters failed (%ld)", | |
735 | PTR_ERR(skb)); | |
736 | return PTR_ERR(skb); | |
737 | } | |
738 | ||
739 | if (skb->len != sizeof(*params)) { | |
740 | bt_dev_err(hdev, "Intel boot parameters size mismatch"); | |
741 | kfree_skb(skb); | |
742 | return -EILSEQ; | |
743 | } | |
744 | ||
745 | memcpy(params, skb->data, sizeof(*params)); | |
746 | ||
747 | kfree_skb(skb); | |
748 | ||
749 | if (params->status) { | |
750 | bt_dev_err(hdev, "Intel boot parameters command failed (%02x)", | |
751 | params->status); | |
752 | return -bt_to_errno(params->status); | |
753 | } | |
754 | ||
755 | bt_dev_info(hdev, "Device revision is %u", | |
756 | le16_to_cpu(params->dev_revid)); | |
757 | ||
758 | bt_dev_info(hdev, "Secure boot is %s", | |
759 | params->secure_boot ? "enabled" : "disabled"); | |
760 | ||
761 | bt_dev_info(hdev, "OTP lock is %s", | |
762 | params->otp_lock ? "enabled" : "disabled"); | |
763 | ||
764 | bt_dev_info(hdev, "API lock is %s", | |
765 | params->api_lock ? "enabled" : "disabled"); | |
766 | ||
767 | bt_dev_info(hdev, "Debug lock is %s", | |
768 | params->debug_lock ? "enabled" : "disabled"); | |
769 | ||
770 | bt_dev_info(hdev, "Minimum firmware build %u week %u %u", | |
771 | params->min_fw_build_nn, params->min_fw_build_cw, | |
772 | 2000 + params->min_fw_build_yy); | |
773 | ||
774 | return 0; | |
775 | } | |
776 | EXPORT_SYMBOL_GPL(btintel_read_boot_params); | |
777 | ||
e9117215 K |
778 | static int btintel_sfi_rsa_header_secure_send(struct hci_dev *hdev, |
779 | const struct firmware *fw) | |
fbbe83c5 THJA |
780 | { |
781 | int err; | |
fbbe83c5 THJA |
782 | |
783 | /* Start the firmware download transaction with the Init fragment | |
784 | * represented by the 128 bytes of CSS header. | |
785 | */ | |
786 | err = btintel_secure_send(hdev, 0x00, 128, fw->data); | |
787 | if (err < 0) { | |
788 | bt_dev_err(hdev, "Failed to send firmware header (%d)", err); | |
789 | goto done; | |
790 | } | |
791 | ||
792 | /* Send the 256 bytes of public key information from the firmware | |
793 | * as the PKey fragment. | |
794 | */ | |
795 | err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128); | |
796 | if (err < 0) { | |
797 | bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err); | |
798 | goto done; | |
799 | } | |
800 | ||
801 | /* Send the 256 bytes of signature information from the firmware | |
802 | * as the Sign fragment. | |
803 | */ | |
804 | err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388); | |
805 | if (err < 0) { | |
806 | bt_dev_err(hdev, "Failed to send firmware signature (%d)", err); | |
807 | goto done; | |
808 | } | |
809 | ||
e9117215 K |
810 | done: |
811 | return err; | |
812 | } | |
813 | ||
81ebea53 K |
814 | static int btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev, |
815 | const struct firmware *fw) | |
816 | { | |
817 | int err; | |
818 | ||
819 | /* Start the firmware download transaction with the Init fragment | |
820 | * represented by the 128 bytes of CSS header. | |
821 | */ | |
822 | err = btintel_secure_send(hdev, 0x00, 128, fw->data + 644); | |
823 | if (err < 0) { | |
824 | bt_dev_err(hdev, "Failed to send firmware header (%d)", err); | |
825 | return err; | |
826 | } | |
827 | ||
828 | /* Send the 96 bytes of public key information from the firmware | |
829 | * as the PKey fragment. | |
830 | */ | |
831 | err = btintel_secure_send(hdev, 0x03, 96, fw->data + 644 + 128); | |
832 | if (err < 0) { | |
833 | bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err); | |
834 | return err; | |
835 | } | |
836 | ||
837 | /* Send the 96 bytes of signature information from the firmware | |
838 | * as the Sign fragment | |
839 | */ | |
840 | err = btintel_secure_send(hdev, 0x02, 96, fw->data + 644 + 224); | |
841 | if (err < 0) { | |
842 | bt_dev_err(hdev, "Failed to send firmware signature (%d)", | |
843 | err); | |
844 | return err; | |
845 | } | |
846 | return 0; | |
847 | } | |
848 | ||
e9117215 K |
849 | static int btintel_download_firmware_payload(struct hci_dev *hdev, |
850 | const struct firmware *fw, | |
851 | u32 *boot_param, size_t offset) | |
852 | { | |
853 | int err; | |
854 | const u8 *fw_ptr; | |
855 | u32 frag_len; | |
856 | ||
857 | fw_ptr = fw->data + offset; | |
fbbe83c5 | 858 | frag_len = 0; |
e9117215 | 859 | err = -EINVAL; |
fbbe83c5 THJA |
860 | |
861 | while (fw_ptr - fw->data < fw->size) { | |
862 | struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len); | |
863 | ||
864 | /* Each SKU has a different reset parameter to use in the | |
865 | * HCI_Intel_Reset command and it is embedded in the firmware | |
866 | * data. So, instead of using static value per SKU, check | |
867 | * the firmware data and save it for later use. | |
868 | */ | |
869 | if (le16_to_cpu(cmd->opcode) == 0xfc0e) { | |
870 | /* The boot parameter is the first 32-bit value | |
871 | * and rest of 3 octets are reserved. | |
872 | */ | |
873 | *boot_param = get_unaligned_le32(fw_ptr + sizeof(*cmd)); | |
874 | ||
875 | bt_dev_dbg(hdev, "boot_param=0x%x", *boot_param); | |
876 | } | |
877 | ||
878 | frag_len += sizeof(*cmd) + cmd->plen; | |
879 | ||
880 | /* The parameter length of the secure send command requires | |
881 | * a 4 byte alignment. It happens so that the firmware file | |
882 | * contains proper Intel_NOP commands to align the fragments | |
883 | * as needed. | |
884 | * | |
885 | * Send set of commands with 4 byte alignment from the | |
886 | * firmware data buffer as a single Data fragement. | |
887 | */ | |
888 | if (!(frag_len % 4)) { | |
889 | err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr); | |
890 | if (err < 0) { | |
891 | bt_dev_err(hdev, | |
892 | "Failed to send firmware data (%d)", | |
893 | err); | |
894 | goto done; | |
895 | } | |
896 | ||
897 | fw_ptr += frag_len; | |
898 | frag_len = 0; | |
899 | } | |
900 | } | |
901 | ||
902 | done: | |
903 | return err; | |
904 | } | |
e9117215 K |
905 | |
906 | int btintel_download_firmware(struct hci_dev *hdev, | |
907 | const struct firmware *fw, | |
908 | u32 *boot_param) | |
909 | { | |
910 | int err; | |
911 | ||
912 | err = btintel_sfi_rsa_header_secure_send(hdev, fw); | |
913 | if (err) | |
914 | return err; | |
915 | ||
916 | return btintel_download_firmware_payload(hdev, fw, boot_param, | |
917 | RSA_HEADER_LEN); | |
918 | } | |
fbbe83c5 THJA |
919 | EXPORT_SYMBOL_GPL(btintel_download_firmware); |
920 | ||
81ebea53 K |
921 | int btintel_download_firmware_newgen(struct hci_dev *hdev, |
922 | const struct firmware *fw, u32 *boot_param, | |
923 | u8 hw_variant, u8 sbe_type) | |
924 | { | |
925 | int err; | |
926 | u32 css_header_ver; | |
927 | ||
928 | /* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support | |
929 | * only RSA secure boot engine. Hence, the corresponding sfi file will | |
930 | * have RSA header of 644 bytes followed by Command Buffer. | |
931 | * | |
932 | * iBT hardware variants 0x17, 0x18 onwards support both RSA and ECDSA | |
933 | * secure boot engine. As a result, the corresponding sfi file will | |
934 | * have RSA header of 644, ECDSA header of 320 bytes followed by | |
935 | * Command Buffer. | |
936 | * | |
937 | * CSS Header byte positions 0x08 to 0x0B represent the CSS Header | |
938 | * version: RSA(0x00010000) , ECDSA (0x00020000) | |
939 | */ | |
940 | css_header_ver = get_unaligned_le32(fw->data + CSS_HEADER_OFFSET); | |
941 | if (css_header_ver != 0x00010000) { | |
942 | bt_dev_err(hdev, "Invalid CSS Header version"); | |
943 | return -EINVAL; | |
944 | } | |
945 | ||
946 | if (hw_variant <= 0x14) { | |
947 | if (sbe_type != 0x00) { | |
948 | bt_dev_err(hdev, "Invalid SBE type for hardware variant (%d)", | |
949 | hw_variant); | |
950 | return -EINVAL; | |
951 | } | |
952 | ||
953 | err = btintel_sfi_rsa_header_secure_send(hdev, fw); | |
954 | if (err) | |
955 | return err; | |
956 | ||
957 | err = btintel_download_firmware_payload(hdev, fw, boot_param, RSA_HEADER_LEN); | |
958 | if (err) | |
959 | return err; | |
960 | } else if (hw_variant >= 0x17) { | |
961 | /* Check if CSS header for ECDSA follows the RSA header */ | |
962 | if (fw->data[ECDSA_OFFSET] != 0x06) | |
963 | return -EINVAL; | |
964 | ||
965 | /* Check if the CSS Header version is ECDSA(0x00020000) */ | |
966 | css_header_ver = get_unaligned_le32(fw->data + ECDSA_OFFSET + CSS_HEADER_OFFSET); | |
967 | if (css_header_ver != 0x00020000) { | |
968 | bt_dev_err(hdev, "Invalid CSS Header version"); | |
969 | return -EINVAL; | |
970 | } | |
971 | ||
972 | if (sbe_type == 0x00) { | |
973 | err = btintel_sfi_rsa_header_secure_send(hdev, fw); | |
974 | if (err) | |
975 | return err; | |
976 | ||
977 | err = btintel_download_firmware_payload(hdev, fw, | |
978 | boot_param, | |
979 | RSA_HEADER_LEN + ECDSA_HEADER_LEN); | |
980 | if (err) | |
981 | return err; | |
982 | } else if (sbe_type == 0x01) { | |
983 | err = btintel_sfi_ecdsa_header_secure_send(hdev, fw); | |
984 | if (err) | |
985 | return err; | |
986 | ||
987 | err = btintel_download_firmware_payload(hdev, fw, | |
988 | boot_param, | |
989 | RSA_HEADER_LEN + ECDSA_HEADER_LEN); | |
990 | if (err) | |
991 | return err; | |
992 | } | |
993 | } | |
994 | return 0; | |
995 | } | |
996 | EXPORT_SYMBOL_GPL(btintel_download_firmware_newgen); | |
997 | ||
b9a2562f AB |
998 | void btintel_reset_to_bootloader(struct hci_dev *hdev) |
999 | { | |
1000 | struct intel_reset params; | |
1001 | struct sk_buff *skb; | |
1002 | ||
1003 | /* Send Intel Reset command. This will result in | |
1004 | * re-enumeration of BT controller. | |
1005 | * | |
1006 | * Intel Reset parameter description: | |
1007 | * reset_type : 0x00 (Soft reset), | |
1008 | * 0x01 (Hard reset) | |
1009 | * patch_enable : 0x00 (Do not enable), | |
1010 | * 0x01 (Enable) | |
1011 | * ddc_reload : 0x00 (Do not reload), | |
1012 | * 0x01 (Reload) | |
1013 | * boot_option: 0x00 (Current image), | |
1014 | * 0x01 (Specified boot address) | |
1015 | * boot_param: Boot address | |
1016 | * | |
1017 | */ | |
1018 | params.reset_type = 0x01; | |
1019 | params.patch_enable = 0x01; | |
1020 | params.ddc_reload = 0x01; | |
1021 | params.boot_option = 0x00; | |
1022 | params.boot_param = cpu_to_le32(0x00000000); | |
1023 | ||
1024 | skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), | |
1025 | ¶ms, HCI_INIT_TIMEOUT); | |
1026 | if (IS_ERR(skb)) { | |
1027 | bt_dev_err(hdev, "FW download error recovery failed (%ld)", | |
1028 | PTR_ERR(skb)); | |
1029 | return; | |
1030 | } | |
1031 | bt_dev_info(hdev, "Intel reset sent to retry FW download"); | |
1032 | kfree_skb(skb); | |
1033 | ||
1034 | /* Current Intel BT controllers(ThP/JfP) hold the USB reset | |
1035 | * lines for 2ms when it receives Intel Reset in bootloader mode. | |
1036 | * Whereas, the upcoming Intel BT controllers will hold USB reset | |
1037 | * for 150ms. To keep the delay generic, 150ms is chosen here. | |
1038 | */ | |
1039 | msleep(150); | |
1040 | } | |
1041 | EXPORT_SYMBOL_GPL(btintel_reset_to_bootloader); | |
1042 | ||
d74abe21 C |
1043 | int btintel_read_debug_features(struct hci_dev *hdev, |
1044 | struct intel_debug_features *features) | |
1045 | { | |
1046 | struct sk_buff *skb; | |
1047 | u8 page_no = 1; | |
1048 | ||
1049 | /* Intel controller supports two pages, each page is of 128-bit | |
1050 | * feature bit mask. And each bit defines specific feature support | |
1051 | */ | |
1052 | skb = __hci_cmd_sync(hdev, 0xfca6, sizeof(page_no), &page_no, | |
1053 | HCI_INIT_TIMEOUT); | |
1054 | if (IS_ERR(skb)) { | |
1055 | bt_dev_err(hdev, "Reading supported features failed (%ld)", | |
1056 | PTR_ERR(skb)); | |
1057 | return PTR_ERR(skb); | |
1058 | } | |
1059 | ||
1060 | if (skb->len != (sizeof(features->page1) + 3)) { | |
1061 | bt_dev_err(hdev, "Supported features event size mismatch"); | |
1062 | kfree_skb(skb); | |
1063 | return -EILSEQ; | |
1064 | } | |
1065 | ||
1066 | memcpy(features->page1, skb->data + 3, sizeof(features->page1)); | |
1067 | ||
1068 | /* Read the supported features page2 if required in future. | |
1069 | */ | |
1070 | kfree_skb(skb); | |
1071 | return 0; | |
1072 | } | |
1073 | EXPORT_SYMBOL_GPL(btintel_read_debug_features); | |
1074 | ||
c453b10c C |
1075 | int btintel_set_debug_features(struct hci_dev *hdev, |
1076 | const struct intel_debug_features *features) | |
1077 | { | |
1078 | u8 mask[11] = { 0x0a, 0x92, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00, | |
1079 | 0x00, 0x00, 0x00 }; | |
1080 | struct sk_buff *skb; | |
1081 | ||
1082 | if (!features) | |
1083 | return -EINVAL; | |
1084 | ||
1085 | if (!(features->page1[0] & 0x3f)) { | |
1086 | bt_dev_info(hdev, "Telemetry exception format not supported"); | |
1087 | return 0; | |
1088 | } | |
1089 | ||
1090 | skb = __hci_cmd_sync(hdev, 0xfc8b, 11, mask, HCI_INIT_TIMEOUT); | |
1091 | if (IS_ERR(skb)) { | |
1092 | bt_dev_err(hdev, "Setting Intel telemetry ddc write event mask failed (%ld)", | |
1093 | PTR_ERR(skb)); | |
1094 | return PTR_ERR(skb); | |
1095 | } | |
1096 | ||
1097 | kfree_skb(skb); | |
1098 | return 0; | |
1099 | } | |
1100 | EXPORT_SYMBOL_GPL(btintel_set_debug_features); | |
1101 | ||
48f0ed1b MH |
1102 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); |
1103 | MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); | |
1104 | MODULE_VERSION(VERSION); | |
1105 | MODULE_LICENSE("GPL"); | |
0ed97e82 MH |
1106 | MODULE_FIRMWARE("intel/ibt-11-5.sfi"); |
1107 | MODULE_FIRMWARE("intel/ibt-11-5.ddc"); | |
d1b7abae JB |
1108 | MODULE_FIRMWARE("intel/ibt-12-16.sfi"); |
1109 | MODULE_FIRMWARE("intel/ibt-12-16.ddc"); |