linux/drivers/staging/media/lirc/lirc_parallel.c
<<
>>
Prefs
   1/*
   2 * lirc_parallel.c
   3 *
   4 * lirc_parallel - device driver for infra-red signal receiving and
   5 *                 transmitting unit built by the author
   6 *
   7 * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de>
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License as published by
  11 *  the Free Software Foundation; either version 2 of the License, or
  12 *  (at your option) any later version.
  13 *
  14 *  This program is distributed in the hope that it will be useful,
  15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *  GNU General Public License for more details.
  18 *
  19 *  You should have received a copy of the GNU General Public License
  20 *  along with this program; if not, write to the Free Software
  21 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22 *
  23 */
  24
  25/*** Includes ***/
  26
  27#include <linux/module.h>
  28#include <linux/sched.h>
  29#include <linux/errno.h>
  30#include <linux/signal.h>
  31#include <linux/fs.h>
  32#include <linux/kernel.h>
  33#include <linux/ioport.h>
  34#include <linux/time.h>
  35#include <linux/mm.h>
  36#include <linux/delay.h>
  37
  38#include <linux/io.h>
  39#include <linux/irq.h>
  40#include <linux/uaccess.h>
  41#include <asm/div64.h>
  42
  43#include <linux/poll.h>
  44#include <linux/parport.h>
  45#include <linux/platform_device.h>
  46
  47#include <media/lirc.h>
  48#include <media/lirc_dev.h>
  49
  50#include "lirc_parallel.h"
  51
  52#define LIRC_DRIVER_NAME "lirc_parallel"
  53
  54#ifndef LIRC_IRQ
  55#define LIRC_IRQ 7
  56#endif
  57#ifndef LIRC_PORT
  58#define LIRC_PORT 0x378
  59#endif
  60#ifndef LIRC_TIMER
  61#define LIRC_TIMER 65536
  62#endif
  63
  64/*** Global Variables ***/
  65
  66static bool debug;
  67static bool check_pselecd;
  68
  69unsigned int irq = LIRC_IRQ;
  70unsigned int io = LIRC_PORT;
  71#ifdef LIRC_TIMER
  72unsigned int timer;
  73unsigned int default_timer = LIRC_TIMER;
  74#endif
  75
  76#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */
  77
  78static int rbuf[RBUF_SIZE];
  79
  80DECLARE_WAIT_QUEUE_HEAD(lirc_wait);
  81
  82unsigned int rptr;
  83unsigned int wptr;
  84unsigned int lost_irqs;
  85int is_open;
  86
  87struct parport *pport;
  88struct pardevice *ppdevice;
  89int is_claimed;
  90
  91unsigned int tx_mask = 1;
  92
  93/*** Internal Functions ***/
  94
  95static unsigned int in(int offset)
  96{
  97        switch (offset) {
  98        case LIRC_LP_BASE:
  99                return parport_read_data(pport);
 100        case LIRC_LP_STATUS:
 101                return parport_read_status(pport);
 102        case LIRC_LP_CONTROL:
 103                return parport_read_control(pport);
 104        }
 105        return 0; /* make compiler happy */
 106}
 107
 108static void out(int offset, int value)
 109{
 110        switch (offset) {
 111        case LIRC_LP_BASE:
 112                parport_write_data(pport, value);
 113                break;
 114        case LIRC_LP_CONTROL:
 115                parport_write_control(pport, value);
 116                break;
 117        case LIRC_LP_STATUS:
 118                printk(KERN_INFO "%s: attempt to write to status register\n",
 119                       LIRC_DRIVER_NAME);
 120                break;
 121        }
 122}
 123
 124static unsigned int lirc_get_timer(void)
 125{
 126        return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT;
 127}
 128
 129static unsigned int lirc_get_signal(void)
 130{
 131        return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT;
 132}
 133
 134static void lirc_on(void)
 135{
 136        out(LIRC_PORT_DATA, tx_mask);
 137}
 138
 139static void lirc_off(void)
 140{
 141        out(LIRC_PORT_DATA, 0);
 142}
 143
 144static unsigned int init_lirc_timer(void)
 145{
 146        struct timeval tv, now;
 147        unsigned int level, newlevel, timeelapsed, newtimer;
 148        int count = 0;
 149
 150        do_gettimeofday(&tv);
 151        tv.tv_sec++;                     /* wait max. 1 sec. */
 152        level = lirc_get_timer();
 153        do {
 154                newlevel = lirc_get_timer();
 155                if (level == 0 && newlevel != 0)
 156                        count++;
 157                level = newlevel;
 158                do_gettimeofday(&now);
 159        } while (count < 1000 && (now.tv_sec < tv.tv_sec
 160                             || (now.tv_sec == tv.tv_sec
 161                                 && now.tv_usec < tv.tv_usec)));
 162
 163        timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000
 164                     + (now.tv_usec - tv.tv_usec));
 165        if (count >= 1000 && timeelapsed > 0) {
 166                if (default_timer == 0) {
 167                        /* autodetect timer */
 168                        newtimer = (1000000*count)/timeelapsed;
 169                        printk(KERN_INFO "%s: %u Hz timer detected\n",
 170                               LIRC_DRIVER_NAME, newtimer);
 171                        return newtimer;
 172                }  else {
 173                        newtimer = (1000000*count)/timeelapsed;
 174                        if (abs(newtimer - default_timer) > default_timer/10) {
 175                                /* bad timer */
 176                                printk(KERN_NOTICE "%s: bad timer: %u Hz\n",
 177                                       LIRC_DRIVER_NAME, newtimer);
 178                                printk(KERN_NOTICE "%s: using default timer: "
 179                                       "%u Hz\n",
 180                                       LIRC_DRIVER_NAME, default_timer);
 181                                return default_timer;
 182                        } else {
 183                                printk(KERN_INFO "%s: %u Hz timer detected\n",
 184                                       LIRC_DRIVER_NAME, newtimer);
 185                                return newtimer; /* use detected value */
 186                        }
 187                }
 188        } else {
 189                printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME);
 190                return 0;
 191        }
 192}
 193
 194static int lirc_claim(void)
 195{
 196        if (parport_claim(ppdevice) != 0) {
 197                printk(KERN_WARNING "%s: could not claim port\n",
 198                       LIRC_DRIVER_NAME);
 199                printk(KERN_WARNING "%s: waiting for port becoming available"
 200                       "\n", LIRC_DRIVER_NAME);
 201                if (parport_claim_or_block(ppdevice) < 0) {
 202                        printk(KERN_NOTICE "%s: could not claim port, giving"
 203                               " up\n", LIRC_DRIVER_NAME);
 204                        return 0;
 205                }
 206        }
 207        out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
 208        is_claimed = 1;
 209        return 1;
 210}
 211
 212/*** interrupt handler ***/
 213
 214static void rbuf_write(int signal)
 215{
 216        unsigned int nwptr;
 217
 218        nwptr = (wptr + 1) & (RBUF_SIZE - 1);
 219        if (nwptr == rptr) {
 220                /* no new signals will be accepted */
 221                lost_irqs++;
 222                printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME);
 223                return;
 224        }
 225        rbuf[wptr] = signal;
 226        wptr = nwptr;
 227}
 228
 229static void irq_handler(void *blah)
 230{
 231        struct timeval tv;
 232        static struct timeval lasttv;
 233        static int init;
 234        long signal;
 235        int data;
 236        unsigned int level, newlevel;
 237        unsigned int timeout;
 238
 239        if (!is_open)
 240                return;
 241
 242        if (!is_claimed)
 243                return;
 244
 245#if 0
 246        /* disable interrupt */
 247          disable_irq(irq);
 248          out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN));
 249#endif
 250        if (check_pselecd && (in(1) & LP_PSELECD))
 251                return;
 252
 253#ifdef LIRC_TIMER
 254        if (init) {
 255                do_gettimeofday(&tv);
 256
 257                signal = tv.tv_sec - lasttv.tv_sec;
 258                if (signal > 15)
 259                        /* really long time */
 260                        data = PULSE_MASK;
 261                else
 262                        data = (int) (signal*1000000 +
 263                                         tv.tv_usec - lasttv.tv_usec +
 264                                         LIRC_SFH506_DELAY);
 265
 266                rbuf_write(data); /* space */
 267        } else {
 268                if (timer == 0) {
 269                        /*
 270                         * wake up; we'll lose this signal, but it will be
 271                         * garbage if the device is turned on anyway
 272                         */
 273                        timer = init_lirc_timer();
 274                        /* enable_irq(irq); */
 275                        return;
 276                }
 277                init = 1;
 278        }
 279
 280        timeout = timer/10;     /* timeout after 1/10 sec. */
 281        signal = 1;
 282        level = lirc_get_timer();
 283        do {
 284                newlevel = lirc_get_timer();
 285                if (level == 0 && newlevel != 0)
 286                        signal++;
 287                level = newlevel;
 288
 289                /* giving up */
 290                if (signal > timeout
 291                    || (check_pselecd && (in(1) & LP_PSELECD))) {
 292                        signal = 0;
 293                        printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME);
 294                        break;
 295                }
 296        } while (lirc_get_signal());
 297
 298        if (signal != 0) {
 299                /* adjust value to usecs */
 300                __u64 helper;
 301
 302                helper = ((__u64) signal)*1000000;
 303                do_div(helper, timer);
 304                signal = (long) helper;
 305
 306                if (signal > LIRC_SFH506_DELAY)
 307                        data = signal - LIRC_SFH506_DELAY;
 308                else
 309                        data = 1;
 310                rbuf_write(PULSE_BIT|data); /* pulse */
 311        }
 312        do_gettimeofday(&lasttv);
 313#else
 314        /* add your code here */
 315#endif
 316
 317        wake_up_interruptible(&lirc_wait);
 318
 319        /* enable interrupt */
 320        /*
 321          enable_irq(irq);
 322          out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN);
 323        */
 324}
 325
 326/*** file operations ***/
 327
 328static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig)
 329{
 330        return -ESPIPE;
 331}
 332
 333static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos)
 334{
 335        int result = 0;
 336        int count = 0;
 337        DECLARE_WAITQUEUE(wait, current);
 338
 339        if (n % sizeof(int))
 340                return -EINVAL;
 341
 342        add_wait_queue(&lirc_wait, &wait);
 343        set_current_state(TASK_INTERRUPTIBLE);
 344        while (count < n) {
 345                if (rptr != wptr) {
 346                        if (copy_to_user(buf+count, (char *) &rbuf[rptr],
 347                                         sizeof(int))) {
 348                                result = -EFAULT;
 349                                break;
 350                        }
 351                        rptr = (rptr + 1) & (RBUF_SIZE - 1);
 352                        count += sizeof(int);
 353                } else {
 354                        if (filep->f_flags & O_NONBLOCK) {
 355                                result = -EAGAIN;
 356                                break;
 357                        }
 358                        if (signal_pending(current)) {
 359                                result = -ERESTARTSYS;
 360                                break;
 361                        }
 362                        schedule();
 363                        set_current_state(TASK_INTERRUPTIBLE);
 364                }
 365        }
 366        remove_wait_queue(&lirc_wait, &wait);
 367        set_current_state(TASK_RUNNING);
 368        return count ? count : result;
 369}
 370
 371static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
 372                          loff_t *ppos)
 373{
 374        int count;
 375        unsigned int i;
 376        unsigned int level, newlevel;
 377        unsigned long flags;
 378        int counttimer;
 379        int *wbuf;
 380        ssize_t ret;
 381
 382        if (!is_claimed)
 383                return -EBUSY;
 384
 385        count = n / sizeof(int);
 386
 387        if (n % sizeof(int) || count % 2 == 0)
 388                return -EINVAL;
 389
 390        wbuf = memdup_user(buf, n);
 391        if (IS_ERR(wbuf))
 392                return PTR_ERR(wbuf);
 393
 394#ifdef LIRC_TIMER
 395        if (timer == 0) {
 396                /* try again if device is ready */
 397                timer = init_lirc_timer();
 398                if (timer == 0) {
 399                        ret = -EIO;
 400                        goto out;
 401                }
 402        }
 403
 404        /* adjust values from usecs */
 405        for (i = 0; i < count; i++) {
 406                __u64 helper;
 407
 408                helper = ((__u64) wbuf[i])*timer;
 409                do_div(helper, 1000000);
 410                wbuf[i] = (int) helper;
 411        }
 412
 413        local_irq_save(flags);
 414        i = 0;
 415        while (i < count) {
 416                level = lirc_get_timer();
 417                counttimer = 0;
 418                lirc_on();
 419                do {
 420                        newlevel = lirc_get_timer();
 421                        if (level == 0 && newlevel != 0)
 422                                counttimer++;
 423                        level = newlevel;
 424                        if (check_pselecd && (in(1) & LP_PSELECD)) {
 425                                lirc_off();
 426                                local_irq_restore(flags);
 427                                ret = -EIO;
 428                                goto out;
 429                        }
 430                } while (counttimer < wbuf[i]);
 431                i++;
 432
 433                lirc_off();
 434                if (i == count)
 435                        break;
 436                counttimer = 0;
 437                do {
 438                        newlevel = lirc_get_timer();
 439                        if (level == 0 && newlevel != 0)
 440                                counttimer++;
 441                        level = newlevel;
 442                        if (check_pselecd && (in(1) & LP_PSELECD)) {
 443                                local_irq_restore(flags);
 444                                ret = -EIO;
 445                                goto out;
 446                        }
 447                } while (counttimer < wbuf[i]);
 448                i++;
 449        }
 450        local_irq_restore(flags);
 451#else
 452        /* place code that handles write without external timer here */
 453#endif
 454        ret = n;
 455out:
 456        kfree(wbuf);
 457
 458        return ret;
 459}
 460
 461static unsigned int lirc_poll(struct file *file, poll_table *wait)
 462{
 463        poll_wait(file, &lirc_wait, wait);
 464        if (rptr != wptr)
 465                return POLLIN | POLLRDNORM;
 466        return 0;
 467}
 468
 469static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 470{
 471        int result;
 472        __u32 features = LIRC_CAN_SET_TRANSMITTER_MASK |
 473                         LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
 474        __u32 mode;
 475        __u32 value;
 476
 477        switch (cmd) {
 478        case LIRC_GET_FEATURES:
 479                result = put_user(features, (__u32 *) arg);
 480                if (result)
 481                        return result;
 482                break;
 483        case LIRC_GET_SEND_MODE:
 484                result = put_user(LIRC_MODE_PULSE, (__u32 *) arg);
 485                if (result)
 486                        return result;
 487                break;
 488        case LIRC_GET_REC_MODE:
 489                result = put_user(LIRC_MODE_MODE2, (__u32 *) arg);
 490                if (result)
 491                        return result;
 492                break;
 493        case LIRC_SET_SEND_MODE:
 494                result = get_user(mode, (__u32 *) arg);
 495                if (result)
 496                        return result;
 497                if (mode != LIRC_MODE_PULSE)
 498                        return -EINVAL;
 499                break;
 500        case LIRC_SET_REC_MODE:
 501                result = get_user(mode, (__u32 *) arg);
 502                if (result)
 503                        return result;
 504                if (mode != LIRC_MODE_MODE2)
 505                        return -ENOSYS;
 506                break;
 507        case LIRC_SET_TRANSMITTER_MASK:
 508                result = get_user(value, (__u32 *) arg);
 509                if (result)
 510                        return result;
 511                if ((value & LIRC_PARALLEL_TRANSMITTER_MASK) != value)
 512                        return LIRC_PARALLEL_MAX_TRANSMITTERS;
 513                tx_mask = value;
 514                break;
 515        default:
 516                return -ENOIOCTLCMD;
 517        }
 518        return 0;
 519}
 520
 521static int lirc_open(struct inode *node, struct file *filep)
 522{
 523        if (is_open || !lirc_claim())
 524                return -EBUSY;
 525
 526        parport_enable_irq(pport);
 527
 528        /* init read ptr */
 529        rptr = 0;
 530        wptr = 0;
 531        lost_irqs = 0;
 532
 533        is_open = 1;
 534        return 0;
 535}
 536
 537static int lirc_close(struct inode *node, struct file *filep)
 538{
 539        if (is_claimed) {
 540                is_claimed = 0;
 541                parport_release(ppdevice);
 542        }
 543        is_open = 0;
 544        return 0;
 545}
 546
 547static const struct file_operations lirc_fops = {
 548        .owner          = THIS_MODULE,
 549        .llseek         = lirc_lseek,
 550        .read           = lirc_read,
 551        .write          = lirc_write,
 552        .poll           = lirc_poll,
 553        .unlocked_ioctl = lirc_ioctl,
 554#ifdef CONFIG_COMPAT
 555        .compat_ioctl   = lirc_ioctl,
 556#endif
 557        .open           = lirc_open,
 558        .release        = lirc_close
 559};
 560
 561static int set_use_inc(void *data)
 562{
 563        return 0;
 564}
 565
 566static void set_use_dec(void *data)
 567{
 568}
 569
 570static struct lirc_driver driver = {
 571        .name           = LIRC_DRIVER_NAME,
 572        .minor          = -1,
 573        .code_length    = 1,
 574        .sample_rate    = 0,
 575        .data           = NULL,
 576        .add_to_buf     = NULL,
 577        .set_use_inc    = set_use_inc,
 578        .set_use_dec    = set_use_dec,
 579        .fops           = &lirc_fops,
 580        .dev            = NULL,
 581        .owner          = THIS_MODULE,
 582};
 583
 584static struct platform_device *lirc_parallel_dev;
 585
 586static int __devinit lirc_parallel_probe(struct platform_device *dev)
 587{
 588        return 0;
 589}
 590
 591static int __devexit lirc_parallel_remove(struct platform_device *dev)
 592{
 593        return 0;
 594}
 595
 596static int lirc_parallel_suspend(struct platform_device *dev,
 597                                        pm_message_t state)
 598{
 599        return 0;
 600}
 601
 602static int lirc_parallel_resume(struct platform_device *dev)
 603{
 604        return 0;
 605}
 606
 607static struct platform_driver lirc_parallel_driver = {
 608        .probe  = lirc_parallel_probe,
 609        .remove = __devexit_p(lirc_parallel_remove),
 610        .suspend        = lirc_parallel_suspend,
 611        .resume = lirc_parallel_resume,
 612        .driver = {
 613                .name   = LIRC_DRIVER_NAME,
 614                .owner  = THIS_MODULE,
 615        },
 616};
 617
 618static int pf(void *handle)
 619{
 620        parport_disable_irq(pport);
 621        is_claimed = 0;
 622        return 0;
 623}
 624
 625static void kf(void *handle)
 626{
 627        if (!is_open)
 628                return;
 629        if (!lirc_claim())
 630                return;
 631        parport_enable_irq(pport);
 632        lirc_off();
 633        /* this is a bit annoying when you actually print...*/
 634        /*
 635        printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME);
 636        */
 637}
 638
 639/*** module initialization and cleanup ***/
 640
 641static int __init lirc_parallel_init(void)
 642{
 643        int result;
 644
 645        result = platform_driver_register(&lirc_parallel_driver);
 646        if (result) {
 647                printk(KERN_NOTICE "platform_driver_register"
 648                                        " returned %d\n", result);
 649                return result;
 650        }
 651
 652        lirc_parallel_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
 653        if (!lirc_parallel_dev) {
 654                result = -ENOMEM;
 655                goto exit_driver_unregister;
 656        }
 657
 658        result = platform_device_add(lirc_parallel_dev);
 659        if (result)
 660                goto exit_device_put;
 661
 662        pport = parport_find_base(io);
 663        if (pport == NULL) {
 664                printk(KERN_NOTICE "%s: no port at %x found\n",
 665                       LIRC_DRIVER_NAME, io);
 666                result = -ENXIO;
 667                goto exit_device_put;
 668        }
 669        ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME,
 670                                           pf, kf, irq_handler, 0, NULL);
 671        parport_put_port(pport);
 672        if (ppdevice == NULL) {
 673                printk(KERN_NOTICE "%s: parport_register_device() failed\n",
 674                       LIRC_DRIVER_NAME);
 675                result = -ENXIO;
 676                goto exit_device_put;
 677        }
 678        if (parport_claim(ppdevice) != 0)
 679                goto skip_init;
 680        is_claimed = 1;
 681        out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
 682
 683#ifdef LIRC_TIMER
 684        if (debug)
 685                out(LIRC_PORT_DATA, tx_mask);
 686
 687        timer = init_lirc_timer();
 688
 689#if 0   /* continue even if device is offline */
 690        if (timer == 0) {
 691                is_claimed = 0;
 692                parport_release(pport);
 693                parport_unregister_device(ppdevice);
 694                result = -EIO;
 695                goto exit_device_put;
 696        }
 697
 698#endif
 699        if (debug)
 700                out(LIRC_PORT_DATA, 0);
 701#endif
 702
 703        is_claimed = 0;
 704        parport_release(ppdevice);
 705 skip_init:
 706        driver.dev = &lirc_parallel_dev->dev;
 707        driver.minor = lirc_register_driver(&driver);
 708        if (driver.minor < 0) {
 709                printk(KERN_NOTICE "%s: register_chrdev() failed\n",
 710                       LIRC_DRIVER_NAME);
 711                parport_unregister_device(ppdevice);
 712                result = -EIO;
 713                goto exit_device_put;
 714        }
 715        printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n",
 716               LIRC_DRIVER_NAME, io, irq);
 717        return 0;
 718
 719exit_device_put:
 720        platform_device_put(lirc_parallel_dev);
 721exit_driver_unregister:
 722        platform_driver_unregister(&lirc_parallel_driver);
 723        return result;
 724}
 725
 726static void __exit lirc_parallel_exit(void)
 727{
 728        parport_unregister_device(ppdevice);
 729        lirc_unregister_driver(driver.minor);
 730
 731        platform_device_unregister(lirc_parallel_dev);
 732        platform_driver_unregister(&lirc_parallel_driver);
 733}
 734
 735module_init(lirc_parallel_init);
 736module_exit(lirc_parallel_exit);
 737
 738MODULE_DESCRIPTION("Infrared receiver driver for parallel ports.");
 739MODULE_AUTHOR("Christoph Bartelmus");
 740MODULE_LICENSE("GPL");
 741
 742module_param(io, int, S_IRUGO);
 743MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)");
 744
 745module_param(irq, int, S_IRUGO);
 746MODULE_PARM_DESC(irq, "Interrupt (7 or 5)");
 747
 748module_param(tx_mask, int, S_IRUGO);
 749MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)");
 750
 751module_param(debug, bool, S_IRUGO | S_IWUSR);
 752MODULE_PARM_DESC(debug, "Enable debugging messages");
 753
 754module_param(check_pselecd, bool, S_IRUGO | S_IWUSR);
 755MODULE_PARM_DESC(check_pselecd, "Check for printer (default: 0)");
 756