ALSA: dice: split subaddress check from category check
Before allocating an instance of sound card, ALSA dice driver checks chip_ID_hi in Bus information block of Config ROM, then also checks subaddresses. The former operation reads cache of Config ROM in Linux FireWire subsystem, while the latter operation sends read transaction. The latter can be merged into initialization of transaction system. This commit splits these two operations to reduce needless transactions in probe processing. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:

committed by
Takashi Iwai

parent
d8c5ed752e
commit
4a47a87def
@@ -331,39 +331,60 @@ int snd_dice_transaction_reinit(struct snd_dice *dice)
|
||||
return register_notification_address(dice, false);
|
||||
}
|
||||
|
||||
int snd_dice_transaction_init(struct snd_dice *dice)
|
||||
static int get_subaddrs(struct snd_dice *dice)
|
||||
{
|
||||
struct fw_address_handler *handler = &dice->notification_handler;
|
||||
static const int min_values[10] = {
|
||||
10, 0x64 / 4,
|
||||
10, 0x18 / 4,
|
||||
10, 0x18 / 4,
|
||||
0, 0,
|
||||
0, 0,
|
||||
};
|
||||
__be32 *pointers;
|
||||
__be32 version;
|
||||
u32 data;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
/* Use the same way which dice_interface_check() does. */
|
||||
pointers = kmalloc(sizeof(__be32) * 10, GFP_KERNEL);
|
||||
pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
|
||||
GFP_KERNEL);
|
||||
if (pointers == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Get offsets for sub-addresses */
|
||||
/*
|
||||
* Check that the sub address spaces exist and are located inside the
|
||||
* private address space. The minimum values are chosen so that all
|
||||
* minimally required registers are included.
|
||||
*/
|
||||
err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
|
||||
DICE_PRIVATE_SPACE,
|
||||
pointers, sizeof(__be32) * 10, 0);
|
||||
DICE_PRIVATE_SPACE, pointers,
|
||||
sizeof(__be32) * ARRAY_SIZE(min_values), 0);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
|
||||
/* Allocation callback in address space over host controller */
|
||||
handler->length = 4;
|
||||
handler->address_callback = dice_notification;
|
||||
handler->callback_data = dice;
|
||||
err = fw_core_add_address_handler(handler, &fw_high_memory_region);
|
||||
if (err < 0) {
|
||||
handler->callback_data = NULL;
|
||||
goto end;
|
||||
for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
|
||||
data = be32_to_cpu(pointers[i]);
|
||||
if (data < min_values[i] || data >= 0x40000) {
|
||||
err = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Register the address space */
|
||||
err = register_notification_address(dice, true);
|
||||
if (err < 0) {
|
||||
fw_core_remove_address_handler(handler);
|
||||
handler->callback_data = NULL;
|
||||
/*
|
||||
* Check that the implemented DICE driver specification major version
|
||||
* number matches.
|
||||
*/
|
||||
err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST,
|
||||
DICE_PRIVATE_SPACE +
|
||||
be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
|
||||
&version, sizeof(version), 0);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
|
||||
if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
|
||||
dev_err(&dice->unit->device,
|
||||
"unknown DICE version: 0x%08x\n", be32_to_cpu(version));
|
||||
err = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -380,3 +401,32 @@ end:
|
||||
kfree(pointers);
|
||||
return err;
|
||||
}
|
||||
|
||||
int snd_dice_transaction_init(struct snd_dice *dice)
|
||||
{
|
||||
struct fw_address_handler *handler = &dice->notification_handler;
|
||||
int err;
|
||||
|
||||
err = get_subaddrs(dice);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Allocation callback in address space over host controller */
|
||||
handler->length = 4;
|
||||
handler->address_callback = dice_notification;
|
||||
handler->callback_data = dice;
|
||||
err = fw_core_add_address_handler(handler, &fw_high_memory_region);
|
||||
if (err < 0) {
|
||||
handler->callback_data = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Register the address space */
|
||||
err = register_notification_address(dice, true);
|
||||
if (err < 0) {
|
||||
fw_core_remove_address_handler(handler);
|
||||
handler->callback_data = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
Reference in New Issue
Block a user