serial_ir.c (20637B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * serial_ir.c 4 * 5 * serial_ir - Device driver that records pulse- and pause-lengths 6 * (space-lengths) between DDCD event on a serial port. 7 * 8 * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de> 9 * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu> 10 * Copyright (C) 1998 Ben Pfaff <blp@gnu.org> 11 * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de> 12 * Copyright (C) 2007 Andrei Tanas <andrei@tanas.ca> (suspend/resume support) 13 * Copyright (C) 2016 Sean Young <sean@mess.org> (port to rc-core) 14 */ 15 16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 17 18#include <linux/module.h> 19#include <linux/errno.h> 20#include <linux/interrupt.h> 21#include <linux/kernel.h> 22#include <linux/serial_reg.h> 23#include <linux/types.h> 24#include <linux/delay.h> 25#include <linux/platform_device.h> 26#include <linux/spinlock.h> 27#include <media/rc-core.h> 28 29struct serial_ir_hw { 30 int signal_pin; 31 int signal_pin_change; 32 u8 on; 33 u8 off; 34 unsigned set_send_carrier:1; 35 unsigned set_duty_cycle:1; 36 void (*send_pulse)(unsigned int length, ktime_t edge); 37 void (*send_space)(void); 38 spinlock_t lock; 39}; 40 41#define IR_HOMEBREW 0 42#define IR_IRDEO 1 43#define IR_IRDEO_REMOTE 2 44#define IR_ANIMAX 3 45#define IR_IGOR 4 46 47/* module parameters */ 48static int type; 49static int io; 50static int irq; 51static ulong iommap; 52static int ioshift; 53static bool softcarrier = true; 54static bool share_irq; 55static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ 56static bool txsense; /* 0 = active high, 1 = active low */ 57 58/* forward declarations */ 59static void send_pulse_irdeo(unsigned int length, ktime_t edge); 60static void send_space_irdeo(void); 61#ifdef CONFIG_IR_SERIAL_TRANSMITTER 62static void send_pulse_homebrew(unsigned int length, ktime_t edge); 63static void send_space_homebrew(void); 64#endif 65 66static struct serial_ir_hw hardware[] = { 67 [IR_HOMEBREW] = { 68 .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_HOMEBREW].lock), 69 .signal_pin = UART_MSR_DCD, 70 .signal_pin_change = UART_MSR_DDCD, 71 .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), 72 .off = (UART_MCR_RTS | UART_MCR_OUT2), 73#ifdef CONFIG_IR_SERIAL_TRANSMITTER 74 .send_pulse = send_pulse_homebrew, 75 .send_space = send_space_homebrew, 76 .set_send_carrier = true, 77 .set_duty_cycle = true, 78#endif 79 }, 80 81 [IR_IRDEO] = { 82 .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IRDEO].lock), 83 .signal_pin = UART_MSR_DSR, 84 .signal_pin_change = UART_MSR_DDSR, 85 .on = UART_MCR_OUT2, 86 .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), 87 .send_pulse = send_pulse_irdeo, 88 .send_space = send_space_irdeo, 89 .set_duty_cycle = true, 90 }, 91 92 [IR_IRDEO_REMOTE] = { 93 .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IRDEO_REMOTE].lock), 94 .signal_pin = UART_MSR_DSR, 95 .signal_pin_change = UART_MSR_DDSR, 96 .on = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), 97 .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), 98 .send_pulse = send_pulse_irdeo, 99 .send_space = send_space_irdeo, 100 .set_duty_cycle = true, 101 }, 102 103 [IR_ANIMAX] = { 104 .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_ANIMAX].lock), 105 .signal_pin = UART_MSR_DCD, 106 .signal_pin_change = UART_MSR_DDCD, 107 .on = 0, 108 .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), 109 }, 110 111 [IR_IGOR] = { 112 .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IGOR].lock), 113 .signal_pin = UART_MSR_DSR, 114 .signal_pin_change = UART_MSR_DDSR, 115 .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), 116 .off = (UART_MCR_RTS | UART_MCR_OUT2), 117#ifdef CONFIG_IR_SERIAL_TRANSMITTER 118 .send_pulse = send_pulse_homebrew, 119 .send_space = send_space_homebrew, 120 .set_send_carrier = true, 121 .set_duty_cycle = true, 122#endif 123 }, 124}; 125 126#define RS_ISR_PASS_LIMIT 256 127 128struct serial_ir { 129 ktime_t lastkt; 130 struct rc_dev *rcdev; 131 struct platform_device *pdev; 132 struct timer_list timeout_timer; 133 134 unsigned int carrier; 135 unsigned int duty_cycle; 136}; 137 138static struct serial_ir serial_ir; 139 140/* fetch serial input packet (1 byte) from register offset */ 141static u8 sinp(int offset) 142{ 143 if (iommap) 144 /* the register is memory-mapped */ 145 offset <<= ioshift; 146 147 return inb(io + offset); 148} 149 150/* write serial output packet (1 byte) of value to register offset */ 151static void soutp(int offset, u8 value) 152{ 153 if (iommap) 154 /* the register is memory-mapped */ 155 offset <<= ioshift; 156 157 outb(value, io + offset); 158} 159 160static void on(void) 161{ 162 if (txsense) 163 soutp(UART_MCR, hardware[type].off); 164 else 165 soutp(UART_MCR, hardware[type].on); 166} 167 168static void off(void) 169{ 170 if (txsense) 171 soutp(UART_MCR, hardware[type].on); 172 else 173 soutp(UART_MCR, hardware[type].off); 174} 175 176static void send_pulse_irdeo(unsigned int length, ktime_t target) 177{ 178 long rawbits; 179 int i; 180 unsigned char output; 181 unsigned char chunk, shifted; 182 183 /* how many bits have to be sent ? */ 184 rawbits = length * 1152 / 10000; 185 if (serial_ir.duty_cycle > 50) 186 chunk = 3; 187 else 188 chunk = 1; 189 for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) { 190 shifted = chunk << (i * 3); 191 shifted >>= 1; 192 output &= (~shifted); 193 i++; 194 if (i == 3) { 195 soutp(UART_TX, output); 196 while (!(sinp(UART_LSR) & UART_LSR_THRE)) 197 ; 198 output = 0x7f; 199 i = 0; 200 } 201 } 202 if (i != 0) { 203 soutp(UART_TX, output); 204 while (!(sinp(UART_LSR) & UART_LSR_TEMT)) 205 ; 206 } 207} 208 209static void send_space_irdeo(void) 210{ 211} 212 213#ifdef CONFIG_IR_SERIAL_TRANSMITTER 214static void send_pulse_homebrew_softcarrier(unsigned int length, ktime_t edge) 215{ 216 ktime_t now, target = ktime_add_us(edge, length); 217 /* 218 * delta should never exceed 4 seconds and on m68k 219 * ndelay(s64) does not compile; so use s32 rather than s64. 220 */ 221 s32 delta; 222 unsigned int pulse, space; 223 224 /* Ensure the dividend fits into 32 bit */ 225 pulse = DIV_ROUND_CLOSEST(serial_ir.duty_cycle * (NSEC_PER_SEC / 100), 226 serial_ir.carrier); 227 space = DIV_ROUND_CLOSEST((100 - serial_ir.duty_cycle) * 228 (NSEC_PER_SEC / 100), serial_ir.carrier); 229 230 for (;;) { 231 now = ktime_get(); 232 if (ktime_compare(now, target) >= 0) 233 break; 234 on(); 235 edge = ktime_add_ns(edge, pulse); 236 delta = ktime_to_ns(ktime_sub(edge, now)); 237 if (delta > 0) 238 ndelay(delta); 239 now = ktime_get(); 240 off(); 241 if (ktime_compare(now, target) >= 0) 242 break; 243 edge = ktime_add_ns(edge, space); 244 delta = ktime_to_ns(ktime_sub(edge, now)); 245 if (delta > 0) 246 ndelay(delta); 247 } 248} 249 250static void send_pulse_homebrew(unsigned int length, ktime_t edge) 251{ 252 if (softcarrier) 253 send_pulse_homebrew_softcarrier(length, edge); 254 else 255 on(); 256} 257 258static void send_space_homebrew(void) 259{ 260 off(); 261} 262#endif 263 264static void frbwrite(unsigned int l, bool is_pulse) 265{ 266 /* simple noise filter */ 267 static unsigned int ptr, pulse, space; 268 struct ir_raw_event ev = {}; 269 270 if (ptr > 0 && is_pulse) { 271 pulse += l; 272 if (pulse > 250) { 273 ev.duration = space; 274 ev.pulse = false; 275 ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); 276 ev.duration = pulse; 277 ev.pulse = true; 278 ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); 279 ptr = 0; 280 pulse = 0; 281 } 282 return; 283 } 284 if (!is_pulse) { 285 if (ptr == 0) { 286 if (l > 20000) { 287 space = l; 288 ptr++; 289 return; 290 } 291 } else { 292 if (l > 20000) { 293 space += pulse; 294 if (space > IR_MAX_DURATION) 295 space = IR_MAX_DURATION; 296 space += l; 297 if (space > IR_MAX_DURATION) 298 space = IR_MAX_DURATION; 299 pulse = 0; 300 return; 301 } 302 303 ev.duration = space; 304 ev.pulse = false; 305 ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); 306 ev.duration = pulse; 307 ev.pulse = true; 308 ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); 309 ptr = 0; 310 pulse = 0; 311 } 312 } 313 314 ev.duration = l; 315 ev.pulse = is_pulse; 316 ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); 317} 318 319static irqreturn_t serial_ir_irq_handler(int i, void *blah) 320{ 321 ktime_t kt; 322 int counter, dcd; 323 u8 status; 324 ktime_t delkt; 325 unsigned int data; 326 static int last_dcd = -1; 327 328 if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { 329 /* not our interrupt */ 330 return IRQ_NONE; 331 } 332 333 counter = 0; 334 do { 335 counter++; 336 status = sinp(UART_MSR); 337 if (counter > RS_ISR_PASS_LIMIT) { 338 dev_err(&serial_ir.pdev->dev, "Trapped in interrupt"); 339 break; 340 } 341 if ((status & hardware[type].signal_pin_change) && 342 sense != -1) { 343 /* get current time */ 344 kt = ktime_get(); 345 346 /* 347 * The driver needs to know if your receiver is 348 * active high or active low, or the space/pulse 349 * sense could be inverted. 350 */ 351 352 /* calc time since last interrupt in nanoseconds */ 353 dcd = (status & hardware[type].signal_pin) ? 1 : 0; 354 355 if (dcd == last_dcd) { 356 dev_dbg(&serial_ir.pdev->dev, 357 "ignoring spike: %d %d %lldns %lldns\n", 358 dcd, sense, ktime_to_ns(kt), 359 ktime_to_ns(serial_ir.lastkt)); 360 continue; 361 } 362 363 delkt = ktime_sub(kt, serial_ir.lastkt); 364 if (ktime_compare(delkt, ktime_set(15, 0)) > 0) { 365 data = IR_MAX_DURATION; /* really long time */ 366 if (!(dcd ^ sense)) { 367 /* sanity check */ 368 dev_err(&serial_ir.pdev->dev, 369 "dcd unexpected: %d %d %lldns %lldns\n", 370 dcd, sense, ktime_to_ns(kt), 371 ktime_to_ns(serial_ir.lastkt)); 372 /* 373 * detecting pulse while this 374 * MUST be a space! 375 */ 376 sense = sense ? 0 : 1; 377 } 378 } else { 379 data = ktime_to_us(delkt); 380 } 381 frbwrite(data, !(dcd ^ sense)); 382 serial_ir.lastkt = kt; 383 last_dcd = dcd; 384 } 385 } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ 386 387 mod_timer(&serial_ir.timeout_timer, 388 jiffies + usecs_to_jiffies(serial_ir.rcdev->timeout)); 389 390 ir_raw_event_handle(serial_ir.rcdev); 391 392 return IRQ_HANDLED; 393} 394 395static int hardware_init_port(void) 396{ 397 u8 scratch, scratch2, scratch3; 398 399 /* 400 * This is a simple port existence test, borrowed from the autoconfig 401 * function in drivers/tty/serial/8250/8250_port.c 402 */ 403 scratch = sinp(UART_IER); 404 soutp(UART_IER, 0); 405#ifdef __i386__ 406 outb(0xff, 0x080); 407#endif 408 scratch2 = sinp(UART_IER) & 0x0f; 409 soutp(UART_IER, 0x0f); 410#ifdef __i386__ 411 outb(0x00, 0x080); 412#endif 413 scratch3 = sinp(UART_IER) & 0x0f; 414 soutp(UART_IER, scratch); 415 if (scratch2 != 0 || scratch3 != 0x0f) { 416 /* we fail, there's nothing here */ 417 pr_err("port existence test failed, cannot continue\n"); 418 return -ENODEV; 419 } 420 421 /* Set DLAB 0. */ 422 soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); 423 424 /* First of all, disable all interrupts */ 425 soutp(UART_IER, sinp(UART_IER) & 426 (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); 427 428 /* Clear registers. */ 429 sinp(UART_LSR); 430 sinp(UART_RX); 431 sinp(UART_IIR); 432 sinp(UART_MSR); 433 434 /* Set line for power source */ 435 off(); 436 437 /* Clear registers again to be sure. */ 438 sinp(UART_LSR); 439 sinp(UART_RX); 440 sinp(UART_IIR); 441 sinp(UART_MSR); 442 443 switch (type) { 444 case IR_IRDEO: 445 case IR_IRDEO_REMOTE: 446 /* setup port to 7N1 @ 115200 Baud */ 447 /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ 448 449 /* Set DLAB 1. */ 450 soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); 451 /* Set divisor to 1 => 115200 Baud */ 452 soutp(UART_DLM, 0); 453 soutp(UART_DLL, 1); 454 /* Set DLAB 0 + 7N1 */ 455 soutp(UART_LCR, UART_LCR_WLEN7); 456 /* THR interrupt already disabled at this point */ 457 break; 458 default: 459 break; 460 } 461 462 return 0; 463} 464 465static void serial_ir_timeout(struct timer_list *unused) 466{ 467 struct ir_raw_event ev = { 468 .timeout = true, 469 .duration = serial_ir.rcdev->timeout 470 }; 471 ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); 472 ir_raw_event_handle(serial_ir.rcdev); 473} 474 475/* Needed by serial_ir_probe() */ 476static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, 477 unsigned int count); 478static int serial_ir_tx_duty_cycle(struct rc_dev *dev, u32 cycle); 479static int serial_ir_tx_carrier(struct rc_dev *dev, u32 carrier); 480static int serial_ir_open(struct rc_dev *rcdev); 481static void serial_ir_close(struct rc_dev *rcdev); 482 483static int serial_ir_probe(struct platform_device *dev) 484{ 485 struct rc_dev *rcdev; 486 int i, nlow, nhigh, result; 487 488 rcdev = devm_rc_allocate_device(&dev->dev, RC_DRIVER_IR_RAW); 489 if (!rcdev) 490 return -ENOMEM; 491 492 if (hardware[type].send_pulse && hardware[type].send_space) 493 rcdev->tx_ir = serial_ir_tx; 494 if (hardware[type].set_send_carrier) 495 rcdev->s_tx_carrier = serial_ir_tx_carrier; 496 if (hardware[type].set_duty_cycle) 497 rcdev->s_tx_duty_cycle = serial_ir_tx_duty_cycle; 498 499 switch (type) { 500 case IR_HOMEBREW: 501 rcdev->device_name = "Serial IR type home-brew"; 502 break; 503 case IR_IRDEO: 504 rcdev->device_name = "Serial IR type IRdeo"; 505 break; 506 case IR_IRDEO_REMOTE: 507 rcdev->device_name = "Serial IR type IRdeo remote"; 508 break; 509 case IR_ANIMAX: 510 rcdev->device_name = "Serial IR type AnimaX"; 511 break; 512 case IR_IGOR: 513 rcdev->device_name = "Serial IR type IgorPlug"; 514 break; 515 } 516 517 rcdev->input_phys = KBUILD_MODNAME "/input0"; 518 rcdev->input_id.bustype = BUS_HOST; 519 rcdev->input_id.vendor = 0x0001; 520 rcdev->input_id.product = 0x0001; 521 rcdev->input_id.version = 0x0100; 522 rcdev->open = serial_ir_open; 523 rcdev->close = serial_ir_close; 524 rcdev->dev.parent = &serial_ir.pdev->dev; 525 rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; 526 rcdev->driver_name = KBUILD_MODNAME; 527 rcdev->map_name = RC_MAP_RC6_MCE; 528 rcdev->min_timeout = 1; 529 rcdev->timeout = IR_DEFAULT_TIMEOUT; 530 rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; 531 rcdev->rx_resolution = 250; 532 533 serial_ir.rcdev = rcdev; 534 535 timer_setup(&serial_ir.timeout_timer, serial_ir_timeout, 0); 536 537 result = devm_request_irq(&dev->dev, irq, serial_ir_irq_handler, 538 share_irq ? IRQF_SHARED : 0, 539 KBUILD_MODNAME, &hardware); 540 if (result < 0) { 541 if (result == -EBUSY) 542 dev_err(&dev->dev, "IRQ %d busy\n", irq); 543 else if (result == -EINVAL) 544 dev_err(&dev->dev, "Bad irq number or handler\n"); 545 return result; 546 } 547 548 /* Reserve io region. */ 549 if ((iommap && 550 (devm_request_mem_region(&dev->dev, iommap, 8UL << ioshift, 551 KBUILD_MODNAME) == NULL)) || 552 (!iommap && (devm_request_region(&dev->dev, io, 8, 553 KBUILD_MODNAME) == NULL))) { 554 dev_err(&dev->dev, "port %04x already in use\n", io); 555 dev_warn(&dev->dev, "use 'setserial /dev/ttySX uart none'\n"); 556 dev_warn(&dev->dev, 557 "or compile the serial port driver as module and\n"); 558 dev_warn(&dev->dev, "make sure this module is loaded first\n"); 559 return -EBUSY; 560 } 561 562 result = hardware_init_port(); 563 if (result < 0) 564 return result; 565 566 /* Initialize pulse/space widths */ 567 serial_ir.duty_cycle = 50; 568 serial_ir.carrier = 38000; 569 570 /* If pin is high, then this must be an active low receiver. */ 571 if (sense == -1) { 572 /* wait 1/2 sec for the power supply */ 573 msleep(500); 574 575 /* 576 * probe 9 times every 0.04s, collect "votes" for 577 * active high/low 578 */ 579 nlow = 0; 580 nhigh = 0; 581 for (i = 0; i < 9; i++) { 582 if (sinp(UART_MSR) & hardware[type].signal_pin) 583 nlow++; 584 else 585 nhigh++; 586 msleep(40); 587 } 588 sense = nlow >= nhigh ? 1 : 0; 589 dev_info(&dev->dev, "auto-detected active %s receiver\n", 590 sense ? "low" : "high"); 591 } else 592 dev_info(&dev->dev, "Manually using active %s receiver\n", 593 sense ? "low" : "high"); 594 595 dev_dbg(&dev->dev, "Interrupt %d, port %04x obtained\n", irq, io); 596 597 return devm_rc_register_device(&dev->dev, rcdev); 598} 599 600static int serial_ir_open(struct rc_dev *rcdev) 601{ 602 unsigned long flags; 603 604 /* initialize timestamp */ 605 serial_ir.lastkt = ktime_get(); 606 607 spin_lock_irqsave(&hardware[type].lock, flags); 608 609 /* Set DLAB 0. */ 610 soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); 611 612 soutp(UART_IER, sinp(UART_IER) | UART_IER_MSI); 613 614 spin_unlock_irqrestore(&hardware[type].lock, flags); 615 616 return 0; 617} 618 619static void serial_ir_close(struct rc_dev *rcdev) 620{ 621 unsigned long flags; 622 623 spin_lock_irqsave(&hardware[type].lock, flags); 624 625 /* Set DLAB 0. */ 626 soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); 627 628 /* First of all, disable all interrupts */ 629 soutp(UART_IER, sinp(UART_IER) & 630 (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); 631 spin_unlock_irqrestore(&hardware[type].lock, flags); 632} 633 634static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, 635 unsigned int count) 636{ 637 unsigned long flags; 638 ktime_t edge; 639 s64 delta; 640 int i; 641 642 spin_lock_irqsave(&hardware[type].lock, flags); 643 if (type == IR_IRDEO) { 644 /* DTR, RTS down */ 645 on(); 646 } 647 648 edge = ktime_get(); 649 for (i = 0; i < count; i++) { 650 if (i % 2) 651 hardware[type].send_space(); 652 else 653 hardware[type].send_pulse(txbuf[i], edge); 654 655 edge = ktime_add_us(edge, txbuf[i]); 656 delta = ktime_us_delta(edge, ktime_get()); 657 if (delta > 25) { 658 spin_unlock_irqrestore(&hardware[type].lock, flags); 659 usleep_range(delta - 25, delta + 25); 660 spin_lock_irqsave(&hardware[type].lock, flags); 661 } else if (delta > 0) { 662 udelay(delta); 663 } 664 } 665 off(); 666 spin_unlock_irqrestore(&hardware[type].lock, flags); 667 return count; 668} 669 670static int serial_ir_tx_duty_cycle(struct rc_dev *dev, u32 cycle) 671{ 672 serial_ir.duty_cycle = cycle; 673 return 0; 674} 675 676static int serial_ir_tx_carrier(struct rc_dev *dev, u32 carrier) 677{ 678 if (carrier > 500000 || carrier < 20000) 679 return -EINVAL; 680 681 serial_ir.carrier = carrier; 682 return 0; 683} 684 685static int serial_ir_suspend(struct platform_device *dev, 686 pm_message_t state) 687{ 688 /* Set DLAB 0. */ 689 soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); 690 691 /* Disable all interrupts */ 692 soutp(UART_IER, sinp(UART_IER) & 693 (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); 694 695 /* Clear registers. */ 696 sinp(UART_LSR); 697 sinp(UART_RX); 698 sinp(UART_IIR); 699 sinp(UART_MSR); 700 701 return 0; 702} 703 704static int serial_ir_resume(struct platform_device *dev) 705{ 706 unsigned long flags; 707 int result; 708 709 result = hardware_init_port(); 710 if (result < 0) 711 return result; 712 713 spin_lock_irqsave(&hardware[type].lock, flags); 714 /* Enable Interrupt */ 715 serial_ir.lastkt = ktime_get(); 716 soutp(UART_IER, sinp(UART_IER) | UART_IER_MSI); 717 off(); 718 719 spin_unlock_irqrestore(&hardware[type].lock, flags); 720 721 return 0; 722} 723 724static struct platform_driver serial_ir_driver = { 725 .probe = serial_ir_probe, 726 .suspend = serial_ir_suspend, 727 .resume = serial_ir_resume, 728 .driver = { 729 .name = "serial_ir", 730 }, 731}; 732 733static int __init serial_ir_init(void) 734{ 735 int result; 736 737 result = platform_driver_register(&serial_ir_driver); 738 if (result) 739 return result; 740 741 serial_ir.pdev = platform_device_alloc("serial_ir", 0); 742 if (!serial_ir.pdev) { 743 result = -ENOMEM; 744 goto exit_driver_unregister; 745 } 746 747 result = platform_device_add(serial_ir.pdev); 748 if (result) 749 goto exit_device_put; 750 751 return 0; 752 753exit_device_put: 754 platform_device_put(serial_ir.pdev); 755exit_driver_unregister: 756 platform_driver_unregister(&serial_ir_driver); 757 return result; 758} 759 760static void serial_ir_exit(void) 761{ 762 platform_device_unregister(serial_ir.pdev); 763 platform_driver_unregister(&serial_ir_driver); 764} 765 766static int __init serial_ir_init_module(void) 767{ 768 switch (type) { 769 case IR_HOMEBREW: 770 case IR_IRDEO: 771 case IR_IRDEO_REMOTE: 772 case IR_ANIMAX: 773 case IR_IGOR: 774 /* if nothing specified, use ttyS0/com1 and irq 4 */ 775 io = io ? io : 0x3f8; 776 irq = irq ? irq : 4; 777 break; 778 default: 779 return -EINVAL; 780 } 781 if (!softcarrier) { 782 switch (type) { 783 case IR_HOMEBREW: 784 case IR_IGOR: 785 hardware[type].set_send_carrier = false; 786 hardware[type].set_duty_cycle = false; 787 break; 788 } 789 } 790 791 /* make sure sense is either -1, 0, or 1 */ 792 if (sense != -1) 793 sense = !!sense; 794 795 return serial_ir_init(); 796} 797 798static void __exit serial_ir_exit_module(void) 799{ 800 del_timer_sync(&serial_ir.timeout_timer); 801 serial_ir_exit(); 802} 803 804module_init(serial_ir_init_module); 805module_exit(serial_ir_exit_module); 806 807MODULE_DESCRIPTION("Infra-red receiver driver for serial ports."); 808MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, Christoph Bartelmus, Andrei Tanas"); 809MODULE_LICENSE("GPL"); 810 811module_param(type, int, 0444); 812MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo, 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug"); 813 814module_param_hw(io, int, ioport, 0444); 815MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); 816 817/* some architectures (e.g. intel xscale) have memory mapped registers */ 818module_param_hw(iommap, ulong, other, 0444); 819MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O (0 = no memory mapped io)"); 820 821/* 822 * some architectures (e.g. intel xscale) align the 8bit serial registers 823 * on 32bit word boundaries. 824 * See linux-kernel/drivers/tty/serial/8250/8250.c serial_in()/out() 825 */ 826module_param_hw(ioshift, int, other, 0444); 827MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)"); 828 829module_param_hw(irq, int, irq, 0444); 830MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); 831 832module_param_hw(share_irq, bool, other, 0444); 833MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)"); 834 835module_param(sense, int, 0444); 836MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit (0 = active high, 1 = active low )"); 837 838#ifdef CONFIG_IR_SERIAL_TRANSMITTER 839module_param(txsense, bool, 0444); 840MODULE_PARM_DESC(txsense, "Sense of transmitter circuit (0 = active high, 1 = active low )"); 841#endif 842 843module_param(softcarrier, bool, 0444); 844MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");