Deleted Added
full compact
channel.c (74763) channel.c (74797)
1/*
2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
3 * Portions Copyright by Luigi Rizzo - 1997-99
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 10 unchanged lines hidden (view full) ---

19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
1/*
2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
3 * Portions Copyright by Luigi Rizzo - 1997-99
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 10 unchanged lines hidden (view full) ---

19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/sys/dev/sound/pcm/channel.c 74763 2001-03-24 23:10:29Z cg $
27 * $FreeBSD: head/sys/dev/sound/pcm/channel.c 74797 2001-03-25 21:43:24Z cg $
28 */
29
30#include <dev/sound/pcm/sound.h>
31
32#include "feeder_if.h"
33
34#define MIN_CHUNK_SIZE 256 /* for uiomove etc. */
35#define DMA_ALIGN_THRESHOLD 4

--- 25 unchanged lines hidden (view full) ---

61{
62 struct snd_dbuf *bs = c->bufsoft;
63 unsigned amt, lim;
64
65 CHN_LOCKASSERT(c);
66 if (c->flags & CHN_F_MAPPED) {
67 if (sndbuf_getprevblocks(bs) == 0)
68 return 1;
28 */
29
30#include <dev/sound/pcm/sound.h>
31
32#include "feeder_if.h"
33
34#define MIN_CHUNK_SIZE 256 /* for uiomove etc. */
35#define DMA_ALIGN_THRESHOLD 4

--- 25 unchanged lines hidden (view full) ---

61{
62 struct snd_dbuf *bs = c->bufsoft;
63 unsigned amt, lim;
64
65 CHN_LOCKASSERT(c);
66 if (c->flags & CHN_F_MAPPED) {
67 if (sndbuf_getprevblocks(bs) == 0)
68 return 1;
69 else
69 else
70 return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0;
71 } else {
72 amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
73 lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1;
74 lim = 1;
75 return (amt >= lim)? 1 : 0;
76 }
77 return 0;

--- 118 unchanged lines hidden (view full) ---

196static void
197chn_wrintr(struct pcm_channel *c)
198{
199 int ret;
200
201 CHN_LOCKASSERT(c);
202 irqc++;
203 /* update pointers in primary buffer */
70 return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0;
71 } else {
72 amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
73 lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1;
74 lim = 1;
75 return (amt >= lim)? 1 : 0;
76 }
77 return 0;

--- 118 unchanged lines hidden (view full) ---

196static void
197chn_wrintr(struct pcm_channel *c)
198{
199 int ret;
200
201 CHN_LOCKASSERT(c);
202 irqc++;
203 /* update pointers in primary buffer */
204 chn_dmaupdate(c);
204 chn_dmaupdate(c);
205 /* ...and feed from secondary to primary */
206 ret = chn_wrfeed(c);
207 /* tell the driver we've updated the primary buffer */
205 /* ...and feed from secondary to primary */
206 ret = chn_wrfeed(c);
207 /* tell the driver we've updated the primary buffer */
208 chn_trigger(c, PCMTRIG_EMLDMAWR);
208 chn_trigger(c, PCMTRIG_EMLDMAWR);
209 DEB(if (ret)
210 printf("chn_wrintr: chn_wrfeed returned %d\n", ret);)
211}
212
213/*
214 * user write routine - uiomove data into secondary bufhard, trigger if necessary
215 * if blocking, sleep, rinse and repeat.
216 *

--- 19 unchanged lines hidden (view full) ---

236 newsize = 16;
237 while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2))
238 newsize <<= 1;
239 chn_setblocksize(c, sndbuf_getblkcnt(bs), newsize);
240 DEB(device_printf(c->parent->dev, "frags reset to %d x %d\n", sndbuf_getblkcnt(bs), sndbuf_getblksz(bs)));
241 }
242
243 ret = 0;
209 DEB(if (ret)
210 printf("chn_wrintr: chn_wrfeed returned %d\n", ret);)
211}
212
213/*
214 * user write routine - uiomove data into secondary bufhard, trigger if necessary
215 * if blocking, sleep, rinse and repeat.
216 *

--- 19 unchanged lines hidden (view full) ---

236 newsize = 16;
237 while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2))
238 newsize <<= 1;
239 chn_setblocksize(c, sndbuf_getblkcnt(bs), newsize);
240 DEB(device_printf(c->parent->dev, "frags reset to %d x %d\n", sndbuf_getblkcnt(bs), sndbuf_getblksz(bs)));
241 }
242
243 ret = 0;
244 count = hz;
244 count = hz;
245 while (!ret && (buf->uio_resid > 0) && (count > 0)) {
246 sz = sndbuf_getfree(bs);
247 if (sz == 0) {
248 if (c->flags & CHN_F_NBIO)
249 ret = EWOULDBLOCK;
250 else {
251 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs));
252 if (timeout < 1)
253 timeout = 1;
254 ret = chn_sleep(c, "pcmwr", timeout);
255 if (ret == EWOULDBLOCK) {
256 count -= timeout;
257 ret = 0;
258 } else if (ret == 0)
245 while (!ret && (buf->uio_resid > 0) && (count > 0)) {
246 sz = sndbuf_getfree(bs);
247 if (sz == 0) {
248 if (c->flags & CHN_F_NBIO)
249 ret = EWOULDBLOCK;
250 else {
251 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs));
252 if (timeout < 1)
253 timeout = 1;
254 ret = chn_sleep(c, "pcmwr", timeout);
255 if (ret == EWOULDBLOCK) {
256 count -= timeout;
257 ret = 0;
258 } else if (ret == 0)
259 count = hz;
260 }
259 count = hz;
260 }
261 } else {
262 sz = MIN(sz, buf->uio_resid);
263 KASSERT(sz > 0, ("confusion in chn_write"));
264 /* printf("sz: %d\n", sz); */
265 ret = sndbuf_uiomove(bs, buf, sz);
266 if (ret == 0 && !(c->flags & CHN_F_TRIGGERED))
267 chn_start(c, 0);
268 }
269 }
270 /* printf("ret: %d left: %d\n", ret, buf->uio_resid); */
271
272 if (count <= 0) {
261 } else {
262 sz = MIN(sz, buf->uio_resid);
263 KASSERT(sz > 0, ("confusion in chn_write"));
264 /* printf("sz: %d\n", sz); */
265 ret = sndbuf_uiomove(bs, buf, sz);
266 if (ret == 0 && !(c->flags & CHN_F_TRIGGERED))
267 chn_start(c, 0);
268 }
269 }
270 /* printf("ret: %d left: %d\n", ret, buf->uio_resid); */
271
272 if (count <= 0) {
273 c->flags |= CHN_F_DEAD;
274 device_printf(c->parent->dev, "play interrupt timeout, channel dead\n");
275 }
273 c->flags |= CHN_F_DEAD;
274 device_printf(c->parent->dev, "play interrupt timeout, channel dead\n");
275 }
276
277 return ret;
278}
279
280static int
281chn_rddump(struct pcm_channel *c, unsigned int cnt)
282{
283 struct snd_dbuf *b = c->bufhard;

--- 51 unchanged lines hidden (view full) ---

335static void
336chn_rdintr(struct pcm_channel *c)
337{
338 struct snd_dbuf *b = c->bufhard;
339 int ret;
340
341 CHN_LOCKASSERT(c);
342 /* tell the driver to update the primary bufhard if non-dma */
276
277 return ret;
278}
279
280static int
281chn_rddump(struct pcm_channel *c, unsigned int cnt)
282{
283 struct snd_dbuf *b = c->bufhard;

--- 51 unchanged lines hidden (view full) ---

335static void
336chn_rdintr(struct pcm_channel *c)
337{
338 struct snd_dbuf *b = c->bufhard;
339 int ret;
340
341 CHN_LOCKASSERT(c);
342 /* tell the driver to update the primary bufhard if non-dma */
343 chn_trigger(c, PCMTRIG_EMLDMARD);
343 chn_trigger(c, PCMTRIG_EMLDMARD);
344 /* update pointers in primary bufhard */
344 /* update pointers in primary bufhard */
345 chn_dmaupdate(c);
345 chn_dmaupdate(c);
346 /* ...and feed from primary to secondary */
347 ret = chn_rdfeed(c);
348 if (ret)
349 chn_rddump(c, sndbuf_getblksz(b));
350}
351
352/*
353 * user read routine - trigger if necessary, uiomove data from secondary bufhard

--- 8 unchanged lines hidden (view full) ---

362 int ret, timeout, sz, count;
363 struct snd_dbuf *bs = c->bufsoft;
364
365 CHN_LOCKASSERT(c);
366 if (!(c->flags & CHN_F_TRIGGERED))
367 chn_start(c, 0);
368
369 ret = 0;
346 /* ...and feed from primary to secondary */
347 ret = chn_rdfeed(c);
348 if (ret)
349 chn_rddump(c, sndbuf_getblksz(b));
350}
351
352/*
353 * user read routine - trigger if necessary, uiomove data from secondary bufhard

--- 8 unchanged lines hidden (view full) ---

362 int ret, timeout, sz, count;
363 struct snd_dbuf *bs = c->bufsoft;
364
365 CHN_LOCKASSERT(c);
366 if (!(c->flags & CHN_F_TRIGGERED))
367 chn_start(c, 0);
368
369 ret = 0;
370 count = hz;
370 count = hz;
371 while (!ret && (buf->uio_resid > 0) && (count > 0)) {
372 sz = MIN(buf->uio_resid, sndbuf_getblksz(bs));
373
374 if (sz <= sndbuf_getready(bs)) {
375 ret = sndbuf_uiomove(bs, buf, sz);
376 } else {
377 if (c->flags & CHN_F_NBIO)
378 ret = EWOULDBLOCK;

--- 8 unchanged lines hidden (view full) ---

387 count -= timeout;
388 ret = 0;
389 }
390 }
391 }
392 }
393
394 if (count <= 0) {
371 while (!ret && (buf->uio_resid > 0) && (count > 0)) {
372 sz = MIN(buf->uio_resid, sndbuf_getblksz(bs));
373
374 if (sz <= sndbuf_getready(bs)) {
375 ret = sndbuf_uiomove(bs, buf, sz);
376 } else {
377 if (c->flags & CHN_F_NBIO)
378 ret = EWOULDBLOCK;

--- 8 unchanged lines hidden (view full) ---

387 count -= timeout;
388 ret = 0;
389 }
390 }
391 }
392 }
393
394 if (count <= 0) {
395 c->flags |= CHN_F_DEAD;
396 device_printf(c->parent->dev, "record interrupt timeout, channel dead\n");
397 }
395 c->flags |= CHN_F_DEAD;
396 device_printf(c->parent->dev, "record interrupt timeout, channel dead\n");
397 }
398
399 return ret;
400}
401
402void
403chn_intr(struct pcm_channel *c)
404{
405 CHN_LOCK(c);

--- 72 unchanged lines hidden (view full) ---

478int
479chn_poll(struct pcm_channel *c, int ev, struct proc *p)
480{
481 struct snd_dbuf *bs = c->bufsoft;
482 int ret;
483
484 CHN_LOCK(c);
485 if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED))
398
399 return ret;
400}
401
402void
403chn_intr(struct pcm_channel *c)
404{
405 CHN_LOCK(c);

--- 72 unchanged lines hidden (view full) ---

478int
479chn_poll(struct pcm_channel *c, int ev, struct proc *p)
480{
481 struct snd_dbuf *bs = c->bufsoft;
482 int ret;
483
484 CHN_LOCK(c);
485 if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED))
486 chn_start(c, 1);
486 chn_start(c, 1);
487 ret = 0;
488 if (chn_polltrigger(c) && chn_pollreset(c))
489 ret = ev;
490 else
491 selrecord(p, sndbuf_getsel(bs));
492 CHN_UNLOCK(c);
493 return ret;
494}

--- 25 unchanged lines hidden (view full) ---

520 c->flags &= ~CHN_F_TRIGGERED;
521 /* kill the channel */
522 chn_trigger(c, PCMTRIG_ABORT);
523 sndbuf_setrun(b, 0);
524 chn_dmaupdate(c);
525 missing = sndbuf_getready(bs) + sndbuf_getready(b);
526
527 c->flags &= ~CHN_F_ABORTING;
487 ret = 0;
488 if (chn_polltrigger(c) && chn_pollreset(c))
489 ret = ev;
490 else
491 selrecord(p, sndbuf_getsel(bs));
492 CHN_UNLOCK(c);
493 return ret;
494}

