Path: blob/master/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
15111 views
/* dvb-usb-remote.c is part of the DVB USB library.1*2* Copyright (C) 2004-6 Patrick Boettcher ([email protected])3* see dvb-usb-init.c for copyright information.4*5* This file contains functions for initializing the input-device and for handling remote-control-queries.6*/7#include "dvb-usb-common.h"8#include <linux/usb/input.h>910static unsigned int11legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke,12struct rc_map_table *keymap,13unsigned int keymap_size)14{15unsigned int index;16unsigned int scancode;1718if (ke->flags & INPUT_KEYMAP_BY_INDEX) {19index = ke->index;20} else {21if (input_scancode_to_scalar(ke, &scancode))22return keymap_size;2324/* See if we can match the raw key code. */25for (index = 0; index < keymap_size; index++)26if (keymap[index].scancode == scancode)27break;2829/* See if there is an unused hole in the map */30if (index >= keymap_size) {31for (index = 0; index < keymap_size; index++) {32if (keymap[index].keycode == KEY_RESERVED ||33keymap[index].keycode == KEY_UNKNOWN) {34break;35}36}37}38}3940return index;41}4243static int legacy_dvb_usb_getkeycode(struct input_dev *dev,44struct input_keymap_entry *ke)45{46struct dvb_usb_device *d = input_get_drvdata(dev);47struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;48unsigned int keymap_size = d->props.rc.legacy.rc_map_size;49unsigned int index;5051index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);52if (index >= keymap_size)53return -EINVAL;5455ke->keycode = keymap[index].keycode;56if (ke->keycode == KEY_UNKNOWN)57ke->keycode = KEY_RESERVED;58ke->len = sizeof(keymap[index].scancode);59memcpy(&ke->scancode, &keymap[index].scancode, ke->len);60ke->index = index;6162return 0;63}6465static int legacy_dvb_usb_setkeycode(struct input_dev *dev,66const struct input_keymap_entry *ke,67unsigned int *old_keycode)68{69struct dvb_usb_device *d = input_get_drvdata(dev);70struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;71unsigned int keymap_size = d->props.rc.legacy.rc_map_size;72unsigned int index;7374index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);75/*76* FIXME: Currently, it is not possible to increase the size of77* scancode table. For it to happen, one possibility78* would be to allocate a table with key_map_size + 1,79* copying data, appending the new key on it, and freeing80* the old one - or maybe just allocating some spare space81*/82if (index >= keymap_size)83return -EINVAL;8485*old_keycode = keymap[index].keycode;86keymap->keycode = ke->keycode;87__set_bit(ke->keycode, dev->keybit);8889if (*old_keycode != KEY_RESERVED) {90__clear_bit(*old_keycode, dev->keybit);91for (index = 0; index < keymap_size; index++) {92if (keymap[index].keycode == *old_keycode) {93__set_bit(*old_keycode, dev->keybit);94break;95}96}97}9899return 0;100}101102/* Remote-control poll function - called every dib->rc_query_interval ms to see103* whether the remote control has received anything.104*105* TODO: Fix the repeat rate of the input device.106*/107static void legacy_dvb_usb_read_remote_control(struct work_struct *work)108{109struct dvb_usb_device *d =110container_of(work, struct dvb_usb_device, rc_query_work.work);111u32 event;112int state;113114/* TODO: need a lock here. We can simply skip checking for the remote control115if we're busy. */116117/* when the parameter has been set to 1 via sysfs while the driver was running */118if (dvb_usb_disable_rc_polling)119return;120121if (d->props.rc.legacy.rc_query(d,&event,&state)) {122err("error while querying for an remote control event.");123goto schedule;124}125126127switch (state) {128case REMOTE_NO_KEY_PRESSED:129break;130case REMOTE_KEY_PRESSED:131deb_rc("key pressed\n");132d->last_event = event;133case REMOTE_KEY_REPEAT:134deb_rc("key repeated\n");135input_event(d->input_dev, EV_KEY, event, 1);136input_sync(d->input_dev);137input_event(d->input_dev, EV_KEY, d->last_event, 0);138input_sync(d->input_dev);139break;140default:141break;142}143144/* improved repeat handling ???145switch (state) {146case REMOTE_NO_KEY_PRESSED:147deb_rc("NO KEY PRESSED\n");148if (d->last_state != REMOTE_NO_KEY_PRESSED) {149deb_rc("releasing event %d\n",d->last_event);150input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);151input_sync(d->rc_input_dev);152}153d->last_state = REMOTE_NO_KEY_PRESSED;154d->last_event = 0;155break;156case REMOTE_KEY_PRESSED:157deb_rc("KEY PRESSED\n");158deb_rc("pressing event %d\n",event);159160input_event(d->rc_input_dev, EV_KEY, event, 1);161input_sync(d->rc_input_dev);162163d->last_event = event;164d->last_state = REMOTE_KEY_PRESSED;165break;166case REMOTE_KEY_REPEAT:167deb_rc("KEY_REPEAT\n");168if (d->last_state != REMOTE_NO_KEY_PRESSED) {169deb_rc("repeating event %d\n",d->last_event);170input_event(d->rc_input_dev, EV_KEY, d->last_event, 2);171input_sync(d->rc_input_dev);172d->last_state = REMOTE_KEY_REPEAT;173}174default:175break;176}177*/178179schedule:180schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval));181}182183static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d)184{185int i, err, rc_interval;186struct input_dev *input_dev;187188input_dev = input_allocate_device();189if (!input_dev)190return -ENOMEM;191192input_dev->evbit[0] = BIT_MASK(EV_KEY);193input_dev->name = "IR-receiver inside an USB DVB receiver";194input_dev->phys = d->rc_phys;195usb_to_input_id(d->udev, &input_dev->id);196input_dev->dev.parent = &d->udev->dev;197d->input_dev = input_dev;198d->rc_dev = NULL;199200input_dev->getkeycode = legacy_dvb_usb_getkeycode;201input_dev->setkeycode = legacy_dvb_usb_setkeycode;202203/* set the bits for the keys */204deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size);205for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {206deb_rc("setting bit for event %d item %d\n",207d->props.rc.legacy.rc_map_table[i].keycode, i);208set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit);209}210211/* setting these two values to non-zero, we have to manage key repeats */212input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval;213input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150;214215input_set_drvdata(input_dev, d);216217err = input_register_device(input_dev);218if (err)219input_free_device(input_dev);220221rc_interval = d->props.rc.legacy.rc_interval;222223INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control);224225info("schedule remote query interval to %d msecs.", rc_interval);226schedule_delayed_work(&d->rc_query_work,227msecs_to_jiffies(rc_interval));228229d->state |= DVB_USB_STATE_REMOTE;230231return err;232}233234/* Remote-control poll function - called every dib->rc_query_interval ms to see235* whether the remote control has received anything.236*237* TODO: Fix the repeat rate of the input device.238*/239static void dvb_usb_read_remote_control(struct work_struct *work)240{241struct dvb_usb_device *d =242container_of(work, struct dvb_usb_device, rc_query_work.work);243int err;244245/* TODO: need a lock here. We can simply skip checking for the remote control246if we're busy. */247248/* when the parameter has been set to 1 via sysfs while the249* driver was running, or when bulk mode is enabled after IR init250*/251if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode)252return;253254err = d->props.rc.core.rc_query(d);255if (err)256err("error %d while querying for an remote control event.", err);257258schedule_delayed_work(&d->rc_query_work,259msecs_to_jiffies(d->props.rc.core.rc_interval));260}261262static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)263{264int err, rc_interval;265struct rc_dev *dev;266267dev = rc_allocate_device();268if (!dev)269return -ENOMEM;270271dev->driver_name = d->props.rc.core.module_name;272dev->map_name = d->props.rc.core.rc_codes;273dev->change_protocol = d->props.rc.core.change_protocol;274dev->allowed_protos = d->props.rc.core.allowed_protos;275dev->driver_type = d->props.rc.core.driver_type;276usb_to_input_id(d->udev, &dev->input_id);277dev->input_name = "IR-receiver inside an USB DVB receiver";278dev->input_phys = d->rc_phys;279dev->dev.parent = &d->udev->dev;280dev->priv = d;281282err = rc_register_device(dev);283if (err < 0) {284rc_free_device(dev);285return err;286}287288d->input_dev = NULL;289d->rc_dev = dev;290291if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)292return 0;293294/* Polling mode - initialize a work queue for handling it */295INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);296297rc_interval = d->props.rc.core.rc_interval;298299info("schedule remote query interval to %d msecs.", rc_interval);300schedule_delayed_work(&d->rc_query_work,301msecs_to_jiffies(rc_interval));302303return 0;304}305306int dvb_usb_remote_init(struct dvb_usb_device *d)307{308int err;309310if (dvb_usb_disable_rc_polling)311return 0;312313if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)314d->props.rc.mode = DVB_RC_LEGACY;315else if (d->props.rc.core.rc_codes)316d->props.rc.mode = DVB_RC_CORE;317else318return 0;319320usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));321strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));322323/* Start the remote-control polling. */324if (d->props.rc.legacy.rc_interval < 40)325d->props.rc.legacy.rc_interval = 100; /* default */326327if (d->props.rc.mode == DVB_RC_LEGACY)328err = legacy_dvb_usb_remote_init(d);329else330err = rc_core_dvb_usb_remote_init(d);331if (err)332return err;333334d->state |= DVB_USB_STATE_REMOTE;335336return 0;337}338339int dvb_usb_remote_exit(struct dvb_usb_device *d)340{341if (d->state & DVB_USB_STATE_REMOTE) {342cancel_delayed_work_sync(&d->rc_query_work);343if (d->props.rc.mode == DVB_RC_LEGACY)344input_unregister_device(d->input_dev);345else346rc_unregister_device(d->rc_dev);347}348d->state &= ~DVB_USB_STATE_REMOTE;349return 0;350}351352#define DVB_USB_RC_NEC_EMPTY 0x00353#define DVB_USB_RC_NEC_KEY_PRESSED 0x01354#define DVB_USB_RC_NEC_KEY_REPEATED 0x02355int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,356u8 keybuf[5], u32 *event, int *state)357{358int i;359struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;360*event = 0;361*state = REMOTE_NO_KEY_PRESSED;362switch (keybuf[0]) {363case DVB_USB_RC_NEC_EMPTY:364break;365case DVB_USB_RC_NEC_KEY_PRESSED:366if ((u8) ~keybuf[1] != keybuf[2] ||367(u8) ~keybuf[3] != keybuf[4]) {368deb_err("remote control checksum failed.\n");369break;370}371/* See if we can match the raw key code. */372for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)373if (rc5_custom(&keymap[i]) == keybuf[1] &&374rc5_data(&keymap[i]) == keybuf[3]) {375*event = keymap[i].keycode;376*state = REMOTE_KEY_PRESSED;377return 0;378}379deb_err("key mapping failed - no appropriate key found in keymapping\n");380break;381case DVB_USB_RC_NEC_KEY_REPEATED:382*state = REMOTE_KEY_REPEAT;383break;384default:385deb_err("unknown type of remote status: %d\n",keybuf[0]);386break;387}388return 0;389}390EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event);391392393