Commit 4a47a87d authored by Takashi Sakamoto's avatar Takashi Sakamoto Committed by Takashi Iwai

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: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent d8c5ed75
...@@ -331,39 +331,60 @@ int snd_dice_transaction_reinit(struct snd_dice *dice) ...@@ -331,39 +331,60 @@ int snd_dice_transaction_reinit(struct snd_dice *dice)
return register_notification_address(dice, false); 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 *pointers;
__be32 version;
u32 data;
unsigned int i;
int err; int err;
/* Use the same way which dice_interface_check() does. */ pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
pointers = kmalloc(sizeof(__be32) * 10, GFP_KERNEL); GFP_KERNEL);
if (pointers == NULL) if (pointers == NULL)
return -ENOMEM; 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, err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
DICE_PRIVATE_SPACE, DICE_PRIVATE_SPACE, pointers,
pointers, sizeof(__be32) * 10, 0); sizeof(__be32) * ARRAY_SIZE(min_values), 0);
if (err < 0) if (err < 0)
goto end; goto end;
/* Allocation callback in address space over host controller */ for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
handler->length = 4; data = be32_to_cpu(pointers[i]);
handler->address_callback = dice_notification; if (data < min_values[i] || data >= 0x40000) {
handler->callback_data = dice; err = -ENODEV;
err = fw_core_add_address_handler(handler, &fw_high_memory_region); goto end;
if (err < 0) { }
handler->callback_data = NULL;
goto end;
} }
/* Register the address space */ /*
err = register_notification_address(dice, true); * Check that the implemented DICE driver specification major version
if (err < 0) { * number matches.
fw_core_remove_address_handler(handler); */
handler->callback_data = NULL; 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; goto end;
} }
...@@ -380,3 +401,32 @@ int snd_dice_transaction_init(struct snd_dice *dice) ...@@ -380,3 +401,32 @@ int snd_dice_transaction_init(struct snd_dice *dice)
kfree(pointers); kfree(pointers);
return err; 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;
}
...@@ -18,27 +18,12 @@ MODULE_LICENSE("GPL v2"); ...@@ -18,27 +18,12 @@ MODULE_LICENSE("GPL v2");
#define WEISS_CATEGORY_ID 0x00 #define WEISS_CATEGORY_ID 0x00
#define LOUD_CATEGORY_ID 0x10 #define LOUD_CATEGORY_ID 0x10
static int dice_interface_check(struct fw_unit *unit) static int check_dice_category(struct fw_unit *unit)
{ {
static const int min_values[10] = {
10, 0x64 / 4,
10, 0x18 / 4,
10, 0x18 / 4,
0, 0,
0, 0,
};
struct fw_device *device = fw_parent_device(unit); struct fw_device *device = fw_parent_device(unit);
struct fw_csr_iterator it; struct fw_csr_iterator it;
int key, val, vendor = -1, model = -1, err; int key, val, vendor = -1, model = -1;
unsigned int category, i; unsigned int category;
__be32 *pointers;
u32 value;
__be32 version;
pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
GFP_KERNEL);
if (pointers == NULL)
return -ENOMEM;
/* /*
* Check that GUID and unit directory are constructed according to DICE * Check that GUID and unit directory are constructed according to DICE
...@@ -64,51 +49,10 @@ static int dice_interface_check(struct fw_unit *unit) ...@@ -64,51 +49,10 @@ static int dice_interface_check(struct fw_unit *unit)
else else
category = DICE_CATEGORY_ID; category = DICE_CATEGORY_ID;
if (device->config_rom[3] != ((vendor << 8) | category) || if (device->config_rom[3] != ((vendor << 8) | category) ||
device->config_rom[4] >> 22 != model) { device->config_rom[4] >> 22 != model)
err = -ENODEV; return -ENODEV;
goto end;
}
/*
* 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(unit, TCODE_READ_BLOCK_REQUEST,
DICE_PRIVATE_SPACE, pointers,
sizeof(__be32) * ARRAY_SIZE(min_values), 0);
if (err < 0) {
err = -ENODEV;
goto end;
}
for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
value = be32_to_cpu(pointers[i]);
if (value < min_values[i] || value >= 0x40000) {
err = -ENODEV;
goto end;
}
}
/* return 0;
* Check that the implemented DICE driver specification major version
* number matches.
*/
err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
DICE_PRIVATE_SPACE +
be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
&version, 4, 0);
if (err < 0) {
err = -ENODEV;
goto end;
}
if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
dev_err(&unit->device,
"unknown DICE version: 0x%08x\n", be32_to_cpu(version));
err = -ENODEV;
goto end;
}
end:
return err;
} }
static int highest_supported_mode_rate(struct snd_dice *dice, static int highest_supported_mode_rate(struct snd_dice *dice,
...@@ -254,9 +198,9 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) ...@@ -254,9 +198,9 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
struct snd_dice *dice; struct snd_dice *dice;
int err; int err;
err = dice_interface_check(unit); err = check_dice_category(unit);
if (err < 0) if (err < 0)
goto end; return -ENODEV;
err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
sizeof(*dice), &card); sizeof(*dice), &card);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment