forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/sound/firewire/oxfw/oxfw-stream.c
....@@ -1,9 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * oxfw_stream.c - a part of driver for OXFW970/971 based devices
34 *
45 * Copyright (c) 2014 Takashi Sakamoto
5
- *
6
- * Licensed under the terms of the GNU General Public License, version 2.
76 */
87
98 #include "oxfw.h"
....@@ -101,85 +100,28 @@
101100 return 0;
102101 }
103102
104
-static void stop_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
103
+static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
105104 {
106
- amdtp_stream_pcm_abort(stream);
107
- amdtp_stream_stop(stream);
108
-
109
- if (stream == &oxfw->tx_stream)
110
- cmp_connection_break(&oxfw->out_conn);
111
- else
112
- cmp_connection_break(&oxfw->in_conn);
113
-}
114
-
115
-static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream,
116
- unsigned int rate, unsigned int pcm_channels)
117
-{
118
- u8 **formats;
119105 struct cmp_connection *conn;
120
- struct snd_oxfw_stream_formation formation;
121
- unsigned int i, midi_ports;
122106 int err;
123107
124
- if (stream == &oxfw->rx_stream) {
125
- formats = oxfw->rx_stream_formats;
108
+ if (stream == &oxfw->rx_stream)
126109 conn = &oxfw->in_conn;
127
- } else {
128
- formats = oxfw->tx_stream_formats;
110
+ else
129111 conn = &oxfw->out_conn;
130
- }
131112
132
- /* Get stream format */
133
- for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
134
- if (formats[i] == NULL)
135
- break;
136
-
137
- err = snd_oxfw_stream_parse_format(formats[i], &formation);
138
- if (err < 0)
139
- goto end;
140
- if (rate != formation.rate)
141
- continue;
142
- if (pcm_channels == 0 || pcm_channels == formation.pcm)
143
- break;
144
- }
145
- if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) {
146
- err = -EINVAL;
147
- goto end;
148
- }
149
-
150
- pcm_channels = formation.pcm;
151
- midi_ports = formation.midi * 8;
152
-
153
- /* The stream should have one pcm channels at least */
154
- if (pcm_channels == 0) {
155
- err = -EINVAL;
156
- goto end;
157
- }
158
- err = amdtp_am824_set_parameters(stream, rate, pcm_channels, midi_ports,
159
- false);
113
+ err = cmp_connection_establish(conn);
160114 if (err < 0)
161
- goto end;
115
+ return err;
162116
163
- err = cmp_connection_establish(conn,
164
- amdtp_stream_get_max_payload(stream));
165
- if (err < 0)
166
- goto end;
167
-
168
- err = amdtp_stream_start(stream,
169
- conn->resources.channel,
170
- conn->speed);
117
+ err = amdtp_domain_add_stream(&oxfw->domain, stream,
118
+ conn->resources.channel, conn->speed);
171119 if (err < 0) {
172120 cmp_connection_break(conn);
173
- goto end;
121
+ return err;
174122 }
175123
176
- /* Wait first packet */
177
- if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
178
- stop_stream(oxfw, stream);
179
- err = -ETIMEDOUT;
180
- }
181
-end:
182
- return err;
124
+ return 0;
183125 }
184126
185127 static int check_connection_used_by_others(struct snd_oxfw *oxfw,
....@@ -206,8 +148,7 @@
206148 return err;
207149 }
208150
209
-int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
210
- struct amdtp_stream *stream)
151
+static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
211152 {
212153 struct cmp_connection *conn;
213154 enum cmp_direction c_dir;
....@@ -226,13 +167,12 @@
226167
227168 err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
228169 if (err < 0)
229
- goto end;
170
+ return err;
230171
231172 err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
232173 if (err < 0) {
233
- amdtp_stream_destroy(stream);
234174 cmp_connection_destroy(conn);
235
- goto end;
175
+ return err;
236176 }
237177
238178 /*
....@@ -246,115 +186,222 @@
246186 if (oxfw->wrong_dbs)
247187 oxfw->tx_stream.flags |= CIP_WRONG_DBS;
248188 }
249
-end:
250
- return err;
189
+
190
+ return 0;
251191 }
252192
253
-int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
254
- struct amdtp_stream *stream,
255
- unsigned int rate, unsigned int pcm_channels)
193
+static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
256194 {
257
- struct amdtp_stream *opposite;
258
- struct snd_oxfw_stream_formation formation;
259195 enum avc_general_plug_dir dir;
260
- unsigned int substreams, opposite_substreams;
261
- int err = 0;
196
+ u8 **formats;
197
+ struct snd_oxfw_stream_formation formation;
198
+ struct cmp_connection *conn;
199
+ int i;
200
+ int err;
262201
263
- if (stream == &oxfw->tx_stream) {
264
- substreams = oxfw->capture_substreams;
265
- opposite = &oxfw->rx_stream;
266
- opposite_substreams = oxfw->playback_substreams;
267
- dir = AVC_GENERAL_PLUG_DIR_OUT;
268
- } else {
269
- substreams = oxfw->playback_substreams;
270
- opposite_substreams = oxfw->capture_substreams;
271
-
272
- if (oxfw->has_output)
273
- opposite = &oxfw->rx_stream;
274
- else
275
- opposite = NULL;
276
-
202
+ if (stream == &oxfw->rx_stream) {
277203 dir = AVC_GENERAL_PLUG_DIR_IN;
204
+ formats = oxfw->rx_stream_formats;
205
+ conn = &oxfw->in_conn;
206
+ } else {
207
+ dir = AVC_GENERAL_PLUG_DIR_OUT;
208
+ formats = oxfw->tx_stream_formats;
209
+ conn = &oxfw->out_conn;
278210 }
279
-
280
- if (substreams == 0)
281
- goto end;
282
-
283
- /*
284
- * Considering JACK/FFADO streaming:
285
- * TODO: This can be removed hwdep functionality becomes popular.
286
- */
287
- err = check_connection_used_by_others(oxfw, stream);
288
- if (err < 0)
289
- goto end;
290
-
291
- /* packet queueing error */
292
- if (amdtp_streaming_error(stream))
293
- stop_stream(oxfw, stream);
294211
295212 err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
296213 if (err < 0)
297
- goto end;
298
- if (rate == 0)
214
+ return err;
215
+
216
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
217
+ struct snd_oxfw_stream_formation fmt;
218
+
219
+ if (formats[i] == NULL)
220
+ break;
221
+
222
+ err = snd_oxfw_stream_parse_format(formats[i], &fmt);
223
+ if (err < 0)
224
+ return err;
225
+
226
+ if (fmt.rate == formation.rate && fmt.pcm == formation.pcm &&
227
+ fmt.midi == formation.midi)
228
+ break;
229
+ }
230
+ if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
231
+ return -EINVAL;
232
+
233
+ // The stream should have one pcm channels at least.
234
+ if (formation.pcm == 0)
235
+ return -EINVAL;
236
+
237
+ err = amdtp_am824_set_parameters(stream, formation.rate, formation.pcm,
238
+ formation.midi * 8, false);
239
+ if (err < 0)
240
+ return err;
241
+
242
+ return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
243
+}
244
+
245
+int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
246
+ struct amdtp_stream *stream,
247
+ unsigned int rate, unsigned int pcm_channels,
248
+ unsigned int frames_per_period,
249
+ unsigned int frames_per_buffer)
250
+{
251
+ struct snd_oxfw_stream_formation formation;
252
+ enum avc_general_plug_dir dir;
253
+ int err;
254
+
255
+ // Considering JACK/FFADO streaming:
256
+ // TODO: This can be removed hwdep functionality becomes popular.
257
+ err = check_connection_used_by_others(oxfw, &oxfw->rx_stream);
258
+ if (err < 0)
259
+ return err;
260
+ if (oxfw->has_output) {
261
+ err = check_connection_used_by_others(oxfw, &oxfw->tx_stream);
262
+ if (err < 0)
263
+ return err;
264
+ }
265
+
266
+ if (stream == &oxfw->tx_stream)
267
+ dir = AVC_GENERAL_PLUG_DIR_OUT;
268
+ else
269
+ dir = AVC_GENERAL_PLUG_DIR_IN;
270
+
271
+ err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
272
+ if (err < 0)
273
+ return err;
274
+ if (rate == 0) {
299275 rate = formation.rate;
300
- if (pcm_channels == 0)
301276 pcm_channels = formation.pcm;
277
+ }
278
+ if (formation.rate != rate || formation.pcm != pcm_channels) {
279
+ amdtp_domain_stop(&oxfw->domain);
302280
303
- if ((formation.rate != rate) || (formation.pcm != pcm_channels)) {
304
- if (opposite != NULL) {
305
- err = check_connection_used_by_others(oxfw, opposite);
306
- if (err < 0)
307
- goto end;
308
- stop_stream(oxfw, opposite);
281
+ cmp_connection_break(&oxfw->in_conn);
282
+ cmp_connection_release(&oxfw->in_conn);
283
+
284
+ if (oxfw->has_output) {
285
+ cmp_connection_break(&oxfw->out_conn);
286
+ cmp_connection_release(&oxfw->out_conn);
309287 }
310
- stop_stream(oxfw, stream);
288
+ }
311289
290
+ if (oxfw->substreams_count == 0 ||
291
+ formation.rate != rate || formation.pcm != pcm_channels) {
312292 err = set_stream_format(oxfw, stream, rate, pcm_channels);
313293 if (err < 0) {
314294 dev_err(&oxfw->unit->device,
315295 "fail to set stream format: %d\n", err);
316
- goto end;
296
+ return err;
317297 }
318298
319
- /* Start opposite stream if needed. */
320
- if (opposite && !amdtp_stream_running(opposite) &&
321
- (opposite_substreams > 0)) {
322
- err = start_stream(oxfw, opposite, rate, 0);
299
+ err = keep_resources(oxfw, &oxfw->rx_stream);
300
+ if (err < 0)
301
+ return err;
302
+
303
+ if (oxfw->has_output) {
304
+ err = keep_resources(oxfw, &oxfw->tx_stream);
305
+ if (err < 0) {
306
+ cmp_connection_release(&oxfw->in_conn);
307
+ return err;
308
+ }
309
+ }
310
+
311
+ err = amdtp_domain_set_events_per_period(&oxfw->domain,
312
+ frames_per_period, frames_per_buffer);
313
+ if (err < 0) {
314
+ cmp_connection_release(&oxfw->in_conn);
315
+ if (oxfw->has_output)
316
+ cmp_connection_release(&oxfw->out_conn);
317
+ return err;
318
+ }
319
+ }
320
+
321
+ return 0;
322
+}
323
+
324
+int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
325
+{
326
+ int err;
327
+
328
+ if (oxfw->substreams_count == 0)
329
+ return -EIO;
330
+
331
+ if (amdtp_streaming_error(&oxfw->rx_stream) ||
332
+ amdtp_streaming_error(&oxfw->tx_stream)) {
333
+ amdtp_domain_stop(&oxfw->domain);
334
+
335
+ cmp_connection_break(&oxfw->in_conn);
336
+ if (oxfw->has_output)
337
+ cmp_connection_break(&oxfw->out_conn);
338
+ }
339
+
340
+ if (!amdtp_stream_running(&oxfw->rx_stream)) {
341
+ err = start_stream(oxfw, &oxfw->rx_stream);
342
+ if (err < 0) {
343
+ dev_err(&oxfw->unit->device,
344
+ "fail to prepare rx stream: %d\n", err);
345
+ goto error;
346
+ }
347
+
348
+ if (oxfw->has_output &&
349
+ !amdtp_stream_running(&oxfw->tx_stream)) {
350
+ err = start_stream(oxfw, &oxfw->tx_stream);
323351 if (err < 0) {
324352 dev_err(&oxfw->unit->device,
325
- "fail to restart stream: %d\n", err);
326
- goto end;
353
+ "fail to prepare tx stream: %d\n", err);
354
+ goto error;
355
+ }
356
+ }
357
+
358
+ err = amdtp_domain_start(&oxfw->domain, 0);
359
+ if (err < 0)
360
+ goto error;
361
+
362
+ // Wait first packet.
363
+ if (!amdtp_stream_wait_callback(&oxfw->rx_stream,
364
+ CALLBACK_TIMEOUT)) {
365
+ err = -ETIMEDOUT;
366
+ goto error;
367
+ }
368
+
369
+ if (oxfw->has_output) {
370
+ if (!amdtp_stream_wait_callback(&oxfw->tx_stream,
371
+ CALLBACK_TIMEOUT)) {
372
+ err = -ETIMEDOUT;
373
+ goto error;
327374 }
328375 }
329376 }
330377
331
- /* Start requested stream. */
332
- if (!amdtp_stream_running(stream)) {
333
- err = start_stream(oxfw, stream, rate, pcm_channels);
334
- if (err < 0)
335
- dev_err(&oxfw->unit->device,
336
- "fail to start stream: %d\n", err);
337
- }
338
-end:
378
+ return 0;
379
+error:
380
+ amdtp_domain_stop(&oxfw->domain);
381
+
382
+ cmp_connection_break(&oxfw->in_conn);
383
+ if (oxfw->has_output)
384
+ cmp_connection_break(&oxfw->out_conn);
385
+
339386 return err;
340387 }
341388
342
-void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
343
- struct amdtp_stream *stream)
389
+void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw)
344390 {
345
- if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) ||
346
- ((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0)))
347
- return;
391
+ if (oxfw->substreams_count == 0) {
392
+ amdtp_domain_stop(&oxfw->domain);
348393
349
- stop_stream(oxfw, stream);
394
+ cmp_connection_break(&oxfw->in_conn);
395
+ cmp_connection_release(&oxfw->in_conn);
396
+
397
+ if (oxfw->has_output) {
398
+ cmp_connection_break(&oxfw->out_conn);
399
+ cmp_connection_release(&oxfw->out_conn);
400
+ }
401
+ }
350402 }
351403
352
-/*
353
- * This function should be called before starting the stream or after stopping
354
- * the streams.
355
- */
356
-void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
357
- struct amdtp_stream *stream)
404
+static void destroy_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
358405 {
359406 struct cmp_connection *conn;
360407
....@@ -367,20 +414,57 @@
367414 cmp_connection_destroy(conn);
368415 }
369416
370
-void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
371
- struct amdtp_stream *stream)
417
+int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw)
372418 {
373
- struct cmp_connection *conn;
419
+ int err;
374420
375
- if (stream == &oxfw->tx_stream)
376
- conn = &oxfw->out_conn;
377
- else
378
- conn = &oxfw->in_conn;
421
+ err = init_stream(oxfw, &oxfw->rx_stream);
422
+ if (err < 0)
423
+ return err;
379424
380
- if (cmp_connection_update(conn) < 0)
381
- stop_stream(oxfw, stream);
382
- else
383
- amdtp_stream_update(stream);
425
+ if (oxfw->has_output) {
426
+ err = init_stream(oxfw, &oxfw->tx_stream);
427
+ if (err < 0) {
428
+ destroy_stream(oxfw, &oxfw->rx_stream);
429
+ return err;
430
+ }
431
+ }
432
+
433
+ err = amdtp_domain_init(&oxfw->domain);
434
+ if (err < 0) {
435
+ destroy_stream(oxfw, &oxfw->rx_stream);
436
+ if (oxfw->has_output)
437
+ destroy_stream(oxfw, &oxfw->tx_stream);
438
+ }
439
+
440
+ return err;
441
+}
442
+
443
+// This function should be called before starting the stream or after stopping
444
+// the streams.
445
+void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw)
446
+{
447
+ amdtp_domain_destroy(&oxfw->domain);
448
+
449
+ destroy_stream(oxfw, &oxfw->rx_stream);
450
+
451
+ if (oxfw->has_output)
452
+ destroy_stream(oxfw, &oxfw->tx_stream);
453
+}
454
+
455
+void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw)
456
+{
457
+ amdtp_domain_stop(&oxfw->domain);
458
+
459
+ cmp_connection_break(&oxfw->in_conn);
460
+
461
+ amdtp_stream_pcm_abort(&oxfw->rx_stream);
462
+
463
+ if (oxfw->has_output) {
464
+ cmp_connection_break(&oxfw->out_conn);
465
+
466
+ amdtp_stream_pcm_abort(&oxfw->tx_stream);
467
+ }
384468 }
385469
386470 int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
....@@ -429,7 +513,7 @@
429513 * Level 1: AM824 Compound (0x40)
430514 */
431515 if ((format[0] != 0x90) || (format[1] != 0x40))
432
- return -ENOSYS;
516
+ return -ENXIO;
433517
434518 /* check the sampling rate */
435519 for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) {
....@@ -437,7 +521,7 @@
437521 break;
438522 }
439523 if (i == ARRAY_SIZE(avc_stream_rate_table))
440
- return -ENOSYS;
524
+ return -ENXIO;
441525
442526 formation->rate = oxfw_rate_table[i];
443527
....@@ -481,13 +565,13 @@
481565 /* Don't care */
482566 case 0xff:
483567 default:
484
- return -ENOSYS; /* not supported */
568
+ return -ENXIO; /* not supported */
485569 }
486570 }
487571
488572 if (formation->pcm > AM824_MAX_CHANNELS_FOR_PCM ||
489573 formation->midi > AM824_MAX_CHANNELS_FOR_MIDI)
490
- return -ENOSYS;
574
+ return -ENXIO;
491575
492576 return 0;
493577 }
....@@ -517,8 +601,9 @@
517601 if (err < 0)
518602 goto end;
519603
520
- formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
521
- if (formats[eid] == NULL) {
604
+ formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
605
+ GFP_KERNEL);
606
+ if (!formats[eid]) {
522607 err = -ENOMEM;
523608 goto end;
524609 }
....@@ -535,7 +620,8 @@
535620 continue;
536621
537622 eid++;
538
- formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
623
+ formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
624
+ GFP_KERNEL);
539625 if (formats[eid] == NULL) {
540626 err = -ENOMEM;
541627 goto end;
....@@ -570,7 +656,7 @@
570656 /* get first entry */
571657 len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
572658 err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0);
573
- if (err == -ENOSYS) {
659
+ if (err == -ENXIO) {
574660 /* LIST subfunction is not implemented */
575661 len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
576662 err = assume_stream_formats(oxfw, dir, pid, buf, &len,
....@@ -597,8 +683,9 @@
597683 if (err < 0)
598684 break;
599685
600
- formats[eid] = kmemdup(buf, len, GFP_KERNEL);
601
- if (formats[eid] == NULL) {
686
+ formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, len,
687
+ GFP_KERNEL);
688
+ if (!formats[eid]) {
602689 err = -ENOMEM;
603690 break;
604691 }
....@@ -641,49 +728,63 @@
641728 err);
642729 goto end;
643730 } else if ((plugs[0] == 0) && (plugs[1] == 0)) {
644
- err = -ENOSYS;
731
+ err = -ENXIO;
645732 goto end;
646733 }
647734
648735 /* use oPCR[0] if exists */
649736 if (plugs[1] > 0) {
650737 err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0);
651
- if (err < 0)
652
- goto end;
738
+ if (err < 0) {
739
+ if (err != -ENXIO)
740
+ return err;
653741
654
- for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
655
- format = oxfw->tx_stream_formats[i];
656
- if (format == NULL)
657
- continue;
658
- err = snd_oxfw_stream_parse_format(format, &formation);
659
- if (err < 0)
660
- continue;
742
+ // The oPCR is not available for isoc communication.
743
+ err = 0;
744
+ } else {
745
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
746
+ format = oxfw->tx_stream_formats[i];
747
+ if (format == NULL)
748
+ continue;
749
+ err = snd_oxfw_stream_parse_format(format,
750
+ &formation);
751
+ if (err < 0)
752
+ continue;
661753
662
- /* Add one MIDI port. */
663
- if (formation.midi > 0)
664
- oxfw->midi_input_ports = 1;
754
+ /* Add one MIDI port. */
755
+ if (formation.midi > 0)
756
+ oxfw->midi_input_ports = 1;
757
+ }
758
+
759
+ oxfw->has_output = true;
665760 }
666
-
667
- oxfw->has_output = true;
668761 }
669762
670763 /* use iPCR[0] if exists */
671764 if (plugs[0] > 0) {
672765 err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
673
- if (err < 0)
674
- goto end;
766
+ if (err < 0) {
767
+ if (err != -ENXIO)
768
+ return err;
675769
676
- for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
677
- format = oxfw->rx_stream_formats[i];
678
- if (format == NULL)
679
- continue;
680
- err = snd_oxfw_stream_parse_format(format, &formation);
681
- if (err < 0)
682
- continue;
770
+ // The iPCR is not available for isoc communication.
771
+ err = 0;
772
+ } else {
773
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
774
+ format = oxfw->rx_stream_formats[i];
775
+ if (format == NULL)
776
+ continue;
777
+ err = snd_oxfw_stream_parse_format(format,
778
+ &formation);
779
+ if (err < 0)
780
+ continue;
683781
684
- /* Add one MIDI port. */
685
- if (formation.midi > 0)
686
- oxfw->midi_output_ports = 1;
782
+ /* Add one MIDI port. */
783
+ if (formation.midi > 0)
784
+ oxfw->midi_output_ports = 1;
785
+ }
786
+
787
+ oxfw->has_input = true;
687788 }
688789 }
689790 end: