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