root/drivers/media/pci/ttpci/av7110_ir.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. av7110_ir_handler
  2. av7110_set_ir_config
  3. change_protocol
  4. av7110_ir_init
  5. av7110_ir_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Driver for the remote control of SAA7146 based AV7110 cards
   4  *
   5  * Copyright (C) 1999-2003 Holger Waechtler <holger@convergence.de>
   6  * Copyright (C) 2003-2007 Oliver Endriss <o.endriss@gmx.de>
   7  * Copyright (C) 2019 Sean Young <sean@mess.org>
   8  */
   9 
  10 #include <linux/kernel.h>
  11 #include <media/rc-core.h>
  12 
  13 #include "av7110.h"
  14 #include "av7110_hw.h"
  15 
  16 #define IR_RC5          0
  17 #define IR_RCMM         1
  18 #define IR_RC5_EXT      2 /* internal only */
  19 
  20 /* interrupt handler */
  21 void av7110_ir_handler(struct av7110 *av7110, u32 ircom)
  22 {
  23         struct rc_dev *rcdev = av7110->ir.rcdev;
  24         enum rc_proto proto;
  25         u32 command, addr, scancode;
  26         u32 toggle;
  27 
  28         dprintk(4, "ir command = %08x\n", ircom);
  29 
  30         if (rcdev) {
  31                 switch (av7110->ir.ir_config) {
  32                 case IR_RC5: /* RC5: 5 bits device address, 6 bits command */
  33                         command = ircom & 0x3f;
  34                         addr = (ircom >> 6) & 0x1f;
  35                         scancode = RC_SCANCODE_RC5(addr, command);
  36                         toggle = ircom & 0x0800;
  37                         proto = RC_PROTO_RC5;
  38                         break;
  39 
  40                 case IR_RCMM: /* RCMM: 32 bits scancode */
  41                         scancode = ircom & ~0x8000;
  42                         toggle = ircom & 0x8000;
  43                         proto = RC_PROTO_RCMM32;
  44                         break;
  45 
  46                 case IR_RC5_EXT:
  47                         /*
  48                          * extended RC5: 5 bits device address, 7 bits command
  49                          *
  50                          * Extended RC5 uses only one start bit. The second
  51                          * start bit is re-assigned bit 6 of the command bit.
  52                          */
  53                         command = ircom & 0x3f;
  54                         addr = (ircom >> 6) & 0x1f;
  55                         if (!(ircom & 0x1000))
  56                                 command |= 0x40;
  57                         scancode = RC_SCANCODE_RC5(addr, command);
  58                         toggle = ircom & 0x0800;
  59                         proto = RC_PROTO_RC5;
  60                         break;
  61                 default:
  62                         dprintk(2, "unknown ir config %d\n",
  63                                 av7110->ir.ir_config);
  64                         return;
  65                 }
  66 
  67                 rc_keydown(rcdev, proto, scancode, toggle != 0);
  68         }
  69 }
  70 
  71 int av7110_set_ir_config(struct av7110 *av7110)
  72 {
  73         dprintk(4, "ir config = %08x\n", av7110->ir.ir_config);
  74 
  75         return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1,
  76                              av7110->ir.ir_config);
  77 }
  78 
  79 static int change_protocol(struct rc_dev *rcdev, u64 *rc_type)
  80 {
  81         struct av7110 *av7110 = rcdev->priv;
  82         u32 ir_config;
  83 
  84         if (*rc_type & RC_PROTO_BIT_RCMM32) {
  85                 ir_config = IR_RCMM;
  86                 *rc_type = RC_PROTO_BIT_RCMM32;
  87         } else if (*rc_type & RC_PROTO_BIT_RC5) {
  88                 if (FW_VERSION(av7110->arm_app) >= 0x2620)
  89                         ir_config = IR_RC5_EXT;
  90                 else
  91                         ir_config = IR_RC5;
  92                 *rc_type = RC_PROTO_BIT_RC5;
  93         } else {
  94                 return -EINVAL;
  95         }
  96 
  97         if (ir_config == av7110->ir.ir_config)
  98                 return 0;
  99 
 100         av7110->ir.ir_config = ir_config;
 101 
 102         return av7110_set_ir_config(av7110);
 103 }
 104 
 105 int av7110_ir_init(struct av7110 *av7110)
 106 {
 107         struct rc_dev *rcdev;
 108         struct pci_dev *pci;
 109         int ret;
 110 
 111         rcdev = rc_allocate_device(RC_DRIVER_SCANCODE);
 112         if (!rcdev)
 113                 return -ENOMEM;
 114 
 115         pci = av7110->dev->pci;
 116 
 117         snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys),
 118                  "pci-%s/ir0", pci_name(pci));
 119 
 120         rcdev->device_name = av7110->card_name;
 121         rcdev->driver_name = KBUILD_MODNAME;
 122         rcdev->input_phys = av7110->ir.input_phys;
 123         rcdev->input_id.bustype = BUS_PCI;
 124         rcdev->input_id.version = 2;
 125         if (pci->subsystem_vendor) {
 126                 rcdev->input_id.vendor  = pci->subsystem_vendor;
 127                 rcdev->input_id.product = pci->subsystem_device;
 128         } else {
 129                 rcdev->input_id.vendor  = pci->vendor;
 130                 rcdev->input_id.product = pci->device;
 131         }
 132 
 133         rcdev->dev.parent = &pci->dev;
 134         rcdev->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RCMM32;
 135         rcdev->change_protocol = change_protocol;
 136         rcdev->map_name = RC_MAP_HAUPPAUGE;
 137         rcdev->priv = av7110;
 138 
 139         av7110->ir.rcdev = rcdev;
 140         av7110->ir.ir_config = IR_RC5;
 141         av7110_set_ir_config(av7110);
 142 
 143         ret = rc_register_device(rcdev);
 144         if (ret) {
 145                 av7110->ir.rcdev = NULL;
 146                 rc_free_device(rcdev);
 147         }
 148 
 149         return ret;
 150 }
 151 
 152 void av7110_ir_exit(struct av7110 *av7110)
 153 {
 154         rc_unregister_device(av7110->ir.rcdev);
 155 }
 156 
 157 //MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>");
 158 //MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */