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)
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 @@ int snd_dice_transaction_init(struct snd_dice *dice)
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;
}
......@@ -18,27 +18,12 @@ MODULE_LICENSE("GPL v2");
#define WEISS_CATEGORY_ID 0x00
#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_csr_iterator it;
int key, val, vendor = -1, model = -1, err;
unsigned int category, i;
__be32 *pointers;
u32 value;
__be32 version;
pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
GFP_KERNEL);
if (pointers == NULL)
return -ENOMEM;
int key, val, vendor = -1, model = -1;
unsigned int category;
/*
* Check that GUID and unit directory are constructed according to DICE
......@@ -64,51 +49,10 @@ static int dice_interface_check(struct fw_unit *unit)
else
category = DICE_CATEGORY_ID;
if (device->config_rom[3] != ((vendor << 8) | category) ||
device->config_rom[4] >> 22 != model) {
err = -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;
}
}
device->config_rom[4] >> 22 != model)
return -ENODEV;
/*
* 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;
return 0;
}
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)
struct snd_dice *dice;
int err;
err = dice_interface_check(unit);
err = check_dice_category(unit);
if (err < 0)
goto end;
return -ENODEV;
err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
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