linux/drivers/media/pci/smipcie/smipcie-ir.c
<<
>>
Prefs
   1/*
   2 * SMI PCIe driver for DVBSky cards.
   3 *
   4 * Copyright (C) 2014 Max nibble <nibble.max@gmail.com>
   5 *
   6 *    This program is free software; you can redistribute it and/or modify
   7 *    it under the terms of the GNU General Public License as published by
   8 *    the Free Software Foundation; either version 2 of the License, or
   9 *    (at your option) any later version.
  10 *
  11 *    This program is distributed in the hope that it will be useful,
  12 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *    GNU General Public License for more details.
  15 */
  16
  17#include "smipcie.h"
  18
  19static void smi_ir_enableInterrupt(struct smi_rc *ir)
  20{
  21        struct smi_dev *dev = ir->dev;
  22
  23        smi_write(MSI_INT_ENA_SET, IR_X_INT);
  24}
  25
  26static void smi_ir_disableInterrupt(struct smi_rc *ir)
  27{
  28        struct smi_dev *dev = ir->dev;
  29
  30        smi_write(MSI_INT_ENA_CLR, IR_X_INT);
  31}
  32
  33static void smi_ir_clearInterrupt(struct smi_rc *ir)
  34{
  35        struct smi_dev *dev = ir->dev;
  36
  37        smi_write(MSI_INT_STATUS_CLR, IR_X_INT);
  38}
  39
  40static void smi_ir_stop(struct smi_rc *ir)
  41{
  42        struct smi_dev *dev = ir->dev;
  43
  44        smi_ir_disableInterrupt(ir);
  45        smi_clear(IR_Init_Reg, 0x80);
  46}
  47
  48#define BITS_PER_COMMAND 14
  49#define GROUPS_PER_BIT 2
  50#define IR_RC5_MIN_BIT 36
  51#define IR_RC5_MAX_BIT 52
  52static u32 smi_decode_rc5(u8 *pData, u8 size)
  53{
  54        u8 index, current_bit, bit_count;
  55        u8 group_array[BITS_PER_COMMAND * GROUPS_PER_BIT + 4];
  56        u8 group_index = 0;
  57        u32 command = 0xFFFFFFFF;
  58
  59        group_array[group_index++] = 1;
  60
  61        for (index = 0; index < size; index++) {
  62
  63                current_bit = (pData[index] & 0x80) ? 1 : 0;
  64                bit_count = pData[index] & 0x7f;
  65
  66                if ((current_bit == 1) && (bit_count >= 2*IR_RC5_MAX_BIT + 1)) {
  67                        goto process_code;
  68                } else if ((bit_count >= IR_RC5_MIN_BIT) &&
  69                           (bit_count <= IR_RC5_MAX_BIT)) {
  70                                group_array[group_index++] = current_bit;
  71                } else if ((bit_count > IR_RC5_MAX_BIT) &&
  72                           (bit_count <= 2*IR_RC5_MAX_BIT)) {
  73                                group_array[group_index++] = current_bit;
  74                                group_array[group_index++] = current_bit;
  75                } else {
  76                        goto invalid_timing;
  77                }
  78                if (group_index >= BITS_PER_COMMAND*GROUPS_PER_BIT)
  79                        goto process_code;
  80
  81                if ((group_index == BITS_PER_COMMAND*GROUPS_PER_BIT - 1)
  82                    && (group_array[group_index-1] == 0)) {
  83                        group_array[group_index++] = 1;
  84                        goto process_code;
  85                }
  86        }
  87
  88process_code:
  89        if (group_index == (BITS_PER_COMMAND*GROUPS_PER_BIT-1))
  90                group_array[group_index++] = 1;
  91
  92        if (group_index == BITS_PER_COMMAND*GROUPS_PER_BIT) {
  93                command = 0;
  94                for (index = 0; index < (BITS_PER_COMMAND*GROUPS_PER_BIT);
  95                     index = index + 2) {
  96                        if ((group_array[index] == 1) &&
  97                            (group_array[index+1] == 0)) {
  98                                command |= (1 << (BITS_PER_COMMAND -
  99                                                   (index/2) - 1));
 100                        } else if ((group_array[index] == 0) &&
 101                                   (group_array[index+1] == 1)) {
 102                                /* */
 103                        } else {
 104                                command = 0xFFFFFFFF;
 105                                goto invalid_timing;
 106                        }
 107                }
 108        }
 109
 110invalid_timing:
 111        return command;
 112}
 113
 114static void smi_ir_decode(struct work_struct *work)
 115{
 116        struct smi_rc *ir = container_of(work, struct smi_rc, work);
 117        struct smi_dev *dev = ir->dev;
 118        struct rc_dev *rc_dev = ir->rc_dev;
 119        u32 dwIRControl, dwIRData, dwIRCode, scancode;
 120        u8 index, ucIRCount, readLoop, rc5_command, rc5_system, toggle;
 121
 122        dwIRControl = smi_read(IR_Init_Reg);
 123        if (dwIRControl & rbIRVld) {
 124                ucIRCount = (u8) smi_read(IR_Data_Cnt);
 125
 126                if (ucIRCount < 4)
 127                        goto end_ir_decode;
 128
 129                readLoop = ucIRCount/4;
 130                if (ucIRCount % 4)
 131                        readLoop += 1;
 132                for (index = 0; index < readLoop; index++) {
 133                        dwIRData = smi_read(IR_DATA_BUFFER_BASE + (index*4));
 134
 135                        ir->irData[index*4 + 0] = (u8)(dwIRData);
 136                        ir->irData[index*4 + 1] = (u8)(dwIRData >> 8);
 137                        ir->irData[index*4 + 2] = (u8)(dwIRData >> 16);
 138                        ir->irData[index*4 + 3] = (u8)(dwIRData >> 24);
 139                }
 140                dwIRCode = smi_decode_rc5(ir->irData, ucIRCount);
 141
 142                if (dwIRCode != 0xFFFFFFFF) {
 143                        rc5_command = dwIRCode & 0x3F;
 144                        rc5_system = (dwIRCode & 0x7C0) >> 6;
 145                        toggle = (dwIRCode & 0x800) ? 1 : 0;
 146                        scancode = rc5_system << 8 | rc5_command;
 147                        rc_keydown(rc_dev, RC_PROTO_RC5, scancode, toggle);
 148                }
 149        }
 150end_ir_decode:
 151        smi_set(IR_Init_Reg, 0x04);
 152        smi_ir_enableInterrupt(ir);
 153}
 154
 155/* ir functions call by main driver.*/
 156int smi_ir_irq(struct smi_rc *ir, u32 int_status)
 157{
 158        int handled = 0;
 159
 160        if (int_status & IR_X_INT) {
 161                smi_ir_disableInterrupt(ir);
 162                smi_ir_clearInterrupt(ir);
 163                schedule_work(&ir->work);
 164                handled = 1;
 165        }
 166        return handled;
 167}
 168
 169void smi_ir_start(struct smi_rc *ir)
 170{
 171        struct smi_dev *dev = ir->dev;
 172
 173        smi_write(IR_Idle_Cnt_Low, 0x00140070);
 174        msleep(20);
 175        smi_set(IR_Init_Reg, 0x90);
 176
 177        smi_ir_enableInterrupt(ir);
 178}
 179
 180int smi_ir_init(struct smi_dev *dev)
 181{
 182        int ret;
 183        struct rc_dev *rc_dev;
 184        struct smi_rc *ir = &dev->ir;
 185
 186        rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
 187        if (!rc_dev)
 188                return -ENOMEM;
 189
 190        /* init input device */
 191        snprintf(ir->device_name, sizeof(ir->device_name), "IR (%s)",
 192                 dev->info->name);
 193        snprintf(ir->input_phys, sizeof(ir->input_phys), "pci-%s/ir0",
 194                 pci_name(dev->pci_dev));
 195
 196        rc_dev->driver_name = "SMI_PCIe";
 197        rc_dev->input_phys = ir->input_phys;
 198        rc_dev->device_name = ir->device_name;
 199        rc_dev->input_id.bustype = BUS_PCI;
 200        rc_dev->input_id.version = 1;
 201        rc_dev->input_id.vendor = dev->pci_dev->subsystem_vendor;
 202        rc_dev->input_id.product = dev->pci_dev->subsystem_device;
 203        rc_dev->dev.parent = &dev->pci_dev->dev;
 204
 205        rc_dev->map_name = dev->info->rc_map;
 206
 207        ir->rc_dev = rc_dev;
 208        ir->dev = dev;
 209
 210        INIT_WORK(&ir->work, smi_ir_decode);
 211        smi_ir_disableInterrupt(ir);
 212
 213        ret = rc_register_device(rc_dev);
 214        if (ret)
 215                goto ir_err;
 216
 217        return 0;
 218ir_err:
 219        rc_free_device(rc_dev);
 220        return ret;
 221}
 222
 223void smi_ir_exit(struct smi_dev *dev)
 224{
 225        struct smi_rc *ir = &dev->ir;
 226        struct rc_dev *rc_dev = ir->rc_dev;
 227
 228        smi_ir_stop(ir);
 229        rc_unregister_device(rc_dev);
 230        ir->rc_dev = NULL;
 231}
 232