Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: add DICE driver

As a start point for further development, this is an incomplete driver
for DICE devices:
- only playback (so no clock source except the bus clock)
- only 44.1 kHz
- no MIDI
- recovery after bus reset is slow
- hwdep device is created, but not actually implemented

Contains compilation fixes by Stefan Richter.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>

+1078 -1
+1
Documentation/ioctl/ioctl-number.txt
··· 138 138 'H' C0-DF net/bluetooth/cmtp/cmtp.h conflict! 139 139 'H' C0-DF net/bluetooth/bnep/bnep.h conflict! 140 140 'H' F1 linux/hid-roccat.h <mailto:erazor_de@users.sourceforge.net> 141 + 'H' F8-FA sound/firewire.h 141 142 'I' all linux/isdn.h conflict! 142 143 'I' 00-0F drivers/isdn/divert/isdn_divert.h conflict! 143 144 'I' 40-4F linux/mISDNif.h conflict!
+1
include/uapi/sound/Kbuild
··· 5 5 header-y += compress_offload.h 6 6 header-y += compress_params.h 7 7 header-y += emu10k1.h 8 + header-y += firewire.h 8 9 header-y += hdsp.h 9 10 header-y += hdspm.h 10 11 header-y += sb16_csp.h
+2 -1
include/uapi/sound/asound.h
··· 93 93 SNDRV_HWDEP_IFACE_SB_RC, /* SB Extigy/Audigy2NX remote control */ 94 94 SNDRV_HWDEP_IFACE_HDA, /* HD-audio */ 95 95 SNDRV_HWDEP_IFACE_USB_STREAM, /* direct access to usb stream */ 96 + SNDRV_HWDEP_IFACE_FW_DICE, /* TC DICE FireWire device */ 96 97 97 98 /* Don't forget to change the following: */ 98 - SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM 99 + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_DICE 99 100 }; 100 101 101 102 struct snd_hwdep_info {
+51
include/uapi/sound/firewire.h
··· 1 + #ifndef UAPI_SOUND_FIREWIRE_H_INCLUDED 2 + #define UAPI_SOUND_FIREWIRE_H_INCLUDED 3 + 4 + #include <linux/ioctl.h> 5 + 6 + /* events can be read() from the hwdep device */ 7 + 8 + #define SNDRV_FIREWIRE_EVENT_LOCK_STATUS 0x000010cc 9 + #define SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION 0xd1ce004e 10 + 11 + struct snd_firewire_event_common { 12 + unsigned int type; /* SNDRV_FIREWIRE_EVENT_xxx */ 13 + }; 14 + 15 + struct snd_firewire_event_lock_status { 16 + unsigned int type; 17 + unsigned int status; /* 0/1 = unlocked/locked */ 18 + }; 19 + 20 + struct snd_firewire_event_dice_notification { 21 + unsigned int type; 22 + unsigned int notification; /* DICE-specific bits */ 23 + }; 24 + 25 + union snd_firewire_event { 26 + struct snd_firewire_event_common common; 27 + struct snd_firewire_event_lock_status lock_status; 28 + struct snd_firewire_event_dice_notification dice_notification; 29 + }; 30 + 31 + 32 + #define SNDRV_FIREWIRE_IOCTL_GET_INFO _IOR('H', 0xf8, struct snd_firewire_get_info) 33 + #define SNDRV_FIREWIRE_IOCTL_LOCK _IO('H', 0xf9) 34 + #define SNDRV_FIREWIRE_IOCTL_UNLOCK _IO('H', 0xfa) 35 + 36 + #define SNDRV_FIREWIRE_TYPE_DICE 1 37 + /* Fireworks, AV/C, RME, MOTU, ... */ 38 + 39 + struct snd_firewire_get_info { 40 + unsigned int type; /* SNDRV_FIREWIRE_TYPE_xxx */ 41 + unsigned int card; /* same as fw_cdev_get_info.card */ 42 + unsigned char guid[8]; 43 + char device_name[16]; /* device node in /dev */ 44 + }; 45 + 46 + /* 47 + * SNDRV_FIREWIRE_IOCTL_LOCK prevents the driver from streaming. 48 + * Returns -EBUSY if the driver is already streaming. 49 + */ 50 + 51 + #endif
+13
sound/firewire/Kconfig
··· 11 11 tristate 12 12 depends on SND_PCM 13 13 14 + config SND_DICE 15 + tristate "DICE devices (EXPERIMENTAL)" 16 + select SND_HWDEP 17 + select SND_PCM 18 + select SND_FIREWIRE_LIB 19 + help 20 + Say Y here to include support for many FireWire audio interfaces 21 + based on the DICE chip family (DICE-II/Jr/Mini) from TC Applied 22 + Technologies. 23 + 24 + To compile this driver as a module, choose M here: the module 25 + will be called snd-dice. 26 + 14 27 config SND_FIREWIRE_SPEAKERS 15 28 tristate "FireWire speakers" 16 29 select SND_PCM
+2
sound/firewire/Makefile
··· 1 1 snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ 2 2 fcp.o cmp.o amdtp.o 3 + snd-dice-objs := dice.o 3 4 snd-firewire-speakers-objs := speakers.o 4 5 snd-isight-objs := isight.o 5 6 snd-scs1x-objs := scs1x.o 6 7 7 8 obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o 9 + obj-$(CONFIG_SND_DICE) += snd-dice.o 8 10 obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o 9 11 obj-$(CONFIG_SND_ISIGHT) += snd-isight.o 10 12 obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o
+1008
sound/firewire/dice.c
··· 1 + /* 2 + * TC Applied Technologies Digital Interface Communications Engine driver 3 + * 4 + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 5 + * Licensed under the terms of the GNU General Public License, version 2. 6 + */ 7 + 8 + #include <linux/delay.h> 9 + #include <linux/device.h> 10 + #include <linux/firewire.h> 11 + #include <linux/firewire-constants.h> 12 + #include <linux/module.h> 13 + #include <linux/mod_devicetable.h> 14 + #include <linux/mutex.h> 15 + #include <linux/slab.h> 16 + #include <sound/control.h> 17 + #include <sound/core.h> 18 + #include <sound/hwdep.h> 19 + #include <sound/initval.h> 20 + #include <sound/pcm.h> 21 + #include <sound/pcm_params.h> 22 + #include "amdtp.h" 23 + #include "iso-resources.h" 24 + #include "lib.h" 25 + 26 + #define DICE_PRIVATE_SPACE 0xffffe0000000uLL 27 + 28 + /* offset from DICE_PRIVATE_SPACE; offsets and sizes in quadlets */ 29 + #define DICE_GLOBAL_OFFSET 0x00 30 + #define DICE_GLOBAL_SIZE 0x04 31 + #define DICE_TX_OFFSET 0x08 32 + #define DICE_TX_SIZE 0x0c 33 + #define DICE_RX_OFFSET 0x10 34 + #define DICE_RX_SIZE 0x14 35 + 36 + /* pointed to by DICE_GLOBAL_OFFSET */ 37 + #define GLOBAL_OWNER 0x000 38 + #define OWNER_NO_OWNER 0xffff000000000000uLL 39 + #define OWNER_NODE_SHIFT 48 40 + #define GLOBAL_NOTIFICATION 0x008 41 + #define NOTIFY_RX_CFG_CHG 0x00000001 42 + #define NOTIFY_TX_CFG_CHG 0x00000002 43 + #define NOTIFY_DUP_ISOC 0x00000004 44 + #define NOTIFY_BW_ERR 0x00000008 45 + #define NOTIFY_LOCK_CHG 0x00000010 46 + #define NOTIFY_CLOCK_ACCEPTED 0x00000020 47 + #define NOTIFY_INTERFACE_CHG 0x00000040 48 + #define NOTIFY_MESSAGE 0x00100000 49 + #define GLOBAL_NICK_NAME 0x00c 50 + #define NICK_NAME_SIZE 64 51 + #define GLOBAL_CLOCK_SELECT 0x04c 52 + #define CLOCK_SOURCE_MASK 0x000000ff 53 + #define CLOCK_SOURCE_AES1 0x00000000 54 + #define CLOCK_SOURCE_AES2 0x00000001 55 + #define CLOCK_SOURCE_AES3 0x00000002 56 + #define CLOCK_SOURCE_AES4 0x00000003 57 + #define CLOCK_SOURCE_AES_ANY 0x00000004 58 + #define CLOCK_SOURCE_ADAT 0x00000005 59 + #define CLOCK_SOURCE_TDIF 0x00000006 60 + #define CLOCK_SOURCE_WC 0x00000007 61 + #define CLOCK_SOURCE_ARX1 0x00000008 62 + #define CLOCK_SOURCE_ARX2 0x00000009 63 + #define CLOCK_SOURCE_ARX3 0x0000000a 64 + #define CLOCK_SOURCE_ARX4 0x0000000b 65 + #define CLOCK_SOURCE_INTERNAL 0x0000000c 66 + #define CLOCK_RATE_MASK 0x0000ff00 67 + #define CLOCK_RATE_32000 0x00000000 68 + #define CLOCK_RATE_44100 0x00000100 69 + #define CLOCK_RATE_48000 0x00000200 70 + #define CLOCK_RATE_88200 0x00000300 71 + #define CLOCK_RATE_96000 0x00000400 72 + #define CLOCK_RATE_176400 0x00000500 73 + #define CLOCK_RATE_192000 0x00000600 74 + #define CLOCK_RATE_ANY_LOW 0x00000700 75 + #define CLOCK_RATE_ANY_MID 0x00000800 76 + #define CLOCK_RATE_ANY_HIGH 0x00000900 77 + #define CLOCK_RATE_NONE 0x00000a00 78 + #define GLOBAL_ENABLE 0x050 79 + #define ENABLE 0x00000001 80 + #define GLOBAL_STATUS 0x054 81 + #define STATUS_SOURCE_LOCKED 0x00000001 82 + #define STATUS_RATE_CONFLICT 0x00000002 83 + #define STATUS_NOMINAL_RATE_MASK 0x0000ff00 84 + #define GLOBAL_EXTENDED_STATUS 0x058 85 + #define EXT_STATUS_AES1_LOCKED 0x00000001 86 + #define EXT_STATUS_AES2_LOCKED 0x00000002 87 + #define EXT_STATUS_AES3_LOCKED 0x00000004 88 + #define EXT_STATUS_AES4_LOCKED 0x00000008 89 + #define EXT_STATUS_ADAT_LOCKED 0x00000010 90 + #define EXT_STATUS_TDIF_LOCKED 0x00000020 91 + #define EXT_STATUS_ARX1_LOCKED 0x00000040 92 + #define EXT_STATUS_ARX2_LOCKED 0x00000080 93 + #define EXT_STATUS_ARX3_LOCKED 0x00000100 94 + #define EXT_STATUS_ARX4_LOCKED 0x00000200 95 + #define EXT_STATUS_WC_LOCKED 0x00000400 96 + #define EXT_STATUS_AES1_SLIP 0x00010000 97 + #define EXT_STATUS_AES2_SLIP 0x00020000 98 + #define EXT_STATUS_AES3_SLIP 0x00040000 99 + #define EXT_STATUS_AES4_SLIP 0x00080000 100 + #define EXT_STATUS_ADAT_SLIP 0x00100000 101 + #define EXT_STATUS_TDIF_SLIP 0x00200000 102 + #define EXT_STATUS_ARX1_SLIP 0x00400000 103 + #define EXT_STATUS_ARX2_SLIP 0x00800000 104 + #define EXT_STATUS_ARX3_SLIP 0x01000000 105 + #define EXT_STATUS_ARX4_SLIP 0x02000000 106 + #define EXT_STATUS_WC_SLIP 0x04000000 107 + #define GLOBAL_SAMPLE_RATE 0x05c 108 + #define GLOBAL_VERSION 0x060 109 + #define GLOBAL_CLOCK_CAPABILITIES 0x064 110 + #define CLOCK_CAP_RATE_32000 0x00000001 111 + #define CLOCK_CAP_RATE_44100 0x00000002 112 + #define CLOCK_CAP_RATE_48000 0x00000004 113 + #define CLOCK_CAP_RATE_88200 0x00000008 114 + #define CLOCK_CAP_RATE_96000 0x00000010 115 + #define CLOCK_CAP_RATE_176400 0x00000020 116 + #define CLOCK_CAP_RATE_192000 0x00000040 117 + #define CLOCK_CAP_SOURCE_AES1 0x00010000 118 + #define CLOCK_CAP_SOURCE_AES2 0x00020000 119 + #define CLOCK_CAP_SOURCE_AES3 0x00040000 120 + #define CLOCK_CAP_SOURCE_AES4 0x00080000 121 + #define CLOCK_CAP_SOURCE_AES_ANY 0x00100000 122 + #define CLOCK_CAP_SOURCE_ADAT 0x00200000 123 + #define CLOCK_CAP_SOURCE_TDIF 0x00400000 124 + #define CLOCK_CAP_SOURCE_WC 0x00800000 125 + #define CLOCK_CAP_SOURCE_ARX1 0x01000000 126 + #define CLOCK_CAP_SOURCE_ARX2 0x02000000 127 + #define CLOCK_CAP_SOURCE_ARX3 0x04000000 128 + #define CLOCK_CAP_SOURCE_ARX4 0x08000000 129 + #define CLOCK_CAP_SOURCE_INTERNAL 0x10000000 130 + #define GLOBAL_CLOCK_SOURCE_NAMES 0x068 131 + #define CLOCK_SOURCE_NAMES_SIZE 256 132 + 133 + /* pointed to by DICE_TX_OFFSET */ 134 + #define TX_NUMBER 0x000 135 + #define TX_SIZE 0x004 136 + /* repeated TX_NUMBER times, offset by TX_SIZE quadlets */ 137 + #define TX_ISOCHRONOUS 0x008 138 + #define TX_NUMBER_AUDIO 0x00c 139 + #define TX_NUMBER_MIDI 0x010 140 + #define TX_SPEED 0x014 141 + #define TX_NAMES 0x018 142 + #define TX_NAMES_SIZE 256 143 + #define TX_AC3_CAPABILITIES 0x118 144 + #define TX_AC3_ENABLE 0x11c 145 + 146 + /* pointed to by DICE_RX_OFFSET */ 147 + #define RX_NUMBER 0x000 148 + #define RX_SIZE 0x004 149 + /* repeated RX_NUMBER times, offset by RX_SIZE quadlets */ 150 + #define RX_ISOCHRONOUS 0x008 151 + #define RX_SEQ_START 0x00c 152 + #define RX_NUMBER_AUDIO 0x010 153 + #define RX_NUMBER_MIDI 0x014 154 + #define RX_NAMES 0x018 155 + #define RX_NAMES_SIZE 256 156 + #define RX_AC3_CAPABILITIES 0x118 157 + #define RX_AC3_ENABLE 0x11c 158 + 159 + 160 + #define FIRMWARE_LOAD_SPACE 0xffffe0100000uLL 161 + 162 + /* offset from FIRMWARE_LOAD_SPACE */ 163 + #define FIRMWARE_VERSION 0x000 164 + #define FIRMWARE_OPCODE 0x004 165 + #define OPCODE_MASK 0x00000fff 166 + #define OPCODE_GET_IMAGE_DESC 0x00000000 167 + #define OPCODE_DELETE_IMAGE 0x00000001 168 + #define OPCODE_CREATE_IMAGE 0x00000002 169 + #define OPCODE_UPLOAD 0x00000003 170 + #define OPCODE_UPLOAD_STAT 0x00000004 171 + #define OPCODE_RESET_IMAGE 0x00000005 172 + #define OPCODE_TEST_ACTION 0x00000006 173 + #define OPCODE_GET_RUNNING_IMAGE_VINFO 0x0000000a 174 + #define OPCODE_EXECUTE 0x80000000 175 + #define FIRMWARE_RETURN_STATUS 0x008 176 + #define FIRMWARE_PROGRESS 0x00c 177 + #define PROGRESS_CURR_MASK 0x00000fff 178 + #define PROGRESS_MAX_MASK 0x00fff000 179 + #define PROGRESS_TOUT_MASK 0x0f000000 180 + #define PROGRESS_FLAG 0x80000000 181 + #define FIRMWARE_CAPABILITIES 0x010 182 + #define FL_CAP_AUTOERASE 0x00000001 183 + #define FL_CAP_PROGRESS 0x00000002 184 + #define FIRMWARE_DATA 0x02c 185 + #define TEST_CMD_POKE 0x00000001 186 + #define TEST_CMD_PEEK 0x00000002 187 + #define CMD_GET_AVS_CNT 0x00000003 188 + #define CMD_CLR_AVS_CNT 0x00000004 189 + #define CMD_SET_MODE 0x00000005 190 + #define CMD_SET_MIDIBP 0x00000006 191 + #define CMD_GET_AVSPHASE 0x00000007 192 + #define CMD_ENABLE_BNC_SYNC 0x00000008 193 + #define CMD_PULSE_BNC_SYNC 0x00000009 194 + #define CMD_EMUL_SLOW_CMD 0x0000000a 195 + #define FIRMWARE_TEST_DELAY 0xfd8 196 + #define FIRMWARE_TEST_BUF 0xfdc 197 + 198 + 199 + /* EAP */ 200 + #define EAP_PRIVATE_SPACE 0xffffe0200000uLL 201 + 202 + #define EAP_CAPABILITY_OFFSET 0x000 203 + #define EAP_CAPABILITY_SIZE 0x004 204 + /* ... */ 205 + 206 + #define EAP_ROUTER_CAPS 0x000 207 + #define ROUTER_EXPOSED 0x00000001 208 + #define ROUTER_READ_ONLY 0x00000002 209 + #define ROUTER_FLASH 0x00000004 210 + #define MAX_ROUTES_MASK 0xffff0000 211 + #define EAP_MIXER_CAPS 0x004 212 + #define MIXER_EXPOSED 0x00000001 213 + #define MIXER_READ_ONLY 0x00000002 214 + #define MIXER_FLASH 0x00000004 215 + #define MIXER_IN_DEV_MASK 0x000000f0 216 + #define MIXER_OUT_DEV_MASK 0x00000f00 217 + #define MIXER_INPUTS_MASK 0x00ff0000 218 + #define MIXER_OUTPUTS_MASK 0xff000000 219 + #define EAP_GENERAL_CAPS 0x008 220 + #define GENERAL_STREAM_CONFIG 0x00000001 221 + #define GENERAL_FLASH 0x00000002 222 + #define GENERAL_PEAK 0x00000004 223 + #define GENERAL_MAX_TX_STREAMS_MASK 0x000000f0 224 + #define GENERAL_MAX_RX_STREAMS_MASK 0x00000f00 225 + #define GENERAL_STREAM_CONFIG_FLASH 0x00001000 226 + #define GENERAL_CHIP_MASK 0x00ff0000 227 + #define GENERAL_CHIP_DICE_II 0x00000000 228 + #define GENERAL_CHIP_DICE_MINI 0x00010000 229 + #define GENERAL_CHIP_DICE_JR 0x00020000 230 + 231 + 232 + struct dice { 233 + struct snd_card *card; 234 + struct fw_unit *unit; 235 + struct mutex mutex; 236 + unsigned int global_offset; 237 + unsigned int rx_offset; 238 + struct fw_address_handler notification_handler; 239 + int owner_generation; 240 + bool global_enabled; 241 + bool stream_running; 242 + struct snd_pcm_substream *pcm; 243 + struct fw_iso_resources resources; 244 + struct amdtp_out_stream stream; 245 + }; 246 + 247 + MODULE_DESCRIPTION("DICE driver"); 248 + MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); 249 + MODULE_LICENSE("GPL v2"); 250 + 251 + static inline u64 global_address(struct dice *dice, unsigned int offset) 252 + { 253 + return DICE_PRIVATE_SPACE + dice->global_offset + offset; 254 + } 255 + 256 + // TODO: rx index 257 + static inline u64 rx_address(struct dice *dice, unsigned int offset) 258 + { 259 + return DICE_PRIVATE_SPACE + dice->rx_offset + offset; 260 + } 261 + 262 + static int dice_owner_set(struct dice *dice) 263 + { 264 + struct fw_device *device = fw_parent_device(dice->unit); 265 + __be64 *buffer; 266 + int rcode, err, errors = 0; 267 + 268 + buffer = kmalloc(2 * 8, GFP_KERNEL); 269 + if (!buffer) 270 + return -ENOMEM; 271 + 272 + for (;;) { 273 + buffer[0] = cpu_to_be64(OWNER_NO_OWNER); 274 + buffer[1] = cpu_to_be64( 275 + ((u64)device->card->node_id << OWNER_NODE_SHIFT) | 276 + dice->notification_handler.offset); 277 + 278 + dice->owner_generation = device->generation; 279 + smp_rmb(); /* node_id vs. generation */ 280 + rcode = fw_run_transaction(device->card, 281 + TCODE_LOCK_COMPARE_SWAP, 282 + device->node_id, 283 + dice->owner_generation, 284 + device->max_speed, 285 + global_address(dice, GLOBAL_OWNER), 286 + buffer, 2 * 8); 287 + 288 + if (rcode == RCODE_COMPLETE) { 289 + if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER)) { 290 + err = 0; 291 + } else { 292 + dev_err(&dice->unit->device, 293 + "device is already in use\n"); 294 + err = -EBUSY; 295 + } 296 + break; 297 + } 298 + if (rcode_is_permanent_error(rcode) || ++errors >= 3) { 299 + dev_err(&dice->unit->device, 300 + "setting device owner failed: %s\n", 301 + fw_rcode_string(rcode)); 302 + err = -EIO; 303 + break; 304 + } 305 + msleep(20); 306 + } 307 + 308 + kfree(buffer); 309 + 310 + return err; 311 + } 312 + 313 + static int dice_owner_update(struct dice *dice) 314 + { 315 + struct fw_device *device = fw_parent_device(dice->unit); 316 + __be64 *buffer; 317 + int rcode, err, errors = 0; 318 + 319 + if (dice->owner_generation == -1) 320 + return 0; 321 + 322 + buffer = kmalloc(2 * 8, GFP_KERNEL); 323 + if (!buffer) 324 + return -ENOMEM; 325 + 326 + for (;;) { 327 + buffer[0] = cpu_to_be64(OWNER_NO_OWNER); 328 + buffer[1] = cpu_to_be64( 329 + ((u64)device->card->node_id << OWNER_NODE_SHIFT) | 330 + dice->notification_handler.offset); 331 + 332 + dice->owner_generation = device->generation; 333 + smp_rmb(); /* node_id vs. generation */ 334 + rcode = fw_run_transaction(device->card, 335 + TCODE_LOCK_COMPARE_SWAP, 336 + device->node_id, 337 + dice->owner_generation, 338 + device->max_speed, 339 + global_address(dice, GLOBAL_OWNER), 340 + buffer, 2 * 8); 341 + 342 + if (rcode == RCODE_COMPLETE) { 343 + if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER)) { 344 + err = 0; 345 + } else { 346 + dev_err(&dice->unit->device, 347 + "device is already in use\n"); 348 + err = -EBUSY; 349 + } 350 + break; 351 + } 352 + if (rcode == RCODE_GENERATION) { 353 + err = 0; /* try again later */ 354 + break; 355 + } 356 + if (rcode_is_permanent_error(rcode) || ++errors >= 3) { 357 + dev_err(&dice->unit->device, 358 + "setting device owner failed: %s\n", 359 + fw_rcode_string(rcode)); 360 + err = -EIO; 361 + break; 362 + } 363 + msleep(20); 364 + } 365 + 366 + kfree(buffer); 367 + 368 + if (err < 0) 369 + dice->owner_generation = -1; 370 + 371 + return err; 372 + } 373 + 374 + static void dice_owner_clear(struct dice *dice) 375 + { 376 + struct fw_device *device = fw_parent_device(dice->unit); 377 + __be64 *buffer; 378 + int rcode, errors = 0; 379 + 380 + buffer = kmalloc(2 * 8, GFP_KERNEL); 381 + if (!buffer) 382 + return; 383 + 384 + for (;;) { 385 + buffer[0] = cpu_to_be64( 386 + ((u64)device->card->node_id << OWNER_NODE_SHIFT) | 387 + dice->notification_handler.offset); 388 + buffer[1] = cpu_to_be64(OWNER_NO_OWNER); 389 + 390 + rcode = fw_run_transaction(device->card, 391 + TCODE_LOCK_COMPARE_SWAP, 392 + device->node_id, 393 + dice->owner_generation, 394 + device->max_speed, 395 + global_address(dice, GLOBAL_OWNER), 396 + buffer, 2 * 8); 397 + 398 + if (rcode == RCODE_COMPLETE) 399 + break; 400 + if (rcode == RCODE_GENERATION) 401 + break; 402 + if (rcode_is_permanent_error(rcode) || ++errors >= 3) { 403 + dev_err(&dice->unit->device, 404 + "clearing device owner failed: %s\n", 405 + fw_rcode_string(rcode)); 406 + break; 407 + } 408 + msleep(20); 409 + } 410 + 411 + kfree(buffer); 412 + 413 + dice->owner_generation = -1; 414 + } 415 + 416 + static int dice_enable_set(struct dice *dice) 417 + { 418 + struct fw_device *device = fw_parent_device(dice->unit); 419 + __be32 value; 420 + int rcode, err, errors = 0; 421 + 422 + value = cpu_to_be32(ENABLE); 423 + for (;;) { 424 + rcode = fw_run_transaction(device->card, 425 + TCODE_WRITE_QUADLET_REQUEST, 426 + device->node_id, 427 + dice->owner_generation, 428 + device->max_speed, 429 + global_address(dice, GLOBAL_ENABLE), 430 + &value, 4); 431 + if (rcode == RCODE_COMPLETE) { 432 + dice->global_enabled = true; 433 + err = 0; 434 + break; 435 + } 436 + if (rcode == RCODE_GENERATION) { 437 + err = -EAGAIN; 438 + break; 439 + } 440 + if (rcode_is_permanent_error(rcode) || ++errors >= 3) { 441 + dev_err(&dice->unit->device, 442 + "device enabling failed: %s\n", 443 + fw_rcode_string(rcode)); 444 + err = -EIO; 445 + break; 446 + } 447 + msleep(20); 448 + } 449 + 450 + return err; 451 + } 452 + 453 + static void dice_enable_clear(struct dice *dice) 454 + { 455 + struct fw_device *device = fw_parent_device(dice->unit); 456 + __be32 value; 457 + int rcode, errors = 0; 458 + 459 + value = 0; 460 + for (;;) { 461 + rcode = fw_run_transaction(device->card, 462 + TCODE_WRITE_QUADLET_REQUEST, 463 + device->node_id, 464 + dice->owner_generation, 465 + device->max_speed, 466 + global_address(dice, GLOBAL_ENABLE), 467 + &value, 4); 468 + if (rcode == RCODE_COMPLETE || 469 + rcode == RCODE_GENERATION) 470 + break; 471 + if (rcode_is_permanent_error(rcode) || ++errors >= 3) { 472 + dev_err(&dice->unit->device, 473 + "device disabling failed: %s\n", 474 + fw_rcode_string(rcode)); 475 + break; 476 + } 477 + msleep(20); 478 + } 479 + dice->global_enabled = false; 480 + } 481 + 482 + static void dice_notification(struct fw_card *card, struct fw_request *request, 483 + int tcode, int destination, int source, 484 + int generation, unsigned long long offset, 485 + void *data, size_t length, void *callback_data) 486 + { 487 + struct dice *dice = callback_data; 488 + 489 + if (tcode != TCODE_WRITE_QUADLET_REQUEST) { 490 + fw_send_response(card, request, RCODE_TYPE_ERROR); 491 + return; 492 + } 493 + if ((offset & 3) != 0) { 494 + fw_send_response(card, request, RCODE_ADDRESS_ERROR); 495 + return; 496 + } 497 + dev_info(&dice->unit->device, 498 + "notification: %08x\n", be32_to_cpup(data)); 499 + fw_send_response(card, request, RCODE_COMPLETE); 500 + } 501 + 502 + static int dice_open(struct snd_pcm_substream *substream) 503 + { 504 + static const struct snd_pcm_hardware hardware = { 505 + .info = SNDRV_PCM_INFO_MMAP | 506 + SNDRV_PCM_INFO_MMAP_VALID | 507 + SNDRV_PCM_INFO_BATCH | 508 + SNDRV_PCM_INFO_INTERLEAVED | 509 + SNDRV_PCM_INFO_BLOCK_TRANSFER, 510 + .formats = AMDTP_OUT_PCM_FORMAT_BITS, 511 + .rates = SNDRV_PCM_RATE_44100, 512 + .rate_min = 44100, 513 + .rate_max = 44100, 514 + .buffer_bytes_max = 16 * 1024 * 1024, 515 + .period_bytes_min = 1, 516 + .period_bytes_max = UINT_MAX, 517 + .periods_min = 1, 518 + .periods_max = UINT_MAX, 519 + }; 520 + struct dice *dice = substream->private_data; 521 + struct snd_pcm_runtime *runtime = substream->runtime; 522 + __be32 number_audio, number_midi; 523 + int err; 524 + 525 + err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST, 526 + rx_address(dice, RX_NUMBER_AUDIO), 527 + &number_audio, 4); 528 + if (err < 0) 529 + return err; 530 + err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST, 531 + rx_address(dice, RX_NUMBER_MIDI), 532 + &number_midi, 4); 533 + if (err < 0) 534 + return err; 535 + 536 + runtime->hw = hardware; 537 + runtime->hw.channels_min = be32_to_cpu(number_audio); 538 + runtime->hw.channels_max = be32_to_cpu(number_audio); 539 + 540 + amdtp_out_stream_set_rate(&dice->stream, 44100); 541 + amdtp_out_stream_set_pcm(&dice->stream, be32_to_cpu(number_audio)); 542 + amdtp_out_stream_set_midi(&dice->stream, be32_to_cpu(number_midi)); 543 + 544 + err = snd_pcm_hw_constraint_minmax(runtime, 545 + SNDRV_PCM_HW_PARAM_PERIOD_TIME, 546 + 5000, 8192000); 547 + if (err < 0) 548 + return err; 549 + 550 + err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 551 + if (err < 0) 552 + return err; 553 + 554 + return 0; 555 + } 556 + 557 + static int dice_close(struct snd_pcm_substream *substream) 558 + { 559 + return 0; 560 + } 561 + 562 + static void dice_stop_stream(struct dice *dice) 563 + { 564 + __be32 channel; 565 + 566 + if (dice->stream_running) { 567 + dice_enable_clear(dice); 568 + 569 + amdtp_out_stream_stop(&dice->stream); 570 + 571 + channel = cpu_to_be32((u32)-1); 572 + snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, 573 + rx_address(dice, RX_ISOCHRONOUS), 574 + &channel, 4); 575 + 576 + fw_iso_resources_free(&dice->resources); 577 + 578 + dice->stream_running = false; 579 + } 580 + } 581 + 582 + static int dice_hw_params(struct snd_pcm_substream *substream, 583 + struct snd_pcm_hw_params *hw_params) 584 + { 585 + struct dice *dice = substream->private_data; 586 + int err; 587 + 588 + mutex_lock(&dice->mutex); 589 + dice_stop_stream(dice); 590 + mutex_unlock(&dice->mutex); 591 + 592 + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, 593 + params_buffer_bytes(hw_params)); 594 + if (err < 0) 595 + goto error; 596 + 597 + amdtp_out_stream_set_pcm_format(&dice->stream, 598 + params_format(hw_params)); 599 + 600 + return 0; 601 + 602 + error: 603 + return err; 604 + } 605 + 606 + static int dice_hw_free(struct snd_pcm_substream *substream) 607 + { 608 + struct dice *dice = substream->private_data; 609 + 610 + mutex_lock(&dice->mutex); 611 + dice_stop_stream(dice); 612 + mutex_unlock(&dice->mutex); 613 + 614 + return snd_pcm_lib_free_vmalloc_buffer(substream); 615 + } 616 + 617 + static int dice_prepare(struct snd_pcm_substream *substream) 618 + { 619 + struct dice *dice = substream->private_data; 620 + struct fw_device *device = fw_parent_device(dice->unit); 621 + __be32 channel; 622 + int err; 623 + 624 + mutex_lock(&dice->mutex); 625 + 626 + if (amdtp_out_streaming_error(&dice->stream)) 627 + dice_stop_stream(dice); 628 + 629 + if (!dice->stream_running) { 630 + err = fw_iso_resources_allocate(&dice->resources, 631 + amdtp_out_stream_get_max_payload(&dice->stream), 632 + device->max_speed); 633 + if (err < 0) 634 + goto error; 635 + 636 + //TODO: RX_SEQ_START 637 + channel = cpu_to_be32(dice->resources.channel); 638 + err = snd_fw_transaction(dice->unit, 639 + TCODE_WRITE_QUADLET_REQUEST, 640 + rx_address(dice, RX_ISOCHRONOUS), 641 + &channel, 4); 642 + if (err < 0) 643 + goto err_resources; 644 + 645 + err = amdtp_out_stream_start(&dice->stream, 646 + dice->resources.channel, 647 + device->max_speed); 648 + if (err < 0) 649 + goto err_resources; 650 + 651 + err = dice_enable_set(dice); 652 + if (err < 0) 653 + goto err_stream; 654 + 655 + dice->stream_running = true; 656 + } 657 + 658 + mutex_unlock(&dice->mutex); 659 + 660 + amdtp_out_stream_pcm_prepare(&dice->stream); 661 + 662 + return 0; 663 + 664 + err_stream: 665 + amdtp_out_stream_stop(&dice->stream); 666 + err_resources: 667 + fw_iso_resources_free(&dice->resources); 668 + error: 669 + mutex_unlock(&dice->mutex); 670 + 671 + return err; 672 + } 673 + 674 + static int dice_trigger(struct snd_pcm_substream *substream, int cmd) 675 + { 676 + struct dice *dice = substream->private_data; 677 + struct snd_pcm_substream *pcm; 678 + 679 + switch (cmd) { 680 + case SNDRV_PCM_TRIGGER_START: 681 + pcm = substream; 682 + break; 683 + case SNDRV_PCM_TRIGGER_STOP: 684 + pcm = NULL; 685 + break; 686 + default: 687 + return -EINVAL; 688 + } 689 + amdtp_out_stream_pcm_trigger(&dice->stream, pcm); 690 + 691 + return 0; 692 + } 693 + 694 + static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream) 695 + { 696 + struct dice *dice = substream->private_data; 697 + 698 + return amdtp_out_stream_pcm_pointer(&dice->stream); 699 + } 700 + 701 + static int dice_create_pcm(struct dice *dice) 702 + { 703 + static struct snd_pcm_ops ops = { 704 + .open = dice_open, 705 + .close = dice_close, 706 + .ioctl = snd_pcm_lib_ioctl, 707 + .hw_params = dice_hw_params, 708 + .hw_free = dice_hw_free, 709 + .prepare = dice_prepare, 710 + .trigger = dice_trigger, 711 + .pointer = dice_pointer, 712 + .page = snd_pcm_lib_get_vmalloc_page, 713 + .mmap = snd_pcm_lib_mmap_vmalloc, 714 + }; 715 + __be32 clock; 716 + struct snd_pcm *pcm; 717 + int err; 718 + 719 + clock = cpu_to_be32(CLOCK_SOURCE_ARX1 | CLOCK_RATE_44100); 720 + err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, 721 + global_address(dice, GLOBAL_CLOCK_SELECT), 722 + &clock, 4); 723 + if (err < 0) 724 + return err; 725 + 726 + err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm); 727 + if (err < 0) 728 + return err; 729 + pcm->private_data = dice; 730 + strcpy(pcm->name, dice->card->shortname); 731 + dice->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 732 + dice->pcm->ops = &ops; 733 + 734 + return 0; 735 + } 736 + 737 + // TODO: implement these 738 + 739 + static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, 740 + long count, loff_t *offset) 741 + { 742 + return -EIO; 743 + } 744 + 745 + static int dice_hwdep_open(struct snd_hwdep *hwdep, struct file *file) 746 + { 747 + return -EIO; 748 + } 749 + 750 + static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file) 751 + { 752 + return 0; 753 + } 754 + 755 + static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file, 756 + poll_table *wait) 757 + { 758 + return POLLERR | POLLHUP; 759 + } 760 + 761 + static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, 762 + unsigned int cmd, unsigned long arg) 763 + { 764 + return -EIO; 765 + } 766 + 767 + static int dice_create_hwdep(struct dice *dice) 768 + { 769 + static const struct snd_hwdep_ops ops = { 770 + .read = dice_hwdep_read, 771 + .open = dice_hwdep_open, 772 + .release = dice_hwdep_release, 773 + .poll = dice_hwdep_poll, 774 + .ioctl = dice_hwdep_ioctl, 775 + .ioctl_compat = dice_hwdep_ioctl, 776 + }; 777 + struct snd_hwdep *hwdep; 778 + int err; 779 + 780 + err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep); 781 + if (err < 0) 782 + return err; 783 + strcpy(hwdep->name, "DICE"); 784 + hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE; 785 + hwdep->ops = ops; 786 + hwdep->private_data = dice; 787 + hwdep->exclusive = true; 788 + 789 + return 0; 790 + } 791 + 792 + static void dice_card_free(struct snd_card *card) 793 + { 794 + struct dice *dice = card->private_data; 795 + 796 + amdtp_out_stream_destroy(&dice->stream); 797 + fw_core_remove_address_handler(&dice->notification_handler); 798 + mutex_destroy(&dice->mutex); 799 + } 800 + 801 + static int dice_init_offsets(struct dice *dice) 802 + { 803 + __be32 pointers[6]; 804 + unsigned int global_size, rx_size; 805 + int err; 806 + 807 + err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, 808 + DICE_PRIVATE_SPACE, &pointers, 6 * 4); 809 + if (err < 0) 810 + return err; 811 + 812 + dice->global_offset = be32_to_cpu(pointers[0]) * 4; 813 + global_size = be32_to_cpu(pointers[1]); 814 + dice->rx_offset = be32_to_cpu(pointers[4]) * 4; 815 + rx_size = be32_to_cpu(pointers[5]); 816 + 817 + /* some sanity checks to ensure that we actually have a DICE */ 818 + if (dice->global_offset < 10 * 4 || global_size < 0x168 / 4 || 819 + dice->rx_offset < 10 * 4 || rx_size < 0x120 / 4) { 820 + dev_err(&dice->unit->device, "invalid register pointers\n"); 821 + return -ENXIO; 822 + } 823 + 824 + return 0; 825 + } 826 + 827 + static void dice_card_strings(struct dice *dice) 828 + { 829 + struct snd_card *card = dice->card; 830 + struct fw_device *dev = fw_parent_device(dice->unit); 831 + char vendor[32], model[32]; 832 + unsigned int i; 833 + int err; 834 + 835 + strcpy(card->driver, "DICE"); 836 + 837 + strcpy(card->shortname, "DICE"); 838 + BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname)); 839 + err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, 840 + global_address(dice, GLOBAL_NICK_NAME), 841 + card->shortname, sizeof(card->shortname)); 842 + if (err >= 0) { 843 + /* DICE strings are returned in "always-wrong" endianness */ 844 + BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0); 845 + for (i = 0; i < sizeof(card->shortname); i += 4) 846 + swab32s((u32 *)&card->shortname[i]); 847 + card->shortname[sizeof(card->shortname) - 1] = '\0'; 848 + } 849 + 850 + strcpy(vendor, "?"); 851 + fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor)); 852 + strcpy(model, "?"); 853 + fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model)); 854 + snprintf(card->longname, sizeof(card->longname), 855 + "%s %s, GUID %08x%08x at %s, S%d", 856 + vendor, model, dev->config_rom[3], dev->config_rom[4], 857 + dev_name(&dice->unit->device), 100 << dev->max_speed); 858 + 859 + strcpy(card->mixername, "DICE"); 860 + } 861 + 862 + static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) 863 + { 864 + struct snd_card *card; 865 + struct dice *dice; 866 + int err; 867 + 868 + err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*dice), &card); 869 + if (err < 0) 870 + return err; 871 + snd_card_set_dev(card, &unit->device); 872 + 873 + dice = card->private_data; 874 + dice->card = card; 875 + mutex_init(&dice->mutex); 876 + dice->unit = unit; 877 + 878 + err = dice_init_offsets(dice); 879 + if (err < 0) 880 + goto err_mutex; 881 + 882 + dice->notification_handler.length = 4; 883 + dice->notification_handler.address_callback = dice_notification; 884 + dice->notification_handler.callback_data = dice; 885 + err = fw_core_add_address_handler(&dice->notification_handler, 886 + &fw_high_memory_region); 887 + if (err < 0) 888 + goto err_mutex; 889 + 890 + err = fw_iso_resources_init(&dice->resources, unit); 891 + if (err < 0) 892 + goto err_notification_handler; 893 + dice->resources.channels_mask = 0x00000000ffffffffuLL; 894 + 895 + err = amdtp_out_stream_init(&dice->stream, unit, CIP_NONBLOCKING); 896 + if (err < 0) 897 + goto err_resources; 898 + 899 + err = dice_owner_set(dice); 900 + if (err < 0) 901 + goto err_stream; 902 + 903 + card->private_free = dice_card_free; 904 + 905 + dice_card_strings(dice); 906 + 907 + err = dice_create_pcm(dice); 908 + if (err < 0) 909 + goto error; 910 + 911 + err = dice_create_hwdep(dice); 912 + if (err < 0) 913 + goto error; 914 + 915 + err = snd_card_register(card); 916 + if (err < 0) 917 + goto error; 918 + 919 + dev_set_drvdata(&unit->device, dice); 920 + 921 + return 0; 922 + 923 + err_stream: 924 + amdtp_out_stream_destroy(&dice->stream); 925 + err_resources: 926 + fw_iso_resources_destroy(&dice->resources); 927 + err_notification_handler: 928 + fw_core_remove_address_handler(&dice->notification_handler); 929 + err_mutex: 930 + mutex_destroy(&dice->mutex); 931 + error: 932 + snd_card_free(card); 933 + return err; 934 + } 935 + 936 + static void dice_remove(struct fw_unit *unit) 937 + { 938 + struct dice *dice = dev_get_drvdata(&unit->device); 939 + 940 + snd_card_disconnect(dice->card); 941 + 942 + mutex_lock(&dice->mutex); 943 + amdtp_out_stream_pcm_abort(&dice->stream); 944 + dice_stop_stream(dice); 945 + dice_owner_clear(dice); 946 + mutex_unlock(&dice->mutex); 947 + 948 + snd_card_free_when_closed(dice->card); 949 + } 950 + 951 + static void dice_bus_reset(struct fw_unit *unit) 952 + { 953 + struct dice *dice = dev_get_drvdata(&unit->device); 954 + 955 + mutex_lock(&dice->mutex); 956 + /* 957 + * XXX is the following true? 958 + * On a bus reset, the DICE firmware disables streaming and then goes 959 + * off contemplating its own navel for hundreds of milliseconds before 960 + * it can react to any of our attempts to reenable streaming. This 961 + * means that we lose synchronization anyway, so we force our streams 962 + * to stop so that the application can restart them in an orderly 963 + * manner. 964 + */ 965 + dice_owner_update(dice); 966 + amdtp_out_stream_pcm_abort(&dice->stream); 967 + dice_stop_stream(dice); 968 + mutex_unlock(&dice->mutex); 969 + } 970 + 971 + #define TC_OUI 0x000166 972 + #define DICE_INTERFACE 0x000001 973 + 974 + static const struct ieee1394_device_id dice_id_table[] = { 975 + { 976 + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | 977 + IEEE1394_MATCH_VERSION, 978 + .specifier_id = TC_OUI, 979 + .version = DICE_INTERFACE, 980 + }, 981 + { } 982 + }; 983 + MODULE_DEVICE_TABLE(ieee1394, dice_id_table); 984 + 985 + static struct fw_driver dice_driver = { 986 + .driver = { 987 + .owner = THIS_MODULE, 988 + .name = KBUILD_MODNAME, 989 + .bus = &fw_bus_type, 990 + }, 991 + .probe = dice_probe, 992 + .update = dice_bus_reset, 993 + .remove = dice_remove, 994 + .id_table = dice_id_table, 995 + }; 996 + 997 + static int __init alsa_dice_init(void) 998 + { 999 + return driver_register(&dice_driver.driver); 1000 + } 1001 + 1002 + static void __exit alsa_dice_exit(void) 1003 + { 1004 + driver_unregister(&dice_driver.driver); 1005 + } 1006 + 1007 + module_init(alsa_dice_init); 1008 + module_exit(alsa_dice_exit);