|
20 | 20 | #define CIRRUS_LOGIC_CALIBRATION_EFI_GUID \ |
21 | 21 | EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3) |
22 | 22 |
|
| 23 | +#define LENOVO_SPEAKER_ID_EFI_NAME L"SdwSpeaker" |
| 24 | +#define LENOVO_SPEAKER_ID_EFI_GUID \ |
| 25 | + EFI_GUID(0x48df970e, 0xe27f, 0x460a, 0xb5, 0x86, 0x77, 0x19, 0x80, 0x1d, 0x92, 0x82) |
| 26 | + |
| 27 | +#define HP_SPEAKER_ID_EFI_NAME L"HPSpeakerID" |
| 28 | +#define HP_SPEAKER_ID_EFI_GUID \ |
| 29 | + EFI_GUID(0xc49593a4, 0xd099, 0x419b, 0xa2, 0xc3, 0x67, 0xe9, 0x80, 0xe6, 0x1d, 0x1e) |
| 30 | + |
23 | 31 | static int cs_amp_write_cal_coeff(struct cs_dsp *dsp, |
24 | 32 | const struct cirrus_amp_cal_controls *controls, |
25 | 33 | const char *ctl_name, u32 val) |
@@ -114,6 +122,24 @@ static efi_status_t cs_amp_get_efi_variable(efi_char16_t *name, |
114 | 122 | return EFI_NOT_FOUND; |
115 | 123 | } |
116 | 124 |
|
| 125 | +static int cs_amp_convert_efi_status(efi_status_t status) |
| 126 | +{ |
| 127 | + switch (status) { |
| 128 | + case EFI_SUCCESS: |
| 129 | + return 0; |
| 130 | + case EFI_NOT_FOUND: |
| 131 | + return -ENOENT; |
| 132 | + case EFI_BUFFER_TOO_SMALL: |
| 133 | + return -EFBIG; |
| 134 | + case EFI_UNSUPPORTED: |
| 135 | + case EFI_ACCESS_DENIED: |
| 136 | + case EFI_SECURITY_VIOLATION: |
| 137 | + return -EACCES; |
| 138 | + default: |
| 139 | + return -EIO; |
| 140 | + } |
| 141 | +} |
| 142 | + |
117 | 143 | static struct cirrus_amp_efi_data *cs_amp_get_cal_efi_buffer(struct device *dev) |
118 | 144 | { |
119 | 145 | struct cirrus_amp_efi_data *efi_data; |
@@ -276,6 +302,81 @@ int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_ |
276 | 302 | } |
277 | 303 | EXPORT_SYMBOL_NS_GPL(cs_amp_get_efi_calibration_data, "SND_SOC_CS_AMP_LIB"); |
278 | 304 |
|
| 305 | +struct cs_amp_spkid_efi { |
| 306 | + efi_char16_t *name; |
| 307 | + efi_guid_t *guid; |
| 308 | + u8 values[2]; |
| 309 | +}; |
| 310 | + |
| 311 | +static int cs_amp_get_efi_byte_spkid(struct device *dev, const struct cs_amp_spkid_efi *info) |
| 312 | +{ |
| 313 | + efi_status_t status; |
| 314 | + unsigned long size; |
| 315 | + u8 spkid; |
| 316 | + int i, ret; |
| 317 | + |
| 318 | + size = sizeof(spkid); |
| 319 | + status = cs_amp_get_efi_variable(info->name, info->guid, &size, &spkid); |
| 320 | + ret = cs_amp_convert_efi_status(status); |
| 321 | + if (ret < 0) |
| 322 | + return ret; |
| 323 | + |
| 324 | + if (size == 0) |
| 325 | + return -ENOENT; |
| 326 | + |
| 327 | + for (i = 0; i < ARRAY_SIZE(info->values); i++) { |
| 328 | + if (info->values[i] == spkid) |
| 329 | + return i; |
| 330 | + } |
| 331 | + |
| 332 | + dev_err(dev, "EFI speaker ID bad value %#x\n", spkid); |
| 333 | + |
| 334 | + return -EINVAL; |
| 335 | +} |
| 336 | + |
| 337 | +static const struct cs_amp_spkid_efi cs_amp_spkid_byte_types[] = { |
| 338 | + { |
| 339 | + .name = LENOVO_SPEAKER_ID_EFI_NAME, |
| 340 | + .guid = &LENOVO_SPEAKER_ID_EFI_GUID, |
| 341 | + .values = { 0xd0, 0xd1 }, |
| 342 | + }, |
| 343 | + { |
| 344 | + .name = HP_SPEAKER_ID_EFI_NAME, |
| 345 | + .guid = &HP_SPEAKER_ID_EFI_GUID, |
| 346 | + .values = { 0x30, 0x31 }, |
| 347 | + }, |
| 348 | +}; |
| 349 | + |
| 350 | +/** |
| 351 | + * cs_amp_get_vendor_spkid - get a speaker ID from vendor-specific storage |
| 352 | + * @dev: pointer to struct device |
| 353 | + * |
| 354 | + * Known vendor-specific methods of speaker ID are checked and if one is |
| 355 | + * found its speaker ID value is returned. |
| 356 | + * |
| 357 | + * Return: >=0 is a valid speaker ID. -ENOENT if a vendor-specific method |
| 358 | + * was not found. -EACCES if the vendor-specific storage could not |
| 359 | + * be read. Other error values indicate that the data from the |
| 360 | + * vendor-specific storage was found but could not be understood. |
| 361 | + */ |
| 362 | +int cs_amp_get_vendor_spkid(struct device *dev) |
| 363 | +{ |
| 364 | + int i, ret; |
| 365 | + |
| 366 | + if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE) && |
| 367 | + !IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST)) |
| 368 | + return -ENOENT; |
| 369 | + |
| 370 | + for (i = 0; i < ARRAY_SIZE(cs_amp_spkid_byte_types); i++) { |
| 371 | + ret = cs_amp_get_efi_byte_spkid(dev, &cs_amp_spkid_byte_types[i]); |
| 372 | + if (ret != -ENOENT) |
| 373 | + return ret; |
| 374 | + } |
| 375 | + |
| 376 | + return -ENOENT; |
| 377 | +} |
| 378 | +EXPORT_SYMBOL_NS_GPL(cs_amp_get_vendor_spkid, "SND_SOC_CS_AMP_LIB"); |
| 379 | + |
279 | 380 | static const struct cs_amp_test_hooks cs_amp_test_hook_ptrs = { |
280 | 381 | .get_efi_variable = cs_amp_get_efi_variable, |
281 | 382 | .write_cal_coeff = cs_amp_write_cal_coeff, |
|
0 commit comments