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