--- 25 unchanged lines hidden (view full) ---

520 c->flags &= ~CHN_F_TRIGGERED;
521 /* kill the channel */
522 chn_trigger(c, PCMTRIG_ABORT);
523 sndbuf_setrun(b, 0);
524 chn_dmaupdate(c);
525 missing = sndbuf_getready(bs) + sndbuf_getready(b);
526
527 c->flags &= ~CHN_F_ABORTING;
528 return missing;
528 return missing;
529}
530
531/*
532 * this routine tries to flush the dma transfer. It is called
533 * on a close. We immediately abort any read DMA
534 * operation, and then wait for the play bufhard to drain.
535 *
536 * called from: dsp_close

--- 7 unchanged lines hidden (view full) ---

544 struct snd_dbuf *bs = c->bufsoft;
545
546 CHN_LOCKASSERT(c);
547 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
548 DEB(printf("chn_flush c->flags 0x%08x\n", c->flags));
549 if (!(c->flags & CHN_F_TRIGGERED))
550 return 0;
551
529}
530
531/*
532 * this routine tries to flush the dma transfer. It is called
533 * on a close. We immediately abort any read DMA
534 * operation, and then wait for the play bufhard to drain.
535 *
536 * called from: dsp_close

--- 7 unchanged lines hidden (view full) ---

544 struct snd_dbuf *bs = c->bufsoft;
545
546 CHN_LOCKASSERT(c);
547 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel"));
548 DEB(printf("chn_flush c->flags 0x%08x\n", c->flags));
549 if (!(c->flags & CHN_F_TRIGGERED))
550 return 0;
551
552 c->flags |= CHN_F_CLOSING;
552 c->flags |= CHN_F_CLOSING;
553 resid = sndbuf_getready(bs) + sndbuf_getready(b);
553 resid = sndbuf_getready(bs) + sndbuf_getready(b);
554 resid_p = resid;
555 count = 10;
554 resid_p = resid;
555 count = 10;
556 ret = 0;
557 while ((count > 0) && (resid > sndbuf_getsize(b)) && (ret == 0)) {
556 ret = 0;
557 while ((count > 0) && (resid > sndbuf_getsize(b)) && (ret == 0)) {
558 /* still pending output data. */
558 /* still pending output data. */
559 ret = chn_sleep(c, "pcmflu", hz / 10);
560 if (ret == EWOULDBLOCK)
561 ret = 0;
562 if (ret == 0) {
563 resid = sndbuf_getready(bs) + sndbuf_getready(b);
564 if (resid >= resid_p)
565 count--;
566 resid_p = resid;
559 ret = chn_sleep(c, "pcmflu", hz / 10);
560 if (ret == EWOULDBLOCK)
561 ret = 0;
562 if (ret == 0) {
563 resid = sndbuf_getready(bs) + sndbuf_getready(b);
564 if (resid >= resid_p)
565 count--;
566 resid_p = resid;
567 }
568 }
567 }
568 }
569 if (count == 0)
570 DEB(printf("chn_flush: timeout\n"));
571
572 c->flags &= ~CHN_F_TRIGGERED;
573 /* kill the channel */
574 chn_trigger(c, PCMTRIG_ABORT);
575 sndbuf_setrun(b, 0);
576

