lirc scancode interface, and more
Subsystems (10)
Sean Young
maintainercover lirc scancode interface, and more
Port lirc_zilog to rc-core, introduce lirc scancode mode for sending and receiving, and then remove the lirc kernel api.
Note that the ported zilog driver needs the scancode interface, since without it the RC_DRIVER_SCANCODE type IR driver would not have a lirc chardev.
In summary:
- This removes the lirc staging directory.
- lirc IR TX can use in-kernel encoders for scancode encoding
- lirc_zilog now can transmit raw IR (or scancodes using above interface)
- lirc kapi (not uapi!) is gone
- The reading lirc scancode interface gives more information (e.g. protocol, toggle, repeat). So you can determine what protocol variant a remotes uses
- Line count is actually down and code cleaner (imo)
v2:
- Add MAINTAINERS entries
- Fixes for nec repeat
- Validate scancode for tx
- Minor bugfixes
v3:
- Review comments from Hans Verkuil
- Documented and fixed rc_validate_scancode()
- Fix a bug in kfifo on arm 32-bit
- this inferface won't be used for cec remote control passthrough
v4:
- Rewrote zilog driver to send raw IR rather than codes from database
- Minor ir-kbd-i2c improvements
Sean Young (28):
media: rc: i2c: set parent of rc device and improve name
media: rc: i2c: use dev_dbg rather hand-rolled debug
media: rc: i2c: only poll if the rc device is opened
media: merge ir_tx_z8f0811_haup and ir_rx_z8f0811_haup i2c devices
media: rc: implement zilog transmitter
media: i2c: enable i2c IR for hardware which isn't HD-PVR
media: staging: remove lirc_zilog driver
media: MAINTAINERS: remove lirc staging area
media: lirc: remove LIRCCODE and LIRC_GET_LENGTH
media: lirc: implement scancode sending
media: lirc: use the correct carrier for scancode transmit
media: rc: auto load encoder if necessary
media: lirc: lirc interface should not be a raw decoder
media: lirc: validate scancode for transmit
media: rc: document and fix rc_validate_scancode()
media: lirc: merge lirc_dev_fop_ioctl and ir_lirc_ioctl
media: lirc: use kfifo rather than lirc_buffer for raw IR
media: lirc: move lirc_dev->attached to rc_dev->registered
media: lirc: do not call rc_close() on unregistered devices
media: lirc: create rc-core open and close lirc functions
media: lirc: remove name from lirc_dev
media: lirc: remove last remnants of lirc kapi
media: lirc: implement reading scancode
media: rc: ensure lirc device receives nec repeats
media: lirc: document LIRC_MODE_SCANCODE
media: lirc: introduce LIRC_SET_POLL_MODES
media: lirc: scancode rc devices should have a lirc device too
kfifo: DECLARE_KIFO_PTR(fifo, u64) does not work on arm 32 bit
Documentation/media/kapi/rc-core.rst | 5 - Documentation/media/lirc.h.rst.exceptions | 31 + Documentation/media/uapi/rc/lirc-dev-intro.rst | 68 +- Documentation/media/uapi/rc/lirc-func.rst | 2 +- Documentation/media/uapi/rc/lirc-get-features.rst | 17 +- Documentation/media/uapi/rc/lirc-get-length.rst | 44 - Documentation/media/uapi/rc/lirc-get-rec-mode.rst | 5 +- Documentation/media/uapi/rc/lirc-get-send-mode.rst | 2 +- Documentation/media/uapi/rc/lirc-read.rst | 15 +- .../media/uapi/rc/lirc-set-poll-modes.rst | 52 + Documentation/media/uapi/rc/lirc-write.rst | 19 +- MAINTAINERS | 6 - drivers/media/i2c/ir-kbd-i2c.c | 540 ++++++- drivers/media/pci/cx18/cx18-cards.h | 8 +- drivers/media/pci/cx18/cx18-i2c.c | 13 +- drivers/media/pci/ivtv/ivtv-cards.h | 22 +- drivers/media/pci/ivtv/ivtv-i2c.c | 20 +- drivers/media/pci/saa7134/saa7134-input.c | 3 +- drivers/media/rc/Kconfig | 29 +- drivers/media/rc/Makefile | 5 +- drivers/media/rc/ir-jvc-decoder.c | 1 + drivers/media/rc/ir-lirc-codec.c | 559 ++++--- drivers/media/rc/ir-mce_kbd-decoder.c | 12 +- drivers/media/rc/ir-nec-decoder.c | 1 + drivers/media/rc/ir-rc5-decoder.c | 1 + drivers/media/rc/ir-rc6-decoder.c | 1 + drivers/media/rc/ir-sanyo-decoder.c | 1 + drivers/media/rc/ir-sharp-decoder.c | 1 + drivers/media/rc/ir-sony-decoder.c | 1 + drivers/media/rc/lirc_dev.c | 487 +----- drivers/media/rc/rc-core-priv.h | 54 +- drivers/media/rc/rc-ir-raw.c | 56 +- drivers/media/rc/rc-main.c | 166 +- drivers/media/usb/hdpvr/hdpvr-core.c | 11 +- drivers/media/usb/hdpvr/hdpvr-i2c.c | 23 +- drivers/media/usb/hdpvr/hdpvr.h | 3 +- drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c | 13 +- drivers/staging/media/Kconfig | 3 - drivers/staging/media/Makefile | 1 - drivers/staging/media/lirc/Kconfig | 21 - drivers/staging/media/lirc/Makefile | 6 - drivers/staging/media/lirc/TODO | 36 - drivers/staging/media/lirc/lirc_zilog.c | 1653 -------------------- include/linux/kfifo.h | 3 +- include/media/i2c/ir-kbd-i2c.h | 6 +- include/media/lirc_dev.h | 192 --- include/media/rc-core.h | 53 +- include/media/rc-map.h | 54 +- include/uapi/linux/lirc.h | 91 ++ 49 files changed, 1479 insertions(+), 2937 deletions(-) delete mode 100644 Documentation/media/uapi/rc/lirc-get-length.rst create mode 100644 Documentation/media/uapi/rc/lirc-set-poll-modes.rst delete mode 100644 drivers/staging/media/lirc/Kconfig delete mode 100644 drivers/staging/media/lirc/Makefile delete mode 100644 drivers/staging/media/lirc/TODO delete mode 100644 drivers/staging/media/lirc/lirc_zilog.c delete mode 100644 include/media/lirc_dev.h
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 1/28 media: rc: i2c: set parent of rc device and improve name
With the parent set for the rc device, the messages clearly state that it is attached via i2c. The additional printk is unnecessary.
So these are the old messages:
rc rc1: i2c IR (Hauppauge WinTV PVR-150 as /devices/virtual/rc/rc1
ir-kbd-i2c: i2c IR (Hauppauge WinTV PVR-150 detected at i2c-10/10-0071/ir0 [ivtv i2c driver #0]
Now we simply get:
rc rc1: Hauppauge WinTV PVR-150 as /devices/pci0000:00/0000:00:1e.0/0000:02:00.0/i2c-10/10-0071/rc/rc1
Note that we no longer copy the name. I've checked all call sites to verfiy this is not a problem.
--- drivers/media/i2c/ir-kbd-i2c.c | 11 +++-------- drivers/media/pci/saa7134/saa7134-input.c | 3 ++- include/media/i2c/ir-kbd-i2c.h | 1 - 3 files changed, 5 insertions(+), 10 deletions(-)
drivers/media/i2c/ir-kbd-i2c.c +3 -8
@@ -439,12 +439,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_out_free; } -/* Sets name */ -snprintf (ir->name,sizeof (ir->name),"i2c IR (%s)" , name); ir->ir_codes = ir_codes; -snprintf (ir->phys,sizeof (ir->phys),"%s/%s/ir0" , -dev_name (&adap->dev), +snprintf (ir->phys,sizeof (ir->phys),"%s/%s" ,dev_name (&adap->dev),dev_name (&client->dev));/*
@@ -453,7 +450,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)*/ rc->input_id.bustype =BUS_I2C ; rc->input_phys = ir->phys; - rc->device_name = ir->name; + rc->device_name = name; + rc->dev.parent = &client->dev;/* * Initialize the other fields of rc_dev
@@ -467,9 +465,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)if (err) goto err_out_free; -printk (MODULE_NAME ": %s detected at %s [%s]\n" , - ir->name, ir->phys, adap->name); -/* start polling via eventd */ INIT_DELAYED_WORK (&ir->work, ir_work);schedule_delayed_work (&ir->work,0 );
drivers/media/pci/saa7134/saa7134-input.c +2 -1
@@ -43,7 +43,8 @@ MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=g } while (0) #define ir_dbg(ir, fmt, arg...) do { \ if (ir_debug) \ - printk(KERN_DEBUG pr_fmt("ir %s: " fmt), ir->name, ## arg); \ + printk(KERN_DEBUG pr_fmt("ir %s: " fmt), ir->rc->device_name, \ + ## arg); \ } while (0)/* Helper function for raw decoding at GPIO16 or GPIO18 */
include/media/i2c/ir-kbd-i2c.h +0 -1
@@ -18,7 +18,6 @@ struct IR_i2c {u32 polling_interval;/* in ms */ struct delayed_work work; -char name[32 ];char phys[32 ]; int (*get_key)(struct IR_i2c *ir, enum rc_proto *protocol,
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 2/28 media: rc: i2c: use dev_dbg rather hand-rolled debug
In reply to Sean YoungUse the dev_dbg dynamic infrastructure instead of rolling our own custom debug logic.
--- drivers/media/i2c/ir-kbd-i2c.c | 61 +++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 36 deletions(-)
drivers/media/i2c/ir-kbd-i2c.c +25 -36
@@ -46,18 +46,6 @@#include <media/rc-core.h> #include <media/i2c/ir-kbd-i2c.h> -/* ----------------------------------------------------------------------- */ -/* insmod parameters */ - -static int debug; -module_param (debug, int,0644 );/* debug level (0,1,2) */ - - -#define MODULE_NAME "ir-kbd-i2c" -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG MODULE_NAME ": " fmt , ## arg) - -/* ----------------------------------------------------------------------- */ static int get_key_haup_common (struct IR_i2c *ir,enum rc_proto *protocol,u32 *scancode,u8 *ptoggle,int size)
@@ -96,7 +84,8 @@ static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol,if (!range) code +=64 ; -dprintk (1 ,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n" , +dev_dbg (&ir->rc->dev, +"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n" , start, range, toggle, dev, code); *protocol =RC_PROTO_RC5 ;
@@ -113,13 +102,15 @@ static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, *ptoggle = (dev &0x80 ) !=0 ; *protocol =RC_PROTO_RC6_MCE ; dev &=0x7f ; -dprintk (1 ,"ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n" , - *ptoggle, vendor, dev, code); +dev_dbg (&ir->rc->dev, +"ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n" , + *ptoggle, vendor, dev, code); }else { *ptoggle =0 ; *protocol =RC_PROTO_RC6_6A_32 ; -dprintk (1 ,"ir hauppauge (rc6-6a-32): vendor=%d dev=%d code=%d\n" , - vendor, dev, code); +dev_dbg (&ir->rc->dev, +"ir hauppauge (rc6-6a-32): vendor=%d dev=%d code=%d\n" , + vendor, dev, code); } *scancode =RC_SCANCODE_RC6_6A (vendor, dev, code);
@@ -162,7 +153,7 @@ static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol,/* poll IR chip */ if (1 !=i2c_master_recv (ir->c, &b,1 )) { -dprintk (1 ,"read error\n" ); +dev_dbg (&ir->rc->dev,"read error\n" );return -EIO ; }
@@ -179,13 +170,12 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol,/* poll IR chip */ if (4 !=i2c_master_recv (ir->c, buf,4 )) { -dprintk (1 ,"read error\n" ); +dev_dbg (&ir->rc->dev,"read error\n" );return -EIO ; } -if (buf[0 ] !=0 || buf[1 ] !=0 || buf[2 ] !=0 || buf[3 ] !=0 ) -dprintk (2 ,"%s: 0x%2x 0x%2x 0x%2x 0x%2x\n" , __func__, - buf[0 ], buf[1 ], buf[2 ], buf[3 ]); +if (buf[0 ] !=0 || buf[1 ] !=0 || buf[2 ] !=0 || buf[3 ] !=0 ) +dev_dbg (&ir->rc->dev,"%s: %*ph\n" , __func__,4 , buf);/* no key pressed or signal from other ir remote */ if (buf[0 ] !=0x1 || buf[1 ] !=0xfe )
@@ -204,7 +194,7 @@ static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol,/* poll IR chip */ if (1 !=i2c_master_recv (ir->c, &b,1 )) { -dprintk (1 ,"read error\n" ); +dev_dbg (&ir->rc->dev,"read error\n" );return -EIO ; }
@@ -212,7 +202,7 @@ static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol,down, while 0xff indicates that no button is hold down. 0xfe sequences are sometimes interrupted by 0xFF */ -dprintk (2 ,"key %02x\n" , b); +dev_dbg (&ir->rc->dev,"key %02x\n" , b);if (b ==0xff )return 0 ;
@@ -237,7 +227,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, .buf = &key, .len = 1} }; subaddr =0x0d ;if (2 !=i2c_transfer (ir->c->adapter, msg,2 )) { -dprintk (1 ,"read error\n" ); +dev_dbg (&ir->rc->dev,"read error\n" );return -EIO ; }
@@ -247,18 +237,17 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, subaddr =0x0b ; msg[1 ].buf = &keygroup;if (2 !=i2c_transfer (ir->c->adapter, msg,2 )) { -dprintk (1 ,"read error\n" ); +dev_dbg (&ir->rc->dev,"read error\n" );return -EIO ; }if (keygroup ==0xff )return 0 ; -dprintk (1 ,"read key 0x%02x/0x%02x\n" , key, keygroup); +dev_dbg (&ir->rc->dev,"read key 0x%02x/0x%02x\n" , key, keygroup);if (keygroup <2 || keygroup >4 ) { -/* Only a warning */ -dprintk (1 ,"warning: invalid key group 0x%02x for key 0x%02x\n" , - keygroup, key); +dev_warn (&ir->rc->dev,"warning: invalid key group 0x%02x for key 0x%02x\n" , + keygroup, key); } key |= (keygroup &1 ) <<6 ;
@@ -279,15 +268,15 @@ static int ir_key_poll(struct IR_i2c *ir)u8 toggle;int rc; -dprintk (3 ,"%s\n" , __func__); +dev_dbg (&ir->rc->dev,"%s\n" , __func__); rc = ir->get_key (ir, &protocol, &scancode, &toggle);if (rc <0 ) { -dprintk (2 ,"error\n" ); +dev_warn (&ir->rc->dev,"error %d\n" , rc);return rc; }if (rc) { -dprintk (1 ,"%s: proto = 0x%04x, scancode = 0x%08x\n" , +dev_dbg (&ir->rc->dev,"%s: proto = 0x%04x, scancode = 0x%08x\n" , __func__, protocol, scancode);rc_keydown (ir->rc, protocol, scancode, toggle); }
@@ -433,8 +422,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)/* Make sure we are all setup before going on */ if (!name || !ir->get_key || !rc_proto || !ir_codes) { -dprintk (1 ,": Unsupported device at address 0x%02x\n" , - addr); +dev_warn (&client->dev,"Unsupported device at address 0x%02x\n" , + addr); err = -ENODEV ; goto err_out_free; }
@@ -459,7 +448,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) rc->map_name = ir->ir_codes; rc->allowed_protocols = rc_proto;if (!rc->driver_name) - rc->driver_name =MODULE_NAME ; + rc->driver_name =KBUILD_MODNAME ; err =rc_register_device (rc);if (err)
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 3/28 media: rc: i2c: only poll if the rc device is opened
In reply to Sean YoungThe lirc_zilog driver only polls the device if the lirc chardev is opened; do the same with the rc-core driver.
--- drivers/media/i2c/ir-kbd-i2c.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-)
drivers/media/i2c/ir-kbd-i2c.c +21 -4
@@ -298,6 +298,22 @@ static void ir_work(struct work_struct *work)schedule_delayed_work (&ir->work,msecs_to_jiffies (ir->polling_interval)); } +static int ir_open (struct rc_dev *dev) +{ +struct IR_i2c *ir = dev->priv; + +schedule_delayed_work (&ir->work,0 ); + +return 0 ; +} + +static void ir_close (struct rc_dev *dev) +{ +struct IR_i2c *ir = dev->priv; + +cancel_delayed_work_sync (&ir->work); +} +/* ----------------------------------------------------------------------- */ static int ir_probe (struct i2c_client *client,const struct i2c_device_id *id)
@@ -441,6 +457,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) rc->input_phys = ir->phys; rc->device_name = name; rc->dev.parent = &client->dev; + rc->priv = ir; + rc->open = ir_open; + rc->close = ir_close;/* * Initialize the other fields of rc_dev
@@ -450,14 +469,12 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)if (!rc->driver_name) rc->driver_name =KBUILD_MODNAME ; +INIT_DELAYED_WORK (&ir->work, ir_work); + err =rc_register_device (rc);if (err) goto err_out_free; -/* start polling via eventd */ -INIT_DELAYED_WORK (&ir->work, ir_work); -schedule_delayed_work (&ir->work,0 ); -return 0 ; err_out_free:
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 4/28 media: merge ir_tx_z8f0811_haup and ir_rx_z8f0811_haup i2c devices
In reply to Sean YoungThese two devices ids are really just one device with multiple addresses. Probing becomes much simpler if we simply fold this into one i2c device with two address.
Note that this breaks the lirc_zilog driver, however we will teach ir-kbd-i2c to do what lirc_zilog does in a later commit.
--- drivers/media/i2c/ir-kbd-i2c.c | 4 ++-- drivers/media/pci/cx18/cx18-cards.h | 8 +------- drivers/media/pci/cx18/cx18-i2c.c | 13 +++++-------- drivers/media/pci/ivtv/ivtv-cards.h | 22 +++++++--------------- drivers/media/pci/ivtv/ivtv-i2c.c | 20 ++++---------------- drivers/media/usb/hdpvr/hdpvr-core.c | 11 ++--------- drivers/media/usb/hdpvr/hdpvr-i2c.c | 23 +++++------------------ drivers/media/usb/hdpvr/hdpvr.h | 3 +-- drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c | 13 +++---------- 9 files changed, 30 insertions(+), 87 deletions(-)
drivers/media/i2c/ir-kbd-i2c.c +2 -2
@@ -501,8 +501,8 @@ static const struct i2c_device_id ir_kbd_id[] = {/* Generic entry for any IR receiver */ { "ir_video", 0 },/* IR device specific entries should be added here */ - { "ir_rx_z8f0811_haup", 0 }, - { "ir_rx_z8f0811_hdpvr", 0 }, + { "ir_z8f0811_haup", 0 }, + { "ir_z8f0811_hdpvr", 0 }, { } };
drivers/media/pci/cx18/cx18-cards.h +1 -7
@@ -25,13 +25,7 @@#define CX18_HW_418_AV (1 << 4)#define CX18_HW_GPIO_MUX (1 << 5)#define CX18_HW_GPIO_RESET_CTRL (1 << 6) -#define CX18_HW_Z8F0811_IR_TX_HAUP (1 << 7) -#define CX18_HW_Z8F0811_IR_RX_HAUP (1 << 8) -#define CX18_HW_Z8F0811_IR_HAUP (CX18_HW_Z8F0811_IR_RX_HAUP | \ - CX18_HW_Z8F0811_IR_TX_HAUP) - -#define CX18_HW_IR_ANY (CX18_HW_Z8F0811_IR_RX_HAUP | \ - CX18_HW_Z8F0811_IR_TX_HAUP) +#define CX18_HW_Z8F0811_IR_HAUP (1 << 7)/* video inputs */ #define CX18_CARD_INPUT_VID_TUNER 1
drivers/media/pci/cx18/cx18-i2c.c +5 -8
@@ -47,8 +47,7 @@ static const u8 hw_addrs[] = {0 ,/* CX18_HW_418_AV */ 0 ,/* CX18_HW_GPIO_MUX */ 0 ,/* CX18_HW_GPIO_RESET_CTRL */ -CX18_Z8F0811_IR_TX_I2C_ADDR ,/* CX18_HW_Z8F0811_IR_TX_HAUP */ - CX18_Z8F0811_IR_RX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_RX_HAUP */ + CX18_Z8F0811_IR_RX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_HAUP */ };/* This array should match the CX18_HW_ defines */
@@ -61,8 +60,7 @@ static const u8 hw_bus[] = {0 ,/* CX18_HW_418_AV */ 0 ,/* CX18_HW_GPIO_MUX */ 0 ,/* CX18_HW_GPIO_RESET_CTRL */ -0 ,/* CX18_HW_Z8F0811_IR_TX_HAUP */ - 0, /* CX18_HW_Z8F0811_IR_RX_HAUP */ + 0, /* CX18_HW_Z8F0811_IR_HAUP */ };/* This array should match the CX18_HW_ defines */
@@ -74,8 +72,7 @@ static const char * const hw_devicenames[] = {"cx23418_AV" ,"gpio_mux" ,"gpio_reset_ctrl" , -"ir_tx_z8f0811_haup" , - "ir_rx_z8f0811_haup", + "ir_z8f0811_haup", }; static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,
@@ -90,7 +87,7 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,/* Our default information for ir-kbd-i2c.c to use */ switch (hw) { -case CX18_HW_Z8F0811_IR_RX_HAUP : +case CX18_HW_Z8F0811_IR_HAUP : init_data->ir_codes =RC_MAP_HAUPPAUGE ; init_data->internal_get_key_func =IR_KBD_GET_KEY_HAUP_XVR ; init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE |
@@ -129,7 +126,7 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)return sd !=NULL ?0 :-1 ; } -if (hw &CX18_HW_IR_ANY ) +if (hw ==CX18_HW_Z8F0811_IR_HAUP )return cx18_i2c_new_ir (cx, adap, hw, type, hw_addrs[idx]);/* Is it not an I2C device or one we do not wish to register? */
drivers/media/pci/ivtv/ivtv-cards.h +7 -15
@@ -109,24 +109,16 @@#define IVTV_HW_I2C_IR_RX_AVER (1 << 16)#define IVTV_HW_I2C_IR_RX_HAUP_EXT (1 << 17)/* External before internal */ #define IVTV_HW_I2C_IR_RX_HAUP_INT (1 << 18) -#define IVTV_HW_Z8F0811_IR_TX_HAUP (1 << 19) -#define IVTV_HW_Z8F0811_IR_RX_HAUP (1 << 20) -#define IVTV_HW_I2C_IR_RX_ADAPTEC (1 << 21) - -#define IVTV_HW_Z8F0811_IR_HAUP (IVTV_HW_Z8F0811_IR_RX_HAUP | \ - IVTV_HW_Z8F0811_IR_TX_HAUP) +#define IVTV_HW_Z8F0811_IR_HAUP (1 << 19) +#define IVTV_HW_I2C_IR_RX_ADAPTEC (1 << 20)#define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) -#define IVTV_HW_IR_RX_ANY (IVTV_HW_I2C_IR_RX_AVER | \ - IVTV_HW_I2C_IR_RX_HAUP_EXT | \ - IVTV_HW_I2C_IR_RX_HAUP_INT | \ - IVTV_HW_Z8F0811_IR_RX_HAUP | \ - IVTV_HW_I2C_IR_RX_ADAPTEC) - -#define IVTV_HW_IR_TX_ANY (IVTV_HW_Z8F0811_IR_TX_HAUP) - -#define IVTV_HW_IR_ANY (IVTV_HW_IR_RX_ANY | IVTV_HW_IR_TX_ANY) +#define IVTV_HW_IR_ANY (IVTV_HW_I2C_IR_RX_AVER | \ + IVTV_HW_I2C_IR_RX_HAUP_EXT | \ + IVTV_HW_I2C_IR_RX_HAUP_INT | \ + IVTV_HW_Z8F0811_IR_HAUP | \ + IVTV_HW_I2C_IR_RX_ADAPTEC)/* video inputs */ #define IVTV_CARD_INPUT_VID_TUNER 1
drivers/media/pci/ivtv/ivtv-i2c.c +4 -16
@@ -117,8 +117,7 @@ static const u8 hw_addrs[] = {IVTV_AVERMEDIA_IR_RX_I2C_ADDR ,/* IVTV_HW_I2C_IR_RX_AVER */ IVTV_HAUP_EXT_IR_RX_I2C_ADDR ,/* IVTV_HW_I2C_IR_RX_HAUP_EXT */ IVTV_HAUP_INT_IR_RX_I2C_ADDR ,/* IVTV_HW_I2C_IR_RX_HAUP_INT */ -IVTV_Z8F0811_IR_TX_I2C_ADDR ,/* IVTV_HW_Z8F0811_IR_TX_HAUP */ -IVTV_Z8F0811_IR_RX_I2C_ADDR ,/* IVTV_HW_Z8F0811_IR_RX_HAUP */ +IVTV_Z8F0811_IR_RX_I2C_ADDR ,/* IVTV_HW_Z8F0811_IR_HAUP */ IVTV_ADAPTEC_IR_ADDR, /* IVTV_HW_I2C_IR_RX_ADAPTEC */ };
@@ -143,8 +142,7 @@ static const char * const hw_devicenames[] = {"ir_video" ,/* IVTV_HW_I2C_IR_RX_AVER */ "ir_video" ,/* IVTV_HW_I2C_IR_RX_HAUP_EXT */ "ir_video" ,/* IVTV_HW_I2C_IR_RX_HAUP_INT */ -"ir_tx_z8f0811_haup" ,/* IVTV_HW_Z8F0811_IR_TX_HAUP */ -"ir_rx_z8f0811_haup" ,/* IVTV_HW_Z8F0811_IR_RX_HAUP */ +"ir_z8f0811_haup" ,/* IVTV_HW_Z8F0811_IR_HAUP */ "ir_video", /* IVTV_HW_I2C_IR_RX_ADAPTEC */ };
@@ -181,18 +179,8 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)struct IR_i2c_init_data *init_data = &itv->ir_i2c_init_data;unsigned short addr_list[2 ] = { addr,I2C_CLIENT_END }; -/* Only allow one IR transmitter to be registered per board */ -if (hw &IVTV_HW_IR_TX_ANY ) { -if (itv->hw_flags &IVTV_HW_IR_TX_ANY ) -return -1 ; -memset (&info,0 ,sizeof (struct i2c_board_info )); -strlcpy (info.type, type,I2C_NAME_SIZE ); -return i2c_new_probed_device (adap, &info, addr_list,NULL ) - ==NULL ?-1 :0 ; - } -/* Only allow one IR receiver to be registered per board */ -if (itv->hw_flags &IVTV_HW_IR_RX_ANY ) +if (itv->hw_flags &IVTV_HW_IR_ANY )return -1 ;/* Our default information for ir-kbd-i2c.c to use */
@@ -211,7 +199,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) init_data->type =RC_PROTO_BIT_RC5 ; init_data->name = itv->card_name;break ; -case IVTV_HW_Z8F0811_IR_RX_HAUP : +case IVTV_HW_Z8F0811_IR_HAUP :/* Default to grey remote */ init_data->ir_codes =RC_MAP_HAUPPAUGE ; init_data->internal_get_key_func =IR_KBD_GET_KEY_HAUP_XVR ;
drivers/media/usb/hdpvr/hdpvr-core.c +2 -9
@@ -364,16 +364,9 @@ static int hdpvr_probe(struct usb_interface *interface, goto error; } - client =hdpvr_register_ir_rx_i2c (dev); + client =hdpvr_register_ir_i2c (dev);if (!client) { -v4l2_err (&dev->v4l2_dev,"i2c IR RX device register failed\n" ); - retval = -ENODEV ; - goto reg_fail; - } - - client =hdpvr_register_ir_tx_i2c (dev); -if (!client) { -v4l2_err (&dev->v4l2_dev,"i2c IR TX device register failed\n" ); +v4l2_err (&dev->v4l2_dev,"i2c IR device register failed\n" ); retval = -ENODEV ; goto reg_fail; }
drivers/media/usb/hdpvr/hdpvr-i2c.c +5 -18
@@ -32,24 +32,11 @@#define Z8F0811_IR_RX_I2C_ADDR 0x71 -struct i2c_client *hdpvr_register_ir_tx_i2c (struct hdpvr_device *dev) +struct i2c_client *hdpvr_register_ir_i2c (struct hdpvr_device *dev) {struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data; -struct i2c_board_info hdpvr_ir_tx_i2c_board_info = { -I2C_BOARD_INFO ("ir_tx_z8f0811_hdpvr" ,Z8F0811_IR_TX_I2C_ADDR ), - }; - - init_data->name ="HD-PVR" ; - hdpvr_ir_tx_i2c_board_info.platform_data = init_data; - -return i2c_new_device (&dev->i2c_adapter, &hdpvr_ir_tx_i2c_board_info); -} - -struct i2c_client *hdpvr_register_ir_rx_i2c (struct hdpvr_device *dev) -{ -struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data; -struct i2c_board_info hdpvr_ir_rx_i2c_board_info = { -I2C_BOARD_INFO ("ir_rx_z8f0811_hdpvr" ,Z8F0811_IR_RX_I2C_ADDR ), +struct i2c_board_info info = { +I2C_BOARD_INFO ("ir_z8f0811_hdpvr" ,Z8F0811_IR_RX_I2C_ADDR ), };/* Our default information for ir-kbd-i2c.c to use */
@@ -59,9 +46,9 @@ struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev)RC_PROTO_BIT_RC6_6A_32 ; init_data->name ="HD-PVR" ; init_data->polling_interval =405 ;/* ms, duplicated from Windows */ - hdpvr_ir_rx_i2c_board_info.platform_data = init_data; + info.platform_data = init_data; -return i2c_new_device (&dev->i2c_adapter, &hdpvr_ir_rx_i2c_board_info); +return i2c_new_device (&dev->i2c_adapter, &info); } static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus,
drivers/media/usb/hdpvr/hdpvr.h +1 -2
@@ -320,8 +320,7 @@ int hdpvr_cancel_queue(struct hdpvr_device *dev);/* i2c adapter registration */ int hdpvr_register_i2c_adapter (struct hdpvr_device *dev); -struct i2c_client *hdpvr_register_ir_rx_i2c (struct hdpvr_device *dev); -struct i2c_client *hdpvr_register_ir_tx_i2c (struct hdpvr_device *dev); +struct i2c_client *hdpvr_register_ir_i2c (struct hdpvr_device *dev);/*========================================================================*/ /* buffer management */
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c +3 -10
@@ -585,17 +585,10 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) init_data->type =RC_PROTO_BIT_RC5 |RC_PROTO_BIT_RC6_MCE |RC_PROTO_BIT_RC6_6A_32 ; init_data->name = hdw->hdw_desc->description; -/* IR Receiver */ - info.addr =0x71 ; - info.platform_data = init_data; -strlcpy (info.type,"ir_rx_z8f0811_haup" ,I2C_NAME_SIZE ); -pvr2_trace (PVR2_TRACE_INFO ,"Binding %s to i2c address 0x%02x." , - info.type, info.addr); -i2c_new_device (&hdw->i2c_adap, &info); -/* IR Trasmitter */ - info.addr =0x70 ; +/* IR Transceiver */ + info.addr =0x71 ; info.platform_data = init_data; -strlcpy (info.type,"ir_tx_z8f0811_haup" ,I2C_NAME_SIZE ); +strlcpy (info.type,"ir_z8f0811_haup" ,I2C_NAME_SIZE );pvr2_trace (PVR2_TRACE_INFO ,"Binding %s to i2c address 0x%02x." , info.type, info.addr);i2c_new_device (&hdw->i2c_adap, &info);
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 5/28 media: rc: implement zilog transmitter
In reply to Sean YoungThis code implements the transmitter which is currently implemented in the staging lirc_zilog driver.
The new code does not need a signal database, iow. the haup-ir-blaster.bin firmware file is no longer needed, and the driver does not know anything about the keycodes in that file.
Instead, the new driver can send raw IR, but the hardware is limited
o few different lengths of pulse and spaces, so it is best to use generated IR rather than recorded IR.
--- drivers/media/i2c/ir-kbd-i2c.c | 436 ++++++++++++++++++++++++++++++++++++++++- include/media/i2c/ir-kbd-i2c.h | 5 + 2 files changed, 433 insertions(+), 8 deletions(-)
drivers/media/i2c/ir-kbd-i2c.c +428 -8
@@ -18,6 +18,20 @@* Brian Rogers <[email protected]> * modified for AVerMedia Cardbus by * Oldrich Jedlicka <[email protected]> +* Zilog Transmitter portions/ideas were derived from GPLv2+ sources: +* - drivers/char/pctv_zilogir.[ch] from Hauppauge Broadway product +* Copyright 2011 Hauppauge Computer works +* - drivers/staging/media/lirc/lirc_zilog.c +* Copyright (c) 2000 Gerd Knorr <[email protected]> +* Michal Kochanowicz <[email protected]> +* Christoph Bartelmus <[email protected]> +* Ulrich Mueller <[email protected]> +* Stefan Jahn <[email protected]> +* Jerome Brock <[email protected]> +* Thomas Reitmayr ([email protected]) +* Mark Weaver <[email protected]> +* Jarod Wilson <[email protected]> +* Copyright (C) 2011 Andy Walls <[email protected]> * * 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
@@ -46,6 +60,8 @@#include <media/rc-core.h> #include <media/i2c/ir-kbd-i2c.h> +#define FLAG_TX 1 +#define FLAG_HDPVR 2static int get_key_haup_common (struct IR_i2c *ir,enum rc_proto *protocol,u32 *scancode,u8 *ptoggle,int size)
@@ -288,11 +304,18 @@ static void ir_work(struct work_struct *work)int rc; struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); - rc =ir_key_poll (ir); -if (rc == -ENODEV ) { -rc_unregister_device (ir->rc); - ir->rc =NULL ; -return ; +/* +* If the transmit code is holding the lock, skip polling for +* IR, we'll get it to it next time round +*/ +if (mutex_trylock (&ir->lock)) { + rc =ir_key_poll (ir); +mutex_unlock (&ir->lock); +if (rc == -ENODEV ) { +rc_unregister_device (ir->rc); + ir->rc =NULL ; +return ; + } }schedule_delayed_work (&ir->work,msecs_to_jiffies (ir->polling_interval));
@@ -314,7 +337,383 @@ static void ir_close(struct rc_dev *dev)cancel_delayed_work_sync (&ir->work); } -/* ----------------------------------------------------------------------- */ +/* Zilog Transmit Interface */ +#define XTAL_FREQ 18432000 + +#define ZILOG_SEND 0x80 +#define ZILOG_UIR_END 0x40 +#define ZILOG_INIT_END 0x20 +#define ZILOG_LIR_END 0x10 + +#define ZILOG_STATUS_OK 0x80 +#define ZILOG_STATUS_TX 0x40 +#define ZILOG_STATUS_SET 0x20 + +/* +* As you can see here, very few different lengths of pulse and space +* can be encoded. This means that the hardware does not work well with +* recorded IR. It's best to work with generated IR, like from ir-ctl or +* the in-kernel encoders. +*/ +struct code_block { +u8 length; +u16 pulse[7 ];/* not aligned */ +u8 carrier_pulse; +u8 carrier_space; +u16 space[8 ];/* not aligned */ +u8 codes[61 ]; +u8 csum[2 ]; +} __packed; + +static int send_data_block (struct IR_i2c *ir,int cmd, +struct code_block *code_block) +{ +int i, j, ret; +u8 buf[5 ], *p; + + p = &code_block->length; +for (i =0 ; p < code_block->csum; i++) + code_block->csum[i &1 ] ^= *p++; + + p = &code_block->length; + +for (i =0 ; i <sizeof (*code_block);) { +int tosend =sizeof (*code_block) - i; + +if (tosend >4 ) + tosend =4 ; + buf[0 ] = i +1 ; +for (j =0 ; j < tosend; ++j) + buf[1 + j] = p[i + j]; +dev_dbg (&ir->rc->dev,"%*ph" , tosend +1 , buf); + ret =i2c_master_send (ir->tx_c, buf, tosend +1 ); +if (ret != tosend +1 ) { +dev_dbg (&ir->rc->dev, +"i2c_master_send failed with %d\n" , ret); +return ret <0 ? ret : -EIO ; + } + i += tosend; + } + + buf[0 ] =0 ; + buf[1 ] = cmd; + ret =i2c_master_send (ir->tx_c, buf,2 ); +if (ret !=2 ) { +dev_err (&ir->rc->dev,"i2c_master_send failed with %d\n" , ret); +return ret <0 ? ret : -EIO ; + } + +msleep (10 ); + + ret =i2c_master_send (ir->tx_c, buf,1 ); +if (ret !=1 ) { +dev_err (&ir->rc->dev,"i2c_master_send failed with %d\n" , ret); +return ret <0 ? ret : -EIO ; + } + +return 0 ; +} + +static int zilog_init (struct IR_i2c *ir) +{ +struct code_block code_block = { .length =sizeof (code_block) }; +u8 buf[4 ]; +int ret; + +put_unaligned_be16 (0x1000 , &code_block.pulse[3 ]); + + ret =send_data_block (ir,ZILOG_INIT_END , &code_block); +if (ret) +return ret; + + ret =i2c_master_recv (ir->tx_c, buf,4 ); +if (ret !=4 ) { +dev_err (&ir->c->dev,"failed to retrieve firmware version: %d\n" , + ret); +return ret <0 ? ret : -EIO ; + } + +dev_info (&ir->c->dev,"Zilog/Hauppauge IR blaster firmware version %d.%d.%d\n" , + buf[1 ], buf[2 ], buf[3 ]); + +return 0 ; +} + +/* +* If the last slot for pulse is the same as the current slot for pulse, +* then use slot no 7. +*/ +static void copy_codes (u8 *dst,u8 *src,unsigned int count) +{ +u8 c, last =0xff ; + +while (count--) { + c = *src++; +if ((c &0xf0 ) == last) { + *dst++ =0x70 | (c &0xf ); + }else { + *dst++ = c; + last = c &0xf0 ; + } + } +} + +/* +* When looking for repeats, we don't care about the trailing space. This +* is set to the shortest possible anyway. +*/ +static int cmp_no_trail (u8 *a,u8 *b,unsigned int count) +{ +while (--count) { +if (*a++ != *b++) +return 1 ; + } + +return (*a &0xf0 ) - (*b &0xf0 ); +} + +static int find_slot (u16 *array,unsigned int size,u16 val) +{ +int i; + +for (i =0 ; i < size; i++) { +if (get_unaligned_be16 (&array[i]) == val) { +return i; + }else if (!array[i]) { +put_unaligned_be16 (val, &array[i]); +return i; + } + } + +return -1 ; +} + +static int zilog_ir_format (struct rc_dev *rcdev,unsigned int *txbuf, +unsigned int count,struct code_block *code_block) +{ +struct IR_i2c *ir = rcdev->priv; +int rep, i, l, p =0 , s, c =0 ; +bool repeating; +u8 codes[174 ]; + + code_block->carrier_pulse =DIV_ROUND_CLOSEST ( + ir->duty_cycle *XTAL_FREQ /1000 , ir->carrier); + code_block->carrier_space =DIV_ROUND_CLOSEST ( + (100 - ir->duty_cycle) *XTAL_FREQ /1000 , ir->carrier); + +for (i =0 ; i < count; i++) { +if (c >=ARRAY_SIZE (codes) -1 ) { +dev_warn (&rcdev->dev,"IR too long, cannot transmit\n" ); +return -EINVAL ; + } + +/* +* Lengths more than 142220us cannot be encoded; also +* this checks for multiply overflow +*/ +if (txbuf[i] >142220 ) +return -EINVAL ; + + l =DIV_ROUND_CLOSEST ((XTAL_FREQ /1000 ) * txbuf[i],40000 ); + +if (i &1 ) { + s =find_slot (code_block->space, +ARRAY_SIZE (code_block->space), l); +if (s ==-1 ) { +dev_warn (&rcdev->dev,"Too many different lengths spaces, cannot transmit" ); +return -EINVAL ; + } + +/* We have a pulse and space */ + codes[c++] = (p <<4 ) | s; + }else { + p =find_slot (code_block->pulse, +ARRAY_SIZE (code_block->pulse), l); +if (p ==-1 ) { +dev_warn (&rcdev->dev,"Too many different lengths pulses, cannot transmit" ); +return -EINVAL ; + } + } + } + +/* We have to encode the trailing pulse. Find the shortest space */ + s =0 ; +for (i =1 ; i <ARRAY_SIZE (code_block->space); i++) { +u16 d =get_unaligned_be16 (&code_block->space[i]); + +if (get_unaligned_be16 (&code_block->space[s]) > d) + s = i; + } + + codes[c++] = (p <<4 ) | s; + +dev_dbg (&rcdev->dev,"generated %d codes\n" , c); + +/* +* Are the last N codes (so pulse + space) repeating 3 times? +* if so we can shorten the codes list and use code 0xc0 to repeat +* them. +*/ + repeating = false; + +for (rep = c /3 ; rep >=1 ; rep--) { +if (!memcmp (&codes[c - rep *3 ], &codes[c - rep *2 ], rep) && + !cmp_no_trail (&codes[c - rep], &codes[c - rep *2 ], rep)) { + repeating = true; +break ; + } + } + +if (repeating) { +/* first copy any leading non-repeating */ +int leading = c - rep *3 ; + +if (leading + rep >=ARRAY_SIZE (code_block->codes) -3 ) { +dev_warn (&rcdev->dev,"IR too long, cannot transmit\n" ); +return -EINVAL ; + } + +dev_dbg (&rcdev->dev,"found trailing %d repeat\n" , rep); +copy_codes (code_block->codes, codes, leading); + code_block->codes[leading] =0x82 ; +copy_codes (code_block->codes + leading +1 , codes + leading, + rep); + c = leading +1 + rep; + code_block->codes[c++] =0xc0 ; + }else { +if (c >=ARRAY_SIZE (code_block->codes) -3 ) { +dev_warn (&rcdev->dev,"IR too long, cannot transmit\n" ); +return -EINVAL ; + } + +dev_dbg (&rcdev->dev,"found no trailing repeat\n" ); + code_block->codes[0 ] =0x82 ; +copy_codes (code_block->codes +1 , codes, c); + c++; + code_block->codes[c++] =0xc4 ; + } + +while (c <ARRAY_SIZE (code_block->codes)) + code_block->codes[c++] =0x83 ; + +return 0 ; +} + +static int zilog_tx (struct rc_dev *rcdev,unsigned int *txbuf, +unsigned int count) +{ +struct IR_i2c *ir = rcdev->priv; +struct code_block code_block = { .length =sizeof (code_block) }; +u8 buf[2 ]; +int ret, i; + + ret =zilog_ir_format (rcdev, txbuf, count, &code_block); +if (ret) +return ret; + + ret =mutex_lock_interruptible (&ir->lock); +if (ret) +return ret; + + ret =send_data_block (ir,ZILOG_UIR_END , &code_block); +if (ret) + goto out_unlock; + + ret =i2c_master_recv (ir->tx_c, buf,1 ); +if (ret !=1 ) { +dev_err (&ir->rc->dev,"i2c_master_recv failed with %d\n" , ret); + goto out_unlock; + } + +dev_dbg (&ir->rc->dev,"code set status: %02x\n" , buf[0 ]); + +if (buf[0 ] != (ZILOG_STATUS_OK |ZILOG_STATUS_SET )) { +dev_err (&ir->rc->dev,"unexpected IR TX response %02x\n" , + buf[0 ]); + ret = -EIO ; + goto out_unlock; + } + + buf[0 ] =0x00 ; + buf[1 ] =ZILOG_SEND ; + + ret =i2c_master_send (ir->tx_c, buf,2 ); +if (ret !=2 ) { +dev_err (&ir->rc->dev,"i2c_master_send failed with %d\n" , ret); +if (ret >=0 ) + ret = -EIO ; + goto out_unlock; + } + +dev_dbg (&ir->rc->dev,"send command sent\n" ); + +/* +* This bit NAKs until the device is ready, so we retry it +* sleeping a bit each time. This seems to be what the windows +* driver does, approximately. +* Try for up to 1s. +*/ +for (i =0 ; i <20 ; ++i) { +set_current_state (TASK_UNINTERRUPTIBLE ); +schedule_timeout (msecs_to_jiffies (50 )); + ret =i2c_master_send (ir->tx_c, buf,1 ); +if (ret ==1 ) +break ; +dev_dbg (&ir->rc->dev, +"NAK expected: i2c_master_send failed with %d (try %d)\n" , + ret, i +1 ); + } + +if (ret !=1 ) { +dev_err (&ir->rc->dev, +"IR TX chip never got ready: last i2c_master_send failed with %d\n" , + ret); +if (ret >=0 ) + ret = -EIO ; + goto out_unlock; + } + + i =i2c_master_recv (ir->tx_c, buf,1 ); +if (i !=1 ) { +dev_err (&ir->rc->dev,"i2c_master_recv failed with %d\n" , ret); + ret = -EIO ; + goto out_unlock; + }else if (buf[0 ] !=ZILOG_STATUS_OK ) { +dev_err (&ir->rc->dev,"unexpected IR TX response #2: %02x\n" , + buf[0 ]); + ret = -EIO ; + goto out_unlock; + } +dev_dbg (&ir->rc->dev,"transmit complete\n" ); + +/* Oh good, it worked */ + ret = count; +out_unlock: +mutex_unlock (&ir->lock); + +return ret; +} + +static int zilog_tx_carrier (struct rc_dev *dev,u32 carrier) +{ +struct IR_i2c *ir = dev->priv; + +if (carrier >500000 || carrier <20000 ) +return -EINVAL ; + + ir->carrier = carrier; + +return 0 ; +} + +static int zilog_tx_duty_cycle (struct rc_dev *dev,u32 duty_cycle) +{ +struct IR_i2c *ir = dev->priv; + + ir->duty_cycle = duty_cycle; + +return 0 ; +}static int ir_probe (struct i2c_client *client,const struct i2c_device_id *id) {
@@ -469,8 +868,23 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)if (!rc->driver_name) rc->driver_name =KBUILD_MODNAME ; +mutex_init (&ir->lock); +INIT_DELAYED_WORK (&ir->work, ir_work); +if (id->driver_data &FLAG_TX ) { + ir->tx_c =i2c_new_dummy (client->adapter,0x70 ); +if (!ir->tx_c) { +dev_err (&client->dev,"failed to setup tx i2c address" ); + }else if (!zilog_init (ir)) { + ir->carrier =38000 ; + ir->duty_cycle =40 ; + rc->tx_ir = zilog_tx; + rc->s_tx_carrier = zilog_tx_carrier; + rc->s_tx_duty_cycle = zilog_tx_duty_cycle; + } + } + err =rc_register_device (rc);if (err) goto err_out_free;
@@ -478,6 +892,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)return 0 ; err_out_free: +if (ir->tx_c) +i2c_unregister_device (ir->tx_c); +/* Only frees rc if it were allocated internally */ rc_free_device (rc);return err;
@@ -490,6 +907,9 @@ static int ir_remove(struct i2c_client *client)/* kill outstanding polls */ cancel_delayed_work_sync (&ir->work); +if (ir->tx_c) +i2c_unregister_device (ir->tx_c); +/* unregister device */ rc_unregister_device (ir->rc);
@@ -501,8 +921,8 @@ static const struct i2c_device_id ir_kbd_id[] = {/* Generic entry for any IR receiver */ { "ir_video", 0 },/* IR device specific entries should be added here */ - { "ir_z8f0811_haup", 0 }, - { "ir_z8f0811_hdpvr", 0 }, + { "ir_z8f0811_haup", FLAG_TX }, + { "ir_z8f0811_hdpvr", FLAG_TX | FLAG_HDPVR }, { } };
include/media/i2c/ir-kbd-i2c.h +5 -0
@@ -22,6 +22,11 @@ struct IR_i2c {int (*get_key)(struct IR_i2c *ir,enum rc_proto *protocol,u32 *scancode,u8 *toggle); +/* tx */ +struct i2c_client *tx_c; +struct mutex lock;/* do not poll Rx during Tx */ +unsigned int carrier; +unsigned int duty_cycle; };enum ir_kbd_get_key_fn {
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 6/28 media: i2c: enable i2c IR for hardware which isn't HD-PVR
In reply to Sean YoungThis is a fix for commit 329d88da4df9 ("[media] media: i2c: Don't export ir-kbd-i2c module alias") that stopped the module from being loaded automagically.
The problems described only affect the HD-PVR, so it should not affect other hardware; also if the module happens to be loaded, the i2c IR part of the HD-PVR will be enabled anyway.
--- drivers/media/i2c/ir-kbd-i2c.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/media/i2c/ir-kbd-i2c.c +9 -0
@@ -63,6 +63,9 @@#define FLAG_TX 1#define FLAG_HDPVR 2 +static bool enable_hdpvr; +module_param (enable_hdpvr, bool,0644 ); +static int get_key_haup_common (struct IR_i2c *ir,enum rc_proto *protocol,u32 *scancode,u8 *ptoggle,int size) {
@@ -726,6 +729,11 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)unsigned short addr = client->addr;int err; +if ((id->driver_data &FLAG_HDPVR ) && !enable_hdpvr) { +dev_err (&client->dev,"IR for HDPVR is known to cause problems during recording, use enable_hdpvr modparam to enable\n" ); +return -ENODEV ; + } + ir =devm_kzalloc (&client->dev,sizeof (*ir),GFP_KERNEL );if (!ir)return -ENOMEM ;
@@ -925,6 +933,7 @@ static const struct i2c_device_id ir_kbd_id[] = { { "ir_z8f0811_hdpvr", FLAG_TX | FLAG_HDPVR }, { } }; +MODULE_DEVICE_TABLE(i2c, ir_kbd_id); static struct i2c_driver ir_kbd_driver = { .driver = {
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 7/28 media: staging: remove lirc_zilog driver
In reply to Sean YoungThe ir-kbd-i2c driver is functionally equivalent to the lirc_zilog driver.
The lirc_zilog driver only polls if the lirc chardev is opened; similarly the ir-kbd-i2c driver only polls if the corresponding input device is opened, or the lirc device.
Polling is disabled during IR transmission through the mutex.
The polling period is 402ms in the ir-kdb-i2c driver, and 260ms in the lirc_zilog driver.
--- drivers/staging/media/Kconfig | 3 - drivers/staging/media/Makefile | 1 - drivers/staging/media/lirc/Kconfig | 21 - drivers/staging/media/lirc/Makefile | 6 - drivers/staging/media/lirc/TODO | 36 - drivers/staging/media/lirc/lirc_zilog.c | 1653 ------------------------------- 6 files changed, 1720 deletions(-) delete mode 100644 drivers/staging/media/lirc/Kconfig delete mode 100644 drivers/staging/media/lirc/Makefile delete mode 100644 drivers/staging/media/lirc/TODO delete mode 100644 drivers/staging/media/lirc/lirc_zilog.c
drivers/staging/media/Kconfig +0 -3
@@ -31,7 +31,4 @@ source "drivers/staging/media/imx/Kconfig" source "drivers/staging/media/omap4iss/Kconfig" -# Keep LIRC at the end, as it has sub-menus -source "drivers/staging/media/lirc/Kconfig" - endif
drivers/staging/media/Makefile +0 -1
@@ -1,7 +1,6 @@ obj-$(CONFIG_I2C_BCM2048) += bcm2048/ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ -obj-$(CONFIG_LIRC_STAGING) += lirc/ obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_INTEL_ATOMISP) += atomisp/
drivers/staging/media/lirc/Kconfig deleted +0 -21
@@ -1,21 +0,0 @@ -# -# LIRC driver(s) configuration -# -menuconfig LIRC_STAGING - bool "Linux Infrared Remote Control IR receiver/transmitter drivers" - depends on LIRC - help - Say Y here, and all supported Linux Infrared Remote Control IR and - RF receiver and transmitter drivers will be displayed. When paired - with a remote control and the lirc daemon, the receiver drivers - allow control of your Linux system via remote control. - -if LIRC_STAGING - -config LIRC_ZILOG - tristate "Zilog/Hauppauge IR Transmitter" - depends on LIRC && I2C - help - Driver for the Zilog/Hauppauge IR Transmitter, found on - PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards -endif
drivers/staging/media/lirc/Makefile deleted +0 -6
@@ -1,6 +0,0 @@ -# Makefile for the lirc drivers. -# - -# Each configuration option enables a list of files. - -obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o
drivers/staging/media/lirc/TODO deleted +0 -36
@@ -1,36 +0,0 @@ -1. Both ir-kbd-i2c and lirc_zilog provide support for RX events for -the chips supported by lirc_zilog. Before moving lirc_zilog out of staging: - -a. ir-kbd-i2c needs a module parameter added to allow the user to tell - ir-kbd-i2c to ignore Z8 IR units. - -b. lirc_zilog should provide Rx key presses to the rc core like ir-kbd-i2c - does. - - -2. lirc_zilog module ref-counting need examination. It has not been -verified that cdev and lirc_dev will take the proper module references on -lirc_zilog to prevent removal of lirc_zilog when the /dev/lircN device node -is open. - -(The good news is ref-counting of lirc_zilog internal structures appears to be -complete. Testing has shown the cx18 module can be unloaded out from under -irw + lircd + lirc_dev, with the /dev/lirc0 device node open, with no adverse -effects. The cx18 module could then be reloaded and irw properly began -receiving button presses again and ir_send worked without error.) - - -3. Bridge drivers, if able, should provide a chip reset() callback -to lirc_zilog via struct IR_i2c_init_data. cx18 and ivtv already have routines -to perform Z8 chip resets via GPIO manipulations. This would allow lirc_zilog -to bring the chip back to normal when it hangs, in the same places the -original lirc_pvr150 driver code does. This is not strictly needed, so it -is not required to move lirc_zilog out of staging. - -Note: Both lirc_zilog and ir-kbd-i2c support the Zilog Z8 for IR, as programmed -and installed on Hauppauge products. When working on either module, developers -must consider at least the following bridge drivers which mention an IR Rx unit -at address 0x71 (indicative of a Z8): - - ivtv cx18 hdpvr pvrusb2 bt8xx cx88 saa7134 -
drivers/staging/media/lirc/lirc_zilog.c deleted +0 -1653
1,653 lines not on this page · raw message
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 8/28 media: MAINTAINERS: remove lirc staging area
In reply to Sean YoungNow that lirc is no longer in the staging area, remove the entry.
--- MAINTAINERS | 6 ------ 1 file changed, 6 deletions(-)
MAINTAINERS +0 -6
@@ -12712,12 +12712,6 @@ S: Odd Fixes F: Documentation/devicetree/bindings/staging/iio/ F: drivers/staging/iio/ -STAGING - LIRC (LINUX INFRARED REMOTE CONTROL) DRIVERS -M: Jarod Wilson <[email protected]> -W: http://www.lirc.org/ -S: Odd Fixes -F: drivers/staging/media/lirc/ - STAGING - LUSTRE PARALLEL FILESYSTEM M: Oleg Drokin <[email protected]> M: Andreas Dilger <[email protected]>
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 9/28 media: lirc: remove LIRCCODE and LIRC_GET_LENGTH
In reply to Sean YoungLIRCCODE is a lirc mode where a driver produces driver-dependent codes for receive and transmit. No driver uses this any more. The LIRC_GET_LENGTH ioctl was used for this mode only.
--- Documentation/media/lirc.h.rst.exceptions | 5 +++ Documentation/media/uapi/rc/lirc-dev-intro.rst | 15 -------- Documentation/media/uapi/rc/lirc-func.rst | 1 - Documentation/media/uapi/rc/lirc-get-features.rst | 7 +--- Documentation/media/uapi/rc/lirc-get-length.rst | 44 ---------------------- Documentation/media/uapi/rc/lirc-get-rec-mode.rst | 4 +- Documentation/media/uapi/rc/lirc-get-send-mode.rst | 3 +- drivers/media/rc/ir-lirc-codec.c | 1 - drivers/media/rc/lirc_dev.c | 12 ------ include/media/lirc_dev.h | 4 -- 10 files changed, 9 insertions(+), 87 deletions(-) delete mode 100644 Documentation/media/uapi/rc/lirc-get-length.rst
Documentation/media/lirc.h.rst.exceptions +5 -0
@@ -28,6 +28,10 @@ ignore define LIRC_CAN_SEND_MASK ignore define LIRC_CAN_REC_MASK ignore define LIRC_CAN_SET_REC_DUTY_CYCLE +# Obsolete ioctls + +ignore ioctl LIRC_GET_LENGTH + # Undocumented macros ignore define PULSE_BIT
@@ -40,3 +44,4 @@ ignore define LIRC_VALUE_MASK ignore define LIRC_MODE2_MASK ignore define LIRC_MODE_RAW +ignore define LIRC_MODE_LIRCCODE
Documentation/media/uapi/rc/lirc-dev-intro.rst +0 -15
@@ -72,21 +72,6 @@ on the following table. this packet will be sent, with the number of microseconds with no IR. -.. _lirc-mode-lirccode: - -``LIRC_MODE_LIRCCODE`` - - This mode can be used for IR receive and send. - - The IR signal is decoded internally by the receiver, or encoded by the - transmitter. The LIRC interface represents the scancode as byte string, - which might not be a u32, it can be any length. The value is entirely - driver dependent. This mode is used by some older lirc drivers. - - The length of each code depends on the driver, which can be retrieved - with :ref:`lirc_get_length`. This length is used both - for transmitting and receiving IR. - .. _lirc-mode-pulse: ``LIRC_MODE_PULSE``
Documentation/media/uapi/rc/lirc-func.rst +0 -1
@@ -18,7 +18,6 @@ LIRC Function Reference lirc-set-send-duty-cycle lirc-get-timeout lirc-set-rec-timeout - lirc-get-length lirc-set-rec-carrier lirc-set-rec-carrier-range lirc-set-send-carrier
Documentation/media/uapi/rc/lirc-get-features.rst +2 -5
@@ -62,8 +62,7 @@ LIRC features ``LIRC_CAN_REC_LIRCCODE`` - The driver is capable of receiving using - :ref:`LIRC_MODE_LIRCCODE <lirc-mode-LIRCCODE>`. + Unused. Kept just to avoid breaking uAPI. .. _LIRC-CAN-SET-SEND-CARRIER:
@@ -170,9 +169,7 @@ LIRC features ``LIRC_CAN_SEND_LIRCCODE`` - The driver supports sending (also called as IR blasting or IR TX) using - :ref:`LIRC_MODE_LIRCCODE <lirc-mode-LIRCCODE>`. - + Unused. Kept just to avoid breaking uAPI. Return Value ============
Documentation/media/uapi/rc/lirc-get-length.rst deleted +0 -44
44 lines not on this page · raw message
Documentation/media/uapi/rc/lirc-get-rec-mode.rst +1 -3
@@ -34,9 +34,7 @@ Description =========== Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>` -and :ref:`LIRC_MODE_LIRCCODE <lirc-mode-lirccode>` are supported for IR -receive. Use :ref:`lirc_get_features` to find out which modes the driver -supports. +is supported for IR receive. Return Value ============
Documentation/media/uapi/rc/lirc-get-send-mode.rst +1 -2
@@ -36,8 +36,7 @@ Description Get/set current transmit mode. -Only :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>` and -:ref:`LIRC_MODE_LIRCCODE <lirc-mode-lirccode>` is supported by for IR send, +Only :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>` is supported by for IR send, depending on the driver. Use :ref:`lirc_get_features` to find out which modes the driver supports.
drivers/media/rc/ir-lirc-codec.c +0 -1
@@ -388,7 +388,6 @@ static int ir_lirc_register(struct rc_dev *dev) ldev->features = features; ldev->data = &dev->raw->lirc; ldev->buf =NULL ; - ldev->code_length =sizeof (struct ir_raw_event ) *8 ; ldev->chunk_size =sizeof (int ); ldev->buffer_size =LIRCBUF_SIZE ; ldev->fops = &lirc_fops;
drivers/media/rc/lirc_dev.c +0 -12
@@ -137,12 +137,6 @@ int lirc_register_device(struct lirc_dev *d)return -EINVAL ; } -if (d->code_length <1 || d->code_length > (BUFLEN *8 )) { -dev_err (&d->dev,"code length must be less than %d bits\n" , -BUFLEN *8 ); -return -EBADRQC ; - } -if (!d->buf && !(d->fops && d->fops->read && d->fops->poll && d->fops->unlocked_ioctl)) {dev_err (&d->dev,"undefined read, poll, ioctl\n" );
@@ -152,9 +146,6 @@ int lirc_register_device(struct lirc_dev *d)/* some safety check 8-) */ d->name[sizeof (d->name) -1 ] ='\0' ; -if (d->features ==0 ) - d->features =LIRC_CAN_REC_LIRCCODE ; -if (LIRC_CAN_REC (d->features)) { err =lirc_allocate_buffer (d);if (err)
@@ -343,9 +334,6 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)* for now, lirc_serial doesn't support mode changing either */ break ; -case LIRC_GET_LENGTH : - result =put_user (d->code_length, (__u32 __user *)arg); -break ;default : result = -ENOTTY ; }
include/media/lirc_dev.h +0 -4
@@ -9,8 +9,6 @@#ifndef _LINUX_LIRC_DEV_H#define _LINUX_LIRC_DEV_H -#define BUFLEN 16 -#include <linux/slab.h> #include <linux/fs.h> #include <linux/ioctl.h>
@@ -117,7 +115,6 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf,* * @name: used for logging * @minor: the minor device (/dev/lircX) number for the device -* @code_length: length of a remote control key code expressed in bits * @features: lirc compatible hardware features, like LIRC_MODE_RAW, * LIRC_CAN\_\*, as defined at include/media/lirc.h. * @buffer_size: Number of FIFO buffers with @chunk_size size.
@@ -142,7 +139,6 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf,struct lirc_dev {char name[40 ];unsigned int minor; -__u32 code_length;__u32 features;unsigned int buffer_size;/* in chunks holding one code each */
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 10/28 media: lirc: implement scancode sending
In reply to Sean YoungThis introduces a new lirc mode: scancode. Any device which can send raw IR can now also send scancodes.
int main()
{
int mode, fd = open("/dev/lirc0", O_RDWR);
mode = LIRC_MODE_SCANCODE;
if (ioctl(fd, LIRC_SET_SEND_MODE, &mode)) {
// kernel too old or lirc does not support transmit
}
struct lirc_scancode scancode = {
.scancode = 0x1e3d,
.rc_proto = RC_PROTO_RC5,
};
write(fd, &scancode, sizeof(scancode));
close(fd);
}The other fields of lirc_scancode must be set to 0.
Note that toggle (rc5, rc6) and repeats (nec) are not implemented. Nor is there a method for holding down a key for a period.
--- drivers/media/rc/ir-lirc-codec.c | 99 +++++++++++++++++++++++++++++----------- drivers/media/rc/rc-core-priv.h | 2 +- include/media/rc-map.h | 54 +--------------------- include/uapi/linux/lirc.h | 82 +++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 81 deletions(-)
drivers/media/rc/ir-lirc-codec.c +72 -27
@@ -107,7 +107,8 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, {struct lirc_codec *lirc;struct rc_dev *dev; -unsigned int *txbuf;/* buffer with values to transmit */ +unsigned int *txbuf =NULL ; +struct ir_raw_event *raw =NULL ;ssize_t ret = -EINVAL ;size_t count;ktime_t start;
@@ -121,16 +122,50 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,if (!lirc)return -EFAULT ; -if (n <sizeof (unsigned ) || n %sizeof (unsigned )) -return -EINVAL ; +if (lirc->send_mode ==LIRC_MODE_SCANCODE ) { +struct lirc_scancode scan; - count = n /sizeof (unsigned ); -if (count >LIRCBUF_SIZE || count %2 ==0 ) -return -EINVAL ; +if (n !=sizeof (scan)) +return -EINVAL ; - txbuf =memdup_user (buf, n); -if (IS_ERR (txbuf)) -return PTR_ERR (txbuf); +if (copy_from_user (&scan, buf,sizeof (scan))) +return -EFAULT ; + +if (scan.flags || scan.keycode || scan.timestamp) +return -EINVAL ; + + raw =kmalloc_array (LIRCBUF_SIZE ,sizeof (*raw),GFP_KERNEL ); +if (!raw) +return -ENOMEM ; + + ret =ir_raw_encode_scancode (scan.rc_proto, scan.scancode, + raw,LIRCBUF_SIZE ); +if (ret <0 ) + goto out; + + count = ret; + + txbuf =kmalloc_array (count,sizeof (unsigned int ),GFP_KERNEL ); +if (!txbuf) { + ret = -ENOMEM ; + goto out; + } + +for (i =0 ; i < count; i++) +/* Convert from NS to US */ + txbuf[i] =DIV_ROUND_UP (raw[i].duration,1000 ); + }else { +if (n <sizeof (unsigned int ) || n %sizeof (unsigned int )) +return -EINVAL ; + + count = n /sizeof (unsigned int ); +if (count >LIRCBUF_SIZE || count %2 ==0 ) +return -EINVAL ; + + txbuf =memdup_user (buf, n); +if (IS_ERR (txbuf)) +return PTR_ERR (txbuf); + } dev = lirc->dev;if (!dev) {
@@ -156,24 +191,30 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,if (ret <0 ) goto out; -for (duration = i =0 ; i < ret; i++) - duration += txbuf[i]; - - ret *=sizeof (unsigned int ); - -/* -* The lircd gap calculation expects the write function to -* wait for the actual IR signal to be transmitted before -* returning. -*/ - towait =ktime_us_delta (ktime_add_us (start, duration),ktime_get ()); -if (towait >0 ) { -set_current_state (TASK_INTERRUPTIBLE ); -schedule_timeout (usecs_to_jiffies (towait)); +if (lirc->send_mode ==LIRC_MODE_SCANCODE ) { + ret = n; + }else { +for (duration = i =0 ; i < ret; i++) + duration += txbuf[i]; + + ret *=sizeof (unsigned int ); + +/* +* The lircd gap calculation expects the write function to +* wait for the actual IR signal to be transmitted before +* returning. +*/ + towait =ktime_us_delta (ktime_add_us (start, duration), +ktime_get ()); +if (towait >0 ) { +set_current_state (TASK_INTERRUPTIBLE ); +schedule_timeout (usecs_to_jiffies (towait)); + } } out:kfree (txbuf); +kfree (raw);return ret; }
@@ -202,20 +243,22 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,switch (cmd) { -/* legacy support */ +/* mode support */ case LIRC_GET_SEND_MODE :if (!dev->tx_ir)return -ENOTTY ; - val =LIRC_MODE_PULSE ; + val = lirc->send_mode;break ;case LIRC_SET_SEND_MODE :if (!dev->tx_ir)return -ENOTTY ; -if (val !=LIRC_MODE_PULSE ) +if (!(val ==LIRC_MODE_PULSE || val ==LIRC_MODE_SCANCODE ))return -EINVAL ; + + lirc->send_mode = val;return 0 ;/* TX settings */
@@ -361,7 +404,7 @@ static int ir_lirc_register(struct rc_dev *dev) }if (dev->tx_ir) { - features |=LIRC_CAN_SEND_PULSE ; + features |=LIRC_CAN_SEND_PULSE |LIRC_CAN_SEND_SCANCODE ;if (dev->s_tx_mask) features |=LIRC_CAN_SET_TRANSMITTER_MASK ;if (dev->s_tx_carrier)
@@ -399,6 +442,8 @@ static int ir_lirc_register(struct rc_dev *dev)if (rc <0 ) goto out; + dev->raw->lirc.send_mode =LIRC_MODE_PULSE ; + dev->raw->lirc.ldev = ldev; dev->raw->lirc.dev = dev;return 0 ;
drivers/media/rc/rc-core-priv.h +1 -1
@@ -113,7 +113,7 @@ struct ir_raw_event_ctrl {u64 gap_duration;bool gap;bool send_timeout_reports; - +u8 send_mode; } lirc;struct xmp_dec {int state;
include/media/rc-map.h +1 -53
60 lines not on this page · raw message
include/uapi/linux/lirc.h +82 -0
104 lines not on this page · raw message
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 11/28 media: lirc: use the correct carrier for scancode transmit
In reply to Sean YoungIf the lirc device supports it, set the carrier for the protocol.
--- drivers/media/rc/ir-jvc-decoder.c | 1 + drivers/media/rc/ir-lirc-codec.c | 29 ++++++++++++++++++----------- drivers/media/rc/ir-mce_kbd-decoder.c | 1 + drivers/media/rc/ir-nec-decoder.c | 1 + drivers/media/rc/ir-rc5-decoder.c | 1 + drivers/media/rc/ir-rc6-decoder.c | 1 + drivers/media/rc/ir-sanyo-decoder.c | 1 + drivers/media/rc/ir-sharp-decoder.c | 1 + drivers/media/rc/ir-sony-decoder.c | 1 + drivers/media/rc/rc-core-priv.h | 1 + drivers/media/rc/rc-ir-raw.c | 30 ++++++++++++++++++++++++++++++ include/media/rc-core.h | 1 + 12 files changed, 58 insertions(+), 11 deletions(-)
drivers/media/rc/ir-jvc-decoder.c +1 -0
@@ -212,6 +212,7 @@ static struct ir_raw_handler jvc_handler = { .protocols = RC_PROTO_BIT_JVC, .decode = ir_jvc_decode, .encode = ir_jvc_encode, + .carrier = 38000, };static int __init ir_jvc_decode_init (void )
drivers/media/rc/ir-lirc-codec.c +18 -11
@@ -122,6 +122,17 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,if (!lirc)return -EFAULT ; + dev = lirc->dev; +if (!dev) { + ret = -EFAULT ; + goto out; + } + +if (!dev->tx_ir) { + ret = -EINVAL ; + goto out; + } +if (lirc->send_mode ==LIRC_MODE_SCANCODE ) {struct lirc_scancode scan;
@@ -154,6 +165,13 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,for (i =0 ; i < count; i++)/* Convert from NS to US */ txbuf[i] =DIV_ROUND_UP (raw[i].duration,1000 ); + +if (dev->s_tx_carrier) { +int carrier =ir_raw_encode_carrier (scan.rc_proto); + +if (carrier >0 ) + dev->s_tx_carrier (dev, carrier); + } }else {if (n <sizeof (unsigned int ) || n %sizeof (unsigned int ))return -EINVAL ;
@@ -167,17 +185,6 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,return PTR_ERR (txbuf); } - dev = lirc->dev; -if (!dev) { - ret = -EFAULT ; - goto out; - } - -if (!dev->tx_ir) { - ret = -EINVAL ; - goto out; - } -for (i =0 ; i < count; i++) {if (txbuf[i] >IR_MAX_DURATION /1000 - duration || !txbuf[i]) { ret = -EINVAL ;
drivers/media/rc/ir-mce_kbd-decoder.c +1 -0
@@ -474,6 +474,7 @@ static struct ir_raw_handler mce_kbd_handler = { .encode = ir_mce_kbd_encode, .raw_register = ir_mce_kbd_register, .raw_unregister = ir_mce_kbd_unregister, + .carrier = 36000, };static int __init ir_mce_kbd_decode_init (void )
drivers/media/rc/ir-nec-decoder.c +1 -0
@@ -264,6 +264,7 @@ static struct ir_raw_handler nec_handler = { RC_PROTO_BIT_NEC32, .decode = ir_nec_decode, .encode = ir_nec_encode, + .carrier = 38000, };static int __init ir_nec_decode_init (void )
drivers/media/rc/ir-rc5-decoder.c +1 -0
@@ -282,6 +282,7 @@ static struct ir_raw_handler rc5_handler = { RC_PROTO_BIT_RC5_SZ, .decode = ir_rc5_decode, .encode = ir_rc5_encode, + .carrier = 36000, };static int __init ir_rc5_decode_init (void )
drivers/media/rc/ir-rc6-decoder.c +1 -0
@@ -408,6 +408,7 @@ static struct ir_raw_handler rc6_handler = { RC_PROTO_BIT_RC6_MCE, .decode = ir_rc6_decode, .encode = ir_rc6_encode, + .carrier = 36000, };static int __init ir_rc6_decode_init (void )
drivers/media/rc/ir-sanyo-decoder.c +1 -0
@@ -218,6 +218,7 @@ static struct ir_raw_handler sanyo_handler = { .protocols = RC_PROTO_BIT_SANYO, .decode = ir_sanyo_decode, .encode = ir_sanyo_encode, + .carrier = 38000, };static int __init ir_sanyo_decode_init (void )
drivers/media/rc/ir-sharp-decoder.c +1 -0
@@ -226,6 +226,7 @@ static struct ir_raw_handler sharp_handler = { .protocols = RC_PROTO_BIT_SHARP, .decode = ir_sharp_decode, .encode = ir_sharp_encode, + .carrier = 38000, };static int __init ir_sharp_decode_init (void )
drivers/media/rc/ir-sony-decoder.c +1 -0
@@ -221,6 +221,7 @@ static struct ir_raw_handler sony_handler = { RC_PROTO_BIT_SONY20, .decode = ir_sony_decode, .encode = ir_sony_encode, + .carrier = 40000, };static int __init ir_sony_decode_init (void )
drivers/media/rc/rc-core-priv.h +1 -0
@@ -29,6 +29,7 @@ struct ir_raw_handler {int (*decode)(struct rc_dev *dev,struct ir_raw_event event);int (*encode)(enum rc_proto protocol,u32 scancode,struct ir_raw_event *events,unsigned int max); +u32 carrier;/* These two should only be used by the lirc decoder */ int (*raw_register)(struct rc_dev *dev);
drivers/media/rc/rc-ir-raw.c +30 -0
@@ -492,6 +492,36 @@ static void edge_handle(unsigned long arg)ir_raw_event_handle (dev); } +/** +* ir_raw_encode_carrier() - Get carrier used for protocol +* +* @protocol: protocol +* +* Attempts to find the carrier for the specified protocol +* +* Returns: The carrier in Hz +* -EINVAL if the protocol is invalid, or if no +* compatible encoder was found. +*/ +int ir_raw_encode_carrier (enum rc_proto protocol) +{ +struct ir_raw_handler *handler; +int ret = -EINVAL ; +u64 mask =BIT_ULL (protocol); + +mutex_lock (&ir_raw_handler_lock); +list_for_each_entry (handler, &ir_raw_handler_list, list) { +if (handler->protocols & mask && handler->encode) { + ret = handler->carrier; +break ; + } + } +mutex_unlock (&ir_raw_handler_lock); + +return ret; +} +EXPORT_SYMBOL (ir_raw_encode_carrier); +/* * Used to (un)register raw event clients */
include/media/rc-core.h +1 -0
@@ -309,6 +309,7 @@ int ir_raw_event_store_with_filter(struct rc_dev *dev,void ir_raw_event_set_idle (struct rc_dev *dev,bool idle);int ir_raw_encode_scancode (enum rc_proto protocol,u32 scancode,struct ir_raw_event *events,unsigned int max); +int ir_raw_encode_carrier (enum rc_proto protocol);static inline void ir_raw_event_reset (struct rc_dev *dev) {
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 12/28 media: rc: auto load encoder if necessary
In reply to Sean YoungWhen sending scancodes, load the encoder if we need it.
--- drivers/media/rc/rc-core-priv.h | 1 + drivers/media/rc/rc-ir-raw.c | 2 ++ drivers/media/rc/rc-main.c | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-)
drivers/media/rc/rc-core-priv.h +1 -0
@@ -271,6 +271,7 @@ void ir_raw_event_free(struct rc_dev *dev);void ir_raw_event_unregister (struct rc_dev *dev);int ir_raw_handler_register (struct ir_raw_handler *ir_raw_handler);void ir_raw_handler_unregister (struct ir_raw_handler *ir_raw_handler); +void ir_raw_load_modules (u64 *protocols);void ir_raw_init (void );/*
drivers/media/rc/rc-ir-raw.c +2 -0
@@ -457,6 +457,8 @@ int ir_raw_encode_scancode(enum rc_proto protocol, u32 scancode,int ret = -EINVAL ;u64 mask =1ULL << protocol; +ir_raw_load_modules (&mask); +mutex_lock (&ir_raw_handler_lock);list_for_each_entry (handler, &ir_raw_handler_list, list) {if (handler->protocols & mask && handler->encode) {
drivers/media/rc/rc-main.c +1 -1
@@ -1081,7 +1081,7 @@ static int parse_protocol_change(u64 *protocols, const char *buf)return count; } -static void ir_raw_load_modules (u64 *protocols) +void ir_raw_load_modules (u64 *protocols) {u64 available;int i, ret;
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 13/28 media: lirc: lirc interface should not be a raw decoder
In reply to Sean YoungThe lirc user interface exists as a raw decoder, which does not make much sense for transmit-only devices.
In addition, we want to have lirc char devices for devices which do not use raw IR, i.e. scancode only devices.
Note that rc-code, lirc_dev, ir-lirc-codec are now calling functions of each other, so they've been merged into one module rc-core to avoid circular dependencies.
Since ir-lirc-codec no longer exists as separate codec module, there is no need for RC_DRIVER_IR_RAW_TX type drivers to call ir_raw_event_register().
--- drivers/media/rc/Kconfig | 29 ++----- drivers/media/rc/Makefile | 5 +- drivers/media/rc/ir-lirc-codec.c | 137 +++++++++------------------------- drivers/media/rc/ir-mce_kbd-decoder.c | 6 -- drivers/media/rc/lirc_dev.c | 47 ++++-------- drivers/media/rc/rc-core-priv.h | 45 ++++++++--- drivers/media/rc/rc-ir-raw.c | 24 ++---- drivers/media/rc/rc-main.c | 52 ++++++------- include/media/lirc_dev.h | 10 --- include/media/rc-core.h | 33 ++++---- 10 files changed, 144 insertions(+), 244 deletions(-)
drivers/media/rc/Kconfig +8 -21
@@ -16,34 +16,21 @@ menuconfig RC_CORE if RC_CORE source "drivers/media/rc/keymaps/Kconfig" -menuconfig RC_DECODERS - bool "Remote controller decoders" - depends on RC_CORE - default y - -if RC_DECODERS config LIRC - tristate "LIRC interface driver" + bool "LIRC user interface" depends on RC_CORE - ---help--- - Enable this option to build the Linux Infrared Remote - Control (LIRC) core device interface driver. The LIRC - interface passes raw IR to and from userspace, where the - LIRC daemon handles protocol decoding for IR reception and - encoding for IR transmitting (aka "blasting"). + Enable this option to enable the Linux Infrared Remote + Control user interface (e.g. /dev/lirc*). This interface + passes raw IR to and from userspace, which is needed for + IR transmitting (aka "blasting") and for the lirc daemon. -config IR_LIRC_CODEC - tristate "Enable IR to LIRC bridge" +menuconfig RC_DECODERS + bool "Remote controller decoders" depends on RC_CORE - depends on LIRC default y - ---help--- - Enable this option to pass raw IR to and from userspace via - the LIRC interface. - - +if RC_DECODERS config IR_NEC_DECODER tristate "Enable IR raw decoder for the NEC protocol" depends on RC_CORE
drivers/media/rc/Makefile +2 -3
@@ -1,9 +1,9 @@ -rc-core-objs := rc-main.o rc-ir-raw.o obj-y += keymaps/ obj-$(CONFIG_RC_CORE) += rc-core.o -obj-$(CONFIG_LIRC) += lirc_dev.o +rc-core-y := rc-main.o rc-ir-raw.o +rc-core-$(CONFIG_LIRC) += lirc_dev.o ir-lirc-codec.o obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
@@ -12,7 +12,6 @@ obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o -obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o # stand-alone IR receivers/transmitters
drivers/media/rc/ir-lirc-codec.c +37 -100
267 lines not on this page · raw message
drivers/media/rc/ir-mce_kbd-decoder.c +0 -6
@@ -358,9 +358,6 @@ static int ir_mce_kbd_register(struct rc_dev *dev)struct input_dev *idev;int i, ret; -if (dev->driver_type ==RC_DRIVER_IR_RAW_TX ) -return 0 ; - idev =input_allocate_device ();if (!idev)return -ENOMEM ;
@@ -416,9 +413,6 @@ static int ir_mce_kbd_unregister(struct rc_dev *dev)struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd;struct input_dev *idev = mce_kbd->idev; -if (dev->driver_type ==RC_DRIVER_IR_RAW_TX ) -return 0 ; -del_timer_sync (&mce_kbd->rx_timeout);input_unregister_device (idev);
drivers/media/rc/lirc_dev.c +13 -34
99 lines not on this page · raw message
drivers/media/rc/rc-core-priv.h +33 -12
69 lines not on this page · raw message
drivers/media/rc/rc-ir-raw.c +5 -19
@@ -40,6 +40,7 @@ static int ir_raw_event_thread(void *data)if (raw->dev->enabled_protocols & handler->protocols || !handler->protocols) handler->decode (raw->dev, ev); +ir_lirc_raw_event (raw->dev, ev); raw->prev_ev = ev; }mutex_unlock (&ir_raw_handler_lock);
@@ -529,16 +530,9 @@ EXPORT_SYMBOL(ir_raw_encode_carrier);*/ int ir_raw_event_prepare (struct rc_dev *dev) { -static bool raw_init;/* 'false' default value, raw decoders loaded? */ -if (!dev)return -EINVAL ; -if (!raw_init) { -request_module ("ir-lirc-codec" ); - raw_init = true; - } - dev->raw =kzalloc (sizeof (*dev->raw),GFP_KERNEL );if (!dev->raw)return -ENOMEM ;
@@ -557,19 +551,11 @@ int ir_raw_event_register(struct rc_dev *dev)struct ir_raw_handler *handler;struct task_struct *thread; -/* -* raw transmitters do not need any event registration -* because the event is coming from userspace -*/ -if (dev->driver_type !=RC_DRIVER_IR_RAW_TX ) { - thread =kthread_run (ir_raw_event_thread, dev->raw,"rc%u" , - dev->minor); + thread =kthread_run (ir_raw_event_thread, dev->raw,"rc%u" , dev->minor); +if (IS_ERR (thread)) +return PTR_ERR (thread); -if (IS_ERR (thread)) -return PTR_ERR (thread); - - dev->raw->thread = thread; - } + dev->raw->thread = thread;mutex_lock (&ir_raw_handler_lock);list_add_tail (&dev->raw->list, &ir_raw_client_list);
drivers/media/rc/rc-main.c +27 -25
117 lines not on this page · raw message
include/media/lirc_dev.h +0 -10
@@ -121,7 +121,6 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf,* Only used if @rbuf is NULL. * @chunk_size: Size of each FIFO buffer. * Only used if @rbuf is NULL. -* @data: private per-driver data * @buf: if %NULL, lirc_dev will allocate and manage the buffer, * otherwise allocated by the caller which will * have to write to the buffer by other means, like irq's
@@ -146,7 +145,6 @@ struct lirc_dev {struct lirc_buffer *buf;bool buf_internal; -void *data;struct rc_dev *rdev;const struct file_operations *fops;struct module *owner;
@@ -168,14 +166,6 @@ int lirc_register_device(struct lirc_dev *d);void lirc_unregister_device (struct lirc_dev *d); -/* Must be called in the open fop before lirc_get_pdata() can be used */ -void lirc_init_pdata (struct inode *inode,struct file *file); - -/* Returns the private data stored in the lirc_dev -* associated with the given device file pointer. -*/ -void *lirc_get_pdata (struct file *file); -/* default file operations * used by drivers if they override only some operations */
include/media/rc-core.h +19 -14
@@ -20,6 +20,7 @@#include <linux/kfifo.h> #include <linux/time.h> #include <linux/timer.h> +#include <media/lirc_dev.h> #include <media/rc-map.h> extern int rc_core_debug;
@@ -115,6 +116,15 @@ enum rc_filter_type {* @max_timeout: maximum timeout supported by device * @rx_resolution : resolution (in ns) of input sampler * @tx_resolution: resolution (in ns) of output sampler +* @lirc_dev: lirc char device +* @carrier_low: when setting the carrier range, first the low end must be +* set with an ioctl and then the high end with another ioctl +* @gap_start: time when gap starts +* @gap_duration: duration of initial gap +* @gap: true if we're in a gap +* @send_timeout_reports: report timeouts in lirc raw IR. +* @send_mode: lirc mode for sending, either LIRC_MODE_SCANCODE or +* LIRC_MODE_PULSE * @change_protocol: allow changing the protocol used on hardware decoders * @open: callback to allow drivers to enable polling/irq when IR input device * is opened.
@@ -174,6 +184,15 @@ struct rc_dev {u32 max_timeout;u32 rx_resolution;u32 tx_resolution; +#ifdef CONFIG_LIRC +struct lirc_dev *lirc_dev; +int carrier_low; +ktime_t gap_start; +u64 gap_duration; +bool gap; +bool send_timeout_reports; +u8 send_mode; +#endif int (*change_protocol)(struct rc_dev *dev,u64 *rc_proto);int (*open)(struct rc_dev *dev);void (*close)(struct rc_dev *dev);
@@ -248,20 +267,6 @@ int devm_rc_register_device(struct device *parent, struct rc_dev *dev);*/ void rc_unregister_device (struct rc_dev *dev); -/** -* rc_open - Opens a RC device -* -* @rdev: pointer to struct rc_dev. -*/ -int rc_open (struct rc_dev *rdev); - -/** -* rc_close - Closes a RC device -* -* @rdev: pointer to struct rc_dev. -*/ -void rc_close (struct rc_dev *rdev); -void rc_repeat (struct rc_dev *dev);void rc_keydown (struct rc_dev *dev,enum rc_proto protocol,u32 scancode,u8 toggle);
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 14/28 media: lirc: validate scancode for transmit
In reply to Sean YoungEnsure we reject an attempt to transmit invalid scancodes.
--- drivers/media/rc/ir-lirc-codec.c | 10 ++++++++ drivers/media/rc/rc-core-priv.h | 1 + drivers/media/rc/rc-main.c | 53 +++++++++++++++++++++++++--------------- 3 files changed, 44 insertions(+), 20 deletions(-)
drivers/media/rc/ir-lirc-codec.c +10 -0
@@ -126,6 +126,16 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,if (scan.flags || scan.keycode || scan.timestamp)return -EINVAL ; +/* +* The scancode field in lirc_scancode is 64-bit simply +* to future-proof it, since there are IR protocols encode +* use more than 32 bits. For now only 32-bit protocols +* are supported. +*/ +if (scan.scancode >U32_MAX || + !rc_validate_scancode (scan.rc_proto, scan.scancode)) +return -EINVAL ; + raw =kmalloc_array (LIRCBUF_SIZE ,sizeof (*raw),GFP_KERNEL );if (!raw)return -ENOMEM ;
drivers/media/rc/rc-core-priv.h +1 -0
@@ -160,6 +160,7 @@ static inline bool is_timing_event(struct ir_raw_event ev)#define TO_STR (is_pulse) ((is_pulse) ? "pulse" : "space")/* functions for IR encoders */ +bool rc_validate_scancode (enum rc_proto proto,u32 scancode); static inline void init_ir_raw_event_duration(struct ir_raw_event *ev, unsigned int pulse,
drivers/media/rc/rc-main.c +33 -20
65 lines not on this page · raw message
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 15/28 media: rc: document and fix rc_validate_scancode()
In reply to Sean YoungFor some IR protocols, some scancode values not valid, i.e. they're part of a different protocol variant.
--- drivers/media/rc/rc-main.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
drivers/media/rc/rc-main.c +16 -2
@@ -776,21 +776,35 @@ void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol,EXPORT_SYMBOL_GPL (rc_keydown_notimeout);/** -* rc_validate_scancode() - checks that a scancode is valid for a protocol +* rc_validate_scancode() - checks that a scancode is valid for a protocol. +* For nec, it should do the opposite of ir_nec_bytes_to_scancode() * @proto: protocol * @scancode: scancode */ bool rc_validate_scancode (enum rc_proto proto,u32 scancode) {switch (proto) { +/* +* NECX has a 16-bit address; if the lower 8 bits match the upper +* 8 bits inverted, then the address would match regular nec. +*/ case RC_PROTO_NECX :if ((((scancode >>16 ) ^ ~(scancode >>8 )) &0xff ) ==0 )return false;break ; +/* +* NEC32 has a 16 bit address and 16 bit command. If the lower 8 bits +* of the command match the upper 8 bits inverted, then it would +* be either NEC or NECX. +*/ case RC_PROTO_NEC32 : -if ((((scancode >>24 ) ^ ~(scancode >>16 )) &0xff ) ==0 ) +if ((((scancode >>8 ) ^ ~scancode) &0xff ) ==0 )return false;break ; +/* +* If the customer code (top 32-bit) is 0x800f, it is MCE else it +* is regular mode-6a 32 bit +*/ case RC_PROTO_RC6_MCE :if ((scancode &0xffff0000 ) !=0x800f0000 )return false;
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 16/28 media: lirc: merge lirc_dev_fop_ioctl and ir_lirc_ioctl
In reply to Sean YoungCalculate lirc features when necessary, and add LIRC_{S,G}ET_REC_MODE cases to ir_lirc_ioctl.
This makes lirc_dev_fop_ioctl() unnecessary since all cases are already handled by ir_lirc_ioctl().
--- drivers/media/rc/ir-lirc-codec.c | 79 ++++++++++++++++++++++++---------------- drivers/media/rc/lirc_dev.c | 62 ++----------------------------- include/media/lirc_dev.h | 4 -- 3 files changed, 50 insertions(+), 95 deletions(-)
drivers/media/rc/ir-lirc-codec.c +47 -32
@@ -231,8 +231,54 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, }switch (cmd) { +case LIRC_GET_FEATURES : +if (dev->driver_type ==RC_DRIVER_IR_RAW ) { + val |=LIRC_CAN_REC_MODE2 ; +if (dev->rx_resolution) + val |=LIRC_CAN_GET_REC_RESOLUTION ; + } + +if (dev->tx_ir) { + val |=LIRC_CAN_SEND_PULSE |LIRC_CAN_SEND_SCANCODE ; +if (dev->s_tx_mask) + val |=LIRC_CAN_SET_TRANSMITTER_MASK ; +if (dev->s_tx_carrier) + val |=LIRC_CAN_SET_SEND_CARRIER ; +if (dev->s_tx_duty_cycle) + val |=LIRC_CAN_SET_SEND_DUTY_CYCLE ; + } + +if (dev->s_rx_carrier_range) + val |=LIRC_CAN_SET_REC_CARRIER | +LIRC_CAN_SET_REC_CARRIER_RANGE ; + +if (dev->s_learning_mode) + val |=LIRC_CAN_USE_WIDEBAND_RECEIVER ; + +if (dev->s_carrier_report) + val |=LIRC_CAN_MEASURE_CARRIER ; + +if (dev->max_timeout) + val |=LIRC_CAN_SET_REC_TIMEOUT ; + +break ;/* mode support */ +case LIRC_GET_REC_MODE : +if (dev->driver_type ==RC_DRIVER_IR_RAW_TX ) +return -ENOTTY ; + + val =LIRC_MODE_MODE2 ; +break ; + +case LIRC_SET_REC_MODE : +if (dev->driver_type ==RC_DRIVER_IR_RAW_TX ) +return -ENOTTY ; + +if (val !=LIRC_MODE_MODE2 ) +return -EINVAL ; +return 0 ; +case LIRC_GET_SEND_MODE :if (!dev->tx_ir)return -ENOTTY ;
@@ -353,7 +399,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,break ;default : -return lirc_dev_fop_ioctl (filep, cmd, arg); +return -ENOTTY ; }if (_IOC_DIR (cmd) & _IOC_READ)
@@ -380,44 +426,13 @@ int ir_lirc_register(struct rc_dev *dev) {struct lirc_dev *ldev;int rc = -ENOMEM ; -unsigned long features =0 ; ldev =lirc_allocate_device ();if (!ldev)return rc; -if (dev->driver_type !=RC_DRIVER_IR_RAW_TX ) { - features |=LIRC_CAN_REC_MODE2 ; -if (dev->rx_resolution) - features |=LIRC_CAN_GET_REC_RESOLUTION ; - } - -if (dev->tx_ir) { - features |=LIRC_CAN_SEND_PULSE |LIRC_CAN_SEND_SCANCODE ; -if (dev->s_tx_mask) - features |=LIRC_CAN_SET_TRANSMITTER_MASK ; -if (dev->s_tx_carrier) - features |=LIRC_CAN_SET_SEND_CARRIER ; -if (dev->s_tx_duty_cycle) - features |=LIRC_CAN_SET_SEND_DUTY_CYCLE ; - } - -if (dev->s_rx_carrier_range) - features |=LIRC_CAN_SET_REC_CARRIER | -LIRC_CAN_SET_REC_CARRIER_RANGE ; - -if (dev->s_learning_mode) - features |=LIRC_CAN_USE_WIDEBAND_RECEIVER ; - -if (dev->s_carrier_report) - features |=LIRC_CAN_MEASURE_CARRIER ; - -if (dev->max_timeout) - features |=LIRC_CAN_SET_REC_TIMEOUT ; -snprintf (ldev->name,sizeof (ldev->name),"ir-lirc-codec (%s)" , dev->driver_name); - ldev->features = features; ldev->buf =NULL ; ldev->chunk_size =sizeof (int ); ldev->buffer_size =LIRCBUF_SIZE ;
drivers/media/rc/lirc_dev.c +3 -59
86 lines not on this page · raw message
include/media/lirc_dev.h +0 -4
@@ -115,8 +115,6 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf,* * @name: used for logging * @minor: the minor device (/dev/lircX) number for the device -* @features: lirc compatible hardware features, like LIRC_MODE_RAW, -* LIRC_CAN\_\*, as defined at include/media/lirc.h. * @buffer_size: Number of FIFO buffers with @chunk_size size. * Only used if @rbuf is NULL. * @chunk_size: Size of each FIFO buffer.
@@ -138,7 +136,6 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf,struct lirc_dev {char name[40 ];unsigned int minor; -__u32 features;unsigned int buffer_size;/* in chunks holding one code each */ unsigned int chunk_size;
@@ -172,7 +169,6 @@ void lirc_unregister_device(struct lirc_dev *d);int lirc_dev_fop_open (struct inode *inode,struct file *file);int lirc_dev_fop_close (struct inode *inode,struct file *file);unsigned int lirc_dev_fop_poll (struct file *file,poll_table *wait); -long lirc_dev_fop_ioctl (struct file *file,unsigned int cmd,unsigned long arg);ssize_t lirc_dev_fop_read (struct file *file,char __user *buffer,size_t length,loff_t *ppos);#endif
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 17/28 media: lirc: use kfifo rather than lirc_buffer for raw IR
In reply to Sean YoungSince the only mode lirc devices can handle is raw IR, handle this in a plain kfifo.
Remove lirc_buffer since this is no longer needed.
--- drivers/media/rc/ir-lirc-codec.c | 79 +++++++++++++--- drivers/media/rc/lirc_dev.c | 199 ++++----------------------------------- include/media/lirc_dev.h | 109 --------------------- include/media/rc-core.h | 4 + 4 files changed, 85 insertions(+), 306 deletions(-)
drivers/media/rc/ir-lirc-codec.c +65 -14
@@ -66,8 +66,6 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) }else {if (dev->gap) { -int gap_sample; - dev->gap_duration +=ktime_to_ns (ktime_sub (ktime_get (), dev->gap_start));
@@ -76,9 +74,7 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) dev->gap_duration =min_t (u64, dev->gap_duration,LIRC_VALUE_MASK ); - gap_sample =LIRC_SPACE (dev->gap_duration); -lirc_buffer_write (dev->lirc_dev->buf, - (unsigned char *)&gap_sample); +kfifo_put (&dev->rawir,LIRC_SPACE (dev->gap_duration)); dev->gap = false; }
@@ -88,10 +84,8 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) TO_US(ev.duration), TO_STR(ev.pulse)); } -lirc_buffer_write (dev->lirc_dev->buf, - (unsigned char *) &sample); - -wake_up (&dev->lirc_dev->buf->wait_poll); +kfifo_put (&dev->rawir, sample); +wake_up_poll (&dev->wait_poll,POLLIN |POLLRDNORM ); } static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
@@ -408,6 +402,66 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,return ret; } +static unsigned int ir_lirc_poll (struct file *file, +struct poll_table_struct *wait) +{ +struct rc_dev *rcdev = file->private_data; +struct lirc_dev *d = rcdev->lirc_dev; +unsigned int events =0 ; + +poll_wait (file, &rcdev->wait_poll, wait); + +if (!d->attached) + events =POLLHUP |POLLERR ; +else if (rcdev->driver_type ==RC_DRIVER_IR_RAW && + !kfifo_is_empty (&rcdev->rawir)) + events =POLLIN |POLLRDNORM ; + +return events; +} + +static ssize_t ir_lirc_read (struct file *file,char __user *buffer, +size_t length,loff_t *ppos) +{ +struct rc_dev *rcdev = file->private_data; +struct lirc_dev *d = rcdev->lirc_dev; +unsigned int copied; +int ret; + +if (rcdev->driver_type ==RC_DRIVER_IR_RAW_TX ) +return -EINVAL ; + +if (length <sizeof (unsigned int ) || length %sizeof (unsigned int )) +return -EINVAL ; + +if (!d->attached) +return -ENODEV ; + +do { +if (kfifo_is_empty (&rcdev->rawir)) { +if (file->f_flags &O_NONBLOCK ) +return -EAGAIN ; + + ret =wait_event_interruptible (rcdev->wait_poll, + !kfifo_is_empty (&rcdev->rawir) || + !d->attached); +if (ret) +return ret; + } + +if (!d->attached) +return -ENODEV ; + +mutex_lock (&rcdev->lock); + ret =kfifo_to_user (&rcdev->rawir, buffer, length, &copied); +mutex_unlock (&rcdev->lock); +if (ret) +return ret; + }while (copied ==0 ); + +return copied; +} +static const struct file_operations lirc_fops = { .owner =THIS_MODULE , .write = ir_lirc_transmit_ir,
@@ -415,8 +469,8 @@ static const struct file_operations lirc_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = ir_lirc_ioctl, #endif - .read = lirc_dev_fop_read, - .poll = lirc_dev_fop_poll, + .read = ir_lirc_read, + .poll = ir_lirc_poll, .open = lirc_dev_fop_open, .release = lirc_dev_fop_close, .llseek = no_llseek,
@@ -433,9 +487,6 @@ int ir_lirc_register(struct rc_dev *dev)snprintf (ldev->name,sizeof (ldev->name),"ir-lirc-codec (%s)" , dev->driver_name); - ldev->buf =NULL ; - ldev->chunk_size =sizeof (int ); - ldev->buffer_size =LIRCBUF_SIZE ; ldev->fops = &lirc_fops; ldev->dev.parent = &dev->dev; ldev->rdev = dev;
drivers/media/rc/lirc_dev.c +16 -183
254 lines not on this page · raw message
include/media/lirc_dev.h +0 -109
130 lines not on this page · raw message
include/media/rc-core.h +4 -0
@@ -123,6 +123,8 @@ enum rc_filter_type {* @gap_duration: duration of initial gap * @gap: true if we're in a gap * @send_timeout_reports: report timeouts in lirc raw IR. +* @rawir: queue for incoming raw IR +* @wait_poll: poll struct for lirc device * @send_mode: lirc mode for sending, either LIRC_MODE_SCANCODE or * LIRC_MODE_PULSE * @change_protocol: allow changing the protocol used on hardware decoders
@@ -191,6 +193,8 @@ struct rc_dev {u64 gap_duration;bool gap;bool send_timeout_reports; + DECLARE_KFIFO_PTR(rawir, unsigned int); +wait_queue_head_t wait_poll;u8 send_mode;#endif int (*change_protocol)(struct rc_dev *dev,u64 *rc_proto);
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 18/28 media: lirc: move lirc_dev->attached to rc_dev->registered
In reply to Sean YoungThis is done to further remove the lirc kernel api. Ensure that every fops checks for this.
--- drivers/media/rc/ir-lirc-codec.c | 16 ++++++++++------ drivers/media/rc/lirc_dev.c | 4 +--- drivers/media/rc/rc-main.c | 8 ++++++++ include/media/lirc_dev.h | 2 -- include/media/rc-core.h | 3 +++ 5 files changed, 22 insertions(+), 11 deletions(-)
drivers/media/rc/ir-lirc-codec.c +10 -6
@@ -101,6 +101,9 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,unsigned int duration =0 ;/* signal duration in us */ int i; +if (!dev->registered) +return -ENODEV ; + start =ktime_get ();if (!dev->tx_ir) {
@@ -224,6 +227,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,return ret; } +if (!dev->registered) +return -ENODEV ; +switch (cmd) {case LIRC_GET_FEATURES :if (dev->driver_type ==RC_DRIVER_IR_RAW ) {
@@ -406,12 +412,11 @@ static unsigned int ir_lirc_poll(struct file *file, struct poll_table_struct *wait) {struct rc_dev *rcdev = file->private_data; -struct lirc_dev *d = rcdev->lirc_dev;unsigned int events =0 ;poll_wait (file, &rcdev->wait_poll, wait); -if (!d->attached) +if (!rcdev->registered) events =POLLHUP |POLLERR ;else if (rcdev->driver_type ==RC_DRIVER_IR_RAW && !kfifo_is_empty (&rcdev->rawir))
@@ -424,7 +429,6 @@ static ssize_t ir_lirc_read(struct file *file, char __user *buffer, size_t length, loff_t *ppos) { struct rc_dev *rcdev = file->private_data; -struct lirc_dev *d = rcdev->lirc_dev;unsigned int copied;int ret;
@@ -434,7 +438,7 @@ static ssize_t ir_lirc_read(struct file *file, char __user *buffer,if (length <sizeof (unsigned int ) || length %sizeof (unsigned int ))return -EINVAL ; -if (!d->attached) +if (!rcdev->registered)return -ENODEV ; do {
@@ -444,12 +448,12 @@ static ssize_t ir_lirc_read(struct file *file, char __user *buffer, ret =wait_event_interruptible (rcdev->wait_poll, !kfifo_is_empty (&rcdev->rawir) || - !d->attached); + !rcdev->registered);if (ret)return ret; } -if (!d->attached) +if (!rcdev->registered)return -ENODEV ;mutex_lock (&rcdev->lock);
drivers/media/rc/lirc_dev.c +1 -3
@@ -122,7 +122,6 @@ int lirc_register_device(struct lirc_dev *d)cdev_init (&d->cdev, d->fops); d->cdev.owner = d->owner; - d->attached = true; err =cdev_device_add (&d->cdev, &d->dev);if (err) {
@@ -153,7 +152,6 @@ void lirc_unregister_device(struct lirc_dev *d)mutex_lock (&d->mutex); - d->attached = false;if (d->open) {dev_dbg (&d->dev,LOGHEAD "releasing opened driver\n" , d->name, d->minor);
@@ -180,7 +178,7 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)if (retval)return retval; -if (!d->attached) { +if (!rcdev->registered) { retval = -ENODEV ; goto out; }
drivers/media/rc/rc-main.c +8 -0
@@ -1809,6 +1809,8 @@ int rc_register_device(struct rc_dev *dev) goto out_lirc; } + dev->registered = true; +IR_dprintk (1 ,"Registered rc%u (driver: %s)\n" , dev->minor, dev->driver_name ? dev->driver_name :"unknown" );
@@ -1871,6 +1873,12 @@ void rc_unregister_device(struct rc_dev *dev)rc_free_rx_device (dev); + dev->registered = false; + +/* +* lirc device should be freed with dev->registered = false, so +* that userspace polling will get notified. +*/ if (dev->driver_type !=RC_DRIVER_SCANCODE )ir_lirc_unregister (dev);
include/media/lirc_dev.h +0 -2
@@ -26,7 +26,6 @@* @rdev: &struct rc_dev associated with the device * @fops: &struct file_operations for the device * @owner: the module owning this struct -* @attached: if the device is still live * @open: open count for the device's chardev * @mutex: serialises file_operations calls * @dev: &struct device assigned to the device
@@ -40,7 +39,6 @@ struct lirc_dev {const struct file_operations *fops;struct module *owner; -bool attached;int open;struct mutex mutex;/* protect from simultaneous accesses */
include/media/rc-core.h +3 -0
@@ -127,6 +127,8 @@ enum rc_filter_type {* @wait_poll: poll struct for lirc device * @send_mode: lirc mode for sending, either LIRC_MODE_SCANCODE or * LIRC_MODE_PULSE +* @registered: set to true by rc_register_device(), false by +* rc_unregister_device * @change_protocol: allow changing the protocol used on hardware decoders * @open: callback to allow drivers to enable polling/irq when IR input device * is opened.
@@ -197,6 +199,7 @@ struct rc_dev {wait_queue_head_t wait_poll;u8 send_mode;#endif +bool registered;int (*change_protocol)(struct rc_dev *dev,u64 *rc_proto);int (*open)(struct rc_dev *dev);void (*close)(struct rc_dev *dev);
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 19/28 media: lirc: do not call rc_close() on unregistered devices
In reply to Sean YoungIf a lirc chardev is held open after a device is unplugged, rc_close() will be called after rc_unregister_device(). The driver is not expecting any calls at this point, and the iguanair driver causes an oops in this scenario.
--- drivers/media/rc/rc-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/rc/rc-main.c +1 -1
@@ -885,7 +885,7 @@ void rc_close(struct rc_dev *rdev)if (rdev) {mutex_lock (&rdev->lock); -if (!--rdev->users && rdev->close !=NULL ) +if (!--rdev->users && rdev->close && rdev->registered) rdev->close (rdev);mutex_unlock (&rdev->lock);
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 20/28 media: lirc: create rc-core open and close lirc functions
In reply to Sean YoungReplace the generic kernel lirc api with ones which use rc-core, further reducing the lirc_dev members.
--- drivers/media/rc/ir-lirc-codec.c | 59 ++++++++++++++++++++++++++++++++-- drivers/media/rc/lirc_dev.c | 68 ++-------------------------------------- include/media/lirc_dev.h | 11 ------- include/media/rc-core.h | 2 ++ 4 files changed, 62 insertions(+), 78 deletions(-)
drivers/media/rc/ir-lirc-codec.c +57 -2
@@ -88,6 +88,61 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)wake_up_poll (&dev->wait_poll,POLLIN |POLLRDNORM ); } +static int ir_lirc_open (struct inode *inode,struct file *file) +{ + struct lirc_dev *d = container_of(inode->i_cdev, struct lirc_dev, cdev); +struct rc_dev *dev = d->rdev; +int retval; + + retval =rc_open (dev); +if (retval) +return retval; + + retval =mutex_lock_interruptible (&dev->lock); +if (retval) + goto out_rc; + +if (!dev->registered) { + retval = -ENODEV ; + goto out_unlock; + } + +if (dev->lirc_open) { + retval = -EBUSY ; + goto out_unlock; + } + +if (dev->driver_type ==RC_DRIVER_IR_RAW ) +kfifo_reset_out (&dev->rawir); + + dev->lirc_open++; + file->private_data = dev; + +nonseekable_open (inode, file); +mutex_unlock (&dev->lock); + +return 0 ; + +out_unlock: +mutex_unlock (&dev->lock); +out_rc: +rc_close (dev); +return retval; +} + +static int ir_lirc_close (struct inode *inode,struct file *file) +{ +struct rc_dev *dev = file->private_data; + +mutex_lock (&dev->lock); + dev->lirc_open--; +mutex_unlock (&dev->lock); + +rc_close (dev); + +return 0 ; +} +static ssize_t ir_lirc_transmit_ir (struct file *file,const char __user *buf,size_t n,loff_t *ppos) {
@@ -475,8 +530,8 @@ static const struct file_operations lirc_fops = {#endif .read = ir_lirc_read, .poll = ir_lirc_poll, - .open = lirc_dev_fop_open, - .release = lirc_dev_fop_close, + .open = ir_lirc_open, + .release = ir_lirc_close, .llseek = no_llseek, };
drivers/media/rc/lirc_dev.c +3 -65
92 lines not on this page · raw message
include/media/lirc_dev.h +0 -11
@@ -26,8 +26,6 @@* @rdev: &struct rc_dev associated with the device * @fops: &struct file_operations for the device * @owner: the module owning this struct -* @open: open count for the device's chardev -* @mutex: serialises file_operations calls * @dev: &struct device assigned to the device * @cdev: &struct cdev assigned to the device */
@@ -39,10 +37,6 @@ struct lirc_dev {const struct file_operations *fops;struct module *owner; -int open; - -struct mutex mutex;/* protect from simultaneous accesses */ -struct device dev;struct cdev cdev; };
@@ -55,9 +49,4 @@ int lirc_register_device(struct lirc_dev *d);void lirc_unregister_device (struct lirc_dev *d); -/* default file operations -* used by drivers if they override only some operations -*/ -int lirc_dev_fop_open (struct inode *inode,struct file *file); -int lirc_dev_fop_close (struct inode *inode,struct file *file);#endif
include/media/rc-core.h +2 -0
@@ -117,6 +117,7 @@ enum rc_filter_type {* @rx_resolution : resolution (in ns) of input sampler * @tx_resolution: resolution (in ns) of output sampler * @lirc_dev: lirc char device +* @lirc_open: count of the number of times the device has been opened * @carrier_low: when setting the carrier range, first the low end must be * set with an ioctl and then the high end with another ioctl * @gap_start: time when gap starts
@@ -190,6 +191,7 @@ struct rc_dev {u32 tx_resolution;#ifdef CONFIG_LIRC struct lirc_dev *lirc_dev; +int lirc_open;int carrier_low;ktime_t gap_start;u64 gap_duration;
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 21/28 media: lirc: remove name from lirc_dev
In reply to Sean YoungThis is a duplicate of rcdev->driver_name.
--- Documentation/media/uapi/rc/lirc-dev-intro.rst | 2 +- drivers/media/rc/ir-lirc-codec.c | 2 -- drivers/media/rc/lirc_dev.c | 9 +++------ include/media/lirc_dev.h | 2 -- 4 files changed, 4 insertions(+), 11 deletions(-)
Documentation/media/uapi/rc/lirc-dev-intro.rst +1 -1
@@ -18,7 +18,7 @@ Example dmesg output upon a driver registering w/LIRC: $ dmesg |grep lirc_dev lirc_dev: IR Remote Control driver registered, major 248 - rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0 + rc rc0: lirc_dev: driver mceusb registered at minor = 0 What you should see for a chardev:
drivers/media/rc/ir-lirc-codec.c +0 -2
@@ -544,8 +544,6 @@ int ir_lirc_register(struct rc_dev *dev)if (!ldev)return rc; -snprintf (ldev->name,sizeof (ldev->name),"ir-lirc-codec (%s)" , - dev->driver_name); ldev->fops = &lirc_fops; ldev->dev.parent = &dev->dev; ldev->rdev = dev;
drivers/media/rc/lirc_dev.c +3 -6
@@ -101,9 +101,6 @@ int lirc_register_device(struct lirc_dev *d)return -EINVAL ; } -/* some safety check 8-) */ - d->name[sizeof (d->name) -1 ] ='\0' ; -if (rcdev->driver_type ==RC_DRIVER_IR_RAW ) {if (kfifo_alloc (&rcdev->rawir,MAX_IR_EVENT_SIZE ,GFP_KERNEL ))return -ENOMEM ;
@@ -131,7 +128,7 @@ int lirc_register_device(struct lirc_dev *d)get_device (d->dev.parent);dev_info (&d->dev,"lirc_dev: driver %s registered at minor = %d\n" , - d->name, d->minor); + rcdev->driver_name, d->minor);return 0 ; }
@@ -147,13 +144,13 @@ void lirc_unregister_device(struct lirc_dev *d) rcdev = d->rdev;dev_dbg (&d->dev,"lirc_dev: driver %s unregistered from minor = %d\n" , - d->name, d->minor); + rcdev->driver_name, d->minor);mutex_lock (&rcdev->lock);if (rcdev->lirc_open) {dev_dbg (&d->dev,LOGHEAD "releasing opened driver\n" , - d->name, d->minor); + rcdev->driver_name, d->minor);wake_up_poll (&rcdev->wait_poll,POLLHUP ); }
include/media/lirc_dev.h +0 -2
@@ -21,7 +21,6 @@/** * struct lirc_dev - represents a LIRC device * -* @name: used for logging * @minor: the minor device (/dev/lircX) number for the device * @rdev: &struct rc_dev associated with the device * @fops: &struct file_operations for the device
@@ -30,7 +29,6 @@* @cdev: &struct cdev assigned to the device */ struct lirc_dev { -char name[40 ];unsigned int minor;struct rc_dev *rdev;
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 22/28 media: lirc: remove last remnants of lirc kapi
In reply to Sean Youngrc-core has replaced the lirc kapi many years ago, and now with the last driver ported to rc-core, we can finally remove it.
Note this has no effect on userspace.
All future IR drivers should use the rc-core api.
--- Documentation/media/kapi/rc-core.rst | 5 -- drivers/media/rc/ir-lirc-codec.c | 41 +--------- drivers/media/rc/lirc_dev.c | 145 ++++++++++++----------------------- drivers/media/rc/rc-core-priv.h | 3 + drivers/media/rc/rc-main.c | 1 - include/media/lirc_dev.h | 50 ------------ include/media/rc-core.h | 8 +- 7 files changed, 60 insertions(+), 193 deletions(-) delete mode 100644 include/media/lirc_dev.h
Documentation/media/kapi/rc-core.rst +0 -5
@@ -7,8 +7,3 @@ Remote Controller core .. kernel-doc:: include/media/rc-core.h .. kernel-doc:: include/media/rc-map.h - -LIRC -~~~~ - -.. kernel-doc:: include/media/lirc_dev.h
drivers/media/rc/ir-lirc-codec.c +4 -37
65 lines not on this page · raw message
drivers/media/rc/lirc_dev.c +48 -97
208 lines not on this page · raw message
drivers/media/rc/rc-core-priv.h +3 -0
@@ -16,6 +16,7 @@#ifndef _RC_CORE_PRIV#define _RC_CORE_PRIV +#define RC_DEV_MAX 256/* Define the max number of pulse/space transitions to buffer */ #define MAX_IR_EVENT_SIZE 512
@@ -287,6 +288,8 @@ void lirc_dev_exit(void);void ir_lirc_raw_event (struct rc_dev *dev,struct ir_raw_event ev);int ir_lirc_register (struct rc_dev *dev);void ir_lirc_unregister (struct rc_dev *dev); + +extern const struct file_operations lirc_fops;#else static inline int lirc_dev_init (void ) {return 0 ; }static inline void lirc_dev_exit (void ) {}
drivers/media/rc/rc-main.c +0 -1
@@ -29,7 +29,6 @@/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ #define IR_TAB_MIN_SIZE 256#define IR_TAB_MAX_SIZE 8192 -#define RC_DEV_MAX 256 static const struct { const char *name;
include/media/lirc_dev.h deleted +0 -50
50 lines not on this page · raw message
include/media/rc-core.h +5 -3
@@ -17,10 +17,10 @@#define _RC_CORE#include <linux/spinlock.h> +#include <linux/cdev.h> #include <linux/kfifo.h> #include <linux/time.h> #include <linux/timer.h> -#include <media/lirc_dev.h> #include <media/rc-map.h> extern int rc_core_debug;
@@ -116,7 +116,8 @@ enum rc_filter_type {* @max_timeout: maximum timeout supported by device * @rx_resolution : resolution (in ns) of input sampler * @tx_resolution: resolution (in ns) of output sampler -* @lirc_dev: lirc char device +* @lirc_dev: lirc device +* @lirc_cdev: lirc char cdev * @lirc_open: count of the number of times the device has been opened * @carrier_low: when setting the carrier range, first the low end must be * set with an ioctl and then the high end with another ioctl
@@ -190,7 +191,8 @@ struct rc_dev {u32 rx_resolution;u32 tx_resolution;#ifdef CONFIG_LIRC -struct lirc_dev *lirc_dev; +struct device lirc_dev; +struct cdev lirc_cdev;int lirc_open;int carrier_low;ktime_t gap_start;
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 23/28 media: lirc: implement reading scancode
In reply to Sean YoungThis implements LIRC_MODE_SCANCODE reading from the lirc device. The scancode can be read from the input device too, but with this interface you get the rc protocol, keycode, toggle and repeat status in addition to just the scancode.
int main()
{
int fd, mode, rc;
fd = open("/dev/lirc0", O_RDWR);
mode = LIRC_MODE_SCANCODE;
if (ioctl(fd, LIRC_SET_REC_MODE, &mode)) {
// kernel too old or lirc does not support transmit
}
struct lirc_scancode scancode;
while (read(fd, &scancode, sizeof(scancode)) == sizeof(scancode)) {
printf("protocol:%d scancode:0x%x toggle:%d repeat:%d\n",
scancode.rc_proto, scancode.scancode,
!!(scancode.flags & LIRC_SCANCODE_FLAG_TOGGLE),
!!(scancode.flags & LIRC_SCANCODE_FLAG_REPEAT));
}
close(fd);
}--- drivers/media/rc/ir-lirc-codec.c | 102 +++++++++++++++++++++++++++++----- drivers/media/rc/ir-mce_kbd-decoder.c | 5 ++ drivers/media/rc/lirc_dev.c | 13 +++++ drivers/media/rc/rc-core-priv.h | 3 + drivers/media/rc/rc-main.c | 7 +++ include/media/rc-core.h | 5 ++ 6 files changed, 120 insertions(+), 15 deletions(-)
drivers/media/rc/ir-lirc-codec.c +87 -15
@@ -88,6 +88,21 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)wake_up_poll (&dev->wait_poll,POLLIN |POLLRDNORM ); } +/** +* ir_lirc_scancode_event() - Send scancode data to lirc to be relayed to +* userspace +* @dev: the struct rc_dev descriptor of the device +* @lsc the struct lirc_scancode describing the decoded scancode +*/ +void ir_lirc_scancode_event (struct rc_dev *dev,struct lirc_scancode *lsc) +{ + lsc->timestamp =ktime_get_ns (); + +if (kfifo_put (&dev->scancodes, *lsc)) +wake_up_poll (&dev->wait_poll,POLLIN |POLLRDNORM ); +} +EXPORT_SYMBOL_GPL (ir_lirc_scancode_event); +static int ir_lirc_open (struct inode *inode,struct file *file) { struct rc_dev *dev = container_of(inode->i_cdev, struct rc_dev,
@@ -114,6 +129,8 @@ static int ir_lirc_open(struct inode *inode, struct file *file)if (dev->driver_type ==RC_DRIVER_IR_RAW )kfifo_reset_out (&dev->rawir); +if (dev->driver_type !=RC_DRIVER_IR_RAW_TX ) +kfifo_reset_out (&dev->scancodes); dev->lirc_open++; file->private_data = dev;
@@ -288,7 +305,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,switch (cmd) {case LIRC_GET_FEATURES :if (dev->driver_type ==RC_DRIVER_IR_RAW ) { - val |=LIRC_CAN_REC_MODE2 ; + val |=LIRC_CAN_REC_MODE2 |LIRC_CAN_REC_SCANCODE ;if (dev->rx_resolution) val |=LIRC_CAN_GET_REC_RESOLUTION ; }
@@ -323,15 +340,17 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,if (dev->driver_type ==RC_DRIVER_IR_RAW_TX )return -ENOTTY ; - val =LIRC_MODE_MODE2 ; + val = dev->rec_mode;break ;case LIRC_SET_REC_MODE :if (dev->driver_type ==RC_DRIVER_IR_RAW_TX )return -ENOTTY ; -if (val !=LIRC_MODE_MODE2 ) +if (!(val ==LIRC_MODE_MODE2 || val ==LIRC_MODE_SCANCODE ))return -EINVAL ; + + dev->rec_mode = val;return 0 ;case LIRC_GET_SEND_MODE :
@@ -471,31 +490,31 @@ static unsigned int ir_lirc_poll(struct file *file,poll_wait (file, &rcdev->wait_poll, wait); -if (!rcdev->registered) +if (!rcdev->registered) { events =POLLHUP |POLLERR ; -else if (rcdev->driver_type ==RC_DRIVER_IR_RAW && - !kfifo_is_empty (&rcdev->rawir)) - events =POLLIN |POLLRDNORM ; + }else if (rcdev->driver_type !=RC_DRIVER_IR_RAW_TX ) { +if (rcdev->rec_mode ==LIRC_MODE_SCANCODE && + !kfifo_is_empty (&rcdev->scancodes)) + events =POLLIN |POLLRDNORM ; + +if (rcdev->rec_mode ==LIRC_MODE_MODE2 && + !kfifo_is_empty (&rcdev->rawir)) + events =POLLIN |POLLRDNORM ; + }return events; } -static ssize_t ir_lirc_read (struct file *file,char __user *buffer, -size_t length,loff_t *ppos) +static ssize_t ir_lirc_read_mode2 (struct file *file,char __user *buffer, +size_t length) {struct rc_dev *rcdev = file->private_data;unsigned int copied;int ret; -if (rcdev->driver_type ==RC_DRIVER_IR_RAW_TX ) -return -EINVAL ; -if (length <sizeof (unsigned int ) || length %sizeof (unsigned int ))return -EINVAL ; -if (!rcdev->registered) -return -ENODEV ; - do { if (kfifo_is_empty(&rcdev->rawir)) { if (file->f_flags & O_NONBLOCK)
@@ -521,6 +540,59 @@ static ssize_t ir_lirc_read(struct file *file, char __user *buffer,return copied; } +static ssize_t ir_lirc_read_scancode (struct file *file,char __user *buffer, +size_t length) +{ +struct rc_dev *rcdev = file->private_data; +unsigned int copied; +int ret; + +if (length <sizeof (struct lirc_scancode ) || + length %sizeof (struct lirc_scancode )) +return -EINVAL ; + +do { +if (kfifo_is_empty (&rcdev->scancodes)) { +if (file->f_flags &O_NONBLOCK ) +return -EAGAIN ; + + ret =wait_event_interruptible (rcdev->wait_poll, + !kfifo_is_empty (&rcdev->scancodes) || + !rcdev->registered); +if (ret) +return ret; + } + +if (!rcdev->registered) +return -ENODEV ; + +mutex_lock (&rcdev->lock); + ret =kfifo_to_user (&rcdev->scancodes, buffer, length, &copied); +mutex_unlock (&rcdev->lock); +if (ret) +return ret; + }while (copied ==0 ); + +return copied; +} + +static ssize_t ir_lirc_read (struct file *file,char __user *buffer, +size_t length,loff_t *ppos) +{ +struct rc_dev *rcdev = file->private_data; + +if (rcdev->driver_type ==RC_DRIVER_IR_RAW_TX ) +return -EINVAL ; + +if (!rcdev->registered) +return -ENODEV ; + +if (rcdev->rec_mode ==LIRC_MODE_MODE2 ) +return ir_lirc_read_mode2 (file, buffer, length); +else /* LIRC_MODE_SCANCODE */ +return ir_lirc_read_scancode (file, buffer, length); +} +const struct file_operations lirc_fops = { .owner =THIS_MODULE , .write = ir_lirc_transmit_ir,
drivers/media/rc/ir-mce_kbd-decoder.c +5 -0
@@ -215,6 +215,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)struct mce_kbd_dec *data = &dev->raw->mce_kbd;u32 scancode;unsigned long delay; +struct lirc_scancode lsc = {};if (!is_timing_event (ev)) {if (ev.reset)
@@ -326,18 +327,22 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)mod_timer (&data->rx_timeout, jiffies + delay);/* Pass data to keyboard buffer parser */ ir_mce_kbd_process_keyboard_data (data->idev, scancode); + lsc.rc_proto =RC_PROTO_MCIR2_KBD ;break ;case MCIR2_MOUSE_NBITS : scancode = data->body &0x1fffff ;IR_dprintk (1 ,"mouse data 0x%06x\n" , scancode);/* Pass data to mouse buffer parser */ ir_mce_kbd_process_mouse_data (data->idev, scancode); + lsc.rc_proto =RC_PROTO_MCIR2_MSE ;break ;default :IR_dprintk (1 ,"not keyboard or mouse data\n" ); goto out; } + lsc.scancode = scancode; +ir_lirc_scancode_event (dev, &lsc); data->state =STATE_INACTIVE ;input_event (data->idev,EV_MSC ,MSC_SCAN , scancode);input_sync (data->idev);
drivers/media/rc/lirc_dev.c +13 -0
@@ -42,6 +42,8 @@ static void lirc_release_device(struct device *ld)if (rcdev->driver_type ==RC_DRIVER_IR_RAW )kfifo_free (&rcdev->rawir); +if (rcdev->driver_type !=RC_DRIVER_IR_RAW_TX ) +kfifo_free (&rcdev->scancodes);put_device (&rcdev->dev); }
@@ -55,11 +57,20 @@ int ir_lirc_register(struct rc_dev *dev) dev->lirc_dev.release = lirc_release_device; dev->send_mode =LIRC_MODE_PULSE ; + dev->rec_mode =LIRC_MODE_MODE2 ; +if (dev->driver_type ==RC_DRIVER_IR_RAW ) {if (kfifo_alloc (&dev->rawir,MAX_IR_EVENT_SIZE ,GFP_KERNEL ))return -ENOMEM ; } +if (dev->driver_type !=RC_DRIVER_IR_RAW_TX ) { +if (kfifo_alloc (&dev->scancodes,32 ,GFP_KERNEL )) { +kfifo_free (&dev->rawir); +return -ENOMEM ; + } + } +init_waitqueue_head (&dev->wait_poll); minor =ida_simple_get (&lirc_ida,0 ,RC_DEV_MAX ,GFP_KERNEL );
@@ -90,6 +101,8 @@ int ir_lirc_register(struct rc_dev *dev) out_kfifo:if (dev->driver_type ==RC_DRIVER_IR_RAW )kfifo_free (&dev->rawir); +if (dev->driver_type !=RC_DRIVER_IR_RAW_TX ) +kfifo_free (&dev->scancodes);return err; }
drivers/media/rc/rc-core-priv.h +3 -0
@@ -286,6 +286,7 @@ void ir_raw_init(void);int lirc_dev_init (void );void lirc_dev_exit (void );void ir_lirc_raw_event (struct rc_dev *dev,struct ir_raw_event ev); +void ir_lirc_scancode_event (struct rc_dev *dev,struct lirc_scancode *lsc);int ir_lirc_register (struct rc_dev *dev);void ir_lirc_unregister (struct rc_dev *dev);
@@ -295,6 +296,8 @@ static inline int lirc_dev_init(void) { return 0; }static inline void lirc_dev_exit (void ) {}static inline void ir_lirc_raw_event (struct rc_dev *dev,struct ir_raw_event ev) { } +static inline void ir_lirc_scancode_event (struct rc_dev *dev, +struct lirc_scancode *lsc) { }static inline int ir_lirc_register (struct rc_dev *dev) {return 0 ; }static inline void ir_lirc_unregister (struct rc_dev *dev) { }#endif
drivers/media/rc/rc-main.c +7 -0
@@ -697,6 +697,13 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, dev->last_protocol != protocol || dev->last_scancode != scancode || dev->last_toggle != toggle); +struct lirc_scancode sc = { + .scancode = scancode, .rc_proto = protocol, + .flags = toggle ?LIRC_SCANCODE_FLAG_TOGGLE :0 , + .keycode = keycode + }; + +ir_lirc_scancode_event (dev, &sc);if (new_event && dev->keypressed)ir_do_keyup (dev, false);
include/media/rc-core.h +5 -0
@@ -126,9 +126,12 @@ enum rc_filter_type {* @gap: true if we're in a gap * @send_timeout_reports: report timeouts in lirc raw IR. * @rawir: queue for incoming raw IR +* @scancodes: queue for incoming decoded scancodes * @wait_poll: poll struct for lirc device * @send_mode: lirc mode for sending, either LIRC_MODE_SCANCODE or * LIRC_MODE_PULSE +* @rec_mode: lirc mode for receiving, either LIRC_MODE_SCANCODE or +* LIRC_MODE_MODE2 * @registered: set to true by rc_register_device(), false by * rc_unregister_device * @change_protocol: allow changing the protocol used on hardware decoders
@@ -200,8 +203,10 @@ struct rc_dev {bool gap;bool send_timeout_reports; DECLARE_KFIFO_PTR(rawir, unsigned int); + DECLARE_KFIFO_PTR(scancodes, struct lirc_scancode);wait_queue_head_t wait_poll;u8 send_mode; +u8 rec_mode;#endif bool registered;int (*change_protocol)(struct rc_dev *dev,u64 *rc_proto);
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 24/28 media: rc: ensure lirc device receives nec repeats
In reply to Sean YoungThe lirc device should get lirc repeats whether there is a keymap match or not.
--- drivers/media/rc/rc-main.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-)
drivers/media/rc/rc-main.c +17 -10
@@ -662,19 +662,25 @@ void rc_repeat(struct rc_dev *dev) {unsigned long flags;unsigned int timeout = protocols[dev->last_protocol].repeat_period; +struct lirc_scancode sc = { + .scancode = dev->last_scancode, .rc_proto = dev->last_protocol, + .keycode = dev->keypressed ? dev->last_keycode :KEY_RESERVED , + .flags =LIRC_SCANCODE_FLAG_REPEAT | + (dev->last_toggle ?LIRC_SCANCODE_FLAG_TOGGLE :0 ) + }; -spin_lock_irqsave (&dev->keylock, flags); +ir_lirc_scancode_event (dev, &sc); -if (!dev->keypressed) - goto out; +spin_lock_irqsave (&dev->keylock, flags);input_event (dev->input_dev,EV_MSC ,MSC_SCAN , dev->last_scancode);input_sync (dev->input_dev); - dev->keyup_jiffies = jiffies +msecs_to_jiffies (timeout); -mod_timer (&dev->timer_keyup, dev->keyup_jiffies); +if (dev->keypressed) { + dev->keyup_jiffies = jiffies +msecs_to_jiffies (timeout); +mod_timer (&dev->timer_keyup, dev->keyup_jiffies); + } -out:spin_unlock_irqrestore (&dev->keylock, flags); }EXPORT_SYMBOL_GPL (rc_repeat);
@@ -710,13 +716,14 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,input_event (dev->input_dev,EV_MSC ,MSC_SCAN , scancode); + dev->last_protocol = protocol; + dev->last_scancode = scancode; + dev->last_toggle = toggle; + dev->last_keycode = keycode; +if (new_event && keycode !=KEY_RESERVED ) {/* Register a keypress */ dev->keypressed = true; - dev->last_protocol = protocol; - dev->last_scancode = scancode; - dev->last_toggle = toggle; - dev->last_keycode = keycode;IR_dprintk (1 ,"%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n" , dev->device_name, keycode, protocol, scancode);
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 25/28 media: lirc: document LIRC_MODE_SCANCODE
In reply to Sean YoungLirc supports a new mode which requires documentation.
--- Documentation/media/lirc.h.rst.exceptions | 26 +++++++++++ Documentation/media/uapi/rc/lirc-dev-intro.rst | 51 +++++++++++++++++++--- Documentation/media/uapi/rc/lirc-get-features.rst | 16 +++++++ Documentation/media/uapi/rc/lirc-get-rec-mode.rst | 3 +- Documentation/media/uapi/rc/lirc-get-send-mode.rst | 3 +- Documentation/media/uapi/rc/lirc-read.rst | 15 +++++-- Documentation/media/uapi/rc/lirc-write.rst | 19 ++++++-- 7 files changed, 118 insertions(+), 15 deletions(-)
Documentation/media/lirc.h.rst.exceptions +26 -0
@@ -32,6 +32,32 @@ ignore define LIRC_CAN_SET_REC_DUTY_CYCLE ignore ioctl LIRC_GET_LENGTH +# rc protocols + +ignore symbol RC_PROTO_UNKNOWN +ignore symbol RC_PROTO_OTHER +ignore symbol RC_PROTO_RC5 +ignore symbol RC_PROTO_RC5X_20 +ignore symbol RC_PROTO_RC5_SZ +ignore symbol RC_PROTO_JVC +ignore symbol RC_PROTO_SONY12 +ignore symbol RC_PROTO_SONY15 +ignore symbol RC_PROTO_SONY20 +ignore symbol RC_PROTO_NEC +ignore symbol RC_PROTO_NECX +ignore symbol RC_PROTO_NEC32 +ignore symbol RC_PROTO_SANYO +ignore symbol RC_PROTO_MCIR2_KBD +ignore symbol RC_PROTO_MCIR2_MSE +ignore symbol RC_PROTO_RC6_0 +ignore symbol RC_PROTO_RC6_6A_20 +ignore symbol RC_PROTO_RC6_6A_24 +ignore symbol RC_PROTO_RC6_6A_32 +ignore symbol RC_PROTO_RC6_MCE +ignore symbol RC_PROTO_SHARP +ignore symbol RC_PROTO_XMP +ignore symbol RC_PROTO_CEC + # Undocumented macros ignore define PULSE_BIT
Documentation/media/uapi/rc/lirc-dev-intro.rst +46 -5
63 lines not on this page · raw message
Documentation/media/uapi/rc/lirc-get-features.rst +16 -0
@@ -64,6 +64,14 @@ LIRC features Unused. Kept just to avoid breaking uAPI. +.. _LIRC-CAN-REC-SCANCODE: + +``LIRC_CAN_REC_SCANCODE`` + + The driver is capable of receiving using + :ref:`LIRC_MODE_SCANCODE <lirc-mode-SCANCODE>`. + + .. _LIRC-CAN-SET-SEND-CARRIER: ``LIRC_CAN_SET_SEND_CARRIER``
@@ -171,6 +179,14 @@ LIRC features Unused. Kept just to avoid breaking uAPI. +.. _LIRC-CAN-SEND-SCANCODE: + +``LIRC_CAN_SEND_SCANCODE`` + + The driver supports sending (also called as IR blasting or IR TX) using + :ref:`LIRC_MODE_SCANCODE <lirc-mode-SCANCODE>`. + + Return Value ============
Documentation/media/uapi/rc/lirc-get-rec-mode.rst +2 -1
@@ -34,7 +34,8 @@ Description =========== Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>` -is supported for IR receive. +and :ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` are supported. +Use :ref:`lirc_get_features` to find out which modes the driver supports. Return Value ============
Documentation/media/uapi/rc/lirc-get-send-mode.rst +2 -1
@@ -36,7 +36,8 @@ Description Get/set current transmit mode. -Only :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>` is supported by for IR send, +Only :ref:`LIRC_MODE_PULSE <lirc-mode-pulse>` and +:ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` are supported by for IR send, depending on the driver. Use :ref:`lirc_get_features` to find out which modes the driver supports.
Documentation/media/uapi/rc/lirc-read.rst +11 -4
@@ -45,13 +45,20 @@ descriptor ``fd`` into the buffer starting at ``buf``. If ``count`` is zero, is greater than ``SSIZE_MAX``, the result is unspecified. The exact format of the data depends on what :ref:`lirc_modes` a driver -uses. Use :ref:`lirc_get_features` to get the supported mode. +uses. Use :ref:`lirc_get_features` to get the supported mode, and use +:ref:`lirc_set_rec_mode` set the current active mode. -The generally preferred mode for receive is -:ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>`, -in which packets containing an int value describing an IR signal are +The mode :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>` is for raw IR, +in which packets containing an unsigned int value describing an IR signal are read from the chardev. +Alternatively, :ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` can be available, +in this mode scancodes which are either decoded by software decoders, or +by hardware decoders. The ``rc_proto`` member is set to the +protocol used for transmission, and ``scancode`` to the decoded scancode, +and the ``keycode`` set to the keycode or ``KEY_RESERVED``. + + Return Value ============
Documentation/media/uapi/rc/lirc-write.rst +15 -4
@@ -42,21 +42,32 @@ Description referenced by the file descriptor ``fd`` from the buffer starting at ``buf``. -The exact format of the data depends on what mode a driver uses, use -:ref:`lirc_get_features` to get the supported mode. +The exact format of the data depends on what mode a driver is in, use +:ref:`lirc_get_features` to get the supported modes and use +:ref:`lirc_set_send_mode` set the mode. When in :ref:`LIRC_MODE_PULSE <lirc-mode-PULSE>` mode, the data written to the chardev is a pulse/space sequence of integer values. Pulses and spaces are only marked implicitly by their position. The data must start and end with a pulse, therefore, the data must always include an uneven number of -samples. The write function must block until the data has been transmitted +samples. The write function blocks until the data has been transmitted by the hardware. If more data is provided than the hardware can send, the driver returns ``EINVAL``. +When in :ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` mode, one +``struct lirc_scancode`` must be written to the chardev at a time, else +``EINVAL`` is returned. Set the desired scancode in the ``scancode`` member, +and the protocol in the ``rc_proto`` member. All other members must be set +to 0, else ``EINVAL`` is returned. If there is no protocol encoder +for the protocol or the scancode is not valid for the specified protocol, +``EINVAL`` is returned. The write function may not wait until the scancode +is transmitted. + + Return Value ============ -On success, the number of bytes read is returned. It is not an error if +On success, the number of bytes written is returned. It is not an error if this number is smaller than the number of bytes requested, or the amount of data required for one frame. On error, -1 is returned, and the ``errno`` variable is set appropriately. The generic error codes are described at the
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 26/28 media: lirc: introduce LIRC_SET_POLL_MODES
In reply to Sean YoungIf you want to poll for both decoded scancodes and raw IR, then this ioctl will help you.
int fd = open("/dev/lirc0", O_RDONLY | O_NONBLOCK);
for (;;) {
unsigned mode = LIRC_MODE_SCANCODE | LIRC_MODE_MODE2;
ioctl(fd, LIRC_SET_POLL_MODES, &mode);
poll(&((struct pollfd){ .fd = fd, .events = POLLIN }), 1, -1);
mode = LIRC_MODE_SCANCODE;
ioctl(fd, LIRC_SET_REC_MODE, &mode);
struct lirc_scancode sc;
if (read(fd, &sc, sizeof(sc)) == sizeof(sc)) {
printf("scancode protocol:%d scancode:%llx\n",
sc.rc_proto, sc.scancode);
}
mode = LIRC_MODE_MODE2;
ioctl(fd, LIRC_SET_REC_MODE, &mode);
unsigned sample;
if (read(fd, &sample, sizeof(sample)) == sizeof(sample)) {
if (LIRC_IS_SPACE(sample))
printf("space %u\n", LIRC_VAL(sample)));
if (LIRC_IS_PULSE(sample))
printf("pulse %u\n", LIRC_VAL(sample)));
}
}Note that LIRC_SET_REC_MODE will also affect the poll mode, so you must set it again before calling poll.
--- Documentation/media/uapi/rc/lirc-func.rst | 1 + .../media/uapi/rc/lirc-set-poll-modes.rst | 52 ++++++++++++++++++++++ drivers/media/rc/ir-lirc-codec.c | 19 ++++++-- drivers/media/rc/lirc_dev.c | 1 + include/media/rc-core.h | 3 ++ include/uapi/linux/lirc.h | 9 ++++ 6 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 Documentation/media/uapi/rc/lirc-set-poll-modes.rst
Documentation/media/uapi/rc/lirc-func.rst +1 -0
@@ -25,3 +25,4 @@ LIRC Function Reference lirc-set-rec-timeout-reports lirc-set-measure-carrier-mode lirc-set-wideband-receiver + lirc-set-poll-modes
Documentation/media/uapi/rc/lirc-set-poll-modes.rst new file +52 -0
52 lines not on this page · raw message
drivers/media/rc/ir-lirc-codec.c +15 -4
@@ -351,6 +351,17 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,return -EINVAL ; dev->rec_mode = val; + dev->poll_mode = val; +return 0 ; + +case LIRC_SET_POLL_MODES : +if (dev->driver_type ==RC_DRIVER_IR_RAW_TX ) +return -ENOTTY ; + +if (val & ~(LIRC_MODE_MODE2 |LIRC_MODE_SCANCODE )) +return -EINVAL ; + + dev->poll_mode = val;return 0 ;case LIRC_GET_SEND_MODE :
@@ -493,13 +504,13 @@ static unsigned int ir_lirc_poll(struct file *file,if (!rcdev->registered) { events =POLLHUP |POLLERR ; }else if (rcdev->driver_type !=RC_DRIVER_IR_RAW_TX ) { -if (rcdev->rec_mode ==LIRC_MODE_SCANCODE && +if ((rcdev->poll_mode &LIRC_MODE_SCANCODE ) && !kfifo_is_empty (&rcdev->scancodes)) - events =POLLIN |POLLRDNORM ; + events |=POLLIN |POLLRDNORM ; -if (rcdev->rec_mode ==LIRC_MODE_MODE2 && +if ((rcdev->poll_mode &LIRC_MODE_MODE2 ) && !kfifo_is_empty (&rcdev->rawir)) - events =POLLIN |POLLRDNORM ; + events |=POLLIN |POLLRDNORM ; }return events;
drivers/media/rc/lirc_dev.c +1 -0
@@ -58,6 +58,7 @@ int ir_lirc_register(struct rc_dev *dev) dev->send_mode =LIRC_MODE_PULSE ; dev->rec_mode =LIRC_MODE_MODE2 ; + dev->poll_mode =LIRC_MODE_MODE2 ;if (dev->driver_type ==RC_DRIVER_IR_RAW ) {if (kfifo_alloc (&dev->rawir,MAX_IR_EVENT_SIZE ,GFP_KERNEL ))
include/media/rc-core.h +3 -0
@@ -132,6 +132,8 @@ enum rc_filter_type {* LIRC_MODE_PULSE * @rec_mode: lirc mode for receiving, either LIRC_MODE_SCANCODE or * LIRC_MODE_MODE2 +* @poll_mode: lirc mode used for polling, can poll for both LIRC_MODE_SCANCODE +* and LIRC_MODE_MODE2 * @registered: set to true by rc_register_device(), false by * rc_unregister_device * @change_protocol: allow changing the protocol used on hardware decoders
@@ -207,6 +209,7 @@ struct rc_dev {wait_queue_head_t wait_poll;u8 send_mode;u8 rec_mode; +u8 poll_mode;#endif bool registered;int (*change_protocol)(struct rc_dev *dev,u64 *rc_proto);
include/uapi/linux/lirc.h +9 -0
@@ -134,6 +134,15 @@#define LIRC_SET_WIDEBAND_RECEIVER _IOW('i', 0x00000023, __u32)/* +* For raw IR devices, both raw IR (LIRC_MODE_MODE2) and decodes scancodes +* (LIRC_MODE_SCANCODE) can be read. By default, poll will show read +* ready for the last mode set by LIRC_SET_REC_MODE. Use LIRC_SET_POLL_MODE +* LIRC_MODE_SCANCODE | LIRC_MODE_MODE2 to show read ready for both +* modes. +*/ +#define LIRC_SET_POLL_MODES _IOW('i', 0x00000024, __u32) + +/* * struct lirc_scancode - decoded scancode with protocol for use with * LIRC_MODE_SCANCODE *
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 27/28 media: lirc: scancode rc devices should have a lirc device too
In reply to Sean YoungNow that the lirc interface supports scancodes, RC scancode devices can also have a lirc device. The only receiving feature they will have enabled is LIRC_CAN_REC_SCANCODE.
Note that CEC devices have no lirc device, since they can be controlled from their /dev/cecN chardev.
--- drivers/media/rc/ir-lirc-codec.c | 34 ++++++++++++++++++++++++++-------- drivers/media/rc/lirc_dev.c | 9 +++++++-- drivers/media/rc/rc-main.c | 6 +++--- 3 files changed, 36 insertions(+), 13 deletions(-)
drivers/media/rc/ir-lirc-codec.c +26 -8
@@ -304,6 +304,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,switch (cmd) {case LIRC_GET_FEATURES : +if (dev->driver_type ==RC_DRIVER_SCANCODE ) + val |=LIRC_CAN_REC_SCANCODE ; +if (dev->driver_type ==RC_DRIVER_IR_RAW ) { val |=LIRC_CAN_REC_MODE2 |LIRC_CAN_REC_SCANCODE ;if (dev->rx_resolution)
@@ -344,22 +347,37 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,break ;case LIRC_SET_REC_MODE : -if (dev->driver_type ==RC_DRIVER_IR_RAW_TX ) +switch (dev->driver_type) { +case RC_DRIVER_IR_RAW_TX :return -ENOTTY ; - -if (!(val ==LIRC_MODE_MODE2 || val ==LIRC_MODE_SCANCODE )) -return -EINVAL ; +case RC_DRIVER_SCANCODE : +if (val !=LIRC_MODE_SCANCODE ) +return -EINVAL ; +break ; +case RC_DRIVER_IR_RAW : +if (!(val ==LIRC_MODE_MODE2 || + val ==LIRC_MODE_SCANCODE )) +return -EINVAL ; +break ; + } dev->rec_mode = val; dev->poll_mode = val;return 0 ;case LIRC_SET_POLL_MODES : -if (dev->driver_type ==RC_DRIVER_IR_RAW_TX ) +switch (dev->driver_type) { +case RC_DRIVER_IR_RAW_TX :return -ENOTTY ; - -if (val & ~(LIRC_MODE_MODE2 |LIRC_MODE_SCANCODE )) -return -EINVAL ; +case RC_DRIVER_SCANCODE : +if (val !=LIRC_MODE_SCANCODE ) +return -EINVAL ; +break ; +case RC_DRIVER_IR_RAW : +if (val & ~(LIRC_MODE_MODE2 |LIRC_MODE_SCANCODE )) +return -EINVAL ; +break ; + } dev->poll_mode = val;return 0 ;
drivers/media/rc/lirc_dev.c +7 -2
@@ -57,8 +57,13 @@ int ir_lirc_register(struct rc_dev *dev) dev->lirc_dev.release = lirc_release_device; dev->send_mode =LIRC_MODE_PULSE ; - dev->rec_mode =LIRC_MODE_MODE2 ; - dev->poll_mode =LIRC_MODE_MODE2 ; +if (dev->driver_type ==RC_DRIVER_SCANCODE ) { + dev->rec_mode =LIRC_MODE_SCANCODE ; + dev->poll_mode =LIRC_MODE_SCANCODE ; + }else { + dev->rec_mode =LIRC_MODE_MODE2 ; + dev->poll_mode =LIRC_MODE_MODE2 ; + }if (dev->driver_type ==RC_DRIVER_IR_RAW ) {if (kfifo_alloc (&dev->rawir,MAX_IR_EVENT_SIZE ,GFP_KERNEL ))
drivers/media/rc/rc-main.c +3 -3
@@ -1810,7 +1810,7 @@ int rc_register_device(struct rc_dev *dev) }/* Ensure that the lirc kfifo is setup before we start the thread */ -if (dev->driver_type !=RC_DRIVER_SCANCODE ) { +if (dev->allowed_protocols !=RC_PROTO_BIT_CEC ) { rc =ir_lirc_register (dev);if (rc <0 ) goto out_rx;
@@ -1831,7 +1831,7 @@ int rc_register_device(struct rc_dev *dev)return 0 ; out_lirc: -if (dev->driver_type !=RC_DRIVER_SCANCODE ) +if (dev->allowed_protocols !=RC_PROTO_BIT_CEC )ir_lirc_unregister (dev); out_rx:rc_free_rx_device (dev);
@@ -1892,7 +1892,7 @@ void rc_unregister_device(struct rc_dev *dev)* lirc device should be freed with dev->registered = false, so * that userspace polling will get notified. */ -if (dev->driver_type !=RC_DRIVER_SCANCODE ) +if (dev->allowed_protocols !=RC_PROTO_BIT_CEC )ir_lirc_unregister (dev);device_del (&dev->dev);
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH 28/28 kfifo: DECLARE_KIFO_PTR(fifo, u64) does not work on arm 32 bit
In reply to Sean YoungIf you try to store u64 in a kfifo (or a struct with u64 members), then the buf member of __STRUCT_KFIFO_PTR will cause 4 bytes padding due to alignment (note that struct __kfifo is 20 bytes on 32 bit).
That in turn causes the __is_kfifo_ptr() to fail, which is caught by kfifo_alloc(), which now returns EINVAL.
So, ensure that __is_kfifo_ptr() compares to the right structure.
--- include/linux/kfifo.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
include/linux/kfifo.h +2 -1
@@ -113,7 +113,8 @@ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);* array is a part of the structure and the fifo type where the array is * outside of the fifo structure. */ -#define __is_kfifo_ptr (fifo) (sizeof(*fifo) == sizeof(struct __kfifo)) +#define __is_kfifo_ptr (fifo) \ + (sizeof(*fifo) == sizeof(STRUCT_KFIFO_PTR(typeof(*(fifo)->type))))/** * DECLARE_KFIFO_PTR - macro to declare a fifo pointer object
Signature · 1 line
2.13.6