^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright(C) 2010 Jarod Wilson <jarod@wilsonet.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Portions based on the original lirc_imon driver,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright(C) 2004 Venky Raju(dev@venky.ws)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Huge thanks to R. Geoff Newbury for invaluable debugging on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * 0xffdc iMON devices, and for sending me one to hack on, without
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * which the support for them wouldn't be nearly as good. Thanks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * also to the numerous 0xffdc device owners that tested auto-config
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * support for me and provided debug dumps from their devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/ktime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/ratelimit.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/usb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/usb/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <media/rc-core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define MOD_AUTHOR "Jarod Wilson <jarod@wilsonet.com>"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define MOD_NAME "imon"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define MOD_VERSION "0.9.4"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define DISPLAY_MINOR_BASE 144
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define DEVICE_NAME "lcd%d"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define BUF_CHUNK_SIZE 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define BUF_SIZE 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define BIT_DURATION 250 /* each bit received is 250us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define IMON_CLOCK_ENABLE_PACKETS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /*** P R O T O T Y P E S ***/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /* USB Callback prototypes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static int imon_probe(struct usb_interface *interface,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) const struct usb_device_id *id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static void imon_disconnect(struct usb_interface *interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static void usb_rx_callback_intf0(struct urb *urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static void usb_rx_callback_intf1(struct urb *urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static void usb_tx_callback(struct urb *urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /* suspend/resume support */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static int imon_resume(struct usb_interface *intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static int imon_suspend(struct usb_interface *intf, pm_message_t message);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* Display file_operations function prototypes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int display_open(struct inode *inode, struct file *file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static int display_close(struct inode *inode, struct file *file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /* VFD write operation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static ssize_t vfd_write(struct file *file, const char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) size_t n_bytes, loff_t *pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* LCD file_operations override function prototypes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static ssize_t lcd_write(struct file *file, const char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) size_t n_bytes, loff_t *pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /*** G L O B A L S ***/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct imon_panel_key_table {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) u64 hw_code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) u32 keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct imon_usb_dev_descr {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) __u16 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define IMON_NO_FLAGS 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define IMON_NEED_20MS_PKT_DELAY 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define IMON_SUPPRESS_REPEATED_KEYS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct imon_panel_key_table key_table[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct imon_context {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* Newer devices have two interfaces */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct usb_device *usbdev_intf0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct usb_device *usbdev_intf1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) bool display_supported; /* not all controllers do */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) bool display_isopen; /* display port has been opened */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) bool rf_device; /* true if iMON 2.4G LT/DT RF device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) bool rf_isassociating; /* RF remote associating */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) bool dev_present_intf0; /* USB device presence, interface 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) bool dev_present_intf1; /* USB device presence, interface 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct mutex lock; /* to lock this object */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) wait_queue_head_t remove_ok; /* For unexpected USB disconnects */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct usb_endpoint_descriptor *rx_endpoint_intf0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct usb_endpoint_descriptor *rx_endpoint_intf1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct usb_endpoint_descriptor *tx_endpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct urb *rx_urb_intf0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct urb *rx_urb_intf1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct urb *tx_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) bool tx_control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) unsigned char usb_rx_buf[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) unsigned char usb_tx_buf[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) unsigned int send_packet_delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct tx_t {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) unsigned char data_buf[35]; /* user data buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct completion finished; /* wait for write to finish */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) bool busy; /* write in progress */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) int status; /* status of tx completion */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) } tx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) u16 vendor; /* usb vendor ID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) u16 product; /* usb product ID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct rc_dev *rdev; /* rc-core device for remote */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct input_dev *idev; /* input device for panel & IR mouse */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) struct input_dev *touch; /* input device for touchscreen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) spinlock_t kc_lock; /* make sure we get keycodes right */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) u32 kc; /* current input keycode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) u32 last_keycode; /* last reported input keycode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) u32 rc_scancode; /* the computed remote scancode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) u8 rc_toggle; /* the computed remote toggle bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) u64 rc_proto; /* iMON or MCE (RC6) IR protocol? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) bool release_code; /* some keys send a release code */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) u8 display_type; /* store the display type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) bool pad_mouse; /* toggle kbd(0)/mouse(1) mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) char name_rdev[128]; /* rc input device name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) char phys_rdev[64]; /* rc input device phys path */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) char name_idev[128]; /* input device name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) char phys_idev[64]; /* input device phys path */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) char name_touch[128]; /* touch screen name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) char phys_touch[64]; /* touch screen phys path */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) struct timer_list ttimer; /* touch screen timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) int touch_x; /* x coordinate on touchscreen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) int touch_y; /* y coordinate on touchscreen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) const struct imon_usb_dev_descr *dev_descr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* device description with key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /* table for front panels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #define TOUCH_TIMEOUT (HZ/30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* vfd character device file operations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static const struct file_operations vfd_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .open = &display_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .write = &vfd_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) .release = &display_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .llseek = noop_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /* lcd character device file operations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) static const struct file_operations lcd_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .open = &display_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .write = &lcd_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .release = &display_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .llseek = noop_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) IMON_DISPLAY_TYPE_AUTO = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) IMON_DISPLAY_TYPE_VFD = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) IMON_DISPLAY_TYPE_LCD = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) IMON_DISPLAY_TYPE_VGA = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) IMON_DISPLAY_TYPE_NONE = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) IMON_KEY_IMON = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) IMON_KEY_MCE = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) IMON_KEY_PANEL = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static struct usb_class_driver imon_vfd_class = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .name = DEVICE_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .fops = &vfd_fops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .minor_base = DISPLAY_MINOR_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static struct usb_class_driver imon_lcd_class = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) .name = DEVICE_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .fops = &lcd_fops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) .minor_base = DISPLAY_MINOR_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /* imon receiver front panel/knob key table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static const struct imon_usb_dev_descr imon_default_table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) .flags = IMON_NO_FLAGS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) .key_table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) { 0x000000001200ffeell, KEY_UP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) { 0x000000001300ffeell, KEY_DOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) { 0x000000001400ffeell, KEY_LEFT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) { 0x000000001500ffeell, KEY_RIGHT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) { 0x000000001600ffeell, KEY_ENTER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) { 0x000000001700ffeell, KEY_ESC },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) { 0x000000001f00ffeell, KEY_AUDIO },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) { 0x000000002000ffeell, KEY_VIDEO },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) { 0x000000002100ffeell, KEY_CAMERA },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) { 0x000000002700ffeell, KEY_DVD },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) { 0x000000002300ffeell, KEY_TV },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) { 0x000000002b00ffeell, KEY_EXIT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) { 0x000000002c00ffeell, KEY_SELECT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) { 0x000000002d00ffeell, KEY_MENU },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) { 0x000000000500ffeell, KEY_PREVIOUS },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) { 0x000000000700ffeell, KEY_REWIND },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) { 0x000000000400ffeell, KEY_STOP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) { 0x000000003c00ffeell, KEY_PLAYPAUSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) { 0x000000000800ffeell, KEY_FASTFORWARD },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) { 0x000000000600ffeell, KEY_NEXT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) { 0x000000010000ffeell, KEY_RIGHT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) { 0x000001000000ffeell, KEY_LEFT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) { 0x000000003d00ffeell, KEY_SELECT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) { 0x000100000000ffeell, KEY_VOLUMEUP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) { 0x010000000000ffeell, KEY_VOLUMEDOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) { 0x000000000100ffeell, KEY_MUTE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* 0xffdc iMON MCE VFD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) { 0x00010000ffffffeell, KEY_VOLUMEUP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) { 0x00000001ffffffeell, KEY_MUTE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) { 0x0000000fffffffeell, KEY_MEDIA },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) { 0x00000012ffffffeell, KEY_UP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) { 0x00000013ffffffeell, KEY_DOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) { 0x00000014ffffffeell, KEY_LEFT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) { 0x00000015ffffffeell, KEY_RIGHT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) { 0x00000016ffffffeell, KEY_ENTER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) { 0x00000017ffffffeell, KEY_ESC },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) /* iMON Knob values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) { 0x000100ffffffffeell, KEY_VOLUMEUP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) { 0x000008ffffffffeell, KEY_MUTE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) { 0, KEY_RESERVED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static const struct imon_usb_dev_descr imon_OEM_VFD = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) .flags = IMON_NEED_20MS_PKT_DELAY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) .key_table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) { 0x000000001200ffeell, KEY_UP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) { 0x000000001300ffeell, KEY_DOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) { 0x000000001400ffeell, KEY_LEFT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) { 0x000000001500ffeell, KEY_RIGHT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) { 0x000000001600ffeell, KEY_ENTER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) { 0x000000001700ffeell, KEY_ESC },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) { 0x000000001f00ffeell, KEY_AUDIO },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) { 0x000000002b00ffeell, KEY_EXIT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) { 0x000000002c00ffeell, KEY_SELECT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) { 0x000000002d00ffeell, KEY_MENU },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) { 0x000000000500ffeell, KEY_PREVIOUS },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) { 0x000000000700ffeell, KEY_REWIND },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) { 0x000000000400ffeell, KEY_STOP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) { 0x000000003c00ffeell, KEY_PLAYPAUSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) { 0x000000000800ffeell, KEY_FASTFORWARD },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) { 0x000000000600ffeell, KEY_NEXT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) { 0x000000010000ffeell, KEY_RIGHT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) { 0x000001000000ffeell, KEY_LEFT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) { 0x000000003d00ffeell, KEY_SELECT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) { 0x000100000000ffeell, KEY_VOLUMEUP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) { 0x010000000000ffeell, KEY_VOLUMEDOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) { 0x000000000100ffeell, KEY_MUTE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /* 0xffdc iMON MCE VFD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) { 0x00010000ffffffeell, KEY_VOLUMEUP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) { 0x00000001ffffffeell, KEY_MUTE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) { 0x0000000fffffffeell, KEY_MEDIA },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) { 0x00000012ffffffeell, KEY_UP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) { 0x00000013ffffffeell, KEY_DOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) { 0x00000014ffffffeell, KEY_LEFT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) { 0x00000015ffffffeell, KEY_RIGHT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) { 0x00000016ffffffeell, KEY_ENTER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) { 0x00000017ffffffeell, KEY_ESC },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /* iMON Knob values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) { 0x000100ffffffffeell, KEY_VOLUMEUP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) { 0x000008ffffffffeell, KEY_MUTE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) { 0, KEY_RESERVED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) /* imon receiver front panel/knob key table for DH102*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static const struct imon_usb_dev_descr imon_DH102 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) .flags = IMON_NO_FLAGS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) .key_table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) { 0x000100000000ffeell, KEY_VOLUMEUP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) { 0x010000000000ffeell, KEY_VOLUMEDOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) { 0x000000010000ffeell, KEY_MUTE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) { 0x0000000f0000ffeell, KEY_MEDIA },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) { 0x000000120000ffeell, KEY_UP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) { 0x000000130000ffeell, KEY_DOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) { 0x000000140000ffeell, KEY_LEFT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) { 0x000000150000ffeell, KEY_RIGHT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) { 0x000000160000ffeell, KEY_ENTER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) { 0x000000170000ffeell, KEY_ESC },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) { 0x0000002b0000ffeell, KEY_EXIT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) { 0x0000002c0000ffeell, KEY_SELECT },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) { 0x0000002d0000ffeell, KEY_MENU },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) { 0, KEY_RESERVED }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) /* imon ultrabay front panel key table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) static const struct imon_usb_dev_descr ultrabay_table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .flags = IMON_SUPPRESS_REPEATED_KEYS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .key_table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) { 0x0000000f0000ffeell, KEY_MEDIA }, /* Go */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) { 0x000000000100ffeell, KEY_UP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) { 0x000000000001ffeell, KEY_DOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) { 0x000000160000ffeell, KEY_ENTER },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) { 0x0000001f0000ffeell, KEY_AUDIO }, /* Music */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) { 0x000000200000ffeell, KEY_VIDEO }, /* Movie */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) { 0x000000210000ffeell, KEY_CAMERA }, /* Photo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) { 0x000000270000ffeell, KEY_DVD }, /* DVD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) { 0x000000230000ffeell, KEY_TV }, /* TV */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) { 0x000000050000ffeell, KEY_PREVIOUS }, /* Previous */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) { 0x000000070000ffeell, KEY_REWIND },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) { 0x000000040000ffeell, KEY_STOP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) { 0x000000020000ffeell, KEY_PLAYPAUSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) { 0x000000080000ffeell, KEY_FASTFORWARD },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) { 0x000000060000ffeell, KEY_NEXT }, /* Next */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) { 0x000100000000ffeell, KEY_VOLUMEUP },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) { 0x010000000000ffeell, KEY_VOLUMEDOWN },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) { 0x000000010000ffeell, KEY_MUTE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) { 0, KEY_RESERVED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) * USB Device ID for iMON USB Control Boards
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) * The Windows drivers contain 6 different inf files, more or less one for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) * each new device until the 0x0034-0x0046 devices, which all use the same
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * driver. Some of the devices in the 34-46 range haven't been definitively
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) * identified yet. Early devices have either a TriGem Computer, Inc. or a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) * devices use the SoundGraph vendor ID (0x15c2). This driver only supports
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) * the ffdc and later devices, which do onboard decoding.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) static const struct usb_device_id imon_usb_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) * Several devices with this same device ID, all use iMON_PAD.inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) * SoundGraph iMON PAD (IR & VFD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) * SoundGraph iMON PAD (IR & LCD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) * SoundGraph iMON Knob (IR only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) { USB_DEVICE(0x15c2, 0xffdc),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) .driver_info = (unsigned long)&imon_default_table },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * Newer devices, all driven by the latest iMON Windows driver, full
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) * list of device IDs extracted via 'strings Setup/data1.hdr |grep 15c2'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * Need user input to fill in details on unknown devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) { USB_DEVICE(0x15c2, 0x0034),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) .driver_info = (unsigned long)&imon_DH102 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) { USB_DEVICE(0x15c2, 0x0035),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) /* SoundGraph iMON OEM VFD (IR & VFD) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) { USB_DEVICE(0x15c2, 0x0036),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) .driver_info = (unsigned long)&imon_OEM_VFD },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) /* device specifics unknown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) { USB_DEVICE(0x15c2, 0x0037),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) /* SoundGraph iMON OEM LCD (IR & LCD) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) { USB_DEVICE(0x15c2, 0x0038),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) /* SoundGraph iMON UltraBay (IR & LCD) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) { USB_DEVICE(0x15c2, 0x0039),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) /* device specifics unknown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) { USB_DEVICE(0x15c2, 0x003a),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) /* device specifics unknown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) { USB_DEVICE(0x15c2, 0x003b),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) /* SoundGraph iMON OEM Inside (IR only) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) { USB_DEVICE(0x15c2, 0x003c),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) /* device specifics unknown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) { USB_DEVICE(0x15c2, 0x003d),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /* device specifics unknown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) { USB_DEVICE(0x15c2, 0x003e),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) /* device specifics unknown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) { USB_DEVICE(0x15c2, 0x003f),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) /* device specifics unknown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) { USB_DEVICE(0x15c2, 0x0040),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) /* SoundGraph iMON MINI (IR only) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) { USB_DEVICE(0x15c2, 0x0041),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) /* Antec Veris Multimedia Station EZ External (IR only) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) { USB_DEVICE(0x15c2, 0x0042),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) /* Antec Veris Multimedia Station Basic Internal (IR only) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) { USB_DEVICE(0x15c2, 0x0043),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) /* Antec Veris Multimedia Station Elite (IR & VFD) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) { USB_DEVICE(0x15c2, 0x0044),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) /* Antec Veris Multimedia Station Premiere (IR & LCD) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) { USB_DEVICE(0x15c2, 0x0045),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) /* device specifics unknown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) { USB_DEVICE(0x15c2, 0x0046),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) .driver_info = (unsigned long)&imon_default_table},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) /* USB Device data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) static struct usb_driver imon_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) .name = MOD_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) .probe = imon_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) .disconnect = imon_disconnect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) .suspend = imon_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) .resume = imon_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) .id_table = imon_usb_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) /* to prevent races between open() and disconnect(), probing, etc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) static DEFINE_MUTEX(driver_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /* Module bookkeeping bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) MODULE_AUTHOR(MOD_AUTHOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) MODULE_DESCRIPTION(MOD_DESC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) MODULE_VERSION(MOD_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) static bool debug;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) module_param(debug, bool, S_IRUGO | S_IWUSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) /* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) static int display_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) module_param(display_type, int, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, 1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) static int pad_stabilize = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) module_param(pad_stabilize, int, S_IRUGO | S_IWUSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD presses in arrow key mode. 0=disable, 1=enable (default).");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) * In certain use cases, mouse mode isn't really helpful, and could actually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) * cause confusion, so allow disabling it when the IR device is open.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) static bool nomouse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) module_param(nomouse, bool, S_IRUGO | S_IWUSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is open. 0=don't disable, 1=disable. (default: don't disable)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) /* threshold at which a pad push registers as an arrow key in kbd mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) static int pad_thresh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) module_param(pad_thresh, int, S_IRUGO | S_IWUSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an arrow key in kbd mode (default: 28)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) static void free_imon_context(struct imon_context *ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) struct device *dev = ictx->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) usb_free_urb(ictx->tx_urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) usb_free_urb(ictx->rx_urb_intf0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) usb_free_urb(ictx->rx_urb_intf1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) kfree(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) dev_dbg(dev, "%s: iMON context freed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) * Called when the Display device (e.g. /dev/lcd0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) * is opened by the application.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) static int display_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) struct usb_interface *interface;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) struct imon_context *ictx = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) int subminor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) /* prevent races with disconnect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) mutex_lock(&driver_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) subminor = iminor(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) interface = usb_find_interface(&imon_driver, subminor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (!interface) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) pr_err("could not find interface for minor %d\n", subminor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) ictx = usb_get_intfdata(interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (!ictx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) pr_err("no context found for minor %d\n", subminor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) if (!ictx->display_supported) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) pr_err("display not supported by device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) } else if (ictx->display_isopen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) pr_err("display port is already open\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) retval = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) ictx->display_isopen = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) file->private_data = ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) dev_dbg(ictx->dev, "display port opened\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) mutex_unlock(&driver_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) * Called when the display device (e.g. /dev/lcd0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) * is closed by the application.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) static int display_close(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) struct imon_context *ictx = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) ictx = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (!ictx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) pr_err("no context for device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (!ictx->display_supported) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) pr_err("display not supported by device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) } else if (!ictx->display_isopen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) pr_err("display is not open\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) retval = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) ictx->display_isopen = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) dev_dbg(ictx->dev, "display port closed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) * Sends a packet to the device -- this function must be called with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) * ictx->lock held, or its unlock/lock sequence while waiting for tx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) * to complete can/will lead to a deadlock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) static int send_packet(struct imon_context *ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) unsigned int pipe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) int interval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) struct usb_ctrlrequest *control_req = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) /* Check if we need to use control or interrupt urb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (!ictx->tx_control) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) pipe = usb_sndintpipe(ictx->usbdev_intf0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) ictx->tx_endpoint->bEndpointAddress);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) interval = ictx->tx_endpoint->bInterval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) usb_fill_int_urb(ictx->tx_urb, ictx->usbdev_intf0, pipe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) ictx->usb_tx_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) sizeof(ictx->usb_tx_buf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) usb_tx_callback, ictx, interval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) ictx->tx_urb->actual_length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) /* fill request into kmalloc'ed space: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) control_req = kmalloc(sizeof(*control_req), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (control_req == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) /* setup packet is '21 09 0200 0001 0008' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) control_req->bRequestType = 0x21;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) control_req->bRequest = 0x09;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) control_req->wValue = cpu_to_le16(0x0200);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) control_req->wIndex = cpu_to_le16(0x0001);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) control_req->wLength = cpu_to_le16(0x0008);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) /* control pipe is endpoint 0x00 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) pipe = usb_sndctrlpipe(ictx->usbdev_intf0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) /* build the control urb */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) usb_fill_control_urb(ictx->tx_urb, ictx->usbdev_intf0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) pipe, (unsigned char *)control_req,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) ictx->usb_tx_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) sizeof(ictx->usb_tx_buf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) usb_tx_callback, ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) ictx->tx_urb->actual_length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) reinit_completion(&ictx->tx.finished);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) ictx->tx.busy = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) smp_rmb(); /* ensure later readers know we're busy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) ictx->tx.busy = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) smp_rmb(); /* ensure later readers know we're not busy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) pr_err_ratelimited("error submitting urb(%d)\n", retval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) /* Wait for transmission to complete (or abort) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) retval = wait_for_completion_interruptible(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) &ictx->tx.finished);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) usb_kill_urb(ictx->tx_urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) pr_err_ratelimited("task interrupted\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) retval = ictx->tx.status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) pr_err_ratelimited("packet tx failed (%d)\n", retval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) kfree(control_req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) * Induce a mandatory delay before returning, as otherwise,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) * send_packet can get called so rapidly as to overwhelm the device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) * particularly on faster systems and/or those with quirky usb.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) timeout = msecs_to_jiffies(ictx->send_packet_delay);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) set_current_state(TASK_INTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) schedule_timeout(timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) * Sends an associate packet to the iMON 2.4G.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) * This might not be such a good idea, since it has an id collision with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) * some versions of the "IR & VFD" combo. The only way to determine if it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * is an RF version is to look at the product description string. (Which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) * we currently do not fetch).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) static int send_associate_24g(struct imon_context *ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) const unsigned char packet[8] = { 0x01, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 0x00, 0x00, 0x00, 0x20 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) if (!ictx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) pr_err("no context for device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) if (!ictx->dev_present_intf0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) pr_err("no iMON device present\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) memcpy(ictx->usb_tx_buf, packet, sizeof(packet));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) retval = send_packet(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) * Sends packets to setup and show clock on iMON display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) * Arguments: year - last 2 digits of year, month - 1..12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) * day - 1..31, dow - day of the week (0-Sun...6-Sat),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) * hour - 0..23, minute - 0..59, second - 0..59
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) static int send_set_imon_clock(struct imon_context *ictx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) unsigned int year, unsigned int month,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) unsigned int day, unsigned int dow,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) unsigned int hour, unsigned int minute,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) unsigned int second)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) unsigned char clock_enable_pkt[IMON_CLOCK_ENABLE_PACKETS][8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) if (!ictx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) pr_err("no context for device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) switch (ictx->display_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) case IMON_DISPLAY_TYPE_LCD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) clock_enable_pkt[0][0] = 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) clock_enable_pkt[0][1] = year;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) clock_enable_pkt[0][2] = month-1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) clock_enable_pkt[0][3] = day;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) clock_enable_pkt[0][4] = hour;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) clock_enable_pkt[0][5] = minute;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) clock_enable_pkt[0][6] = second;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) clock_enable_pkt[1][0] = 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) clock_enable_pkt[1][1] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) clock_enable_pkt[1][2] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) clock_enable_pkt[1][3] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) clock_enable_pkt[1][4] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) clock_enable_pkt[1][5] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) clock_enable_pkt[1][6] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (ictx->product == 0xffdc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) clock_enable_pkt[0][7] = 0x50;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) clock_enable_pkt[1][7] = 0x51;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) clock_enable_pkt[0][7] = 0x88;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) clock_enable_pkt[1][7] = 0x8a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) case IMON_DISPLAY_TYPE_VFD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) clock_enable_pkt[0][0] = year;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) clock_enable_pkt[0][1] = month-1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) clock_enable_pkt[0][2] = day;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) clock_enable_pkt[0][3] = dow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) clock_enable_pkt[0][4] = hour;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) clock_enable_pkt[0][5] = minute;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) clock_enable_pkt[0][6] = second;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) clock_enable_pkt[0][7] = 0x40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) clock_enable_pkt[1][0] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) clock_enable_pkt[1][1] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) clock_enable_pkt[1][2] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) clock_enable_pkt[1][3] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) clock_enable_pkt[1][4] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) clock_enable_pkt[1][5] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) clock_enable_pkt[1][6] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) clock_enable_pkt[1][7] = 0x42;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) for (i = 0; i < IMON_CLOCK_ENABLE_PACKETS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) retval = send_packet(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) pr_err("send_packet failed for packet %d\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) * These are the sysfs functions to handle the association on the iMON 2.4G LT.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) static ssize_t show_associate_remote(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) struct imon_context *ictx = dev_get_drvdata(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) if (!ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) if (ictx->rf_isassociating)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) strscpy(buf, "associating\n", PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) strscpy(buf, "closed\n", PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) dev_info(d, "Visit https://www.lirc.org/html/imon-24g.html for instructions on how to associate your iMON 2.4G DT/LT remote\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) return strlen(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) static ssize_t store_associate_remote(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) struct imon_context *ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) ictx = dev_get_drvdata(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) if (!ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) ictx->rf_isassociating = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) send_associate_24g(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) * sysfs functions to control internal imon clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) static ssize_t show_imon_clock(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) struct imon_context *ictx = dev_get_drvdata(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) size_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if (!ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if (!ictx->display_supported) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) len = snprintf(buf, PAGE_SIZE, "Not supported.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) len = snprintf(buf, PAGE_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) "To set the clock on your iMON display:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) "# date \"+%%y %%m %%d %%w %%H %%M %%S\" > imon_clock\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) "%s", ictx->display_isopen ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) "\nNOTE: imon device must be closed\n" : "");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) static ssize_t store_imon_clock(struct device *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) struct imon_context *ictx = dev_get_drvdata(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) ssize_t retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) unsigned int year, month, day, dow, hour, minute, second;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) if (!ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (!ictx->display_supported) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) } else if (ictx->display_isopen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) retval = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) if (sscanf(buf, "%u %u %u %u %u %u %u", &year, &month, &day, &dow,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) &hour, &minute, &second) != 7) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) retval = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) if ((month < 1 || month > 12) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) (day < 1 || day > 31) || (dow > 6) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) (hour > 23) || (minute > 59) || (second > 59)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) retval = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) retval = send_set_imon_clock(ictx, year, month, day, dow,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) hour, minute, second);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) retval = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) static DEVICE_ATTR(imon_clock, S_IWUSR | S_IRUGO, show_imon_clock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) store_imon_clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) store_associate_remote);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) static struct attribute *imon_display_sysfs_entries[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) &dev_attr_imon_clock.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) static const struct attribute_group imon_display_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) .attrs = imon_display_sysfs_entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) static struct attribute *imon_rf_sysfs_entries[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) &dev_attr_associate_remote.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) static const struct attribute_group imon_rf_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) .attrs = imon_rf_sysfs_entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) * Writes data to the VFD. The iMON VFD is 2x16 characters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) * and requires data in 5 consecutive USB interrupt packets,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) * each packet but the last carrying 7 bytes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) * I don't know if the VFD board supports features such as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) * scrolling, clearing rows, blanking, etc. so at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) * the caller must provide a full screen of data. If fewer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) * than 32 bytes are provided spaces will be appended to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) * generate a full screen.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) static ssize_t vfd_write(struct file *file, const char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) size_t n_bytes, loff_t *pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) int seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) struct imon_context *ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) static const unsigned char vfd_packet6[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) ictx = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) if (!ictx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) pr_err_ratelimited("no context for device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) if (!ictx->dev_present_intf0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) pr_err_ratelimited("no iMON device present\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) if (n_bytes <= 0 || n_bytes > 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) pr_err_ratelimited("invalid payload size\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) retval = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) if (copy_from_user(ictx->tx.data_buf, buf, n_bytes)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) retval = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) /* Pad with spaces */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) for (i = n_bytes; i < 32; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) ictx->tx.data_buf[i] = ' ';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) for (i = 32; i < 35; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) ictx->tx.data_buf[i] = 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) seq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) memcpy(ictx->usb_tx_buf, ictx->tx.data_buf + offset, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) ictx->usb_tx_buf[7] = (unsigned char) seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) retval = send_packet(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) pr_err_ratelimited("send packet #%d failed\n", seq / 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) seq += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) offset += 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) } while (offset < 35);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) /* Send packet #6 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) memcpy(ictx->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) ictx->usb_tx_buf[7] = (unsigned char) seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) retval = send_packet(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) pr_err_ratelimited("send packet #%d failed\n", seq / 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) return (!retval) ? n_bytes : retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) * Writes data to the LCD. The iMON OEM LCD screen expects 8-byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) * packets. We accept data as 16 hexadecimal digits, followed by a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) * newline (to make it easy to drive the device from a command-line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) * -- even though the actual binary data is a bit complicated).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) * The device itself is not a "traditional" text-mode display. It's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) * actually a 16x96 pixel bitmap display. That means if you want to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) * display text, you've got to have your own "font" and translate the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) * text into bitmaps for display. This is really flexible (you can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) * display whatever diacritics you need, and so on), but it's also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) * a lot more complicated than most LCDs...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) static ssize_t lcd_write(struct file *file, const char __user *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) size_t n_bytes, loff_t *pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) struct imon_context *ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) ictx = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) if (!ictx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) pr_err_ratelimited("no context for device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) if (!ictx->display_supported) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) pr_err_ratelimited("no iMON display present\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) if (n_bytes != 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) pr_err_ratelimited("invalid payload size: %d (expected 8)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) (int)n_bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) retval = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) if (copy_from_user(ictx->usb_tx_buf, buf, 8)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) retval = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) retval = send_packet(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) if (retval) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) pr_err_ratelimited("send packet failed!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) __func__, (int) n_bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) return (!retval) ? n_bytes : retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) * Callback function for USB core API: transmit data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) static void usb_tx_callback(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) struct imon_context *ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) if (!urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) ictx = (struct imon_context *)urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) if (!ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) ictx->tx.status = urb->status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) /* notify waiters that write has finished */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) ictx->tx.busy = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) smp_rmb(); /* ensure later readers know we're not busy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) complete(&ictx->tx.finished);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) * report touchscreen input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) static void imon_touch_display_timeout(struct timer_list *t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) struct imon_context *ictx = from_timer(ictx, t, ttimer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) if (ictx->display_type != IMON_DISPLAY_TYPE_VGA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) input_report_abs(ictx->touch, ABS_X, ictx->touch_x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) input_report_abs(ictx->touch, ABS_Y, ictx->touch_y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) input_report_key(ictx->touch, BTN_TOUCH, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) input_sync(ictx->touch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) * iMON IR receivers support two different signal sets -- those used by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) * the iMON remotes, and those used by the Windows MCE remotes (which is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) * really just RC-6), but only one or the other at a time, as the signals
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) * are decoded onboard the receiver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) * This function gets called two different ways, one way is from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) * rc_register_device, for initial protocol selection/setup, and the other is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) * via a userspace-initiated protocol change request, either by direct sysfs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) * prodding or by something like ir-keytable. In the rc_register_device case,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) * the imon context lock is already held, but when initiated from userspace,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) * it is not, so we must acquire it prior to calling send_packet, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) * requires that the lock is held.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) struct imon_context *ictx = rc->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) struct device *dev = ictx->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) bool unlock = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) unsigned char ir_proto_packet[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) if (*rc_proto && !(*rc_proto & rc->allowed_protocols))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) dev_warn(dev, "Looks like you're trying to use an IR protocol this device does not support\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) if (*rc_proto & RC_PROTO_BIT_RC6_MCE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) dev_dbg(dev, "Configuring IR receiver for MCE protocol\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) ir_proto_packet[0] = 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) *rc_proto = RC_PROTO_BIT_RC6_MCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) } else if (*rc_proto & RC_PROTO_BIT_IMON) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) if (!pad_stabilize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) dev_dbg(dev, "PAD stabilize functionality disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) /* ir_proto_packet[0] = 0x00; // already the default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) *rc_proto = RC_PROTO_BIT_IMON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) dev_warn(dev, "Unsupported IR protocol specified, overriding to iMON IR protocol\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) if (!pad_stabilize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) dev_dbg(dev, "PAD stabilize functionality disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) /* ir_proto_packet[0] = 0x00; // already the default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) *rc_proto = RC_PROTO_BIT_IMON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) if (!mutex_is_locked(&ictx->lock)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) unlock = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) retval = send_packet(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) ictx->rc_proto = *rc_proto;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) ictx->pad_mouse = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) if (unlock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) * The directional pad behaves a bit differently, depending on whether this is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) * one of the older ffdc devices or a newer device. Newer devices appear to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) * have a higher resolution matrix for more precise mouse movement, but it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) * makes things overly sensitive in keyboard mode, so we do some interesting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) * contortions to make it less touchy. Older devices run through the same
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) * routine with shorter timeout and a smaller threshold.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) static int stabilize(int a, int b, u16 timeout, u16 threshold)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) ktime_t ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) static ktime_t prev_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) static ktime_t hit_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) static int x, y, prev_result, hits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) long msec, msec_hit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) ct = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) msec = ktime_ms_delta(ct, prev_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) msec_hit = ktime_ms_delta(ct, hit_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) if (msec > 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) x = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) y = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) hits = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) x += a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) y += b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) prev_time = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) if (abs(x) > threshold || abs(y) > threshold) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) if (abs(y) > abs(x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) result = (y > 0) ? 0x7F : 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) result = (x > 0) ? 0x7F00 : 0x8000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) x = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) y = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) if (result == prev_result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) hits++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) if (hits > 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) switch (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) case 0x7F:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) y = 17 * threshold / 30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) case 0x80:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) y -= 17 * threshold / 30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) case 0x7F00:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) x = 17 * threshold / 30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) case 0x8000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) x -= 17 * threshold / 30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) if (hits == 2 && msec_hit < timeout) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) hits = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) prev_result = result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) hits = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) hit_time = ct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 scancode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) u32 keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) u32 release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) bool is_release_code = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) /* Look for the initial press of a button */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) ictx->rc_toggle = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) ictx->rc_scancode = scancode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) /* Look for the release of a button */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) if (keycode == KEY_RESERVED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) release = scancode & ~0x4000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) keycode = rc_g_keycode_from_table(ictx->rdev, release);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) if (keycode != KEY_RESERVED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) is_release_code = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) ictx->release_code = is_release_code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) return keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) u32 keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) #define MCE_KEY_MASK 0x7000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) #define MCE_TOGGLE_BIT 0x8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) * On some receivers, mce keys decode to 0x8000f04xx and 0x8000f84xx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) * (the toggle bit flipping between alternating key presses), while
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) * on other receivers, we see 0x8000f74xx and 0x8000ff4xx. To keep
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) * the table trim, we always or in the bits to look up 0x8000ff4xx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) * but we can't or them into all codes, as some keys are decoded in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) * a different way w/o the same use of the toggle bit...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) if (scancode & 0x80000000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) ictx->rc_scancode = scancode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) /* not used in mce mode, but make sure we know its false */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) ictx->release_code = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) return keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) static u32 imon_panel_key_lookup(struct imon_context *ictx, u64 code)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) const struct imon_panel_key_table *key_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) u32 keycode = KEY_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) key_table = ictx->dev_descr->key_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) for (i = 0; key_table[i].hw_code != 0; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) if (key_table[i].hw_code == (code | 0xffee)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) keycode = key_table[i].keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) ictx->release_code = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) return keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) static bool imon_mouse_event(struct imon_context *ictx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) unsigned char *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) signed char rel_x = 0x00, rel_y = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) u8 right_shift = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) bool mouse_input = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) int dir = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) spin_lock_irqsave(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) /* newer iMON device PAD or mouse button */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) rel_x = buf[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) rel_y = buf[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) right_shift = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) /* 0xffdc iMON PAD or mouse button input */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) } else if (ictx->product == 0xffdc && (buf[0] & 0x40) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) !((buf[1] & 0x01) || ((buf[1] >> 2) & 0x01))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) if (buf[0] & 0x02)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) rel_x |= ~0x0f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) rel_x = rel_x + rel_x / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) if (buf[0] & 0x01)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) rel_y |= ~0x0f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) rel_y = rel_y + rel_y / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) right_shift = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) /* some ffdc devices decode mouse buttons differently... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) } else if (ictx->product == 0xffdc && (buf[0] == 0x68)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) right_shift = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) /* ch+/- buttons, which we use for an emulated scroll wheel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) } else if (ictx->kc == KEY_CHANNELUP && (buf[2] & 0x40) != 0x40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) dir = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) } else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) dir = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) mouse_input = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) spin_unlock_irqrestore(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) if (mouse_input) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) if (dir) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) input_report_rel(ictx->idev, REL_WHEEL, dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) } else if (rel_x || rel_y) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) input_report_rel(ictx->idev, REL_X, rel_x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) input_report_rel(ictx->idev, REL_Y, rel_y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) input_report_key(ictx->idev, BTN_LEFT, buf[1] & 0x1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) input_report_key(ictx->idev, BTN_RIGHT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) buf[1] >> right_shift & 0x1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) input_sync(ictx->idev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) spin_lock_irqsave(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) ictx->last_keycode = ictx->kc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) spin_unlock_irqrestore(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) return mouse_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) static void imon_touch_event(struct imon_context *ictx, unsigned char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) mod_timer(&ictx->ttimer, jiffies + TOUCH_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) ictx->touch_x = (buf[0] << 4) | (buf[1] >> 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) ictx->touch_y = 0xfff - ((buf[2] << 4) | (buf[1] & 0xf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) input_report_abs(ictx->touch, ABS_X, ictx->touch_x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) input_report_abs(ictx->touch, ABS_Y, ictx->touch_y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) input_report_key(ictx->touch, BTN_TOUCH, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) input_sync(ictx->touch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) int dir = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) signed char rel_x = 0x00, rel_y = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) u16 timeout, threshold;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) u32 scancode = KEY_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) * The imon directional pad functions more like a touchpad. Bytes 3 & 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) * contain a position coordinate (x,y), with each component ranging
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) * from -14 to 14. We want to down-sample this to only 4 discrete values
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) * for up/down/left/right arrow keys. Also, when you get too close to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) * diagonals, it has a tendency to jump back and forth, so lets try to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) * ignore when they get too close.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) if (ictx->product != 0xffdc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) /* first, pad to 8 bytes so it conforms with everything else */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) buf[5] = buf[6] = buf[7] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) timeout = 500; /* in msecs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) /* (2*threshold) x (2*threshold) square */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) threshold = pad_thresh ? pad_thresh : 28;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) rel_x = buf[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) rel_y = buf[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) if (ictx->rc_proto == RC_PROTO_BIT_IMON && pad_stabilize) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) dir = stabilize((int)rel_x, (int)rel_y,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) timeout, threshold);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) if (!dir) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) spin_lock_irqsave(&ictx->kc_lock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) ictx->kc = KEY_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) spin_unlock_irqrestore(&ictx->kc_lock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) buf[2] = dir & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) buf[3] = (dir >> 8) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) scancode = be32_to_cpu(*((__be32 *)buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) * Hack alert: instead of using keycodes, we have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) * to use hard-coded scancodes here...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) if (abs(rel_y) > abs(rel_x)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) buf[2] = (rel_y > 0) ? 0x7F : 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) buf[3] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) if (rel_y > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) scancode = 0x01007f00; /* KEY_DOWN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) scancode = 0x01008000; /* KEY_UP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) buf[2] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) buf[3] = (rel_x > 0) ? 0x7F : 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) if (rel_x > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) scancode = 0x0100007f; /* KEY_RIGHT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) scancode = 0x01000080; /* KEY_LEFT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) * Handle on-board decoded pad events for e.g. older VFD/iMON-Pad
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) * device (15c2:ffdc). The remote generates various codes from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) * 0x68nnnnB7 to 0x6AnnnnB7, the left mouse button generates
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) * 0x688301b7 and the right one 0x688481b7. All other keys generate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) * 0x2nnnnnnn. Position coordinate is encoded in buf[1] and buf[2] with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) * reversed endianness. Extract direction from buffer, rotate endianness,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) * adjust sign and feed the values into stabilize(). The resulting codes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) * will be 0x01008000, 0x01007F00, which match the newer devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) timeout = 10; /* in msecs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) /* (2*threshold) x (2*threshold) square */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) threshold = pad_thresh ? pad_thresh : 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) /* buf[1] is x */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) if (buf[0] & 0x02)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) rel_x |= ~0x10+1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) /* buf[2] is y */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) if (buf[0] & 0x01)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) rel_y |= ~0x10+1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) buf[0] = 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) if (ictx->rc_proto == RC_PROTO_BIT_IMON && pad_stabilize) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) dir = stabilize((int)rel_x, (int)rel_y,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) timeout, threshold);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) if (!dir) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) spin_lock_irqsave(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) ictx->kc = KEY_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) spin_unlock_irqrestore(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) buf[2] = dir & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) buf[3] = (dir >> 8) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) scancode = be32_to_cpu(*((__be32 *)buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) * Hack alert: instead of using keycodes, we have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) * to use hard-coded scancodes here...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) if (abs(rel_y) > abs(rel_x)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) buf[2] = (rel_y > 0) ? 0x7F : 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) buf[3] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) if (rel_y > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) scancode = 0x01007f00; /* KEY_DOWN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) scancode = 0x01008000; /* KEY_UP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) buf[2] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) buf[3] = (rel_x > 0) ? 0x7F : 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) if (rel_x > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) scancode = 0x0100007f; /* KEY_RIGHT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) scancode = 0x01000080; /* KEY_LEFT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) if (scancode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) spin_lock_irqsave(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) ictx->kc = imon_remote_key_lookup(ictx, scancode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) spin_unlock_irqrestore(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) * figure out if these is a press or a release. We don't actually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) * care about repeats, as those will be auto-generated within the IR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) * subsystem for repeating scancodes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) static int imon_parse_press_type(struct imon_context *ictx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) unsigned char *buf, u8 ktype)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) int press_type = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) spin_lock_irqsave(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) /* key release of 0x02XXXXXX key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) ictx->kc = ictx->last_keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) /* mouse button release on (some) 0xffdc devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) else if (ictx->kc == KEY_RESERVED && buf[0] == 0x68 && buf[1] == 0x82 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) buf[2] == 0x81 && buf[3] == 0xb7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) ictx->kc = ictx->last_keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) /* mouse button release on (some other) 0xffdc devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) else if (ictx->kc == KEY_RESERVED && buf[0] == 0x01 && buf[1] == 0x00 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) buf[2] == 0x81 && buf[3] == 0xb7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) ictx->kc = ictx->last_keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) /* mce-specific button handling, no keyup events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) else if (ktype == IMON_KEY_MCE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) ictx->rc_toggle = buf[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) press_type = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) /* incoherent or irrelevant data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) } else if (ictx->kc == KEY_RESERVED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) press_type = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) /* key release of 0xXXXXXXb7 key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) else if (ictx->release_code)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) press_type = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) /* this is a button press */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) press_type = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) spin_unlock_irqrestore(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) return press_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) * Process the incoming packet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) static void imon_incoming_packet(struct imon_context *ictx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) struct urb *urb, int intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) int len = urb->actual_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) unsigned char *buf = urb->transfer_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) struct device *dev = ictx->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) u32 kc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) u64 scancode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) int press_type = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) ktime_t t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) static ktime_t prev_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) u8 ktype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) /* filter out junk data on the older 0xffdc imon devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) /* Figure out what key was pressed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) if (len == 8 && buf[7] == 0xee) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) scancode = be64_to_cpu(*((__be64 *)buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) ktype = IMON_KEY_PANEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) kc = imon_panel_key_lookup(ictx, scancode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) ictx->release_code = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) scancode = be32_to_cpu(*((__be32 *)buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) ktype = IMON_KEY_IMON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) if (buf[0] == 0x80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) ktype = IMON_KEY_MCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) kc = imon_mce_key_lookup(ictx, scancode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) ktype = IMON_KEY_IMON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) kc = imon_remote_key_lookup(ictx, scancode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) spin_lock_irqsave(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) /* keyboard/mouse mode toggle button */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) if (kc == KEY_KEYBOARD && !ictx->release_code) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) ictx->last_keycode = kc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) if (!nomouse) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) ictx->pad_mouse = !ictx->pad_mouse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) dev_dbg(dev, "toggling to %s mode\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) ictx->pad_mouse ? "mouse" : "keyboard");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) spin_unlock_irqrestore(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) ictx->pad_mouse = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) dev_dbg(dev, "mouse mode disabled, passing key value\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) ictx->kc = kc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) spin_unlock_irqrestore(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) /* send touchscreen events through input subsystem if touchpad data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) if (ictx->touch && len == 8 && buf[7] == 0x86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) imon_touch_event(ictx, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) /* look for mouse events with pad in mouse mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) } else if (ictx->pad_mouse) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) if (imon_mouse_event(ictx, buf, len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) /* Now for some special handling to convert pad input to arrow keys */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) if (((len == 5) && (buf[0] == 0x01) && (buf[4] == 0x00)) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) ((len == 8) && (buf[0] & 0x40) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) len = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) imon_pad_to_keys(ictx, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) if (debug) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) printk(KERN_INFO "intf%d decoded packet: %*ph\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) intf, len, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) press_type = imon_parse_press_type(ictx, buf, ktype);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) if (press_type < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) goto not_input_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) if (ktype != IMON_KEY_PANEL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) if (press_type == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) rc_keyup(ictx->rdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) enum rc_proto proto;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) proto = RC_PROTO_RC6_MCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) else if (ictx->rc_proto == RC_PROTO_BIT_IMON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) proto = RC_PROTO_IMON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) rc_keydown(ictx->rdev, proto, ictx->rc_scancode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) ictx->rc_toggle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) spin_lock_irqsave(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) ictx->last_keycode = ictx->kc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) spin_unlock_irqrestore(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) /* Only panel type events left to process now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) spin_lock_irqsave(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) t = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) /* KEY repeats from knob and panel that need to be suppressed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) if (ictx->kc == KEY_MUTE ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) ictx->dev_descr->flags & IMON_SUPPRESS_REPEATED_KEYS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) if (ictx->kc == ictx->last_keycode &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) ktime_ms_delta(t, prev_time) < ictx->idev->rep[REP_DELAY]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) spin_unlock_irqrestore(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) prev_time = t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) kc = ictx->kc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) spin_unlock_irqrestore(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) input_report_key(ictx->idev, kc, press_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) input_sync(ictx->idev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) /* panel keys don't generate a release */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) input_report_key(ictx->idev, kc, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) input_sync(ictx->idev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) spin_lock_irqsave(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) ictx->last_keycode = kc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) spin_unlock_irqrestore(&ictx->kc_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) not_input_data:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) if (len != 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) dev_warn(dev, "imon %s: invalid incoming packet size (len = %d, intf%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) __func__, len, intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) /* iMON 2.4G associate frame */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) if (buf[0] == 0x00 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) buf[2] == 0xFF && /* REFID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) buf[3] == 0xFF &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) buf[4] == 0xFF &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) buf[5] == 0xFF && /* iMON 2.4G */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) ((buf[6] == 0x4E && buf[7] == 0xDF) || /* LT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) (buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) dev_warn(dev, "%s: remote associated refid=%02X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) __func__, buf[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) ictx->rf_isassociating = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) * Callback function for USB core API: receive data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) static void usb_rx_callback_intf0(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) struct imon_context *ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) int intfnum = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) if (!urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) ictx = (struct imon_context *)urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) if (!ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) * if we get a callback before we're done configuring the hardware, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) * can't yet process the data, as there's nowhere to send it, but we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) * still need to submit a new rx URB to avoid wedging the hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) if (!ictx->dev_present_intf0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) switch (urb->status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) case -ENOENT: /* usbcore unlink successful! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) case -ESHUTDOWN: /* transport endpoint was shut down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) imon_incoming_packet(ictx, urb, intfnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) dev_warn(ictx->dev, "imon %s: status(%d): ignored\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) __func__, urb->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) static void usb_rx_callback_intf1(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) struct imon_context *ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) int intfnum = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) if (!urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) ictx = (struct imon_context *)urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) if (!ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) * if we get a callback before we're done configuring the hardware, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) * can't yet process the data, as there's nowhere to send it, but we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) * still need to submit a new rx URB to avoid wedging the hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) if (!ictx->dev_present_intf1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) switch (urb->status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) case -ENOENT: /* usbcore unlink successful! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) case -ESHUTDOWN: /* transport endpoint was shut down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) imon_incoming_packet(ictx, urb, intfnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) dev_warn(ictx->dev, "imon %s: status(%d): ignored\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) __func__, urb->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) * The 0x15c2:0xffdc device ID was used for umpteen different imon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) * devices, and all of them constantly spew interrupts, even when there
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) * is no actual data to report. However, byte 6 of this buffer looks like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) * its unique across device variants, so we're trying to key off that to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) * figure out which display type (if any) and what IR protocol the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) * actually supports. These devices have their IR protocol hard-coded into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) * their firmware, they can't be changed on the fly like the newer hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) static void imon_get_ffdc_type(struct imon_context *ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) u64 allowed_protos = RC_PROTO_BIT_IMON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) switch (ffdc_cfg_byte) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) /* iMON Knob, no display, iMON IR + vol knob */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) case 0x21:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) ictx->display_supported = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) /* iMON 2.4G LT (usb stick), no display, iMON RF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840) case 0x4e:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) ictx->display_supported = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) ictx->rf_device = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) /* iMON VFD, no IR (does have vol knob tho) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846) case 0x35:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848) detected_display_type = IMON_DISPLAY_TYPE_VFD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) /* iMON VFD, iMON IR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) case 0x24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) case 0x30:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) case 0x85:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) detected_display_type = IMON_DISPLAY_TYPE_VFD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) /* iMON VFD, MCE IR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) case 0x46:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) case 0x9e:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) detected_display_type = IMON_DISPLAY_TYPE_VFD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) allowed_protos = RC_PROTO_BIT_RC6_MCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) /* iMON VFD, iMON or MCE IR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) case 0x7e:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) dev_info(ictx->dev, "0xffdc iMON VFD, iMON or MCE IR");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) detected_display_type = IMON_DISPLAY_TYPE_VFD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) allowed_protos |= RC_PROTO_BIT_RC6_MCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870) /* iMON LCD, MCE IR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) case 0x9f:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) detected_display_type = IMON_DISPLAY_TYPE_LCD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874) allowed_protos = RC_PROTO_BIT_RC6_MCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) /* no display, iMON IR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) case 0x26:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) dev_info(ictx->dev, "0xffdc iMON Inside, iMON IR");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) ictx->display_supported = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) /* Soundgraph iMON UltraBay */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) case 0x98:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) dev_info(ictx->dev, "0xffdc iMON UltraBay, LCD + IR");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) detected_display_type = IMON_DISPLAY_TYPE_LCD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885) allowed_protos = RC_PROTO_BIT_IMON | RC_PROTO_BIT_RC6_MCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) ictx->dev_descr = &ultrabay_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) dev_info(ictx->dev, "Unknown 0xffdc device, defaulting to VFD and iMON IR");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) detected_display_type = IMON_DISPLAY_TYPE_VFD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) * We don't know which one it is, allow user to set the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) * RC6 one from userspace if IMON wasn't correct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) allowed_protos |= RC_PROTO_BIT_RC6_MCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) ictx->display_type = detected_display_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) ictx->rc_proto = allowed_protos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) static void imon_set_display_type(struct imon_context *ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) u8 configured_display_type = IMON_DISPLAY_TYPE_VFD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911) * Try to auto-detect the type of display if the user hasn't set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) * it by hand via the display_type modparam. Default is VFD.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) if (display_type == IMON_DISPLAY_TYPE_AUTO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) switch (ictx->product) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917) case 0xffdc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918) /* set in imon_get_ffdc_type() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919) configured_display_type = ictx->display_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) case 0x0034:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) case 0x0035:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) configured_display_type = IMON_DISPLAY_TYPE_VGA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925) case 0x0038:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) case 0x0039:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) case 0x0045:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) configured_display_type = IMON_DISPLAY_TYPE_LCD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) case 0x003c:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) case 0x0041:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932) case 0x0042:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) case 0x0043:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934) configured_display_type = IMON_DISPLAY_TYPE_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) ictx->display_supported = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) case 0x0036:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938) case 0x0044:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) configured_display_type = IMON_DISPLAY_TYPE_VFD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) configured_display_type = display_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) if (display_type == IMON_DISPLAY_TYPE_NONE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946) ictx->display_supported = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) ictx->display_supported = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949) dev_info(ictx->dev, "%s: overriding display type to %d via modparam\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950) __func__, display_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953) ictx->display_type = configured_display_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956) static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) struct rc_dev *rdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) static const unsigned char fp_packet[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961) 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963) rdev = rc_allocate_device(RC_DRIVER_SCANCODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) if (!rdev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965) dev_err(ictx->dev, "remote control dev allocation failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) snprintf(ictx->name_rdev, sizeof(ictx->name_rdev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) usb_make_path(ictx->usbdev_intf0, ictx->phys_rdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) sizeof(ictx->phys_rdev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973) strlcat(ictx->phys_rdev, "/input0", sizeof(ictx->phys_rdev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) rdev->device_name = ictx->name_rdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976) rdev->input_phys = ictx->phys_rdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977) usb_to_input_id(ictx->usbdev_intf0, &rdev->input_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) rdev->dev.parent = ictx->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980) rdev->priv = ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) /* iMON PAD or MCE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982) rdev->allowed_protocols = RC_PROTO_BIT_IMON | RC_PROTO_BIT_RC6_MCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983) rdev->change_protocol = imon_ir_change_protocol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) rdev->driver_name = MOD_NAME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986) /* Enable front-panel buttons and/or knobs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987) memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988) ret = send_packet(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989) /* Not fatal, but warn about it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991) dev_info(ictx->dev, "panel buttons/knobs setup failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) if (ictx->product == 0xffdc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) imon_get_ffdc_type(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995) rdev->allowed_protocols = ictx->rc_proto;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) imon_set_display_type(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000) if (ictx->rc_proto == RC_PROTO_BIT_RC6_MCE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001) rdev->map_name = RC_MAP_IMON_MCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003) rdev->map_name = RC_MAP_IMON_PAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) ret = rc_register_device(rdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) dev_err(ictx->dev, "remote input dev register failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) return rdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2013) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2014) rc_free_device(rdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2015) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2016) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2017)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2018) static struct input_dev *imon_init_idev(struct imon_context *ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2019) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2020) const struct imon_panel_key_table *key_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2021) struct input_dev *idev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2022) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2024) key_table = ictx->dev_descr->key_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2026) idev = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2027) if (!idev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2028) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2030) snprintf(ictx->name_idev, sizeof(ictx->name_idev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2031) "iMON Panel, Knob and Mouse(%04x:%04x)",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2032) ictx->vendor, ictx->product);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2033) idev->name = ictx->name_idev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2035) usb_make_path(ictx->usbdev_intf0, ictx->phys_idev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2036) sizeof(ictx->phys_idev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2037) strlcat(ictx->phys_idev, "/input1", sizeof(ictx->phys_idev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2038) idev->phys = ictx->phys_idev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2040) idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2042) idev->keybit[BIT_WORD(BTN_MOUSE)] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2043) BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2044) idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2045) BIT_MASK(REL_WHEEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2047) /* panel and/or knob code support */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2048) for (i = 0; key_table[i].hw_code != 0; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2049) u32 kc = key_table[i].keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2050) __set_bit(kc, idev->keybit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2051) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2053) usb_to_input_id(ictx->usbdev_intf0, &idev->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2054) idev->dev.parent = ictx->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2055) input_set_drvdata(idev, ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2057) ret = input_register_device(idev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2058) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2059) dev_err(ictx->dev, "input dev register failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2060) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2061) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2062)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2063) return idev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2065) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2066) input_free_device(idev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2067) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2068) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2069)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2070) static struct input_dev *imon_init_touch(struct imon_context *ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2071) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2072) struct input_dev *touch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2073) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2075) touch = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2076) if (!touch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2077) goto touch_alloc_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2079) snprintf(ictx->name_touch, sizeof(ictx->name_touch),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2080) "iMON USB Touchscreen (%04x:%04x)",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2081) ictx->vendor, ictx->product);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2082) touch->name = ictx->name_touch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2083)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2084) usb_make_path(ictx->usbdev_intf1, ictx->phys_touch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2085) sizeof(ictx->phys_touch));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2086) strlcat(ictx->phys_touch, "/input2", sizeof(ictx->phys_touch));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2087) touch->phys = ictx->phys_touch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2089) touch->evbit[0] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2090) BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2091) touch->keybit[BIT_WORD(BTN_TOUCH)] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2092) BIT_MASK(BTN_TOUCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2093) input_set_abs_params(touch, ABS_X,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2094) 0x00, 0xfff, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2095) input_set_abs_params(touch, ABS_Y,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2096) 0x00, 0xfff, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2098) input_set_drvdata(touch, ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2099)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2100) usb_to_input_id(ictx->usbdev_intf1, &touch->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2101) touch->dev.parent = ictx->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2102) ret = input_register_device(touch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2103) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2104) dev_info(ictx->dev, "touchscreen input dev register failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2105) goto touch_register_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2108) return touch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2110) touch_register_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2111) input_free_device(touch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2113) touch_alloc_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2114) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2117) static bool imon_find_endpoints(struct imon_context *ictx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2118) struct usb_host_interface *iface_desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2120) struct usb_endpoint_descriptor *ep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2121) struct usb_endpoint_descriptor *rx_endpoint = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2122) struct usb_endpoint_descriptor *tx_endpoint = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2123) int ifnum = iface_desc->desc.bInterfaceNumber;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2124) int num_endpts = iface_desc->desc.bNumEndpoints;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2125) int i, ep_dir, ep_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2126) bool ir_ep_found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2127) bool display_ep_found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2128) bool tx_control = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2130) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2131) * Scan the endpoint list and set:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2132) * first input endpoint = IR endpoint
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2133) * first output endpoint = display endpoint
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2134) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2135) for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2136) ep = &iface_desc->endpoint[i].desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2137) ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2138) ep_type = usb_endpoint_type(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2140) if (!ir_ep_found && ep_dir == USB_DIR_IN &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2141) ep_type == USB_ENDPOINT_XFER_INT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2143) rx_endpoint = ep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2144) ir_ep_found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2145) dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2147) } else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2148) ep_type == USB_ENDPOINT_XFER_INT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2149) tx_endpoint = ep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2150) display_ep_found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2151) dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2155) if (ifnum == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2156) ictx->rx_endpoint_intf0 = rx_endpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2157) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2158) * tx is used to send characters to lcd/vfd, associate RF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2159) * remotes, set IR protocol, and maybe more...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2160) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2161) ictx->tx_endpoint = tx_endpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2162) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2163) ictx->rx_endpoint_intf1 = rx_endpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2166) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2167) * If we didn't find a display endpoint, this is probably one of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2168) * newer iMON devices that use control urb instead of interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2169) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2170) if (!display_ep_found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2171) tx_control = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2172) display_ep_found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2173) dev_dbg(ictx->dev, "%s: device uses control endpoint, not interface OUT endpoint\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2174) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2177) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2178) * Some iMON receivers have no display. Unfortunately, it seems
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2179) * that SoundGraph recycles device IDs between devices both with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2180) * and without... :\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2181) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2182) if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2183) display_ep_found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2184) dev_dbg(ictx->dev, "%s: device has no display\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2187) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2188) * iMON Touch devices have a VGA touchscreen, but no "display", as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2189) * that refers to e.g. /dev/lcd0 (a character device LCD or VFD).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2190) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2191) if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2192) display_ep_found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2193) dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2196) /* Input endpoint is mandatory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2197) if (!ir_ep_found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2198) pr_err("no valid input (IR) endpoint found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2200) ictx->tx_control = tx_control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2202) if (display_ep_found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2203) ictx->display_supported = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2205) return ir_ep_found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2209) static struct imon_context *imon_init_intf0(struct usb_interface *intf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2210) const struct usb_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2211) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2212) struct imon_context *ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2213) struct urb *rx_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2214) struct urb *tx_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2215) struct device *dev = &intf->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2216) struct usb_host_interface *iface_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2217) int ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2219) ictx = kzalloc(sizeof(*ictx), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2220) if (!ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2221) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2223) rx_urb = usb_alloc_urb(0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2224) if (!rx_urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2225) goto rx_urb_alloc_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2226) tx_urb = usb_alloc_urb(0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2227) if (!tx_urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2228) goto tx_urb_alloc_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2230) mutex_init(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2231) spin_lock_init(&ictx->kc_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2233) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2235) ictx->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2236) ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2237) ictx->rx_urb_intf0 = rx_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2238) ictx->tx_urb = tx_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2239) ictx->rf_device = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2241) init_completion(&ictx->tx.finished);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2243) ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2244) ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2246) /* save drive info for later accessing the panel/knob key table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2247) ictx->dev_descr = (struct imon_usb_dev_descr *)id->driver_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2248) /* default send_packet delay is 5ms but some devices need more */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2249) ictx->send_packet_delay = ictx->dev_descr->flags &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2250) IMON_NEED_20MS_PKT_DELAY ? 20 : 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2252) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2253) iface_desc = intf->cur_altsetting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2254) if (!imon_find_endpoints(ictx, iface_desc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2255) goto find_endpoint_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2258) usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2259) usb_rcvintpipe(ictx->usbdev_intf0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2260) ictx->rx_endpoint_intf0->bEndpointAddress),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2261) ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2262) usb_rx_callback_intf0, ictx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2263) ictx->rx_endpoint_intf0->bInterval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2265) ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2266) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2267) pr_err("usb_submit_urb failed for intf0 (%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2268) goto urb_submit_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2271) ictx->idev = imon_init_idev(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2272) if (!ictx->idev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2273) dev_err(dev, "%s: input device setup failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2274) goto idev_setup_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2277) ictx->rdev = imon_init_rdev(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2278) if (!ictx->rdev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2279) dev_err(dev, "%s: rc device setup failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2280) goto rdev_setup_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2283) ictx->dev_present_intf0 = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2285) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2286) return ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2288) rdev_setup_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2289) input_unregister_device(ictx->idev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2290) idev_setup_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2291) usb_kill_urb(ictx->rx_urb_intf0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2292) urb_submit_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2293) find_endpoint_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2294) usb_put_dev(ictx->usbdev_intf0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2295) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2296) usb_free_urb(tx_urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2297) tx_urb_alloc_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2298) usb_free_urb(rx_urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2299) rx_urb_alloc_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2300) kfree(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2301) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2302) dev_err(dev, "unable to initialize intf0, err %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2304) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2307) static struct imon_context *imon_init_intf1(struct usb_interface *intf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2308) struct imon_context *ictx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2310) struct urb *rx_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2311) struct usb_host_interface *iface_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2312) int ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2314) rx_urb = usb_alloc_urb(0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2315) if (!rx_urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2316) goto rx_urb_alloc_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2318) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2320) if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2321) timer_setup(&ictx->ttimer, imon_touch_display_timeout, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2324) ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2325) ictx->rx_urb_intf1 = rx_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2327) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2328) iface_desc = intf->cur_altsetting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2329) if (!imon_find_endpoints(ictx, iface_desc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2330) goto find_endpoint_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2332) if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2333) ictx->touch = imon_init_touch(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2334) if (!ictx->touch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2335) goto touch_setup_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2336) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2337) ictx->touch = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2339) usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2340) usb_rcvintpipe(ictx->usbdev_intf1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2341) ictx->rx_endpoint_intf1->bEndpointAddress),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2342) ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2343) usb_rx_callback_intf1, ictx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2344) ictx->rx_endpoint_intf1->bInterval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2346) ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2348) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2349) pr_err("usb_submit_urb failed for intf1 (%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2350) goto urb_submit_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2353) ictx->dev_present_intf1 = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2355) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2356) return ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2358) urb_submit_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2359) if (ictx->touch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2360) input_unregister_device(ictx->touch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2361) touch_setup_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2362) find_endpoint_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2363) usb_put_dev(ictx->usbdev_intf1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2364) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2365) usb_free_urb(rx_urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2366) rx_urb_alloc_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2367) dev_err(ictx->dev, "unable to initialize intf1, err %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2369) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2372) static void imon_init_display(struct imon_context *ictx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2373) struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2374) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2375) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2377) dev_dbg(ictx->dev, "Registering iMON display with sysfs\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2379) /* set up sysfs entry for built-in clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2380) ret = sysfs_create_group(&intf->dev.kobj, &imon_display_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2381) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2382) dev_err(ictx->dev, "Could not create display sysfs entries(%d)",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2383) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2385) if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2386) ret = usb_register_dev(intf, &imon_lcd_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2387) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2388) ret = usb_register_dev(intf, &imon_vfd_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2389) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2390) /* Not a fatal error, so ignore */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2391) dev_info(ictx->dev, "could not get a minor number for display\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2395) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2396) * Callback function for USB core API: Probe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2397) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2398) static int imon_probe(struct usb_interface *interface,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2399) const struct usb_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2400) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2401) struct usb_device *usbdev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2402) struct usb_host_interface *iface_desc = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2403) struct usb_interface *first_if;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2404) struct device *dev = &interface->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2405) int ifnum, sysfs_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2406) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2407) struct imon_context *ictx = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2408) struct imon_context *first_if_ctx = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2409) u16 vendor, product;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2411) usbdev = usb_get_dev(interface_to_usbdev(interface));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2412) iface_desc = interface->cur_altsetting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2413) ifnum = iface_desc->desc.bInterfaceNumber;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2414) vendor = le16_to_cpu(usbdev->descriptor.idVendor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2415) product = le16_to_cpu(usbdev->descriptor.idProduct);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2417) dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2418) __func__, vendor, product, ifnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2420) /* prevent races probing devices w/multiple interfaces */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2421) mutex_lock(&driver_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2423) first_if = usb_ifnum_to_if(usbdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2424) if (!first_if) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2425) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2426) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2429) first_if_ctx = usb_get_intfdata(first_if);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2431) if (ifnum == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2432) ictx = imon_init_intf0(interface, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2433) if (!ictx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2434) pr_err("failed to initialize context!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2435) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2436) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2439) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2440) /* this is the secondary interface on the device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2442) /* fail early if first intf failed to register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2443) if (!first_if_ctx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2444) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2445) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2448) ictx = imon_init_intf1(interface, first_if_ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2449) if (!ictx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2450) pr_err("failed to attach to context!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2451) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2452) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2457) usb_set_intfdata(interface, ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2459) if (ifnum == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2460) mutex_lock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2462) if (product == 0xffdc && ictx->rf_device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2463) sysfs_err = sysfs_create_group(&interface->dev.kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2464) &imon_rf_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2465) if (sysfs_err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2466) pr_err("Could not create RF sysfs entries(%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2467) sysfs_err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2470) if (ictx->display_supported)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2471) imon_init_display(ictx, interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2473) mutex_unlock(&ictx->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2476) dev_info(dev, "iMON device (%04x:%04x, intf%d) on usb<%d:%d> initialized\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2477) vendor, product, ifnum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2478) usbdev->bus->busnum, usbdev->devnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2480) mutex_unlock(&driver_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2481) usb_put_dev(usbdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2483) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2485) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2486) mutex_unlock(&driver_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2487) usb_put_dev(usbdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2488) dev_err(dev, "unable to register, err %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2490) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2493) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2494) * Callback function for USB core API: disconnect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2495) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2496) static void imon_disconnect(struct usb_interface *interface)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2497) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2498) struct imon_context *ictx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2499) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2500) int ifnum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2502) /* prevent races with multi-interface device probing and display_open */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2503) mutex_lock(&driver_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2505) ictx = usb_get_intfdata(interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2506) dev = ictx->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2507) ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2509) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2510) * sysfs_remove_group is safe to call even if sysfs_create_group
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2511) * hasn't been called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2512) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2513) sysfs_remove_group(&interface->dev.kobj, &imon_display_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2514) sysfs_remove_group(&interface->dev.kobj, &imon_rf_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2516) usb_set_intfdata(interface, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2518) /* Abort ongoing write */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2519) if (ictx->tx.busy) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2520) usb_kill_urb(ictx->tx_urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2521) complete(&ictx->tx.finished);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2524) if (ifnum == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2525) ictx->dev_present_intf0 = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2526) usb_kill_urb(ictx->rx_urb_intf0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2527) usb_put_dev(ictx->usbdev_intf0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2528) input_unregister_device(ictx->idev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2529) rc_unregister_device(ictx->rdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2530) if (ictx->display_supported) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2531) if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2532) usb_deregister_dev(interface, &imon_lcd_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2533) else if (ictx->display_type == IMON_DISPLAY_TYPE_VFD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2534) usb_deregister_dev(interface, &imon_vfd_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2535) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2536) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2537) ictx->dev_present_intf1 = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2538) usb_kill_urb(ictx->rx_urb_intf1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2539) usb_put_dev(ictx->usbdev_intf1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2540) if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2541) input_unregister_device(ictx->touch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2542) del_timer_sync(&ictx->ttimer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2544) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2546) if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2547) free_imon_context(ictx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2549) mutex_unlock(&driver_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2551) dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2552) __func__, ifnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2555) static int imon_suspend(struct usb_interface *intf, pm_message_t message)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2556) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2557) struct imon_context *ictx = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2558) int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2560) if (ifnum == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2561) usb_kill_urb(ictx->rx_urb_intf0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2562) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2563) usb_kill_urb(ictx->rx_urb_intf1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2565) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2568) static int imon_resume(struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2569) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2570) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2571) struct imon_context *ictx = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2572) int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2574) if (ifnum == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2575) usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2576) usb_rcvintpipe(ictx->usbdev_intf0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2577) ictx->rx_endpoint_intf0->bEndpointAddress),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2578) ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2579) usb_rx_callback_intf0, ictx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2580) ictx->rx_endpoint_intf0->bInterval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2582) rc = usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2584) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2585) usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2586) usb_rcvintpipe(ictx->usbdev_intf1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2587) ictx->rx_endpoint_intf1->bEndpointAddress),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2588) ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2589) usb_rx_callback_intf1, ictx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2590) ictx->rx_endpoint_intf1->bInterval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2592) rc = usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2595) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2596) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2598) module_usb_driver(imon_driver);