tascam-transaction.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. * tascam-transaction.c - a part of driver for TASCAM FireWire series
  3. *
  4. * Copyright (c) 2015 Takashi Sakamoto
  5. *
  6. * Licensed under the terms of the GNU General Public License, version 2.
  7. */
  8. #include "tascam.h"
  9. /*
  10. * When return minus value, given argument is not MIDI status.
  11. * When return 0, given argument is a beginning of system exclusive.
  12. * When return the others, given argument is MIDI data.
  13. */
  14. static inline int calculate_message_bytes(u8 status)
  15. {
  16. switch (status) {
  17. case 0xf6: /* Tune request. */
  18. case 0xf8: /* Timing clock. */
  19. case 0xfa: /* Start. */
  20. case 0xfb: /* Continue. */
  21. case 0xfc: /* Stop. */
  22. case 0xfe: /* Active sensing. */
  23. case 0xff: /* System reset. */
  24. return 1;
  25. case 0xf1: /* MIDI time code quarter frame. */
  26. case 0xf3: /* Song select. */
  27. return 2;
  28. case 0xf2: /* Song position pointer. */
  29. return 3;
  30. case 0xf0: /* Exclusive. */
  31. return 0;
  32. case 0xf7: /* End of exclusive. */
  33. break;
  34. case 0xf4: /* Undefined. */
  35. case 0xf5: /* Undefined. */
  36. case 0xf9: /* Undefined. */
  37. case 0xfd: /* Undefined. */
  38. break;
  39. default:
  40. switch (status & 0xf0) {
  41. case 0x80: /* Note on. */
  42. case 0x90: /* Note off. */
  43. case 0xa0: /* Polyphonic key pressure. */
  44. case 0xb0: /* Control change and Mode change. */
  45. case 0xe0: /* Pitch bend change. */
  46. return 3;
  47. case 0xc0: /* Program change. */
  48. case 0xd0: /* Channel pressure. */
  49. return 2;
  50. default:
  51. break;
  52. }
  53. break;
  54. }
  55. return -EINVAL;
  56. }
  57. static int fill_message(struct snd_rawmidi_substream *substream, u8 *buf)
  58. {
  59. struct snd_tscm *tscm = substream->rmidi->private_data;
  60. unsigned int port = substream->number;
  61. int i, len, consume;
  62. u8 *label, *msg;
  63. u8 status;
  64. /* The first byte is used for label, the rest for MIDI bytes. */
  65. label = buf;
  66. msg = buf + 1;
  67. consume = snd_rawmidi_transmit_peek(substream, msg, 3);
  68. if (consume == 0)
  69. return 0;
  70. /* On exclusive message. */
  71. if (tscm->on_sysex[port]) {
  72. /* Seek the end of exclusives. */
  73. for (i = 0; i < consume; ++i) {
  74. if (msg[i] == 0xf7) {
  75. tscm->on_sysex[port] = false;
  76. break;
  77. }
  78. }
  79. /* At the end of exclusive message, use label 0x07. */
  80. if (!tscm->on_sysex[port]) {
  81. consume = i + 1;
  82. *label = (port << 4) | 0x07;
  83. /* During exclusive message, use label 0x04. */
  84. } else if (consume == 3) {
  85. *label = (port << 4) | 0x04;
  86. /* We need to fill whole 3 bytes. Go to next change. */
  87. } else {
  88. return 0;
  89. }
  90. len = consume;
  91. } else {
  92. /* The beginning of exclusives. */
  93. if (msg[0] == 0xf0) {
  94. /* Transfer it in next chance in another condition. */
  95. tscm->on_sysex[port] = true;
  96. return 0;
  97. } else {
  98. /* On running-status. */
  99. if ((msg[0] & 0x80) != 0x80)
  100. status = tscm->running_status[port];
  101. else
  102. status = msg[0];
  103. /* Calculate consume bytes. */
  104. len = calculate_message_bytes(status);
  105. if (len <= 0)
  106. return 0;
  107. /* On running-status. */
  108. if ((msg[0] & 0x80) != 0x80) {
  109. /* Enough MIDI bytes were not retrieved. */
  110. if (consume < len - 1)
  111. return 0;
  112. consume = len - 1;
  113. msg[2] = msg[1];
  114. msg[1] = msg[0];
  115. msg[0] = tscm->running_status[port];
  116. } else {
  117. /* Enough MIDI bytes were not retrieved. */
  118. if (consume < len)
  119. return 0;
  120. consume = len;
  121. tscm->running_status[port] = msg[0];
  122. }
  123. }
  124. *label = (port << 4) | (msg[0] >> 4);
  125. }
  126. if (len > 0 && len < 3)
  127. memset(msg + len, 0, 3 - len);
  128. return consume;
  129. }
  130. static void handle_midi_tx(struct fw_card *card, struct fw_request *request,
  131. int tcode, int destination, int source,
  132. int generation, unsigned long long offset,
  133. void *data, size_t length, void *callback_data)
  134. {
  135. struct snd_tscm *tscm = callback_data;
  136. u32 *buf = (u32 *)data;
  137. unsigned int messages;
  138. unsigned int i;
  139. unsigned int port;
  140. struct snd_rawmidi_substream *substream;
  141. u8 *b;
  142. int bytes;
  143. if (offset != tscm->async_handler.offset)
  144. goto end;
  145. messages = length / 8;
  146. for (i = 0; i < messages; i++) {
  147. b = (u8 *)(buf + i * 2);
  148. port = b[0] >> 4;
  149. /* TODO: support virtual MIDI ports. */
  150. if (port >= tscm->spec->midi_capture_ports)
  151. goto end;
  152. /* Assume the message length. */
  153. bytes = calculate_message_bytes(b[1]);
  154. /* On MIDI data or exclusives. */
  155. if (bytes <= 0) {
  156. /* Seek the end of exclusives. */
  157. for (bytes = 1; bytes < 4; bytes++) {
  158. if (b[bytes] == 0xf7)
  159. break;
  160. }
  161. if (bytes == 4)
  162. bytes = 3;
  163. }
  164. substream = ACCESS_ONCE(tscm->tx_midi_substreams[port]);
  165. if (substream != NULL)
  166. snd_rawmidi_receive(substream, b + 1, bytes);
  167. }
  168. end:
  169. fw_send_response(card, request, RCODE_COMPLETE);
  170. }
  171. int snd_tscm_transaction_register(struct snd_tscm *tscm)
  172. {
  173. static const struct fw_address_region resp_register_region = {
  174. .start = 0xffffe0000000ull,
  175. .end = 0xffffe000ffffull,
  176. };
  177. unsigned int i;
  178. int err;
  179. /*
  180. * Usually, two quadlets are transferred by one transaction. The first
  181. * quadlet has MIDI messages, the rest includes timestamp.
  182. * Sometimes, 8 set of the data is transferred by a block transaction.
  183. */
  184. tscm->async_handler.length = 8 * 8;
  185. tscm->async_handler.address_callback = handle_midi_tx;
  186. tscm->async_handler.callback_data = tscm;
  187. err = fw_core_add_address_handler(&tscm->async_handler,
  188. &resp_register_region);
  189. if (err < 0)
  190. return err;
  191. err = snd_tscm_transaction_reregister(tscm);
  192. if (err < 0)
  193. goto error;
  194. for (i = 0; i < TSCM_MIDI_OUT_PORT_MAX; i++) {
  195. err = snd_fw_async_midi_port_init(
  196. &tscm->out_ports[i], tscm->unit,
  197. TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_RX_QUAD,
  198. 4, fill_message);
  199. if (err < 0)
  200. goto error;
  201. }
  202. return err;
  203. error:
  204. fw_core_remove_address_handler(&tscm->async_handler);
  205. return err;
  206. }
  207. /* At bus reset, these registers are cleared. */
  208. int snd_tscm_transaction_reregister(struct snd_tscm *tscm)
  209. {
  210. struct fw_device *device = fw_parent_device(tscm->unit);
  211. __be32 reg;
  212. int err;
  213. /* Register messaging address. Block transaction is not allowed. */
  214. reg = cpu_to_be32((device->card->node_id << 16) |
  215. (tscm->async_handler.offset >> 32));
  216. err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
  217. TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_HI,
  218. &reg, sizeof(reg), 0);
  219. if (err < 0)
  220. return err;
  221. reg = cpu_to_be32(tscm->async_handler.offset);
  222. err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
  223. TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_LO,
  224. &reg, sizeof(reg), 0);
  225. if (err < 0)
  226. return err;
  227. /* Turn on messaging. */
  228. reg = cpu_to_be32(0x00000001);
  229. err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
  230. TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ON,
  231. &reg, sizeof(reg), 0);
  232. if (err < 0)
  233. return err;
  234. /* Turn on FireWire LED. */
  235. reg = cpu_to_be32(0x0001008e);
  236. return snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
  237. TSCM_ADDR_BASE + TSCM_OFFSET_LED_POWER,
  238. &reg, sizeof(reg), 0);
  239. }
  240. void snd_tscm_transaction_unregister(struct snd_tscm *tscm)
  241. {
  242. __be32 reg;
  243. unsigned int i;
  244. /* Turn off FireWire LED. */
  245. reg = cpu_to_be32(0x0000008e);
  246. snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
  247. TSCM_ADDR_BASE + TSCM_OFFSET_LED_POWER,
  248. &reg, sizeof(reg), 0);
  249. /* Turn off messaging. */
  250. reg = cpu_to_be32(0x00000000);
  251. snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
  252. TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ON,
  253. &reg, sizeof(reg), 0);
  254. /* Unregister the address. */
  255. snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
  256. TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_HI,
  257. &reg, sizeof(reg), 0);
  258. snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
  259. TSCM_ADDR_BASE + TSCM_OFFSET_MIDI_TX_ADDR_LO,
  260. &reg, sizeof(reg), 0);
  261. fw_core_remove_address_handler(&tscm->async_handler);
  262. for (i = 0; i < TSCM_MIDI_OUT_PORT_MAX; i++)
  263. snd_fw_async_midi_port_destroy(&tscm->out_ports[i]);
  264. }