--- 28 unchanged lines hidden (view full) ---

605 r = chn_setformat(c, fmt);
606 if (r == 0)
607 r = chn_setspeed(c, hwspd);
608 if (r == 0)
609 r = chn_setvolume(c, 100, 100);
610 }
611 r = chn_setblocksize(c, 0, 0);
612 if (r == 0) {
569 if (count == 0)
570 DEB(printf("chn_flush: timeout\n"));
571
572 c->flags &= ~CHN_F_TRIGGERED;
573 /* kill the channel */
574 chn_trigger(c, PCMTRIG_ABORT);
575 sndbuf_setrun(b, 0);
576

--- 28 unchanged lines hidden (view full) ---

605 r = chn_setformat(c, fmt);
606 if (r == 0)
607 r = chn_setspeed(c, hwspd);
608 if (r == 0)
609 r = chn_setvolume(c, 100, 100);
610 }
611 r = chn_setblocksize(c, 0, 0);
612 if (r == 0) {
613 chn_resetbuf(c);
614 CHANNEL_RESETDONE(c->methods, c->devinfo);
613 chn_resetbuf(c);
614 CHANNEL_RESETDONE(c->methods, c->devinfo);
615 }
616 return r;
617}
618
619int
620chn_init(struct pcm_channel *c, void *devinfo, int dir)
621{
622 struct feeder_class *fc;

--- 75 unchanged lines hidden (view full) ---

698 return r;
699}
700
701int
702chn_setvolume(struct pcm_channel *c, int left, int right)
703{
704 CHN_LOCKASSERT(c);
705 /* could add a feeder for volume changing if channel returns -1 */
615 }
616 return r;
617}
618
619int
620chn_init(struct pcm_channel *c, void *devinfo, int dir)
621{
622 struct feeder_class *fc;

--- 75 unchanged lines hidden (view full) ---

698 return r;
699}
700
701int
702chn_setvolume(struct pcm_channel *c, int left, int right)
703{
704 CHN_LOCKASSERT(c);
705 /* could add a feeder for volume changing if channel returns -1 */
706 c->volume = (left << 8) | right;
707 return 0;
706 c->volume = (left << 8) | right;
707 return 0;
708}
709
710static int
711chn_tryspeed(struct pcm_channel *c, int speed)
712{
713 struct pcm_feeder *f;
714 struct snd_dbuf *b = c->bufhard;
715 struct snd_dbuf *bs = c->bufsoft;

--- 44 unchanged lines hidden (view full) ---

760 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(bs));
761 DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(bs), r));
762 if (r)
763 goto out;
764
765 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(b));
766 DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(b), r));
767out:
708}
709
710static int
711chn_tryspeed(struct pcm_channel *c, int speed)
712{
713 struct pcm_feeder *f;
714 struct snd_dbuf *b = c->bufhard;
715 struct snd_dbuf *bs = c->bufsoft;

--- 44 unchanged lines hidden (view full) ---

760 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(bs));
761 DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(bs), r));
762 if (r)
763 goto out;
764
765 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(b));
766 DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(b), r));
767out:
768 return r;
768 return r;
769 } else
770 return EINVAL;
771}
772
773int
774chn_setspeed(struct pcm_channel *c, int speed)
775{
776 int r, oldspeed = c->speed;

--- 19 unchanged lines hidden (view full) ---

796 DEB(printf("want format %d\n", fmt));
797 c->format = fmt;
798 hwfmt = c->format;
799 c->feederflags &= ~(1 << FEEDER_FMT);
800 if (!fmtvalid(hwfmt, chn_getcaps(c)->fmtlist))
801 c->feederflags |= 1 << FEEDER_FMT;
802 r = chn_buildfeeder(c);
803 if (r == 0) {
769 } else
770 return EINVAL;
771}
772
773int
774chn_setspeed(struct pcm_channel *c, int speed)
775{
776 int r, oldspeed = c->speed;

--- 19 unchanged lines hidden (view full) ---

796 DEB(printf("want format %d\n", fmt));
797 c->format = fmt;
798 hwfmt = c->format;
799 c->feederflags &= ~(1 << FEEDER_FMT);
800 if (!fmtvalid(hwfmt, chn_getcaps(c)->fmtlist))
801 c->feederflags |= 1 << FEEDER_FMT;
802 r = chn_buildfeeder(c);
803 if (r == 0) {
804 hwfmt = c->feeder->desc->out;
805 sndbuf_setfmt(b, hwfmt);
804 hwfmt = c->feeder->desc->out;
805 sndbuf_setfmt(b, hwfmt);
806 sndbuf_setfmt(bs, fmt);
806 sndbuf_setfmt(bs, fmt);
807 chn_resetbuf(c);
808 CHANNEL_SETFORMAT(c->methods, c->devinfo, hwfmt);
807 chn_resetbuf(c);
808 CHANNEL_SETFORMAT(c->methods, c->devinfo, hwfmt);
809 r = chn_tryspeed(c, c->speed);
809 r = chn_tryspeed(c, c->speed);
810 }
810 }
811 return r;
812 } else
813 return EINVAL;
814}
815
816int
817chn_setformat(struct pcm_channel *c, u_int32_t fmt)
818{

--- 199 unchanged lines hidden ---
811 return r;
812 } else
813 return EINVAL;
814}
815
816int
817chn_setformat(struct pcm_channel *c, u_int32_t fmt)
818{

--- 199 unchanged lines hidden ---