lirc scancode interface, and more
Subsystems (4)
Sean Young
maintainerv2 cover lirc scancode interface, and more
Introduce lirc scancode mode, use that to port lirc_zilog to rc-core using that interface, and then remove the lirc kernel api.
In summary:
- This removes the lirc staging directory.
- lirc IR TX can use in-kernel encoders for scancode encoding
- lirc_zilog uses the same interface
- lirc kapi (not uapi!) is gone
- The reading lirc scancode 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)
- The scancode interface can be used for cec keycode transmit.
On the cec keycode transmit I am hoping for feedback. Also I am ensure what to do with the new firmware file for the zilog_ir.
v2:
- Add MAINTAINERS entries
- Fixes for nec repeat
- Validate scancode for tx
- Minor bugfixes
Sean Young (25):
media: lirc: implement scancode sending
media: lirc: use the correct carrier for scancode transmit
media: rc: auto load encoder if necessary
media: lirc_zilog: remove receiver
media: lirc_zilog: fix variable types and other ugliness
media: lirc_zilog: port to rc-core using scancode tx interface
media: promote lirc_zilog out of staging
media: lirc: remove LIRCCODE and LIRC_GET_LENGTH
media: lirc: lirc interface should not be a raw decoder
media: lirc: validate scancode for transmit
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_MODE
media: lirc: scancode rc devices should have a lirc device too
media: MAINTAINERS: remove lirc staging area
media: MAINTAINERS: add entry for zilog_ir
media: rc: nec decoder should not send both repeat and keycode
Documentation/media/kapi/rc-core.rst | 5 - Documentation/media/lirc.h.rst.exceptions | 31 + Documentation/media/uapi/rc/lirc-dev-intro.rst | 43 +- 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 | 7 +- Documentation/media/uapi/rc/lirc-get-send-mode.rst | 4 +- Documentation/media/uapi/rc/lirc-read.rst | 14 +- Documentation/media/uapi/rc/lirc-set-poll-mode.rst | 45 + Documentation/media/uapi/rc/lirc-write.rst | 16 +- MAINTAINERS | 12 +- drivers/media/rc/Kconfig | 41 +- drivers/media/rc/Makefile | 6 +- drivers/media/rc/ir-jvc-decoder.c | 1 + drivers/media/rc/ir-lirc-codec.c | 560 ++++--- drivers/media/rc/ir-mce_kbd-decoder.c | 12 +- drivers/media/rc/ir-nec-decoder.c | 30 +- 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 | 481 +----- drivers/media/rc/rc-core-priv.h | 54 +- drivers/media/rc/rc-ir-raw.c | 56 +- drivers/media/rc/rc-main.c | 150 +- drivers/media/rc/zilog_ir.c | 742 +++++++++ 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/media/lirc_dev.h | 192 --- include/media/rc-core.h | 55 +- include/media/rc-map.h | 54 +- include/uapi/linux/lirc.h | 93 ++ 38 files changed, 1701 insertions(+), 2791 deletions(-) delete mode 100644 Documentation/media/uapi/rc/lirc-get-length.rst create mode 100644 Documentation/media/uapi/rc/lirc-set-poll-mode.rst create mode 100644 drivers/media/rc/zilog_ir.c 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 v2 1/25 media: lirc: implement scancode sending
This 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 | 101 ++++++++++++++++++++++++++++----------- drivers/media/rc/rc-core-priv.h | 2 +- include/media/rc-map.h | 54 +-------------------- include/uapi/linux/lirc.h | 93 +++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 81 deletions(-)
drivers/media/rc/ir-lirc-codec.c +74 -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,51 @@ 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.source || scan.target || scan.unused || + 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 +192,31 @@ 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 +245,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 */
@@ -358,7 +403,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)
@@ -397,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 +93 -0
115 lines not on this page · raw message
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH v2 2/25 media: lirc: use the correct carrier for scancode transmit
If 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 | 7 +++++++ 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, 47 insertions(+)
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 +7 -0
@@ -155,6 +155,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 ;
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
@@ -259,6 +259,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 v2 3/25 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 v2 4/25 media: lirc_zilog: remove receiver
In reply to Sean YoungThe ir-kbd-i2c module already handles this very well.
--- drivers/staging/media/lirc/lirc_zilog.c | 901 +++----------------------------- 1 file changed, 76 insertions(+), 825 deletions(-)
drivers/staging/media/lirc/lirc_zilog.c +76 -825
@@ -64,28 +64,7 @@/* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 -struct IR ; - -struct IR_rx { -struct kref ref; -struct IR *ir; - -/* RX device */ -struct mutex client_lock; -struct i2c_client *c; - -/* RX polling thread data */ -struct task_struct *task; - -/* RX read data */ -unsigned char b[3 ]; -bool hdpvr_data_fmt; -}; -struct IR_tx { -struct kref ref; -struct IR *ir; -/* TX device */ struct mutex client_lock;struct i2c_client *c;
@@ -93,39 +72,9 @@ struct IR_tx {/* TX additional actions needed */ int need_boot;bool post_tx_ready_poll; -}; - -struct IR { -struct kref ref; -struct list_head list; - -/* FIXME spinlock access to l->features */ struct lirc_dev *l; -struct lirc_buffer rbuf; - -struct mutex ir_lock; -atomic_t open_count; - -struct device *dev; -struct i2c_adapter *adapter; - -spinlock_t rx_ref_lock;/* struct IR_rx kref get()/put() */ -struct IR_rx *rx; - -spinlock_t tx_ref_lock;/* struct IR_tx kref get()/put() */ -struct IR_tx *tx; }; -/* IR transceiver instance object list */ -/* -* This lock is used for the following: -* a. ir_devices_list access, insertions, deletions -* b. struct IR kref get()s and put()s -* c. serialization of ir_probe() for the two i2c_clients for a Z8 -*/ -static DEFINE_MUTEX (ir_devices_lock); -static LIST_HEAD (ir_devices_list); -/* Block size for IR transmitter */ #define TX_BLOCK_SIZE 99
@@ -153,348 +102,8 @@ struct tx_data_struct {static struct tx_data_struct *tx_data;static struct mutex tx_data_lock; -/* module parameters */ static bool debug;/* debug output */ -static bool tx_only;/* only handle the IR Tx function */ - - -/* struct IR reference counting */ -static struct IR *get_ir_device (struct IR *ir,bool ir_devices_lock_held) -{ -if (ir_devices_lock_held) { -kref_get (&ir->ref); - }else { -mutex_lock (&ir_devices_lock); -kref_get (&ir->ref); -mutex_unlock (&ir_devices_lock); - } -return ir; -} - -static void release_ir_device (struct kref *ref) -{ - struct IR *ir = container_of(ref, struct IR, ref); - -/* -* Things should be in this state by now: -* ir->rx set to NULL and deallocated - happens before ir->rx->ir put() -* ir->rx->task kthread stopped - happens before ir->rx->ir put() -* ir->tx set to NULL and deallocated - happens before ir->tx->ir put() -* ir->open_count == 0 - happens on final close() -* ir_lock, tx_ref_lock, rx_ref_lock, all released -*/ -if (ir->l) -lirc_unregister_device (ir->l); - -if (kfifo_initialized (&ir->rbuf.fifo)) -lirc_buffer_free (&ir->rbuf); -list_del (&ir->list); -kfree (ir); -} - -static int put_ir_device (struct IR *ir,bool ir_devices_lock_held) -{ -int released; - -if (ir_devices_lock_held) -return kref_put (&ir->ref, release_ir_device); - -mutex_lock (&ir_devices_lock); - released =kref_put (&ir->ref, release_ir_device); -mutex_unlock (&ir_devices_lock); - -return released; -} - -/* struct IR_rx reference counting */ -static struct IR_rx *get_ir_rx (struct IR *ir) -{ -struct IR_rx *rx; - -spin_lock (&ir->rx_ref_lock); - rx = ir->rx; -if (rx) -kref_get (&rx->ref); -spin_unlock (&ir->rx_ref_lock); -return rx; -} - -static void destroy_rx_kthread (struct IR_rx *rx,bool ir_devices_lock_held) -{ -/* end up polling thread */ -if (!IS_ERR_OR_NULL (rx->task)) { -kthread_stop (rx->task); - rx->task =NULL ; -/* Put the ir ptr that ir_probe() gave to the rx poll thread */ -put_ir_device (rx->ir, ir_devices_lock_held); - } -} - -static void release_ir_rx (struct kref *ref) -{ - struct IR_rx *rx = container_of(ref, struct IR_rx, ref); -struct IR *ir = rx->ir; - -/* -* This release function can't do all the work, as we want -* to keep the rx_ref_lock a spinlock, and killing the poll thread -* and releasing the ir reference can cause a sleep. That work is -* performed by put_ir_rx() -*/ - ir->l->features &= ~LIRC_CAN_REC_LIRCCODE ; -/* Don't put_ir_device(rx->ir) here; lock can't be freed yet */ - ir->rx =NULL ; -/* Don't do the kfree(rx) here; we still need to kill the poll thread */ -} - -static int put_ir_rx (struct IR_rx *rx,bool ir_devices_lock_held) -{ -int released; -struct IR *ir = rx->ir; - -spin_lock (&ir->rx_ref_lock); - released =kref_put (&rx->ref, release_ir_rx); -spin_unlock (&ir->rx_ref_lock); -/* Destroy the rx kthread while not holding the spinlock */ -if (released) { -destroy_rx_kthread (rx, ir_devices_lock_held); -kfree (rx); -/* Make sure we're not still in a poll_table somewhere */ -wake_up_interruptible (&ir->rbuf.wait_poll); - } -/* Do a reference put() for the rx->ir reference, if we released rx */ -if (released) -put_ir_device (ir, ir_devices_lock_held); -return released; -} - -/* struct IR_tx reference counting */ -static struct IR_tx *get_ir_tx (struct IR *ir) -{ -struct IR_tx *tx; - -spin_lock (&ir->tx_ref_lock); - tx = ir->tx; -if (tx) -kref_get (&tx->ref); -spin_unlock (&ir->tx_ref_lock); -return tx; -} - -static void release_ir_tx (struct kref *ref) -{ - struct IR_tx *tx = container_of(ref, struct IR_tx, ref); -struct IR *ir = tx->ir; - - ir->l->features &= ~LIRC_CAN_SEND_LIRCCODE ; -/* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */ - ir->tx =NULL ; -kfree (tx); -} - -static int put_ir_tx (struct IR_tx *tx,bool ir_devices_lock_held) -{ -int released; -struct IR *ir = tx->ir; - -spin_lock (&ir->tx_ref_lock); - released =kref_put (&tx->ref, release_ir_tx); -spin_unlock (&ir->tx_ref_lock); -/* Do a reference put() for the tx->ir reference, if we released tx */ -if (released) -put_ir_device (ir, ir_devices_lock_held); -return released; -} - -static int add_to_buf (struct IR *ir) -{ -__u16 code; -unsigned char codes[2 ]; -unsigned char keybuf[6 ]; -int got_data =0 ; -int ret; -int failures =0 ; -unsigned char sendbuf[1 ] = {0 }; -struct lirc_buffer *rbuf = ir->l->buf; -struct IR_rx *rx; -struct IR_tx *tx; - -if (lirc_buffer_full (rbuf)) { -dev_dbg (ir->dev,"buffer overflow\n" ); -return -EOVERFLOW ; - } - - rx =get_ir_rx (ir); -if (!rx) -return -ENXIO ; - -/* Ensure our rx->c i2c_client remains valid for the duration */ -mutex_lock (&rx->client_lock); -if (!rx->c) { -mutex_unlock (&rx->client_lock); -put_ir_rx (rx, false); -return -ENXIO ; - } - - tx =get_ir_tx (ir); - -/* -* service the device as long as it is returning -* data and we have space -*/ -do { -if (kthread_should_stop ()) { - ret = -ENODATA ; -break ; - } - -/* -* Lock i2c bus for the duration. RX/TX chips interfere so -* this is worth it -*/ -mutex_lock (&ir->ir_lock); - -if (kthread_should_stop ()) { -mutex_unlock (&ir->ir_lock); - ret = -ENODATA ; -break ; - } - -/* -* Send random "poll command" (?) Windows driver does this -* and it is a good point to detect chip failure. -*/ - ret =i2c_master_send (rx->c, sendbuf,1 ); -if (ret !=1 ) { -dev_err (ir->dev,"i2c_master_send failed with %d\n" , - ret); -if (failures >=3 ) { -mutex_unlock (&ir->ir_lock); -dev_err (ir->dev, -"unable to read from the IR chip after 3 resets, giving up\n" ); -break ; - } - -/* Looks like the chip crashed, reset it */ -dev_err (ir->dev, -"polling the IR receiver chip failed, trying reset\n" ); - -set_current_state (TASK_UNINTERRUPTIBLE ); -if (kthread_should_stop ()) { -mutex_unlock (&ir->ir_lock); - ret = -ENODATA ; -break ; - } -schedule_timeout ((100 *HZ +999 ) /1000 ); -if (tx) - tx->need_boot =1 ; - - ++failures; -mutex_unlock (&ir->ir_lock); - ret =0 ; -continue ; - } - -if (kthread_should_stop ()) { -mutex_unlock (&ir->ir_lock); - ret = -ENODATA ; -break ; - } - ret =i2c_master_recv (rx->c, keybuf,sizeof (keybuf)); -mutex_unlock (&ir->ir_lock); -if (ret !=sizeof (keybuf)) { -dev_err (ir->dev, -"i2c_master_recv failed with %d -- keeping last read buffer\n" , - ret); - }else { - rx->b[0 ] = keybuf[3 ]; - rx->b[1 ] = keybuf[4 ]; - rx->b[2 ] = keybuf[5 ]; -dev_dbg (ir->dev, -"key (0x%02x/0x%02x)\n" , - rx->b[0 ], rx->b[1 ]); - } - -/* key pressed ? */ -if (rx->hdpvr_data_fmt) { -if (got_data && (keybuf[0 ] ==0x80 )) { - ret =0 ; -break ; - }else if (got_data && (keybuf[0 ] ==0x00 )) { - ret = -ENODATA ; -break ; - } - }else if ((rx->b[0 ] &0x80 ) ==0 ) { - ret = got_data ?0 : -ENODATA ; -break ; - } - -/* look what we have */ - code = (((__u16 )rx->b[0 ] &0x7f ) <<6 ) | (rx->b[1 ] >>2 ); - - codes[0 ] = (code >>8 ) &0xff ; - codes[1 ] = code &0xff ; - -/* return it */ -lirc_buffer_write (rbuf, codes); - ++got_data; - ret =0 ; - }while (!lirc_buffer_full (rbuf)); - -mutex_unlock (&rx->client_lock); -if (tx) -put_ir_tx (tx, false); -put_ir_rx (rx, false); -return ret; -} - -/* -* Main function of the polling thread -- from lirc_dev. -* We don't fit the LIRC model at all anymore. This is horrible, but -* basically we have a single RX/TX device with a nasty failure mode -* that needs to be accounted for across the pair. lirc lets us provide -* fops, but prevents us from using the internal polling, etc. if we do -* so. Hence the replication. Might be neater to extend the LIRC model -* to account for this but I'd think it's a very special case of seriously -* messed up hardware. -*/ -static int lirc_thread (void *arg) -{ -struct IR *ir = arg; -struct lirc_buffer *rbuf = ir->l->buf; - -dev_dbg (ir->dev,"poll thread started\n" ); - -while (!kthread_should_stop ()) { -set_current_state (TASK_INTERRUPTIBLE ); - -/* if device not opened, we can sleep half a second */ -if (atomic_read (&ir->open_count) ==0 ) { -schedule_timeout (HZ /2 ); -continue ; - } - -/* -* This is ~113*2 + 24 + jitter (2*repeat gap + code length). -* We use this interval as the chip resets every time you poll -* it (bad!). This is therefore just sufficient to catch all -* of the button presses. It makes the remote much more -* responsive. You can see the difference by running irw and -* holding down a button. With 100ms, the old polling -* interval, you'll notice breaks in the repeat sequence -* corresponding to lost keypresses. -*/ -schedule_timeout ((260 *HZ ) /1000 ); -if (kthread_should_stop ()) -break ; -if (!add_to_buf (ir)) -wake_up_interruptible (&rbuf->wait_poll); - } - -dev_dbg (ir->dev,"poll thread ended\n" ); -return 0 ; -}/* safe read of a uint32 (always network byte order) */ static int read_uint32(unsigned char **data,
@@ -645,10 +254,10 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block) buf[0 ] = (unsigned char )(i +1 );for (j =0 ; j < tosend; ++j) buf[1 + j] = data_block[i + j]; -dev_dbg (tx->ir->dev,"%*ph" ,5 , buf); +dev_dbg (&tx->l->dev,"%*ph" ,5 , buf); ret =i2c_master_send (tx->c, buf, tosend +1 );if (ret != tosend +1 ) { -dev_err (tx->ir->dev, +dev_err (&tx->l->dev,"i2c_master_send failed with %d\n" , ret);return ret <0 ? ret : -EFAULT ; }
@@ -673,7 +282,7 @@ static int send_boot_data(struct IR_tx *tx) buf[1 ] =0x20 ; ret =i2c_master_send (tx->c, buf,2 );if (ret !=2 ) { -dev_err (tx->ir->dev,"i2c_master_send failed with %d\n" , ret); +dev_err (&tx->l->dev,"i2c_master_send failed with %d\n" , ret);return ret <0 ? ret : -EFAULT ; }
@@ -690,22 +299,22 @@ static int send_boot_data(struct IR_tx *tx) }if (ret !=1 ) { -dev_err (tx->ir->dev,"i2c_master_send failed with %d\n" , ret); +dev_err (&tx->l->dev,"i2c_master_send failed with %d\n" , ret);return ret <0 ? ret : -EFAULT ; }/* Here comes the firmware version... (hopefully) */ ret =i2c_master_recv (tx->c, buf,4 );if (ret !=4 ) { -dev_err (tx->ir->dev,"i2c_master_recv failed with %d\n" , ret); +dev_err (&tx->l->dev,"i2c_master_recv failed with %d\n" , ret);return 0 ; }if ((buf[0 ] !=0x80 ) && (buf[0 ] !=0xa0 )) { -dev_err (tx->ir->dev,"unexpected IR TX init response: %02x\n" , +dev_err (&tx->l->dev,"unexpected IR TX init response: %02x\n" , buf[0 ]);return 0 ; } -dev_notice (tx->ir->dev, +dev_notice (&tx->l->dev,"Zilog/Hauppauge IR blaster firmware version %d.%d.%d loaded\n" , buf[1 ], buf[2 ], buf[3 ]);
@@ -750,15 +359,15 @@ static int fw_load(struct IR_tx *tx) }/* Request codeset data file */ - ret =request_firmware (&fw_entry,"haup-ir-blaster.bin" , tx->ir->dev); + ret =request_firmware (&fw_entry,"haup-ir-blaster.bin" , &tx->l->dev);if (ret !=0 ) { -dev_err (tx->ir->dev, +dev_err (&tx->l->dev,"firmware haup-ir-blaster.bin not available (%d)\n" , ret); ret = ret <0 ? ret : -EFAULT ; goto out; } -dev_dbg (tx->ir->dev,"firmware of size %zu loaded\n" , fw_entry->size); +dev_dbg (&tx->l->dev,"firmware of size %zu loaded\n" , fw_entry->size);/* Parse the file */ tx_data =vmalloc (sizeof (*tx_data));
@@ -786,7 +395,7 @@ static int fw_load(struct IR_tx *tx)if (!read_uint8 (&data, tx_data->endp, &version)) goto corrupt;if (version !=1 ) { -dev_err (tx->ir->dev, +dev_err (&tx->l->dev,"unsupported code set file version (%u, expected 1) -- please upgrade to a newer driver\n" , version);fw_unload_locked ();
@@ -803,7 +412,7 @@ static int fw_load(struct IR_tx *tx) &tx_data->num_code_sets)) goto corrupt; -dev_dbg (tx->ir->dev,"%u IR blaster codesets loaded\n" , +dev_dbg (&tx->l->dev,"%u IR blaster codesets loaded\n" , tx_data->num_code_sets); tx_data->code_sets = vmalloc(
@@ -868,7 +477,7 @@ static int fw_load(struct IR_tx *tx) goto out; corrupt: -dev_err (tx->ir->dev,"firmware is corrupt\n" ); +dev_err (&tx->l->dev,"firmware is corrupt\n" );fw_unload_locked (); ret = -EFAULT ;
@@ -877,94 +486,6 @@ static int fw_load(struct IR_tx *tx)return ret; } -/* copied from lirc_dev */ -static ssize_t read (struct file *filep,char __user *outbuf,size_t n, -loff_t *ppos) -{ -struct IR *ir =lirc_get_pdata (filep); -struct IR_rx *rx; -struct lirc_buffer *rbuf = ir->l->buf; -int ret =0 , written =0 , retries =0 ; -unsigned int m; -DECLARE_WAITQUEUE (wait, current); - -dev_dbg (ir->dev,"read called\n" ); -if (n % rbuf->chunk_size) { -dev_dbg (ir->dev,"read result = -EINVAL\n" ); -return -EINVAL ; - } - - rx =get_ir_rx (ir); -if (!rx) -return -ENXIO ; - -/* -* we add ourselves to the task queue before buffer check -* to avoid losing scan code (in case when queue is awaken somewhere -* between while condition checking and scheduling) -*/ -add_wait_queue (&rbuf->wait_poll, &wait); -set_current_state (TASK_INTERRUPTIBLE ); - -/* -* while we didn't provide 'length' bytes, device is opened in blocking -* mode and 'copy_to_user' is happy, wait for data. -*/ -while (written < n && ret ==0 ) { -if (lirc_buffer_empty (rbuf)) { -/* -* According to the read(2) man page, 'written' can be -* returned as less than 'n', instead of blocking -* again, returning -EWOULDBLOCK, or returning -* -ERESTARTSYS -*/ -if (written) -break ; -if (filep->f_flags &O_NONBLOCK ) { - ret = -EWOULDBLOCK ; -break ; - } -if (signal_pending (current)) { - ret = -ERESTARTSYS ; -break ; - } -schedule (); -set_current_state (TASK_INTERRUPTIBLE ); - }else { -unsigned char buf[MAX_XFER_SIZE ]; - -if (rbuf->chunk_size >sizeof (buf)) { -dev_err (ir->dev, -"chunk_size is too big (%d)!\n" , - rbuf->chunk_size); - ret = -EINVAL ; -break ; - } - m =lirc_buffer_read (rbuf, buf); -if (m == rbuf->chunk_size) { - ret =copy_to_user (outbuf + written, buf, - rbuf->chunk_size); - written += rbuf->chunk_size; - }else { - retries++; - } -if (retries >=5 ) { -dev_err (ir->dev,"Buffer read failed!\n" ); - ret = -EIO ; - } - } - } - -remove_wait_queue (&rbuf->wait_poll, &wait); -put_ir_rx (rx, false); -set_current_state (TASK_RUNNING ); - -dev_dbg (ir->dev,"read result = %d (%s)\n" , ret, - ret ?"Error" :"OK" ); - -return ret ? ret : written; -} -/* send a keypress to the IR TX device */ static int send_code (struct IR_tx *tx,unsigned int code,unsigned int key) {
@@ -976,7 +497,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) ret =get_key_data (data_block, code, key);if (ret == -EPROTO ) { -dev_err (tx->ir->dev, +dev_err (&tx->l->dev,"failed to get data for code %u, key %u -- check lircd.conf entries\n" , code, key);return ret;
@@ -994,7 +515,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) buf[1 ] =0x40 ; ret =i2c_master_send (tx->c, buf,2 );if (ret !=2 ) { -dev_err (tx->ir->dev,"i2c_master_send failed with %d\n" , ret); +dev_err (&tx->l->dev,"i2c_master_send failed with %d\n" , ret);return ret <0 ? ret : -EFAULT ; }
@@ -1007,18 +528,18 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) }if (ret !=1 ) { -dev_err (tx->ir->dev,"i2c_master_send failed with %d\n" , ret); +dev_err (&tx->l->dev,"i2c_master_send failed with %d\n" , ret);return ret <0 ? ret : -EFAULT ; }/* Send finished download? */ ret =i2c_master_recv (tx->c, buf,1 );if (ret !=1 ) { -dev_err (tx->ir->dev,"i2c_master_recv failed with %d\n" , ret); +dev_err (&tx->l->dev,"i2c_master_recv failed with %d\n" , ret);return ret <0 ? ret : -EFAULT ; }if (buf[0 ] !=0xA0 ) { -dev_err (tx->ir->dev,"unexpected IR TX response #1: %02x\n" , +dev_err (&tx->l->dev,"unexpected IR TX response #1: %02x\n" , buf[0 ]);return -EFAULT ; }
@@ -1028,7 +549,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) buf[1 ] =0x80 ; ret =i2c_master_send (tx->c, buf,2 );if (ret !=2 ) { -dev_err (tx->ir->dev,"i2c_master_send failed with %d\n" , ret); +dev_err (&tx->l->dev,"i2c_master_send failed with %d\n" , ret);return ret <0 ? ret : -EFAULT ; }
@@ -1038,7 +559,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)* going to skip this whole mess and say we're done on the HD PVR */ if (!tx->post_tx_ready_poll) { -dev_dbg (tx->ir->dev,"sent code %u, key %u\n" , code, key); +dev_dbg (&tx->l->dev,"sent code %u, key %u\n" , code, key);return 0 ; }
@@ -1054,12 +575,12 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) ret =i2c_master_send (tx->c, buf,1 );if (ret ==1 )break ; -dev_dbg (tx->ir->dev, +dev_dbg (&tx->l->dev,"NAK expected: i2c_master_send failed with %d (try %d)\n" , ret, i +1 ); }if (ret !=1 ) { -dev_err (tx->ir->dev, +dev_err (&tx->l->dev,"IR TX chip never got ready: last i2c_master_send failed with %d\n" , ret);return ret <0 ? ret : -EFAULT ;
@@ -1068,17 +589,17 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)/* Seems to be an 'ok' response */ i =i2c_master_recv (tx->c, buf,1 );if (i !=1 ) { -dev_err (tx->ir->dev,"i2c_master_recv failed with %d\n" , ret); +dev_err (&tx->l->dev,"i2c_master_recv failed with %d\n" , ret);return -EFAULT ; }if (buf[0 ] !=0x80 ) { -dev_err (tx->ir->dev,"unexpected IR TX response #2: %02x\n" , +dev_err (&tx->l->dev,"unexpected IR TX response #2: %02x\n" , buf[0 ]);return -EFAULT ; }/* Oh good, it worked */ -dev_dbg (tx->ir->dev,"sent code %u, key %u\n" , code, key); +dev_dbg (&tx->l->dev,"sent code %u, key %u\n" , code, key);return 0 ; }
@@ -1091,8 +612,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)static ssize_t write (struct file *filep,const char __user *buf,size_t n,loff_t *ppos) { -struct IR *ir =lirc_get_pdata (filep); -struct IR_tx *tx; +struct IR_tx *tx =lirc_get_pdata (filep);size_t i;int failures =0 ;
@@ -1100,31 +620,20 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n,if (n %sizeof (int ))return -EINVAL ; -/* Get a struct IR_tx reference */ - tx =get_ir_tx (ir); -if (!tx) -return -ENXIO ; -/* Ensure our tx->c i2c_client remains valid for the duration */ mutex_lock (&tx->client_lock);if (!tx->c) {mutex_unlock (&tx->client_lock); -put_ir_tx (tx, false);return -ENXIO ; } -/* Lock i2c bus for the duration */ -mutex_lock (&ir->ir_lock); -/* Send each keypress */ for (i =0 ; i < n;) {int ret =0 ;int command;if (copy_from_user (&command, buf + i,sizeof (command))) { -mutex_unlock (&ir->ir_lock);mutex_unlock (&tx->client_lock); -put_ir_tx (tx, false);return -EFAULT ; }
@@ -1133,9 +642,7 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n,/* Make sure we have the 'firmware' loaded, first */ ret =fw_load (tx);if (ret !=0 ) { -mutex_unlock (&ir->ir_lock);mutex_unlock (&tx->client_lock); -put_ir_tx (tx, false);if (ret != -ENOMEM ) ret = -EIO ;return ret;
@@ -1151,9 +658,7 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n, ret =send_code (tx, (unsigned int )command >>16 , (unsigned int )command &0xFFFF );if (ret == -EPROTO ) { -mutex_unlock (&ir->ir_lock);mutex_unlock (&tx->client_lock); -put_ir_tx (tx, false);return ret; } }
@@ -1164,15 +669,13 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n,*/ if (ret !=0 ) {/* Looks like the chip crashed, reset it */ -dev_err (tx->ir->dev, +dev_err (&tx->l->dev,"sending to the IR transmitter chip failed, trying reset\n" );if (failures >=3 ) { -dev_err (tx->ir->dev, +dev_err (&tx->l->dev,"unable to send to the IR chip after 3 resets, giving up\n" ); -mutex_unlock (&ir->ir_lock);mutex_unlock (&tx->client_lock); -put_ir_tx (tx, false);return ret; }set_current_state (TASK_UNINTERRUPTIBLE );
@@ -1184,60 +687,21 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n, } } -/* Release i2c bus */ -mutex_unlock (&ir->ir_lock); -mutex_unlock (&tx->client_lock); -/* Give back our struct IR_tx reference */ -put_ir_tx (tx, false); -/* All looks good */ return n; } -/* copied from lirc_dev */ -static unsigned int poll (struct file *filep,poll_table *wait) -{ -struct IR *ir =lirc_get_pdata (filep); -struct IR_rx *rx; -struct lirc_buffer *rbuf = ir->l->buf; -unsigned int ret; - -dev_dbg (ir->dev,"%s called\n" , __func__); - - rx =get_ir_rx (ir); -if (!rx) { -/* -* Revisit this, if our poll function ever reports writeable -* status for Tx -*/ -dev_dbg (ir->dev,"%s result = POLLERR\n" , __func__); -return POLLERR ; - } - -/* -* Add our lirc_buffer's wait_queue to the poll_table. A wake up on -* that buffer's wait queue indicates we may have a new poll status. -*/ -poll_wait (filep, &rbuf->wait_poll, wait); - -/* Indicate what ops could happen immediately without blocking */ - ret =lirc_buffer_empty (rbuf) ?0 : (POLLIN |POLLRDNORM ); - -dev_dbg (ir->dev,"%s result = %s\n" , __func__, - ret ?"POLLIN|POLLRDNORM" :"none" ); -return ret; -}static long ioctl (struct file *filep,unsigned int cmd,unsigned long arg) { -struct IR *ir =lirc_get_pdata (filep); +struct IR_tx *tx =lirc_get_pdata (filep);unsigned long __user *uptr = (unsigned long __user *)arg;int result;unsigned long mode, features; - features = ir->l->features; + features = tx->l->features;switch (cmd) {case LIRC_GET_LENGTH :
@@ -1287,13 +751,7 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)*/ static int open (struct inode *node,struct file *filep) { -struct IR *ir; -lirc_init_pdata (node, filep); - ir =lirc_get_pdata (filep); - -atomic_inc (&ir->open_count); -nonseekable_open (node, filep);return 0 ; }
@@ -1301,25 +759,16 @@ static int open(struct inode *node, struct file *filep)/* Close the IR device */ static int close (struct inode *node,struct file *filep) { -struct IR *ir =lirc_get_pdata (filep); - -atomic_dec (&ir->open_count); - -put_ir_device (ir, false);return 0 ; } -static int ir_remove (struct i2c_client *client);static int ir_probe (struct i2c_client *client,const struct i2c_device_id *id); -#define ID_FLAG_TX 0x01 -#define ID_FLAG_HDPVR 0x02 +#define ID_FLAG_HDPVR 0x01static const struct i2c_device_id ir_transceiver_id[] = { - {"ir_tx_z8f0811_haup" ,ID_FLAG_TX }, - {"ir_rx_z8f0811_haup" ,0 }, - {"ir_tx_z8f0811_hdpvr" ,ID_FLAG_HDPVR |ID_FLAG_TX }, - {"ir_rx_z8f0811_hdpvr" ,ID_FLAG_HDPVR }, + {"ir_tx_z8f0811_haup" ,0 }, + {"ir_tx_z8f0811_hdpvr" ,ID_FLAG_HDPVR }, { } };MODULE_DEVICE_TABLE (i2c, ir_transceiver_id);
@@ -1329,16 +778,13 @@ static struct i2c_driver driver = { .name = "Zilog/Hauppauge i2c IR", }, .probe = ir_probe, - .remove = ir_remove, .id_table = ir_transceiver_id, };static const struct file_operations lirc_fops = { .owner =THIS_MODULE , .llseek = no_llseek, - .read = read, .write = write, - .poll = poll, .unlocked_ioctl = ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ioctl,
@@ -1347,55 +793,11 @@ static const struct file_operations lirc_fops = { .release = close }; -static int ir_remove (struct i2c_client *client) -{ -if (strncmp ("ir_tx_z8" , client->name,8 ) ==0 ) { -struct IR_tx *tx =i2c_get_clientdata (client); - -if (tx) { -mutex_lock (&tx->client_lock); - tx->c =NULL ; -mutex_unlock (&tx->client_lock); -put_ir_tx (tx, false); - } - }else if (strncmp ("ir_rx_z8" , client->name,8 ) ==0 ) { -struct IR_rx *rx =i2c_get_clientdata (client); - -if (rx) { -mutex_lock (&rx->client_lock); - rx->c =NULL ; -mutex_unlock (&rx->client_lock); -put_ir_rx (rx, false); - } - } -return 0 ; -} - -/* ir_devices_lock must be held */ -static struct IR *get_ir_device_by_adapter (struct i2c_adapter *adapter) -{ -struct IR *ir; - -if (list_empty (&ir_devices_list)) -return NULL ; - -list_for_each_entry (ir, &ir_devices_list, list) -if (ir->adapter == adapter) { -get_ir_device (ir, true); -return ir; - } - -return NULL ; -} -static int ir_probe (struct i2c_client *client,const struct i2c_device_id *id) { -struct IR *ir;struct IR_tx *tx; -struct IR_rx *rx;struct i2c_adapter *adap = client->adapter;int ret; -bool tx_probe = false;dev_dbg (&client->dev,"%s: %s on i2c-%d (%s), client addr=0x%02x\n" , __func__, id->name, adap->nr, adap->name, client->addr);
@@ -1405,209 +807,61 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)* The IR transmitter is at i2c address 0x70. */ -if (id->driver_data &ID_FLAG_TX ) - tx_probe = true; -else if (tx_only)/* module option */ -return -ENXIO ; - -pr_info ("probing IR %s on %s (i2c-%d)\n" , - tx_probe ?"Tx" :"Rx" , adap->name, adap->nr); - -mutex_lock (&ir_devices_lock); - -/* Use a single struct IR instance for both the Rx and Tx functions */ - ir =get_ir_device_by_adapter (adap); -if (!ir) { - ir =kzalloc (sizeof (*ir),GFP_KERNEL ); -if (!ir) { - ret = -ENOMEM ; - goto out_no_ir; - } -kref_init (&ir->ref); - -/* store for use in ir_probe() again, and open() later on */ -INIT_LIST_HEAD (&ir->list); -list_add_tail (&ir->list, &ir_devices_list); - - ir->adapter = adap; - ir->dev = &adap->dev; -mutex_init (&ir->ir_lock); -atomic_set (&ir->open_count,0 ); -spin_lock_init (&ir->tx_ref_lock); -spin_lock_init (&ir->rx_ref_lock); - -/* set lirc_dev stuff */ - ir->l =lirc_allocate_device (); -if (!ir->l) { - ret = -ENOMEM ; - goto out_put_ir; - } - -snprintf (ir->l->name,sizeof (ir->l->name),"lirc_zilog" ); - ir->l->code_length =13 ; - ir->l->fops = &lirc_fops; - ir->l->owner =THIS_MODULE ; - ir->l->dev.parent = &adap->dev; - -/* -* FIXME this is a pointer reference to us, but no refcount. -* -* This OK for now, since lirc_dev currently won't touch this -* buffer as we provide our own lirc_fops. -* -* Currently our own lirc_fops rely on this ir->l->buf pointer -*/ - ir->l->buf = &ir->rbuf; -/* This will be returned by lirc_get_pdata() */ - ir->l->data = ir; - ret =lirc_buffer_init (ir->l->buf,2 ,BUFLEN /2 ); -if (ret) { -lirc_free_device (ir->l); - ir->l =NULL ; - goto out_put_ir; - } - } +pr_info ("probing IR Tx on %s (i2c-%d)\n" , adap->name, adap->nr); -if (tx_probe) { -/* Get the IR_rx instance for later, if already allocated */ - rx =get_ir_rx (ir); - -/* Set up a struct IR_tx instance */ - tx =kzalloc (sizeof (*tx),GFP_KERNEL ); -if (!tx) { - ret = -ENOMEM ; - goto out_put_xx; - } -kref_init (&tx->ref); - ir->tx = tx; - - ir->l->features |=LIRC_CAN_SEND_LIRCCODE ; -mutex_init (&tx->client_lock); - tx->c = client; - tx->need_boot =1 ; - tx->post_tx_ready_poll = - (id->driver_data &ID_FLAG_HDPVR ) ? false : true; - -/* An ir ref goes to the struct IR_tx instance */ - tx->ir =get_ir_device (ir, true); - -/* A tx ref goes to the i2c_client */ -i2c_set_clientdata (client,get_ir_tx (ir)); - -/* -* Load the 'firmware'. We do this before registering with -* lirc_dev, so the first firmware load attempt does not happen -* after a open() or write() call on the device. -* -* Failure here is not deemed catastrophic, so the receiver will -* still be usable. Firmware load will be retried in write(), -* if it is needed. -*/ -fw_load (tx); - -/* Proceed only if the Rx client is also ready or not needed */ -if (!rx && !tx_only) { -dev_info (tx->ir->dev, -"probe of IR Tx on %s (i2c-%d) done. Waiting on IR Rx.\n" , - adap->name, adap->nr); - goto out_ok; - } - }else { -/* Get the IR_tx instance for later, if already allocated */ - tx =get_ir_tx (ir); - -/* Set up a struct IR_rx instance */ - rx =kzalloc (sizeof (*rx),GFP_KERNEL ); -if (!rx) { - ret = -ENOMEM ; - goto out_put_xx; - } -kref_init (&rx->ref); - ir->rx = rx; - - ir->l->features |=LIRC_CAN_REC_LIRCCODE ; -mutex_init (&rx->client_lock); - rx->c = client; - rx->hdpvr_data_fmt = - (id->driver_data &ID_FLAG_HDPVR ) ? true : false; - -/* An ir ref goes to the struct IR_rx instance */ - rx->ir =get_ir_device (ir, true); +/* Set up a struct IR_tx instance */ + tx =devm_kzalloc (&client->dev,sizeof (*tx),GFP_KERNEL ); +if (!tx) +return -ENOMEM ; -/* An rx ref goes to the i2c_client */ -i2c_set_clientdata (client,get_ir_rx (ir)); +mutex_init (&tx->client_lock); + tx->c = client; + tx->need_boot =1 ; + tx->post_tx_ready_poll = !(id->driver_data &ID_FLAG_HDPVR ); -/* -* Start the polling thread. -* It will only perform an empty loop around schedule_timeout() -* until we register with lirc_dev and the first user open() -*/ -/* An ir ref goes to the new rx polling kthread */ - rx->task =kthread_run (lirc_thread,get_ir_device (ir, true), -"zilog-rx-i2c-%d" , adap->nr); -if (IS_ERR (rx->task)) { - ret =PTR_ERR (rx->task); -dev_err (tx->ir->dev, -"%s: could not start IR Rx polling thread\n" , - __func__); -/* Failed kthread, so put back the ir ref */ -put_ir_device (ir, true); -/* Failure exit, so put back rx ref from i2c_client */ -i2c_set_clientdata (client,NULL ); -put_ir_rx (rx, true); - ir->l->features &= ~LIRC_CAN_REC_LIRCCODE ; - goto out_put_tx; - } +/* set lirc_dev stuff */ + tx->l =lirc_allocate_device (); +if (!tx->l) +return -ENOMEM ; -/* Proceed only if the Tx client is also ready */ -if (!tx) { -pr_info ("probe of IR Rx on %s (i2c-%d) done. Waiting on IR Tx.\n" , - adap->name, adap->nr); - goto out_ok; - } - } +snprintf (tx->l->name,sizeof (tx->l->name),"lirc_zilog" ); + tx->l->features |=LIRC_CAN_SEND_LIRCCODE ; + tx->l->code_length =13 ; + tx->l->fops = &lirc_fops; + tx->l->owner =THIS_MODULE ; + tx->l->dev.parent = &client->dev;/* register with lirc */ - ret =lirc_register_device (ir->l); + ret =lirc_register_device (tx->l);if (ret <0 ) { -dev_err (tx->ir->dev, -"%s: lirc_register_device() failed: %i\n" , +dev_err (&tx->l->dev,"%s: lirc_register_device() failed: %i\n" , __func__, ret); -lirc_free_device (ir->l); - ir->l =NULL ; - goto out_put_xx; +lirc_free_device (tx->l); + tx->l =NULL ; +return ret; } -dev_info (ir->dev, +/* +* Load the 'firmware'. We do this before registering with +* lirc_dev, so the first firmware load attempt does not happen +* after a open() or write() call on the device. +*/ + ret =fw_load (tx); +if (ret <0 ) { +lirc_unregister_device (tx->l); +return ret; + } + +/* A tx ref goes to the i2c_client */ +i2c_set_clientdata (client, tx); + +dev_info (&tx->l->dev,"IR unit on %s (i2c-%d) registered as lirc%d and ready\n" , - adap->name, adap->nr, ir->l->minor); - -out_ok: -if (rx) -put_ir_rx (rx, true); -if (tx) -put_ir_tx (tx, true); -put_ir_device (ir, true); -dev_info (ir->dev, -"probe of IR %s on %s (i2c-%d) done\n" , - tx_probe ?"Tx" :"Rx" , adap->name, adap->nr); -mutex_unlock (&ir_devices_lock); -return 0 ; + adap->name, adap->nr, tx->l->minor); -out_put_xx: -if (rx) -put_ir_rx (rx, true); -out_put_tx: -if (tx) -put_ir_tx (tx, true); -out_put_ir: -put_ir_device (ir, true); -out_no_ir: -dev_err (&client->dev, -"%s: probing IR %s on %s (i2c-%d) failed with %d\n" , - __func__, tx_probe ?"Tx" :"Rx" , adap->name, adap->nr, ret); -mutex_unlock (&ir_devices_lock); -return ret; +dev_info (&tx->l->dev, +"probe of IR Tx on %s (i2c-%d) done\n" , adap->name, adap->nr); +return 0 ; }static int __init zilog_init (void )
@@ -1648,6 +902,3 @@ MODULE_ALIAS("lirc_pvr150");module_param (debug, bool,0644 );MODULE_PARM_DESC (debug,"Enable debugging messages" ); - -module_param (tx_only, bool,0644 ); -MODULE_PARM_DESC (tx_only,"Only handle the IR transmit function" );
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH v2 5/25 media: lirc_zilog: fix variable types and other ugliness
In reply to Sean YoungCleans up code and makes checkpatch happy.
--- drivers/staging/media/lirc/lirc_zilog.c | 162 +++++++++++--------------------- 1 file changed, 55 insertions(+), 107 deletions(-)
drivers/staging/media/lirc/lirc_zilog.c +55 -107
@@ -32,32 +32,15 @@* but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* */ +#include <asm/unaligned.h> #include <linux/module.h> -#include <linux/kmod.h> -#include <linux/kernel.h> -#include <linux/sched/signal.h> -#include <linux/fs.h> -#include <linux/poll.h> -#include <linux/string.h> -#include <linux/timer.h> #include <linux/delay.h> -#include <linux/completion.h> -#include <linux/errno.h> -#include <linux/slab.h> #include <linux/i2c.h> #include <linux/firmware.h> #include <linux/vmalloc.h> -#include <linux/mutex.h> -#include <linux/kthread.h> -#include <media/lirc_dev.h> #include <media/lirc.h>
@@ -70,7 +53,7 @@ struct IR_tx {struct i2c_client *c;/* TX additional actions needed */ -int need_boot; +bool need_boot;bool post_tx_ready_poll;struct lirc_dev *l; };
@@ -81,45 +64,39 @@ struct IR_tx {/* Hauppauge IR transmitter data */ struct tx_data_struct {/* Boot block */ -unsigned char *boot_data; +u8 *boot_data;/* Start of binary data block */ -unsigned char *datap; +u8 *datap;/* End of binary data block */ -unsigned char *endp; +u8 *endp;/* Number of installed codesets */ -unsigned int num_code_sets; +u32 num_code_sets;/* Pointers to codesets */ -unsigned char **code_sets; +u8 **code_sets;/* Global fixed data template */ int fixed[TX_BLOCK_SIZE ]; };static struct tx_data_struct *tx_data; -static struct mutex tx_data_lock; - -/* module parameters */ -static bool debug;/* debug output */ +static DEFINE_MUTEX (tx_data_lock);/* safe read of a uint32 (always network byte order) */ -static int read_uint32 (unsigned char **data, -unsigned char *endp,unsigned int *val) +static int read_u32 (u8 **data,u8 *endp,u32 *val) {if (*data +4 > endp)return 0 ; - *val = ((*data)[0 ] <<24 ) | ((*data)[1 ] <<16 ) | - ((*data)[2 ] <<8 ) | (*data)[3 ]; + *val =get_unaligned_be32 (*data); *data +=4 ;return 1 ; }/* safe read of a uint8 */ -static int read_uint8 (unsigned char **data, -unsigned char *endp,unsigned char *val) +static int read_u8 (u8 **data,u8 *endp,u8 *val) {if (*data +1 > endp)return 0 ;
@@ -128,8 +105,8 @@ static int read_uint8(unsigned char **data, }/* safe skipping of N bytes */ -static int skip (unsigned char **data, -unsigned char *endp,unsigned int distance) +static int skip (u8 **data, +u8 *endp,unsigned int distance) {if (*data + distance > endp)return 0 ;
@@ -138,11 +115,11 @@ static int skip(unsigned char **data, }/* decompress key data into the given buffer */ -static int get_key_data (unsigned char *buf, +static int get_key_data (u8 *buf,unsigned int codeset,unsigned int key) { -unsigned char *data, *endp, *diffs, *key_block; -unsigned char keys, ndiffs, id; +u8 *data, *endp, *diffs, *key_block; +u8 keys, ndiffs, id;unsigned int base, lim, pos, i;/* Binary search for the codeset */
@@ -150,7 +127,7 @@ static int get_key_data(unsigned char *buf, pos = base + (lim >>1 ); data = tx_data->code_sets[pos]; -if (!read_uint32 (&data, tx_data->endp, &i)) +if (!read_u32 (&data, tx_data->endp, &i)) goto corrupt;if (i == codeset) {
@@ -169,8 +146,8 @@ static int get_key_data(unsigned char *buf, tx_data->code_sets[pos + 1] : tx_data->endp;/* Read the block header */ -if (!read_uint8 (&data, endp, &keys) || - !read_uint8 (&data, endp, &ndiffs) || +if (!read_u8 (&data, endp, &keys) || + !read_u8 (&data, endp, &ndiffs) || ndiffs >TX_BLOCK_SIZE || keys ==0 ) goto corrupt;
@@ -180,16 +157,16 @@ static int get_key_data(unsigned char *buf, goto corrupt;/* Read the id of the first key */ -if (!read_uint8 (&data, endp, &id)) +if (!read_u8 (&data, endp, &id)) goto corrupt;/* Unpack the first key's data */ for (i =0 ; i <TX_BLOCK_SIZE ; ++i) {if (tx_data->fixed[i] ==-1 ) { -if (!read_uint8 (&data, endp, &buf[i])) +if (!read_u8 (&data, endp, &buf[i])) goto corrupt; }else { - buf[i] = (unsigned char )tx_data->fixed[i]; + buf[i] = tx_data->fixed[i]; } }
@@ -207,7 +184,7 @@ static int get_key_data(unsigned char *buf,/* Binary search for the key */ for (base =0 , lim = keys -1 ; lim; lim >>=1 ) {/* Seek to block */ -unsigned char *key_data; +u8 *key_data; pos = base + (lim >>1 ); key_data = key_block + (ndiffs +1 ) * pos;
@@ -218,9 +195,9 @@ static int get_key_data(unsigned char *buf,/* found, so unpack the diffs */ for (i =0 ; i < ndiffs; ++i) { -unsigned char val; +u8 val; -if (!read_uint8 (&key_data, endp, &val) || +if (!read_u8 (&key_data, endp, &val) || diffs[i] >=TX_BLOCK_SIZE ) goto corrupt; buf[diffs[i]] = val;
@@ -241,17 +218,17 @@ static int get_key_data(unsigned char *buf, }/* send a block of data to the IR TX device */ -static int send_data_block (struct IR_tx *tx,unsigned char *data_block) +static int send_data_block (struct IR_tx *tx,u8 *data_block) {int i, j, ret; -unsigned char buf[5 ]; +u8 buf[5 ];for (i =0 ; i <TX_BLOCK_SIZE ;) {int tosend =TX_BLOCK_SIZE - i;if (tosend >4 ) tosend =4 ; - buf[0 ] = (unsigned char )(i +1 ); + buf[0 ] = i +1 ;for (j =0 ; j < tosend; ++j) buf[1 + j] = data_block[i + j];dev_dbg (&tx->l->dev,"%*ph" ,5 , buf);
@@ -270,7 +247,7 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block)static int send_boot_data (struct IR_tx *tx) {int ret, i; -unsigned char buf[4 ]; +u8 buf[4 ];/* send the boot block */ ret =send_data_block (tx, tx_data->boot_data);
@@ -295,7 +272,7 @@ static int send_boot_data(struct IR_tx *tx) ret =i2c_master_send (tx->c, buf,1 );if (ret ==1 )break ; -udelay (100 ); +usleep_range (100 ,110 ); }if (ret !=1 ) {
@@ -348,7 +325,7 @@ static int fw_load(struct IR_tx *tx) {int ret;unsigned int i; -unsigned char *data, version, num_global_fixed; +u8 *data, version, num_global_fixed;const struct firmware *fw_entry;/* Already loaded? */
@@ -392,7 +369,7 @@ static int fw_load(struct IR_tx *tx)/* Check version */ data = tx_data->datap; -if (!read_uint8 (&data, tx_data->endp, &version)) +if (!read_u8 (&data, tx_data->endp, &version)) goto corrupt;if (version !=1 ) { dev_err(&tx->l->dev,
@@ -408,8 +385,8 @@ static int fw_load(struct IR_tx *tx)if (!skip (&data, tx_data->endp,TX_BLOCK_SIZE )) goto corrupt; -if (!read_uint32 (&data, tx_data->endp, - &tx_data->num_code_sets)) +if (!read_u32 (&data, tx_data->endp, + &tx_data->num_code_sets)) goto corrupt; dev_dbg(&tx->l->dev, "%u IR blaster codesets loaded\n",
@@ -427,14 +404,14 @@ static int fw_load(struct IR_tx *tx) tx_data->fixed[i] =-1 ;/* Read global fixed data template */ -if (!read_uint8 (&data, tx_data->endp, &num_global_fixed) || +if (!read_u8 (&data, tx_data->endp, &num_global_fixed) || num_global_fixed >TX_BLOCK_SIZE ) goto corrupt;for (i =0 ; i < num_global_fixed; ++i) { -unsigned char pos, val; +u8 pos, val; -if (!read_uint8 (&data, tx_data->endp, &pos) || - !read_uint8 (&data, tx_data->endp, &val) || +if (!read_u8 (&data, tx_data->endp, &pos) || + !read_u8 (&data, tx_data->endp, &val) || pos >=TX_BLOCK_SIZE ) goto corrupt; tx_data->fixed[pos] = (int )val;
@@ -442,17 +419,17 @@ static int fw_load(struct IR_tx *tx)/* Filch out the position of each code set */ for (i =0 ; i < tx_data->num_code_sets; ++i) { -unsigned int id; -unsigned char keys; -unsigned char ndiffs; +u32 id; +u8 keys; +u8 ndiffs;/* Save the codeset position */ tx_data->code_sets[i] = data;/* Read header */ -if (!read_uint32 (&data, tx_data->endp, &id) || - !read_uint8 (&data, tx_data->endp, &keys) || - !read_uint8 (&data, tx_data->endp, &ndiffs) || +if (!read_u32 (&data, tx_data->endp, &id) || + !read_u8 (&data, tx_data->endp, &keys) || + !read_u8 (&data, tx_data->endp, &ndiffs) || ndiffs >TX_BLOCK_SIZE || keys ==0 ) goto corrupt;
@@ -489,8 +466,8 @@ static int fw_load(struct IR_tx *tx)/* send a keypress to the IR TX device */ static int send_code (struct IR_tx *tx,unsigned int code,unsigned int key) { -unsigned char data_block[TX_BLOCK_SIZE ]; -unsigned char buf[2 ]; +u8 data_block[TX_BLOCK_SIZE ]; +u8 buf[2 ];int i, ret;/* Get data for the codeset/key */
@@ -524,7 +501,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) ret =i2c_master_send (tx->c, buf,1 );if (ret ==1 )break ; -udelay (100 ); +usleep_range (100 ,110 ); }if (ret !=1 ) {
@@ -638,7 +615,7 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n, }/* Send boot data first if required */ -if (tx->need_boot ==1 ) { +if (tx->need_boot) {/* Make sure we have the 'firmware' loaded, first */ ret =fw_load (tx);if (ret !=0 ) {
@@ -650,13 +627,13 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n,/* Prep the chip for transmitting codes */ ret =send_boot_data (tx);if (ret ==0 ) - tx->need_boot =0 ; + tx->need_boot = false; }/* Send the code */ if (ret ==0 ) { ret =send_code (tx, (unsigned int )command >>16 , - (unsigned int )command &0xFFFF ); + (unsigned int )command &0xFFFF );if (ret == -EPROTO ) {mutex_unlock (&tx->client_lock);return ret;
@@ -680,7 +657,7 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n, }set_current_state (TASK_UNINTERRUPTIBLE );schedule_timeout ((100 *HZ +999 ) /1000 ); - tx->need_boot =1 ; + tx->need_boot = true; ++failures; }else { i +=sizeof (int );
@@ -693,7 +670,6 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n,return n; } -static long ioctl (struct file *filep,unsigned int cmd,unsigned long arg) {struct IR_tx *tx =lirc_get_pdata (filep);
@@ -773,7 +749,7 @@ static const struct i2c_device_id ir_transceiver_id[] = { };MODULE_DEVICE_TABLE (i2c, ir_transceiver_id); -static struct i2c_driver driver = { +static struct i2c_driver zilog_driver = { .driver = { .name ="Zilog/Hauppauge i2c IR" , },
@@ -806,17 +782,13 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)* The IR receiver is at i2c address 0x71. * The IR transmitter is at i2c address 0x70. */ - -pr_info ("probing IR Tx on %s (i2c-%d)\n" , adap->name, adap->nr); - -/* Set up a struct IR_tx instance */ tx =devm_kzalloc (&client->dev,sizeof (*tx),GFP_KERNEL );if (!tx)return -ENOMEM ;mutex_init (&tx->client_lock); tx->c = client; - tx->need_boot =1 ; + tx->need_boot = true; tx->post_tx_ready_poll = !(id->driver_data &ID_FLAG_HDPVR );/* set lirc_dev stuff */
@@ -855,40 +827,21 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)/* A tx ref goes to the i2c_client */ i2c_set_clientdata (client, tx); -dev_info (&tx->l->dev, -"IR unit on %s (i2c-%d) registered as lirc%d and ready\n" , - adap->name, adap->nr, tx->l->minor); - -dev_info (&tx->l->dev, -"probe of IR Tx on %s (i2c-%d) done\n" , adap->name, adap->nr);return 0 ; }static int __init zilog_init (void ) { -int ret; - -pr_notice ("Zilog/Hauppauge IR driver initializing\n" ); - -mutex_init (&tx_data_lock); -request_module ("firmware_class" ); - ret =i2c_add_driver (&driver); -if (ret) -pr_err ("initialization failed\n" ); -else -pr_notice ("initialization complete\n" ); - -return ret; +return i2c_add_driver (&zilog_driver); } static void __exit zilog_exit(void) { -i2c_del_driver (&driver); +i2c_del_driver (&zilog_driver);/* if loaded */ fw_unload (); -pr_notice ("Zilog/Hauppauge IR driver unloaded\n" ); }module_init (zilog_init);
@@ -897,8 +850,3 @@ module_exit(zilog_exit);MODULE_DESCRIPTION ("Zilog/Hauppauge infrared transmitter driver (i2c stack)" );MODULE_AUTHOR ("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver, Andy Walls" );MODULE_LICENSE ("GPL" ); -/* for compat with old name, which isn't all that accurate anymore */ -MODULE_ALIAS ("lirc_pvr150" ); - -module_param (debug, bool,0644 ); -MODULE_PARM_DESC (debug,"Enable debugging messages" );
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH v2 6/25 media: lirc_zilog: port to rc-core using scancode tx interface
In reply to Sean YoungNow that rc-core can send a scancode by rc protocol and scancode, port the lirc_zilog to this interface. The firmware file needs updating to contain the protocol and scancode, so we have haup-ir-blaster-v2.bin for this.
The LIRC_MODE_LIRCCODE is no longer supported, and transmit can only be done using the new LIRC_MODE_SCANCODE interface.
--- drivers/media/rc/ir-lirc-codec.c | 30 ++- drivers/staging/media/lirc/lirc_zilog.c | 446 ++++++++++++-------------------- include/media/rc-core.h | 2 + 3 files changed, 191 insertions(+), 287 deletions(-)
drivers/media/rc/ir-lirc-codec.c +21 -9
@@ -122,6 +122,10 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,if (!lirc)return -EFAULT ; + dev = lirc->dev; +if (!dev) +return -EFAULT ; +if (lirc->send_mode ==LIRC_MODE_SCANCODE ) {struct lirc_scancode scan;
@@ -135,6 +139,11 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, scan.timestamp)return -EINVAL ; +if (dev->tx_scancode) { + ret = dev->tx_scancode (dev, &scan); +return ret <0 ? ret : n; + } + raw =kmalloc_array (LIRCBUF_SIZE ,sizeof (*raw),GFP_KERNEL );if (!raw)return -ENOMEM ;
@@ -175,12 +184,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;
@@ -254,16 +257,19 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,/* mode support */ case LIRC_GET_SEND_MODE : -if (!dev->tx_ir) +if (!dev->tx_ir && !dev->tx_scancode)return -ENOTTY ; val = lirc->send_mode;break ;case LIRC_SET_SEND_MODE : -if (!dev->tx_ir) +if (!dev->tx_ir && !dev->tx_scancode)return -ENOTTY ; +if (!dev->tx_ir && val ==LIRC_MODE_PULSE ) +return -EINVAL ; +if (!(val ==LIRC_MODE_PULSE || val ==LIRC_MODE_SCANCODE ))return -EINVAL ;
@@ -409,6 +415,9 @@ static int ir_lirc_register(struct rc_dev *dev) features |=LIRC_CAN_GET_REC_RESOLUTION ; } +if (dev->tx_scancode) + features |=LIRC_CAN_SEND_SCANCODE ; +if (dev->tx_ir) { features |=LIRC_CAN_SEND_PULSE |LIRC_CAN_SEND_SCANCODE ;if (dev->s_tx_mask)
@@ -449,7 +458,10 @@ static int ir_lirc_register(struct rc_dev *dev)if (rc <0 ) goto out; - dev->raw->lirc.send_mode =LIRC_MODE_PULSE ; +if (dev->tx_scancode) + dev->raw->lirc.send_mode =LIRC_MODE_SCANCODE ; +else + dev->raw->lirc.send_mode =LIRC_MODE_PULSE ; dev->raw->lirc.ldev = ldev; dev->raw->lirc.dev = dev;
drivers/staging/media/lirc/lirc_zilog.c +168 -278
708 lines not on this page · raw message
include/media/rc-core.h +2 -0
@@ -125,6 +125,7 @@ enum rc_filter_type {* @s_tx_duty_cycle: set transmit duty cycle (0% - 100%) * @s_rx_carrier_range: inform driver about carrier it is expected to handle * @tx_ir: transmit IR +* @tx_scancode: transmit scancode * @s_idle: enable/disable hardware idle mode, upon which, * device doesn't interrupt host until it sees IR pulses * @s_learning_mode: enable wide band receiver used for learning
@@ -182,6 +183,7 @@ struct rc_dev {int (*s_tx_duty_cycle)(struct rc_dev *dev,u32 duty_cycle);int (*s_rx_carrier_range)(struct rc_dev *dev,u32 min,u32 max);int (*tx_ir)(struct rc_dev *dev,unsigned *txbuf,unsigned n); +int (*tx_scancode)(struct rc_dev *dev,struct lirc_scancode *scancode);void (*s_idle)(struct rc_dev *dev,bool enable);int (*s_learning_mode)(struct rc_dev *dev,int enable);int (*s_carrier_report) (struct rc_dev *dev,int enable);
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH v2 7/25 media: promote lirc_zilog out of staging
In reply to Sean YoungRename to zilog_ir in the process.
---
drivers/media/rc/Kconfig | 12 ++++++++
drivers/media/rc/Makefile | 1 +
.../lirc/lirc_zilog.c => media/rc/zilog_ir.c} | 0
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 ----------------------
8 files changed, 13 insertions(+), 67 deletions(-)
rename drivers/{staging/media/lirc/lirc_zilog.c => media/rc/zilog_ir.c} (100%)
delete mode 100644 drivers/staging/media/lirc/Kconfig
delete mode 100644 drivers/staging/media/lirc/Makefile
delete mode 100644 drivers/staging/media/lirc/TODOdrivers/media/rc/Kconfig +12 -0
@@ -468,6 +468,18 @@ config IR_SIR To compile this driver as a module, choose M here: the module will be called sir-ir. +config IR_ZILOG + tristate "Zilog/Hauppauge IR Transmitter" + depends on RC_CORE + depends on LIRC + depends on I2C + ---help--- + Driver for the Zilog/Hauppauge IR Transmitter, found on + PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards + + To compile this driver as a module, choose M here: the + module will be called zilog_ir. + config IR_ZX tristate "ZTE ZX IR remote control" depends on RC_CORE
drivers/media/rc/Makefile +1 -0
@@ -43,4 +43,5 @@ obj-$(CONFIG_IR_IMG) += img-ir/ obj-$(CONFIG_IR_SERIAL) += serial_ir.o obj-$(CONFIG_IR_SIR) += sir_ir.o obj-$(CONFIG_IR_MTK) += mtk-cir.o +obj-$(CONFIG_IR_ZILOG) += zilog_ir.o obj-$(CONFIG_IR_ZX) += zx-irdec.o
drivers/media/rc/zilog_ir.c renamed from drivers/staging/media/lirc/lirc_zilog.c +0 -0
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 -
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH v2 8/25 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 record and transmit. No driver use 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
@@ -446,7 +446,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 v2 9/25 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, 145 insertions(+), 243 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 +38 -99
269 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.
@@ -175,6 +185,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);
@@ -250,20 +269,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 v2 10/25 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 | 3 +++ drivers/media/rc/rc-core-priv.h | 1 + drivers/media/rc/rc-main.c | 53 +++++++++++++++++++++++++--------------- 3 files changed, 37 insertions(+), 20 deletions(-)
drivers/media/rc/ir-lirc-codec.c +3 -0
@@ -122,6 +122,9 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, scan.timestamp)return -EINVAL ; +if (!rc_validate_scancode (scan.rc_proto, scan.scancode)) +return -EINVAL ; +if (dev->tx_scancode) { ret = dev->tx_scancode (dev, &scan);return ret <0 ? ret : n;
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
Re: [PATCH v2 10/25] media: lirc: validate scancode for transmit
Quoted 40 lines · Sean Young
Ensure we reject an attempt to transmit invalid scancodes.
Signed-off-by Sean Young <[email protected]>--- drivers/media/rc/ir-lirc-codec.c | 3 +++ drivers/media/rc/rc-core-priv.h | 1 + drivers/media/rc/rc-main.c | 53 +++++++++++++++++++++++++--------------- 3 files changed, 37 insertions(+), 20 deletions(-)drivers/media/rc/ir-lirc-codec.c +3
-0@@ -122,6 +122,9 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, scan.timestamp)return -EINVAL ; +if (!rc_validate_scancode (scan.rc_proto, scan.scancode)) +return -EINVAL ; +if (dev->tx_scancode) { ret = dev->tx_scancode (dev, &scan);return ret <0 ? ret : n;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 +0
-0
drivers/media/rc/rc-main.c void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol, · line 783
Quoted 8 lines
drivers/media/rc/rc-main.c +5
-0@@ -776,6 +776,37 @@ 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 +* @proto: protocol +* @scancode: scancode +*/ +bool rc_validate_scancode (enum rc_proto proto,u32 scancode)
The scancode in struct lirc_scancode is a u64. Shouldn't this be a u64 as well?
Quoted 7 lines
drivers/media/rc/rc-main.c +7
-0+{ +switch (proto) { +case RC_PROTO_NECX : +if ((((scancode >>16 ) ^ ~(scancode >>8 )) &0xff ) ==0 ) +return false; +break ; +case RC_PROTO_NEC32 :
drivers/media/rc/rc-main.c void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol, · line 800
Quoted 10 lines
drivers/media/rc/rc-main.c +10
-0+if ((((scancode >>24 ) ^ ~(scancode >>16 )) &0xff ) ==0 ) +return false; +break ; +case RC_PROTO_RC6_MCE : +if ((scancode &0xffff0000 ) !=0x800f0000 ) +return false; +break ; +case RC_PROTO_RC6_6A_32 : +if ((scancode &0xffff0000 ) ==0x800f0000 ) +return false;
I think that some comments explaining what is tested here would be useful.
This can be done in a separate patch, or done here.
Regards,
Hans
Quoted 42 lines
drivers/media/rc/rc-main.c +11
-20+break ; +default : +break ; + } + +return true; +} + +/** * rc_validate_filter() - checks that the scancode and mask are valid and * provides sensible defaults * @dev: the struct rc_dev descriptor of the device @@ -793,26 +824,8 @@ static int rc_validate_filter(struct rc_dev *dev, mask = protocols[protocol].scancode_bits; -switch (protocol) { -case RC_PROTO_NECX : -if ((((s >>16 ) ^ ~(s >>8 )) &0xff ) ==0 ) -return -EINVAL ; -break ; -case RC_PROTO_NEC32 : -if ((((s >>24 ) ^ ~(s >>16 )) &0xff ) ==0 ) -return -EINVAL ; -break ; -case RC_PROTO_RC6_MCE : -if ((s &0xffff0000 ) !=0x800f0000 ) -return -EINVAL ; -break ; -case RC_PROTO_RC6_6A_32 : -if ((s &0xffff0000 ) ==0x800f0000 ) -return -EINVAL ; -break ; -default : -break ; - } +if (!rc_validate_scancode (protocol, s)) +return -EINVAL ; filter->data &= mask; filter->mask &= mask;
Sean Young
maintainerRe: [PATCH v2 10/25] media: lirc: validate scancode for transmit
Quoted 43 lines · Hans Verkuil
Quoted 42 lines · Sean Young
Ensure we reject an attempt to transmit invalid scancodes.
Signed-off-by Sean Young <[email protected]>--- drivers/media/rc/ir-lirc-codec.c | 3 +++ drivers/media/rc/rc-core-priv.h | 1 + drivers/media/rc/rc-main.c | 53 +++++++++++++++++++++++++--------------- 3 files changed, 37 insertions(+), 20 deletions(-)drivers/media/rc/ir-lirc-codec.c +3
-0@@ -122,6 +122,9 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, scan.timestamp)return -EINVAL ; +if (!rc_validate_scancode (scan.rc_proto, scan.scancode)) +return -EINVAL ; +if (dev->tx_scancode) { ret = dev->tx_scancode (dev, &scan);return ret <0 ? ret : n;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 +0
-0@@ -776,6 +776,37 @@ void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol,EXPORT_SYMBOL_GPL (rc_keydown_notimeout);
Quoted 8 lines
drivers/media/rc/rc-main.c void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol, · line 783
Quoted 6 lines
drivers/media/rc/rc-main.c +5
-0/** +* rc_validate_scancode() - checks that a scancode is valid for a protocol +* @proto: protocol +* @scancode: scancode +*/ +bool rc_validate_scancode (enum rc_proto proto,u32 scancode)The scancode in struct
lirc_scancodeis a u64. Shouldn't this be a u64 as well?
The scancode in struct lirc_scancode is 64 bit to make it future-proof (there are IR protocols with > 32 bits). However none are currently supported.
So, that needs documenting.
Quoted 20 lines
Quoted 7 lines
drivers/media/rc/rc-main.c +7
-0+{ +switch (proto) { +case RC_PROTO_NECX : +if ((((scancode >>16 ) ^ ~(scancode >>8 )) &0xff ) ==0 ) +return false; +break ; +case RC_PROTO_NEC32 :drivers/media/rc/rc-main.c void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol, · line 800
Quoted 10 lines
drivers/media/rc/rc-main.c +10
-0+if ((((scancode >>24 ) ^ ~(scancode >>16 )) &0xff ) ==0 ) +return false; +break ; +case RC_PROTO_RC6_MCE : +if ((scancode &0xffff0000 ) !=0x800f0000 ) +return false; +break ; +case RC_PROTO_RC6_6A_32 : +if ((scancode &0xffff0000 ) ==0x800f0000 ) +return false;I think that some comments explaining what is tested here would be useful.
Quoted 1 line
This can be done in a separate patch, or done here.
Yes, you are right.
Quoted 47 lines
Regards,
Hans
Quoted 42 lines
drivers/media/rc/rc-main.c +11
-20+break ; +default : +break ; + } + +return true; +} + +/** * rc_validate_filter() - checks that the scancode and mask are valid and * provides sensible defaults * @dev: the struct rc_dev descriptor of the device @@ -793,26 +824,8 @@ static int rc_validate_filter(struct rc_dev *dev, mask = protocols[protocol].scancode_bits; -switch (protocol) { -case RC_PROTO_NECX : -if ((((s >>16 ) ^ ~(s >>8 )) &0xff ) ==0 ) -return -EINVAL ; -break ; -case RC_PROTO_NEC32 : -if ((((s >>24 ) ^ ~(s >>16 )) &0xff ) ==0 ) -return -EINVAL ; -break ; -case RC_PROTO_RC6_MCE : -if ((s &0xffff0000 ) !=0x800f0000 ) -return -EINVAL ; -break ; -case RC_PROTO_RC6_6A_32 : -if ((s &0xffff0000 ) ==0x800f0000 ) -return -EINVAL ; -break ; -default : -break ; - } +if (!rc_validate_scancode (protocol, s)) +return -EINVAL ; filter->data &= mask; filter->mask &= mask;
Sean Young
maintainerPATCH v2 11/25 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 | 85 +++++++++++++++++++++++----------------- drivers/media/rc/lirc_dev.c | 62 ++--------------------------- include/media/lirc_dev.h | 4 -- 3 files changed, 53 insertions(+), 98 deletions(-)
drivers/media/rc/ir-lirc-codec.c +50 -35
@@ -230,8 +230,57 @@ 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_scancode) + val |=LIRC_CAN_SEND_SCANCODE ; + +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 && !dev->tx_scancode)return -ENOTTY ;
@@ -352,7 +401,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)
@@ -379,47 +428,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_scancode) - features |=LIRC_CAN_SEND_SCANCODE ; - -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 v2 12/25 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 | 191 ++++----------------------------------- include/media/lirc_dev.h | 109 ---------------------- include/media/rc-core.h | 4 + 4 files changed, 85 insertions(+), 298 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,
@@ -410,6 +404,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,
@@ -417,8 +471,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,
@@ -435,9 +489,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 -175
246 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
@@ -192,6 +194,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 v2 13/25 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->send_mode ==LIRC_MODE_SCANCODE ) {
@@ -223,6 +226,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 ) {
@@ -408,12 +414,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))
@@ -426,7 +431,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;
@@ -436,7 +440,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 {
@@ -446,12 +450,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
@@ -1795,6 +1795,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" );
@@ -1857,6 +1859,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.
@@ -198,6 +200,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 v2 14/25 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
@@ -871,7 +871,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 v2 15/25 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) {
@@ -477,8 +532,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
@@ -191,6 +192,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 v2 16/25 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
@@ -546,8 +546,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 v2 17/25 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 | 45 +---------- drivers/media/rc/lirc_dev.c | 147 ++++++++++++----------------------- 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, 63 insertions(+), 196 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 -41
69 lines not on this page · raw message
drivers/media/rc/lirc_dev.c +51 -96
211 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
@@ -191,7 +192,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 v2 18/25 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, toggle and repeat status in addition too 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);
}Note that the translated KEY_* is not included, that information is published to the input device.
--- 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 | 6 ++ include/media/rc-core.h | 5 ++ 6 files changed, 119 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;
@@ -287,7 +304,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 ; }
@@ -325,15 +342,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 :
@@ -473,31 +492,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)
@@ -523,6 +542,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); }
@@ -59,11 +61,20 @@ int ir_lirc_register(struct rc_dev *dev)else 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 );
@@ -94,6 +105,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 +6 -0
@@ -697,6 +697,12 @@ 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 + }; + +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 recording, 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
@@ -201,8 +204,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
Re: [PATCH v2 18/25] media: lirc: implement reading scancode
Quoted 3 lines · Sean Young
This implements
LIRC_MODE_SCANCODEreading from the lirc device. The scancode can be read from the input device too, but with this interface you get the rc protocol, toggle and repeat status in addition too just
too -> to
Regards,
Hans
Quoted 23 lines
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); }Note that the translated KEY_* is not included, that information is published to the input device.
Sean Young
maintainerPATCH v2 19/25 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 | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
drivers/media/rc/rc-main.c +16 -10
@@ -662,19 +662,24 @@ 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, + .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);
@@ -709,13 +714,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 v2 20/25 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 | 26 ++++++++++++++++++++++ Documentation/media/uapi/rc/lirc-get-features.rst | 16 +++++++++++++ Documentation/media/uapi/rc/lirc-get-rec-mode.rst | 5 +++-- Documentation/media/uapi/rc/lirc-get-send-mode.rst | 3 ++- Documentation/media/uapi/rc/lirc-read.rst | 14 ++++++++---- Documentation/media/uapi/rc/lirc-write.rst | 16 ++++++++++--- 7 files changed, 96 insertions(+), 10 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 +26 -0
@@ -36,6 +36,32 @@ LIRC modes LIRC supports some modes of receiving and sending IR codes, as shown on the following table. +.. _lirc-mode-scancode: +.. _lirc-scancode-flag-toggle: +.. _lirc-scancode-flag-repeat: + +``LIRC_MODE_SCANCODE`` + + This mode is for both sending and receiving IR. + + For transmitting (aka sending), create a ``struct lirc_scancode`` with + the desired scancode set in the ``scancode`` member, ``rc_proto`` set + the IR protocol, and all other members set to 0. Write this struct to + the lirc device. + + For receiving, you read ``struct lirc_scancode`` from the lirc device, + with ``scancode`` set to the received scancode in the IR protocol + ``rc_proto``. The ``flags`` can have ``LIRC_SCANCODE_FLAG_TOGGLE`` set + if the toggle bit is set in protocols that support it (e.g. rc-5 and rc-6), + or ``LIRC_SCANCODE_FLAG_REPEAT`` for when a repeat is received for protocols + that support it (e.g. nec). + + The ``timestamp`` field is filled with the time nanoseconds + (in ``CLOCK_MONOTONIC``) when the scancode was decoded. + + An ``enum rc_proto`` in the :ref:`lirc_header` lists all the supported + IR protocols. + .. _lirc-mode-mode2: ``LIRC_MODE_MODE2``
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 +3 -2
@@ -33,8 +33,9 @@ Arguments Description =========== -Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>` -is supported for IR receive. +Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>`, +: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>`, +:ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` is 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 +10 -4
@@ -45,13 +45,19 @@ 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 +my hardware decoders are available. The ``rc_proto`` member is set to the +protocol used for transmission, and ``scancode`` to the decoded scancode. + + Return Value ============
Documentation/media/uapi/rc/lirc-write.rst +13 -3
@@ -42,17 +42,27 @@ 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 to 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. Set the desired +scancode in the ``scancode`` member, and the protocol in the ``rc_proto`` +member. All other members must be set to 0. 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 ============
Signature · 1 line
2.13.6
Re: [PATCH v2 20/25] media: lirc: document LIRC_MODE_SCANCODE
Quoted 55 lines · Sean Young
Lirc supports a new mode which requires documentation.
Signed-off-by Sean Young <[email protected]>--- Documentation/media/lirc.h.rst.exceptions | 26 ++++++++++++++++++++++ Documentation/media/uapi/rc/lirc-dev-intro.rst | 26 ++++++++++++++++++++++ Documentation/media/uapi/rc/lirc-get-features.rst | 16 +++++++++++++ Documentation/media/uapi/rc/lirc-get-rec-mode.rst | 5 +++-- Documentation/media/uapi/rc/lirc-get-send-mode.rst | 3 ++- Documentation/media/uapi/rc/lirc-read.rst | 14 ++++++++---- Documentation/media/uapi/rc/lirc-write.rst | 16 ++++++++++--- 7 files changed, 96 insertions(+), 10 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_BITDocumentation/media/uapi/rc/lirc-dev-intro.rst +0
-0
Documentation/media/uapi/rc/lirc-dev-intro.rst LIRC modes · line 37
Quoted 2 lines
Documentation/media/uapi/rc/lirc-dev-intro.rst +0
-0@@ -36,6 +36,32 @@ LIRC modes LIRC supports some modes of receiving and sending IR codes, as shown on the following table.
A general note: I don't think it is defined anywhere in the documentation what 'LIRC' stands for. Might be useful to add :-)
Quoted 8 lines
Documentation/media/uapi/rc/lirc-dev-intro.rst +7
-0+.. _lirc-mode-scancode: +.. _lirc-scancode-flag-toggle: +.. _lirc-scancode-flag-repeat: + +``LIRC_MODE_SCANCODE`` + + This mode is for both sending and receiving IR.
Documentation/media/uapi/rc/lirc-dev-intro.rst LIRC modes · line 55
Quoted 10 lines
Documentation/media/uapi/rc/lirc-dev-intro.rst +10
-0+ + For transmitting (aka sending), create a ``struct lirc_scancode`` with + the desired scancode set in the ``scancode`` member, ``rc_proto`` set + the IR protocol, and all other members set to 0. Write this struct to + the lirc device. + + For receiving, you read ``struct lirc_scancode`` from the lirc device, + with ``scancode`` set to the received scancode in the IR protocol + ``rc_proto``. The ``flags`` can have ``LIRC_SCANCODE_FLAG_TOGGLE`` set + if the toggle bit is set in protocols that support it (e.g. rc-5 and rc-6),
Is the meaning of 'toggle' defined anywhere? I'm not sure what it means myself.
Quoted 17 lines
Documentation/media/uapi/rc/lirc-dev-intro.rst +9
-0+ or ``LIRC_SCANCODE_FLAG_REPEAT`` for when a repeat is received for protocols + that support it (e.g. nec). + + The ``timestamp`` field is filled with the time nanoseconds + (in ``CLOCK_MONOTONIC``) when the scancode was decoded. + + An ``enum rc_proto`` in the :ref:`lirc_header` lists all the supported + IR protocols. + .. _lirc-mode-mode2: ``LIRC_MODE_MODE2``Documentation/media/uapi/rc/lirc-get-features.rst +0
-0
Documentation/media/uapi/rc/lirc-get-features.rst LIRC features · line 69
Quoted 6 lines
Documentation/media/uapi/rc/lirc-get-features.rst +3
-0@@ -64,6 +64,14 @@ LIRC features Unused. Kept just to avoid breaking uAPI. +.. _LIRC-CAN-REC-SCANCODE: + +``LIRC_CAN_REC_SCANCODE``
Wouldn't LIRC_CAN_RECEIVE_SCANCODE be better?
I misread 'REC' as 'record' :-)
I thought about using RCV as the abbreviation, but REC is used elsewhere already (rec_mode).
Quoted 28 lines
Documentation/media/uapi/rc/lirc-get-features.rst +13
-0+ + 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 +0
-0
Documentation/media/uapi/rc/lirc-get-rec-mode.rst Arguments · line 36
Quoted 6 lines
Documentation/media/uapi/rc/lirc-get-rec-mode.rst +1
-2@@ -33,8 +33,9 @@ Arguments Description =========== -Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>` -is supported for IR receive. +Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>`,
, -> and
Quoted 10 lines
Documentation/media/uapi/rc/lirc-get-rec-mode.rst +2
-0+: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 +0
-0
Documentation/media/uapi/rc/lirc-get-send-mode.rst Description · line 39
Quoted 5 lines
Documentation/media/uapi/rc/lirc-get-send-mode.rst +1
-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
Documentation/media/uapi/rc/lirc-get-send-mode.rst Description · line 40
Quoted 1 line
Documentation/media/uapi/rc/lirc-get-send-mode.rst +1
-0+:ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` is supported by for IR send,
is -> are
Quoted 15 lines
Documentation/media/uapi/rc/lirc-get-send-mode.rst +0
-0depending on the driver. Use :ref:`lirc_get_features` to find out which modes the driver supports.Documentation/media/uapi/rc/lirc-read.rst +2
-1@@ -45,13 +45,19 @@ 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.
Documentation/media/uapi/rc/lirc-read.rst descriptor ``fd`` into the buffer starting at ``buf``. If ``count`` is zero, · line 57
Quoted 10 lines
Documentation/media/uapi/rc/lirc-read.rst +5
-3-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 +my hardware decoders are available. The ``rc_proto`` member is set to the
my -> by
Quoted 11 lines
Documentation/media/uapi/rc/lirc-read.rst +3
-0+protocol used for transmission, and ``scancode`` to the decoded scancode. + + Return Value ============Documentation/media/uapi/rc/lirc-write.rst +0
-0
Documentation/media/uapi/rc/lirc-write.rst Description · line 47
Quoted 8 lines
Documentation/media/uapi/rc/lirc-write.rst +3
-2@@ -42,17 +42,27 @@ 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 to the mode.
set to -> set
Documentation/media/uapi/rc/lirc-write.rst Description · line 58
Quoted 12 lines
Documentation/media/uapi/rc/lirc-write.rst +3
-1When 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. Set the desired
I would suggest: "must be written to the chardev at a time."
What happens when only a partial struct or multiple structs are written? Is an error returned?
Documentation/media/uapi/rc/lirc-write.rst Description · line 60
Quoted 2 lines
Documentation/media/uapi/rc/lirc-write.rst +2
-0+scancode in the ``scancode`` member, and the protocol in the ``rc_proto`` +member. All other members must be set to 0. If there is no protocol encoder
Is there a check that the other members are 0? Would such a check make sense?
Documentation/media/uapi/rc/lirc-write.rst Description
Quoted 9 lines
Documentation/media/uapi/rc/lirc-write.rst +5
-0+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 ============
Regards,
Hans
Sean Young
maintainerRe: [PATCH v2 20/25] media: lirc: document LIRC_MODE_SCANCODE
Quoted 50 lines · Hans Verkuil
Quoted 49 lines · Sean Young
Lirc supports a new mode which requires documentation.
Signed-off-by Sean Young <[email protected]>--- Documentation/media/lirc.h.rst.exceptions | 26 ++++++++++++++++++++++ Documentation/media/uapi/rc/lirc-dev-intro.rst | 26 ++++++++++++++++++++++ Documentation/media/uapi/rc/lirc-get-features.rst | 16 +++++++++++++ Documentation/media/uapi/rc/lirc-get-rec-mode.rst | 5 +++-- Documentation/media/uapi/rc/lirc-get-send-mode.rst | 3 ++- Documentation/media/uapi/rc/lirc-read.rst | 14 ++++++++---- Documentation/media/uapi/rc/lirc-write.rst | 16 ++++++++++--- 7 files changed, 96 insertions(+), 10 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
Quoted 11 lines
Documentation/media/uapi/rc/lirc-dev-intro.rst LIRC modes · line 37
Quoted 8 lines
Documentation/media/lirc.h.rst.exceptions +0
-0ignore define PULSE_BITDocumentation/media/uapi/rc/lirc-dev-intro.rst +0
-0@@ -36,6 +36,32 @@ LIRC modes LIRC supports some modes of receiving and sending IR codes, as shown on the following table.A general note: I don't think it is defined anywhere in the documentation what 'LIRC' stands for. Might be useful to add :-)
Good point, will do.
Quoted 13 lines
Quoted 13 lines
Documentation/media/uapi/rc/lirc-dev-intro.rst +11
-0+.. _lirc-mode-scancode: +.. _lirc-scancode-flag-toggle: +.. _lirc-scancode-flag-repeat: + +``LIRC_MODE_SCANCODE`` + + This mode is for both sending and receiving IR. + + For transmitting (aka sending), create a ``struct lirc_scancode`` with + the desired scancode set in the ``scancode`` member, ``rc_proto`` set + the IR protocol, and all other members set to 0. Write this struct to
Quoted 8 lines
Documentation/media/uapi/rc/lirc-dev-intro.rst LIRC modes · line 55
Quoted 6 lines
Documentation/media/uapi/rc/lirc-dev-intro.rst +6
-0+ the lirc device. + + For receiving, you read ``struct lirc_scancode`` from the lirc device, + with ``scancode`` set to the received scancode in the IR protocol + ``rc_proto``. The ``flags`` can have ``LIRC_SCANCODE_FLAG_TOGGLE`` set + if the toggle bit is set in protocols that support it (e.g. rc-5 and rc-6),Is the meaning of 'toggle' defined anywhere? I'm not sure what it means myself.
The nec protocol just sends the scancode, no key up/key down event. So it not possible to tell whether the user is pressing a button or press-release-press button. The rc-5 and rc-6 protocols therefore include a toggle-bit, which flips if the user press-release-press the button. Note that keyup event is simply absence of any IR.
Anyway, good point, I'll add it.
Quoted 21 lines
Quoted 21 lines
Documentation/media/uapi/rc/lirc-dev-intro.rst +9
-0+ or ``LIRC_SCANCODE_FLAG_REPEAT`` for when a repeat is received for protocols + that support it (e.g. nec). + + The ``timestamp`` field is filled with the time nanoseconds + (in ``CLOCK_MONOTONIC``) when the scancode was decoded. + + An ``enum rc_proto`` in the :ref:`lirc_header` lists all the supported + IR protocols. + .. _lirc-mode-mode2: ``LIRC_MODE_MODE2``Documentation/media/uapi/rc/lirc-get-features.rst +0
-0@@ -64,6 +64,14 @@ LIRC features Unused. Kept just to avoid breaking uAPI.
Quoted 7 lines
Documentation/media/uapi/rc/lirc-get-features.rst LIRC features · line 69
Quoted 3 lines
Documentation/media/uapi/rc/lirc-get-features.rst +3
-0+.. _LIRC-CAN-REC-SCANCODE: + +``LIRC_CAN_REC_SCANCODE``Wouldn't
LIRC_CAN_RECEIVE_SCANCODEbe better?I misread 'REC' as 'record' :-)
Unfortunately some lirc parts itself refers to record as well.
Quoted 2 lines
I thought about using RCV as the abbreviation, but REC is used elsewhere already (
rec_mode).
There are many other LIRC_CAN_REC_* features already.
Quoted 120 lines
Quoted 29 lines
Documentation/media/uapi/rc/lirc-get-features.rst +13
-0+ + 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 +0
-0Documentation/media/uapi/rc/lirc-get-rec-mode.rst Arguments · line 36
Quoted 6 lines
Documentation/media/uapi/rc/lirc-get-rec-mode.rst +1
-2@@ -33,8 +33,9 @@ Arguments Description =========== -Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>` -is supported for IR receive. +Get/set supported receive modes. Only :ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>`,, -> and
Quoted 10 lines
Documentation/media/uapi/rc/lirc-get-rec-mode.rst +2
-0+: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 +0
-0Documentation/media/uapi/rc/lirc-get-send-mode.rst Description · line 39
Quoted 5 lines
Documentation/media/uapi/rc/lirc-get-send-mode.rst +1
-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
Documentation/media/uapi/rc/lirc-get-send-mode.rst Description · line 40
Quoted 1 line
Documentation/media/uapi/rc/lirc-get-send-mode.rst +1
-0+:ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` is supported by for IR send,is -> are
Quoted 15 lines
Documentation/media/uapi/rc/lirc-get-send-mode.rst +0
-0depending on the driver. Use :ref:`lirc_get_features` to find out which modes the driver supports.Documentation/media/uapi/rc/lirc-read.rst +2
-1@@ -45,13 +45,19 @@ 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.Documentation/media/uapi/rc/lirc-read.rst descriptor ``fd`` into the buffer starting at ``buf``. If ``count`` is zero, · line 57
Quoted 10 lines
Documentation/media/uapi/rc/lirc-read.rst +5
-3-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 +my hardware decoders are available. The ``rc_proto`` member is set to themy -> by
Quoted 11 lines
Documentation/media/uapi/rc/lirc-read.rst +3
-0+protocol used for transmission, and ``scancode`` to the decoded scancode. + + Return Value ============Documentation/media/uapi/rc/lirc-write.rst +0
-0Documentation/media/uapi/rc/lirc-write.rst Description · line 47
Quoted 8 lines
Documentation/media/uapi/rc/lirc-write.rst +3
-2@@ -42,17 +42,27 @@ 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 to the mode.set to -> set
Quoted 10 lines
Documentation/media/uapi/rc/lirc-write.rst +1
-1When 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``.
Quoted 7 lines
Documentation/media/uapi/rc/lirc-write.rst Description · line 58
Quoted 2 lines
Documentation/media/uapi/rc/lirc-write.rst +2
-0+When in :ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` mode, one +``struct lirc_scancode`` must be written to the chardev. Set the desiredI would suggest: "must be written to the chardev at a time."
What happens when only a partial struct or multiple structs are written? Is an error returned?
Good point, I'll document this.
Quoted 5 lines
Documentation/media/uapi/rc/lirc-write.rst Description · line 60
Quoted 3 lines
Documentation/media/uapi/rc/lirc-write.rst +2
-0+scancode in the ``scancode`` member, and the protocol in the ``rc_proto`` +member. All other members must be set to 0. If there is no protocol encoderIs there a check that the other members are 0? Would such a check make sense?
There is. I'll add something about an error will be returned.
Quoted 10 lines
Documentation/media/uapi/rc/lirc-write.rst Description
Quoted 9 lines
Documentation/media/uapi/rc/lirc-write.rst +5
-0+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 ============
Thanks for your review
Sean
Sean Young
maintainerPATCH v2 21/25 media: lirc: introduce LIRC_SET_POLL_MODE
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_MODE, &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 + Documentation/media/uapi/rc/lirc-set-poll-mode.rst | 45 ++++++++++++++++++++++ drivers/media/rc/ir-lirc-codec.c | 19 +++++++-- drivers/media/rc/lirc_dev.c | 1 + include/media/rc-core.h | 3 ++ 5 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 Documentation/media/uapi/rc/lirc-set-poll-mode.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-mode
Documentation/media/uapi/rc/lirc-set-poll-mode.rst new file +45 -0
45 lines not on this page · raw message
drivers/media/rc/ir-lirc-codec.c +15 -4
@@ -353,6 +353,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_MODE : +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 :
@@ -495,13 +506,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
@@ -62,6 +62,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 recording, 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
@@ -208,6 +210,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);
Signature · 1 line
2.13.6
Re: [PATCH v2 21/25] media: lirc: introduce LIRC_SET_POLL_MODE
Quoted 2 lines · Sean Young
If you want to poll for both decoded scancodes and raw IR, then this ioctl will help you.
I don't get the point of this. You can be in one mode at a time anyway, so why not just poll for the current mode?
Quoted 9 lines
int fd =
open("/dev/lirc0", O_RDONLY | O_NONBLOCK);for (;;) { unsigned mode = LIRC_MODE_SCANCODE | LIRC_MODE_MODE2; ioctl(fd, LIRC_SET_POLL_MODE, &mode); poll(&((struct pollfd){ .fd = fd, .events = POLLIN }), 1, -1); mode = LIRC_MODE_SCANCODE; ioctl(fd, LIRC_SET_REC_MODE, &mode);
Hold on, in a comment below I read that rec_mode stands for 'recording mode'. Is that right, or should it be 'receive mode'?
Quoted 146 lines
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_MODEwill also affect the poll mode, so you must set it again before calling poll.Signed-off-by Sean Young <[email protected]>--- Documentation/media/uapi/rc/lirc-func.rst | 1 + Documentation/media/uapi/rc/lirc-set-poll-mode.rst | 45 ++++++++++++++++++++++ drivers/media/rc/ir-lirc-codec.c | 19 +++++++-- drivers/media/rc/lirc_dev.c | 1 + include/media/rc-core.h | 3 ++ 5 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 Documentation/media/uapi/rc/lirc-set-poll-mode.rstDocumentation/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-modeDocumentation/media/uapi/rc/lirc-set-poll-mode.rst new file +45
-0@@ -0,0 +1,45 @@ +.. -*- coding: utf-8; mode: rst -*- + +.. _lirc_set_poll_mode: + +********************************************** +ioctls LIRC_SET_POLL_MODE +********************************************** + +Name +==== + +LIRC_SET_POLL_MODE - Set LIRC modes to use for poll + +Synopsis +======== + +.. c:function:: int ioctl( int fd, LIRC_SET_POLL_MODE, __u32 modes) + :name: LIRC_SET_POLL_MODE + +Arguments +========= + +``fd`` + File descriptor returned by open(). + +``modes`` + Bitmask with enabled poll lirc modes + +Description +=========== + +Set lirc modes for which read readiness is reported by poll. Only +:ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>` and +:ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` are supported. Poll +can report read readiness for both modes if you bitwise or them together. +Use :ref:`lirc_get_features` to find out which modes the driver supports. + +Note that using :ref:`lirc_set_rec_mode` resets the poll mode. + +Return Value +============ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter.drivers/media/rc/ir-lirc-codec.c +15
-4@@ -353,6 +353,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_MODE : +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 :@@ -495,13 +506,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@@ -62,6 +62,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 +0
-0
include/media/rc-core.h enum rc_filter_type { · line 133
Quoted 2 lines
include/media/rc-core.h +0
-0@@ -132,6 +132,8 @@ enum rc_filter_type {* LIRC_MODE_PULSE * @rec_mode: lirc mode for recording, either LIRC_MODE_SCANCODE or
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ here is the 'recording' comment.
Quoted 8 lines
include/media/rc-core.h +2
-0* 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
include/media/rc-core.h struct rc_dev { · line 216
Quoted 7 lines
include/media/rc-core.h +1
-0@@ -208,6 +210,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);
Regards,
Hans
Sean Young
maintainerRe: [PATCH v2 21/25] media: lirc: introduce LIRC_SET_POLL_MODE
Quoted 6 lines · Hans Verkuil
Quoted 2 lines · Sean Young
If you want to poll for both decoded scancodes and raw IR, then this ioctl will help you.
I don't get the point of this. You can be in one mode at a time anyway, so why not just poll for the current mode?
Well, you might want to poll for the current mode and another mode. Actually, I think the ioctl should be called LIRC_SET_POLL_MODES to clarify that.
So say if I want to poll for raw IR (LIRC_MODE_MODE2) and decoded scancodes (LIRC_MODE_SCANCODES), then without this ioctl, I would have to poll one for a period, then switch modes, poll for the other, switch modes, ad infinitum.
Quoted 11 lines
Quoted 10 lines
int fd =
open("/dev/lirc0", O_RDONLY | O_NONBLOCK);for (;;) { unsigned mode = LIRC_MODE_SCANCODE | LIRC_MODE_MODE2; ioctl(fd, LIRC_SET_POLL_MODE, &mode); poll(&((struct pollfd){ .fd = fd, .events = POLLIN }), 1, -1); mode = LIRC_MODE_SCANCODE; ioctl(fd, LIRC_SET_REC_MODE, &mode);
Quoted 2 lines
Hold on, in a comment below I read that
rec_modestands for 'recording mode'. Is that right, or should it be 'receive mode'?
You're right, I've confused myself! Lirc calls it record and sometimes receive.
Quoted 139 lines
Quoted 139 lines
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_MODEwill also affect the poll mode, so you must set it again before calling poll.Signed-off-by Sean Young <[email protected]>--- Documentation/media/uapi/rc/lirc-func.rst | 1 + Documentation/media/uapi/rc/lirc-set-poll-mode.rst | 45 ++++++++++++++++++++++ drivers/media/rc/ir-lirc-codec.c | 19 +++++++-- drivers/media/rc/lirc_dev.c | 1 + include/media/rc-core.h | 3 ++ 5 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 Documentation/media/uapi/rc/lirc-set-poll-mode.rstDocumentation/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-modeDocumentation/media/uapi/rc/lirc-set-poll-mode.rst new file +45
-0@@ -0,0 +1,45 @@ +.. -*- coding: utf-8; mode: rst -*- + +.. _lirc_set_poll_mode: + +********************************************** +ioctls LIRC_SET_POLL_MODE +********************************************** + +Name +==== + +LIRC_SET_POLL_MODE - Set LIRC modes to use for poll + +Synopsis +======== + +.. c:function:: int ioctl( int fd, LIRC_SET_POLL_MODE, __u32 modes) + :name: LIRC_SET_POLL_MODE + +Arguments +========= + +``fd`` + File descriptor returned by open(). + +``modes`` + Bitmask with enabled poll lirc modes + +Description +=========== + +Set lirc modes for which read readiness is reported by poll. Only +:ref:`LIRC_MODE_MODE2 <lirc-mode-mode2>` and +:ref:`LIRC_MODE_SCANCODE <lirc-mode-scancode>` are supported. Poll +can report read readiness for both modes if you bitwise or them together. +Use :ref:`lirc_get_features` to find out which modes the driver supports. + +Note that using :ref:`lirc_set_rec_mode` resets the poll mode. + +Return Value +============ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter.drivers/media/rc/ir-lirc-codec.c +15
-4@@ -353,6 +353,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_MODE : +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 :@@ -495,13 +506,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@@ -62,6 +62,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 ;
Quoted 11 lines
include/media/rc-core.h enum rc_filter_type { · line 133
Quoted 9 lines
drivers/media/rc/lirc_dev.c +0
-0if (dev->driver_type ==RC_DRIVER_IR_RAW ) {if (kfifo_alloc (&dev->rawir,MAX_IR_EVENT_SIZE ,GFP_KERNEL ))include/media/rc-core.h +0
-0@@ -132,6 +132,8 @@ enum rc_filter_type {* LIRC_MODE_PULSE * @rec_mode: lirc mode for recording, either LIRC_MODE_SCANCODE or ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ here is the 'recording' comment.
Thanks for spotting that! That should be receive of course.
Quoted 19 lines
Quoted 8 lines
include/media/rc-core.h +2
-0* 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 include/media/rc-core.h struct rc_dev { · line 216
Quoted 7 lines
include/media/rc-core.h +1
-0@@ -208,6 +210,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);Regards,
Hans
Sean Young
maintainerPATCH v2 22/25 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 feature they will have enabled is LIRC_CAN_REC_SCANCODE.
Note that CEC devices will have no lirc device yet, as this is still under discussion.
--- 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
@@ -303,6 +303,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)
@@ -346,22 +349,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_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 |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
@@ -61,8 +61,13 @@ int ir_lirc_register(struct rc_dev *dev)else 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
@@ -1794,7 +1794,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;
@@ -1815,7 +1815,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);
@@ -1876,7 +1876,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 v2 23/25 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
@@ -12677,12 +12677,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 v2 24/25 media: MAINTAINERS: add entry for zilog_ir
In reply to Sean YoungAdd MAINTAINER's entry for this new driver ported from staging.
--- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+)
MAINTAINERS +6 -0
@@ -14876,6 +14876,12 @@ Q: https://patchwork.linuxtv.org/project/linux-media/list/ S: Maintained F: drivers/media/dvb-frontends/zd1301_demod* +ZILOG/HAUPPAUGE IR TRANSMITTER +M: Sean Young <[email protected]> +L: [email protected] +S: Maintained +F: drivers/media/rc/zilog_ir.c + ZPOOL COMPRESSED PAGE STORAGE API M: Dan Streetman <[email protected]> L: [email protected]
Signature · 1 line
2.13.6
Sean Young
maintainerPATCH v2 25/25 media: rc: nec decoder should not send both repeat and keycode
In reply to Sean YoungWhen receiving an nec repeat, rc_repeat() is called and then rc_keydown() with the last decoded scancode. That last call is redundant.
--- drivers/media/rc/ir-nec-decoder.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)
drivers/media/rc/ir-nec-decoder.c +17 -12
@@ -87,8 +87,6 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) data->state =STATE_BIT_PULSE ;return 0 ; }else if (eq_margin (ev.duration,NEC_REPEAT_SPACE ,NEC_UNIT /2 )) { -rc_repeat (dev); -IR_dprintk (1 ,"Repeat last key\n" ); data->state =STATE_TRAILER_PULSE ;return 0 ; }
@@ -151,19 +149,26 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)if (!geq_margin (ev.duration,NEC_TRAILER_SPACE ,NEC_UNIT /2 ))break ; - address =bitrev8 ((data->bits >>24 ) &0xff ); - not_address =bitrev8 ((data->bits >>16 ) &0xff ); - command =bitrev8 ((data->bits >>8 ) &0xff ); - not_command =bitrev8 ((data->bits >>0 ) &0xff ); +if (data->count ==NEC_NBITS ) { + address =bitrev8 ((data->bits >>24 ) &0xff ); + not_address =bitrev8 ((data->bits >>16 ) &0xff ); + command =bitrev8 ((data->bits >>8 ) &0xff ); + not_command =bitrev8 ((data->bits >>0 ) &0xff ); + + scancode =ir_nec_bytes_to_scancode (address, + not_address, + command, + not_command, + &rc_proto); - scancode =ir_nec_bytes_to_scancode (address, not_address, - command, not_command, - &rc_proto); +if (data->is_nec_x) + data->necx_repeat = true; -if (data->is_nec_x) - data->necx_repeat = true; +rc_keydown (dev, rc_proto, scancode,0 ); + }else { +rc_repeat (dev); + } -rc_keydown (dev, rc_proto, scancode,0 ); data->state =STATE_INACTIVE ;return 0 ; }
Signature · 1 line
2.13.6
Re: [PATCH v2 01/25] media: lirc: implement scancode sending
In reply to Sean YoungQuoted 327 lines · Sean Young
This 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_scancodemust 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.
Signed-off-by Sean Young <[email protected]>--- drivers/media/rc/ir-lirc-codec.c | 101 ++++++++++++++++++++++++++++----------- drivers/media/rc/rc-core-priv.h | 2 +- include/media/rc-map.h | 54 +-------------------- include/uapi/linux/lirc.h | 93 +++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 81 deletions(-)drivers/media/rc/ir-lirc-codec.c +74
-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,51 @@ 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.source || scan.target || scan.unused || + 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 +192,31 @@ 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 +245,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 */ @@ -358,7 +403,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)@@ -397,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@@ -10,59 +10,7 @@*/ #include <linux/input.h> - -/** -* enum rc_proto - the Remote Controller protocol -* -* @RC_PROTO_UNKNOWN: Protocol not known -* @RC_PROTO_OTHER: Protocol known but proprietary -* @RC_PROTO_RC5: Philips RC5 protocol -* @RC_PROTO_RC5X_20: Philips RC5x 20 bit protocol -* @RC_PROTO_RC5_SZ: StreamZap variant of RC5 -* @RC_PROTO_JVC: JVC protocol -* @RC_PROTO_SONY12: Sony 12 bit protocol -* @RC_PROTO_SONY15: Sony 15 bit protocol -* @RC_PROTO_SONY20: Sony 20 bit protocol -* @RC_PROTO_NEC: NEC protocol -* @RC_PROTO_NECX: Extended NEC protocol -* @RC_PROTO_NEC32: NEC 32 bit protocol -* @RC_PROTO_SANYO: Sanyo protocol -* @RC_PROTO_MCIR2_KBD: RC6-ish MCE keyboard -* @RC_PROTO_MCIR2_MSE: RC6-ish MCE mouse -* @RC_PROTO_RC6_0: Philips RC6-0-16 protocol -* @RC_PROTO_RC6_6A_20: Philips RC6-6A-20 protocol -* @RC_PROTO_RC6_6A_24: Philips RC6-6A-24 protocol -* @RC_PROTO_RC6_6A_32: Philips RC6-6A-32 protocol -* @RC_PROTO_RC6_MCE: MCE (Philips RC6-6A-32 subtype) protocol -* @RC_PROTO_SHARP: Sharp protocol -* @RC_PROTO_XMP: XMP protocol -* @RC_PROTO_CEC: CEC protocol -*/ -enum rc_proto { -RC_PROTO_UNKNOWN =0 , -RC_PROTO_OTHER =1 , -RC_PROTO_RC5 =2 , -RC_PROTO_RC5X_20 =3 , -RC_PROTO_RC5_SZ =4 , -RC_PROTO_JVC =5 , -RC_PROTO_SONY12 =6 , -RC_PROTO_SONY15 =7 , -RC_PROTO_SONY20 =8 , -RC_PROTO_NEC =9 , -RC_PROTO_NECX =10 , -RC_PROTO_NEC32 =11 , -RC_PROTO_SANYO =12 , -RC_PROTO_MCIR2_KBD =13 , -RC_PROTO_MCIR2_MSE =14 , -RC_PROTO_RC6_0 =15 , -RC_PROTO_RC6_6A_20 =16 , -RC_PROTO_RC6_6A_24 =17 , -RC_PROTO_RC6_6A_32 =18 , -RC_PROTO_RC6_MCE =19 , -RC_PROTO_SHARP =20 , -RC_PROTO_XMP =21 , -RC_PROTO_CEC =22 , -}; +#include <uapi/linux/lirc.h> #define RC_PROTO_BIT_NONE 0ULL#define RC_PROTO_BIT_UNKNOWN BIT_ULL(RC_PROTO_UNKNOWN)include/uapi/linux/lirc.h +25
-0@@ -46,12 +46,14 @@#define LIRC_MODE_RAW 0x00000001#define LIRC_MODE_PULSE 0x00000002#define LIRC_MODE_MODE2 0x00000004 +#define LIRC_MODE_SCANCODE 0x00000008#define LIRC_MODE_LIRCCODE 0x00000010#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW)#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE)#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2) +#define LIRC_CAN_SEND_SCANCODE LIRC_MODE2SEND(LIRC_MODE_SCANCODE)#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)#define LIRC_CAN_SEND_MASK 0x0000003f@@ -63,6 +65,7 @@#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW)#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE)#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2) +#define LIRC_CAN_REC_SCANCODE LIRC_MODE2REC(LIRC_MODE_SCANCODE)#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE)#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK)@@ -130,4 +133,94 @@#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_MODE _IOW('i', 0x00000024, __u32) + +/* +* struct lirc_scancode - decoded scancode with protocol for use with +* LIRC_MODE_SCANCODE +* +* @timestamp: Timestamp in nanoseconds using CLOCK_MONOTONIC when IR +* was decoded. +* @flags: should be 0 for transmit. When receiving scancodes, +* LIRC_SCANCODE_FLAG_TOGGLE or LIRC_SCANCODE_FLAG_REPEAT can be set +* depending on the protocol +* @target: target for transmit. Unused, set to 0. +* @source: source for receive. Unused, set to 0. +* @unused: set to 0. +* @rc_proto: see enum rc_proto
include/uapi/linux/lirc.h line 167
Quoted 10 lines
include/uapi/linux/lirc.h +10
-0+* @scancode: the scancode received or to be sent +*/ +struct lirc_scancode { +__u64 timestamp; +__u32 flags; +__u8 target; +__u8 source; +__u8 unused; +__u8 rc_proto; +__u64 scancode;
I'm thinking how this will be implemented using CEC. Some RC commands take arguments (up to 4 bytes for the 0x67 (Tune Function) code), so how will they be handled?
See CEC table 6 in the HDMI 1.4 spec.
Should they be part of the scancode, or would it be better to add a '__u8 args[8];' field?
I've no idea what makes sense, it's a weird corner case.
include/uapi/linux/lirc.h line 171
Quoted 4 lines
include/uapi/linux/lirc.h +4
-0+}; + +#define LIRC_SCANCODE_FLAG_TOGGLE 1 +#define LIRC_SCANCODE_FLAG_REPEAT 2
These flags need documentation.
Regards,
Hans
Quoted 56 lines
include/uapi/linux/lirc.h +54
-0+ +/** +* enum rc_proto - the Remote Controller protocol +* +* @RC_PROTO_UNKNOWN: Protocol not known +* @RC_PROTO_OTHER: Protocol known but proprietary +* @RC_PROTO_RC5: Philips RC5 protocol +* @RC_PROTO_RC5X_20: Philips RC5x 20 bit protocol +* @RC_PROTO_RC5_SZ: StreamZap variant of RC5 +* @RC_PROTO_JVC: JVC protocol +* @RC_PROTO_SONY12: Sony 12 bit protocol +* @RC_PROTO_SONY15: Sony 15 bit protocol +* @RC_PROTO_SONY20: Sony 20 bit protocol +* @RC_PROTO_NEC: NEC protocol +* @RC_PROTO_NECX: Extended NEC protocol +* @RC_PROTO_NEC32: NEC 32 bit protocol +* @RC_PROTO_SANYO: Sanyo protocol +* @RC_PROTO_MCIR2_KBD: RC6-ish MCE keyboard +* @RC_PROTO_MCIR2_MSE: RC6-ish MCE mouse +* @RC_PROTO_RC6_0: Philips RC6-0-16 protocol +* @RC_PROTO_RC6_6A_20: Philips RC6-6A-20 protocol +* @RC_PROTO_RC6_6A_24: Philips RC6-6A-24 protocol +* @RC_PROTO_RC6_6A_32: Philips RC6-6A-32 protocol +* @RC_PROTO_RC6_MCE: MCE (Philips RC6-6A-32 subtype) protocol +* @RC_PROTO_SHARP: Sharp protocol +* @RC_PROTO_XMP: XMP protocol +* @RC_PROTO_CEC: CEC protocol +*/ +enum rc_proto { +RC_PROTO_UNKNOWN =0 , +RC_PROTO_OTHER =1 , +RC_PROTO_RC5 =2 , +RC_PROTO_RC5X_20 =3 , +RC_PROTO_RC5_SZ =4 , +RC_PROTO_JVC =5 , +RC_PROTO_SONY12 =6 , +RC_PROTO_SONY15 =7 , +RC_PROTO_SONY20 =8 , +RC_PROTO_NEC =9 , +RC_PROTO_NECX =10 , +RC_PROTO_NEC32 =11 , +RC_PROTO_SANYO =12 , +RC_PROTO_MCIR2_KBD =13 , +RC_PROTO_MCIR2_MSE =14 , +RC_PROTO_RC6_0 =15 , +RC_PROTO_RC6_6A_20 =16 , +RC_PROTO_RC6_6A_24 =17 , +RC_PROTO_RC6_6A_32 =18 , +RC_PROTO_RC6_MCE =19 , +RC_PROTO_SHARP =20 , +RC_PROTO_XMP =21 , +RC_PROTO_CEC =22 , +}; +#endif
Sean Young
maintainerRe: [PATCH v2 01/25] media: lirc: implement scancode sending
Quoted 1 line · Hans Verkuil
On 05/10/17 10:45, Sean Young wrote:
-snip-
Quoted 27 lines
Quoted 13 lines
include/uapi/linux/lirc.h +13
-0+/* +* struct lirc_scancode - decoded scancode with protocol for use with +* LIRC_MODE_SCANCODE +* +* @timestamp: Timestamp in nanoseconds using CLOCK_MONOTONIC when IR +* was decoded. +* @flags: should be 0 for transmit. When receiving scancodes, +* LIRC_SCANCODE_FLAG_TOGGLE or LIRC_SCANCODE_FLAG_REPEAT can be set +* depending on the protocol +* @target: target for transmit. Unused, set to 0. +* @source: source for receive. Unused, set to 0. +* @unused: set to 0. +* @rc_proto: see enum rc_proto include/uapi/linux/lirc.h line 167
Quoted 10 lines
include/uapi/linux/lirc.h +10
-0+* @scancode: the scancode received or to be sent +*/ +struct lirc_scancode { +__u64 timestamp; +__u32 flags; +__u8 target; +__u8 source; +__u8 unused; +__u8 rc_proto; +__u64 scancode;I'm thinking how this will be implemented using CEC. Some RC commands take arguments (up to 4 bytes for the
0x67(Tune Function) code), so how will they be handled?
Quoted 6 lines
See CEC table 6 in the HDMI 1.4 spec.
Should they be part of the scancode, or would it be better to add a '
__u8args[8];' field?I've no idea what makes sense, it's a weird corner case.
I've given it some more thought.
For cec remote control passthrough, you have the tv with the IR receiver (A), which then transmits CEC_MSG_USER_CONTROL_PRESSED and CEC_MSG_USER_CONTROL_RELEASED cec messages to the correct target, with arguments. Then on the target (B), it reads those commands and should execute them as if it received them itself.
First of all (B) is already implemented in cec using rc-core. If RC passthrough is enabled, then cec will pass those keycodes to rc-core (which end up in an input device).
So the problem we are trying to solve here is (A). How I would see this implemented is:
1) A physical IR receiver exists which has an rc-core driver and a /dev/lircN device. This is configured using ir-keytable to map to regular input events
2) A process receives input events, and decides that a particular key/command is not for itself (e.g. tell top set box to tune), so it knows what the target cec address is and the tune arguments, so it fills out a cec_msg with the target, CEC_MSG_USER_CONTROL_PRESSED, 0x67, arguments, and then transmits it using the ioctl CEC_TRANSMIT, followed by another CEC_MSG_USER_CONTROL_RELEASED cec_msg sent using ioctl CEC_TRANSMIT.
In this way of viewing things, an rc-core device is either cec or lirc, and thus rc-core lirc devices have a /dev/lircN and rc-core cec devices have a /dev/cecN.
So, the alternative which is being proposed is that a cec device has both a /dev/cecN and a /dev/lircN. In this case step 2) would look like:
2) A process receives input events, and decides that a particular key/command is not for itself (e.g. tell top set box to tune), so it knows what the target cec address is and the tune arguments, so it fills in a lirc_scancode with the target, CEC_MSG_USER_CONTROL_PRESSED, 0x67, arguments, and then transmits it using write() to the /dev/lircN device, which then passes it on to cec_transmit() in drivers/media/cec/cec-api.c (without having a cec_fh), and then another lirc_scancode is filled in CEC_MSG_USER_CONTROL_RELEASED and sent.
Now, I think that this has a number of problems:
- It's a lot of API for simply doing a CEC_TRANSMIT
- and another chardev for a cec device (i.e. /dev/lircN).
- lirc scancode tx deals with scancodes, for cec rc passthrough it isn't really scancodes.
- Wiring this up is not going to be pretty or easy.
- The lirc chardev has no other function other than sending CEC_MSG_USER_CONTROL_PRESSED and CEC_MSG_USER_CONTROL_RELEASED cec messages.
So what I am proposing is that we don't use lirc for sending rc passthrough messages for cec.
I hope this makes sense and where not, please *do* tell me exactly where I am wrong. I think that I missed something about the scancode tx idea.
Quoted 7 lines
include/uapi/linux/lirc.h line 171
Quoted 5 lines
include/uapi/linux/lirc.h +4
-0+}; + +#define LIRC_SCANCODE_FLAG_TOGGLE 1 +#define LIRC_SCANCODE_FLAG_REPEAT 2These flags need documentation.
They do, fair point.
Thanks,
Sean
Re: [PATCH v2 01/25] media: lirc: implement scancode sending
Quoted 89 lines · Sean Young
Quoted 1 line · Hans Verkuil
On 05/10/17 10:45, Sean Young wrote:
-snip-
Quoted 27 lines
Quoted 13 lines
include/uapi/linux/lirc.h +13
-0+/* +* struct lirc_scancode - decoded scancode with protocol for use with +* LIRC_MODE_SCANCODE +* +* @timestamp: Timestamp in nanoseconds using CLOCK_MONOTONIC when IR +* was decoded. +* @flags: should be 0 for transmit. When receiving scancodes, +* LIRC_SCANCODE_FLAG_TOGGLE or LIRC_SCANCODE_FLAG_REPEAT can be set +* depending on the protocol +* @target: target for transmit. Unused, set to 0. +* @source: source for receive. Unused, set to 0. +* @unused: set to 0. +* @rc_proto: see enum rc_proto include/uapi/linux/lirc.h line 167
Quoted 10 lines
include/uapi/linux/lirc.h +10
-0+* @scancode: the scancode received or to be sent +*/ +struct lirc_scancode { +__u64 timestamp; +__u32 flags; +__u8 target; +__u8 source; +__u8 unused; +__u8 rc_proto; +__u64 scancode;I'm thinking how this will be implemented using CEC. Some RC commands take arguments (up to 4 bytes for the
0x67(Tune Function) code), so how will they be handled?Quoted 6 lines
See CEC table 6 in the HDMI 1.4 spec.
Should they be part of the scancode, or would it be better to add a '
__u8args[8];' field?I've no idea what makes sense, it's a weird corner case.
I've given it some more thought.
For cec remote control passthrough, you have the tv with the IR receiver (A), which then transmits
CEC_MSG_USER_CONTROL_PRESSEDandCEC_MSG_USER_CONTROL_RELEASEDcec messages to the correct target, with arguments. Then on the target (B), it reads those commands and should execute them as if it received them itself.First of all (B) is already implemented in cec using rc-core. If RC passthrough is enabled, then cec will pass those keycodes to rc-core (which end up in an input device).
So the problem we are trying to solve here is (A). How I would see this implemented is:
1) A physical IR receiver exists which has an rc-core driver and a
/dev/lircNdevice. This is configured using ir-keytable to map to regular input events2) A process receives input events, and decides that a particular key/command is not for itself (e.g. tell top set box to tune), so it knows what the target cec address is and the tune arguments, so it fills out a
cec_msgwith the target,CEC_MSG_USER_CONTROL_PRESSED,0x67, arguments, and then transmits it using the ioctlCEC_TRANSMIT, followed by anotherCEC_MSG_USER_CONTROL_RELEASEDcec_msgsent using ioctlCEC_TRANSMIT.In this way of viewing things, an rc-core device is either cec or lirc, and thus rc-core lirc devices have a
/dev/lircNand rc-core cec devices have a/dev/cecN.So, the alternative which is being proposed is that a cec device has both a
/dev/cecNand a/dev/lircN. In this case step 2) would look like:2) A process receives input events, and decides that a particular key/command is not for itself (e.g. tell top set box to tune), so it knows what the target cec address is and the tune arguments, so it fills in a
lirc_scancodewith the target,CEC_MSG_USER_CONTROL_PRESSED,0x67, arguments, and then transmits it usingwrite()to the/dev/lircNdevice, which then passes it on tocec_transmit()indrivers/media/cec/cec-api.c(without having acec_fh), and then anotherlirc_scancodeis filled inCEC_MSG_USER_CONTROL_RELEASEDand sent.Now, I think that this has a number of problems:
- It's a lot of API for simply doing a
CEC_TRANSMIT- and another chardev for a cec device (i.e.
/dev/lircN).- lirc scancode tx deals with scancodes, for cec rc passthrough it isn't really scancodes.
- Wiring this up is not going to be pretty or easy.
Quoted 8 lines
- The lirc chardev has no other function other than sending
CEC_MSG_USER_CONTROL_PRESSEDandCEC_MSG_USER_CONTROL_RELEASEDcec messages.So what I am proposing is that we don't use lirc for sending rc passthrough messages for cec.
I hope this makes sense and where not, please *do* tell me exactly where I am wrong. I think that I missed something about the scancode tx idea.
You are right, it makes no sense. Let's forget about this.
Regards,
Hans
Quoted 15 lines
Quoted 8 lines
include/uapi/linux/lirc.h line 171
Quoted 6 lines
include/uapi/linux/lirc.h +4
-0+}; + +#define LIRC_SCANCODE_FLAG_TOGGLE 1 +#define LIRC_SCANCODE_FLAG_REPEAT 2These flags need documentation.
They do, fair point.
Thanks,
Sean