diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2011-12-04 16:23:59 -0500 |
---|---|---|
committer | Clemens Ladisch <clemens@ladisch.de> | 2013-10-20 16:07:57 -0400 |
commit | 15a75c8bed591dd23a3d221f5ccd91843c109670 (patch) | |
tree | 0ded272107635d8c6d4f311130091790abe02fcc /sound/firewire | |
parent | 5ea4018e4321f24e8305ea8a8b0a9c3e270456ae (diff) |
ALSA: dice: get rate-dependent parameters
In preparation for sample rate selection support, read the stream
parameters that might change when running at different sample rates.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r-- | sound/firewire/dice.c | 92 |
1 files changed, 90 insertions, 2 deletions
diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c index 49b47ba09cdd..e6bba6d32bd8 100644 --- a/sound/firewire/dice.c +++ b/sound/firewire/dice.c | |||
@@ -6,10 +6,12 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/compat.h> | 8 | #include <linux/compat.h> |
9 | #include <linux/completion.h> | ||
9 | #include <linux/delay.h> | 10 | #include <linux/delay.h> |
10 | #include <linux/device.h> | 11 | #include <linux/device.h> |
11 | #include <linux/firewire.h> | 12 | #include <linux/firewire.h> |
12 | #include <linux/firewire-constants.h> | 13 | #include <linux/firewire-constants.h> |
14 | #include <linux/jiffies.h> | ||
13 | #include <linux/module.h> | 15 | #include <linux/module.h> |
14 | #include <linux/mod_devicetable.h> | 16 | #include <linux/mod_devicetable.h> |
15 | #include <linux/mutex.h> | 17 | #include <linux/mutex.h> |
@@ -37,11 +39,14 @@ struct dice { | |||
37 | unsigned int global_offset; | 39 | unsigned int global_offset; |
38 | unsigned int rx_offset; | 40 | unsigned int rx_offset; |
39 | unsigned int clock_caps; | 41 | unsigned int clock_caps; |
42 | unsigned int rx_channels[3]; | ||
43 | unsigned int rx_midi_ports[3]; | ||
40 | struct fw_address_handler notification_handler; | 44 | struct fw_address_handler notification_handler; |
41 | int owner_generation; | 45 | int owner_generation; |
42 | int dev_lock_count; /* > 0 driver, < 0 userspace */ | 46 | int dev_lock_count; /* > 0 driver, < 0 userspace */ |
43 | bool dev_lock_changed; | 47 | bool dev_lock_changed; |
44 | bool global_enabled; | 48 | bool global_enabled; |
49 | struct completion clock_accepted; | ||
45 | wait_queue_head_t hwdep_wait; | 50 | wait_queue_head_t hwdep_wait; |
46 | u32 notification_bits; | 51 | u32 notification_bits; |
47 | struct fw_iso_resources resources; | 52 | struct fw_iso_resources resources; |
@@ -53,15 +58,23 @@ MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | |||
53 | MODULE_LICENSE("GPL v2"); | 58 | MODULE_LICENSE("GPL v2"); |
54 | 59 | ||
55 | static const unsigned int dice_rates[] = { | 60 | static const unsigned int dice_rates[] = { |
61 | /* mode 0 */ | ||
56 | [0] = 32000, | 62 | [0] = 32000, |
57 | [1] = 44100, | 63 | [1] = 44100, |
58 | [2] = 48000, | 64 | [2] = 48000, |
65 | /* mode 1 */ | ||
59 | [3] = 88200, | 66 | [3] = 88200, |
60 | [4] = 96000, | 67 | [4] = 96000, |
68 | /* mode 2 */ | ||
61 | [5] = 176400, | 69 | [5] = 176400, |
62 | [6] = 192000, | 70 | [6] = 192000, |
63 | }; | 71 | }; |
64 | 72 | ||
73 | static unsigned int rate_index_to_mode(unsigned int rate_index) | ||
74 | { | ||
75 | return ((int)rate_index - 1) / 2; | ||
76 | } | ||
77 | |||
65 | static void dice_lock_changed(struct dice *dice) | 78 | static void dice_lock_changed(struct dice *dice) |
66 | { | 79 | { |
67 | dice->dev_lock_changed = true; | 80 | dice->dev_lock_changed = true; |
@@ -264,6 +277,7 @@ static void dice_notification(struct fw_card *card, struct fw_request *request, | |||
264 | void *data, size_t length, void *callback_data) | 277 | void *data, size_t length, void *callback_data) |
265 | { | 278 | { |
266 | struct dice *dice = callback_data; | 279 | struct dice *dice = callback_data; |
280 | u32 bits; | ||
267 | unsigned long flags; | 281 | unsigned long flags; |
268 | 282 | ||
269 | if (tcode != TCODE_WRITE_QUADLET_REQUEST) { | 283 | if (tcode != TCODE_WRITE_QUADLET_REQUEST) { |
@@ -274,10 +288,17 @@ static void dice_notification(struct fw_card *card, struct fw_request *request, | |||
274 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); | 288 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); |
275 | return; | 289 | return; |
276 | } | 290 | } |
291 | |||
292 | bits = be32_to_cpup(data); | ||
293 | |||
277 | spin_lock_irqsave(&dice->lock, flags); | 294 | spin_lock_irqsave(&dice->lock, flags); |
278 | dice->notification_bits |= be32_to_cpup(data); | 295 | dice->notification_bits |= bits; |
279 | spin_unlock_irqrestore(&dice->lock, flags); | 296 | spin_unlock_irqrestore(&dice->lock, flags); |
297 | |||
280 | fw_send_response(card, request, RCODE_COMPLETE); | 298 | fw_send_response(card, request, RCODE_COMPLETE); |
299 | |||
300 | if (bits & NOTIFY_CLOCK_ACCEPTED) | ||
301 | complete(&dice->clock_accepted); | ||
281 | wake_up(&dice->hwdep_wait); | 302 | wake_up(&dice->hwdep_wait); |
282 | } | 303 | } |
283 | 304 | ||
@@ -457,6 +478,26 @@ static void dice_stream_stop(struct dice *dice) | |||
457 | fw_iso_resources_free(&dice->resources); | 478 | fw_iso_resources_free(&dice->resources); |
458 | } | 479 | } |
459 | 480 | ||
481 | static int dice_change_rate(struct dice *dice, unsigned int clock_rate) | ||
482 | { | ||
483 | __be32 value; | ||
484 | int err; | ||
485 | |||
486 | INIT_COMPLETION(dice->clock_accepted); | ||
487 | |||
488 | value = cpu_to_be32(clock_rate | CLOCK_SOURCE_ARX1); | ||
489 | err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, | ||
490 | global_address(dice, GLOBAL_CLOCK_SELECT), | ||
491 | &value, 4, 0); | ||
492 | if (err < 0) | ||
493 | return err; | ||
494 | |||
495 | wait_for_completion_timeout(&dice->clock_accepted, | ||
496 | msecs_to_jiffies(100)); | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
460 | static int dice_hw_params(struct snd_pcm_substream *substream, | 501 | static int dice_hw_params(struct snd_pcm_substream *substream, |
461 | struct snd_pcm_hw_params *hw_params) | 502 | struct snd_pcm_hw_params *hw_params) |
462 | { | 503 | { |
@@ -831,11 +872,51 @@ static int dice_interface_check(struct fw_unit *unit) | |||
831 | return 0; | 872 | return 0; |
832 | } | 873 | } |
833 | 874 | ||
875 | static int highest_supported_mode_rate(struct dice *dice, unsigned int mode) | ||
876 | { | ||
877 | int i; | ||
878 | |||
879 | for (i = ARRAY_SIZE(dice_rates) - 1; i >= 0; --i) | ||
880 | if ((dice->clock_caps & (1 << i)) && | ||
881 | rate_index_to_mode(i) == mode) | ||
882 | return i; | ||
883 | |||
884 | return -1; | ||
885 | } | ||
886 | |||
887 | static int dice_read_mode_params(struct dice *dice, unsigned int mode) | ||
888 | { | ||
889 | __be32 values[2]; | ||
890 | int rate_index, err; | ||
891 | |||
892 | rate_index = highest_supported_mode_rate(dice, mode); | ||
893 | if (rate_index < 0) { | ||
894 | dice->rx_channels[mode] = 0; | ||
895 | dice->rx_midi_ports[mode] = 0; | ||
896 | return 0; | ||
897 | } | ||
898 | |||
899 | err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT); | ||
900 | if (err < 0) | ||
901 | return err; | ||
902 | |||
903 | err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, | ||
904 | rx_address(dice, RX_NUMBER_AUDIO), | ||
905 | values, 2 * 4, 0); | ||
906 | if (err < 0) | ||
907 | return err; | ||
908 | |||
909 | dice->rx_channels[mode] = be32_to_cpu(values[0]); | ||
910 | dice->rx_midi_ports[mode] = be32_to_cpu(values[1]); | ||
911 | |||
912 | return 0; | ||
913 | } | ||
914 | |||
834 | static int dice_read_params(struct dice *dice) | 915 | static int dice_read_params(struct dice *dice) |
835 | { | 916 | { |
836 | __be32 pointers[6]; | 917 | __be32 pointers[6]; |
837 | __be32 value; | 918 | __be32 value; |
838 | int err; | 919 | int mode, err; |
839 | 920 | ||
840 | err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, | 921 | err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, |
841 | DICE_PRIVATE_SPACE, | 922 | DICE_PRIVATE_SPACE, |
@@ -863,6 +944,12 @@ static int dice_read_params(struct dice *dice) | |||
863 | CLOCK_CAP_SOURCE_INTERNAL; | 944 | CLOCK_CAP_SOURCE_INTERNAL; |
864 | } | 945 | } |
865 | 946 | ||
947 | for (mode = 2; mode >= 0; --mode) { | ||
948 | err = dice_read_mode_params(dice, mode); | ||
949 | if (err < 0) | ||
950 | return err; | ||
951 | } | ||
952 | |||
866 | return 0; | 953 | return 0; |
867 | } | 954 | } |
868 | 955 | ||
@@ -922,6 +1009,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) | |||
922 | spin_lock_init(&dice->lock); | 1009 | spin_lock_init(&dice->lock); |
923 | mutex_init(&dice->mutex); | 1010 | mutex_init(&dice->mutex); |
924 | dice->unit = unit; | 1011 | dice->unit = unit; |
1012 | init_completion(&dice->clock_accepted); | ||
925 | init_waitqueue_head(&dice->hwdep_wait); | 1013 | init_waitqueue_head(&dice->hwdep_wait); |
926 | 1014 | ||
927 | dice->notification_handler.length = 4; | 1015 | dice->notification_handler.length = 4; |