1 /* 2 * oxfw-scs1x.c - a part of driver for OXFW970/971 based devices 3 * 4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 5 * Copyright (c) 2015 Takashi Sakamoto <o-takashi@sakamocchi.jp> 6 * 7 * Licensed under the terms of the GNU General Public License, version 2. 8 */ 9 10 #include "oxfw.h" 11 12 #define HSS1394_ADDRESS 0xc007dedadadaULL 13 #define HSS1394_MAX_PACKET_SIZE 64 14 #define HSS1394_TAG_USER_DATA 0x00 15 #define HSS1394_TAG_CHANGE_ADDRESS 0xf1 16 17 struct fw_scs1x { 18 struct fw_address_handler hss_handler; 19 u8 input_escape_count; 20 struct snd_rawmidi_substream *input; 21 22 /* For MIDI playback. */ 23 struct snd_rawmidi_substream *output; 24 bool output_idle; 25 u8 output_status; 26 u8 output_bytes; 27 bool output_escaped; 28 bool output_escape_high_nibble; 29 struct tasklet_struct tasklet; 30 wait_queue_head_t idle_wait; 31 u8 buffer[HSS1394_MAX_PACKET_SIZE]; 32 bool transaction_running; 33 struct fw_transaction transaction; 34 struct fw_device *fw_dev; 35 }; 36 37 static const u8 sysex_escape_prefix[] = { 38 0xf0, /* SysEx begin */ 39 0x00, 0x01, 0x60, /* Stanton DJ */ 40 0x48, 0x53, 0x53, /* "HSS" */ 41 }; 42 43 static void midi_input_escaped_byte(struct snd_rawmidi_substream *stream, 44 u8 byte) 45 { 46 u8 nibbles[2]; 47 48 nibbles[0] = byte >> 4; 49 nibbles[1] = byte & 0x0f; 50 snd_rawmidi_receive(stream, nibbles, 2); 51 } 52 53 static void midi_input_byte(struct fw_scs1x *scs, 54 struct snd_rawmidi_substream *stream, u8 byte) 55 { 56 const u8 eox = 0xf7; 57 58 if (scs->input_escape_count > 0) { 59 midi_input_escaped_byte(stream, byte); 60 scs->input_escape_count--; 61 if (scs->input_escape_count == 0) 62 snd_rawmidi_receive(stream, &eox, sizeof(eox)); 63 } else if (byte == 0xf9) { 64 snd_rawmidi_receive(stream, sysex_escape_prefix, 65 ARRAY_SIZE(sysex_escape_prefix)); 66 midi_input_escaped_byte(stream, 0x00); 67 midi_input_escaped_byte(stream, 0xf9); 68 scs->input_escape_count = 3; 69 } else { 70 snd_rawmidi_receive(stream, &byte, 1); 71 } 72 } 73 74 static void midi_input_packet(struct fw_scs1x *scs, 75 struct snd_rawmidi_substream *stream, 76 const u8 *data, unsigned int bytes) 77 { 78 unsigned int i; 79 const u8 eox = 0xf7; 80 81 if (data[0] == HSS1394_TAG_USER_DATA) { 82 for (i = 1; i < bytes; ++i) 83 midi_input_byte(scs, stream, data[i]); 84 } else { 85 snd_rawmidi_receive(stream, sysex_escape_prefix, 86 ARRAY_SIZE(sysex_escape_prefix)); 87 for (i = 0; i < bytes; ++i) 88 midi_input_escaped_byte(stream, data[i]); 89 snd_rawmidi_receive(stream, &eox, sizeof(eox)); 90 } 91 } 92 93 static void handle_hss(struct fw_card *card, struct fw_request *request, 94 int tcode, int destination, int source, int generation, 95 unsigned long long offset, void *data, size_t length, 96 void *callback_data) 97 { 98 struct fw_scs1x *scs = callback_data; 99 struct snd_rawmidi_substream *stream; 100 int rcode; 101 102 if (offset != scs->hss_handler.offset) { 103 rcode = RCODE_ADDRESS_ERROR; 104 goto end; 105 } 106 if (tcode != TCODE_WRITE_QUADLET_REQUEST && 107 tcode != TCODE_WRITE_BLOCK_REQUEST) { 108 rcode = RCODE_TYPE_ERROR; 109 goto end; 110 } 111 112 if (length >= 1) { 113 stream = ACCESS_ONCE(scs->input); 114 if (stream) 115 midi_input_packet(scs, stream, data, length); 116 } 117 118 rcode = RCODE_COMPLETE; 119 end: 120 fw_send_response(card, request, rcode); 121 } 122 123 static void scs_write_callback(struct fw_card *card, int rcode, 124 void *data, size_t length, void *callback_data) 125 { 126 struct fw_scs1x *scs = callback_data; 127 128 if (rcode == RCODE_GENERATION) 129 ; /* TODO: retry this packet */ 130 131 scs->transaction_running = false; 132 tasklet_schedule(&scs->tasklet); 133 } 134 135 static bool is_valid_running_status(u8 status) 136 { 137 return status >= 0x80 && status <= 0xef; 138 } 139 140 static bool is_one_byte_cmd(u8 status) 141 { 142 return status == 0xf6 || 143 status >= 0xf8; 144 } 145 146 static bool is_two_bytes_cmd(u8 status) 147 { 148 return (status >= 0xc0 && status <= 0xdf) || 149 status == 0xf1 || 150 status == 0xf3; 151 } 152 153 static bool is_three_bytes_cmd(u8 status) 154 { 155 return (status >= 0x80 && status <= 0xbf) || 156 (status >= 0xe0 && status <= 0xef) || 157 status == 0xf2; 158 } 159 160 static bool is_invalid_cmd(u8 status) 161 { 162 return status == 0xf4 || 163 status == 0xf5 || 164 status == 0xf9 || 165 status == 0xfd; 166 } 167 168 static void scs_output_tasklet(unsigned long data) 169 { 170 struct fw_scs1x *scs = (struct fw_scs1x *)data; 171 struct snd_rawmidi_substream *stream; 172 unsigned int i; 173 u8 byte; 174 int generation; 175 176 if (scs->transaction_running) 177 return; 178 179 stream = ACCESS_ONCE(scs->output); 180 if (!stream) { 181 scs->output_idle = true; 182 wake_up(&scs->idle_wait); 183 return; 184 } 185 186 i = scs->output_bytes; 187 for (;;) { 188 if (snd_rawmidi_transmit(stream, &byte, 1) != 1) { 189 scs->output_bytes = i; 190 scs->output_idle = true; 191 wake_up(&scs->idle_wait); 192 return; 193 } 194 /* 195 * Convert from real MIDI to what I think the device expects (no 196 * running status, one command per packet, unescaped SysExs). 197 */ 198 if (scs->output_escaped && byte < 0x80) { 199 if (scs->output_escape_high_nibble) { 200 if (i < HSS1394_MAX_PACKET_SIZE) { 201 scs->buffer[i] = byte << 4; 202 scs->output_escape_high_nibble = false; 203 } 204 } else { 205 scs->buffer[i++] |= byte & 0x0f; 206 scs->output_escape_high_nibble = true; 207 } 208 } else if (byte < 0x80) { 209 if (i == 1) { 210 if (!is_valid_running_status( 211 scs->output_status)) 212 continue; 213 scs->buffer[0] = HSS1394_TAG_USER_DATA; 214 scs->buffer[i++] = scs->output_status; 215 } 216 scs->buffer[i++] = byte; 217 if ((i == 3 && is_two_bytes_cmd(scs->output_status)) || 218 (i == 4 && is_three_bytes_cmd(scs->output_status))) 219 break; 220 if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) && 221 !memcmp(scs->buffer + 1, sysex_escape_prefix, 222 ARRAY_SIZE(sysex_escape_prefix))) { 223 scs->output_escaped = true; 224 scs->output_escape_high_nibble = true; 225 i = 0; 226 } 227 if (i >= HSS1394_MAX_PACKET_SIZE) 228 i = 1; 229 } else if (byte == 0xf7) { 230 if (scs->output_escaped) { 231 if (i >= 1 && scs->output_escape_high_nibble && 232 scs->buffer[0] != 233 HSS1394_TAG_CHANGE_ADDRESS) 234 break; 235 } else { 236 if (i > 1 && scs->output_status == 0xf0) { 237 scs->buffer[i++] = 0xf7; 238 break; 239 } 240 } 241 i = 1; 242 scs->output_escaped = false; 243 } else if (!is_invalid_cmd(byte) && byte < 0xf8) { 244 i = 1; 245 scs->buffer[0] = HSS1394_TAG_USER_DATA; 246 scs->buffer[i++] = byte; 247 scs->output_status = byte; 248 scs->output_escaped = false; 249 if (is_one_byte_cmd(byte)) 250 break; 251 } 252 } 253 scs->output_bytes = 1; 254 scs->output_escaped = false; 255 256 scs->transaction_running = true; 257 generation = scs->fw_dev->generation; 258 smp_rmb(); /* node_id vs. generation */ 259 fw_send_request(scs->fw_dev->card, &scs->transaction, 260 TCODE_WRITE_BLOCK_REQUEST, scs->fw_dev->node_id, 261 generation, scs->fw_dev->max_speed, HSS1394_ADDRESS, 262 scs->buffer, i, scs_write_callback, scs); 263 } 264 265 static int midi_capture_open(struct snd_rawmidi_substream *stream) 266 { 267 return 0; 268 } 269 270 static int midi_capture_close(struct snd_rawmidi_substream *stream) 271 { 272 return 0; 273 } 274 275 static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up) 276 { 277 struct fw_scs1x *scs = stream->rmidi->private_data; 278 279 if (up) { 280 scs->input_escape_count = 0; 281 ACCESS_ONCE(scs->input) = stream; 282 } else { 283 ACCESS_ONCE(scs->input) = NULL; 284 } 285 } 286 287 static struct snd_rawmidi_ops midi_capture_ops = { 288 .open = midi_capture_open, 289 .close = midi_capture_close, 290 .trigger = midi_capture_trigger, 291 }; 292 293 static int midi_playback_open(struct snd_rawmidi_substream *stream) 294 { 295 return 0; 296 } 297 298 static int midi_playback_close(struct snd_rawmidi_substream *stream) 299 { 300 return 0; 301 } 302 303 static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up) 304 { 305 struct fw_scs1x *scs = stream->rmidi->private_data; 306 307 if (up) { 308 scs->output_status = 0; 309 scs->output_bytes = 1; 310 scs->output_escaped = false; 311 scs->output_idle = false; 312 313 ACCESS_ONCE(scs->output) = stream; 314 tasklet_schedule(&scs->tasklet); 315 } else { 316 ACCESS_ONCE(scs->output) = NULL; 317 } 318 } 319 static void midi_playback_drain(struct snd_rawmidi_substream *stream) 320 { 321 struct fw_scs1x *scs = stream->rmidi->private_data; 322 323 wait_event(scs->idle_wait, scs->output_idle); 324 } 325 326 static struct snd_rawmidi_ops midi_playback_ops = { 327 .open = midi_playback_open, 328 .close = midi_playback_close, 329 .trigger = midi_playback_trigger, 330 .drain = midi_playback_drain, 331 }; 332 static int register_address(struct snd_oxfw *oxfw) 333 { 334 struct fw_scs1x *scs = oxfw->spec; 335 __be64 data; 336 337 data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | 338 scs->hss_handler.offset); 339 return snd_fw_transaction(oxfw->unit, TCODE_WRITE_BLOCK_REQUEST, 340 HSS1394_ADDRESS, &data, sizeof(data), 0); 341 } 342 343 static void remove_scs1x(struct snd_rawmidi *rmidi) 344 { 345 struct fw_scs1x *scs = rmidi->private_data; 346 347 fw_core_remove_address_handler(&scs->hss_handler); 348 } 349 350 void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw) 351 { 352 register_address(oxfw); 353 } 354 355 int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) 356 { 357 struct snd_rawmidi *rmidi; 358 struct fw_scs1x *scs; 359 int err; 360 361 scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL); 362 if (scs == NULL) 363 return -ENOMEM; 364 scs->fw_dev = fw_parent_device(oxfw->unit); 365 oxfw->spec = scs; 366 367 /* Allocate own handler for imcoming asynchronous transaction. */ 368 scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE; 369 scs->hss_handler.address_callback = handle_hss; 370 scs->hss_handler.callback_data = scs; 371 err = fw_core_add_address_handler(&scs->hss_handler, 372 &fw_high_memory_region); 373 if (err < 0) 374 return err; 375 376 err = register_address(oxfw); 377 if (err < 0) 378 goto err_allocated; 379 380 /* Use unique name for backward compatibility to scs1x module. */ 381 err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 1, 1, &rmidi); 382 if (err < 0) 383 goto err_allocated; 384 rmidi->private_data = scs; 385 rmidi->private_free = remove_scs1x; 386 387 snprintf(rmidi->name, sizeof(rmidi->name), 388 "%s MIDI", oxfw->card->shortname); 389 390 rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT | 391 SNDRV_RAWMIDI_INFO_OUTPUT | 392 SNDRV_RAWMIDI_INFO_DUPLEX; 393 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 394 &midi_capture_ops); 395 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 396 &midi_playback_ops); 397 398 tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); 399 init_waitqueue_head(&scs->idle_wait); 400 scs->output_idle = true; 401 402 return 0; 403 err_allocated: 404 fw_core_remove_address_handler(&scs->hss_handler); 405 return err; 406 } 407