Commit 017a079d authored by 吴智聪John's avatar 吴智聪John

Import and convert IR driver from OSD1 tree

parent 857d0ea3
......@@ -676,7 +676,8 @@ CONFIG_KEYBOARD_XTKBD=y
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
CONFIG_INPUT_MISC=y
CONFIG_INPUT_NEUROS_IR=m
#
# Hardware I/O ports
......@@ -763,6 +764,7 @@ CONFIG_GPIOEXPANDER_DAVINCI=y
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
CONFIG_I2C_NEUROS_MSP430=m
#
# SPI support
......
......@@ -183,4 +183,17 @@ config HP_SDC_RTC
Say Y here if you want to support the built-in real time clock
of the HP SDC controller.
config INPUT_NEUROS_IR
tristate "Neuros IR driver"
depends on ARCH_DAVINCI
help
This option enables the Neuros IR driver.
FIXME: This needs a better description.
To compile this driver as a module (recommended), choose M here: the
module will be called neuros_ir.
If unsure and targeting the Neuros OSD, say M.
endif
......@@ -18,3 +18,4 @@ obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_NEUROS_IR) += neuros_ir.o
/*
* Copyright(C) 2006-2007 Neuros Technology International LLC.
* <www.neurostechnology.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* This program is distributed in the hope that, in addition to its
* original purpose to support Neuros hardware, it will be useful
* otherwise, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
****************************************************************************
*
* IR Receiver driver.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/jiffies.h>
#include <linux/poll.h>
#include <linux/input.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch/hardware.h>
#include <linux/neuros_ir.h>
#include <linux/neuros_ir_blaster.h>
#include "neuros_keymaps.h"
#define MOD_DESC "Neuros IR Driver (c) 2008"
#if 0
#define dbg(fmt, arg...) \
printk(KERN_INFO "%s:%d> " fmt, __func__, __LINE__ , ## arg)
#else
#define dbg(fmt, arg...)
#endif
#define GPIO01_DIR __REG(0x01C67010)
#define GPIO01_RIS_INT __REG(0x01C67024)
#define USE_WORKQUEUE 1
#define READ_ONLY_ONE_KEY 1
#define IR_RETRY_COUNT 3
#define FACTORY_TEST_DELAY 6
struct irrtc_device {
int key;
};
static struct irrtc_device device;
static wait_queue_head_t wait;
static wait_queue_head_t poll_queue;
static char *devname = "neuros_ir";
static struct input_dev *ir_input_dev;
static int factory_test=0;
static int osd_key=0;
static int is_learning=0;
#if USE_WORKQUEUE
#define KEYBUF_SIZE 2
static int keybuf[KEYBUF_SIZE];
static int roffset=0;
static int woffset=0;
static int numOfKeys=0;
#else
static int keyin=0;
#endif
static void irrtc_report_key(int ir_key);
DECLARE_MUTEX(keybuf_sem);
static spinlock_t data_protect = SPIN_LOCK_UNLOCKED;
static void lock_data_protect(void)
{
spin_lock(&data_protect);
}
EXPORT_SYMBOL(lock_data_protect);
static void unlock_data_protect(void)
{
spin_unlock(&data_protect);
}
EXPORT_SYMBOL(unlock_data_protect);
static void set_factory_test(int value)
{
factory_test=value;
}
EXPORT_SYMBOL(set_factory_test);
static int get_osd_key(void)
{
return osd_key;
}
EXPORT_SYMBOL(get_osd_key);
static void set_osd_key(int value)
{
osd_key=value;
}
EXPORT_SYMBOL(set_osd_key);
static void set_is_learning(int value)
{
is_learning=value;
}
EXPORT_SYMBOL(set_is_learning);
static int read_keybuf(void)
{
int key = -1;//none key
if (-EINTR == down_interruptible(&keybuf_sem))
return -1;
dbg("numOfKeys = %d", numOfKeys);
if (numOfKeys > 0)
{
numOfKeys--;
key = keybuf[roffset];
if(++roffset >= KEYBUF_SIZE) roffset = 0;
}
up(&keybuf_sem);
return key;
}
#if USE_WORKQUEUE
static void write_keybuf(int key)
{
if (-EINTR == down_interruptible(&keybuf_sem))
return;
// Display some more sober debug message on key presses but don't bother with key releases.
if (key != 0x00) printk("{IR:key:%02x}\n", key);
if(++numOfKeys > KEYBUF_SIZE)
{
numOfKeys = KEYBUF_SIZE;
if(++roffset >= KEYBUF_SIZE) roffset = 0;
}
keybuf[woffset]=key;
if(++woffset >= KEYBUF_SIZE) woffset = 0;
up(&keybuf_sem);
}
#endif
static void report_key(int key)
{
irrtc_report_key(key); //before adding to keybuf we report this key to the input system
write_keybuf(key);
wake_up_interruptible(&poll_queue);
}
EXPORT_SYMBOL(report_key);
//----------------------------------------------------------- INTERRUPTS -------------------------------------------------------
#if USE_WORKQUEUE
static void irrtc_do_wq(struct work_struct *work)
{
int key;
int retry = IR_RETRY_COUNT;
if (is_learning == 1)
{
//disable_irq(IRQ_TIMER1);
//outw( inw( IO_GIO_IRQPORT) & (~GIO3), IO_GIO_IRQPORT); // gio 3 external IRQ disable;
lock_data_protect();
set_osd_key(1);
set_is_learning(0);
unlock_data_protect();
}
//HACK: we KNOW that key should never become 0xFF!!
do
{
key = KEY_MASK & i2c_read(regIR);
} while ((key == NULL_KEY) && (retry--));
dbg("do tasklet: key = [%x]\n", key);
if (key <= TEST_KEY && key >= UP_KEY)
{
report_key(key);
}
}
DECLARE_WORK(irrtc_wq, irrtc_do_wq);
DECLARE_DELAYED_WORK(irrtc_delay_wq, irrtc_do_wq);
#endif
static irqreturn_t handle_irrtc_irqs(int irq, void * dev_id)
{
#if USE_WORKQUEUE
if (!factory_test)
schedule_work(&irrtc_wq);
else
{
schedule_delayed_work(&irrtc_delay_wq,FACTORY_TEST_DELAY);
set_factory_test(0);
}
#else
keyin=1;
#endif
return IRQ_HANDLED;
}
static void irqs_irrtc_init( void )
{
GPIO01_DIR |= 0x04; //gio 2 direction input
GPIO01_RIS_INT |= 0x04; // gio 2 rising edge IRQ enable
//outw( inw( IO_GIO_DIR0 ) | 0x0001, IO_GIO_DIR0 ); //gio 0 direction input
//outw( inw( IO_GIO_INV0 ) | 0x0001, IO_GIO_INV0 ); //gio 0 inv
//outw( inw( IO_GIO_IRQPORT) | 0x0001, IO_GIO_IRQPORT); // gio 0 external IRQ enable
request_irq(IRQ_GPIO2, handle_irrtc_irqs, 0, "irrtc", &device);
}
static void irqs_irrtc_exit( void )
{
free_irq(IRQ_GPIO2, &device);
}
// ---------------------------------------------------------- DEVICE -----------------------------------------------------------
static int irrtc_open(struct inode * inode, struct file * file)
{
#ifdef ONLYOPENONE
if (opened)
return -EBUSY;
opened = 1;
#endif
return 0;
}
static int irrtc_release(struct inode * inode, struct file * file)
{
#ifdef ONLYOPENONE
if (!opened)
return -ERESTARTSYS;
opened = 0;
#endif
return 0;
}
static ssize_t irrtc_read(struct file *filp, char __user *buff, size_t count, loff_t *ppos)
{
#if READ_ONLY_ONE_KEY
int key,r;
key = read_keybuf();
dbg("key=%d\n", key);
if (key!=-1) //none key
r=copy_to_user(buff, &key, sizeof(int));
else
count=0;
#else
if (-EINTR == down_interruptible(&keybuf_sem))
return 0;
if (count > KEYBUF_SIZE * sizeof(int)) {
if (roffset <= woffset)
count = (woffset - roffset) * sizeof(int);
else
count = (KEYBUF_SIZE - (roffset - woffset + 1)) * sizeof(int);
}
if (count == 0) {
printk("buffer empty\n");
goto out;
}
if (roffset < woffset)
r=copy_to_user(buff, keybuf + roffset, count);
else {
r=copy_to_user(buff, &keybuf[roffset], (KEYBUF_SIZE - roffset + 1) * sizeof(int));
r=copy_to_user(buff + (KEYBUF_SIZE - roffset + 1) * sizeof(int), keybuf, woffset * sizeof(int));
}
out:
up(&keybuf_sem);
#endif
return count;
}
static ssize_t irrtc_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos)
{
int key;
if (copy_from_user(&key, buf, sizeof(int)))
return -1;
//printk("-----------------%x\n",key);
report_key(key);
return count;
}
static unsigned int irrtc_poll(struct file*filp, poll_table*wait)
{
unsigned int mask = 0;
poll_wait(filp, &poll_queue, wait);
if (numOfKeys)
mask |= POLLIN | POLLRDNORM;
return mask;
}
static struct file_operations irrtc_fops = {
.open = irrtc_open,
.release = irrtc_release,
.read = irrtc_read,
.poll = irrtc_poll,
.write = irrtc_write,
};
// setup all input device information and actually create the device
static void irrtc_inputdev_init(void)
{
int i;
ir_input_dev = input_allocate_device();
ir_input_dev->name = devname;
ir_input_dev->evbit[0] = BIT(EV_KEY); //this is the type of events we will generate. only keys.
// set a bit in the input device structure for each key that we are able to generate.
for (i = 0; i < NUM_KEYS; i++)
if (keymap[i] != 0)
set_bit(keymap[i], ir_input_dev->keybit);
input_register_device(ir_input_dev); //done. we can now send events into the system.
}
// close the input device
static void irrtc_inputdev_close(void)
{
input_unregister_device(ir_input_dev);
}
// gets an IR key code and reports it to the input system
static void irrtc_report_key(int key)
{
int code;
// Repeat keypresses on IR remote have different codes, but we treat all them as normal key
// presses by clearing away the modifiers.
//if ((key & 0x80) == 0x80) key ^= 0x80; //START_REPEAT_MOD
//if ((key & 0x40) == 0x40) key ^= 0x40; //REPEAT_MOD
// Map the code to one of the standard keboard codes accepted by the input system.
// todo: allow keymap switching via ioctl (maybe custom remapping too)
code = (key > NUM_KEYS) ? 0 : keymap[key];
if (code == 0) code = KEY_UNKNOWN;
// Report a full key press + release for each even received from IR. I see no other way to do this
// until MSP430 can send us properly flagged "key release" codes.
input_report_key(ir_input_dev, code, 1);
input_report_key(ir_input_dev, code, 0);
}
//-------------------------------------------------- INIT / EXIT ----------------------------------------------------------
static const char * pname = "NEUROS_IR(KM):";
static int __init irrtc_init(void)
{
int status = 0;
init_waitqueue_head (&wait);
init_waitqueue_head (&poll_queue);
printk(KERN_INFO "\t" MOD_DESC "\n");
status = register_chrdev(NEUROS_IR_MAJOR, "neuros_ir", &irrtc_fops);
if (status != 0)
{
if (status == -EINVAL) printk(KERN_ERR "%s Couldn't register device: invalid major number %d.\n", pname, NEUROS_IR_MAJOR);
else if (status == -EBUSY) printk(KERN_ERR "%s Couldn't register device: major number %d already busy.\n", pname, NEUROS_IR_MAJOR);
else printk(KERN_ERR "%s Couldn't register device: error %d.\n", pname, status);
status = -1;
goto out;
}
irrtc_inputdev_init();
memset(keybuf,-1,sizeof(keybuf)); //init keybuf to none key
//proc_irrtc_init(); //PROC:
irqs_irrtc_init();
out:
return status;
}
static void __exit irrtc_exit(void)
{
//proc_irrtc_exit(); //PROC
irqs_irrtc_exit();
irrtc_inputdev_close();
unregister_chrdev(NEUROS_IR_MAJOR, "neuros_ir");
}
MODULE_AUTHOR("Neuros");
MODULE_DESCRIPTION(MOD_DESC);
MODULE_LICENSE("Neuros Technology LLC");
module_init(irrtc_init);
module_exit(irrtc_exit);
/*
* Copyright(C) 2006-2007 Neuros Technology International LLC.
* <www.neurostechnology.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* This program is distributed in the hope that, in addition to its
* original purpose to support Neuros hardware, it will be useful
* otherwise, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
****************************************************************************
*
* IR Receiver driver / key mappings file
*
* TODO: support 2 different mappings (current keyboard-area mapping and another mapping which uses media keys)
* TODO: make the 2 mappings switchable via ioctl. Maybe allow remapping at runtime via ioctl.
*
*/
#define NUM_KEYS 36
static int keymap[NUM_KEYS] = {
0, //0
KEY_KP1, //1
KEY_KP2, //2
KEY_KP3, //3
KEY_KP4, //4
KEY_KP5, //5
KEY_KP6, //6
KEY_KP7, //7
KEY_KP8, //8
KEY_KP9, //9
KEY_KP0, //10
0, //11
0, //12
0, //13
0, //14
KEY_KPASTERISK, //15 "*"
KEY_KPDOT, //16 "#" //this was the only way.
KEY_PAGEUP, //17 CHAN_UP
KEY_PAGEDOWN, //18 CHAN_DN
KEY_BACKSPACE, //19 BACK
KEY_ESC, //20 HOME
KEY_UP, //21 UP
KEY_DOWN, //22 DOWN
KEY_LEFT, //23 LEFT
KEY_RIGHT, //24 RIGHT
KEY_ENTER, //25 ENTER
KEY_H, //26 HELP // no better idea than H
KEY_TAB, //27 XIM // TAB seems just better than X, no other reason
KEY_U, //28 UNLABELED_1 //this is a tiny "Unknown" and "Unlabeled" tiny key on remote
KEY_KPMINUS, //29 REW
KEY_KPPLUS, //30 FFW
KEY_SPACE, //31 PLAY //Most media apps use space for quick pause/play
KEY_HOME, //32 PREV
KEY_END, //33 NEXT
KEY_DELETE, //34 STOP
KEY_INSERT //35 RECORD
};
#ifndef NEUROS_IR__H
#define NEUROS_IR__H
/*
* Copyright(C) 2006-2007 Neuros Technology International LLC.
* <www.neurostechnology.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* This program is distributed in the hope that, in addition to its
* original purpose to support Neuros hardware, it will be useful
* otherwise, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
****************************************************************************
*
* IR Receiver driver header.
*
*/
#ifdef __KERNEL__
#include <linux/types.h>
extern int i2c_write(uint8_t reg, uint16_t value);
extern int i2c_read(uint8_t reg);
#else
#include <stdint.h>
#endif
#define regIR 0x40 // IR receiver register.
#define NEUROS_IR_MAJOR 110
#define NEUROS_IR_IOC_MAGIC 'i'
#define NULL_KEY 0xff
#define LEARNING_COMPLETE_KEY 0x3e
#define RELEASE_REMOTE_KEY 0x29
#define TEST_KEY 0x3f
#define UP_KEY 0x00
#endif /* NEUROS_IR__H */
#ifndef NEUROS_IR_BLASTER__H
#define NEUROS_IR_BLASTER__H
/*
* Copyright(C) 2006-2007 Neuros Technology International LLC.
* <www.neurostechnology.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* This program is distributed in the hope that, in addition to its
* original purpose to support Neuros hardware, it will be useful
* otherwise, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
****************************************************************************
*
* IR Blaster driver header.
*
*/
#ifdef __KERNEL__
#include <linux/types.h>
extern int i2c_write(uint8_t reg, uint16_t value);
extern int i2c_read(uint8_t reg);
#else
#include <stdint.h>
#endif
#define BLASTER_THROUGH_ARM
#define GIO3 0x0008
#define KEY_MASK 0xff
#define NEUROS_IR_BLASTER_MAJOR 111
#define NEUROS_IR_BLASTER_IOC_MAGIC 'b'
#define the_same(x,y,p) \
((((x)*100<=(y)*(100+(p)))&&((y)*100<=(x)*(100+(p))))?1:0)
#define SIMILAR_PRECISION 20 /*averaged off x% difference.*/
#define the_similar(x,y) the_same(x,y,SIMILAR_PRECISION)
#define CAPTRUE_PRECISION1 10 /*averaged off x% difference.*/
#define the_same1(x,y) the_same(x,y,CAPTRUE_PRECISION1)
#define CAPTRUE_PRECISION2 13 /*averaged off x% difference.*/
#define the_same2(x,y) the_same(x,y,CAPTRUE_PRECISION2)
#define CAPTRUE_PRECISION3 17 /*averaged off x% difference.*/
#define the_same3(x,y) the_same(x,y,CAPTRUE_PRECISION3)
#ifdef BLASTER_THROUGH_ARM
#define BLS_START 0
#define BLS_COMPLETE 1
#define BLS_ERROR -1
#define BLASTER_MAX_CHANGE (8*50) /* maximum edge changes. */
#define BLASTER_MAX_SBITS 20 /*special edge number min is 6*/
#define BITS_COUNT_START 0 /*bits count start. */
#define BITS_COUNT_MASK (0x3FF<<BITS_COUNT_START) /*bits count mask. */
#define FIRST_LEVEL_BIT_START 15 /*bits count start. */
#define FIRST_LEVEL_BIT_MASK (1<<FIRST_LEVEL_BIT_START) /*end flag mask. */
struct blaster_data_type {
uint16_t bitstimes; /*first[15] 1 bit 1=high level 0=low level;
[0-9]10 bit =how many bits;*/
uint32_t bits[BLASTER_MAX_CHANGE]; /*each bit length*/
};
#else
// I2C command definitions.
#define cmdBLASTER_SEND 0x18
/* RRB registers definitions. */
#define regCMND 0 // command register.
#define regBLASTER_DBITS (0x80+24) // used to put blaster data(part7)
#define regBLASTER_MBITS 0x80 // used to put blaster data(part6)
#define regFLASH_DATA 0x06 // used to put blaster data(part5)
#define regBLASTER_BIT2 (regBLASTER_DATA+6) // used to put blaster data(part4)
#define regBLASTER_BIT1 (regBLASTER_DATA+4) // used to put blaster data(part3)
#define regBLASTER_BIT0 (regBLASTER_DATA+2) // used to put blaster data(part2)
#define regBLASTER_DATA 0x1C // used to put blaster data(part1)
#define BLASTER_MAX_CHANGE (8*24) /* maximum edge changes. */
#define BLASTER_MAX_SBITS 8 /*special edge number min is 6*/
#define BLASTER_MAX_BITS (8*24) /*maximum edge changes, use for uncompacted data structure*/
#define END_COUNT 8 /*number of edges for end bit. */
#define BITS_COUNT_START 7 /*bits count start. */
#define END_FLAG_START 6 /*end flag mask. */
#define BITS_COUNT_MASK (0xFF<<BITS_COUNT_START) /*bits count mask. */
#define END_FLAG_MASK (1<<END_FLAG_START) /*end flag mask. */
#define MAX_REPEAT_TIMES 7 /*bits count start. */
#define BITS_TIMES_MASK 0xFFF8 /*bits times mask. */
#define FIRST_LEVEL_BIT_START 15 /*bits count start. */
#define FIRST_LEVEL_BIT_MASK (1<<FIRST_LEVEL_BIT_START) /*end flag mask. */
struct blaster_data_type {
uint16_t bitstimes; /*first[15] 1 bit 1=high level 0=low level;
[8+BITS_COUNT_START-BITS_COUNT_START]8 bit =how many bits;
[END_FLAG_START] 1=have end bits 0=not have end bits
[2-0]3 bit=how many repeat times*/
uint16_t start1; /*start mark first length */
uint16_t start2; /*start mark second length*/
uint16_t interval; /*interval for each times */
uint16_t bits[BLASTER_MAX_BITS]; /*each bit length*/
uint16_t end[END_COUNT];
};
#endif
struct blaster_data_pack {
uint16_t bitstimes; /*first[15] 1 bit 1=high level 0=low level;
[7+BITS_COUNT_START-BITS_COUNT_START]8 bit =how many bits;
[END_FLAG_START] 1=have end bits 0=not have end bits
[2-0]3 bit=how many repeat times*/
uint32_t bit0;
uint32_t bit1;
uint32_t bit2;
uint8_t mbits[BLASTER_MAX_CHANGE/8];
uint8_t dbits[BLASTER_MAX_CHANGE/8];
uint32_t specbits[BLASTER_MAX_SBITS];
};
#define keybit_set(bi, base, val) \
do {\
if (val)\
*((base) + ((bi) / 8)) |=(1 << ((bi) % 8));\
else\
*((base) + ((bi) / 8)) &=~(1 << ((bi) % 8));\
} while(0)
#define keybit_get(base, bi) \
*((base) + ((bi) / 8)) & (1 << ((bi) % 8))
#define RRB_CAPTURE_KEY _IO(NEUROS_IR_BLASTER_IOC_MAGIC, 7)
#define RRB_BLASTER_KEY _IOW(NEUROS_IR_BLASTER_IOC_MAGIC, 8, \
struct blaster_data_pack)
#define RRB_FACTORY_TEST _IO(NEUROS_IR_BLASTER_IOC_MAGIC, 9)
#define RRB_READ_LEARNING_DATA _IOR(NEUROS_IR_BLASTER_IOC_MAGIC, 10, \
struct blaster_data_type)
#define RRB_GET_BLASTER_STATUS _IOR(NEUROS_IR_BLASTER_IOC_MAGIC, 11, \
int)
#endif /* NEUROS_IR_BLASTER__H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment