diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2014-04-25 22:45:01 +0900 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-05-26 14:24:03 +0200 |
commit | bde8a8f23bbe6db51fa4e81644273af18fef3d7a (patch) | |
tree | 92ea0fbb1023bda284156ac561640f4502132409 /sound/firewire/fireworks/fireworks.c | |
parent | b5b04336015e76eb52ffc188e16c9cee01821c7c (diff) | |
download | linux-stable-bde8a8f23bbe6db51fa4e81644273af18fef3d7a.tar.gz linux-stable-bde8a8f23bbe6db51fa4e81644273af18fef3d7a.tar.bz2 linux-stable-bde8a8f23bbe6db51fa4e81644273af18fef3d7a.zip |
ALSA: fireworks: Add transaction and some commands
Fireworks uses own command and response. This commit adds functionality to
transact and adds some commands required for sound card instance and kernel
streaming.
There are two ways to deliver substance of this transaction:
1.AV/C vendor dependent command for command/response
2.Async transaction to specific addresses for command/response
By way 1, I confirm AudioFire12 cannot correctly response to some commands with
firmware version 5.0 or later. This is also confirmed by FFADO. So this driver
implement way 2.
The address for response gives an issue. When this driver allocate own callback
function into the address, then no one can allocate its own callback function.
This situation is not good for applications in user-land. This issue is solved
in later commit.
I note there is a command to change the address for response if the device
supports. But this driver uses default value. So users should not execute this
command as long as hoping this driver works correctly.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/fireworks/fireworks.c')
-rw-r--r-- | sound/firewire/fireworks/fireworks.c | 69 |
1 files changed, 63 insertions, 6 deletions
diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index ad719a1d5353..6fa3a5d725d5 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c @@ -59,6 +59,50 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS); /* unknown as product */ #define MODEL_GIBSON_GOLDTOP 0x00afb9 +/* part of hardware capability flags */ +#define FLAG_RESP_ADDR_CHANGABLE 0 + +static int +get_hardware_info(struct snd_efw *efw) +{ + struct fw_device *fw_dev = fw_parent_device(efw->unit); + struct snd_efw_hwinfo *hwinfo; + char version[12] = {0}; + int err; + + hwinfo = kzalloc(sizeof(struct snd_efw_hwinfo), GFP_KERNEL); + if (hwinfo == NULL) + return -ENOMEM; + + err = snd_efw_command_get_hwinfo(efw, hwinfo); + if (err < 0) + goto end; + + /* firmware version for communication chipset */ + snprintf(version, sizeof(version), "%u.%u", + (hwinfo->arm_version >> 24) & 0xff, + (hwinfo->arm_version >> 16) & 0xff); + if (err < 0) + goto end; + + strcpy(efw->card->driver, "Fireworks"); + strcpy(efw->card->shortname, hwinfo->model_name); + strcpy(efw->card->mixername, hwinfo->model_name); + snprintf(efw->card->longname, sizeof(efw->card->longname), + "%s %s v%s, GUID %08x%08x at %s, S%d", + hwinfo->vendor_name, hwinfo->model_name, version, + hwinfo->guid_hi, hwinfo->guid_lo, + dev_name(&efw->unit->device), 100 << fw_dev->max_speed); + if (err < 0) + goto end; + + if (hwinfo->flags & BIT(FLAG_RESP_ADDR_CHANGABLE)) + efw->resp_addr_changable = true; +end: + kfree(hwinfo); + return err; +} + static void efw_card_free(struct snd_card *card) { @@ -107,14 +151,14 @@ efw_probe(struct fw_unit *unit, mutex_init(&efw->mutex); spin_lock_init(&efw->lock); - strcpy(efw->card->driver, "Fireworks"); - strcpy(efw->card->shortname, efw->card->driver); - strcpy(efw->card->longname, efw->card->driver); - strcpy(efw->card->mixername, efw->card->driver); + err = get_hardware_info(efw); + if (err < 0) + goto error; err = snd_card_register(card); if (err < 0) goto error; + dev_set_drvdata(&unit->device, efw); end: mutex_unlock(&devices_mutex); @@ -127,7 +171,8 @@ error: static void efw_update(struct fw_unit *unit) { - return; + struct snd_efw *efw = dev_get_drvdata(&unit->device); + snd_efw_transaction_bus_reset(efw->unit); } static void efw_remove(struct fw_unit *unit) @@ -169,11 +214,23 @@ static struct fw_driver efw_driver = { static int __init snd_efw_init(void) { - return driver_register(&efw_driver.driver); + int err; + + err = snd_efw_transaction_register(); + if (err < 0) + goto end; + + err = driver_register(&efw_driver.driver); + if (err < 0) + snd_efw_transaction_unregister(); + +end: + return err; } static void __exit snd_efw_exit(void) { + snd_efw_transaction_unregister(); driver_unregister(&efw_driver.driver); mutex_destroy(&devices_mutex); } |