Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * tascam-transaction.c - a part of driver for TASCAM FireWire series
0004  *
0005  * Copyright (c) 2015 Takashi Sakamoto
0006  */
0007 
0008 #include "tascam.h"
0009 
0010 /*
0011  * When return minus value, given argument is not MIDI status.
0012  * When return 0, given argument is a beginning of system exclusive.
0013  * When return the others, given argument is MIDI data.
0014  */
0015 static inline int calculate_message_bytes(u8 status)
0016 {
0017     switch (status) {
0018     case 0xf6:  /* Tune request. */
0019     case 0xf8:  /* Timing clock. */
0020     case 0xfa:  /* Start. */
0021     case 0xfb:  /* Continue. */
0022     case 0xfc:  /* Stop. */
0023     case 0xfe:  /* Active sensing. */
0024     case 0xff:  /* System reset. */
0025         return 1;
0026     case 0xf1:  /* MIDI time code quarter frame. */
0027     case 0xf3:  /* Song select. */
0028         return 2;
0029     case 0xf2:  /* Song position pointer. */
0030         return 3;
0031     case 0xf0:  /* Exclusive. */
0032         return 0;
0033     case 0xf7:  /* End of exclusive. */
0034         break;
0035     case 0xf4:  /* Undefined. */
0036     case 0xf5:  /* Undefined. */
0037     case 0xf9:  /* Undefined. */
0038     case 0xfd:  /* Undefined. */
0039         break;
0040     default:
0041         switch (status & 0xf0) {
0042         case 0x80:  /* Note on. */
0043         case 0x90:  /* Note off. */
0044         case 0xa0:  /* Polyphonic key pressure. */
0045         case 0xb0:  /* Control change and Mode change. */
0046         case 0xe0:  /* Pitch bend change. */
0047             return 3;
0048         case 0xc0:  /* Program change. */
0049         case 0xd0:  /* Channel pressure. */
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     /* The first byte is used for label, the rest for MIDI bytes. */
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     /* On exclusive message. */
0076     if (port->on_sysex) {
0077         /* Seek the end of exclusives. */
0078         for (i = 0; i < consume; ++i) {
0079             if (msg[i] == 0xf7) {
0080                 port->on_sysex = false;
0081                 break;
0082             }
0083         }
0084 
0085         /* At the end of exclusive message, use label 0x07. */
0086         if (!port->on_sysex) {
0087             consume = i + 1;
0088             *label = (substream->number << 4) | 0x07;
0089         /* During exclusive message, use label 0x04. */
0090         } else if (consume == 3) {
0091             *label = (substream->number << 4) | 0x04;
0092         /* We need to fill whole 3 bytes. Go to next change. */
0093         } else {
0094             return 0;
0095         }
0096 
0097         len = consume;
0098     } else {
0099         /* The beginning of exclusives. */
0100         if (msg[0] == 0xf0) {
0101             /* Transfer it in next chance in another condition. */
0102             port->on_sysex = true;
0103             return 0;
0104         } else {
0105             /* On running-status. */
0106             if ((msg[0] & 0x80) != 0x80)
0107                 status = port->running_status;
0108             else
0109                 status = msg[0];
0110 
0111             /* Calculate consume bytes. */
0112             len = calculate_message_bytes(status);
0113             if (len <= 0)
0114                 return 0;
0115 
0116             /* On running-status. */
0117             if ((msg[0] & 0x80) != 0x80) {
0118                 /* Enough MIDI bytes were not retrieved. */
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                 /* Enough MIDI bytes were not retrieved. */
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     /* This port is closed. */
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         /* To start next transaction immediately for recovery. */
0160         port->next_ktime = 0;
0161     else
0162         /* Don't continue processing. */
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     /* Under transacting or error state. */
0179     if (!port->idling || port->error)
0180         return;
0181 
0182     /* Nothing to do. */
0183     if (substream == NULL || snd_rawmidi_transmit_empty(substream))
0184         return;
0185 
0186     /* Do it in next chance. */
0187     if (ktime_after(port->next_ktime, ktime_get())) {
0188         schedule_work(&port->work);
0189         return;
0190     }
0191 
0192     /*
0193      * Fill the buffer. The callee must use snd_rawmidi_transmit_peek().
0194      * Later, snd_rawmidi_transmit_ack() is called.
0195      */
0196     memset(port->buf, 0, 4);
0197     port->consume_bytes = fill_message(port, substream);
0198     if (port->consume_bytes <= 0) {
0199         /* Do it in next chance, immediately. */
0200         if (port->consume_bytes == 0) {
0201             port->next_ktime = 0;
0202             schedule_work(&port->work);
0203         } else {
0204             /* Fatal error. */
0205             port->error = true;
0206         }
0207         return;
0208     }
0209 
0210     /* Set interval to next transaction. */
0211     port->next_ktime = ktime_add_ns(ktime_get(),
0212             port->consume_bytes * 8 * (NSEC_PER_SEC / 31250));
0213 
0214     /* Start this transaction. */
0215     port->idling = false;
0216 
0217     /*
0218      * In Linux FireWire core, when generation is updated with memory
0219      * barrier, node id has already been updated. In this module, After
0220      * this smp_rmb(), load/store instructions to memory are completed.
0221      * Thus, both of generation and node id are available with recent
0222      * values. This is a light-serialization solution to handle bus reset
0223      * events on IEEE 1394 bus.
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         /* TODO: support virtual MIDI ports. */
0268         if (port >= tscm->spec->midi_capture_ports)
0269             goto end;
0270 
0271         /* Assume the message length. */
0272         bytes = calculate_message_bytes(b[1]);
0273         /* On MIDI data or exclusives. */
0274         if (bytes <= 0) {
0275             /* Seek the end of exclusives. */
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      * Usually, two quadlets are transferred by one transaction. The first
0303      * quadlet has MIDI messages, the rest includes timestamp.
0304      * Sometimes, 8 set of the data is transferred by a block transaction.
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 /* At bus reset, these registers are cleared. */
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     /* Register messaging address. Block transaction is not allowed. */
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                  &reg, 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                  &reg, sizeof(reg), 0);
0352     if (err < 0)
0353         return err;
0354 
0355     /* Turn on messaging. */
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                   &reg, sizeof(reg), 0);
0360     if (err < 0)
0361         return err;
0362 
0363     /* Turn on FireWire LED. */
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                   &reg, 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     /* Turn off FireWire LED. */
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                &reg, sizeof(reg), 0);
0382 
0383     /* Turn off messaging. */
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                &reg, sizeof(reg), 0);
0388 
0389     /* Unregister the address. */
0390     snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
0391                TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_HI,
0392                &reg, sizeof(reg), 0);
0393     snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
0394                TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_LO,
0395                &reg, sizeof(reg), 0);
0396 
0397     fw_core_remove_address_handler(&tscm->async_handler);
0398     tscm->async_handler.callback_data = NULL;
0399 }