linux/sound/drivers/mpu401/mpu401_uart.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
   4 *  Routines for control of MPU-401 in UART mode
   5 *
   6 *  MPU-401 supports UART mode which is not capable generate transmit
   7 *  interrupts thus output is done via polling. Without interrupt,
   8 *  input is done also via polling. Do not expect good performance.
   9 *
  10 *   13-03-2003:
  11 *      Added support for different kind of hardware I/O. Build in choices
  12 *      are port and mmio. For other kind of I/O, set mpu->read and
  13 *      mpu->write to your own I/O functions.
  14 */
  15
  16#include <linux/io.h>
  17#include <linux/delay.h>
  18#include <linux/init.h>
  19#include <linux/slab.h>
  20#include <linux/ioport.h>
  21#include <linux/module.h>
  22#include <linux/interrupt.h>
  23#include <linux/errno.h>
  24#include <sound/core.h>
  25#include <sound/mpu401.h>
  26
  27MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
  28MODULE_DESCRIPTION("Routines for control of MPU-401 in UART mode");
  29MODULE_LICENSE("GPL");
  30
  31static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu);
  32static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu);
  33
  34/*
  35
  36 */
  37
  38#define snd_mpu401_input_avail(mpu) \
  39        (!(mpu->read(mpu, MPU401C(mpu)) & MPU401_RX_EMPTY))
  40#define snd_mpu401_output_ready(mpu) \
  41        (!(mpu->read(mpu, MPU401C(mpu)) & MPU401_TX_FULL))
  42
  43/* Build in lowlevel io */
  44static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data,
  45                              unsigned long addr)
  46{
  47        outb(data, addr);
  48}
  49
  50static unsigned char mpu401_read_port(struct snd_mpu401 *mpu,
  51                                      unsigned long addr)
  52{
  53        return inb(addr);
  54}
  55
  56static void mpu401_write_mmio(struct snd_mpu401 *mpu, unsigned char data,
  57                              unsigned long addr)
  58{
  59        writeb(data, (void __iomem *)addr);
  60}
  61
  62static unsigned char mpu401_read_mmio(struct snd_mpu401 *mpu,
  63                                      unsigned long addr)
  64{
  65        return readb((void __iomem *)addr);
  66}
  67/*  */
  68
  69static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu)
  70{
  71        int timeout = 100000;
  72        for (; timeout > 0 && snd_mpu401_input_avail(mpu); timeout--)
  73                mpu->read(mpu, MPU401D(mpu));
  74#ifdef CONFIG_SND_DEBUG
  75        if (timeout <= 0)
  76                snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n",
  77                           mpu->read(mpu, MPU401C(mpu)));
  78#endif
  79}
  80
  81static void uart_interrupt_tx(struct snd_mpu401 *mpu)
  82{
  83        unsigned long flags;
  84
  85        if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) &&
  86            test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) {
  87                spin_lock_irqsave(&mpu->output_lock, flags);
  88                snd_mpu401_uart_output_write(mpu);
  89                spin_unlock_irqrestore(&mpu->output_lock, flags);
  90        }
  91}
  92
  93static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
  94{
  95        unsigned long flags;
  96
  97        if (mpu->info_flags & MPU401_INFO_INPUT) {
  98                spin_lock_irqsave(&mpu->input_lock, flags);
  99                if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode))
 100                        snd_mpu401_uart_input_read(mpu);
 101                else
 102                        snd_mpu401_uart_clear_rx(mpu);
 103                spin_unlock_irqrestore(&mpu->input_lock, flags);
 104        }
 105        if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
 106                /* ok. for better Tx performance try do some output
 107                   when input is done */
 108                uart_interrupt_tx(mpu);
 109}
 110
 111/**
 112 * snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler
 113 * @irq: the irq number
 114 * @dev_id: mpu401 instance
 115 *
 116 * Processes the interrupt for MPU401-UART i/o.
 117 *
 118 * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise.
 119 */
 120irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id)
 121{
 122        struct snd_mpu401 *mpu = dev_id;
 123        
 124        if (!mpu)
 125                return IRQ_NONE;
 126        _snd_mpu401_uart_interrupt(mpu);
 127        return IRQ_HANDLED;
 128}
 129
 130EXPORT_SYMBOL(snd_mpu401_uart_interrupt);
 131
 132/**
 133 * snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler
 134 * @irq: the irq number
 135 * @dev_id: mpu401 instance
 136 *
 137 * Processes the interrupt for MPU401-UART output.
 138 *
 139 * Return: %IRQ_HANDLED if the interrupt was handled. %IRQ_NONE otherwise.
 140 */
 141irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id)
 142{
 143        struct snd_mpu401 *mpu = dev_id;
 144        
 145        if (!mpu)
 146                return IRQ_NONE;
 147        uart_interrupt_tx(mpu);
 148        return IRQ_HANDLED;
 149}
 150
 151EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx);
 152
 153/*
 154 * timer callback
 155 * reprogram the timer and call the interrupt job
 156 */
 157static void snd_mpu401_uart_timer(struct timer_list *t)
 158{
 159        struct snd_mpu401 *mpu = from_timer(mpu, t, timer);
 160        unsigned long flags;
 161
 162        spin_lock_irqsave(&mpu->timer_lock, flags);
 163        /*mpu->mode |= MPU401_MODE_TIMER;*/
 164        mod_timer(&mpu->timer,  1 + jiffies);
 165        spin_unlock_irqrestore(&mpu->timer_lock, flags);
 166        if (mpu->rmidi)
 167                _snd_mpu401_uart_interrupt(mpu);
 168}
 169
 170/*
 171 * initialize the timer callback if not programmed yet
 172 */
 173static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input)
 174{
 175        unsigned long flags;
 176
 177        spin_lock_irqsave (&mpu->timer_lock, flags);
 178        if (mpu->timer_invoked == 0) {
 179                timer_setup(&mpu->timer, snd_mpu401_uart_timer, 0);
 180                mod_timer(&mpu->timer, 1 + jiffies);
 181        } 
 182        mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER :
 183                MPU401_MODE_OUTPUT_TIMER;
 184        spin_unlock_irqrestore (&mpu->timer_lock, flags);
 185}
 186
 187/*
 188 * remove the timer callback if still active
 189 */
 190static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input)
 191{
 192        unsigned long flags;
 193
 194        spin_lock_irqsave (&mpu->timer_lock, flags);
 195        if (mpu->timer_invoked) {
 196                mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER :
 197                        ~MPU401_MODE_OUTPUT_TIMER;
 198                if (! mpu->timer_invoked)
 199                        del_timer(&mpu->timer);
 200        }
 201        spin_unlock_irqrestore (&mpu->timer_lock, flags);
 202}
 203
 204/*
 205 * send a UART command
 206 * return zero if successful, non-zero for some errors
 207 */
 208
 209static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
 210                               int ack)
 211{
 212        unsigned long flags;
 213        int timeout, ok;
 214
 215        spin_lock_irqsave(&mpu->input_lock, flags);
 216        if (mpu->hardware != MPU401_HW_TRID4DWAVE) {
 217                mpu->write(mpu, 0x00, MPU401D(mpu));
 218                /*snd_mpu401_uart_clear_rx(mpu);*/
 219        }
 220        /* ok. standard MPU-401 initialization */
 221        if (mpu->hardware != MPU401_HW_SB) {
 222                for (timeout = 1000; timeout > 0 &&
 223                             !snd_mpu401_output_ready(mpu); timeout--)
 224                        udelay(10);
 225#ifdef CONFIG_SND_DEBUG
 226                if (!timeout)
 227                        snd_printk(KERN_ERR "cmd: tx timeout (status = 0x%x)\n",
 228                                   mpu->read(mpu, MPU401C(mpu)));
 229#endif
 230        }
 231        mpu->write(mpu, cmd, MPU401C(mpu));
 232        if (ack && !(mpu->info_flags & MPU401_INFO_NO_ACK)) {
 233                ok = 0;
 234                timeout = 10000;
 235                while (!ok && timeout-- > 0) {
 236                        if (snd_mpu401_input_avail(mpu)) {
 237                                if (mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK)
 238                                        ok = 1;
 239                        }
 240                }
 241                if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK)
 242                        ok = 1;
 243        } else
 244                ok = 1;
 245        spin_unlock_irqrestore(&mpu->input_lock, flags);
 246        if (!ok) {
 247                snd_printk(KERN_ERR "cmd: 0x%x failed at 0x%lx "
 248                           "(status = 0x%x, data = 0x%x)\n", cmd, mpu->port,
 249                           mpu->read(mpu, MPU401C(mpu)),
 250                           mpu->read(mpu, MPU401D(mpu)));
 251                return 1;
 252        }
 253        return 0;
 254}
 255
 256static int snd_mpu401_do_reset(struct snd_mpu401 *mpu)
 257{
 258        if (snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1))
 259                return -EIO;
 260        if (snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 0))
 261                return -EIO;
 262        return 0;
 263}
 264
 265/*
 266 * input/output open/close - protected by open_mutex in rawmidi.c
 267 */
 268static int snd_mpu401_uart_input_open(struct snd_rawmidi_substream *substream)
 269{
 270        struct snd_mpu401 *mpu;
 271        int err;
 272
 273        mpu = substream->rmidi->private_data;
 274        if (mpu->open_input && (err = mpu->open_input(mpu)) < 0)
 275                return err;
 276        if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) {
 277                if (snd_mpu401_do_reset(mpu) < 0)
 278                        goto error_out;
 279        }
 280        mpu->substream_input = substream;
 281        set_bit(MPU401_MODE_BIT_INPUT, &mpu->mode);
 282        return 0;
 283
 284error_out:
 285        if (mpu->open_input && mpu->close_input)
 286                mpu->close_input(mpu);
 287        return -EIO;
 288}
 289
 290static int snd_mpu401_uart_output_open(struct snd_rawmidi_substream *substream)
 291{
 292        struct snd_mpu401 *mpu;
 293        int err;
 294
 295        mpu = substream->rmidi->private_data;
 296        if (mpu->open_output && (err = mpu->open_output(mpu)) < 0)
 297                return err;
 298        if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) {
 299                if (snd_mpu401_do_reset(mpu) < 0)
 300                        goto error_out;
 301        }
 302        mpu->substream_output = substream;
 303        set_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode);
 304        return 0;
 305
 306error_out:
 307        if (mpu->open_output && mpu->close_output)
 308                mpu->close_output(mpu);
 309        return -EIO;
 310}
 311
 312static int snd_mpu401_uart_input_close(struct snd_rawmidi_substream *substream)
 313{
 314        struct snd_mpu401 *mpu;
 315        int err = 0;
 316
 317        mpu = substream->rmidi->private_data;
 318        clear_bit(MPU401_MODE_BIT_INPUT, &mpu->mode);
 319        mpu->substream_input = NULL;
 320        if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode))
 321                err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0);
 322        if (mpu->close_input)
 323                mpu->close_input(mpu);
 324        if (err)
 325                return -EIO;
 326        return 0;
 327}
 328
 329static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream)
 330{
 331        struct snd_mpu401 *mpu;
 332        int err = 0;
 333
 334        mpu = substream->rmidi->private_data;
 335        clear_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode);
 336        mpu->substream_output = NULL;
 337        if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode))
 338                err = snd_mpu401_uart_cmd(mpu, MPU401_RESET, 0);
 339        if (mpu->close_output)
 340                mpu->close_output(mpu);
 341        if (err)
 342                return -EIO;
 343        return 0;
 344}
 345
 346/*
 347 * trigger input callback
 348 */
 349static void
 350snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up)
 351{
 352        unsigned long flags;
 353        struct snd_mpu401 *mpu;
 354        int max = 64;
 355
 356        mpu = substream->rmidi->private_data;
 357        if (up) {
 358                if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER,
 359                                       &mpu->mode)) {
 360                        /* first time - flush FIFO */
 361                        while (max-- > 0)
 362                                mpu->read(mpu, MPU401D(mpu));
 363                        if (mpu->info_flags & MPU401_INFO_USE_TIMER)
 364                                snd_mpu401_uart_add_timer(mpu, 1);
 365                }
 366                
 367                /* read data in advance */
 368                spin_lock_irqsave(&mpu->input_lock, flags);
 369                snd_mpu401_uart_input_read(mpu);
 370                spin_unlock_irqrestore(&mpu->input_lock, flags);
 371        } else {
 372                if (mpu->info_flags & MPU401_INFO_USE_TIMER)
 373                        snd_mpu401_uart_remove_timer(mpu, 1);
 374                clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
 375        }
 376
 377}
 378
 379/*
 380 * transfer input pending data
 381 * call with input_lock spinlock held
 382 */
 383static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu)
 384{
 385        int max = 128;
 386        unsigned char byte;
 387
 388        while (max-- > 0) {
 389                if (! snd_mpu401_input_avail(mpu))
 390                        break; /* input not available */
 391                byte = mpu->read(mpu, MPU401D(mpu));
 392                if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
 393                        snd_rawmidi_receive(mpu->substream_input, &byte, 1);
 394        }
 395}
 396
 397/*
 398 *  Tx FIFO sizes:
 399 *    CS4237B                   - 16 bytes
 400 *    AudioDrive ES1688         - 12 bytes
 401 *    S3 SonicVibes             -  8 bytes
 402 *    SoundBlaster AWE 64       -  2 bytes (ugly hardware)
 403 */
 404
 405/*
 406 * write output pending bytes
 407 * call with output_lock spinlock held
 408 */
 409static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu)
 410{
 411        unsigned char byte;
 412        int max = 256;
 413
 414        do {
 415                if (snd_rawmidi_transmit_peek(mpu->substream_output,
 416                                              &byte, 1) == 1) {
 417                        /*
 418                         * Try twice because there is hardware that insists on
 419                         * setting the output busy bit after each write.
 420                         */
 421                        if (!snd_mpu401_output_ready(mpu) &&
 422                            !snd_mpu401_output_ready(mpu))
 423                                break;  /* Tx FIFO full - try again later */
 424                        mpu->write(mpu, byte, MPU401D(mpu));
 425                        snd_rawmidi_transmit_ack(mpu->substream_output, 1);
 426                } else {
 427                        snd_mpu401_uart_remove_timer (mpu, 0);
 428                        break;  /* no other data - leave the tx loop */
 429                }
 430        } while (--max > 0);
 431}
 432
 433/*
 434 * output trigger callback
 435 */
 436static void
 437snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
 438{
 439        unsigned long flags;
 440        struct snd_mpu401 *mpu;
 441
 442        mpu = substream->rmidi->private_data;
 443        if (up) {
 444                set_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode);
 445
 446                /* try to add the timer at each output trigger,
 447                 * since the output timer might have been removed in
 448                 * snd_mpu401_uart_output_write().
 449                 */
 450                if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
 451                        snd_mpu401_uart_add_timer(mpu, 0);
 452
 453                /* output pending data */
 454                spin_lock_irqsave(&mpu->output_lock, flags);
 455                snd_mpu401_uart_output_write(mpu);
 456                spin_unlock_irqrestore(&mpu->output_lock, flags);
 457        } else {
 458                if (! (mpu->info_flags & MPU401_INFO_TX_IRQ))
 459                        snd_mpu401_uart_remove_timer(mpu, 0);
 460                clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode);
 461        }
 462}
 463
 464/*
 465
 466 */
 467
 468static const struct snd_rawmidi_ops snd_mpu401_uart_output =
 469{
 470        .open =         snd_mpu401_uart_output_open,
 471        .close =        snd_mpu401_uart_output_close,
 472        .trigger =      snd_mpu401_uart_output_trigger,
 473};
 474
 475static const struct snd_rawmidi_ops snd_mpu401_uart_input =
 476{
 477        .open =         snd_mpu401_uart_input_open,
 478        .close =        snd_mpu401_uart_input_close,
 479        .trigger =      snd_mpu401_uart_input_trigger,
 480};
 481
 482static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi)
 483{
 484        struct snd_mpu401 *mpu = rmidi->private_data;
 485        if (mpu->irq >= 0)
 486                free_irq(mpu->irq, (void *) mpu);
 487        release_and_free_resource(mpu->res);
 488        kfree(mpu);
 489}
 490
 491/**
 492 * snd_mpu401_uart_new - create an MPU401-UART instance
 493 * @card: the card instance
 494 * @device: the device index, zero-based
 495 * @hardware: the hardware type, MPU401_HW_XXXX
 496 * @port: the base address of MPU401 port
 497 * @info_flags: bitflags MPU401_INFO_XXX
 498 * @irq: the ISA irq number, -1 if not to be allocated
 499 * @rrawmidi: the pointer to store the new rawmidi instance
 500 *
 501 * Creates a new MPU-401 instance.
 502 *
 503 * Note that the rawmidi instance is returned on the rrawmidi argument,
 504 * not the mpu401 instance itself.  To access to the mpu401 instance,
 505 * cast from rawmidi->private_data (with struct snd_mpu401 magic-cast).
 506 *
 507 * Return: Zero if successful, or a negative error code.
 508 */
 509int snd_mpu401_uart_new(struct snd_card *card, int device,
 510                        unsigned short hardware,
 511                        unsigned long port,
 512                        unsigned int info_flags,
 513                        int irq,
 514                        struct snd_rawmidi ** rrawmidi)
 515{
 516        struct snd_mpu401 *mpu;
 517        struct snd_rawmidi *rmidi;
 518        int in_enable, out_enable;
 519        int err;
 520
 521        if (rrawmidi)
 522                *rrawmidi = NULL;
 523        if (! (info_flags & (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT)))
 524                info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT;
 525        in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0;
 526        out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0;
 527        if ((err = snd_rawmidi_new(card, "MPU-401U", device,
 528                                   out_enable, in_enable, &rmidi)) < 0)
 529                return err;
 530        mpu = kzalloc(sizeof(*mpu), GFP_KERNEL);
 531        if (!mpu) {
 532                err = -ENOMEM;
 533                goto free_device;
 534        }
 535        rmidi->private_data = mpu;
 536        rmidi->private_free = snd_mpu401_uart_free;
 537        spin_lock_init(&mpu->input_lock);
 538        spin_lock_init(&mpu->output_lock);
 539        spin_lock_init(&mpu->timer_lock);
 540        mpu->hardware = hardware;
 541        mpu->irq = -1;
 542        if (! (info_flags & MPU401_INFO_INTEGRATED)) {
 543                int res_size = hardware == MPU401_HW_PC98II ? 4 : 2;
 544                mpu->res = request_region(port, res_size, "MPU401 UART");
 545                if (!mpu->res) {
 546                        snd_printk(KERN_ERR "mpu401_uart: "
 547                                   "unable to grab port 0x%lx size %d\n",
 548                                   port, res_size);
 549                        err = -EBUSY;
 550                        goto free_device;
 551                }
 552        }
 553        if (info_flags & MPU401_INFO_MMIO) {
 554                mpu->write = mpu401_write_mmio;
 555                mpu->read = mpu401_read_mmio;
 556        } else {
 557                mpu->write = mpu401_write_port;
 558                mpu->read = mpu401_read_port;
 559        }
 560        mpu->port = port;
 561        if (hardware == MPU401_HW_PC98II)
 562                mpu->cport = port + 2;
 563        else
 564                mpu->cport = port + 1;
 565        if (irq >= 0) {
 566                if (request_irq(irq, snd_mpu401_uart_interrupt, 0,
 567                                "MPU401 UART", (void *) mpu)) {
 568                        snd_printk(KERN_ERR "mpu401_uart: "
 569                                   "unable to grab IRQ %d\n", irq);
 570                        err = -EBUSY;
 571                        goto free_device;
 572                }
 573        }
 574        if (irq < 0 && !(info_flags & MPU401_INFO_IRQ_HOOK))
 575                info_flags |= MPU401_INFO_USE_TIMER;
 576        mpu->info_flags = info_flags;
 577        mpu->irq = irq;
 578        if (card->shortname[0])
 579                snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI",
 580                         card->shortname);
 581        else
 582                sprintf(rmidi->name, "MPU-401 MIDI %d-%d",card->number, device);
 583        if (out_enable) {
 584                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
 585                                    &snd_mpu401_uart_output);
 586                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
 587        }
 588        if (in_enable) {
 589                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
 590                                    &snd_mpu401_uart_input);
 591                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
 592                if (out_enable)
 593                        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
 594        }
 595        mpu->rmidi = rmidi;
 596        if (rrawmidi)
 597                *rrawmidi = rmidi;
 598        return 0;
 599free_device:
 600        snd_device_free(card, rmidi);
 601        return err;
 602}
 603
 604EXPORT_SYMBOL(snd_mpu401_uart_new);
 605