0001
0002
0003
0004
0005
0006
0007
0008 #include "tascam.h"
0009
0010
0011
0012
0013
0014
0015 static inline int calculate_message_bytes(u8 status)
0016 {
0017 switch (status) {
0018 case 0xf6:
0019 case 0xf8:
0020 case 0xfa:
0021 case 0xfb:
0022 case 0xfc:
0023 case 0xfe:
0024 case 0xff:
0025 return 1;
0026 case 0xf1:
0027 case 0xf3:
0028 return 2;
0029 case 0xf2:
0030 return 3;
0031 case 0xf0:
0032 return 0;
0033 case 0xf7:
0034 break;
0035 case 0xf4:
0036 case 0xf5:
0037 case 0xf9:
0038 case 0xfd:
0039 break;
0040 default:
0041 switch (status & 0xf0) {
0042 case 0x80:
0043 case 0x90:
0044 case 0xa0:
0045 case 0xb0:
0046 case 0xe0:
0047 return 3;
0048 case 0xc0:
0049 case 0xd0:
0050 return 2;
0051 default:
0052 break;
0053 }
0054 break;
0055 }
0056
0057 return -EINVAL;
0058 }
0059
0060 static int fill_message(struct snd_fw_async_midi_port *port,
0061 struct snd_rawmidi_substream *substream)
0062 {
0063 int i, len, consume;
0064 u8 *label, *msg;
0065 u8 status;
0066
0067
0068 label = port->buf;
0069 msg = port->buf + 1;
0070
0071 consume = snd_rawmidi_transmit_peek(substream, msg, 3);
0072 if (consume == 0)
0073 return 0;
0074
0075
0076 if (port->on_sysex) {
0077
0078 for (i = 0; i < consume; ++i) {
0079 if (msg[i] == 0xf7) {
0080 port->on_sysex = false;
0081 break;
0082 }
0083 }
0084
0085
0086 if (!port->on_sysex) {
0087 consume = i + 1;
0088 *label = (substream->number << 4) | 0x07;
0089
0090 } else if (consume == 3) {
0091 *label = (substream->number << 4) | 0x04;
0092
0093 } else {
0094 return 0;
0095 }
0096
0097 len = consume;
0098 } else {
0099
0100 if (msg[0] == 0xf0) {
0101
0102 port->on_sysex = true;
0103 return 0;
0104 } else {
0105
0106 if ((msg[0] & 0x80) != 0x80)
0107 status = port->running_status;
0108 else
0109 status = msg[0];
0110
0111
0112 len = calculate_message_bytes(status);
0113 if (len <= 0)
0114 return 0;
0115
0116
0117 if ((msg[0] & 0x80) != 0x80) {
0118
0119 if (consume < len - 1)
0120 return 0;
0121 consume = len - 1;
0122
0123 msg[2] = msg[1];
0124 msg[1] = msg[0];
0125 msg[0] = port->running_status;
0126 } else {
0127
0128 if (consume < len)
0129 return 0;
0130 consume = len;
0131
0132 port->running_status = msg[0];
0133 }
0134 }
0135
0136 *label = (substream->number << 4) | (msg[0] >> 4);
0137 }
0138
0139 if (len > 0 && len < 3)
0140 memset(msg + len, 0, 3 - len);
0141
0142 return consume;
0143 }
0144
0145 static void async_midi_port_callback(struct fw_card *card, int rcode,
0146 void *data, size_t length,
0147 void *callback_data)
0148 {
0149 struct snd_fw_async_midi_port *port = callback_data;
0150 struct snd_rawmidi_substream *substream = READ_ONCE(port->substream);
0151
0152
0153 if (substream == NULL)
0154 return;
0155
0156 if (rcode == RCODE_COMPLETE)
0157 snd_rawmidi_transmit_ack(substream, port->consume_bytes);
0158 else if (!rcode_is_permanent_error(rcode))
0159
0160 port->next_ktime = 0;
0161 else
0162
0163 port->error = true;
0164
0165 port->idling = true;
0166
0167 if (!snd_rawmidi_transmit_empty(substream))
0168 schedule_work(&port->work);
0169 }
0170
0171 static void midi_port_work(struct work_struct *work)
0172 {
0173 struct snd_fw_async_midi_port *port =
0174 container_of(work, struct snd_fw_async_midi_port, work);
0175 struct snd_rawmidi_substream *substream = READ_ONCE(port->substream);
0176 int generation;
0177
0178
0179 if (!port->idling || port->error)
0180 return;
0181
0182
0183 if (substream == NULL || snd_rawmidi_transmit_empty(substream))
0184 return;
0185
0186
0187 if (ktime_after(port->next_ktime, ktime_get())) {
0188 schedule_work(&port->work);
0189 return;
0190 }
0191
0192
0193
0194
0195
0196 memset(port->buf, 0, 4);
0197 port->consume_bytes = fill_message(port, substream);
0198 if (port->consume_bytes <= 0) {
0199
0200 if (port->consume_bytes == 0) {
0201 port->next_ktime = 0;
0202 schedule_work(&port->work);
0203 } else {
0204
0205 port->error = true;
0206 }
0207 return;
0208 }
0209
0210
0211 port->next_ktime = ktime_add_ns(ktime_get(),
0212 port->consume_bytes * 8 * (NSEC_PER_SEC / 31250));
0213
0214
0215 port->idling = false;
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225 generation = port->parent->generation;
0226 smp_rmb();
0227
0228 fw_send_request(port->parent->card, &port->transaction,
0229 TCODE_WRITE_QUADLET_REQUEST,
0230 port->parent->node_id, generation,
0231 port->parent->max_speed,
0232 TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_RX_QUAD,
0233 port->buf, 4, async_midi_port_callback,
0234 port);
0235 }
0236
0237 void snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port)
0238 {
0239 port->idling = true;
0240 port->error = false;
0241 port->running_status = 0;
0242 port->on_sysex = false;
0243 }
0244
0245 static void handle_midi_tx(struct fw_card *card, struct fw_request *request,
0246 int tcode, int destination, int source,
0247 int generation, unsigned long long offset,
0248 void *data, size_t length, void *callback_data)
0249 {
0250 struct snd_tscm *tscm = callback_data;
0251 u32 *buf = (u32 *)data;
0252 unsigned int messages;
0253 unsigned int i;
0254 unsigned int port;
0255 struct snd_rawmidi_substream *substream;
0256 u8 *b;
0257 int bytes;
0258
0259 if (offset != tscm->async_handler.offset)
0260 goto end;
0261
0262 messages = length / 8;
0263 for (i = 0; i < messages; i++) {
0264 b = (u8 *)(buf + i * 2);
0265
0266 port = b[0] >> 4;
0267
0268 if (port >= tscm->spec->midi_capture_ports)
0269 goto end;
0270
0271
0272 bytes = calculate_message_bytes(b[1]);
0273
0274 if (bytes <= 0) {
0275
0276 for (bytes = 1; bytes < 4; bytes++) {
0277 if (b[bytes] == 0xf7)
0278 break;
0279 }
0280 if (bytes == 4)
0281 bytes = 3;
0282 }
0283
0284 substream = READ_ONCE(tscm->tx_midi_substreams[port]);
0285 if (substream != NULL)
0286 snd_rawmidi_receive(substream, b + 1, bytes);
0287 }
0288 end:
0289 fw_send_response(card, request, RCODE_COMPLETE);
0290 }
0291
0292 int snd_tscm_transaction_register(struct snd_tscm *tscm)
0293 {
0294 static const struct fw_address_region resp_register_region = {
0295 .start = 0xffffe0000000ull,
0296 .end = 0xffffe000ffffull,
0297 };
0298 unsigned int i;
0299 int err;
0300
0301
0302
0303
0304
0305
0306 tscm->async_handler.length = 8 * 8;
0307 tscm->async_handler.address_callback = handle_midi_tx;
0308 tscm->async_handler.callback_data = tscm;
0309
0310 err = fw_core_add_address_handler(&tscm->async_handler,
0311 &resp_register_region);
0312 if (err < 0)
0313 return err;
0314
0315 err = snd_tscm_transaction_reregister(tscm);
0316 if (err < 0)
0317 goto error;
0318
0319 for (i = 0; i < TSCM_MIDI_OUT_PORT_MAX; i++) {
0320 tscm->out_ports[i].parent = fw_parent_device(tscm->unit);
0321 tscm->out_ports[i].next_ktime = 0;
0322 INIT_WORK(&tscm->out_ports[i].work, midi_port_work);
0323 }
0324
0325 return err;
0326 error:
0327 fw_core_remove_address_handler(&tscm->async_handler);
0328 tscm->async_handler.callback_data = NULL;
0329 return err;
0330 }
0331
0332
0333 int snd_tscm_transaction_reregister(struct snd_tscm *tscm)
0334 {
0335 struct fw_device *device = fw_parent_device(tscm->unit);
0336 __be32 reg;
0337 int err;
0338
0339
0340 reg = cpu_to_be32((device->card->node_id << 16) |
0341 (tscm->async_handler.offset >> 32));
0342 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
0343 TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_HI,
0344 ®, sizeof(reg), 0);
0345 if (err < 0)
0346 return err;
0347
0348 reg = cpu_to_be32(tscm->async_handler.offset);
0349 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
0350 TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_LO,
0351 ®, sizeof(reg), 0);
0352 if (err < 0)
0353 return err;
0354
0355
0356 reg = cpu_to_be32(0x00000001);
0357 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
0358 TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ON,
0359 ®, sizeof(reg), 0);
0360 if (err < 0)
0361 return err;
0362
0363
0364 reg = cpu_to_be32(0x0001008e);
0365 return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
0366 TSCM_ADDR_BASE + TSCM_OFFSET_LED_POWER,
0367 ®, sizeof(reg), 0);
0368 }
0369
0370 void snd_tscm_transaction_unregister(struct snd_tscm *tscm)
0371 {
0372 __be32 reg;
0373
0374 if (tscm->async_handler.callback_data == NULL)
0375 return;
0376
0377
0378 reg = cpu_to_be32(0x0000008e);
0379 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
0380 TSCM_ADDR_BASE + TSCM_OFFSET_LED_POWER,
0381 ®, sizeof(reg), 0);
0382
0383
0384 reg = cpu_to_be32(0x00000000);
0385 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
0386 TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ON,
0387 ®, sizeof(reg), 0);
0388
0389
0390 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
0391 TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_HI,
0392 ®, sizeof(reg), 0);
0393 snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
0394 TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_LO,
0395 ®, sizeof(reg), 0);
0396
0397 fw_core_remove_address_handler(&tscm->async_handler);
0398 tscm->async_handler.callback_data = NULL;
0399 }