diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
| commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
| tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/staging/lirc | |
| parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) | |
Diffstat (limited to 'drivers/staging/lirc')
| -rw-r--r-- | drivers/staging/lirc/Kconfig | 78 | ||||
| -rw-r--r-- | drivers/staging/lirc/Makefile | 14 | ||||
| -rw-r--r-- | drivers/staging/lirc/TODO | 8 | ||||
| -rw-r--r-- | drivers/staging/lirc/TODO.lirc_zilog | 36 | ||||
| -rw-r--r-- | drivers/staging/lirc/lirc_bt829.c | 383 | ||||
| -rw-r--r-- | drivers/staging/lirc/lirc_ene0100.h | 169 | ||||
| -rw-r--r-- | drivers/staging/lirc/lirc_igorplugusb.c | 577 | ||||
| -rw-r--r-- | drivers/staging/lirc/lirc_imon.c | 1050 | ||||
| -rw-r--r-- | drivers/staging/lirc/lirc_parallel.c | 755 | ||||
| -rw-r--r-- | drivers/staging/lirc/lirc_parallel.h | 26 | ||||
| -rw-r--r-- | drivers/staging/lirc/lirc_sasem.c | 939 | ||||
| -rw-r--r-- | drivers/staging/lirc/lirc_serial.c | 1315 | ||||
| -rw-r--r-- | drivers/staging/lirc/lirc_sir.c | 1279 | ||||
| -rw-r--r-- | drivers/staging/lirc/lirc_ttusbir.c | 395 | ||||
| -rw-r--r-- | drivers/staging/lirc/lirc_zilog.c | 1676 |
15 files changed, 8700 insertions, 0 deletions
diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig new file mode 100644 index 00000000000..526ec0fc2f0 --- /dev/null +++ b/drivers/staging/lirc/Kconfig | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | # | ||
| 2 | # LIRC driver(s) configuration | ||
| 3 | # | ||
| 4 | menuconfig LIRC_STAGING | ||
| 5 | bool "Linux Infrared Remote Control IR receiver/transmitter drivers" | ||
| 6 | depends on LIRC | ||
| 7 | help | ||
| 8 | Say Y here, and all supported Linux Infrared Remote Control IR and | ||
| 9 | RF receiver and transmitter drivers will be displayed. When paired | ||
| 10 | with a remote control and the lirc daemon, the receiver drivers | ||
| 11 | allow control of your Linux system via remote control. | ||
| 12 | |||
| 13 | if LIRC_STAGING | ||
| 14 | |||
| 15 | config LIRC_BT829 | ||
| 16 | tristate "BT829 based hardware" | ||
| 17 | depends on LIRC && PCI | ||
| 18 | help | ||
| 19 | Driver for the IR interface on BT829-based hardware | ||
| 20 | |||
| 21 | config LIRC_IGORPLUGUSB | ||
| 22 | tristate "Igor Cesko's USB IR Receiver" | ||
| 23 | depends on LIRC && USB | ||
| 24 | help | ||
| 25 | Driver for Igor Cesko's USB IR Receiver | ||
| 26 | |||
| 27 | config LIRC_IMON | ||
| 28 | tristate "Legacy SoundGraph iMON Receiver and Display" | ||
| 29 | depends on LIRC && USB | ||
| 30 | help | ||
| 31 | Driver for the original SoundGraph iMON IR Receiver and Display | ||
| 32 | |||
| 33 | Current generation iMON devices use the input layer imon driver. | ||
| 34 | |||
| 35 | config LIRC_PARALLEL | ||
| 36 | tristate "Homebrew Parallel Port Receiver" | ||
| 37 | depends on LIRC && PARPORT | ||
| 38 | help | ||
| 39 | Driver for Homebrew Parallel Port Receivers | ||
| 40 | |||
| 41 | config LIRC_SASEM | ||
| 42 | tristate "Sasem USB IR Remote" | ||
| 43 | depends on LIRC && USB | ||
| 44 | help | ||
| 45 | Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module | ||
| 46 | |||
| 47 | config LIRC_SERIAL | ||
| 48 | tristate "Homebrew Serial Port Receiver" | ||
| 49 | depends on LIRC | ||
| 50 | help | ||
| 51 | Driver for Homebrew Serial Port Receivers | ||
| 52 | |||
| 53 | config LIRC_SERIAL_TRANSMITTER | ||
| 54 | bool "Serial Port Transmitter" | ||
| 55 | default y | ||
| 56 | depends on LIRC_SERIAL | ||
| 57 | help | ||
| 58 | Serial Port Transmitter support | ||
| 59 | |||
| 60 | config LIRC_SIR | ||
| 61 | tristate "Built-in SIR IrDA port" | ||
| 62 | depends on LIRC | ||
| 63 | help | ||
| 64 | Driver for the SIR IrDA port | ||
| 65 | |||
| 66 | config LIRC_TTUSBIR | ||
| 67 | tristate "Technotrend USB IR Receiver" | ||
| 68 | depends on LIRC && USB | ||
| 69 | help | ||
| 70 | Driver for the Technotrend USB IR Receiver | ||
| 71 | |||
| 72 | config LIRC_ZILOG | ||
| 73 | tristate "Zilog/Hauppauge IR Transmitter" | ||
| 74 | depends on LIRC && I2C | ||
| 75 | help | ||
| 76 | Driver for the Zilog/Hauppauge IR Transmitter, found on | ||
| 77 | PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards | ||
| 78 | endif | ||
diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/lirc/Makefile new file mode 100644 index 00000000000..d76b0fa2af5 --- /dev/null +++ b/drivers/staging/lirc/Makefile | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | # Makefile for the lirc drivers. | ||
| 2 | # | ||
| 3 | |||
| 4 | # Each configuration option enables a list of files. | ||
| 5 | |||
| 6 | obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o | ||
| 7 | obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o | ||
| 8 | obj-$(CONFIG_LIRC_IMON) += lirc_imon.o | ||
| 9 | obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o | ||
| 10 | obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o | ||
| 11 | obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o | ||
| 12 | obj-$(CONFIG_LIRC_SIR) += lirc_sir.o | ||
| 13 | obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o | ||
| 14 | obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o | ||
diff --git a/drivers/staging/lirc/TODO b/drivers/staging/lirc/TODO new file mode 100644 index 00000000000..b6cb593f55c --- /dev/null +++ b/drivers/staging/lirc/TODO | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | - All drivers should either be ported to ir-core, or dropped entirely | ||
| 2 | (see drivers/media/IR/mceusb.c vs. lirc_mceusb.c in lirc cvs for an | ||
| 3 | example of a previously completed port). | ||
| 4 | |||
| 5 | Please send patches to: | ||
| 6 | Jarod Wilson <jarod@wilsonet.com> | ||
| 7 | Greg Kroah-Hartman <greg@kroah.com> | ||
| 8 | |||
diff --git a/drivers/staging/lirc/TODO.lirc_zilog b/drivers/staging/lirc/TODO.lirc_zilog new file mode 100644 index 00000000000..a97800a8e12 --- /dev/null +++ b/drivers/staging/lirc/TODO.lirc_zilog | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | 1. Both ir-kbd-i2c and lirc_zilog provide support for RX events for | ||
| 2 | the chips supported by lirc_zilog. Before moving lirc_zilog out of staging: | ||
| 3 | |||
| 4 | a. ir-kbd-i2c needs a module parameter added to allow the user to tell | ||
| 5 | ir-kbd-i2c to ignore Z8 IR units. | ||
| 6 | |||
| 7 | b. lirc_zilog should provide Rx key presses to the rc core like ir-kbd-i2c | ||
| 8 | does. | ||
| 9 | |||
| 10 | |||
| 11 | 2. lirc_zilog module ref-counting need examination. It has not been | ||
| 12 | verified that cdev and lirc_dev will take the proper module references on | ||
| 13 | lirc_zilog to prevent removal of lirc_zilog when the /dev/lircN device node | ||
| 14 | is open. | ||
| 15 | |||
| 16 | (The good news is ref-counting of lirc_zilog internal structures appears to be | ||
| 17 | complete. Testing has shown the cx18 module can be unloaded out from under | ||
| 18 | irw + lircd + lirc_dev, with the /dev/lirc0 device node open, with no adverse | ||
| 19 | effects. The cx18 module could then be reloaded and irw properly began | ||
| 20 | receiving button presses again and ir_send worked without error.) | ||
| 21 | |||
| 22 | |||
| 23 | 3. Bridge drivers, if able, should provide a chip reset() callback | ||
| 24 | to lirc_zilog via struct IR_i2c_init_data. cx18 and ivtv already have routines | ||
| 25 | to perform Z8 chip resets via GPIO manipulations. This would allow lirc_zilog | ||
| 26 | to bring the chip back to normal when it hangs, in the same places the | ||
| 27 | original lirc_pvr150 driver code does. This is not strictly needed, so it | ||
| 28 | is not required to move lirc_zilog out of staging. | ||
| 29 | |||
| 30 | Note: Both lirc_zilog and ir-kbd-i2c support the Zilog Z8 for IR, as programmed | ||
| 31 | and installed on Hauppauge products. When working on either module, developers | ||
| 32 | must consider at least the following bridge drivers which mention an IR Rx unit | ||
| 33 | at address 0x71 (indicative of a Z8): | ||
| 34 | |||
| 35 | ivtv cx18 hdpvr pvrusb2 bt8xx cx88 saa7134 | ||
| 36 | |||
diff --git a/drivers/staging/lirc/lirc_bt829.c b/drivers/staging/lirc/lirc_bt829.c new file mode 100644 index 00000000000..c5a0d27a02d --- /dev/null +++ b/drivers/staging/lirc/lirc_bt829.c | |||
| @@ -0,0 +1,383 @@ | |||
| 1 | /* | ||
| 2 | * Remote control driver for the TV-card based on bt829 | ||
| 3 | * | ||
| 4 | * by Leonid Froenchenko <lfroen@galileo.co.il> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/threads.h> | ||
| 24 | #include <linux/sched.h> | ||
| 25 | #include <linux/ioport.h> | ||
| 26 | #include <linux/pci.h> | ||
| 27 | #include <linux/delay.h> | ||
| 28 | |||
| 29 | #include <media/lirc_dev.h> | ||
| 30 | |||
| 31 | static int poll_main(void); | ||
| 32 | static int atir_init_start(void); | ||
| 33 | |||
| 34 | static void write_index(unsigned char index, unsigned int value); | ||
| 35 | static unsigned int read_index(unsigned char index); | ||
| 36 | |||
| 37 | static void do_i2c_start(void); | ||
| 38 | static void do_i2c_stop(void); | ||
| 39 | |||
| 40 | static void seems_wr_byte(unsigned char al); | ||
| 41 | static unsigned char seems_rd_byte(void); | ||
| 42 | |||
| 43 | static unsigned int read_index(unsigned char al); | ||
| 44 | static void write_index(unsigned char ah, unsigned int edx); | ||
| 45 | |||
| 46 | static void cycle_delay(int cycle); | ||
| 47 | |||
| 48 | static void do_set_bits(unsigned char bl); | ||
| 49 | static unsigned char do_get_bits(void); | ||
| 50 | |||
| 51 | #define DATA_PCI_OFF 0x7FFC00 | ||
| 52 | #define WAIT_CYCLE 20 | ||
| 53 | |||
| 54 | #define DRIVER_NAME "lirc_bt829" | ||
| 55 | |||
| 56 | static int debug; | ||
| 57 | #define dprintk(fmt, args...) \ | ||
| 58 | do { \ | ||
| 59 | if (debug) \ | ||
| 60 | printk(KERN_DEBUG DRIVER_NAME ": "fmt, ## args); \ | ||
| 61 | } while (0) | ||
| 62 | |||
| 63 | static int atir_minor; | ||
| 64 | static unsigned long pci_addr_phys; | ||
| 65 | static unsigned char *pci_addr_lin; | ||
| 66 | |||
| 67 | static struct lirc_driver atir_driver; | ||
| 68 | |||
| 69 | static struct pci_dev *do_pci_probe(void) | ||
| 70 | { | ||
| 71 | struct pci_dev *my_dev; | ||
| 72 | my_dev = pci_get_device(PCI_VENDOR_ID_ATI, | ||
| 73 | PCI_DEVICE_ID_ATI_264VT, NULL); | ||
| 74 | if (my_dev) { | ||
| 75 | printk(KERN_ERR DRIVER_NAME ": Using device: %s\n", | ||
| 76 | pci_name(my_dev)); | ||
| 77 | pci_addr_phys = 0; | ||
| 78 | if (my_dev->resource[0].flags & IORESOURCE_MEM) { | ||
| 79 | pci_addr_phys = my_dev->resource[0].start; | ||
| 80 | printk(KERN_INFO DRIVER_NAME ": memory at 0x%08X\n", | ||
| 81 | (unsigned int)pci_addr_phys); | ||
| 82 | } | ||
| 83 | if (pci_addr_phys == 0) { | ||
| 84 | printk(KERN_ERR DRIVER_NAME ": no memory resource ?\n"); | ||
| 85 | return NULL; | ||
| 86 | } | ||
| 87 | } else { | ||
| 88 | printk(KERN_ERR DRIVER_NAME ": pci_probe failed\n"); | ||
| 89 | return NULL; | ||
| 90 | } | ||
| 91 | return my_dev; | ||
| 92 | } | ||
| 93 | |||
| 94 | static int atir_add_to_buf(void *data, struct lirc_buffer *buf) | ||
| 95 | { | ||
| 96 | unsigned char key; | ||
| 97 | int status; | ||
| 98 | status = poll_main(); | ||
| 99 | key = (status >> 8) & 0xFF; | ||
| 100 | if (status & 0xFF) { | ||
| 101 | dprintk("reading key %02X\n", key); | ||
| 102 | lirc_buffer_write(buf, &key); | ||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | return -ENODATA; | ||
| 106 | } | ||
| 107 | |||
| 108 | static int atir_set_use_inc(void *data) | ||
| 109 | { | ||
| 110 | dprintk("driver is opened\n"); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | static void atir_set_use_dec(void *data) | ||
| 115 | { | ||
| 116 | dprintk("driver is closed\n"); | ||
| 117 | } | ||
| 118 | |||
| 119 | int init_module(void) | ||
| 120 | { | ||
| 121 | struct pci_dev *pdev; | ||
| 122 | |||
| 123 | pdev = do_pci_probe(); | ||
| 124 | if (pdev == NULL) | ||
| 125 | return -ENODEV; | ||
| 126 | |||
| 127 | if (!atir_init_start()) | ||
| 128 | return -ENODEV; | ||
| 129 | |||
| 130 | strcpy(atir_driver.name, "ATIR"); | ||
| 131 | atir_driver.minor = -1; | ||
| 132 | atir_driver.code_length = 8; | ||
| 133 | atir_driver.sample_rate = 10; | ||
| 134 | atir_driver.data = 0; | ||
| 135 | atir_driver.add_to_buf = atir_add_to_buf; | ||
| 136 | atir_driver.set_use_inc = atir_set_use_inc; | ||
| 137 | atir_driver.set_use_dec = atir_set_use_dec; | ||
| 138 | atir_driver.dev = &pdev->dev; | ||
| 139 | atir_driver.owner = THIS_MODULE; | ||
| 140 | |||
| 141 | atir_minor = lirc_register_driver(&atir_driver); | ||
| 142 | if (atir_minor < 0) { | ||
| 143 | printk(KERN_ERR DRIVER_NAME ": failed to register driver!\n"); | ||
| 144 | return atir_minor; | ||
| 145 | } | ||
| 146 | dprintk("driver is registered on minor %d\n", atir_minor); | ||
| 147 | |||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | |||
| 152 | void cleanup_module(void) | ||
| 153 | { | ||
| 154 | lirc_unregister_driver(atir_minor); | ||
| 155 | } | ||
| 156 | |||
| 157 | |||
| 158 | static int atir_init_start(void) | ||
| 159 | { | ||
| 160 | pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400); | ||
| 161 | if (pci_addr_lin == 0) { | ||
| 162 | printk(KERN_INFO DRIVER_NAME ": pci mem must be mapped\n"); | ||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | return 1; | ||
| 166 | } | ||
| 167 | |||
| 168 | static void cycle_delay(int cycle) | ||
| 169 | { | ||
| 170 | udelay(WAIT_CYCLE*cycle); | ||
| 171 | } | ||
| 172 | |||
| 173 | |||
| 174 | static int poll_main() | ||
| 175 | { | ||
| 176 | unsigned char status_high, status_low; | ||
| 177 | |||
| 178 | do_i2c_start(); | ||
| 179 | |||
| 180 | seems_wr_byte(0xAA); | ||
| 181 | seems_wr_byte(0x01); | ||
| 182 | |||
| 183 | do_i2c_start(); | ||
| 184 | |||
| 185 | seems_wr_byte(0xAB); | ||
| 186 | |||
| 187 | status_low = seems_rd_byte(); | ||
| 188 | status_high = seems_rd_byte(); | ||
| 189 | |||
| 190 | do_i2c_stop(); | ||
| 191 | |||
| 192 | return (status_high << 8) | status_low; | ||
| 193 | } | ||
| 194 | |||
| 195 | static void do_i2c_start(void) | ||
| 196 | { | ||
| 197 | do_set_bits(3); | ||
| 198 | cycle_delay(4); | ||
| 199 | |||
| 200 | do_set_bits(1); | ||
| 201 | cycle_delay(7); | ||
| 202 | |||
| 203 | do_set_bits(0); | ||
| 204 | cycle_delay(2); | ||
| 205 | } | ||
| 206 | |||
| 207 | static void do_i2c_stop(void) | ||
| 208 | { | ||
| 209 | unsigned char bits; | ||
| 210 | bits = do_get_bits() & 0xFD; | ||
| 211 | do_set_bits(bits); | ||
| 212 | cycle_delay(1); | ||
| 213 | |||
| 214 | bits |= 1; | ||
| 215 | do_set_bits(bits); | ||
| 216 | cycle_delay(2); | ||
| 217 | |||
| 218 | bits |= 2; | ||
| 219 | do_set_bits(bits); | ||
| 220 | bits = 3; | ||
| 221 | do_set_bits(bits); | ||
| 222 | cycle_delay(2); | ||
| 223 | } | ||
| 224 | |||
| 225 | static void seems_wr_byte(unsigned char value) | ||
| 226 | { | ||
| 227 | int i; | ||
| 228 | unsigned char reg; | ||
| 229 | |||
| 230 | reg = do_get_bits(); | ||
| 231 | for (i = 0; i < 8; i++) { | ||
| 232 | if (value & 0x80) | ||
| 233 | reg |= 0x02; | ||
| 234 | else | ||
| 235 | reg &= 0xFD; | ||
| 236 | |||
| 237 | do_set_bits(reg); | ||
| 238 | cycle_delay(1); | ||
| 239 | |||
| 240 | reg |= 1; | ||
| 241 | do_set_bits(reg); | ||
| 242 | cycle_delay(1); | ||
| 243 | |||
| 244 | reg &= 0xFE; | ||
| 245 | do_set_bits(reg); | ||
| 246 | cycle_delay(1); | ||
| 247 | value <<= 1; | ||
| 248 | } | ||
| 249 | cycle_delay(2); | ||
| 250 | |||
| 251 | reg |= 2; | ||
| 252 | do_set_bits(reg); | ||
| 253 | |||
| 254 | reg |= 1; | ||
| 255 | do_set_bits(reg); | ||
| 256 | |||
| 257 | cycle_delay(1); | ||
| 258 | do_get_bits(); | ||
| 259 | |||
| 260 | reg &= 0xFE; | ||
| 261 | do_set_bits(reg); | ||
| 262 | cycle_delay(3); | ||
| 263 | } | ||
| 264 | |||
| 265 | static unsigned char seems_rd_byte(void) | ||
| 266 | { | ||
| 267 | int i; | ||
| 268 | int rd_byte; | ||
| 269 | unsigned char bits_2, bits_1; | ||
| 270 | |||
| 271 | bits_1 = do_get_bits() | 2; | ||
| 272 | do_set_bits(bits_1); | ||
| 273 | |||
| 274 | rd_byte = 0; | ||
| 275 | for (i = 0; i < 8; i++) { | ||
| 276 | bits_1 &= 0xFE; | ||
| 277 | do_set_bits(bits_1); | ||
| 278 | cycle_delay(2); | ||
| 279 | |||
| 280 | bits_1 |= 1; | ||
| 281 | do_set_bits(bits_1); | ||
| 282 | cycle_delay(1); | ||
| 283 | |||
| 284 | bits_2 = do_get_bits(); | ||
| 285 | if (bits_2 & 2) | ||
| 286 | rd_byte |= 1; | ||
| 287 | |||
| 288 | rd_byte <<= 1; | ||
| 289 | } | ||
| 290 | |||
| 291 | bits_1 = 0; | ||
| 292 | if (bits_2 == 0) | ||
| 293 | bits_1 |= 2; | ||
| 294 | |||
| 295 | do_set_bits(bits_1); | ||
| 296 | cycle_delay(2); | ||
| 297 | |||
| 298 | bits_1 |= 1; | ||
| 299 | do_set_bits(bits_1); | ||
| 300 | cycle_delay(3); | ||
| 301 | |||
| 302 | bits_1 &= 0xFE; | ||
| 303 | do_set_bits(bits_1); | ||
| 304 | cycle_delay(2); | ||
| 305 | |||
| 306 | rd_byte >>= 1; | ||
| 307 | rd_byte &= 0xFF; | ||
| 308 | return rd_byte; | ||
| 309 | } | ||
| 310 | |||
| 311 | static void do_set_bits(unsigned char new_bits) | ||
| 312 | { | ||
| 313 | int reg_val; | ||
| 314 | reg_val = read_index(0x34); | ||
| 315 | if (new_bits & 2) { | ||
| 316 | reg_val &= 0xFFFFFFDF; | ||
| 317 | reg_val |= 1; | ||
| 318 | } else { | ||
| 319 | reg_val &= 0xFFFFFFFE; | ||
| 320 | reg_val |= 0x20; | ||
| 321 | } | ||
| 322 | reg_val |= 0x10; | ||
| 323 | write_index(0x34, reg_val); | ||
| 324 | |||
| 325 | reg_val = read_index(0x31); | ||
| 326 | if (new_bits & 1) | ||
| 327 | reg_val |= 0x1000000; | ||
| 328 | else | ||
| 329 | reg_val &= 0xFEFFFFFF; | ||
| 330 | |||
| 331 | reg_val |= 0x8000000; | ||
| 332 | write_index(0x31, reg_val); | ||
| 333 | } | ||
| 334 | |||
| 335 | static unsigned char do_get_bits(void) | ||
| 336 | { | ||
| 337 | unsigned char bits; | ||
| 338 | int reg_val; | ||
| 339 | |||
| 340 | reg_val = read_index(0x34); | ||
| 341 | reg_val |= 0x10; | ||
| 342 | reg_val &= 0xFFFFFFDF; | ||
| 343 | write_index(0x34, reg_val); | ||
| 344 | |||
| 345 | reg_val = read_index(0x34); | ||
| 346 | bits = 0; | ||
| 347 | if (reg_val & 8) | ||
| 348 | bits |= 2; | ||
| 349 | else | ||
| 350 | bits &= 0xFD; | ||
| 351 | |||
| 352 | reg_val = read_index(0x31); | ||
| 353 | if (reg_val & 0x1000000) | ||
| 354 | bits |= 1; | ||
| 355 | else | ||
| 356 | bits &= 0xFE; | ||
| 357 | |||
| 358 | return bits; | ||
| 359 | } | ||
| 360 | |||
| 361 | static unsigned int read_index(unsigned char index) | ||
| 362 | { | ||
| 363 | unsigned char *addr; | ||
| 364 | unsigned int value; | ||
| 365 | /* addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */ | ||
| 366 | addr = pci_addr_lin + ((index & 0xFF) << 2); | ||
| 367 | value = readl(addr); | ||
| 368 | return value; | ||
| 369 | } | ||
| 370 | |||
| 371 | static void write_index(unsigned char index, unsigned int reg_val) | ||
| 372 | { | ||
| 373 | unsigned char *addr; | ||
| 374 | addr = pci_addr_lin + ((index & 0xFF) << 2); | ||
| 375 | writel(reg_val, addr); | ||
| 376 | } | ||
| 377 | |||
| 378 | MODULE_AUTHOR("Froenchenko Leonid"); | ||
| 379 | MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards"); | ||
| 380 | MODULE_LICENSE("GPL"); | ||
| 381 | |||
| 382 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
| 383 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | ||
diff --git a/drivers/staging/lirc/lirc_ene0100.h b/drivers/staging/lirc/lirc_ene0100.h new file mode 100644 index 00000000000..06bebd6acc4 --- /dev/null +++ b/drivers/staging/lirc/lirc_ene0100.h | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* | ||
| 2 | * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@gmail.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License as | ||
| 8 | * published by the Free Software Foundation; either version 2 of the | ||
| 9 | * License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
| 19 | * USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <media/lirc.h> | ||
| 23 | #include <media/lirc_dev.h> | ||
| 24 | |||
| 25 | /* hardware address */ | ||
| 26 | #define ENE_STATUS 0 /* hardware status - unused */ | ||
| 27 | #define ENE_ADDR_HI 1 /* hi byte of register address */ | ||
| 28 | #define ENE_ADDR_LO 2 /* low byte of register address */ | ||
| 29 | #define ENE_IO 3 /* read/write window */ | ||
| 30 | #define ENE_MAX_IO 4 | ||
| 31 | |||
| 32 | /* 8 bytes of samples, divided in 2 halfs*/ | ||
| 33 | #define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */ | ||
| 34 | #define ENE_SAMPLE_SPC_MASK (1 << 7) /* sample is space */ | ||
| 35 | #define ENE_SAMPLE_VALUE_MASK 0x7F | ||
| 36 | #define ENE_SAMPLE_OVERFLOW 0x7F | ||
| 37 | #define ENE_SAMPLES_SIZE 4 | ||
| 38 | |||
| 39 | /* fan input sample buffer */ | ||
| 40 | #define ENE_SAMPLE_BUFFER_FAN 0xF8FB /* this buffer holds high byte of */ | ||
| 41 | /* each sample of normal buffer */ | ||
| 42 | |||
| 43 | #define ENE_FAN_SMPL_PULS_MSK 0x8000 /* this bit of combined sample */ | ||
| 44 | /* if set, says that sample is pulse */ | ||
| 45 | #define ENE_FAN_VALUE_MASK 0x0FFF /* mask for valid bits of the value */ | ||
| 46 | |||
| 47 | /* first firmware register */ | ||
| 48 | #define ENE_FW1 0xF8F8 | ||
| 49 | #define ENE_FW1_ENABLE (1 << 0) /* enable fw processing */ | ||
| 50 | #define ENE_FW1_TXIRQ (1 << 1) /* TX interrupt pending */ | ||
| 51 | #define ENE_FW1_WAKE (1 << 6) /* enable wake from S3 */ | ||
| 52 | #define ENE_FW1_IRQ (1 << 7) /* enable interrupt */ | ||
| 53 | |||
| 54 | /* second firmware register */ | ||
| 55 | #define ENE_FW2 0xF8F9 | ||
| 56 | #define ENE_FW2_BUF_HIGH (1 << 0) /* which half of the buffer to read */ | ||
| 57 | #define ENE_FW2_IRQ_CLR (1 << 2) /* clear this on IRQ */ | ||
| 58 | #define ENE_FW2_GP40_AS_LEARN (1 << 4) /* normal input is used as */ | ||
| 59 | /* learning input */ | ||
| 60 | #define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */ | ||
| 61 | #define ENE_FW2_LEARNING (1 << 7) /* hardware supports learning and TX */ | ||
| 62 | |||
| 63 | /* fan as input settings - only if learning capable */ | ||
| 64 | #define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */ | ||
| 65 | #define ENE_FAN_AS_IN1_EN 0xCD | ||
| 66 | #define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */ | ||
| 67 | #define ENE_FAN_AS_IN2_EN 0x03 | ||
| 68 | #define ENE_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */ | ||
| 69 | |||
| 70 | /* IRQ registers block (for revision B) */ | ||
| 71 | #define ENEB_IRQ 0xFD09 /* IRQ number */ | ||
| 72 | #define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */ | ||
| 73 | #define ENEB_IRQ_STATUS 0xFD80 /* irq status */ | ||
| 74 | #define ENEB_IRQ_STATUS_IR (1 << 5) /* IR irq */ | ||
| 75 | |||
| 76 | /* IRQ registers block (for revision C,D) */ | ||
| 77 | #define ENEC_IRQ 0xFE9B /* new irq settings register */ | ||
| 78 | #define ENEC_IRQ_MASK 0x0F /* irq number mask */ | ||
| 79 | #define ENEC_IRQ_UNK_EN (1 << 4) /* always enabled */ | ||
| 80 | #define ENEC_IRQ_STATUS (1 << 5) /* irq status and ACK */ | ||
| 81 | |||
| 82 | /* CIR block settings */ | ||
| 83 | #define ENE_CIR_CONF1 0xFEC0 | ||
| 84 | #define ENE_CIR_CONF1_ADC_ON 0x7 /* receiver on gpio40 enabled */ | ||
| 85 | #define ENE_CIR_CONF1_LEARN1 (1 << 3) /* enabled on learning mode */ | ||
| 86 | #define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */ | ||
| 87 | #define ENE_CIR_CONF1_TX_CARR (1 << 7) /* send TX carrier or not */ | ||
| 88 | |||
| 89 | #define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */ | ||
| 90 | #define ENE_CIR_CONF2_LEARN2 (1 << 4) /* set on enable learning */ | ||
| 91 | #define ENE_CIR_CONF2_GPIO40DIS (1 << 5) /* disable normal input via gpio40 */ | ||
| 92 | |||
| 93 | #define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */ | ||
| 94 | #define ENE_CIR_SAMPLE_OVERFLOW (1 << 7) /* interrupt on overflows if set */ | ||
| 95 | |||
| 96 | |||
| 97 | /* transmitter - not implemented yet */ | ||
| 98 | /* KB3926C and higher */ | ||
| 99 | /* transmission is very similar to receiving, a byte is written to */ | ||
| 100 | /* ENE_TX_INPUT, in same manner as it is read from sample buffer */ | ||
| 101 | /* sample period is fixed*/ | ||
| 102 | |||
| 103 | |||
| 104 | /* transmitter ports */ | ||
| 105 | #define ENE_TX_PORT1 0xFC01 /* this enables one or both */ | ||
| 106 | #define ENE_TX_PORT1_EN (1 << 5) /* TX ports */ | ||
| 107 | #define ENE_TX_PORT2 0xFC08 | ||
| 108 | #define ENE_TX_PORT2_EN (1 << 1) | ||
| 109 | |||
| 110 | #define ENE_TX_INPUT 0xFEC9 /* next byte to transmit */ | ||
| 111 | #define ENE_TX_SPC_MASK (1 << 7) /* Transmitted sample is space */ | ||
| 112 | #define ENE_TX_UNK1 0xFECB /* set to 0x63 */ | ||
| 113 | #define ENE_TX_SMPL_PERIOD 50 /* transmit sample period */ | ||
| 114 | |||
| 115 | |||
| 116 | #define ENE_TX_CARRIER 0xFECE /* TX carrier * 2 (khz) */ | ||
| 117 | #define ENE_TX_CARRIER_UNKBIT 0x80 /* This bit set on transmit */ | ||
| 118 | #define ENE_TX_CARRIER_LOW 0xFECF /* TX carrier / 2 */ | ||
| 119 | |||
| 120 | /* Hardware versions */ | ||
| 121 | #define ENE_HW_VERSION 0xFF00 /* hardware revision */ | ||
| 122 | #define ENE_HW_UNK 0xFF1D | ||
| 123 | #define ENE_HW_UNK_CLR (1 << 2) | ||
| 124 | #define ENE_HW_VER_MAJOR 0xFF1E /* chip version */ | ||
| 125 | #define ENE_HW_VER_MINOR 0xFF1F | ||
| 126 | #define ENE_HW_VER_OLD 0xFD00 | ||
| 127 | |||
| 128 | #define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0)) | ||
| 129 | |||
| 130 | #define ENE_DRIVER_NAME "enecir" | ||
| 131 | #define ENE_MAXGAP 250000 /* this is amount of time we wait | ||
| 132 | before turning the sampler, chosen | ||
| 133 | arbitry */ | ||
| 134 | |||
| 135 | #define space(len) (-(len)) /* add a space */ | ||
| 136 | |||
| 137 | /* software defines */ | ||
| 138 | #define ENE_IRQ_RX 1 | ||
| 139 | #define ENE_IRQ_TX 2 | ||
| 140 | |||
| 141 | #define ENE_HW_B 1 /* 3926B */ | ||
| 142 | #define ENE_HW_C 2 /* 3926C */ | ||
| 143 | #define ENE_HW_D 3 /* 3926D */ | ||
| 144 | |||
| 145 | #define ene_printk(level, text, ...) \ | ||
| 146 | printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__) | ||
| 147 | |||
| 148 | struct ene_device { | ||
| 149 | struct pnp_dev *pnp_dev; | ||
| 150 | struct lirc_driver *lirc_driver; | ||
| 151 | |||
| 152 | /* hw settings */ | ||
| 153 | unsigned long hw_io; | ||
| 154 | int irq; | ||
| 155 | |||
| 156 | int hw_revision; /* hardware revision */ | ||
| 157 | int hw_learning_and_tx_capable; /* learning capable */ | ||
| 158 | int hw_gpio40_learning; /* gpio40 is learning */ | ||
| 159 | int hw_fan_as_normal_input; /* fan input is used as regular input */ | ||
| 160 | |||
| 161 | /* device data */ | ||
| 162 | int idle; | ||
| 163 | int fan_input_inuse; | ||
| 164 | |||
| 165 | int sample; | ||
| 166 | int in_use; | ||
| 167 | |||
| 168 | struct timeval gap_start; | ||
| 169 | }; | ||
diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/lirc/lirc_igorplugusb.c new file mode 100644 index 00000000000..0dc2c2b22c2 --- /dev/null +++ b/drivers/staging/lirc/lirc_igorplugusb.c | |||
| @@ -0,0 +1,577 @@ | |||
| 1 | /* | ||
| 2 | * lirc_igorplugusb - USB remote support for LIRC | ||
| 3 | * | ||
| 4 | * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware. | ||
| 5 | * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm | ||
| 6 | * | ||
| 7 | * The device can only record bursts of up to 36 pulses/spaces. | ||
| 8 | * Works fine with RC5. Longer commands lead to device buffer overrun. | ||
| 9 | * (Maybe a better firmware or a microcontroller with more ram can help?) | ||
| 10 | * | ||
| 11 | * Version 0.1 [beta status] | ||
| 12 | * | ||
| 13 | * Copyright (C) 2004 Jan M. Hochstein | ||
| 14 | * <hochstein@algo.informatik.tu-darmstadt.de> | ||
| 15 | * | ||
| 16 | * This driver was derived from: | ||
| 17 | * Paul Miller <pmiller9@users.sourceforge.net> | ||
| 18 | * "lirc_atiusb" module | ||
| 19 | * Vladimir Dergachev <volodya@minspring.com>'s 2002 | ||
| 20 | * "USB ATI Remote support" (input device) | ||
| 21 | * Adrian Dewhurst <sailor-lk@sailorfrag.net>'s 2002 | ||
| 22 | * "USB StreamZap remote driver" (LIRC) | ||
| 23 | * Artur Lipowski <alipowski@kki.net.pl>'s 2002 | ||
| 24 | * "lirc_dev" and "lirc_gpio" LIRC modules | ||
| 25 | */ | ||
| 26 | |||
| 27 | /* | ||
| 28 | * This program is free software; you can redistribute it and/or modify | ||
| 29 | * it under the terms of the GNU General Public License as published by | ||
| 30 | * the Free Software Foundation; either version 2 of the License, or | ||
| 31 | * (at your option) any later version. | ||
| 32 | * | ||
| 33 | * This program is distributed in the hope that it will be useful, | ||
| 34 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 35 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 36 | * GNU General Public License for more details. | ||
| 37 | * | ||
| 38 | * You should have received a copy of the GNU General Public License | ||
| 39 | * along with this program; if not, write to the Free Software | ||
| 40 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 41 | */ | ||
| 42 | |||
| 43 | #include <linux/module.h> | ||
| 44 | #include <linux/kernel.h> | ||
| 45 | #include <linux/kmod.h> | ||
| 46 | #include <linux/sched.h> | ||
| 47 | #include <linux/errno.h> | ||
| 48 | #include <linux/fs.h> | ||
| 49 | #include <linux/usb.h> | ||
| 50 | #include <linux/time.h> | ||
| 51 | |||
| 52 | #include <media/lirc.h> | ||
| 53 | #include <media/lirc_dev.h> | ||
| 54 | |||
| 55 | |||
| 56 | /* module identification */ | ||
| 57 | #define DRIVER_VERSION "0.2" | ||
| 58 | #define DRIVER_AUTHOR \ | ||
| 59 | "Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>" | ||
| 60 | #define DRIVER_DESC "Igorplug USB remote driver for LIRC" | ||
| 61 | #define DRIVER_NAME "lirc_igorplugusb" | ||
| 62 | |||
| 63 | /* debugging support */ | ||
| 64 | #ifdef CONFIG_USB_DEBUG | ||
| 65 | static int debug = 1; | ||
| 66 | #else | ||
| 67 | static int debug; | ||
| 68 | #endif | ||
| 69 | |||
| 70 | #define dprintk(fmt, args...) \ | ||
| 71 | do { \ | ||
| 72 | if (debug) \ | ||
| 73 | printk(KERN_DEBUG fmt, ## args); \ | ||
| 74 | } while (0) | ||
| 75 | |||
| 76 | /* One mode2 pulse/space has 4 bytes. */ | ||
| 77 | #define CODE_LENGTH sizeof(int) | ||
| 78 | |||
| 79 | /* Igor's firmware cannot record bursts longer than 36. */ | ||
| 80 | #define DEVICE_BUFLEN 36 | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Header at the beginning of the device's buffer: | ||
| 84 | * unsigned char data_length | ||
| 85 | * unsigned char data_start (!=0 means ring-buffer overrun) | ||
| 86 | * unsigned char counter (incremented by each burst) | ||
| 87 | */ | ||
| 88 | #define DEVICE_HEADERLEN 3 | ||
| 89 | |||
| 90 | /* This is for the gap */ | ||
| 91 | #define ADDITIONAL_LIRC_BYTES 2 | ||
| 92 | |||
| 93 | /* times to poll per second */ | ||
| 94 | #define SAMPLE_RATE 100 | ||
| 95 | static int sample_rate = SAMPLE_RATE; | ||
| 96 | |||
| 97 | |||
| 98 | /**** Igor's USB Request Codes */ | ||
| 99 | |||
| 100 | #define SET_INFRABUFFER_EMPTY 1 | ||
| 101 | /** | ||
| 102 | * Params: none | ||
| 103 | * Answer: empty | ||
| 104 | */ | ||
| 105 | |||
| 106 | #define GET_INFRACODE 2 | ||
| 107 | /** | ||
| 108 | * Params: | ||
| 109 | * wValue: offset to begin reading infra buffer | ||
| 110 | * | ||
| 111 | * Answer: infra data | ||
| 112 | */ | ||
| 113 | |||
| 114 | #define SET_DATAPORT_DIRECTION 3 | ||
| 115 | /** | ||
| 116 | * Params: | ||
| 117 | * wValue: (byte) 1 bit for each data port pin (0=in, 1=out) | ||
| 118 | * | ||
| 119 | * Answer: empty | ||
| 120 | */ | ||
| 121 | |||
| 122 | #define GET_DATAPORT_DIRECTION 4 | ||
| 123 | /** | ||
| 124 | * Params: none | ||
| 125 | * | ||
| 126 | * Answer: (byte) 1 bit for each data port pin (0=in, 1=out) | ||
| 127 | */ | ||
| 128 | |||
| 129 | #define SET_OUT_DATAPORT 5 | ||
| 130 | /** | ||
| 131 | * Params: | ||
| 132 | * wValue: byte to write to output data port | ||
| 133 | * | ||
| 134 | * Answer: empty | ||
| 135 | */ | ||
| 136 | |||
| 137 | #define GET_OUT_DATAPORT 6 | ||
| 138 | /** | ||
| 139 | * Params: none | ||
| 140 | * | ||
| 141 | * Answer: least significant 3 bits read from output data port | ||
| 142 | */ | ||
| 143 | |||
| 144 | #define GET_IN_DATAPORT 7 | ||
| 145 | /** | ||
| 146 | * Params: none | ||
| 147 | * | ||
| 148 | * Answer: least significant 3 bits read from input data port | ||
| 149 | */ | ||
| 150 | |||
| 151 | #define READ_EEPROM 8 | ||
| 152 | /** | ||
| 153 | * Params: | ||
| 154 | * wValue: offset to begin reading EEPROM | ||
| 155 | * | ||
| 156 | * Answer: EEPROM bytes | ||
| 157 | */ | ||
| 158 | |||
| 159 | #define WRITE_EEPROM 9 | ||
| 160 | /** | ||
| 161 | * Params: | ||
| 162 | * wValue: offset to EEPROM byte | ||
| 163 | * wIndex: byte to write | ||
| 164 | * | ||
| 165 | * Answer: empty | ||
| 166 | */ | ||
| 167 | |||
| 168 | #define SEND_RS232 10 | ||
| 169 | /** | ||
| 170 | * Params: | ||
| 171 | * wValue: byte to send | ||
| 172 | * | ||
| 173 | * Answer: empty | ||
| 174 | */ | ||
| 175 | |||
| 176 | #define RECV_RS232 11 | ||
| 177 | /** | ||
| 178 | * Params: none | ||
| 179 | * | ||
| 180 | * Answer: byte received | ||
| 181 | */ | ||
| 182 | |||
| 183 | #define SET_RS232_BAUD 12 | ||
| 184 | /** | ||
| 185 | * Params: | ||
| 186 | * wValue: byte to write to UART bit rate register (UBRR) | ||
| 187 | * | ||
| 188 | * Answer: empty | ||
| 189 | */ | ||
| 190 | |||
| 191 | #define GET_RS232_BAUD 13 | ||
| 192 | /** | ||
| 193 | * Params: none | ||
| 194 | * | ||
| 195 | * Answer: byte read from UART bit rate register (UBRR) | ||
| 196 | */ | ||
| 197 | |||
| 198 | |||
| 199 | /* data structure for each usb remote */ | ||
| 200 | struct igorplug { | ||
| 201 | |||
| 202 | /* usb */ | ||
| 203 | struct usb_device *usbdev; | ||
| 204 | int devnum; | ||
| 205 | |||
| 206 | unsigned char *buf_in; | ||
| 207 | unsigned int len_in; | ||
| 208 | int in_space; | ||
| 209 | struct timeval last_time; | ||
| 210 | |||
| 211 | dma_addr_t dma_in; | ||
| 212 | |||
| 213 | /* lirc */ | ||
| 214 | struct lirc_driver *d; | ||
| 215 | |||
| 216 | /* handle sending (init strings) */ | ||
| 217 | int send_flags; | ||
| 218 | }; | ||
| 219 | |||
| 220 | static int unregister_from_lirc(struct igorplug *ir) | ||
| 221 | { | ||
| 222 | struct lirc_driver *d; | ||
| 223 | int devnum; | ||
| 224 | |||
| 225 | if (!ir) { | ||
| 226 | printk(KERN_ERR "%s: called with NULL device struct!\n", | ||
| 227 | __func__); | ||
| 228 | return -EINVAL; | ||
| 229 | } | ||
| 230 | |||
| 231 | devnum = ir->devnum; | ||
| 232 | d = ir->d; | ||
| 233 | |||
| 234 | if (!d) { | ||
| 235 | printk(KERN_ERR "%s: called with NULL lirc driver struct!\n", | ||
| 236 | __func__); | ||
| 237 | return -EINVAL; | ||
| 238 | } | ||
| 239 | |||
| 240 | dprintk(DRIVER_NAME "[%d]: calling lirc_unregister_driver\n", devnum); | ||
| 241 | lirc_unregister_driver(d->minor); | ||
| 242 | |||
| 243 | kfree(d); | ||
| 244 | ir->d = NULL; | ||
| 245 | kfree(ir); | ||
| 246 | |||
| 247 | return devnum; | ||
| 248 | } | ||
| 249 | |||
| 250 | static int set_use_inc(void *data) | ||
| 251 | { | ||
| 252 | struct igorplug *ir = data; | ||
| 253 | |||
| 254 | if (!ir) { | ||
| 255 | printk(DRIVER_NAME "[?]: set_use_inc called with no context\n"); | ||
| 256 | return -EIO; | ||
| 257 | } | ||
| 258 | |||
| 259 | dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum); | ||
| 260 | |||
| 261 | if (!ir->usbdev) | ||
| 262 | return -ENODEV; | ||
| 263 | |||
| 264 | return 0; | ||
| 265 | } | ||
| 266 | |||
| 267 | static void set_use_dec(void *data) | ||
| 268 | { | ||
| 269 | struct igorplug *ir = data; | ||
| 270 | |||
| 271 | if (!ir) { | ||
| 272 | printk(DRIVER_NAME "[?]: set_use_dec called with no context\n"); | ||
| 273 | return; | ||
| 274 | } | ||
| 275 | |||
| 276 | dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum); | ||
| 277 | } | ||
| 278 | |||
| 279 | static void send_fragment(struct igorplug *ir, struct lirc_buffer *buf, | ||
| 280 | int i, int max) | ||
| 281 | { | ||
| 282 | int code; | ||
| 283 | |||
| 284 | /* MODE2: pulse/space (PULSE_BIT) in 1us units */ | ||
| 285 | while (i < max) { | ||
| 286 | /* 1 Igor-tick = 85.333333 us */ | ||
| 287 | code = (unsigned int)ir->buf_in[i] * 85 + | ||
| 288 | (unsigned int)ir->buf_in[i] / 3; | ||
| 289 | ir->last_time.tv_usec += code; | ||
| 290 | if (ir->in_space) | ||
| 291 | code |= PULSE_BIT; | ||
| 292 | lirc_buffer_write(buf, (unsigned char *)&code); | ||
| 293 | /* 1 chunk = CODE_LENGTH bytes */ | ||
| 294 | ir->in_space ^= 1; | ||
| 295 | ++i; | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 299 | /** | ||
| 300 | * Called in user context. | ||
| 301 | * return 0 if data was added to the buffer and | ||
| 302 | * -ENODATA if none was available. This should add some number of bits | ||
| 303 | * evenly divisible by code_length to the buffer | ||
| 304 | */ | ||
| 305 | static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf) | ||
| 306 | { | ||
| 307 | int ret; | ||
| 308 | struct igorplug *ir = (struct igorplug *)data; | ||
| 309 | |||
| 310 | if (!ir || !ir->usbdev) /* Has the device been removed? */ | ||
| 311 | return -ENODEV; | ||
| 312 | |||
| 313 | memset(ir->buf_in, 0, ir->len_in); | ||
| 314 | |||
| 315 | ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), | ||
| 316 | GET_INFRACODE, USB_TYPE_VENDOR | USB_DIR_IN, | ||
| 317 | 0/* offset */, /*unused*/0, | ||
| 318 | ir->buf_in, ir->len_in, | ||
| 319 | /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); | ||
| 320 | if (ret > 0) { | ||
| 321 | int code, timediff; | ||
| 322 | struct timeval now; | ||
| 323 | |||
| 324 | /* ACK packet has 1 byte --> ignore */ | ||
| 325 | if (ret < DEVICE_HEADERLEN) | ||
| 326 | return -ENODATA; | ||
| 327 | |||
| 328 | dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n", | ||
| 329 | ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]); | ||
| 330 | |||
| 331 | do_gettimeofday(&now); | ||
| 332 | timediff = now.tv_sec - ir->last_time.tv_sec; | ||
| 333 | if (timediff + 1 > PULSE_MASK / 1000000) | ||
| 334 | timediff = PULSE_MASK; | ||
| 335 | else { | ||
| 336 | timediff *= 1000000; | ||
| 337 | timediff += now.tv_usec - ir->last_time.tv_usec; | ||
| 338 | } | ||
| 339 | ir->last_time.tv_sec = now.tv_sec; | ||
| 340 | ir->last_time.tv_usec = now.tv_usec; | ||
| 341 | |||
| 342 | /* create leading gap */ | ||
| 343 | code = timediff; | ||
| 344 | lirc_buffer_write(buf, (unsigned char *)&code); | ||
| 345 | ir->in_space = 1; /* next comes a pulse */ | ||
| 346 | |||
| 347 | if (ir->buf_in[2] == 0) | ||
| 348 | send_fragment(ir, buf, DEVICE_HEADERLEN, ret); | ||
| 349 | else { | ||
| 350 | printk(KERN_WARNING DRIVER_NAME | ||
| 351 | "[%d]: Device buffer overrun.\n", ir->devnum); | ||
| 352 | /* HHHNNNNNNNNNNNOOOOOOOO H = header | ||
| 353 | <---[2]---> N = newer | ||
| 354 | <---------ret--------> O = older */ | ||
| 355 | ir->buf_in[2] %= ret - DEVICE_HEADERLEN; /* sanitize */ | ||
| 356 | /* keep even-ness to not desync pulse/pause */ | ||
| 357 | send_fragment(ir, buf, DEVICE_HEADERLEN + | ||
| 358 | ir->buf_in[2] - (ir->buf_in[2] & 1), ret); | ||
| 359 | send_fragment(ir, buf, DEVICE_HEADERLEN, | ||
| 360 | DEVICE_HEADERLEN + ir->buf_in[2]); | ||
| 361 | } | ||
| 362 | |||
| 363 | ret = usb_control_msg( | ||
| 364 | ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), | ||
| 365 | SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, | ||
| 366 | /*unused*/0, /*unused*/0, | ||
| 367 | /*dummy*/ir->buf_in, /*dummy*/ir->len_in, | ||
| 368 | /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); | ||
| 369 | if (ret < 0) | ||
| 370 | printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: " | ||
| 371 | "error %d\n", ir->devnum, ret); | ||
| 372 | return 0; | ||
| 373 | } else if (ret < 0) | ||
| 374 | printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n", | ||
| 375 | ir->devnum, ret); | ||
| 376 | |||
| 377 | return -ENODATA; | ||
| 378 | } | ||
| 379 | |||
| 380 | |||
| 381 | |||
| 382 | static int igorplugusb_remote_probe(struct usb_interface *intf, | ||
| 383 | const struct usb_device_id *id) | ||
| 384 | { | ||
| 385 | struct usb_device *dev = NULL; | ||
| 386 | struct usb_host_interface *idesc = NULL; | ||
| 387 | struct usb_endpoint_descriptor *ep; | ||
| 388 | struct igorplug *ir = NULL; | ||
| 389 | struct lirc_driver *driver = NULL; | ||
| 390 | int devnum, pipe, maxp; | ||
| 391 | int minor = 0; | ||
| 392 | char buf[63], name[128] = ""; | ||
| 393 | int mem_failure = 0; | ||
| 394 | int ret; | ||
| 395 | |||
| 396 | dprintk(DRIVER_NAME ": usb probe called.\n"); | ||
| 397 | |||
| 398 | dev = interface_to_usbdev(intf); | ||
| 399 | |||
| 400 | idesc = intf->cur_altsetting; | ||
| 401 | |||
| 402 | if (idesc->desc.bNumEndpoints != 1) | ||
| 403 | return -ENODEV; | ||
| 404 | |||
| 405 | ep = &idesc->endpoint->desc; | ||
| 406 | if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) | ||
| 407 | != USB_DIR_IN) | ||
| 408 | || (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | ||
| 409 | != USB_ENDPOINT_XFER_CONTROL) | ||
| 410 | return -ENODEV; | ||
| 411 | |||
| 412 | pipe = usb_rcvctrlpipe(dev, ep->bEndpointAddress); | ||
| 413 | devnum = dev->devnum; | ||
| 414 | maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); | ||
| 415 | |||
| 416 | dprintk(DRIVER_NAME "[%d]: bytes_in_key=%zu maxp=%d\n", | ||
| 417 | devnum, CODE_LENGTH, maxp); | ||
| 418 | |||
| 419 | mem_failure = 0; | ||
| 420 | ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL); | ||
| 421 | if (!ir) { | ||
| 422 | mem_failure = 1; | ||
| 423 | goto mem_failure_switch; | ||
| 424 | } | ||
| 425 | driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); | ||
| 426 | if (!driver) { | ||
| 427 | mem_failure = 2; | ||
| 428 | goto mem_failure_switch; | ||
| 429 | } | ||
| 430 | |||
| 431 | ir->buf_in = usb_alloc_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN, | ||
| 432 | GFP_ATOMIC, &ir->dma_in); | ||
| 433 | if (!ir->buf_in) { | ||
| 434 | mem_failure = 3; | ||
| 435 | goto mem_failure_switch; | ||
| 436 | } | ||
| 437 | |||
| 438 | strcpy(driver->name, DRIVER_NAME " "); | ||
| 439 | driver->minor = -1; | ||
| 440 | driver->code_length = CODE_LENGTH * 8; /* in bits */ | ||
| 441 | driver->features = LIRC_CAN_REC_MODE2; | ||
| 442 | driver->data = ir; | ||
| 443 | driver->chunk_size = CODE_LENGTH; | ||
| 444 | driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES; | ||
| 445 | driver->set_use_inc = &set_use_inc; | ||
| 446 | driver->set_use_dec = &set_use_dec; | ||
| 447 | driver->sample_rate = sample_rate; /* per second */ | ||
| 448 | driver->add_to_buf = &igorplugusb_remote_poll; | ||
| 449 | driver->dev = &intf->dev; | ||
| 450 | driver->owner = THIS_MODULE; | ||
| 451 | |||
| 452 | minor = lirc_register_driver(driver); | ||
| 453 | if (minor < 0) | ||
| 454 | mem_failure = 9; | ||
| 455 | |||
| 456 | mem_failure_switch: | ||
| 457 | |||
| 458 | switch (mem_failure) { | ||
| 459 | case 9: | ||
| 460 | usb_free_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN, | ||
| 461 | ir->buf_in, ir->dma_in); | ||
| 462 | case 3: | ||
| 463 | kfree(driver); | ||
| 464 | case 2: | ||
| 465 | kfree(ir); | ||
| 466 | case 1: | ||
| 467 | printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n", | ||
| 468 | devnum, mem_failure); | ||
| 469 | return -ENOMEM; | ||
| 470 | } | ||
| 471 | |||
| 472 | driver->minor = minor; | ||
| 473 | ir->d = driver; | ||
| 474 | ir->devnum = devnum; | ||
| 475 | ir->usbdev = dev; | ||
| 476 | ir->len_in = DEVICE_BUFLEN + DEVICE_HEADERLEN; | ||
| 477 | ir->in_space = 1; /* First mode2 event is a space. */ | ||
| 478 | do_gettimeofday(&ir->last_time); | ||
| 479 | |||
| 480 | if (dev->descriptor.iManufacturer | ||
| 481 | && usb_string(dev, dev->descriptor.iManufacturer, | ||
| 482 | buf, sizeof(buf)) > 0) | ||
| 483 | strlcpy(name, buf, sizeof(name)); | ||
| 484 | if (dev->descriptor.iProduct | ||
| 485 | && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0) | ||
| 486 | snprintf(name + strlen(name), sizeof(name) - strlen(name), | ||
| 487 | " %s", buf); | ||
| 488 | printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name, | ||
| 489 | dev->bus->busnum, devnum); | ||
| 490 | |||
| 491 | /* clear device buffer */ | ||
| 492 | ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), | ||
| 493 | SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, | ||
| 494 | /*unused*/0, /*unused*/0, | ||
| 495 | /*dummy*/ir->buf_in, /*dummy*/ir->len_in, | ||
| 496 | /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); | ||
| 497 | if (ret < 0) | ||
| 498 | printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n", | ||
| 499 | devnum, ret); | ||
| 500 | |||
| 501 | usb_set_intfdata(intf, ir); | ||
| 502 | return 0; | ||
| 503 | } | ||
| 504 | |||
| 505 | |||
| 506 | static void igorplugusb_remote_disconnect(struct usb_interface *intf) | ||
| 507 | { | ||
| 508 | struct usb_device *usbdev = interface_to_usbdev(intf); | ||
| 509 | struct igorplug *ir = usb_get_intfdata(intf); | ||
| 510 | struct device *dev = &intf->dev; | ||
| 511 | int devnum; | ||
| 512 | |||
| 513 | usb_set_intfdata(intf, NULL); | ||
| 514 | |||
| 515 | if (!ir || !ir->d) | ||
| 516 | return; | ||
| 517 | |||
| 518 | ir->usbdev = NULL; | ||
| 519 | |||
| 520 | usb_free_coherent(usbdev, ir->len_in, ir->buf_in, ir->dma_in); | ||
| 521 | |||
| 522 | devnum = unregister_from_lirc(ir); | ||
| 523 | |||
| 524 | dev_info(dev, DRIVER_NAME "[%d]: %s done\n", devnum, __func__); | ||
| 525 | } | ||
| 526 | |||
| 527 | static struct usb_device_id igorplugusb_remote_id_table[] = { | ||
| 528 | /* Igor Plug USB (Atmel's Manufact. ID) */ | ||
| 529 | { USB_DEVICE(0x03eb, 0x0002) }, | ||
| 530 | /* Fit PC2 Infrared Adapter */ | ||
| 531 | { USB_DEVICE(0x03eb, 0x21fe) }, | ||
| 532 | |||
| 533 | /* Terminating entry */ | ||
| 534 | { } | ||
| 535 | }; | ||
| 536 | |||
| 537 | static struct usb_driver igorplugusb_remote_driver = { | ||
| 538 | .name = DRIVER_NAME, | ||
| 539 | .probe = igorplugusb_remote_probe, | ||
| 540 | .disconnect = igorplugusb_remote_disconnect, | ||
| 541 | .id_table = igorplugusb_remote_id_table | ||
| 542 | }; | ||
| 543 | |||
| 544 | static int __init igorplugusb_remote_init(void) | ||
| 545 | { | ||
| 546 | int ret = 0; | ||
| 547 | |||
| 548 | dprintk(DRIVER_NAME ": loaded, debug mode enabled\n"); | ||
| 549 | |||
| 550 | ret = usb_register(&igorplugusb_remote_driver); | ||
| 551 | if (ret) | ||
| 552 | printk(KERN_ERR DRIVER_NAME ": usb register failed!\n"); | ||
| 553 | |||
| 554 | return ret; | ||
| 555 | } | ||
| 556 | |||
| 557 | static void __exit igorplugusb_remote_exit(void) | ||
| 558 | { | ||
| 559 | usb_deregister(&igorplugusb_remote_driver); | ||
| 560 | } | ||
| 561 | |||
| 562 | module_init(igorplugusb_remote_init); | ||
| 563 | module_exit(igorplugusb_remote_exit); | ||
| 564 | |||
| 565 | #include <linux/vermagic.h> | ||
| 566 | MODULE_INFO(vermagic, VERMAGIC_STRING); | ||
| 567 | |||
| 568 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 569 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 570 | MODULE_LICENSE("GPL"); | ||
| 571 | MODULE_DEVICE_TABLE(usb, igorplugusb_remote_id_table); | ||
| 572 | |||
| 573 | module_param(sample_rate, int, S_IRUGO | S_IWUSR); | ||
| 574 | MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)"); | ||
| 575 | |||
| 576 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
| 577 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | ||
diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c new file mode 100644 index 00000000000..4a9e563f40f --- /dev/null +++ b/drivers/staging/lirc/lirc_imon.c | |||
| @@ -0,0 +1,1050 @@ | |||
| 1 | /* | ||
| 2 | * lirc_imon.c: LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD | ||
| 3 | * including the iMON PAD model | ||
| 4 | * | ||
| 5 | * Copyright(C) 2004 Venky Raju(dev@venky.ws) | ||
| 6 | * Copyright(C) 2009 Jarod Wilson <jarod@wilsonet.com> | ||
| 7 | * | ||
| 8 | * lirc_imon is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/errno.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/kernel.h> | ||
| 26 | #include <linux/module.h> | ||
| 27 | #include <linux/slab.h> | ||
| 28 | #include <linux/uaccess.h> | ||
| 29 | #include <linux/usb.h> | ||
| 30 | |||
| 31 | #include <media/lirc.h> | ||
| 32 | #include <media/lirc_dev.h> | ||
| 33 | |||
| 34 | |||
| 35 | #define MOD_AUTHOR "Venky Raju <dev@venky.ws>" | ||
| 36 | #define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" | ||
| 37 | #define MOD_NAME "lirc_imon" | ||
| 38 | #define MOD_VERSION "0.8" | ||
| 39 | |||
| 40 | #define DISPLAY_MINOR_BASE 144 | ||
| 41 | #define DEVICE_NAME "lcd%d" | ||
| 42 | |||
| 43 | #define BUF_CHUNK_SIZE 4 | ||
| 44 | #define BUF_SIZE 128 | ||
| 45 | |||
| 46 | #define BIT_DURATION 250 /* each bit received is 250us */ | ||
| 47 | |||
| 48 | /*** P R O T O T Y P E S ***/ | ||
| 49 | |||
| 50 | /* USB Callback prototypes */ | ||
| 51 | static int imon_probe(struct usb_interface *interface, | ||
| 52 | const struct usb_device_id *id); | ||
| 53 | static void imon_disconnect(struct usb_interface *interface); | ||
| 54 | static void usb_rx_callback(struct urb *urb); | ||
| 55 | static void usb_tx_callback(struct urb *urb); | ||
| 56 | |||
| 57 | /* suspend/resume support */ | ||
| 58 | static int imon_resume(struct usb_interface *intf); | ||
| 59 | static int imon_suspend(struct usb_interface *intf, pm_message_t message); | ||
| 60 | |||
| 61 | /* Display file_operations function prototypes */ | ||
| 62 | static int display_open(struct inode *inode, struct file *file); | ||
| 63 | static int display_close(struct inode *inode, struct file *file); | ||
| 64 | |||
| 65 | /* VFD write operation */ | ||
| 66 | static ssize_t vfd_write(struct file *file, const char *buf, | ||
| 67 | size_t n_bytes, loff_t *pos); | ||
| 68 | |||
| 69 | /* LIRC driver function prototypes */ | ||
| 70 | static int ir_open(void *data); | ||
| 71 | static void ir_close(void *data); | ||
| 72 | |||
| 73 | /* Driver init/exit prototypes */ | ||
| 74 | static int __init imon_init(void); | ||
| 75 | static void __exit imon_exit(void); | ||
| 76 | |||
| 77 | /*** G L O B A L S ***/ | ||
| 78 | #define IMON_DATA_BUF_SZ 35 | ||
| 79 | |||
| 80 | struct imon_context { | ||
| 81 | struct usb_device *usbdev; | ||
| 82 | /* Newer devices have two interfaces */ | ||
| 83 | int display; /* not all controllers do */ | ||
| 84 | int display_isopen; /* display port has been opened */ | ||
| 85 | int ir_isopen; /* IR port open */ | ||
| 86 | int dev_present; /* USB device presence */ | ||
| 87 | struct mutex ctx_lock; /* to lock this object */ | ||
| 88 | wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ | ||
| 89 | |||
| 90 | int vfd_proto_6p; /* some VFD require a 6th packet */ | ||
| 91 | |||
| 92 | struct lirc_driver *driver; | ||
| 93 | struct usb_endpoint_descriptor *rx_endpoint; | ||
| 94 | struct usb_endpoint_descriptor *tx_endpoint; | ||
| 95 | struct urb *rx_urb; | ||
| 96 | struct urb *tx_urb; | ||
| 97 | unsigned char usb_rx_buf[8]; | ||
| 98 | unsigned char usb_tx_buf[8]; | ||
| 99 | |||
| 100 | struct rx_data { | ||
| 101 | int count; /* length of 0 or 1 sequence */ | ||
| 102 | int prev_bit; /* logic level of sequence */ | ||
| 103 | int initial_space; /* initial space flag */ | ||
| 104 | } rx; | ||
| 105 | |||
| 106 | struct tx_t { | ||
| 107 | unsigned char data_buf[IMON_DATA_BUF_SZ]; /* user data buffer */ | ||
| 108 | struct completion finished; /* wait for write to finish */ | ||
| 109 | atomic_t busy; /* write in progress */ | ||
| 110 | int status; /* status of tx completion */ | ||
| 111 | } tx; | ||
| 112 | }; | ||
| 113 | |||
| 114 | static const struct file_operations display_fops = { | ||
| 115 | .owner = THIS_MODULE, | ||
| 116 | .open = &display_open, | ||
| 117 | .write = &vfd_write, | ||
| 118 | .release = &display_close, | ||
| 119 | .llseek = noop_llseek, | ||
| 120 | }; | ||
| 121 | |||
| 122 | /* | ||
| 123 | * USB Device ID for iMON USB Control Boards | ||
| 124 | * | ||
| 125 | * The Windows drivers contain 6 different inf files, more or less one for | ||
| 126 | * each new device until the 0x0034-0x0046 devices, which all use the same | ||
| 127 | * driver. Some of the devices in the 34-46 range haven't been definitively | ||
| 128 | * identified yet. Early devices have either a TriGem Computer, Inc. or a | ||
| 129 | * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later | ||
| 130 | * devices use the SoundGraph vendor ID (0x15c2). | ||
| 131 | */ | ||
| 132 | static struct usb_device_id imon_usb_id_table[] = { | ||
| 133 | /* TriGem iMON (IR only) -- TG_iMON.inf */ | ||
| 134 | { USB_DEVICE(0x0aa8, 0x8001) }, | ||
| 135 | |||
| 136 | /* SoundGraph iMON (IR only) -- sg_imon.inf */ | ||
| 137 | { USB_DEVICE(0x04e8, 0xff30) }, | ||
| 138 | |||
| 139 | /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */ | ||
| 140 | { USB_DEVICE(0x0aa8, 0xffda) }, | ||
| 141 | |||
| 142 | /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */ | ||
| 143 | { USB_DEVICE(0x15c2, 0xffda) }, | ||
| 144 | |||
| 145 | {} | ||
| 146 | }; | ||
| 147 | |||
| 148 | /* Some iMON VFD models requires a 6th packet for VFD writes */ | ||
| 149 | static struct usb_device_id vfd_proto_6p_list[] = { | ||
| 150 | { USB_DEVICE(0x15c2, 0xffda) }, | ||
| 151 | {} | ||
| 152 | }; | ||
| 153 | |||
| 154 | /* Some iMON devices have no lcd/vfd, don't set one up */ | ||
| 155 | static struct usb_device_id ir_only_list[] = { | ||
| 156 | { USB_DEVICE(0x0aa8, 0x8001) }, | ||
| 157 | { USB_DEVICE(0x04e8, 0xff30) }, | ||
| 158 | {} | ||
| 159 | }; | ||
| 160 | |||
| 161 | /* USB Device data */ | ||
| 162 | static struct usb_driver imon_driver = { | ||
| 163 | .name = MOD_NAME, | ||
| 164 | .probe = imon_probe, | ||
| 165 | .disconnect = imon_disconnect, | ||
| 166 | .suspend = imon_suspend, | ||
| 167 | .resume = imon_resume, | ||
| 168 | .id_table = imon_usb_id_table, | ||
| 169 | }; | ||
| 170 | |||
| 171 | static struct usb_class_driver imon_class = { | ||
| 172 | .name = DEVICE_NAME, | ||
| 173 | .fops = &display_fops, | ||
| 174 | .minor_base = DISPLAY_MINOR_BASE, | ||
| 175 | }; | ||
| 176 | |||
| 177 | /* to prevent races between open() and disconnect(), probing, etc */ | ||
| 178 | static DEFINE_MUTEX(driver_lock); | ||
| 179 | |||
| 180 | static int debug; | ||
| 181 | |||
| 182 | /*** M O D U L E C O D E ***/ | ||
| 183 | |||
| 184 | MODULE_AUTHOR(MOD_AUTHOR); | ||
| 185 | MODULE_DESCRIPTION(MOD_DESC); | ||
| 186 | MODULE_VERSION(MOD_VERSION); | ||
| 187 | MODULE_LICENSE("GPL"); | ||
| 188 | MODULE_DEVICE_TABLE(usb, imon_usb_id_table); | ||
| 189 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
| 190 | MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)"); | ||
| 191 | |||
| 192 | static void free_imon_context(struct imon_context *context) | ||
| 193 | { | ||
| 194 | struct device *dev = context->driver->dev; | ||
| 195 | usb_free_urb(context->tx_urb); | ||
| 196 | usb_free_urb(context->rx_urb); | ||
| 197 | lirc_buffer_free(context->driver->rbuf); | ||
| 198 | kfree(context->driver->rbuf); | ||
| 199 | kfree(context->driver); | ||
| 200 | kfree(context); | ||
| 201 | |||
| 202 | dev_dbg(dev, "%s: iMON context freed\n", __func__); | ||
| 203 | } | ||
| 204 | |||
| 205 | static void deregister_from_lirc(struct imon_context *context) | ||
| 206 | { | ||
| 207 | int retval; | ||
| 208 | int minor = context->driver->minor; | ||
| 209 | |||
| 210 | retval = lirc_unregister_driver(minor); | ||
| 211 | if (retval) | ||
| 212 | err("%s: unable to deregister from lirc(%d)", | ||
| 213 | __func__, retval); | ||
| 214 | else | ||
| 215 | printk(KERN_INFO MOD_NAME ": Deregistered iMON driver " | ||
| 216 | "(minor:%d)\n", minor); | ||
| 217 | |||
| 218 | } | ||
| 219 | |||
| 220 | /** | ||
| 221 | * Called when the Display device (e.g. /dev/lcd0) | ||
| 222 | * is opened by the application. | ||
| 223 | */ | ||
| 224 | static int display_open(struct inode *inode, struct file *file) | ||
| 225 | { | ||
| 226 | struct usb_interface *interface; | ||
| 227 | struct imon_context *context = NULL; | ||
| 228 | int subminor; | ||
| 229 | int retval = 0; | ||
| 230 | |||
| 231 | /* prevent races with disconnect */ | ||
| 232 | mutex_lock(&driver_lock); | ||
| 233 | |||
| 234 | subminor = iminor(inode); | ||
| 235 | interface = usb_find_interface(&imon_driver, subminor); | ||
| 236 | if (!interface) { | ||
| 237 | err("%s: could not find interface for minor %d", | ||
| 238 | __func__, subminor); | ||
| 239 | retval = -ENODEV; | ||
| 240 | goto exit; | ||
| 241 | } | ||
| 242 | context = usb_get_intfdata(interface); | ||
| 243 | |||
| 244 | if (!context) { | ||
| 245 | err("%s: no context found for minor %d", | ||
| 246 | __func__, subminor); | ||
| 247 | retval = -ENODEV; | ||
| 248 | goto exit; | ||
| 249 | } | ||
| 250 | |||
| 251 | mutex_lock(&context->ctx_lock); | ||
| 252 | |||
| 253 | if (!context->display) { | ||
| 254 | err("%s: display not supported by device", __func__); | ||
| 255 | retval = -ENODEV; | ||
| 256 | } else if (context->display_isopen) { | ||
| 257 | err("%s: display port is already open", __func__); | ||
| 258 | retval = -EBUSY; | ||
| 259 | } else { | ||
| 260 | context->display_isopen = 1; | ||
| 261 | file->private_data = context; | ||
| 262 | dev_info(context->driver->dev, "display port opened\n"); | ||
| 263 | } | ||
| 264 | |||
| 265 | mutex_unlock(&context->ctx_lock); | ||
| 266 | |||
| 267 | exit: | ||
| 268 | mutex_unlock(&driver_lock); | ||
| 269 | return retval; | ||
| 270 | } | ||
| 271 | |||
| 272 | /** | ||
| 273 | * Called when the display device (e.g. /dev/lcd0) | ||
| 274 | * is closed by the application. | ||
| 275 | */ | ||
| 276 | static int display_close(struct inode *inode, struct file *file) | ||
| 277 | { | ||
| 278 | struct imon_context *context = NULL; | ||
| 279 | int retval = 0; | ||
| 280 | |||
| 281 | context = file->private_data; | ||
| 282 | |||
| 283 | if (!context) { | ||
| 284 | err("%s: no context for device", __func__); | ||
| 285 | return -ENODEV; | ||
| 286 | } | ||
| 287 | |||
| 288 | mutex_lock(&context->ctx_lock); | ||
| 289 | |||
| 290 | if (!context->display) { | ||
| 291 | err("%s: display not supported by device", __func__); | ||
| 292 | retval = -ENODEV; | ||
| 293 | } else if (!context->display_isopen) { | ||
| 294 | err("%s: display is not open", __func__); | ||
| 295 | retval = -EIO; | ||
| 296 | } else { | ||
| 297 | context->display_isopen = 0; | ||
| 298 | dev_info(context->driver->dev, "display port closed\n"); | ||
| 299 | if (!context->dev_present && !context->ir_isopen) { | ||
| 300 | /* | ||
| 301 | * Device disconnected before close and IR port is not | ||
| 302 | * open. If IR port is open, context will be deleted by | ||
| 303 | * ir_close. | ||
| 304 | */ | ||
| 305 | mutex_unlock(&context->ctx_lock); | ||
| 306 | free_imon_context(context); | ||
| 307 | return retval; | ||
| 308 | } | ||
| 309 | } | ||
| 310 | |||
| 311 | mutex_unlock(&context->ctx_lock); | ||
| 312 | return retval; | ||
| 313 | } | ||
| 314 | |||
| 315 | /** | ||
| 316 | * Sends a packet to the device -- this function must be called | ||
| 317 | * with context->ctx_lock held. | ||
| 318 | */ | ||
| 319 | static int send_packet(struct imon_context *context) | ||
| 320 | { | ||
| 321 | unsigned int pipe; | ||
| 322 | int interval = 0; | ||
| 323 | int retval = 0; | ||
| 324 | |||
| 325 | /* Check if we need to use control or interrupt urb */ | ||
| 326 | pipe = usb_sndintpipe(context->usbdev, | ||
| 327 | context->tx_endpoint->bEndpointAddress); | ||
| 328 | interval = context->tx_endpoint->bInterval; | ||
| 329 | |||
| 330 | usb_fill_int_urb(context->tx_urb, context->usbdev, pipe, | ||
| 331 | context->usb_tx_buf, | ||
| 332 | sizeof(context->usb_tx_buf), | ||
| 333 | usb_tx_callback, context, interval); | ||
| 334 | |||
| 335 | context->tx_urb->actual_length = 0; | ||
| 336 | |||
| 337 | init_completion(&context->tx.finished); | ||
| 338 | atomic_set(&(context->tx.busy), 1); | ||
| 339 | |||
| 340 | retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); | ||
| 341 | if (retval) { | ||
| 342 | atomic_set(&(context->tx.busy), 0); | ||
| 343 | err("%s: error submitting urb(%d)", __func__, retval); | ||
| 344 | } else { | ||
| 345 | /* Wait for transmission to complete (or abort) */ | ||
| 346 | mutex_unlock(&context->ctx_lock); | ||
| 347 | retval = wait_for_completion_interruptible( | ||
| 348 | &context->tx.finished); | ||
| 349 | if (retval) | ||
| 350 | err("%s: task interrupted", __func__); | ||
| 351 | mutex_lock(&context->ctx_lock); | ||
| 352 | |||
| 353 | retval = context->tx.status; | ||
| 354 | if (retval) | ||
| 355 | err("%s: packet tx failed (%d)", __func__, retval); | ||
| 356 | } | ||
| 357 | |||
| 358 | return retval; | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * Writes data to the VFD. The iMON VFD is 2x16 characters | ||
| 363 | * and requires data in 5 consecutive USB interrupt packets, | ||
| 364 | * each packet but the last carrying 7 bytes. | ||
| 365 | * | ||
| 366 | * I don't know if the VFD board supports features such as | ||
| 367 | * scrolling, clearing rows, blanking, etc. so at | ||
| 368 | * the caller must provide a full screen of data. If fewer | ||
| 369 | * than 32 bytes are provided spaces will be appended to | ||
| 370 | * generate a full screen. | ||
| 371 | */ | ||
| 372 | static ssize_t vfd_write(struct file *file, const char *buf, | ||
| 373 | size_t n_bytes, loff_t *pos) | ||
| 374 | { | ||
| 375 | int i; | ||
| 376 | int offset; | ||
| 377 | int seq; | ||
| 378 | int retval = 0; | ||
| 379 | struct imon_context *context; | ||
| 380 | const unsigned char vfd_packet6[] = { | ||
| 381 | 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; | ||
| 382 | int *data_buf = NULL; | ||
| 383 | |||
| 384 | context = file->private_data; | ||
| 385 | if (!context) { | ||
| 386 | err("%s: no context for device", __func__); | ||
| 387 | return -ENODEV; | ||
| 388 | } | ||
| 389 | |||
| 390 | mutex_lock(&context->ctx_lock); | ||
| 391 | |||
| 392 | if (!context->dev_present) { | ||
| 393 | err("%s: no iMON device present", __func__); | ||
| 394 | retval = -ENODEV; | ||
| 395 | goto exit; | ||
| 396 | } | ||
| 397 | |||
| 398 | if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) { | ||
| 399 | err("%s: invalid payload size", __func__); | ||
| 400 | retval = -EINVAL; | ||
| 401 | goto exit; | ||
| 402 | } | ||
| 403 | |||
| 404 | data_buf = memdup_user(buf, n_bytes); | ||
| 405 | if (IS_ERR(data_buf)) { | ||
| 406 | retval = PTR_ERR(data_buf); | ||
| 407 | goto exit; | ||
| 408 | } | ||
| 409 | |||
| 410 | memcpy(context->tx.data_buf, data_buf, n_bytes); | ||
| 411 | |||
| 412 | /* Pad with spaces */ | ||
| 413 | for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i) | ||
| 414 | context->tx.data_buf[i] = ' '; | ||
| 415 | |||
| 416 | for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i) | ||
| 417 | context->tx.data_buf[i] = 0xFF; | ||
| 418 | |||
| 419 | offset = 0; | ||
| 420 | seq = 0; | ||
| 421 | |||
| 422 | do { | ||
| 423 | memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7); | ||
| 424 | context->usb_tx_buf[7] = (unsigned char) seq; | ||
| 425 | |||
| 426 | retval = send_packet(context); | ||
| 427 | if (retval) { | ||
| 428 | err("%s: send packet failed for packet #%d", | ||
| 429 | __func__, seq/2); | ||
| 430 | goto exit; | ||
| 431 | } else { | ||
| 432 | seq += 2; | ||
| 433 | offset += 7; | ||
| 434 | } | ||
| 435 | |||
| 436 | } while (offset < IMON_DATA_BUF_SZ); | ||
| 437 | |||
| 438 | if (context->vfd_proto_6p) { | ||
| 439 | /* Send packet #6 */ | ||
| 440 | memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6)); | ||
| 441 | context->usb_tx_buf[7] = (unsigned char) seq; | ||
| 442 | retval = send_packet(context); | ||
| 443 | if (retval) | ||
| 444 | err("%s: send packet failed for packet #%d", | ||
| 445 | __func__, seq/2); | ||
| 446 | } | ||
| 447 | |||
| 448 | exit: | ||
| 449 | mutex_unlock(&context->ctx_lock); | ||
| 450 | kfree(data_buf); | ||
| 451 | |||
| 452 | return (!retval) ? n_bytes : retval; | ||
| 453 | } | ||
| 454 | |||
| 455 | /** | ||
| 456 | * Callback function for USB core API: transmit data | ||
| 457 | */ | ||
| 458 | static void usb_tx_callback(struct urb *urb) | ||
| 459 | { | ||
| 460 | struct imon_context *context; | ||
| 461 | |||
| 462 | if (!urb) | ||
| 463 | return; | ||
| 464 | context = (struct imon_context *)urb->context; | ||
| 465 | if (!context) | ||
| 466 | return; | ||
| 467 | |||
| 468 | context->tx.status = urb->status; | ||
| 469 | |||
| 470 | /* notify waiters that write has finished */ | ||
| 471 | atomic_set(&context->tx.busy, 0); | ||
| 472 | complete(&context->tx.finished); | ||
| 473 | |||
| 474 | return; | ||
| 475 | } | ||
| 476 | |||
| 477 | /** | ||
| 478 | * Called by lirc_dev when the application opens /dev/lirc | ||
| 479 | */ | ||
| 480 | static int ir_open(void *data) | ||
| 481 | { | ||
| 482 | int retval = 0; | ||
| 483 | struct imon_context *context; | ||
| 484 | |||
| 485 | /* prevent races with disconnect */ | ||
| 486 | mutex_lock(&driver_lock); | ||
| 487 | |||
| 488 | context = (struct imon_context *)data; | ||
| 489 | |||
| 490 | /* initial IR protocol decode variables */ | ||
| 491 | context->rx.count = 0; | ||
| 492 | context->rx.initial_space = 1; | ||
| 493 | context->rx.prev_bit = 0; | ||
| 494 | |||
| 495 | context->ir_isopen = 1; | ||
| 496 | dev_info(context->driver->dev, "IR port opened\n"); | ||
| 497 | |||
| 498 | mutex_unlock(&driver_lock); | ||
| 499 | return retval; | ||
| 500 | } | ||
| 501 | |||
| 502 | /** | ||
| 503 | * Called by lirc_dev when the application closes /dev/lirc | ||
| 504 | */ | ||
| 505 | static void ir_close(void *data) | ||
| 506 | { | ||
| 507 | struct imon_context *context; | ||
| 508 | |||
| 509 | context = (struct imon_context *)data; | ||
| 510 | if (!context) { | ||
| 511 | err("%s: no context for device", __func__); | ||
| 512 | return; | ||
| 513 | } | ||
| 514 | |||
| 515 | mutex_lock(&context->ctx_lock); | ||
| 516 | |||
| 517 | context->ir_isopen = 0; | ||
| 518 | dev_info(context->driver->dev, "IR port closed\n"); | ||
| 519 | |||
| 520 | if (!context->dev_present) { | ||
| 521 | /* | ||
| 522 | * Device disconnected while IR port was still open. Driver | ||
| 523 | * was not deregistered at disconnect time, so do it now. | ||
| 524 | */ | ||
| 525 | deregister_from_lirc(context); | ||
| 526 | |||
| 527 | if (!context->display_isopen) { | ||
| 528 | mutex_unlock(&context->ctx_lock); | ||
| 529 | free_imon_context(context); | ||
| 530 | return; | ||
| 531 | } | ||
| 532 | /* | ||
| 533 | * If display port is open, context will be deleted by | ||
| 534 | * display_close | ||
| 535 | */ | ||
| 536 | } | ||
| 537 | |||
| 538 | mutex_unlock(&context->ctx_lock); | ||
| 539 | return; | ||
| 540 | } | ||
| 541 | |||
| 542 | /** | ||
| 543 | * Convert bit count to time duration (in us) and submit | ||
| 544 | * the value to lirc_dev. | ||
| 545 | */ | ||
| 546 | static void submit_data(struct imon_context *context) | ||
| 547 | { | ||
| 548 | unsigned char buf[4]; | ||
| 549 | int value = context->rx.count; | ||
| 550 | int i; | ||
| 551 | |||
| 552 | dev_dbg(context->driver->dev, "submitting data to LIRC\n"); | ||
| 553 | |||
| 554 | value *= BIT_DURATION; | ||
| 555 | value &= PULSE_MASK; | ||
| 556 | if (context->rx.prev_bit) | ||
| 557 | value |= PULSE_BIT; | ||
| 558 | |||
| 559 | for (i = 0; i < 4; ++i) | ||
| 560 | buf[i] = value>>(i*8); | ||
| 561 | |||
| 562 | lirc_buffer_write(context->driver->rbuf, buf); | ||
| 563 | wake_up(&context->driver->rbuf->wait_poll); | ||
| 564 | return; | ||
| 565 | } | ||
| 566 | |||
| 567 | static inline int tv2int(const struct timeval *a, const struct timeval *b) | ||
| 568 | { | ||
| 569 | int usecs = 0; | ||
| 570 | int sec = 0; | ||
| 571 | |||
| 572 | if (b->tv_usec > a->tv_usec) { | ||
| 573 | usecs = 1000000; | ||
| 574 | sec--; | ||
| 575 | } | ||
| 576 | |||
| 577 | usecs += a->tv_usec - b->tv_usec; | ||
| 578 | |||
| 579 | sec += a->tv_sec - b->tv_sec; | ||
| 580 | sec *= 1000; | ||
| 581 | usecs /= 1000; | ||
| 582 | sec += usecs; | ||
| 583 | |||
| 584 | if (sec < 0) | ||
| 585 | sec = 1000; | ||
| 586 | |||
| 587 | return sec; | ||
| 588 | } | ||
| 589 | |||
| 590 | /** | ||
| 591 | * Process the incoming packet | ||
| 592 | */ | ||
| 593 | static void imon_incoming_packet(struct imon_context *context, | ||
| 594 | struct urb *urb, int intf) | ||
| 595 | { | ||
| 596 | int len = urb->actual_length; | ||
| 597 | unsigned char *buf = urb->transfer_buffer; | ||
| 598 | struct device *dev = context->driver->dev; | ||
| 599 | int octet, bit; | ||
| 600 | unsigned char mask; | ||
| 601 | int i; | ||
| 602 | |||
| 603 | /* | ||
| 604 | * just bail out if no listening IR client | ||
| 605 | */ | ||
| 606 | if (!context->ir_isopen) | ||
| 607 | return; | ||
| 608 | |||
| 609 | if (len != 8) { | ||
| 610 | dev_warn(dev, "imon %s: invalid incoming packet " | ||
| 611 | "size (len = %d, intf%d)\n", __func__, len, intf); | ||
| 612 | return; | ||
| 613 | } | ||
| 614 | |||
| 615 | if (debug) { | ||
| 616 | printk(KERN_INFO "raw packet: "); | ||
| 617 | for (i = 0; i < len; ++i) | ||
| 618 | printk("%02x ", buf[i]); | ||
| 619 | printk("\n"); | ||
| 620 | } | ||
| 621 | |||
| 622 | /* | ||
| 623 | * Translate received data to pulse and space lengths. | ||
| 624 | * Received data is active low, i.e. pulses are 0 and | ||
| 625 | * spaces are 1. | ||
| 626 | * | ||
| 627 | * My original algorithm was essentially similar to | ||
| 628 | * Changwoo Ryu's with the exception that he switched | ||
| 629 | * the incoming bits to active high and also fed an | ||
| 630 | * initial space to LIRC at the start of a new sequence | ||
| 631 | * if the previous bit was a pulse. | ||
| 632 | * | ||
| 633 | * I've decided to adopt his algorithm. | ||
| 634 | */ | ||
| 635 | |||
| 636 | if (buf[7] == 1 && context->rx.initial_space) { | ||
| 637 | /* LIRC requires a leading space */ | ||
| 638 | context->rx.prev_bit = 0; | ||
| 639 | context->rx.count = 4; | ||
| 640 | submit_data(context); | ||
| 641 | context->rx.count = 0; | ||
| 642 | } | ||
| 643 | |||
| 644 | for (octet = 0; octet < 5; ++octet) { | ||
| 645 | mask = 0x80; | ||
| 646 | for (bit = 0; bit < 8; ++bit) { | ||
| 647 | int curr_bit = !(buf[octet] & mask); | ||
| 648 | if (curr_bit != context->rx.prev_bit) { | ||
| 649 | if (context->rx.count) { | ||
| 650 | submit_data(context); | ||
| 651 | context->rx.count = 0; | ||
| 652 | } | ||
| 653 | context->rx.prev_bit = curr_bit; | ||
| 654 | } | ||
| 655 | ++context->rx.count; | ||
| 656 | mask >>= 1; | ||
| 657 | } | ||
| 658 | } | ||
| 659 | |||
| 660 | if (buf[7] == 10) { | ||
| 661 | if (context->rx.count) { | ||
| 662 | submit_data(context); | ||
| 663 | context->rx.count = 0; | ||
| 664 | } | ||
| 665 | context->rx.initial_space = context->rx.prev_bit; | ||
| 666 | } | ||
| 667 | } | ||
| 668 | |||
| 669 | /** | ||
| 670 | * Callback function for USB core API: receive data | ||
| 671 | */ | ||
| 672 | static void usb_rx_callback(struct urb *urb) | ||
| 673 | { | ||
| 674 | struct imon_context *context; | ||
| 675 | int intfnum = 0; | ||
| 676 | |||
| 677 | if (!urb) | ||
| 678 | return; | ||
| 679 | |||
| 680 | context = (struct imon_context *)urb->context; | ||
| 681 | if (!context) | ||
| 682 | return; | ||
| 683 | |||
| 684 | switch (urb->status) { | ||
| 685 | case -ENOENT: /* usbcore unlink successful! */ | ||
| 686 | return; | ||
| 687 | |||
| 688 | case 0: | ||
| 689 | imon_incoming_packet(context, urb, intfnum); | ||
| 690 | break; | ||
| 691 | |||
| 692 | default: | ||
| 693 | dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n", | ||
| 694 | __func__, urb->status); | ||
| 695 | break; | ||
| 696 | } | ||
| 697 | |||
| 698 | usb_submit_urb(context->rx_urb, GFP_ATOMIC); | ||
| 699 | |||
| 700 | return; | ||
| 701 | } | ||
| 702 | |||
| 703 | /** | ||
| 704 | * Callback function for USB core API: Probe | ||
| 705 | */ | ||
| 706 | static int imon_probe(struct usb_interface *interface, | ||
| 707 | const struct usb_device_id *id) | ||
| 708 | { | ||
| 709 | struct usb_device *usbdev = NULL; | ||
| 710 | struct usb_host_interface *iface_desc = NULL; | ||
| 711 | struct usb_endpoint_descriptor *rx_endpoint = NULL; | ||
| 712 | struct usb_endpoint_descriptor *tx_endpoint = NULL; | ||
| 713 | struct urb *rx_urb = NULL; | ||
| 714 | struct urb *tx_urb = NULL; | ||
| 715 | struct lirc_driver *driver = NULL; | ||
| 716 | struct lirc_buffer *rbuf = NULL; | ||
| 717 | struct device *dev = &interface->dev; | ||
| 718 | int ifnum; | ||
| 719 | int lirc_minor = 0; | ||
| 720 | int num_endpts; | ||
| 721 | int retval = 0; | ||
| 722 | int display_ep_found = 0; | ||
| 723 | int ir_ep_found = 0; | ||
| 724 | int alloc_status = 0; | ||
| 725 | int vfd_proto_6p = 0; | ||
| 726 | struct imon_context *context = NULL; | ||
| 727 | int i; | ||
| 728 | u16 vendor, product; | ||
| 729 | |||
| 730 | context = kzalloc(sizeof(struct imon_context), GFP_KERNEL); | ||
| 731 | if (!context) { | ||
| 732 | err("%s: kzalloc failed for context", __func__); | ||
| 733 | alloc_status = 1; | ||
| 734 | goto alloc_status_switch; | ||
| 735 | } | ||
| 736 | |||
| 737 | /* | ||
| 738 | * Try to auto-detect the type of display if the user hasn't set | ||
| 739 | * it by hand via the display_type modparam. Default is VFD. | ||
| 740 | */ | ||
| 741 | if (usb_match_id(interface, ir_only_list)) | ||
| 742 | context->display = 0; | ||
| 743 | else | ||
| 744 | context->display = 1; | ||
| 745 | |||
| 746 | usbdev = usb_get_dev(interface_to_usbdev(interface)); | ||
| 747 | iface_desc = interface->cur_altsetting; | ||
| 748 | num_endpts = iface_desc->desc.bNumEndpoints; | ||
| 749 | ifnum = iface_desc->desc.bInterfaceNumber; | ||
| 750 | vendor = le16_to_cpu(usbdev->descriptor.idVendor); | ||
| 751 | product = le16_to_cpu(usbdev->descriptor.idProduct); | ||
| 752 | |||
| 753 | dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n", | ||
| 754 | __func__, vendor, product, ifnum); | ||
| 755 | |||
| 756 | /* prevent races probing devices w/multiple interfaces */ | ||
| 757 | mutex_lock(&driver_lock); | ||
| 758 | |||
| 759 | /* | ||
| 760 | * Scan the endpoint list and set: | ||
| 761 | * first input endpoint = IR endpoint | ||
| 762 | * first output endpoint = display endpoint | ||
| 763 | */ | ||
| 764 | for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { | ||
| 765 | struct usb_endpoint_descriptor *ep; | ||
| 766 | int ep_dir; | ||
| 767 | int ep_type; | ||
| 768 | ep = &iface_desc->endpoint[i].desc; | ||
| 769 | ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; | ||
| 770 | ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; | ||
| 771 | |||
| 772 | if (!ir_ep_found && | ||
| 773 | ep_dir == USB_DIR_IN && | ||
| 774 | ep_type == USB_ENDPOINT_XFER_INT) { | ||
| 775 | |||
| 776 | rx_endpoint = ep; | ||
| 777 | ir_ep_found = 1; | ||
| 778 | dev_dbg(dev, "%s: found IR endpoint\n", __func__); | ||
| 779 | |||
| 780 | } else if (!display_ep_found && ep_dir == USB_DIR_OUT && | ||
| 781 | ep_type == USB_ENDPOINT_XFER_INT) { | ||
| 782 | tx_endpoint = ep; | ||
| 783 | display_ep_found = 1; | ||
| 784 | dev_dbg(dev, "%s: found display endpoint\n", __func__); | ||
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 788 | /* | ||
| 789 | * Some iMON receivers have no display. Unfortunately, it seems | ||
| 790 | * that SoundGraph recycles device IDs between devices both with | ||
| 791 | * and without... :\ | ||
| 792 | */ | ||
| 793 | if (context->display == 0) { | ||
| 794 | display_ep_found = 0; | ||
| 795 | dev_dbg(dev, "%s: device has no display\n", __func__); | ||
| 796 | } | ||
| 797 | |||
| 798 | /* Input endpoint is mandatory */ | ||
| 799 | if (!ir_ep_found) { | ||
| 800 | err("%s: no valid input (IR) endpoint found.", __func__); | ||
| 801 | retval = -ENODEV; | ||
| 802 | alloc_status = 2; | ||
| 803 | goto alloc_status_switch; | ||
| 804 | } | ||
| 805 | |||
| 806 | /* Determine if display requires 6 packets */ | ||
| 807 | if (display_ep_found) { | ||
| 808 | if (usb_match_id(interface, vfd_proto_6p_list)) | ||
| 809 | vfd_proto_6p = 1; | ||
| 810 | |||
| 811 | dev_dbg(dev, "%s: vfd_proto_6p: %d\n", | ||
| 812 | __func__, vfd_proto_6p); | ||
| 813 | } | ||
| 814 | |||
| 815 | driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); | ||
| 816 | if (!driver) { | ||
| 817 | err("%s: kzalloc failed for lirc_driver", __func__); | ||
| 818 | alloc_status = 2; | ||
| 819 | goto alloc_status_switch; | ||
| 820 | } | ||
| 821 | rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); | ||
| 822 | if (!rbuf) { | ||
| 823 | err("%s: kmalloc failed for lirc_buffer", __func__); | ||
| 824 | alloc_status = 3; | ||
| 825 | goto alloc_status_switch; | ||
| 826 | } | ||
| 827 | if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { | ||
| 828 | err("%s: lirc_buffer_init failed", __func__); | ||
| 829 | alloc_status = 4; | ||
| 830 | goto alloc_status_switch; | ||
| 831 | } | ||
| 832 | rx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 833 | if (!rx_urb) { | ||
| 834 | err("%s: usb_alloc_urb failed for IR urb", __func__); | ||
| 835 | alloc_status = 5; | ||
| 836 | goto alloc_status_switch; | ||
| 837 | } | ||
| 838 | tx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 839 | if (!tx_urb) { | ||
| 840 | err("%s: usb_alloc_urb failed for display urb", | ||
| 841 | __func__); | ||
| 842 | alloc_status = 6; | ||
| 843 | goto alloc_status_switch; | ||
| 844 | } | ||
| 845 | |||
| 846 | mutex_init(&context->ctx_lock); | ||
| 847 | context->vfd_proto_6p = vfd_proto_6p; | ||
| 848 | |||
| 849 | strcpy(driver->name, MOD_NAME); | ||
| 850 | driver->minor = -1; | ||
| 851 | driver->code_length = BUF_CHUNK_SIZE * 8; | ||
| 852 | driver->sample_rate = 0; | ||
| 853 | driver->features = LIRC_CAN_REC_MODE2; | ||
| 854 | driver->data = context; | ||
| 855 | driver->rbuf = rbuf; | ||
| 856 | driver->set_use_inc = ir_open; | ||
| 857 | driver->set_use_dec = ir_close; | ||
| 858 | driver->dev = &interface->dev; | ||
| 859 | driver->owner = THIS_MODULE; | ||
| 860 | |||
| 861 | mutex_lock(&context->ctx_lock); | ||
| 862 | |||
| 863 | context->driver = driver; | ||
| 864 | /* start out in keyboard mode */ | ||
| 865 | |||
| 866 | lirc_minor = lirc_register_driver(driver); | ||
| 867 | if (lirc_minor < 0) { | ||
| 868 | err("%s: lirc_register_driver failed", __func__); | ||
| 869 | alloc_status = 7; | ||
| 870 | goto unlock; | ||
| 871 | } else | ||
| 872 | dev_info(dev, "Registered iMON driver " | ||
| 873 | "(lirc minor: %d)\n", lirc_minor); | ||
| 874 | |||
| 875 | /* Needed while unregistering! */ | ||
| 876 | driver->minor = lirc_minor; | ||
| 877 | |||
| 878 | context->usbdev = usbdev; | ||
| 879 | context->dev_present = 1; | ||
| 880 | context->rx_endpoint = rx_endpoint; | ||
| 881 | context->rx_urb = rx_urb; | ||
| 882 | |||
| 883 | /* | ||
| 884 | * tx is used to send characters to lcd/vfd, associate RF | ||
| 885 | * remotes, set IR protocol, and maybe more... | ||
| 886 | */ | ||
| 887 | context->tx_endpoint = tx_endpoint; | ||
| 888 | context->tx_urb = tx_urb; | ||
| 889 | |||
| 890 | if (display_ep_found) | ||
| 891 | context->display = 1; | ||
| 892 | |||
| 893 | usb_fill_int_urb(context->rx_urb, context->usbdev, | ||
| 894 | usb_rcvintpipe(context->usbdev, | ||
| 895 | context->rx_endpoint->bEndpointAddress), | ||
| 896 | context->usb_rx_buf, sizeof(context->usb_rx_buf), | ||
| 897 | usb_rx_callback, context, | ||
| 898 | context->rx_endpoint->bInterval); | ||
| 899 | |||
| 900 | retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); | ||
| 901 | |||
| 902 | if (retval) { | ||
| 903 | err("%s: usb_submit_urb failed for intf0 (%d)", | ||
| 904 | __func__, retval); | ||
| 905 | mutex_unlock(&context->ctx_lock); | ||
| 906 | goto exit; | ||
| 907 | } | ||
| 908 | |||
| 909 | usb_set_intfdata(interface, context); | ||
| 910 | |||
| 911 | if (context->display && ifnum == 0) { | ||
| 912 | dev_dbg(dev, "%s: Registering iMON display with sysfs\n", | ||
| 913 | __func__); | ||
| 914 | |||
| 915 | if (usb_register_dev(interface, &imon_class)) { | ||
| 916 | /* Not a fatal error, so ignore */ | ||
| 917 | dev_info(dev, "%s: could not get a minor number for " | ||
| 918 | "display\n", __func__); | ||
| 919 | } | ||
| 920 | } | ||
| 921 | |||
| 922 | dev_info(dev, "iMON device (%04x:%04x, intf%d) on " | ||
| 923 | "usb<%d:%d> initialized\n", vendor, product, ifnum, | ||
| 924 | usbdev->bus->busnum, usbdev->devnum); | ||
| 925 | |||
| 926 | unlock: | ||
| 927 | mutex_unlock(&context->ctx_lock); | ||
| 928 | alloc_status_switch: | ||
| 929 | |||
| 930 | switch (alloc_status) { | ||
| 931 | case 7: | ||
| 932 | usb_free_urb(tx_urb); | ||
| 933 | case 6: | ||
| 934 | usb_free_urb(rx_urb); | ||
| 935 | case 5: | ||
| 936 | if (rbuf) | ||
| 937 | lirc_buffer_free(rbuf); | ||
| 938 | case 4: | ||
| 939 | kfree(rbuf); | ||
| 940 | case 3: | ||
| 941 | kfree(driver); | ||
| 942 | case 2: | ||
| 943 | kfree(context); | ||
| 944 | context = NULL; | ||
| 945 | case 1: | ||
| 946 | if (retval != -ENODEV) | ||
| 947 | retval = -ENOMEM; | ||
| 948 | break; | ||
| 949 | case 0: | ||
| 950 | retval = 0; | ||
| 951 | } | ||
| 952 | |||
| 953 | exit: | ||
| 954 | mutex_unlock(&driver_lock); | ||
| 955 | |||
| 956 | return retval; | ||
| 957 | } | ||
| 958 | |||
| 959 | /** | ||
| 960 | * Callback function for USB core API: disconnect | ||
| 961 | */ | ||
| 962 | static void imon_disconnect(struct usb_interface *interface) | ||
| 963 | { | ||
| 964 | struct imon_context *context; | ||
| 965 | int ifnum; | ||
| 966 | |||
| 967 | /* prevent races with ir_open()/display_open() */ | ||
| 968 | mutex_lock(&driver_lock); | ||
| 969 | |||
| 970 | context = usb_get_intfdata(interface); | ||
| 971 | ifnum = interface->cur_altsetting->desc.bInterfaceNumber; | ||
| 972 | |||
| 973 | mutex_lock(&context->ctx_lock); | ||
| 974 | |||
| 975 | usb_set_intfdata(interface, NULL); | ||
| 976 | |||
| 977 | /* Abort ongoing write */ | ||
| 978 | if (atomic_read(&context->tx.busy)) { | ||
| 979 | usb_kill_urb(context->tx_urb); | ||
| 980 | complete_all(&context->tx.finished); | ||
| 981 | } | ||
| 982 | |||
| 983 | context->dev_present = 0; | ||
| 984 | usb_kill_urb(context->rx_urb); | ||
| 985 | if (context->display) | ||
| 986 | usb_deregister_dev(interface, &imon_class); | ||
| 987 | |||
| 988 | if (!context->ir_isopen && !context->dev_present) { | ||
| 989 | deregister_from_lirc(context); | ||
| 990 | mutex_unlock(&context->ctx_lock); | ||
| 991 | if (!context->display_isopen) | ||
| 992 | free_imon_context(context); | ||
| 993 | } else | ||
| 994 | mutex_unlock(&context->ctx_lock); | ||
| 995 | |||
| 996 | mutex_unlock(&driver_lock); | ||
| 997 | |||
| 998 | printk(KERN_INFO "%s: iMON device (intf%d) disconnected\n", | ||
| 999 | __func__, ifnum); | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | static int imon_suspend(struct usb_interface *intf, pm_message_t message) | ||
| 1003 | { | ||
| 1004 | struct imon_context *context = usb_get_intfdata(intf); | ||
| 1005 | |||
| 1006 | usb_kill_urb(context->rx_urb); | ||
| 1007 | |||
| 1008 | return 0; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | static int imon_resume(struct usb_interface *intf) | ||
| 1012 | { | ||
| 1013 | int rc = 0; | ||
| 1014 | struct imon_context *context = usb_get_intfdata(intf); | ||
| 1015 | |||
| 1016 | usb_fill_int_urb(context->rx_urb, context->usbdev, | ||
| 1017 | usb_rcvintpipe(context->usbdev, | ||
| 1018 | context->rx_endpoint->bEndpointAddress), | ||
| 1019 | context->usb_rx_buf, sizeof(context->usb_rx_buf), | ||
| 1020 | usb_rx_callback, context, | ||
| 1021 | context->rx_endpoint->bInterval); | ||
| 1022 | |||
| 1023 | rc = usb_submit_urb(context->rx_urb, GFP_ATOMIC); | ||
| 1024 | |||
| 1025 | return rc; | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | static int __init imon_init(void) | ||
| 1029 | { | ||
| 1030 | int rc; | ||
| 1031 | |||
| 1032 | printk(KERN_INFO MOD_NAME ": " MOD_DESC ", v" MOD_VERSION "\n"); | ||
| 1033 | |||
| 1034 | rc = usb_register(&imon_driver); | ||
| 1035 | if (rc) { | ||
| 1036 | err("%s: usb register failed(%d)", __func__, rc); | ||
| 1037 | return -ENODEV; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | return 0; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | static void __exit imon_exit(void) | ||
| 1044 | { | ||
| 1045 | usb_deregister(&imon_driver); | ||
| 1046 | printk(KERN_INFO MOD_NAME ": module removed. Goodbye!\n"); | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | module_init(imon_init); | ||
| 1050 | module_exit(imon_exit); | ||
diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c new file mode 100644 index 00000000000..792aac0a8e7 --- /dev/null +++ b/drivers/staging/lirc/lirc_parallel.c | |||
| @@ -0,0 +1,755 @@ | |||
| 1 | /* | ||
| 2 | * lirc_parallel.c | ||
| 3 | * | ||
| 4 | * lirc_parallel - device driver for infra-red signal receiving and | ||
| 5 | * transmitting unit built by the author | ||
| 6 | * | ||
| 7 | * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | * | ||
| 23 | */ | ||
| 24 | |||
| 25 | /*** Includes ***/ | ||
| 26 | |||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/sched.h> | ||
| 29 | #include <linux/errno.h> | ||
| 30 | #include <linux/signal.h> | ||
| 31 | #include <linux/fs.h> | ||
| 32 | #include <linux/kernel.h> | ||
| 33 | #include <linux/ioport.h> | ||
| 34 | #include <linux/time.h> | ||
| 35 | #include <linux/mm.h> | ||
| 36 | #include <linux/delay.h> | ||
| 37 | |||
| 38 | #include <linux/io.h> | ||
| 39 | #include <linux/irq.h> | ||
| 40 | #include <linux/uaccess.h> | ||
| 41 | #include <asm/div64.h> | ||
| 42 | |||
| 43 | #include <linux/poll.h> | ||
| 44 | #include <linux/parport.h> | ||
| 45 | #include <linux/platform_device.h> | ||
| 46 | |||
| 47 | #include <media/lirc.h> | ||
| 48 | #include <media/lirc_dev.h> | ||
| 49 | |||
| 50 | #include "lirc_parallel.h" | ||
| 51 | |||
| 52 | #define LIRC_DRIVER_NAME "lirc_parallel" | ||
| 53 | |||
| 54 | #ifndef LIRC_IRQ | ||
| 55 | #define LIRC_IRQ 7 | ||
| 56 | #endif | ||
| 57 | #ifndef LIRC_PORT | ||
| 58 | #define LIRC_PORT 0x378 | ||
| 59 | #endif | ||
| 60 | #ifndef LIRC_TIMER | ||
| 61 | #define LIRC_TIMER 65536 | ||
| 62 | #endif | ||
| 63 | |||
| 64 | /*** Global Variables ***/ | ||
| 65 | |||
| 66 | static int debug; | ||
| 67 | static int check_pselecd; | ||
| 68 | |||
| 69 | unsigned int irq = LIRC_IRQ; | ||
| 70 | unsigned int io = LIRC_PORT; | ||
| 71 | #ifdef LIRC_TIMER | ||
| 72 | unsigned int timer; | ||
| 73 | unsigned int default_timer = LIRC_TIMER; | ||
| 74 | #endif | ||
| 75 | |||
| 76 | #define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */ | ||
| 77 | |||
| 78 | static int rbuf[RBUF_SIZE]; | ||
| 79 | |||
| 80 | DECLARE_WAIT_QUEUE_HEAD(lirc_wait); | ||
| 81 | |||
| 82 | unsigned int rptr; | ||
| 83 | unsigned int wptr; | ||
| 84 | unsigned int lost_irqs; | ||
| 85 | int is_open; | ||
| 86 | |||
| 87 | struct parport *pport; | ||
| 88 | struct pardevice *ppdevice; | ||
| 89 | int is_claimed; | ||
| 90 | |||
| 91 | unsigned int tx_mask = 1; | ||
| 92 | |||
| 93 | /*** Internal Functions ***/ | ||
| 94 | |||
| 95 | static unsigned int in(int offset) | ||
| 96 | { | ||
| 97 | switch (offset) { | ||
| 98 | case LIRC_LP_BASE: | ||
| 99 | return parport_read_data(pport); | ||
| 100 | case LIRC_LP_STATUS: | ||
| 101 | return parport_read_status(pport); | ||
| 102 | case LIRC_LP_CONTROL: | ||
| 103 | return parport_read_control(pport); | ||
| 104 | } | ||
| 105 | return 0; /* make compiler happy */ | ||
| 106 | } | ||
| 107 | |||
| 108 | static void out(int offset, int value) | ||
| 109 | { | ||
| 110 | switch (offset) { | ||
| 111 | case LIRC_LP_BASE: | ||
| 112 | parport_write_data(pport, value); | ||
| 113 | break; | ||
| 114 | case LIRC_LP_CONTROL: | ||
| 115 | parport_write_control(pport, value); | ||
| 116 | break; | ||
| 117 | case LIRC_LP_STATUS: | ||
| 118 | printk(KERN_INFO "%s: attempt to write to status register\n", | ||
| 119 | LIRC_DRIVER_NAME); | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | static unsigned int lirc_get_timer(void) | ||
| 125 | { | ||
| 126 | return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT; | ||
| 127 | } | ||
| 128 | |||
| 129 | static unsigned int lirc_get_signal(void) | ||
| 130 | { | ||
| 131 | return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT; | ||
| 132 | } | ||
| 133 | |||
| 134 | static void lirc_on(void) | ||
| 135 | { | ||
| 136 | out(LIRC_PORT_DATA, tx_mask); | ||
| 137 | } | ||
| 138 | |||
| 139 | static void lirc_off(void) | ||
| 140 | { | ||
| 141 | out(LIRC_PORT_DATA, 0); | ||
| 142 | } | ||
| 143 | |||
| 144 | static unsigned int init_lirc_timer(void) | ||
| 145 | { | ||
| 146 | struct timeval tv, now; | ||
| 147 | unsigned int level, newlevel, timeelapsed, newtimer; | ||
| 148 | int count = 0; | ||
| 149 | |||
| 150 | do_gettimeofday(&tv); | ||
| 151 | tv.tv_sec++; /* wait max. 1 sec. */ | ||
| 152 | level = lirc_get_timer(); | ||
| 153 | do { | ||
| 154 | newlevel = lirc_get_timer(); | ||
| 155 | if (level == 0 && newlevel != 0) | ||
| 156 | count++; | ||
| 157 | level = newlevel; | ||
| 158 | do_gettimeofday(&now); | ||
| 159 | } while (count < 1000 && (now.tv_sec < tv.tv_sec | ||
| 160 | || (now.tv_sec == tv.tv_sec | ||
| 161 | && now.tv_usec < tv.tv_usec))); | ||
| 162 | |||
| 163 | timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000 | ||
| 164 | + (now.tv_usec - tv.tv_usec)); | ||
| 165 | if (count >= 1000 && timeelapsed > 0) { | ||
| 166 | if (default_timer == 0) { | ||
| 167 | /* autodetect timer */ | ||
| 168 | newtimer = (1000000*count)/timeelapsed; | ||
| 169 | printk(KERN_INFO "%s: %u Hz timer detected\n", | ||
| 170 | LIRC_DRIVER_NAME, newtimer); | ||
| 171 | return newtimer; | ||
| 172 | } else { | ||
| 173 | newtimer = (1000000*count)/timeelapsed; | ||
| 174 | if (abs(newtimer - default_timer) > default_timer/10) { | ||
| 175 | /* bad timer */ | ||
| 176 | printk(KERN_NOTICE "%s: bad timer: %u Hz\n", | ||
| 177 | LIRC_DRIVER_NAME, newtimer); | ||
| 178 | printk(KERN_NOTICE "%s: using default timer: " | ||
| 179 | "%u Hz\n", | ||
| 180 | LIRC_DRIVER_NAME, default_timer); | ||
| 181 | return default_timer; | ||
| 182 | } else { | ||
| 183 | printk(KERN_INFO "%s: %u Hz timer detected\n", | ||
| 184 | LIRC_DRIVER_NAME, newtimer); | ||
| 185 | return newtimer; /* use detected value */ | ||
| 186 | } | ||
| 187 | } | ||
| 188 | } else { | ||
| 189 | printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME); | ||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | static int lirc_claim(void) | ||
| 195 | { | ||
| 196 | if (parport_claim(ppdevice) != 0) { | ||
| 197 | printk(KERN_WARNING "%s: could not claim port\n", | ||
| 198 | LIRC_DRIVER_NAME); | ||
| 199 | printk(KERN_WARNING "%s: waiting for port becoming available" | ||
| 200 | "\n", LIRC_DRIVER_NAME); | ||
| 201 | if (parport_claim_or_block(ppdevice) < 0) { | ||
| 202 | printk(KERN_NOTICE "%s: could not claim port, giving" | ||
| 203 | " up\n", LIRC_DRIVER_NAME); | ||
| 204 | return 0; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); | ||
| 208 | is_claimed = 1; | ||
| 209 | return 1; | ||
| 210 | } | ||
| 211 | |||
| 212 | /*** interrupt handler ***/ | ||
| 213 | |||
| 214 | static void rbuf_write(int signal) | ||
| 215 | { | ||
| 216 | unsigned int nwptr; | ||
| 217 | |||
| 218 | nwptr = (wptr + 1) & (RBUF_SIZE - 1); | ||
| 219 | if (nwptr == rptr) { | ||
| 220 | /* no new signals will be accepted */ | ||
| 221 | lost_irqs++; | ||
| 222 | printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME); | ||
| 223 | return; | ||
| 224 | } | ||
| 225 | rbuf[wptr] = signal; | ||
| 226 | wptr = nwptr; | ||
| 227 | } | ||
| 228 | |||
| 229 | static void irq_handler(void *blah) | ||
| 230 | { | ||
| 231 | struct timeval tv; | ||
| 232 | static struct timeval lasttv; | ||
| 233 | static int init; | ||
| 234 | long signal; | ||
| 235 | int data; | ||
| 236 | unsigned int level, newlevel; | ||
| 237 | unsigned int timeout; | ||
| 238 | |||
| 239 | if (!is_open) | ||
| 240 | return; | ||
| 241 | |||
| 242 | if (!is_claimed) | ||
| 243 | return; | ||
| 244 | |||
| 245 | #if 0 | ||
| 246 | /* disable interrupt */ | ||
| 247 | disable_irq(irq); | ||
| 248 | out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN)); | ||
| 249 | #endif | ||
| 250 | if (check_pselecd && (in(1) & LP_PSELECD)) | ||
| 251 | return; | ||
| 252 | |||
| 253 | #ifdef LIRC_TIMER | ||
| 254 | if (init) { | ||
| 255 | do_gettimeofday(&tv); | ||
| 256 | |||
| 257 | signal = tv.tv_sec - lasttv.tv_sec; | ||
| 258 | if (signal > 15) | ||
| 259 | /* really long time */ | ||
| 260 | data = PULSE_MASK; | ||
| 261 | else | ||
| 262 | data = (int) (signal*1000000 + | ||
| 263 | tv.tv_usec - lasttv.tv_usec + | ||
| 264 | LIRC_SFH506_DELAY); | ||
| 265 | |||
| 266 | rbuf_write(data); /* space */ | ||
| 267 | } else { | ||
| 268 | if (timer == 0) { | ||
| 269 | /* | ||
| 270 | * wake up; we'll lose this signal, but it will be | ||
| 271 | * garbage if the device is turned on anyway | ||
| 272 | */ | ||
| 273 | timer = init_lirc_timer(); | ||
| 274 | /* enable_irq(irq); */ | ||
| 275 | return; | ||
| 276 | } | ||
| 277 | init = 1; | ||
| 278 | } | ||
| 279 | |||
| 280 | timeout = timer/10; /* timeout after 1/10 sec. */ | ||
| 281 | signal = 1; | ||
| 282 | level = lirc_get_timer(); | ||
| 283 | do { | ||
| 284 | newlevel = lirc_get_timer(); | ||
| 285 | if (level == 0 && newlevel != 0) | ||
| 286 | signal++; | ||
| 287 | level = newlevel; | ||
| 288 | |||
| 289 | /* giving up */ | ||
| 290 | if (signal > timeout | ||
| 291 | || (check_pselecd && (in(1) & LP_PSELECD))) { | ||
| 292 | signal = 0; | ||
| 293 | printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME); | ||
| 294 | break; | ||
| 295 | } | ||
| 296 | } while (lirc_get_signal()); | ||
| 297 | |||
| 298 | if (signal != 0) { | ||
| 299 | /* adjust value to usecs */ | ||
| 300 | __u64 helper; | ||
| 301 | |||
| 302 | helper = ((__u64) signal)*1000000; | ||
| 303 | do_div(helper, timer); | ||
| 304 | signal = (long) helper; | ||
| 305 | |||
| 306 | if (signal > LIRC_SFH506_DELAY) | ||
| 307 | data = signal - LIRC_SFH506_DELAY; | ||
| 308 | else | ||
| 309 | data = 1; | ||
| 310 | rbuf_write(PULSE_BIT|data); /* pulse */ | ||
| 311 | } | ||
| 312 | do_gettimeofday(&lasttv); | ||
| 313 | #else | ||
| 314 | /* add your code here */ | ||
| 315 | #endif | ||
| 316 | |||
| 317 | wake_up_interruptible(&lirc_wait); | ||
| 318 | |||
| 319 | /* enable interrupt */ | ||
| 320 | /* | ||
| 321 | enable_irq(irq); | ||
| 322 | out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN); | ||
| 323 | */ | ||
| 324 | } | ||
| 325 | |||
| 326 | /*** file operations ***/ | ||
| 327 | |||
| 328 | static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig) | ||
| 329 | { | ||
| 330 | return -ESPIPE; | ||
| 331 | } | ||
| 332 | |||
| 333 | static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos) | ||
| 334 | { | ||
| 335 | int result = 0; | ||
| 336 | int count = 0; | ||
| 337 | DECLARE_WAITQUEUE(wait, current); | ||
| 338 | |||
| 339 | if (n % sizeof(int)) | ||
| 340 | return -EINVAL; | ||
| 341 | |||
| 342 | add_wait_queue(&lirc_wait, &wait); | ||
| 343 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 344 | while (count < n) { | ||
| 345 | if (rptr != wptr) { | ||
| 346 | if (copy_to_user(buf+count, (char *) &rbuf[rptr], | ||
| 347 | sizeof(int))) { | ||
| 348 | result = -EFAULT; | ||
| 349 | break; | ||
| 350 | } | ||
| 351 | rptr = (rptr + 1) & (RBUF_SIZE - 1); | ||
| 352 | count += sizeof(int); | ||
| 353 | } else { | ||
| 354 | if (filep->f_flags & O_NONBLOCK) { | ||
| 355 | result = -EAGAIN; | ||
| 356 | break; | ||
| 357 | } | ||
| 358 | if (signal_pending(current)) { | ||
| 359 | result = -ERESTARTSYS; | ||
| 360 | break; | ||
| 361 | } | ||
| 362 | schedule(); | ||
| 363 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 364 | } | ||
| 365 | } | ||
| 366 | remove_wait_queue(&lirc_wait, &wait); | ||
| 367 | set_current_state(TASK_RUNNING); | ||
| 368 | return count ? count : result; | ||
| 369 | } | ||
| 370 | |||
| 371 | static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, | ||
| 372 | loff_t *ppos) | ||
| 373 | { | ||
| 374 | int count; | ||
| 375 | unsigned int i; | ||
| 376 | unsigned int level, newlevel; | ||
| 377 | unsigned long flags; | ||
| 378 | int counttimer; | ||
| 379 | int *wbuf; | ||
| 380 | ssize_t ret; | ||
| 381 | |||
| 382 | if (!is_claimed) | ||
| 383 | return -EBUSY; | ||
| 384 | |||
| 385 | count = n / sizeof(int); | ||
| 386 | |||
| 387 | if (n % sizeof(int) || count % 2 == 0) | ||
| 388 | return -EINVAL; | ||
| 389 | |||
| 390 | wbuf = memdup_user(buf, n); | ||
| 391 | if (IS_ERR(wbuf)) | ||
| 392 | return PTR_ERR(wbuf); | ||
| 393 | |||
| 394 | #ifdef LIRC_TIMER | ||
| 395 | if (timer == 0) { | ||
| 396 | /* try again if device is ready */ | ||
| 397 | timer = init_lirc_timer(); | ||
| 398 | if (timer == 0) { | ||
| 399 | ret = -EIO; | ||
| 400 | goto out; | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | /* adjust values from usecs */ | ||
| 405 | for (i = 0; i < count; i++) { | ||
| 406 | __u64 helper; | ||
| 407 | |||
| 408 | helper = ((__u64) wbuf[i])*timer; | ||
| 409 | do_div(helper, 1000000); | ||
| 410 | wbuf[i] = (int) helper; | ||
| 411 | } | ||
| 412 | |||
| 413 | local_irq_save(flags); | ||
| 414 | i = 0; | ||
| 415 | while (i < count) { | ||
| 416 | level = lirc_get_timer(); | ||
| 417 | counttimer = 0; | ||
| 418 | lirc_on(); | ||
| 419 | do { | ||
| 420 | newlevel = lirc_get_timer(); | ||
| 421 | if (level == 0 && newlevel != 0) | ||
| 422 | counttimer++; | ||
| 423 | level = newlevel; | ||
| 424 | if (check_pselecd && (in(1) & LP_PSELECD)) { | ||
| 425 | lirc_off(); | ||
| 426 | local_irq_restore(flags); | ||
| 427 | ret = -EIO; | ||
| 428 | goto out; | ||
| 429 | } | ||
| 430 | } while (counttimer < wbuf[i]); | ||
| 431 | i++; | ||
| 432 | |||
| 433 | lirc_off(); | ||
| 434 | if (i == count) | ||
| 435 | break; | ||
| 436 | counttimer = 0; | ||
| 437 | do { | ||
| 438 | newlevel = lirc_get_timer(); | ||
| 439 | if (level == 0 && newlevel != 0) | ||
| 440 | counttimer++; | ||
| 441 | level = newlevel; | ||
| 442 | if (check_pselecd && (in(1) & LP_PSELECD)) { | ||
| 443 | local_irq_restore(flags); | ||
| 444 | ret = -EIO; | ||
| 445 | goto out; | ||
| 446 | } | ||
| 447 | } while (counttimer < wbuf[i]); | ||
| 448 | i++; | ||
| 449 | } | ||
| 450 | local_irq_restore(flags); | ||
| 451 | #else | ||
| 452 | /* place code that handles write without external timer here */ | ||
| 453 | #endif | ||
| 454 | ret = n; | ||
| 455 | out: | ||
| 456 | kfree(wbuf); | ||
| 457 | |||
| 458 | return ret; | ||
| 459 | } | ||
| 460 | |||
| 461 | static unsigned int lirc_poll(struct file *file, poll_table *wait) | ||
| 462 | { | ||
| 463 | poll_wait(file, &lirc_wait, wait); | ||
| 464 | if (rptr != wptr) | ||
| 465 | return POLLIN | POLLRDNORM; | ||
| 466 | return 0; | ||
| 467 | } | ||
| 468 | |||
| 469 | static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) | ||
| 470 | { | ||
| 471 | int result; | ||
| 472 | __u32 features = LIRC_CAN_SET_TRANSMITTER_MASK | | ||
| 473 | LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; | ||
| 474 | __u32 mode; | ||
| 475 | __u32 value; | ||
| 476 | |||
| 477 | switch (cmd) { | ||
| 478 | case LIRC_GET_FEATURES: | ||
| 479 | result = put_user(features, (__u32 *) arg); | ||
| 480 | if (result) | ||
| 481 | return result; | ||
| 482 | break; | ||
| 483 | case LIRC_GET_SEND_MODE: | ||
| 484 | result = put_user(LIRC_MODE_PULSE, (__u32 *) arg); | ||
| 485 | if (result) | ||
| 486 | return result; | ||
| 487 | break; | ||
| 488 | case LIRC_GET_REC_MODE: | ||
| 489 | result = put_user(LIRC_MODE_MODE2, (__u32 *) arg); | ||
| 490 | if (result) | ||
| 491 | return result; | ||
| 492 | break; | ||
| 493 | case LIRC_SET_SEND_MODE: | ||
| 494 | result = get_user(mode, (__u32 *) arg); | ||
| 495 | if (result) | ||
| 496 | return result; | ||
| 497 | if (mode != LIRC_MODE_PULSE) | ||
| 498 | return -EINVAL; | ||
| 499 | break; | ||
| 500 | case LIRC_SET_REC_MODE: | ||
| 501 | result = get_user(mode, (__u32 *) arg); | ||
| 502 | if (result) | ||
| 503 | return result; | ||
| 504 | if (mode != LIRC_MODE_MODE2) | ||
| 505 | return -ENOSYS; | ||
| 506 | break; | ||
| 507 | case LIRC_SET_TRANSMITTER_MASK: | ||
| 508 | result = get_user(value, (__u32 *) arg); | ||
| 509 | if (result) | ||
| 510 | return result; | ||
| 511 | if ((value & LIRC_PARALLEL_TRANSMITTER_MASK) != value) | ||
| 512 | return LIRC_PARALLEL_MAX_TRANSMITTERS; | ||
| 513 | tx_mask = value; | ||
| 514 | break; | ||
| 515 | default: | ||
| 516 | return -ENOIOCTLCMD; | ||
| 517 | } | ||
| 518 | return 0; | ||
| 519 | } | ||
| 520 | |||
| 521 | static int lirc_open(struct inode *node, struct file *filep) | ||
| 522 | { | ||
| 523 | if (is_open || !lirc_claim()) | ||
| 524 | return -EBUSY; | ||
| 525 | |||
| 526 | parport_enable_irq(pport); | ||
| 527 | |||
| 528 | /* init read ptr */ | ||
| 529 | rptr = 0; | ||
| 530 | wptr = 0; | ||
| 531 | lost_irqs = 0; | ||
| 532 | |||
| 533 | is_open = 1; | ||
| 534 | return 0; | ||
| 535 | } | ||
| 536 | |||
| 537 | static int lirc_close(struct inode *node, struct file *filep) | ||
| 538 | { | ||
| 539 | if (is_claimed) { | ||
| 540 | is_claimed = 0; | ||
| 541 | parport_release(ppdevice); | ||
| 542 | } | ||
| 543 | is_open = 0; | ||
| 544 | return 0; | ||
| 545 | } | ||
| 546 | |||
| 547 | static const struct file_operations lirc_fops = { | ||
| 548 | .owner = THIS_MODULE, | ||
| 549 | .llseek = lirc_lseek, | ||
| 550 | .read = lirc_read, | ||
| 551 | .write = lirc_write, | ||
| 552 | .poll = lirc_poll, | ||
| 553 | .unlocked_ioctl = lirc_ioctl, | ||
| 554 | #ifdef CONFIG_COMPAT | ||
| 555 | .compat_ioctl = lirc_ioctl, | ||
| 556 | #endif | ||
| 557 | .open = lirc_open, | ||
| 558 | .release = lirc_close | ||
| 559 | }; | ||
| 560 | |||
| 561 | static int set_use_inc(void *data) | ||
| 562 | { | ||
| 563 | return 0; | ||
| 564 | } | ||
| 565 | |||
| 566 | static void set_use_dec(void *data) | ||
| 567 | { | ||
| 568 | } | ||
| 569 | |||
| 570 | static struct lirc_driver driver = { | ||
| 571 | .name = LIRC_DRIVER_NAME, | ||
| 572 | .minor = -1, | ||
| 573 | .code_length = 1, | ||
| 574 | .sample_rate = 0, | ||
| 575 | .data = NULL, | ||
| 576 | .add_to_buf = NULL, | ||
| 577 | .set_use_inc = set_use_inc, | ||
| 578 | .set_use_dec = set_use_dec, | ||
| 579 | .fops = &lirc_fops, | ||
| 580 | .dev = NULL, | ||
| 581 | .owner = THIS_MODULE, | ||
| 582 | }; | ||
| 583 | |||
| 584 | static struct platform_device *lirc_parallel_dev; | ||
| 585 | |||
| 586 | static int __devinit lirc_parallel_probe(struct platform_device *dev) | ||
| 587 | { | ||
| 588 | return 0; | ||
| 589 | } | ||
| 590 | |||
| 591 | static int __devexit lirc_parallel_remove(struct platform_device *dev) | ||
| 592 | { | ||
| 593 | return 0; | ||
| 594 | } | ||
| 595 | |||
| 596 | static int lirc_parallel_suspend(struct platform_device *dev, | ||
| 597 | pm_message_t state) | ||
| 598 | { | ||
| 599 | return 0; | ||
| 600 | } | ||
| 601 | |||
| 602 | static int lirc_parallel_resume(struct platform_device *dev) | ||
| 603 | { | ||
| 604 | return 0; | ||
| 605 | } | ||
| 606 | |||
| 607 | static struct platform_driver lirc_parallel_driver = { | ||
| 608 | .probe = lirc_parallel_probe, | ||
| 609 | .remove = __devexit_p(lirc_parallel_remove), | ||
| 610 | .suspend = lirc_parallel_suspend, | ||
| 611 | .resume = lirc_parallel_resume, | ||
| 612 | .driver = { | ||
| 613 | .name = LIRC_DRIVER_NAME, | ||
| 614 | .owner = THIS_MODULE, | ||
| 615 | }, | ||
| 616 | }; | ||
| 617 | |||
| 618 | static int pf(void *handle) | ||
| 619 | { | ||
| 620 | parport_disable_irq(pport); | ||
| 621 | is_claimed = 0; | ||
| 622 | return 0; | ||
| 623 | } | ||
| 624 | |||
| 625 | static void kf(void *handle) | ||
| 626 | { | ||
| 627 | if (!is_open) | ||
| 628 | return; | ||
| 629 | if (!lirc_claim()) | ||
| 630 | return; | ||
| 631 | parport_enable_irq(pport); | ||
| 632 | lirc_off(); | ||
| 633 | /* this is a bit annoying when you actually print...*/ | ||
| 634 | /* | ||
| 635 | printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME); | ||
| 636 | */ | ||
| 637 | } | ||
| 638 | |||
| 639 | /*** module initialization and cleanup ***/ | ||
| 640 | |||
| 641 | static int __init lirc_parallel_init(void) | ||
| 642 | { | ||
| 643 | int result; | ||
| 644 | |||
| 645 | result = platform_driver_register(&lirc_parallel_driver); | ||
| 646 | if (result) { | ||
| 647 | printk(KERN_NOTICE "platform_driver_register" | ||
| 648 | " returned %d\n", result); | ||
| 649 | return result; | ||
| 650 | } | ||
| 651 | |||
| 652 | lirc_parallel_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0); | ||
| 653 | if (!lirc_parallel_dev) { | ||
| 654 | result = -ENOMEM; | ||
| 655 | goto exit_driver_unregister; | ||
| 656 | } | ||
| 657 | |||
| 658 | result = platform_device_add(lirc_parallel_dev); | ||
| 659 | if (result) | ||
| 660 | goto exit_device_put; | ||
| 661 | |||
| 662 | pport = parport_find_base(io); | ||
| 663 | if (pport == NULL) { | ||
| 664 | printk(KERN_NOTICE "%s: no port at %x found\n", | ||
| 665 | LIRC_DRIVER_NAME, io); | ||
| 666 | result = -ENXIO; | ||
| 667 | goto exit_device_put; | ||
| 668 | } | ||
| 669 | ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME, | ||
| 670 | pf, kf, irq_handler, 0, NULL); | ||
| 671 | parport_put_port(pport); | ||
| 672 | if (ppdevice == NULL) { | ||
| 673 | printk(KERN_NOTICE "%s: parport_register_device() failed\n", | ||
| 674 | LIRC_DRIVER_NAME); | ||
| 675 | result = -ENXIO; | ||
| 676 | goto exit_device_put; | ||
| 677 | } | ||
| 678 | if (parport_claim(ppdevice) != 0) | ||
| 679 | goto skip_init; | ||
| 680 | is_claimed = 1; | ||
| 681 | out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); | ||
| 682 | |||
| 683 | #ifdef LIRC_TIMER | ||
| 684 | if (debug) | ||
| 685 | out(LIRC_PORT_DATA, tx_mask); | ||
| 686 | |||
| 687 | timer = init_lirc_timer(); | ||
| 688 | |||
| 689 | #if 0 /* continue even if device is offline */ | ||
| 690 | if (timer == 0) { | ||
| 691 | is_claimed = 0; | ||
| 692 | parport_release(pport); | ||
| 693 | parport_unregister_device(ppdevice); | ||
| 694 | result = -EIO; | ||
| 695 | goto exit_device_put; | ||
| 696 | } | ||
| 697 | |||
| 698 | #endif | ||
| 699 | if (debug) | ||
| 700 | out(LIRC_PORT_DATA, 0); | ||
| 701 | #endif | ||
| 702 | |||
| 703 | is_claimed = 0; | ||
| 704 | parport_release(ppdevice); | ||
| 705 | skip_init: | ||
| 706 | driver.dev = &lirc_parallel_dev->dev; | ||
| 707 | driver.minor = lirc_register_driver(&driver); | ||
| 708 | if (driver.minor < 0) { | ||
| 709 | printk(KERN_NOTICE "%s: register_chrdev() failed\n", | ||
| 710 | LIRC_DRIVER_NAME); | ||
| 711 | parport_unregister_device(ppdevice); | ||
| 712 | result = -EIO; | ||
| 713 | goto exit_device_put; | ||
| 714 | } | ||
| 715 | printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n", | ||
| 716 | LIRC_DRIVER_NAME, io, irq); | ||
| 717 | return 0; | ||
| 718 | |||
| 719 | exit_device_put: | ||
| 720 | platform_device_put(lirc_parallel_dev); | ||
| 721 | exit_driver_unregister: | ||
| 722 | platform_driver_unregister(&lirc_parallel_driver); | ||
| 723 | return result; | ||
| 724 | } | ||
| 725 | |||
| 726 | static void __exit lirc_parallel_exit(void) | ||
| 727 | { | ||
| 728 | parport_unregister_device(ppdevice); | ||
| 729 | lirc_unregister_driver(driver.minor); | ||
| 730 | |||
| 731 | platform_device_unregister(lirc_parallel_dev); | ||
| 732 | platform_driver_unregister(&lirc_parallel_driver); | ||
| 733 | } | ||
| 734 | |||
| 735 | module_init(lirc_parallel_init); | ||
| 736 | module_exit(lirc_parallel_exit); | ||
| 737 | |||
| 738 | MODULE_DESCRIPTION("Infrared receiver driver for parallel ports."); | ||
| 739 | MODULE_AUTHOR("Christoph Bartelmus"); | ||
| 740 | MODULE_LICENSE("GPL"); | ||
| 741 | |||
| 742 | module_param(io, int, S_IRUGO); | ||
| 743 | MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)"); | ||
| 744 | |||
| 745 | module_param(irq, int, S_IRUGO); | ||
| 746 | MODULE_PARM_DESC(irq, "Interrupt (7 or 5)"); | ||
| 747 | |||
| 748 | module_param(tx_mask, int, S_IRUGO); | ||
| 749 | MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)"); | ||
| 750 | |||
| 751 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
| 752 | MODULE_PARM_DESC(debug, "Enable debugging messages"); | ||
| 753 | |||
| 754 | module_param(check_pselecd, bool, S_IRUGO | S_IWUSR); | ||
| 755 | MODULE_PARM_DESC(debug, "Check for printer (default: 0)"); | ||
diff --git a/drivers/staging/lirc/lirc_parallel.h b/drivers/staging/lirc/lirc_parallel.h new file mode 100644 index 00000000000..4bed6afe063 --- /dev/null +++ b/drivers/staging/lirc/lirc_parallel.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* lirc_parallel.h */ | ||
| 2 | |||
| 3 | #ifndef _LIRC_PARALLEL_H | ||
| 4 | #define _LIRC_PARALLEL_H | ||
| 5 | |||
| 6 | #include <linux/lp.h> | ||
| 7 | |||
| 8 | #define LIRC_PORT_LEN 3 | ||
| 9 | |||
| 10 | #define LIRC_LP_BASE 0 | ||
| 11 | #define LIRC_LP_STATUS 1 | ||
| 12 | #define LIRC_LP_CONTROL 2 | ||
| 13 | |||
| 14 | #define LIRC_PORT_DATA LIRC_LP_BASE /* base */ | ||
| 15 | #define LIRC_PORT_TIMER LIRC_LP_STATUS /* status port */ | ||
| 16 | #define LIRC_PORT_TIMER_BIT LP_PBUSY /* busy signal */ | ||
| 17 | #define LIRC_PORT_SIGNAL LIRC_LP_STATUS /* status port */ | ||
| 18 | #define LIRC_PORT_SIGNAL_BIT LP_PACK /* ack signal */ | ||
| 19 | #define LIRC_PORT_IRQ LIRC_LP_CONTROL /* control port */ | ||
| 20 | |||
| 21 | #define LIRC_SFH506_DELAY 0 /* delay t_phl in usecs */ | ||
| 22 | |||
| 23 | #define LIRC_PARALLEL_MAX_TRANSMITTERS 8 | ||
| 24 | #define LIRC_PARALLEL_TRANSMITTER_MASK ((1<<LIRC_PARALLEL_MAX_TRANSMITTERS) - 1) | ||
| 25 | |||
| 26 | #endif | ||
diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/lirc/lirc_sasem.c new file mode 100644 index 00000000000..7080cdeab5a --- /dev/null +++ b/drivers/staging/lirc/lirc_sasem.c | |||
| @@ -0,0 +1,939 @@ | |||
| 1 | /* | ||
| 2 | * lirc_sasem.c - USB remote support for LIRC | ||
| 3 | * Version 0.5 | ||
| 4 | * | ||
| 5 | * Copyright (C) 2004-2005 Oliver Stabel <oliver.stabel@gmx.de> | ||
| 6 | * Tim Davies <tim@opensystems.net.au> | ||
| 7 | * | ||
| 8 | * This driver was derived from: | ||
| 9 | * Venky Raju <dev@venky.ws> | ||
| 10 | * "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD" | ||
| 11 | * Paul Miller <pmiller9@users.sourceforge.net>'s 2003-2004 | ||
| 12 | * "lirc_atiusb - USB remote support for LIRC" | ||
| 13 | * Culver Consulting Services <henry@culcon.com>'s 2003 | ||
| 14 | * "Sasem OnAir VFD/IR USB driver" | ||
| 15 | * | ||
| 16 | * | ||
| 17 | * NOTE - The LCDproc iMon driver should work with this module. More info at | ||
| 18 | * http://www.frogstorm.info/sasem | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * This program is free software; you can redistribute it and/or modify | ||
| 23 | * it under the terms of the GNU General Public License as published by | ||
| 24 | * the Free Software Foundation; either version 2 of the License, or | ||
| 25 | * (at your option) any later version. | ||
| 26 | * | ||
| 27 | * This program is distributed in the hope that it will be useful, | ||
| 28 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 29 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 30 | * GNU General Public License for more details. | ||
| 31 | * | ||
| 32 | * You should have received a copy of the GNU General Public License | ||
| 33 | * along with this program; if not, write to the Free Software | ||
| 34 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 35 | */ | ||
| 36 | |||
| 37 | #include <linux/errno.h> | ||
| 38 | #include <linux/init.h> | ||
| 39 | #include <linux/kernel.h> | ||
| 40 | #include <linux/module.h> | ||
| 41 | #include <linux/slab.h> | ||
| 42 | #include <linux/uaccess.h> | ||
| 43 | #include <linux/usb.h> | ||
| 44 | |||
| 45 | #include <media/lirc.h> | ||
| 46 | #include <media/lirc_dev.h> | ||
| 47 | |||
| 48 | |||
| 49 | #define MOD_AUTHOR "Oliver Stabel <oliver.stabel@gmx.de>, " \ | ||
| 50 | "Tim Davies <tim@opensystems.net.au>" | ||
| 51 | #define MOD_DESC "USB Driver for Sasem Remote Controller V1.1" | ||
| 52 | #define MOD_NAME "lirc_sasem" | ||
| 53 | #define MOD_VERSION "0.5" | ||
| 54 | |||
| 55 | #define VFD_MINOR_BASE 144 /* Same as LCD */ | ||
| 56 | #define DEVICE_NAME "lcd%d" | ||
| 57 | |||
| 58 | #define BUF_CHUNK_SIZE 8 | ||
| 59 | #define BUF_SIZE 128 | ||
| 60 | |||
| 61 | #define IOCTL_LCD_CONTRAST 1 | ||
| 62 | |||
| 63 | /*** P R O T O T Y P E S ***/ | ||
| 64 | |||
| 65 | /* USB Callback prototypes */ | ||
| 66 | static int sasem_probe(struct usb_interface *interface, | ||
| 67 | const struct usb_device_id *id); | ||
| 68 | static void sasem_disconnect(struct usb_interface *interface); | ||
| 69 | static void usb_rx_callback(struct urb *urb); | ||
| 70 | static void usb_tx_callback(struct urb *urb); | ||
| 71 | |||
| 72 | /* VFD file_operations function prototypes */ | ||
| 73 | static int vfd_open(struct inode *inode, struct file *file); | ||
| 74 | static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg); | ||
| 75 | static int vfd_close(struct inode *inode, struct file *file); | ||
| 76 | static ssize_t vfd_write(struct file *file, const char *buf, | ||
| 77 | size_t n_bytes, loff_t *pos); | ||
| 78 | |||
| 79 | /* LIRC driver function prototypes */ | ||
| 80 | static int ir_open(void *data); | ||
| 81 | static void ir_close(void *data); | ||
| 82 | |||
| 83 | /* Driver init/exit prototypes */ | ||
| 84 | static int __init sasem_init(void); | ||
| 85 | static void __exit sasem_exit(void); | ||
| 86 | |||
| 87 | /*** G L O B A L S ***/ | ||
| 88 | #define SASEM_DATA_BUF_SZ 32 | ||
| 89 | |||
| 90 | struct sasem_context { | ||
| 91 | |||
| 92 | struct usb_device *dev; | ||
| 93 | int vfd_isopen; /* VFD port has been opened */ | ||
| 94 | unsigned int vfd_contrast; /* VFD contrast */ | ||
| 95 | int ir_isopen; /* IR port has been opened */ | ||
| 96 | int dev_present; /* USB device presence */ | ||
| 97 | struct mutex ctx_lock; /* to lock this object */ | ||
| 98 | wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ | ||
| 99 | |||
| 100 | struct lirc_driver *driver; | ||
| 101 | struct usb_endpoint_descriptor *rx_endpoint; | ||
| 102 | struct usb_endpoint_descriptor *tx_endpoint; | ||
| 103 | struct urb *rx_urb; | ||
| 104 | struct urb *tx_urb; | ||
| 105 | unsigned char usb_rx_buf[8]; | ||
| 106 | unsigned char usb_tx_buf[8]; | ||
| 107 | |||
| 108 | struct tx_t { | ||
| 109 | unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data buffer */ | ||
| 110 | struct completion finished; /* wait for write to finish */ | ||
| 111 | atomic_t busy; /* write in progress */ | ||
| 112 | int status; /* status of tx completion */ | ||
| 113 | } tx; | ||
| 114 | |||
| 115 | /* for dealing with repeat codes (wish there was a toggle bit!) */ | ||
| 116 | struct timeval presstime; | ||
| 117 | char lastcode[8]; | ||
| 118 | int codesaved; | ||
| 119 | }; | ||
| 120 | |||
| 121 | /* VFD file operations */ | ||
| 122 | static const struct file_operations vfd_fops = { | ||
| 123 | .owner = THIS_MODULE, | ||
| 124 | .open = &vfd_open, | ||
| 125 | .write = &vfd_write, | ||
| 126 | .unlocked_ioctl = &vfd_ioctl, | ||
| 127 | .release = &vfd_close, | ||
| 128 | .llseek = noop_llseek, | ||
| 129 | }; | ||
| 130 | |||
| 131 | /* USB Device ID for Sasem USB Control Board */ | ||
| 132 | static struct usb_device_id sasem_usb_id_table[] = { | ||
| 133 | /* Sasem USB Control Board */ | ||
| 134 | { USB_DEVICE(0x11ba, 0x0101) }, | ||
| 135 | /* Terminating entry */ | ||
| 136 | {} | ||
| 137 | }; | ||
| 138 | |||
| 139 | /* USB Device data */ | ||
| 140 | static struct usb_driver sasem_driver = { | ||
| 141 | .name = MOD_NAME, | ||
| 142 | .probe = sasem_probe, | ||
| 143 | .disconnect = sasem_disconnect, | ||
| 144 | .id_table = sasem_usb_id_table, | ||
| 145 | }; | ||
| 146 | |||
| 147 | static struct usb_class_driver sasem_class = { | ||
| 148 | .name = DEVICE_NAME, | ||
| 149 | .fops = &vfd_fops, | ||
| 150 | .minor_base = VFD_MINOR_BASE, | ||
| 151 | }; | ||
| 152 | |||
| 153 | /* to prevent races between open() and disconnect() */ | ||
| 154 | static DEFINE_MUTEX(disconnect_lock); | ||
| 155 | |||
| 156 | static int debug; | ||
| 157 | |||
| 158 | |||
| 159 | /*** M O D U L E C O D E ***/ | ||
| 160 | |||
| 161 | MODULE_AUTHOR(MOD_AUTHOR); | ||
| 162 | MODULE_DESCRIPTION(MOD_DESC); | ||
| 163 | MODULE_LICENSE("GPL"); | ||
| 164 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
| 165 | MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)"); | ||
| 166 | |||
| 167 | static void delete_context(struct sasem_context *context) | ||
| 168 | { | ||
| 169 | usb_free_urb(context->tx_urb); /* VFD */ | ||
| 170 | usb_free_urb(context->rx_urb); /* IR */ | ||
| 171 | lirc_buffer_free(context->driver->rbuf); | ||
| 172 | kfree(context->driver->rbuf); | ||
| 173 | kfree(context->driver); | ||
| 174 | kfree(context); | ||
| 175 | |||
| 176 | if (debug) | ||
| 177 | printk(KERN_INFO "%s: context deleted\n", __func__); | ||
| 178 | } | ||
| 179 | |||
| 180 | static void deregister_from_lirc(struct sasem_context *context) | ||
| 181 | { | ||
| 182 | int retval; | ||
| 183 | int minor = context->driver->minor; | ||
| 184 | |||
| 185 | retval = lirc_unregister_driver(minor); | ||
| 186 | if (retval) | ||
| 187 | err("%s: unable to deregister from lirc (%d)", | ||
| 188 | __func__, retval); | ||
| 189 | else | ||
| 190 | printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n", | ||
| 191 | minor); | ||
| 192 | |||
| 193 | } | ||
| 194 | |||
| 195 | /** | ||
| 196 | * Called when the VFD device (e.g. /dev/usb/lcd) | ||
| 197 | * is opened by the application. | ||
| 198 | */ | ||
| 199 | static int vfd_open(struct inode *inode, struct file *file) | ||
| 200 | { | ||
| 201 | struct usb_interface *interface; | ||
| 202 | struct sasem_context *context = NULL; | ||
| 203 | int subminor; | ||
| 204 | int retval = 0; | ||
| 205 | |||
| 206 | /* prevent races with disconnect */ | ||
| 207 | mutex_lock(&disconnect_lock); | ||
| 208 | |||
| 209 | subminor = iminor(inode); | ||
| 210 | interface = usb_find_interface(&sasem_driver, subminor); | ||
| 211 | if (!interface) { | ||
| 212 | err("%s: could not find interface for minor %d", | ||
| 213 | __func__, subminor); | ||
| 214 | retval = -ENODEV; | ||
| 215 | goto exit; | ||
| 216 | } | ||
| 217 | context = usb_get_intfdata(interface); | ||
| 218 | |||
| 219 | if (!context) { | ||
| 220 | err("%s: no context found for minor %d", | ||
| 221 | __func__, subminor); | ||
| 222 | retval = -ENODEV; | ||
| 223 | goto exit; | ||
| 224 | } | ||
| 225 | |||
| 226 | mutex_lock(&context->ctx_lock); | ||
| 227 | |||
| 228 | if (context->vfd_isopen) { | ||
| 229 | err("%s: VFD port is already open", __func__); | ||
| 230 | retval = -EBUSY; | ||
| 231 | } else { | ||
| 232 | context->vfd_isopen = 1; | ||
| 233 | file->private_data = context; | ||
| 234 | printk(KERN_INFO "VFD port opened\n"); | ||
| 235 | } | ||
| 236 | |||
| 237 | mutex_unlock(&context->ctx_lock); | ||
| 238 | |||
| 239 | exit: | ||
| 240 | mutex_unlock(&disconnect_lock); | ||
| 241 | return retval; | ||
| 242 | } | ||
| 243 | |||
| 244 | /** | ||
| 245 | * Called when the VFD device (e.g. /dev/usb/lcd) | ||
| 246 | * is closed by the application. | ||
| 247 | */ | ||
| 248 | static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg) | ||
| 249 | { | ||
| 250 | struct sasem_context *context = NULL; | ||
| 251 | |||
| 252 | context = (struct sasem_context *) file->private_data; | ||
| 253 | |||
| 254 | if (!context) { | ||
| 255 | err("%s: no context for device", __func__); | ||
| 256 | return -ENODEV; | ||
| 257 | } | ||
| 258 | |||
| 259 | mutex_lock(&context->ctx_lock); | ||
| 260 | |||
| 261 | switch (cmd) { | ||
| 262 | case IOCTL_LCD_CONTRAST: | ||
| 263 | if (arg > 1000) | ||
| 264 | arg = 1000; | ||
| 265 | context->vfd_contrast = (unsigned int)arg; | ||
| 266 | break; | ||
| 267 | default: | ||
| 268 | printk(KERN_INFO "Unknown IOCTL command\n"); | ||
| 269 | mutex_unlock(&context->ctx_lock); | ||
| 270 | return -ENOIOCTLCMD; /* not supported */ | ||
| 271 | } | ||
| 272 | |||
| 273 | mutex_unlock(&context->ctx_lock); | ||
| 274 | return 0; | ||
| 275 | } | ||
| 276 | |||
| 277 | /** | ||
| 278 | * Called when the VFD device (e.g. /dev/usb/lcd) | ||
| 279 | * is closed by the application. | ||
| 280 | */ | ||
| 281 | static int vfd_close(struct inode *inode, struct file *file) | ||
| 282 | { | ||
| 283 | struct sasem_context *context = NULL; | ||
| 284 | int retval = 0; | ||
| 285 | |||
| 286 | context = (struct sasem_context *) file->private_data; | ||
| 287 | |||
| 288 | if (!context) { | ||
| 289 | err("%s: no context for device", __func__); | ||
| 290 | return -ENODEV; | ||
| 291 | } | ||
| 292 | |||
| 293 | mutex_lock(&context->ctx_lock); | ||
| 294 | |||
| 295 | if (!context->vfd_isopen) { | ||
| 296 | err("%s: VFD is not open", __func__); | ||
| 297 | retval = -EIO; | ||
| 298 | } else { | ||
| 299 | context->vfd_isopen = 0; | ||
| 300 | printk(KERN_INFO "VFD port closed\n"); | ||
| 301 | if (!context->dev_present && !context->ir_isopen) { | ||
| 302 | |||
| 303 | /* Device disconnected before close and IR port is | ||
| 304 | * not open. If IR port is open, context will be | ||
| 305 | * deleted by ir_close. */ | ||
| 306 | mutex_unlock(&context->ctx_lock); | ||
| 307 | delete_context(context); | ||
| 308 | return retval; | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | mutex_unlock(&context->ctx_lock); | ||
| 313 | return retval; | ||
| 314 | } | ||
| 315 | |||
| 316 | /** | ||
| 317 | * Sends a packet to the VFD. | ||
| 318 | */ | ||
| 319 | static int send_packet(struct sasem_context *context) | ||
| 320 | { | ||
| 321 | unsigned int pipe; | ||
| 322 | int interval = 0; | ||
| 323 | int retval = 0; | ||
| 324 | |||
| 325 | pipe = usb_sndintpipe(context->dev, | ||
| 326 | context->tx_endpoint->bEndpointAddress); | ||
| 327 | interval = context->tx_endpoint->bInterval; | ||
| 328 | |||
| 329 | usb_fill_int_urb(context->tx_urb, context->dev, pipe, | ||
| 330 | context->usb_tx_buf, sizeof(context->usb_tx_buf), | ||
| 331 | usb_tx_callback, context, interval); | ||
| 332 | |||
| 333 | context->tx_urb->actual_length = 0; | ||
| 334 | |||
| 335 | init_completion(&context->tx.finished); | ||
| 336 | atomic_set(&(context->tx.busy), 1); | ||
| 337 | |||
| 338 | retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); | ||
| 339 | if (retval) { | ||
| 340 | atomic_set(&(context->tx.busy), 0); | ||
| 341 | err("%s: error submitting urb (%d)", __func__, retval); | ||
| 342 | } else { | ||
| 343 | /* Wait for transmission to complete (or abort) */ | ||
| 344 | mutex_unlock(&context->ctx_lock); | ||
| 345 | wait_for_completion(&context->tx.finished); | ||
| 346 | mutex_lock(&context->ctx_lock); | ||
| 347 | |||
| 348 | retval = context->tx.status; | ||
| 349 | if (retval) | ||
| 350 | err("%s: packet tx failed (%d)", __func__, retval); | ||
| 351 | } | ||
| 352 | |||
| 353 | return retval; | ||
| 354 | } | ||
| 355 | |||
| 356 | /** | ||
| 357 | * Writes data to the VFD. The Sasem VFD is 2x16 characters | ||
| 358 | * and requires data in 9 consecutive USB interrupt packets, | ||
| 359 | * each packet carrying 8 bytes. | ||
| 360 | */ | ||
| 361 | static ssize_t vfd_write(struct file *file, const char *buf, | ||
| 362 | size_t n_bytes, loff_t *pos) | ||
| 363 | { | ||
| 364 | int i; | ||
| 365 | int retval = 0; | ||
| 366 | struct sasem_context *context; | ||
| 367 | int *data_buf = NULL; | ||
| 368 | |||
| 369 | context = (struct sasem_context *) file->private_data; | ||
| 370 | if (!context) { | ||
| 371 | err("%s: no context for device", __func__); | ||
| 372 | return -ENODEV; | ||
| 373 | } | ||
| 374 | |||
| 375 | mutex_lock(&context->ctx_lock); | ||
| 376 | |||
| 377 | if (!context->dev_present) { | ||
| 378 | err("%s: no Sasem device present", __func__); | ||
| 379 | retval = -ENODEV; | ||
| 380 | goto exit; | ||
| 381 | } | ||
| 382 | |||
| 383 | if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) { | ||
| 384 | err("%s: invalid payload size", __func__); | ||
| 385 | retval = -EINVAL; | ||
| 386 | goto exit; | ||
| 387 | } | ||
| 388 | |||
| 389 | data_buf = memdup_user(buf, n_bytes); | ||
| 390 | if (IS_ERR(data_buf)) { | ||
| 391 | retval = PTR_ERR(data_buf); | ||
| 392 | goto exit; | ||
| 393 | } | ||
| 394 | |||
| 395 | memcpy(context->tx.data_buf, data_buf, n_bytes); | ||
| 396 | |||
| 397 | /* Pad with spaces */ | ||
| 398 | for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i) | ||
| 399 | context->tx.data_buf[i] = ' '; | ||
| 400 | |||
| 401 | /* Nine 8 byte packets to be sent */ | ||
| 402 | /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0" | ||
| 403 | * will clear the VFD */ | ||
| 404 | for (i = 0; i < 9; i++) { | ||
| 405 | switch (i) { | ||
| 406 | case 0: | ||
| 407 | memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8); | ||
| 408 | context->usb_tx_buf[1] = (context->vfd_contrast) ? | ||
| 409 | (0x2B - (context->vfd_contrast - 1) / 250) | ||
| 410 | : 0x2B; | ||
| 411 | break; | ||
| 412 | case 1: | ||
| 413 | memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); | ||
| 414 | break; | ||
| 415 | case 2: | ||
| 416 | memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8); | ||
| 417 | break; | ||
| 418 | case 3: | ||
| 419 | memcpy(context->usb_tx_buf, context->tx.data_buf, 8); | ||
| 420 | break; | ||
| 421 | case 4: | ||
| 422 | memcpy(context->usb_tx_buf, | ||
| 423 | context->tx.data_buf + 8, 8); | ||
| 424 | break; | ||
| 425 | case 5: | ||
| 426 | memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); | ||
| 427 | break; | ||
| 428 | case 6: | ||
| 429 | memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8); | ||
| 430 | break; | ||
| 431 | case 7: | ||
| 432 | memcpy(context->usb_tx_buf, | ||
| 433 | context->tx.data_buf + 16, 8); | ||
| 434 | break; | ||
| 435 | case 8: | ||
| 436 | memcpy(context->usb_tx_buf, | ||
| 437 | context->tx.data_buf + 24, 8); | ||
| 438 | break; | ||
| 439 | } | ||
| 440 | retval = send_packet(context); | ||
| 441 | if (retval) { | ||
| 442 | |||
| 443 | err("%s: send packet failed for packet #%d", | ||
| 444 | __func__, i); | ||
| 445 | goto exit; | ||
| 446 | } | ||
| 447 | } | ||
| 448 | exit: | ||
| 449 | |||
| 450 | mutex_unlock(&context->ctx_lock); | ||
| 451 | kfree(data_buf); | ||
| 452 | |||
| 453 | return (!retval) ? n_bytes : retval; | ||
| 454 | } | ||
| 455 | |||
| 456 | /** | ||
| 457 | * Callback function for USB core API: transmit data | ||
| 458 | */ | ||
| 459 | static void usb_tx_callback(struct urb *urb) | ||
| 460 | { | ||
| 461 | struct sasem_context *context; | ||
| 462 | |||
| 463 | if (!urb) | ||
| 464 | return; | ||
| 465 | context = (struct sasem_context *) urb->context; | ||
| 466 | if (!context) | ||
| 467 | return; | ||
| 468 | |||
| 469 | context->tx.status = urb->status; | ||
| 470 | |||
| 471 | /* notify waiters that write has finished */ | ||
| 472 | atomic_set(&context->tx.busy, 0); | ||
| 473 | complete(&context->tx.finished); | ||
| 474 | |||
| 475 | return; | ||
| 476 | } | ||
| 477 | |||
| 478 | /** | ||
| 479 | * Called by lirc_dev when the application opens /dev/lirc | ||
| 480 | */ | ||
| 481 | static int ir_open(void *data) | ||
| 482 | { | ||
| 483 | int retval = 0; | ||
| 484 | struct sasem_context *context; | ||
| 485 | |||
| 486 | /* prevent races with disconnect */ | ||
| 487 | mutex_lock(&disconnect_lock); | ||
| 488 | |||
| 489 | context = (struct sasem_context *) data; | ||
| 490 | |||
| 491 | mutex_lock(&context->ctx_lock); | ||
| 492 | |||
| 493 | if (context->ir_isopen) { | ||
| 494 | err("%s: IR port is already open", __func__); | ||
| 495 | retval = -EBUSY; | ||
| 496 | goto exit; | ||
| 497 | } | ||
| 498 | |||
| 499 | usb_fill_int_urb(context->rx_urb, context->dev, | ||
| 500 | usb_rcvintpipe(context->dev, | ||
| 501 | context->rx_endpoint->bEndpointAddress), | ||
| 502 | context->usb_rx_buf, sizeof(context->usb_rx_buf), | ||
| 503 | usb_rx_callback, context, context->rx_endpoint->bInterval); | ||
| 504 | |||
| 505 | retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); | ||
| 506 | |||
| 507 | if (retval) | ||
| 508 | err("%s: usb_submit_urb failed for ir_open (%d)", | ||
| 509 | __func__, retval); | ||
| 510 | else { | ||
| 511 | context->ir_isopen = 1; | ||
| 512 | printk(KERN_INFO "IR port opened\n"); | ||
| 513 | } | ||
| 514 | |||
| 515 | exit: | ||
| 516 | mutex_unlock(&context->ctx_lock); | ||
| 517 | |||
| 518 | mutex_unlock(&disconnect_lock); | ||
| 519 | return retval; | ||
| 520 | } | ||
| 521 | |||
| 522 | /** | ||
| 523 | * Called by lirc_dev when the application closes /dev/lirc | ||
| 524 | */ | ||
| 525 | static void ir_close(void *data) | ||
| 526 | { | ||
| 527 | struct sasem_context *context; | ||
| 528 | |||
| 529 | context = (struct sasem_context *)data; | ||
| 530 | if (!context) { | ||
| 531 | err("%s: no context for device", __func__); | ||
| 532 | return; | ||
| 533 | } | ||
| 534 | |||
| 535 | mutex_lock(&context->ctx_lock); | ||
| 536 | |||
| 537 | usb_kill_urb(context->rx_urb); | ||
| 538 | context->ir_isopen = 0; | ||
| 539 | printk(KERN_INFO "IR port closed\n"); | ||
| 540 | |||
| 541 | if (!context->dev_present) { | ||
| 542 | |||
| 543 | /* | ||
| 544 | * Device disconnected while IR port was | ||
| 545 | * still open. Driver was not deregistered | ||
| 546 | * at disconnect time, so do it now. | ||
| 547 | */ | ||
| 548 | deregister_from_lirc(context); | ||
| 549 | |||
| 550 | if (!context->vfd_isopen) { | ||
| 551 | |||
| 552 | mutex_unlock(&context->ctx_lock); | ||
| 553 | delete_context(context); | ||
| 554 | return; | ||
| 555 | } | ||
| 556 | /* If VFD port is open, context will be deleted by vfd_close */ | ||
| 557 | } | ||
| 558 | |||
| 559 | mutex_unlock(&context->ctx_lock); | ||
| 560 | return; | ||
| 561 | } | ||
| 562 | |||
| 563 | /** | ||
| 564 | * Process the incoming packet | ||
| 565 | */ | ||
| 566 | static void incoming_packet(struct sasem_context *context, | ||
| 567 | struct urb *urb) | ||
| 568 | { | ||
| 569 | int len = urb->actual_length; | ||
| 570 | unsigned char *buf = urb->transfer_buffer; | ||
| 571 | long ms; | ||
| 572 | struct timeval tv; | ||
| 573 | int i; | ||
| 574 | |||
| 575 | if (len != 8) { | ||
| 576 | printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n", | ||
| 577 | __func__, len); | ||
| 578 | return; | ||
| 579 | } | ||
| 580 | |||
| 581 | if (debug) { | ||
| 582 | printk(KERN_INFO "Incoming data: "); | ||
| 583 | for (i = 0; i < 8; ++i) | ||
| 584 | printk(KERN_CONT "%02x ", buf[i]); | ||
| 585 | printk(KERN_CONT "\n"); | ||
| 586 | } | ||
| 587 | |||
| 588 | /* | ||
| 589 | * Lirc could deal with the repeat code, but we really need to block it | ||
| 590 | * if it arrives too late. Otherwise we could repeat the wrong code. | ||
| 591 | */ | ||
| 592 | |||
| 593 | /* get the time since the last button press */ | ||
| 594 | do_gettimeofday(&tv); | ||
| 595 | ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 + | ||
| 596 | (tv.tv_usec - context->presstime.tv_usec) / 1000; | ||
| 597 | |||
| 598 | if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) { | ||
| 599 | /* | ||
| 600 | * the repeat code is being sent, so we copy | ||
| 601 | * the old code to LIRC | ||
| 602 | */ | ||
| 603 | |||
| 604 | /* | ||
| 605 | * NOTE: Only if the last code was less than 250ms ago | ||
| 606 | * - no one should be able to push another (undetected) button | ||
| 607 | * in that time and then get a false repeat of the previous | ||
| 608 | * press but it is long enough for a genuine repeat | ||
| 609 | */ | ||
| 610 | if ((ms < 250) && (context->codesaved != 0)) { | ||
| 611 | memcpy(buf, &context->lastcode, 8); | ||
| 612 | context->presstime.tv_sec = tv.tv_sec; | ||
| 613 | context->presstime.tv_usec = tv.tv_usec; | ||
| 614 | } | ||
| 615 | } else { | ||
| 616 | /* save the current valid code for repeats */ | ||
| 617 | memcpy(&context->lastcode, buf, 8); | ||
| 618 | /* | ||
| 619 | * set flag to signal a valid code was save; | ||
| 620 | * just for safety reasons | ||
| 621 | */ | ||
| 622 | context->codesaved = 1; | ||
| 623 | context->presstime.tv_sec = tv.tv_sec; | ||
| 624 | context->presstime.tv_usec = tv.tv_usec; | ||
| 625 | } | ||
| 626 | |||
| 627 | lirc_buffer_write(context->driver->rbuf, buf); | ||
| 628 | wake_up(&context->driver->rbuf->wait_poll); | ||
| 629 | } | ||
| 630 | |||
| 631 | /** | ||
| 632 | * Callback function for USB core API: receive data | ||
| 633 | */ | ||
| 634 | static void usb_rx_callback(struct urb *urb) | ||
| 635 | { | ||
| 636 | struct sasem_context *context; | ||
| 637 | |||
| 638 | if (!urb) | ||
| 639 | return; | ||
| 640 | context = (struct sasem_context *) urb->context; | ||
| 641 | if (!context) | ||
| 642 | return; | ||
| 643 | |||
| 644 | switch (urb->status) { | ||
| 645 | |||
| 646 | case -ENOENT: /* usbcore unlink successful! */ | ||
| 647 | return; | ||
| 648 | |||
| 649 | case 0: | ||
| 650 | if (context->ir_isopen) | ||
| 651 | incoming_packet(context, urb); | ||
| 652 | break; | ||
| 653 | |||
| 654 | default: | ||
| 655 | printk(KERN_WARNING "%s: status (%d): ignored", | ||
| 656 | __func__, urb->status); | ||
| 657 | break; | ||
| 658 | } | ||
| 659 | |||
| 660 | usb_submit_urb(context->rx_urb, GFP_ATOMIC); | ||
| 661 | return; | ||
| 662 | } | ||
| 663 | |||
| 664 | |||
| 665 | |||
| 666 | /** | ||
| 667 | * Callback function for USB core API: Probe | ||
| 668 | */ | ||
| 669 | static int sasem_probe(struct usb_interface *interface, | ||
| 670 | const struct usb_device_id *id) | ||
| 671 | { | ||
| 672 | struct usb_device *dev = NULL; | ||
| 673 | struct usb_host_interface *iface_desc = NULL; | ||
| 674 | struct usb_endpoint_descriptor *rx_endpoint = NULL; | ||
| 675 | struct usb_endpoint_descriptor *tx_endpoint = NULL; | ||
| 676 | struct urb *rx_urb = NULL; | ||
| 677 | struct urb *tx_urb = NULL; | ||
| 678 | struct lirc_driver *driver = NULL; | ||
| 679 | struct lirc_buffer *rbuf = NULL; | ||
| 680 | int lirc_minor = 0; | ||
| 681 | int num_endpoints; | ||
| 682 | int retval = 0; | ||
| 683 | int vfd_ep_found; | ||
| 684 | int ir_ep_found; | ||
| 685 | int alloc_status; | ||
| 686 | struct sasem_context *context = NULL; | ||
| 687 | int i; | ||
| 688 | |||
| 689 | printk(KERN_INFO "%s: found Sasem device\n", __func__); | ||
| 690 | |||
| 691 | |||
| 692 | dev = usb_get_dev(interface_to_usbdev(interface)); | ||
| 693 | iface_desc = interface->cur_altsetting; | ||
| 694 | num_endpoints = iface_desc->desc.bNumEndpoints; | ||
| 695 | |||
| 696 | /* | ||
| 697 | * Scan the endpoint list and set: | ||
| 698 | * first input endpoint = IR endpoint | ||
| 699 | * first output endpoint = VFD endpoint | ||
| 700 | */ | ||
| 701 | |||
| 702 | ir_ep_found = 0; | ||
| 703 | vfd_ep_found = 0; | ||
| 704 | |||
| 705 | for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) { | ||
| 706 | |||
| 707 | struct usb_endpoint_descriptor *ep; | ||
| 708 | int ep_dir; | ||
| 709 | int ep_type; | ||
| 710 | ep = &iface_desc->endpoint [i].desc; | ||
| 711 | ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; | ||
| 712 | ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; | ||
| 713 | |||
| 714 | if (!ir_ep_found && | ||
| 715 | ep_dir == USB_DIR_IN && | ||
| 716 | ep_type == USB_ENDPOINT_XFER_INT) { | ||
| 717 | |||
| 718 | rx_endpoint = ep; | ||
| 719 | ir_ep_found = 1; | ||
| 720 | if (debug) | ||
| 721 | printk(KERN_INFO "%s: found IR endpoint\n", | ||
| 722 | __func__); | ||
| 723 | |||
| 724 | } else if (!vfd_ep_found && | ||
| 725 | ep_dir == USB_DIR_OUT && | ||
| 726 | ep_type == USB_ENDPOINT_XFER_INT) { | ||
| 727 | |||
| 728 | tx_endpoint = ep; | ||
| 729 | vfd_ep_found = 1; | ||
| 730 | if (debug) | ||
| 731 | printk(KERN_INFO "%s: found VFD endpoint\n", | ||
| 732 | __func__); | ||
| 733 | } | ||
| 734 | } | ||
| 735 | |||
| 736 | /* Input endpoint is mandatory */ | ||
| 737 | if (!ir_ep_found) { | ||
| 738 | |||
| 739 | err("%s: no valid input (IR) endpoint found.", __func__); | ||
| 740 | retval = -ENODEV; | ||
| 741 | goto exit; | ||
| 742 | } | ||
| 743 | |||
| 744 | if (!vfd_ep_found) | ||
| 745 | printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n", | ||
| 746 | __func__); | ||
| 747 | |||
| 748 | |||
| 749 | /* Allocate memory */ | ||
| 750 | alloc_status = 0; | ||
| 751 | |||
| 752 | context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL); | ||
| 753 | if (!context) { | ||
| 754 | err("%s: kzalloc failed for context", __func__); | ||
| 755 | alloc_status = 1; | ||
| 756 | goto alloc_status_switch; | ||
| 757 | } | ||
| 758 | driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); | ||
| 759 | if (!driver) { | ||
| 760 | err("%s: kzalloc failed for lirc_driver", __func__); | ||
| 761 | alloc_status = 2; | ||
| 762 | goto alloc_status_switch; | ||
| 763 | } | ||
| 764 | rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); | ||
| 765 | if (!rbuf) { | ||
| 766 | err("%s: kmalloc failed for lirc_buffer", __func__); | ||
| 767 | alloc_status = 3; | ||
| 768 | goto alloc_status_switch; | ||
| 769 | } | ||
| 770 | if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { | ||
| 771 | err("%s: lirc_buffer_init failed", __func__); | ||
| 772 | alloc_status = 4; | ||
| 773 | goto alloc_status_switch; | ||
| 774 | } | ||
| 775 | rx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 776 | if (!rx_urb) { | ||
| 777 | err("%s: usb_alloc_urb failed for IR urb", __func__); | ||
| 778 | alloc_status = 5; | ||
| 779 | goto alloc_status_switch; | ||
| 780 | } | ||
| 781 | if (vfd_ep_found) { | ||
| 782 | tx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 783 | if (!tx_urb) { | ||
| 784 | err("%s: usb_alloc_urb failed for VFD urb", | ||
| 785 | __func__); | ||
| 786 | alloc_status = 6; | ||
| 787 | goto alloc_status_switch; | ||
| 788 | } | ||
| 789 | } | ||
| 790 | |||
| 791 | mutex_init(&context->ctx_lock); | ||
| 792 | |||
| 793 | strcpy(driver->name, MOD_NAME); | ||
| 794 | driver->minor = -1; | ||
| 795 | driver->code_length = 64; | ||
| 796 | driver->sample_rate = 0; | ||
| 797 | driver->features = LIRC_CAN_REC_LIRCCODE; | ||
| 798 | driver->data = context; | ||
| 799 | driver->rbuf = rbuf; | ||
| 800 | driver->set_use_inc = ir_open; | ||
| 801 | driver->set_use_dec = ir_close; | ||
| 802 | driver->dev = &interface->dev; | ||
| 803 | driver->owner = THIS_MODULE; | ||
| 804 | |||
| 805 | mutex_lock(&context->ctx_lock); | ||
| 806 | |||
| 807 | lirc_minor = lirc_register_driver(driver); | ||
| 808 | if (lirc_minor < 0) { | ||
| 809 | err("%s: lirc_register_driver failed", __func__); | ||
| 810 | alloc_status = 7; | ||
| 811 | retval = lirc_minor; | ||
| 812 | goto unlock; | ||
| 813 | } else | ||
| 814 | printk(KERN_INFO "%s: Registered Sasem driver (minor:%d)\n", | ||
| 815 | __func__, lirc_minor); | ||
| 816 | |||
| 817 | alloc_status_switch: | ||
| 818 | |||
| 819 | switch (alloc_status) { | ||
| 820 | |||
| 821 | case 7: | ||
| 822 | if (vfd_ep_found) | ||
| 823 | usb_free_urb(tx_urb); | ||
| 824 | case 6: | ||
| 825 | usb_free_urb(rx_urb); | ||
| 826 | case 5: | ||
| 827 | lirc_buffer_free(rbuf); | ||
| 828 | case 4: | ||
| 829 | kfree(rbuf); | ||
| 830 | case 3: | ||
| 831 | kfree(driver); | ||
| 832 | case 2: | ||
| 833 | kfree(context); | ||
| 834 | context = NULL; | ||
| 835 | case 1: | ||
| 836 | retval = -ENOMEM; | ||
| 837 | goto unlock; | ||
| 838 | } | ||
| 839 | |||
| 840 | /* Needed while unregistering! */ | ||
| 841 | driver->minor = lirc_minor; | ||
| 842 | |||
| 843 | context->dev = dev; | ||
| 844 | context->dev_present = 1; | ||
| 845 | context->rx_endpoint = rx_endpoint; | ||
| 846 | context->rx_urb = rx_urb; | ||
| 847 | if (vfd_ep_found) { | ||
| 848 | context->tx_endpoint = tx_endpoint; | ||
| 849 | context->tx_urb = tx_urb; | ||
| 850 | context->vfd_contrast = 1000; /* range 0 - 1000 */ | ||
| 851 | } | ||
| 852 | context->driver = driver; | ||
| 853 | |||
| 854 | usb_set_intfdata(interface, context); | ||
| 855 | |||
| 856 | if (vfd_ep_found) { | ||
| 857 | |||
| 858 | if (debug) | ||
| 859 | printk(KERN_INFO "Registering VFD with sysfs\n"); | ||
| 860 | if (usb_register_dev(interface, &sasem_class)) | ||
| 861 | /* Not a fatal error, so ignore */ | ||
| 862 | printk(KERN_INFO "%s: could not get a minor number " | ||
| 863 | "for VFD\n", __func__); | ||
| 864 | } | ||
| 865 | |||
| 866 | printk(KERN_INFO "%s: Sasem device on usb<%d:%d> initialized\n", | ||
| 867 | __func__, dev->bus->busnum, dev->devnum); | ||
| 868 | unlock: | ||
| 869 | mutex_unlock(&context->ctx_lock); | ||
| 870 | exit: | ||
| 871 | return retval; | ||
| 872 | } | ||
| 873 | |||
| 874 | /** | ||
| 875 | * Callback function for USB core API: disonnect | ||
| 876 | */ | ||
| 877 | static void sasem_disconnect(struct usb_interface *interface) | ||
| 878 | { | ||
| 879 | struct sasem_context *context; | ||
| 880 | |||
| 881 | /* prevent races with ir_open()/vfd_open() */ | ||
| 882 | mutex_lock(&disconnect_lock); | ||
| 883 | |||
| 884 | context = usb_get_intfdata(interface); | ||
| 885 | mutex_lock(&context->ctx_lock); | ||
| 886 | |||
| 887 | printk(KERN_INFO "%s: Sasem device disconnected\n", __func__); | ||
| 888 | |||
| 889 | usb_set_intfdata(interface, NULL); | ||
| 890 | context->dev_present = 0; | ||
| 891 | |||
| 892 | /* Stop reception */ | ||
| 893 | usb_kill_urb(context->rx_urb); | ||
| 894 | |||
| 895 | /* Abort ongoing write */ | ||
| 896 | if (atomic_read(&context->tx.busy)) { | ||
| 897 | |||
| 898 | usb_kill_urb(context->tx_urb); | ||
| 899 | wait_for_completion(&context->tx.finished); | ||
| 900 | } | ||
| 901 | |||
| 902 | /* De-register from lirc_dev if IR port is not open */ | ||
| 903 | if (!context->ir_isopen) | ||
| 904 | deregister_from_lirc(context); | ||
| 905 | |||
| 906 | usb_deregister_dev(interface, &sasem_class); | ||
| 907 | |||
| 908 | mutex_unlock(&context->ctx_lock); | ||
| 909 | |||
| 910 | if (!context->ir_isopen && !context->vfd_isopen) | ||
| 911 | delete_context(context); | ||
| 912 | |||
| 913 | mutex_unlock(&disconnect_lock); | ||
| 914 | } | ||
| 915 | |||
| 916 | static int __init sasem_init(void) | ||
| 917 | { | ||
| 918 | int rc; | ||
| 919 | |||
| 920 | printk(KERN_INFO MOD_DESC ", v" MOD_VERSION "\n"); | ||
| 921 | printk(KERN_INFO MOD_AUTHOR "\n"); | ||
| 922 | |||
| 923 | rc = usb_register(&sasem_driver); | ||
| 924 | if (rc < 0) { | ||
| 925 | err("%s: usb register failed (%d)", __func__, rc); | ||
| 926 | return -ENODEV; | ||
| 927 | } | ||
| 928 | return 0; | ||
| 929 | } | ||
| 930 | |||
| 931 | static void __exit sasem_exit(void) | ||
| 932 | { | ||
| 933 | usb_deregister(&sasem_driver); | ||
| 934 | printk(KERN_INFO "module removed. Goodbye!\n"); | ||
| 935 | } | ||
| 936 | |||
| 937 | |||
| 938 | module_init(sasem_init); | ||
| 939 | module_exit(sasem_exit); | ||
diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c new file mode 100644 index 00000000000..805df913bb6 --- /dev/null +++ b/drivers/staging/lirc/lirc_serial.c | |||
| @@ -0,0 +1,1315 @@ | |||
| 1 | /* | ||
| 2 | * lirc_serial.c | ||
| 3 | * | ||
| 4 | * lirc_serial - Device driver that records pulse- and pause-lengths | ||
| 5 | * (space-lengths) between DDCD event on a serial port. | ||
| 6 | * | ||
| 7 | * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de> | ||
| 8 | * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu> | ||
| 9 | * Copyright (C) 1998 Ben Pfaff <blp@gnu.org> | ||
| 10 | * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de> | ||
| 11 | * Copyright (C) 2007 Andrei Tanas <andrei@tanas.ca> (suspend/resume support) | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2 of the License, or | ||
| 15 | * (at your option) any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Steve's changes to improve transmission fidelity: | ||
| 30 | * - for systems with the rdtsc instruction and the clock counter, a | ||
| 31 | * send_pule that times the pulses directly using the counter. | ||
| 32 | * This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is | ||
| 33 | * not needed. Measurement shows very stable waveform, even where | ||
| 34 | * PCI activity slows the access to the UART, which trips up other | ||
| 35 | * versions. | ||
| 36 | * - For other system, non-integer-microsecond pulse/space lengths, | ||
| 37 | * done using fixed point binary. So, much more accurate carrier | ||
| 38 | * frequency. | ||
| 39 | * - fine tuned transmitter latency, taking advantage of fractional | ||
| 40 | * microseconds in previous change | ||
| 41 | * - Fixed bug in the way transmitter latency was accounted for by | ||
| 42 | * tuning the pulse lengths down - the send_pulse routine ignored | ||
| 43 | * this overhead as it timed the overall pulse length - so the | ||
| 44 | * pulse frequency was right but overall pulse length was too | ||
| 45 | * long. Fixed by accounting for latency on each pulse/space | ||
| 46 | * iteration. | ||
| 47 | * | ||
| 48 | * Steve Davies <steve@daviesfam.org> July 2001 | ||
| 49 | */ | ||
| 50 | |||
| 51 | #include <linux/module.h> | ||
| 52 | #include <linux/errno.h> | ||
| 53 | #include <linux/signal.h> | ||
| 54 | #include <linux/sched.h> | ||
| 55 | #include <linux/fs.h> | ||
| 56 | #include <linux/interrupt.h> | ||
| 57 | #include <linux/ioport.h> | ||
| 58 | #include <linux/kernel.h> | ||
| 59 | #include <linux/serial_reg.h> | ||
| 60 | #include <linux/time.h> | ||
| 61 | #include <linux/string.h> | ||
| 62 | #include <linux/types.h> | ||
| 63 | #include <linux/wait.h> | ||
| 64 | #include <linux/mm.h> | ||
| 65 | #include <linux/delay.h> | ||
| 66 | #include <linux/poll.h> | ||
| 67 | #include <linux/platform_device.h> | ||
| 68 | |||
| 69 | #include <asm/system.h> | ||
| 70 | #include <linux/io.h> | ||
| 71 | #include <linux/irq.h> | ||
| 72 | #include <linux/fcntl.h> | ||
| 73 | #include <linux/spinlock.h> | ||
| 74 | |||
| 75 | #ifdef CONFIG_LIRC_SERIAL_NSLU2 | ||
| 76 | #include <asm/hardware.h> | ||
| 77 | #endif | ||
| 78 | /* From Intel IXP42X Developer's Manual (#252480-005): */ | ||
| 79 | /* ftp://download.intel.com/design/network/manuals/25248005.pdf */ | ||
| 80 | #define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ | ||
| 81 | #define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ | ||
| 82 | |||
| 83 | #include <media/lirc.h> | ||
| 84 | #include <media/lirc_dev.h> | ||
| 85 | |||
| 86 | #define LIRC_DRIVER_NAME "lirc_serial" | ||
| 87 | |||
| 88 | struct lirc_serial { | ||
| 89 | int signal_pin; | ||
| 90 | int signal_pin_change; | ||
| 91 | u8 on; | ||
| 92 | u8 off; | ||
| 93 | long (*send_pulse)(unsigned long length); | ||
| 94 | void (*send_space)(long length); | ||
| 95 | int features; | ||
| 96 | spinlock_t lock; | ||
| 97 | }; | ||
| 98 | |||
| 99 | #define LIRC_HOMEBREW 0 | ||
| 100 | #define LIRC_IRDEO 1 | ||
| 101 | #define LIRC_IRDEO_REMOTE 2 | ||
| 102 | #define LIRC_ANIMAX 3 | ||
| 103 | #define LIRC_IGOR 4 | ||
| 104 | #define LIRC_NSLU2 5 | ||
| 105 | |||
| 106 | /*** module parameters ***/ | ||
| 107 | static int type; | ||
| 108 | static int io; | ||
| 109 | static int irq; | ||
| 110 | static int iommap; | ||
| 111 | static int ioshift; | ||
| 112 | static int softcarrier = 1; | ||
| 113 | static int share_irq; | ||
| 114 | static int debug; | ||
| 115 | static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ | ||
| 116 | static int txsense; /* 0 = active high, 1 = active low */ | ||
| 117 | |||
| 118 | #define dprintk(fmt, args...) \ | ||
| 119 | do { \ | ||
| 120 | if (debug) \ | ||
| 121 | printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ | ||
| 122 | fmt, ## args); \ | ||
| 123 | } while (0) | ||
| 124 | |||
| 125 | /* forward declarations */ | ||
| 126 | static long send_pulse_irdeo(unsigned long length); | ||
| 127 | static long send_pulse_homebrew(unsigned long length); | ||
| 128 | static void send_space_irdeo(long length); | ||
| 129 | static void send_space_homebrew(long length); | ||
| 130 | |||
| 131 | static struct lirc_serial hardware[] = { | ||
| 132 | [LIRC_HOMEBREW] = { | ||
| 133 | .signal_pin = UART_MSR_DCD, | ||
| 134 | .signal_pin_change = UART_MSR_DDCD, | ||
| 135 | .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), | ||
| 136 | .off = (UART_MCR_RTS | UART_MCR_OUT2), | ||
| 137 | .send_pulse = send_pulse_homebrew, | ||
| 138 | .send_space = send_space_homebrew, | ||
| 139 | #ifdef CONFIG_LIRC_SERIAL_TRANSMITTER | ||
| 140 | .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | | ||
| 141 | LIRC_CAN_SET_SEND_CARRIER | | ||
| 142 | LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) | ||
| 143 | #else | ||
| 144 | .features = LIRC_CAN_REC_MODE2 | ||
| 145 | #endif | ||
| 146 | }, | ||
| 147 | |||
| 148 | [LIRC_IRDEO] = { | ||
| 149 | .signal_pin = UART_MSR_DSR, | ||
| 150 | .signal_pin_change = UART_MSR_DDSR, | ||
| 151 | .on = UART_MCR_OUT2, | ||
| 152 | .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), | ||
| 153 | .send_pulse = send_pulse_irdeo, | ||
| 154 | .send_space = send_space_irdeo, | ||
| 155 | .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | | ||
| 156 | LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) | ||
| 157 | }, | ||
| 158 | |||
| 159 | [LIRC_IRDEO_REMOTE] = { | ||
| 160 | .signal_pin = UART_MSR_DSR, | ||
| 161 | .signal_pin_change = UART_MSR_DDSR, | ||
| 162 | .on = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), | ||
| 163 | .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), | ||
| 164 | .send_pulse = send_pulse_irdeo, | ||
| 165 | .send_space = send_space_irdeo, | ||
| 166 | .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | | ||
| 167 | LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) | ||
| 168 | }, | ||
| 169 | |||
| 170 | [LIRC_ANIMAX] = { | ||
| 171 | .signal_pin = UART_MSR_DCD, | ||
| 172 | .signal_pin_change = UART_MSR_DDCD, | ||
| 173 | .on = 0, | ||
| 174 | .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), | ||
| 175 | .send_pulse = NULL, | ||
| 176 | .send_space = NULL, | ||
| 177 | .features = LIRC_CAN_REC_MODE2 | ||
| 178 | }, | ||
| 179 | |||
| 180 | [LIRC_IGOR] = { | ||
| 181 | .signal_pin = UART_MSR_DSR, | ||
| 182 | .signal_pin_change = UART_MSR_DDSR, | ||
| 183 | .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), | ||
| 184 | .off = (UART_MCR_RTS | UART_MCR_OUT2), | ||
| 185 | .send_pulse = send_pulse_homebrew, | ||
| 186 | .send_space = send_space_homebrew, | ||
| 187 | #ifdef CONFIG_LIRC_SERIAL_TRANSMITTER | ||
| 188 | .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | | ||
| 189 | LIRC_CAN_SET_SEND_CARRIER | | ||
| 190 | LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) | ||
| 191 | #else | ||
| 192 | .features = LIRC_CAN_REC_MODE2 | ||
| 193 | #endif | ||
| 194 | }, | ||
| 195 | |||
| 196 | #ifdef CONFIG_LIRC_SERIAL_NSLU2 | ||
| 197 | /* | ||
| 198 | * Modified Linksys Network Storage Link USB 2.0 (NSLU2): | ||
| 199 | * We receive on CTS of the 2nd serial port (R142,LHS), we | ||
| 200 | * transmit with a IR diode between GPIO[1] (green status LED), | ||
| 201 | * and ground (Matthias Goebl <matthias.goebl@goebl.net>). | ||
| 202 | * See also http://www.nslu2-linux.org for this device | ||
| 203 | */ | ||
| 204 | [LIRC_NSLU2] = { | ||
| 205 | .signal_pin = UART_MSR_CTS, | ||
| 206 | .signal_pin_change = UART_MSR_DCTS, | ||
| 207 | .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), | ||
| 208 | .off = (UART_MCR_RTS | UART_MCR_OUT2), | ||
| 209 | .send_pulse = send_pulse_homebrew, | ||
| 210 | .send_space = send_space_homebrew, | ||
| 211 | #ifdef CONFIG_LIRC_SERIAL_TRANSMITTER | ||
| 212 | .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | | ||
| 213 | LIRC_CAN_SET_SEND_CARRIER | | ||
| 214 | LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) | ||
| 215 | #else | ||
| 216 | .features = LIRC_CAN_REC_MODE2 | ||
| 217 | #endif | ||
| 218 | }, | ||
| 219 | #endif | ||
| 220 | |||
| 221 | }; | ||
| 222 | |||
| 223 | #define RS_ISR_PASS_LIMIT 256 | ||
| 224 | |||
| 225 | /* | ||
| 226 | * A long pulse code from a remote might take up to 300 bytes. The | ||
| 227 | * daemon should read the bytes as soon as they are generated, so take | ||
| 228 | * the number of keys you think you can push before the daemon runs | ||
| 229 | * and multiply by 300. The driver will warn you if you overrun this | ||
| 230 | * buffer. If you have a slow computer or non-busmastering IDE disks, | ||
| 231 | * maybe you will need to increase this. | ||
| 232 | */ | ||
| 233 | |||
| 234 | /* This MUST be a power of two! It has to be larger than 1 as well. */ | ||
| 235 | |||
| 236 | #define RBUF_LEN 256 | ||
| 237 | |||
| 238 | static struct timeval lasttv = {0, 0}; | ||
| 239 | |||
| 240 | static struct lirc_buffer rbuf; | ||
| 241 | |||
| 242 | static unsigned int freq = 38000; | ||
| 243 | static unsigned int duty_cycle = 50; | ||
| 244 | |||
| 245 | /* Initialized in init_timing_params() */ | ||
| 246 | static unsigned long period; | ||
| 247 | static unsigned long pulse_width; | ||
| 248 | static unsigned long space_width; | ||
| 249 | |||
| 250 | #if defined(__i386__) | ||
| 251 | /* | ||
| 252 | * From: | ||
| 253 | * Linux I/O port programming mini-HOWTO | ||
| 254 | * Author: Riku Saikkonen <Riku.Saikkonen@hut.fi> | ||
| 255 | * v, 28 December 1997 | ||
| 256 | * | ||
| 257 | * [...] | ||
| 258 | * Actually, a port I/O instruction on most ports in the 0-0x3ff range | ||
| 259 | * takes almost exactly 1 microsecond, so if you're, for example, using | ||
| 260 | * the parallel port directly, just do additional inb()s from that port | ||
| 261 | * to delay. | ||
| 262 | * [...] | ||
| 263 | */ | ||
| 264 | /* transmitter latency 1.5625us 0x1.90 - this figure arrived at from | ||
| 265 | * comment above plus trimming to match actual measured frequency. | ||
| 266 | * This will be sensitive to cpu speed, though hopefully most of the 1.5us | ||
| 267 | * is spent in the uart access. Still - for reference test machine was a | ||
| 268 | * 1.13GHz Athlon system - Steve | ||
| 269 | */ | ||
| 270 | |||
| 271 | /* | ||
| 272 | * changed from 400 to 450 as this works better on slower machines; | ||
| 273 | * faster machines will use the rdtsc code anyway | ||
| 274 | */ | ||
| 275 | #define LIRC_SERIAL_TRANSMITTER_LATENCY 450 | ||
| 276 | |||
| 277 | #else | ||
| 278 | |||
| 279 | /* does anybody have information on other platforms ? */ | ||
| 280 | /* 256 = 1<<8 */ | ||
| 281 | #define LIRC_SERIAL_TRANSMITTER_LATENCY 256 | ||
| 282 | |||
| 283 | #endif /* __i386__ */ | ||
| 284 | /* | ||
| 285 | * FIXME: should we be using hrtimers instead of this | ||
| 286 | * LIRC_SERIAL_TRANSMITTER_LATENCY nonsense? | ||
| 287 | */ | ||
| 288 | |||
| 289 | /* fetch serial input packet (1 byte) from register offset */ | ||
| 290 | static u8 sinp(int offset) | ||
| 291 | { | ||
| 292 | if (iommap != 0) | ||
| 293 | /* the register is memory-mapped */ | ||
| 294 | offset <<= ioshift; | ||
| 295 | |||
| 296 | return inb(io + offset); | ||
| 297 | } | ||
| 298 | |||
| 299 | /* write serial output packet (1 byte) of value to register offset */ | ||
| 300 | static void soutp(int offset, u8 value) | ||
| 301 | { | ||
| 302 | if (iommap != 0) | ||
| 303 | /* the register is memory-mapped */ | ||
| 304 | offset <<= ioshift; | ||
| 305 | |||
| 306 | outb(value, io + offset); | ||
| 307 | } | ||
| 308 | |||
| 309 | static void on(void) | ||
| 310 | { | ||
| 311 | #ifdef CONFIG_LIRC_SERIAL_NSLU2 | ||
| 312 | /* | ||
| 313 | * On NSLU2, we put the transmit diode between the output of the green | ||
| 314 | * status LED and ground | ||
| 315 | */ | ||
| 316 | if (type == LIRC_NSLU2) { | ||
| 317 | gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW); | ||
| 318 | return; | ||
| 319 | } | ||
| 320 | #endif | ||
| 321 | if (txsense) | ||
| 322 | soutp(UART_MCR, hardware[type].off); | ||
| 323 | else | ||
| 324 | soutp(UART_MCR, hardware[type].on); | ||
| 325 | } | ||
| 326 | |||
| 327 | static void off(void) | ||
| 328 | { | ||
| 329 | #ifdef CONFIG_LIRC_SERIAL_NSLU2 | ||
| 330 | if (type == LIRC_NSLU2) { | ||
| 331 | gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH); | ||
| 332 | return; | ||
| 333 | } | ||
| 334 | #endif | ||
| 335 | if (txsense) | ||
| 336 | soutp(UART_MCR, hardware[type].on); | ||
| 337 | else | ||
| 338 | soutp(UART_MCR, hardware[type].off); | ||
| 339 | } | ||
| 340 | |||
| 341 | #ifndef MAX_UDELAY_MS | ||
| 342 | #define MAX_UDELAY_US 5000 | ||
| 343 | #else | ||
| 344 | #define MAX_UDELAY_US (MAX_UDELAY_MS*1000) | ||
| 345 | #endif | ||
| 346 | |||
| 347 | static void safe_udelay(unsigned long usecs) | ||
| 348 | { | ||
| 349 | while (usecs > MAX_UDELAY_US) { | ||
| 350 | udelay(MAX_UDELAY_US); | ||
| 351 | usecs -= MAX_UDELAY_US; | ||
| 352 | } | ||
| 353 | udelay(usecs); | ||
| 354 | } | ||
| 355 | |||
| 356 | #ifdef USE_RDTSC | ||
| 357 | /* | ||
| 358 | * This is an overflow/precision juggle, complicated in that we can't | ||
| 359 | * do long long divide in the kernel | ||
| 360 | */ | ||
| 361 | |||
| 362 | /* | ||
| 363 | * When we use the rdtsc instruction to measure clocks, we keep the | ||
| 364 | * pulse and space widths as clock cycles. As this is CPU speed | ||
| 365 | * dependent, the widths must be calculated in init_port and ioctl | ||
| 366 | * time | ||
| 367 | */ | ||
| 368 | |||
| 369 | /* So send_pulse can quickly convert microseconds to clocks */ | ||
| 370 | static unsigned long conv_us_to_clocks; | ||
| 371 | |||
| 372 | static int init_timing_params(unsigned int new_duty_cycle, | ||
| 373 | unsigned int new_freq) | ||
| 374 | { | ||
| 375 | __u64 loops_per_sec, work; | ||
| 376 | |||
| 377 | duty_cycle = new_duty_cycle; | ||
| 378 | freq = new_freq; | ||
| 379 | |||
| 380 | loops_per_sec = __this_cpu_read(cpu.info.loops_per_jiffy); | ||
| 381 | loops_per_sec *= HZ; | ||
| 382 | |||
| 383 | /* How many clocks in a microsecond?, avoiding long long divide */ | ||
| 384 | work = loops_per_sec; | ||
| 385 | work *= 4295; /* 4295 = 2^32 / 1e6 */ | ||
| 386 | conv_us_to_clocks = (work >> 32); | ||
| 387 | |||
| 388 | /* | ||
| 389 | * Carrier period in clocks, approach good up to 32GHz clock, | ||
| 390 | * gets carrier frequency within 8Hz | ||
| 391 | */ | ||
| 392 | period = loops_per_sec >> 3; | ||
| 393 | period /= (freq >> 3); | ||
| 394 | |||
| 395 | /* Derive pulse and space from the period */ | ||
| 396 | pulse_width = period * duty_cycle / 100; | ||
| 397 | space_width = period - pulse_width; | ||
| 398 | dprintk("in init_timing_params, freq=%d, duty_cycle=%d, " | ||
| 399 | "clk/jiffy=%ld, pulse=%ld, space=%ld, " | ||
| 400 | "conv_us_to_clocks=%ld\n", | ||
| 401 | freq, duty_cycle, __this_cpu_read(cpu_info.loops_per_jiffy), | ||
| 402 | pulse_width, space_width, conv_us_to_clocks); | ||
| 403 | return 0; | ||
| 404 | } | ||
| 405 | #else /* ! USE_RDTSC */ | ||
| 406 | static int init_timing_params(unsigned int new_duty_cycle, | ||
| 407 | unsigned int new_freq) | ||
| 408 | { | ||
| 409 | /* | ||
| 410 | * period, pulse/space width are kept with 8 binary places - | ||
| 411 | * IE multiplied by 256. | ||
| 412 | */ | ||
| 413 | if (256 * 1000000L / new_freq * new_duty_cycle / 100 <= | ||
| 414 | LIRC_SERIAL_TRANSMITTER_LATENCY) | ||
| 415 | return -EINVAL; | ||
| 416 | if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= | ||
| 417 | LIRC_SERIAL_TRANSMITTER_LATENCY) | ||
| 418 | return -EINVAL; | ||
| 419 | duty_cycle = new_duty_cycle; | ||
| 420 | freq = new_freq; | ||
| 421 | period = 256 * 1000000L / freq; | ||
| 422 | pulse_width = period * duty_cycle / 100; | ||
| 423 | space_width = period - pulse_width; | ||
| 424 | dprintk("in init_timing_params, freq=%d pulse=%ld, " | ||
| 425 | "space=%ld\n", freq, pulse_width, space_width); | ||
| 426 | return 0; | ||
| 427 | } | ||
| 428 | #endif /* USE_RDTSC */ | ||
| 429 | |||
| 430 | |||
| 431 | /* return value: space length delta */ | ||
| 432 | |||
| 433 | static long send_pulse_irdeo(unsigned long length) | ||
| 434 | { | ||
| 435 | long rawbits, ret; | ||
| 436 | int i; | ||
| 437 | unsigned char output; | ||
| 438 | unsigned char chunk, shifted; | ||
| 439 | |||
| 440 | /* how many bits have to be sent ? */ | ||
| 441 | rawbits = length * 1152 / 10000; | ||
| 442 | if (duty_cycle > 50) | ||
| 443 | chunk = 3; | ||
| 444 | else | ||
| 445 | chunk = 1; | ||
| 446 | for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) { | ||
| 447 | shifted = chunk << (i * 3); | ||
| 448 | shifted >>= 1; | ||
| 449 | output &= (~shifted); | ||
| 450 | i++; | ||
| 451 | if (i == 3) { | ||
| 452 | soutp(UART_TX, output); | ||
| 453 | while (!(sinp(UART_LSR) & UART_LSR_THRE)) | ||
| 454 | ; | ||
| 455 | output = 0x7f; | ||
| 456 | i = 0; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | if (i != 0) { | ||
| 460 | soutp(UART_TX, output); | ||
| 461 | while (!(sinp(UART_LSR) & UART_LSR_TEMT)) | ||
| 462 | ; | ||
| 463 | } | ||
| 464 | |||
| 465 | if (i == 0) | ||
| 466 | ret = (-rawbits) * 10000 / 1152; | ||
| 467 | else | ||
| 468 | ret = (3 - i) * 3 * 10000 / 1152 + (-rawbits) * 10000 / 1152; | ||
| 469 | |||
| 470 | return ret; | ||
| 471 | } | ||
| 472 | |||
| 473 | #ifdef USE_RDTSC | ||
| 474 | /* Version that uses Pentium rdtsc instruction to measure clocks */ | ||
| 475 | |||
| 476 | /* | ||
| 477 | * This version does sub-microsecond timing using rdtsc instruction, | ||
| 478 | * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY | ||
| 479 | * Implicitly i586 architecture... - Steve | ||
| 480 | */ | ||
| 481 | |||
| 482 | static long send_pulse_homebrew_softcarrier(unsigned long length) | ||
| 483 | { | ||
| 484 | int flag; | ||
| 485 | unsigned long target, start, now; | ||
| 486 | |||
| 487 | /* Get going quick as we can */ | ||
| 488 | rdtscl(start); | ||
| 489 | on(); | ||
| 490 | /* Convert length from microseconds to clocks */ | ||
| 491 | length *= conv_us_to_clocks; | ||
| 492 | /* And loop till time is up - flipping at right intervals */ | ||
| 493 | now = start; | ||
| 494 | target = pulse_width; | ||
| 495 | flag = 1; | ||
| 496 | /* | ||
| 497 | * FIXME: This looks like a hard busy wait, without even an occasional, | ||
| 498 | * polite, cpu_relax() call. There's got to be a better way? | ||
| 499 | * | ||
| 500 | * The i2c code has the result of a lot of bit-banging work, I wonder if | ||
| 501 | * there's something there which could be helpful here. | ||
| 502 | */ | ||
| 503 | while ((now - start) < length) { | ||
| 504 | /* Delay till flip time */ | ||
| 505 | do { | ||
| 506 | rdtscl(now); | ||
| 507 | } while ((now - start) < target); | ||
| 508 | |||
| 509 | /* flip */ | ||
| 510 | if (flag) { | ||
| 511 | rdtscl(now); | ||
| 512 | off(); | ||
| 513 | target += space_width; | ||
| 514 | } else { | ||
| 515 | rdtscl(now); on(); | ||
| 516 | target += pulse_width; | ||
| 517 | } | ||
| 518 | flag = !flag; | ||
| 519 | } | ||
| 520 | rdtscl(now); | ||
| 521 | return ((now - start) - length) / conv_us_to_clocks; | ||
| 522 | } | ||
| 523 | #else /* ! USE_RDTSC */ | ||
| 524 | /* Version using udelay() */ | ||
| 525 | |||
| 526 | /* | ||
| 527 | * here we use fixed point arithmetic, with 8 | ||
| 528 | * fractional bits. that gets us within 0.1% or so of the right average | ||
| 529 | * frequency, albeit with some jitter in pulse length - Steve | ||
| 530 | */ | ||
| 531 | |||
| 532 | /* To match 8 fractional bits used for pulse/space length */ | ||
| 533 | |||
| 534 | static long send_pulse_homebrew_softcarrier(unsigned long length) | ||
| 535 | { | ||
| 536 | int flag; | ||
| 537 | unsigned long actual, target, d; | ||
| 538 | length <<= 8; | ||
| 539 | |||
| 540 | actual = 0; target = 0; flag = 0; | ||
| 541 | while (actual < length) { | ||
| 542 | if (flag) { | ||
| 543 | off(); | ||
| 544 | target += space_width; | ||
| 545 | } else { | ||
| 546 | on(); | ||
| 547 | target += pulse_width; | ||
| 548 | } | ||
| 549 | d = (target - actual - | ||
| 550 | LIRC_SERIAL_TRANSMITTER_LATENCY + 128) >> 8; | ||
| 551 | /* | ||
| 552 | * Note - we've checked in ioctl that the pulse/space | ||
| 553 | * widths are big enough so that d is > 0 | ||
| 554 | */ | ||
| 555 | udelay(d); | ||
| 556 | actual += (d << 8) + LIRC_SERIAL_TRANSMITTER_LATENCY; | ||
| 557 | flag = !flag; | ||
| 558 | } | ||
| 559 | return (actual-length) >> 8; | ||
| 560 | } | ||
| 561 | #endif /* USE_RDTSC */ | ||
| 562 | |||
| 563 | static long send_pulse_homebrew(unsigned long length) | ||
| 564 | { | ||
| 565 | if (length <= 0) | ||
| 566 | return 0; | ||
| 567 | |||
| 568 | if (softcarrier) | ||
| 569 | return send_pulse_homebrew_softcarrier(length); | ||
| 570 | else { | ||
| 571 | on(); | ||
| 572 | safe_udelay(length); | ||
| 573 | return 0; | ||
| 574 | } | ||
| 575 | } | ||
| 576 | |||
| 577 | static void send_space_irdeo(long length) | ||
| 578 | { | ||
| 579 | if (length <= 0) | ||
| 580 | return; | ||
| 581 | |||
| 582 | safe_udelay(length); | ||
| 583 | } | ||
| 584 | |||
| 585 | static void send_space_homebrew(long length) | ||
| 586 | { | ||
| 587 | off(); | ||
| 588 | if (length <= 0) | ||
| 589 | return; | ||
| 590 | safe_udelay(length); | ||
| 591 | } | ||
| 592 | |||
| 593 | static void rbwrite(int l) | ||
| 594 | { | ||
| 595 | if (lirc_buffer_full(&rbuf)) { | ||
| 596 | /* no new signals will be accepted */ | ||
| 597 | dprintk("Buffer overrun\n"); | ||
| 598 | return; | ||
| 599 | } | ||
| 600 | lirc_buffer_write(&rbuf, (void *)&l); | ||
| 601 | } | ||
| 602 | |||
| 603 | static void frbwrite(int l) | ||
| 604 | { | ||
| 605 | /* simple noise filter */ | ||
| 606 | static int pulse, space; | ||
| 607 | static unsigned int ptr; | ||
| 608 | |||
| 609 | if (ptr > 0 && (l & PULSE_BIT)) { | ||
| 610 | pulse += l & PULSE_MASK; | ||
| 611 | if (pulse > 250) { | ||
| 612 | rbwrite(space); | ||
| 613 | rbwrite(pulse | PULSE_BIT); | ||
| 614 | ptr = 0; | ||
| 615 | pulse = 0; | ||
| 616 | } | ||
| 617 | return; | ||
| 618 | } | ||
| 619 | if (!(l & PULSE_BIT)) { | ||
| 620 | if (ptr == 0) { | ||
| 621 | if (l > 20000) { | ||
| 622 | space = l; | ||
| 623 | ptr++; | ||
| 624 | return; | ||
| 625 | } | ||
| 626 | } else { | ||
| 627 | if (l > 20000) { | ||
| 628 | space += pulse; | ||
| 629 | if (space > PULSE_MASK) | ||
| 630 | space = PULSE_MASK; | ||
| 631 | space += l; | ||
| 632 | if (space > PULSE_MASK) | ||
| 633 | space = PULSE_MASK; | ||
| 634 | pulse = 0; | ||
| 635 | return; | ||
| 636 | } | ||
| 637 | rbwrite(space); | ||
| 638 | rbwrite(pulse | PULSE_BIT); | ||
| 639 | ptr = 0; | ||
| 640 | pulse = 0; | ||
| 641 | } | ||
| 642 | } | ||
| 643 | rbwrite(l); | ||
| 644 | } | ||
| 645 | |||
| 646 | static irqreturn_t irq_handler(int i, void *blah) | ||
| 647 | { | ||
| 648 | struct timeval tv; | ||
| 649 | int counter, dcd; | ||
| 650 | u8 status; | ||
| 651 | long deltv; | ||
| 652 | int data; | ||
| 653 | static int last_dcd = -1; | ||
| 654 | |||
| 655 | if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { | ||
| 656 | /* not our interrupt */ | ||
| 657 | return IRQ_NONE; | ||
| 658 | } | ||
| 659 | |||
| 660 | counter = 0; | ||
| 661 | do { | ||
| 662 | counter++; | ||
| 663 | status = sinp(UART_MSR); | ||
| 664 | if (counter > RS_ISR_PASS_LIMIT) { | ||
| 665 | printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: " | ||
| 666 | "We're caught!\n"); | ||
| 667 | break; | ||
| 668 | } | ||
| 669 | if ((status & hardware[type].signal_pin_change) | ||
| 670 | && sense != -1) { | ||
| 671 | /* get current time */ | ||
| 672 | do_gettimeofday(&tv); | ||
| 673 | |||
| 674 | /* New mode, written by Trent Piepho | ||
| 675 | <xyzzy@u.washington.edu>. */ | ||
| 676 | |||
| 677 | /* | ||
| 678 | * The old format was not very portable. | ||
| 679 | * We now use an int to pass pulses | ||
| 680 | * and spaces to user space. | ||
| 681 | * | ||
| 682 | * If PULSE_BIT is set a pulse has been | ||
| 683 | * received, otherwise a space has been | ||
| 684 | * received. The driver needs to know if your | ||
| 685 | * receiver is active high or active low, or | ||
| 686 | * the space/pulse sense could be | ||
| 687 | * inverted. The bits denoted by PULSE_MASK are | ||
| 688 | * the length in microseconds. Lengths greater | ||
| 689 | * than or equal to 16 seconds are clamped to | ||
| 690 | * PULSE_MASK. All other bits are unused. | ||
| 691 | * This is a much simpler interface for user | ||
| 692 | * programs, as well as eliminating "out of | ||
| 693 | * phase" errors with space/pulse | ||
| 694 | * autodetection. | ||
| 695 | */ | ||
| 696 | |||
| 697 | /* calc time since last interrupt in microseconds */ | ||
| 698 | dcd = (status & hardware[type].signal_pin) ? 1 : 0; | ||
| 699 | |||
| 700 | if (dcd == last_dcd) { | ||
| 701 | printk(KERN_WARNING LIRC_DRIVER_NAME | ||
| 702 | ": ignoring spike: %d %d %lx %lx %lx %lx\n", | ||
| 703 | dcd, sense, | ||
| 704 | tv.tv_sec, lasttv.tv_sec, | ||
| 705 | tv.tv_usec, lasttv.tv_usec); | ||
| 706 | continue; | ||
| 707 | } | ||
| 708 | |||
| 709 | deltv = tv.tv_sec-lasttv.tv_sec; | ||
| 710 | if (tv.tv_sec < lasttv.tv_sec || | ||
| 711 | (tv.tv_sec == lasttv.tv_sec && | ||
| 712 | tv.tv_usec < lasttv.tv_usec)) { | ||
| 713 | printk(KERN_WARNING LIRC_DRIVER_NAME | ||
| 714 | ": AIEEEE: your clock just jumped " | ||
| 715 | "backwards\n"); | ||
| 716 | printk(KERN_WARNING LIRC_DRIVER_NAME | ||
| 717 | ": %d %d %lx %lx %lx %lx\n", | ||
| 718 | dcd, sense, | ||
| 719 | tv.tv_sec, lasttv.tv_sec, | ||
| 720 | tv.tv_usec, lasttv.tv_usec); | ||
| 721 | data = PULSE_MASK; | ||
| 722 | } else if (deltv > 15) { | ||
| 723 | data = PULSE_MASK; /* really long time */ | ||
| 724 | if (!(dcd^sense)) { | ||
| 725 | /* sanity check */ | ||
| 726 | printk(KERN_WARNING LIRC_DRIVER_NAME | ||
| 727 | ": AIEEEE: " | ||
| 728 | "%d %d %lx %lx %lx %lx\n", | ||
| 729 | dcd, sense, | ||
| 730 | tv.tv_sec, lasttv.tv_sec, | ||
| 731 | tv.tv_usec, lasttv.tv_usec); | ||
| 732 | /* | ||
| 733 | * detecting pulse while this | ||
| 734 | * MUST be a space! | ||
| 735 | */ | ||
| 736 | sense = sense ? 0 : 1; | ||
| 737 | } | ||
| 738 | } else | ||
| 739 | data = (int) (deltv*1000000 + | ||
| 740 | tv.tv_usec - | ||
| 741 | lasttv.tv_usec); | ||
| 742 | frbwrite(dcd^sense ? data : (data|PULSE_BIT)); | ||
| 743 | lasttv = tv; | ||
| 744 | last_dcd = dcd; | ||
| 745 | wake_up_interruptible(&rbuf.wait_poll); | ||
| 746 | } | ||
| 747 | } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ | ||
| 748 | return IRQ_HANDLED; | ||
| 749 | } | ||
| 750 | |||
| 751 | |||
| 752 | static int hardware_init_port(void) | ||
| 753 | { | ||
| 754 | u8 scratch, scratch2, scratch3; | ||
| 755 | |||
| 756 | /* | ||
| 757 | * This is a simple port existence test, borrowed from the autoconfig | ||
| 758 | * function in drivers/serial/8250.c | ||
| 759 | */ | ||
| 760 | scratch = sinp(UART_IER); | ||
| 761 | soutp(UART_IER, 0); | ||
| 762 | #ifdef __i386__ | ||
| 763 | outb(0xff, 0x080); | ||
| 764 | #endif | ||
| 765 | scratch2 = sinp(UART_IER) & 0x0f; | ||
| 766 | soutp(UART_IER, 0x0f); | ||
| 767 | #ifdef __i386__ | ||
| 768 | outb(0x00, 0x080); | ||
| 769 | #endif | ||
| 770 | scratch3 = sinp(UART_IER) & 0x0f; | ||
| 771 | soutp(UART_IER, scratch); | ||
| 772 | if (scratch2 != 0 || scratch3 != 0x0f) { | ||
| 773 | /* we fail, there's nothing here */ | ||
| 774 | printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test " | ||
| 775 | "failed, cannot continue\n"); | ||
| 776 | return -EINVAL; | ||
| 777 | } | ||
| 778 | |||
| 779 | |||
| 780 | |||
| 781 | /* Set DLAB 0. */ | ||
| 782 | soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); | ||
| 783 | |||
| 784 | /* First of all, disable all interrupts */ | ||
| 785 | soutp(UART_IER, sinp(UART_IER) & | ||
| 786 | (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); | ||
| 787 | |||
| 788 | /* Clear registers. */ | ||
| 789 | sinp(UART_LSR); | ||
| 790 | sinp(UART_RX); | ||
| 791 | sinp(UART_IIR); | ||
| 792 | sinp(UART_MSR); | ||
| 793 | |||
| 794 | #ifdef CONFIG_LIRC_SERIAL_NSLU2 | ||
| 795 | if (type == LIRC_NSLU2) { | ||
| 796 | /* Setup NSLU2 UART */ | ||
| 797 | |||
| 798 | /* Enable UART */ | ||
| 799 | soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE); | ||
| 800 | /* Disable Receiver data Time out interrupt */ | ||
| 801 | soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE); | ||
| 802 | /* set out2 = interrupt unmask; off() doesn't set MCR | ||
| 803 | on NSLU2 */ | ||
| 804 | soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); | ||
| 805 | } | ||
| 806 | #endif | ||
| 807 | |||
| 808 | /* Set line for power source */ | ||
| 809 | off(); | ||
| 810 | |||
| 811 | /* Clear registers again to be sure. */ | ||
| 812 | sinp(UART_LSR); | ||
| 813 | sinp(UART_RX); | ||
| 814 | sinp(UART_IIR); | ||
| 815 | sinp(UART_MSR); | ||
| 816 | |||
| 817 | switch (type) { | ||
| 818 | case LIRC_IRDEO: | ||
| 819 | case LIRC_IRDEO_REMOTE: | ||
| 820 | /* setup port to 7N1 @ 115200 Baud */ | ||
| 821 | /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ | ||
| 822 | |||
| 823 | /* Set DLAB 1. */ | ||
| 824 | soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); | ||
| 825 | /* Set divisor to 1 => 115200 Baud */ | ||
| 826 | soutp(UART_DLM, 0); | ||
| 827 | soutp(UART_DLL, 1); | ||
| 828 | /* Set DLAB 0 + 7N1 */ | ||
| 829 | soutp(UART_LCR, UART_LCR_WLEN7); | ||
| 830 | /* THR interrupt already disabled at this point */ | ||
| 831 | break; | ||
| 832 | default: | ||
| 833 | break; | ||
| 834 | } | ||
| 835 | |||
| 836 | return 0; | ||
| 837 | } | ||
| 838 | |||
| 839 | static int init_port(void) | ||
| 840 | { | ||
| 841 | int i, nlow, nhigh, result; | ||
| 842 | |||
| 843 | result = request_irq(irq, irq_handler, | ||
| 844 | IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0), | ||
| 845 | LIRC_DRIVER_NAME, (void *)&hardware); | ||
| 846 | |||
| 847 | switch (result) { | ||
| 848 | case -EBUSY: | ||
| 849 | printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); | ||
| 850 | return -EBUSY; | ||
| 851 | case -EINVAL: | ||
| 852 | printk(KERN_ERR LIRC_DRIVER_NAME | ||
| 853 | ": Bad irq number or handler\n"); | ||
| 854 | return -EINVAL; | ||
| 855 | default: | ||
| 856 | break; | ||
| 857 | }; | ||
| 858 | |||
| 859 | /* Reserve io region. */ | ||
| 860 | /* | ||
| 861 | * Future MMAP-Developers: Attention! | ||
| 862 | * For memory mapped I/O you *might* need to use ioremap() first, | ||
| 863 | * for the NSLU2 it's done in boot code. | ||
| 864 | */ | ||
| 865 | if (((iommap != 0) | ||
| 866 | && (request_mem_region(iommap, 8 << ioshift, | ||
| 867 | LIRC_DRIVER_NAME) == NULL)) | ||
| 868 | || ((iommap == 0) | ||
| 869 | && (request_region(io, 8, LIRC_DRIVER_NAME) == NULL))) { | ||
| 870 | printk(KERN_ERR LIRC_DRIVER_NAME | ||
| 871 | ": port %04x already in use\n", io); | ||
| 872 | printk(KERN_WARNING LIRC_DRIVER_NAME | ||
| 873 | ": use 'setserial /dev/ttySX uart none'\n"); | ||
| 874 | printk(KERN_WARNING LIRC_DRIVER_NAME | ||
| 875 | ": or compile the serial port driver as module and\n"); | ||
| 876 | printk(KERN_WARNING LIRC_DRIVER_NAME | ||
| 877 | ": make sure this module is loaded first\n"); | ||
| 878 | return -EBUSY; | ||
| 879 | } | ||
| 880 | |||
| 881 | if (hardware_init_port() < 0) | ||
| 882 | return -EINVAL; | ||
| 883 | |||
| 884 | /* Initialize pulse/space widths */ | ||
| 885 | init_timing_params(duty_cycle, freq); | ||
| 886 | |||
| 887 | /* If pin is high, then this must be an active low receiver. */ | ||
| 888 | if (sense == -1) { | ||
| 889 | /* wait 1/2 sec for the power supply */ | ||
| 890 | msleep(500); | ||
| 891 | |||
| 892 | /* | ||
| 893 | * probe 9 times every 0.04s, collect "votes" for | ||
| 894 | * active high/low | ||
| 895 | */ | ||
| 896 | nlow = 0; | ||
| 897 | nhigh = 0; | ||
| 898 | for (i = 0; i < 9; i++) { | ||
| 899 | if (sinp(UART_MSR) & hardware[type].signal_pin) | ||
| 900 | nlow++; | ||
| 901 | else | ||
| 902 | nhigh++; | ||
| 903 | msleep(40); | ||
| 904 | } | ||
| 905 | sense = (nlow >= nhigh ? 1 : 0); | ||
| 906 | printk(KERN_INFO LIRC_DRIVER_NAME ": auto-detected active " | ||
| 907 | "%s receiver\n", sense ? "low" : "high"); | ||
| 908 | } else | ||
| 909 | printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " | ||
| 910 | "%s receiver\n", sense ? "low" : "high"); | ||
| 911 | |||
| 912 | dprintk("Interrupt %d, port %04x obtained\n", irq, io); | ||
| 913 | return 0; | ||
| 914 | } | ||
| 915 | |||
| 916 | static int set_use_inc(void *data) | ||
| 917 | { | ||
| 918 | unsigned long flags; | ||
| 919 | |||
| 920 | /* initialize timestamp */ | ||
| 921 | do_gettimeofday(&lasttv); | ||
| 922 | |||
| 923 | spin_lock_irqsave(&hardware[type].lock, flags); | ||
| 924 | |||
| 925 | /* Set DLAB 0. */ | ||
| 926 | soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); | ||
| 927 | |||
| 928 | soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); | ||
| 929 | |||
| 930 | spin_unlock_irqrestore(&hardware[type].lock, flags); | ||
| 931 | |||
| 932 | return 0; | ||
| 933 | } | ||
| 934 | |||
| 935 | static void set_use_dec(void *data) | ||
| 936 | { unsigned long flags; | ||
| 937 | |||
| 938 | spin_lock_irqsave(&hardware[type].lock, flags); | ||
| 939 | |||
| 940 | /* Set DLAB 0. */ | ||
| 941 | soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); | ||
| 942 | |||
| 943 | /* First of all, disable all interrupts */ | ||
| 944 | soutp(UART_IER, sinp(UART_IER) & | ||
| 945 | (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); | ||
| 946 | spin_unlock_irqrestore(&hardware[type].lock, flags); | ||
| 947 | } | ||
| 948 | |||
| 949 | static ssize_t lirc_write(struct file *file, const char *buf, | ||
| 950 | size_t n, loff_t *ppos) | ||
| 951 | { | ||
| 952 | int i, count; | ||
| 953 | unsigned long flags; | ||
| 954 | long delta = 0; | ||
| 955 | int *wbuf; | ||
| 956 | |||
| 957 | if (!(hardware[type].features & LIRC_CAN_SEND_PULSE)) | ||
| 958 | return -EBADF; | ||
| 959 | |||
| 960 | count = n / sizeof(int); | ||
| 961 | if (n % sizeof(int) || count % 2 == 0) | ||
| 962 | return -EINVAL; | ||
| 963 | wbuf = memdup_user(buf, n); | ||
| 964 | if (IS_ERR(wbuf)) | ||
| 965 | return PTR_ERR(wbuf); | ||
| 966 | spin_lock_irqsave(&hardware[type].lock, flags); | ||
| 967 | if (type == LIRC_IRDEO) { | ||
| 968 | /* DTR, RTS down */ | ||
| 969 | on(); | ||
| 970 | } | ||
| 971 | for (i = 0; i < count; i++) { | ||
| 972 | if (i%2) | ||
| 973 | hardware[type].send_space(wbuf[i] - delta); | ||
| 974 | else | ||
| 975 | delta = hardware[type].send_pulse(wbuf[i]); | ||
| 976 | } | ||
| 977 | off(); | ||
| 978 | spin_unlock_irqrestore(&hardware[type].lock, flags); | ||
| 979 | kfree(wbuf); | ||
| 980 | return n; | ||
| 981 | } | ||
| 982 | |||
| 983 | static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) | ||
| 984 | { | ||
| 985 | int result; | ||
| 986 | __u32 value; | ||
| 987 | |||
| 988 | switch (cmd) { | ||
| 989 | case LIRC_GET_SEND_MODE: | ||
| 990 | if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) | ||
| 991 | return -ENOIOCTLCMD; | ||
| 992 | |||
| 993 | result = put_user(LIRC_SEND2MODE | ||
| 994 | (hardware[type].features&LIRC_CAN_SEND_MASK), | ||
| 995 | (__u32 *) arg); | ||
| 996 | if (result) | ||
| 997 | return result; | ||
| 998 | break; | ||
| 999 | |||
| 1000 | case LIRC_SET_SEND_MODE: | ||
| 1001 | if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) | ||
| 1002 | return -ENOIOCTLCMD; | ||
| 1003 | |||
| 1004 | result = get_user(value, (__u32 *) arg); | ||
| 1005 | if (result) | ||
| 1006 | return result; | ||
| 1007 | /* only LIRC_MODE_PULSE supported */ | ||
| 1008 | if (value != LIRC_MODE_PULSE) | ||
| 1009 | return -ENOSYS; | ||
| 1010 | break; | ||
| 1011 | |||
| 1012 | case LIRC_GET_LENGTH: | ||
| 1013 | return -ENOSYS; | ||
| 1014 | break; | ||
| 1015 | |||
| 1016 | case LIRC_SET_SEND_DUTY_CYCLE: | ||
| 1017 | dprintk("SET_SEND_DUTY_CYCLE\n"); | ||
| 1018 | if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE)) | ||
| 1019 | return -ENOIOCTLCMD; | ||
| 1020 | |||
| 1021 | result = get_user(value, (__u32 *) arg); | ||
| 1022 | if (result) | ||
| 1023 | return result; | ||
| 1024 | if (value <= 0 || value > 100) | ||
| 1025 | return -EINVAL; | ||
| 1026 | return init_timing_params(value, freq); | ||
| 1027 | break; | ||
| 1028 | |||
| 1029 | case LIRC_SET_SEND_CARRIER: | ||
| 1030 | dprintk("SET_SEND_CARRIER\n"); | ||
| 1031 | if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER)) | ||
| 1032 | return -ENOIOCTLCMD; | ||
| 1033 | |||
| 1034 | result = get_user(value, (__u32 *) arg); | ||
| 1035 | if (result) | ||
| 1036 | return result; | ||
| 1037 | if (value > 500000 || value < 20000) | ||
| 1038 | return -EINVAL; | ||
| 1039 | return init_timing_params(duty_cycle, value); | ||
| 1040 | break; | ||
| 1041 | |||
| 1042 | default: | ||
| 1043 | return lirc_dev_fop_ioctl(filep, cmd, arg); | ||
| 1044 | } | ||
| 1045 | return 0; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | static const struct file_operations lirc_fops = { | ||
| 1049 | .owner = THIS_MODULE, | ||
| 1050 | .write = lirc_write, | ||
| 1051 | .unlocked_ioctl = lirc_ioctl, | ||
| 1052 | #ifdef CONFIG_COMPAT | ||
| 1053 | .compat_ioctl = lirc_ioctl, | ||
| 1054 | #endif | ||
| 1055 | .read = lirc_dev_fop_read, | ||
| 1056 | .poll = lirc_dev_fop_poll, | ||
| 1057 | .open = lirc_dev_fop_open, | ||
| 1058 | .release = lirc_dev_fop_close, | ||
| 1059 | .llseek = no_llseek, | ||
| 1060 | }; | ||
| 1061 | |||
| 1062 | static struct lirc_driver driver = { | ||
| 1063 | .name = LIRC_DRIVER_NAME, | ||
| 1064 | .minor = -1, | ||
| 1065 | .code_length = 1, | ||
| 1066 | .sample_rate = 0, | ||
| 1067 | .data = NULL, | ||
| 1068 | .add_to_buf = NULL, | ||
| 1069 | .rbuf = &rbuf, | ||
| 1070 | .set_use_inc = set_use_inc, | ||
| 1071 | .set_use_dec = set_use_dec, | ||
| 1072 | .fops = &lirc_fops, | ||
| 1073 | .dev = NULL, | ||
| 1074 | .owner = THIS_MODULE, | ||
| 1075 | }; | ||
| 1076 | |||
| 1077 | static struct platform_device *lirc_serial_dev; | ||
| 1078 | |||
| 1079 | static int __devinit lirc_serial_probe(struct platform_device *dev) | ||
| 1080 | { | ||
| 1081 | return 0; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | static int __devexit lirc_serial_remove(struct platform_device *dev) | ||
| 1085 | { | ||
| 1086 | return 0; | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | static int lirc_serial_suspend(struct platform_device *dev, | ||
| 1090 | pm_message_t state) | ||
| 1091 | { | ||
| 1092 | /* Set DLAB 0. */ | ||
| 1093 | soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); | ||
| 1094 | |||
| 1095 | /* Disable all interrupts */ | ||
| 1096 | soutp(UART_IER, sinp(UART_IER) & | ||
| 1097 | (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); | ||
| 1098 | |||
| 1099 | /* Clear registers. */ | ||
| 1100 | sinp(UART_LSR); | ||
| 1101 | sinp(UART_RX); | ||
| 1102 | sinp(UART_IIR); | ||
| 1103 | sinp(UART_MSR); | ||
| 1104 | |||
| 1105 | return 0; | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | /* twisty maze... need a forward-declaration here... */ | ||
| 1109 | static void lirc_serial_exit(void); | ||
| 1110 | |||
| 1111 | static int lirc_serial_resume(struct platform_device *dev) | ||
| 1112 | { | ||
| 1113 | unsigned long flags; | ||
| 1114 | |||
| 1115 | if (hardware_init_port() < 0) { | ||
| 1116 | lirc_serial_exit(); | ||
| 1117 | return -EINVAL; | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | spin_lock_irqsave(&hardware[type].lock, flags); | ||
| 1121 | /* Enable Interrupt */ | ||
| 1122 | do_gettimeofday(&lasttv); | ||
| 1123 | soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); | ||
| 1124 | off(); | ||
| 1125 | |||
| 1126 | lirc_buffer_clear(&rbuf); | ||
| 1127 | |||
| 1128 | spin_unlock_irqrestore(&hardware[type].lock, flags); | ||
| 1129 | |||
| 1130 | return 0; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | static struct platform_driver lirc_serial_driver = { | ||
| 1134 | .probe = lirc_serial_probe, | ||
| 1135 | .remove = __devexit_p(lirc_serial_remove), | ||
| 1136 | .suspend = lirc_serial_suspend, | ||
| 1137 | .resume = lirc_serial_resume, | ||
| 1138 | .driver = { | ||
| 1139 | .name = "lirc_serial", | ||
| 1140 | .owner = THIS_MODULE, | ||
| 1141 | }, | ||
| 1142 | }; | ||
| 1143 | |||
| 1144 | static int __init lirc_serial_init(void) | ||
| 1145 | { | ||
| 1146 | int result; | ||
| 1147 | |||
| 1148 | /* Init read buffer. */ | ||
| 1149 | result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN); | ||
| 1150 | if (result < 0) | ||
| 1151 | return -ENOMEM; | ||
| 1152 | |||
| 1153 | result = platform_driver_register(&lirc_serial_driver); | ||
| 1154 | if (result) { | ||
| 1155 | printk("lirc register returned %d\n", result); | ||
| 1156 | goto exit_buffer_free; | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | lirc_serial_dev = platform_device_alloc("lirc_serial", 0); | ||
| 1160 | if (!lirc_serial_dev) { | ||
| 1161 | result = -ENOMEM; | ||
| 1162 | goto exit_driver_unregister; | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | result = platform_device_add(lirc_serial_dev); | ||
| 1166 | if (result) | ||
| 1167 | goto exit_device_put; | ||
| 1168 | |||
| 1169 | return 0; | ||
| 1170 | |||
| 1171 | exit_device_put: | ||
| 1172 | platform_device_put(lirc_serial_dev); | ||
| 1173 | exit_driver_unregister: | ||
| 1174 | platform_driver_unregister(&lirc_serial_driver); | ||
| 1175 | exit_buffer_free: | ||
| 1176 | lirc_buffer_free(&rbuf); | ||
| 1177 | return result; | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | static void lirc_serial_exit(void) | ||
| 1181 | { | ||
| 1182 | platform_device_unregister(lirc_serial_dev); | ||
| 1183 | platform_driver_unregister(&lirc_serial_driver); | ||
| 1184 | lirc_buffer_free(&rbuf); | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | static int __init lirc_serial_init_module(void) | ||
| 1188 | { | ||
| 1189 | int result; | ||
| 1190 | |||
| 1191 | result = lirc_serial_init(); | ||
| 1192 | if (result) | ||
| 1193 | return result; | ||
| 1194 | |||
| 1195 | switch (type) { | ||
| 1196 | case LIRC_HOMEBREW: | ||
| 1197 | case LIRC_IRDEO: | ||
| 1198 | case LIRC_IRDEO_REMOTE: | ||
| 1199 | case LIRC_ANIMAX: | ||
| 1200 | case LIRC_IGOR: | ||
| 1201 | /* if nothing specified, use ttyS0/com1 and irq 4 */ | ||
| 1202 | io = io ? io : 0x3f8; | ||
| 1203 | irq = irq ? irq : 4; | ||
| 1204 | break; | ||
| 1205 | #ifdef CONFIG_LIRC_SERIAL_NSLU2 | ||
| 1206 | case LIRC_NSLU2: | ||
| 1207 | io = io ? io : IRQ_IXP4XX_UART2; | ||
| 1208 | irq = irq ? irq : (IXP4XX_UART2_BASE_VIRT + REG_OFFSET); | ||
| 1209 | iommap = iommap ? iommap : IXP4XX_UART2_BASE_PHYS; | ||
| 1210 | ioshift = ioshift ? ioshift : 2; | ||
| 1211 | break; | ||
| 1212 | #endif | ||
| 1213 | default: | ||
| 1214 | result = -EINVAL; | ||
| 1215 | goto exit_serial_exit; | ||
| 1216 | } | ||
| 1217 | if (!softcarrier) { | ||
| 1218 | switch (type) { | ||
| 1219 | case LIRC_HOMEBREW: | ||
| 1220 | case LIRC_IGOR: | ||
| 1221 | #ifdef CONFIG_LIRC_SERIAL_NSLU2 | ||
| 1222 | case LIRC_NSLU2: | ||
| 1223 | #endif | ||
| 1224 | hardware[type].features &= | ||
| 1225 | ~(LIRC_CAN_SET_SEND_DUTY_CYCLE| | ||
| 1226 | LIRC_CAN_SET_SEND_CARRIER); | ||
| 1227 | break; | ||
| 1228 | } | ||
| 1229 | } | ||
| 1230 | |||
| 1231 | result = init_port(); | ||
| 1232 | if (result < 0) | ||
| 1233 | goto exit_serial_exit; | ||
| 1234 | driver.features = hardware[type].features; | ||
| 1235 | driver.dev = &lirc_serial_dev->dev; | ||
| 1236 | driver.minor = lirc_register_driver(&driver); | ||
| 1237 | if (driver.minor < 0) { | ||
| 1238 | printk(KERN_ERR LIRC_DRIVER_NAME | ||
| 1239 | ": register_chrdev failed!\n"); | ||
| 1240 | result = -EIO; | ||
| 1241 | goto exit_release; | ||
| 1242 | } | ||
| 1243 | return 0; | ||
| 1244 | exit_release: | ||
| 1245 | release_region(io, 8); | ||
| 1246 | exit_serial_exit: | ||
| 1247 | lirc_serial_exit(); | ||
| 1248 | return result; | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | static void __exit lirc_serial_exit_module(void) | ||
| 1252 | { | ||
| 1253 | lirc_serial_exit(); | ||
| 1254 | |||
| 1255 | free_irq(irq, (void *)&hardware); | ||
| 1256 | |||
| 1257 | if (iommap != 0) | ||
| 1258 | release_mem_region(iommap, 8 << ioshift); | ||
| 1259 | else | ||
| 1260 | release_region(io, 8); | ||
| 1261 | lirc_unregister_driver(driver.minor); | ||
| 1262 | dprintk("cleaned up module\n"); | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | |||
| 1266 | module_init(lirc_serial_init_module); | ||
| 1267 | module_exit(lirc_serial_exit_module); | ||
| 1268 | |||
| 1269 | MODULE_DESCRIPTION("Infra-red receiver driver for serial ports."); | ||
| 1270 | MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, " | ||
| 1271 | "Christoph Bartelmus, Andrei Tanas"); | ||
| 1272 | MODULE_LICENSE("GPL"); | ||
| 1273 | |||
| 1274 | module_param(type, int, S_IRUGO); | ||
| 1275 | MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo," | ||
| 1276 | " 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug," | ||
| 1277 | " 5 = NSLU2 RX:CTS2/TX:GreenLED)"); | ||
| 1278 | |||
| 1279 | module_param(io, int, S_IRUGO); | ||
| 1280 | MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); | ||
| 1281 | |||
| 1282 | /* some architectures (e.g. intel xscale) have memory mapped registers */ | ||
| 1283 | module_param(iommap, bool, S_IRUGO); | ||
| 1284 | MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O" | ||
| 1285 | " (0 = no memory mapped io)"); | ||
| 1286 | |||
| 1287 | /* | ||
| 1288 | * some architectures (e.g. intel xscale) align the 8bit serial registers | ||
| 1289 | * on 32bit word boundaries. | ||
| 1290 | * See linux-kernel/serial/8250.c serial_in()/out() | ||
| 1291 | */ | ||
| 1292 | module_param(ioshift, int, S_IRUGO); | ||
| 1293 | MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)"); | ||
| 1294 | |||
| 1295 | module_param(irq, int, S_IRUGO); | ||
| 1296 | MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); | ||
| 1297 | |||
| 1298 | module_param(share_irq, bool, S_IRUGO); | ||
| 1299 | MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)"); | ||
| 1300 | |||
| 1301 | module_param(sense, bool, S_IRUGO); | ||
| 1302 | MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit" | ||
| 1303 | " (0 = active high, 1 = active low )"); | ||
| 1304 | |||
| 1305 | #ifdef CONFIG_LIRC_SERIAL_TRANSMITTER | ||
| 1306 | module_param(txsense, bool, S_IRUGO); | ||
| 1307 | MODULE_PARM_DESC(txsense, "Sense of transmitter circuit" | ||
| 1308 | " (0 = active high, 1 = active low )"); | ||
| 1309 | #endif | ||
| 1310 | |||
| 1311 | module_param(softcarrier, bool, S_IRUGO); | ||
| 1312 | MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)"); | ||
| 1313 | |||
| 1314 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
| 1315 | MODULE_PARM_DESC(debug, "Enable debugging messages"); | ||
diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c new file mode 100644 index 00000000000..0d3864594b1 --- /dev/null +++ b/drivers/staging/lirc/lirc_sir.c | |||
| @@ -0,0 +1,1279 @@ | |||
| 1 | /* | ||
| 2 | * LIRC SIR driver, (C) 2000 Milan Pikula <www@fornax.sk> | ||
| 3 | * | ||
| 4 | * lirc_sir - Device driver for use with SIR (serial infra red) | ||
| 5 | * mode of IrDA on many notebooks. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | * | ||
| 21 | * | ||
| 22 | * 2000/09/16 Frank Przybylski <mail@frankprzybylski.de> : | ||
| 23 | * added timeout and relaxed pulse detection, removed gap bug | ||
| 24 | * | ||
| 25 | * 2000/12/15 Christoph Bartelmus <lirc@bartelmus.de> : | ||
| 26 | * added support for Tekram Irmate 210 (sending does not work yet, | ||
| 27 | * kind of disappointing that nobody was able to implement that | ||
| 28 | * before), | ||
| 29 | * major clean-up | ||
| 30 | * | ||
| 31 | * 2001/02/27 Christoph Bartelmus <lirc@bartelmus.de> : | ||
| 32 | * added support for StrongARM SA1100 embedded microprocessor | ||
| 33 | * parts cut'n'pasted from sa1100_ir.c (C) 2000 Russell King | ||
| 34 | */ | ||
| 35 | |||
| 36 | #include <linux/module.h> | ||
| 37 | #include <linux/sched.h> | ||
| 38 | #include <linux/errno.h> | ||
| 39 | #include <linux/signal.h> | ||
| 40 | #include <linux/fs.h> | ||
| 41 | #include <linux/interrupt.h> | ||
| 42 | #include <linux/ioport.h> | ||
| 43 | #include <linux/kernel.h> | ||
| 44 | #include <linux/serial_reg.h> | ||
| 45 | #include <linux/time.h> | ||
| 46 | #include <linux/string.h> | ||
| 47 | #include <linux/types.h> | ||
| 48 | #include <linux/wait.h> | ||
| 49 | #include <linux/mm.h> | ||
| 50 | #include <linux/delay.h> | ||
| 51 | #include <linux/poll.h> | ||
| 52 | #include <asm/system.h> | ||
| 53 | #include <linux/io.h> | ||
| 54 | #include <asm/irq.h> | ||
| 55 | #include <linux/fcntl.h> | ||
| 56 | #ifdef LIRC_ON_SA1100 | ||
| 57 | #include <asm/hardware.h> | ||
| 58 | #ifdef CONFIG_SA1100_COLLIE | ||
| 59 | #include <asm/arch/tc35143.h> | ||
| 60 | #include <asm/ucb1200.h> | ||
| 61 | #endif | ||
| 62 | #endif | ||
| 63 | |||
| 64 | #include <linux/timer.h> | ||
| 65 | |||
| 66 | #include <media/lirc.h> | ||
| 67 | #include <media/lirc_dev.h> | ||
| 68 | |||
| 69 | /* SECTION: Definitions */ | ||
| 70 | |||
| 71 | /*** Tekram dongle ***/ | ||
| 72 | #ifdef LIRC_SIR_TEKRAM | ||
| 73 | /* stolen from kernel source */ | ||
| 74 | /* definitions for Tekram dongle */ | ||
| 75 | #define TEKRAM_115200 0x00 | ||
| 76 | #define TEKRAM_57600 0x01 | ||
| 77 | #define TEKRAM_38400 0x02 | ||
| 78 | #define TEKRAM_19200 0x03 | ||
| 79 | #define TEKRAM_9600 0x04 | ||
| 80 | #define TEKRAM_2400 0x08 | ||
| 81 | |||
| 82 | #define TEKRAM_PW 0x10 /* Pulse select bit */ | ||
| 83 | |||
| 84 | /* 10bit * 1s/115200bit in milliseconds = 87ms*/ | ||
| 85 | #define TIME_CONST (10000000ul/115200ul) | ||
| 86 | |||
| 87 | #endif | ||
| 88 | |||
| 89 | #ifdef LIRC_SIR_ACTISYS_ACT200L | ||
| 90 | static void init_act200(void); | ||
| 91 | #elif defined(LIRC_SIR_ACTISYS_ACT220L) | ||
| 92 | static void init_act220(void); | ||
| 93 | #endif | ||
| 94 | |||
| 95 | /*** SA1100 ***/ | ||
| 96 | #ifdef LIRC_ON_SA1100 | ||
| 97 | struct sa1100_ser2_registers { | ||
| 98 | /* HSSP control register */ | ||
| 99 | unsigned char hscr0; | ||
| 100 | /* UART registers */ | ||
| 101 | unsigned char utcr0; | ||
| 102 | unsigned char utcr1; | ||
| 103 | unsigned char utcr2; | ||
| 104 | unsigned char utcr3; | ||
| 105 | unsigned char utcr4; | ||
| 106 | unsigned char utdr; | ||
| 107 | unsigned char utsr0; | ||
| 108 | unsigned char utsr1; | ||
| 109 | } sr; | ||
| 110 | |||
| 111 | static int irq = IRQ_Ser2ICP; | ||
| 112 | |||
| 113 | #define LIRC_ON_SA1100_TRANSMITTER_LATENCY 0 | ||
| 114 | |||
| 115 | /* pulse/space ratio of 50/50 */ | ||
| 116 | static unsigned long pulse_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); | ||
| 117 | /* 1000000/freq-pulse_width */ | ||
| 118 | static unsigned long space_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); | ||
| 119 | static unsigned int freq = 38000; /* modulation frequency */ | ||
| 120 | static unsigned int duty_cycle = 50; /* duty cycle of 50% */ | ||
| 121 | |||
| 122 | #endif | ||
| 123 | |||
| 124 | #define RBUF_LEN 1024 | ||
| 125 | #define WBUF_LEN 1024 | ||
| 126 | |||
| 127 | #define LIRC_DRIVER_NAME "lirc_sir" | ||
| 128 | |||
| 129 | #define PULSE '[' | ||
| 130 | |||
| 131 | #ifndef LIRC_SIR_TEKRAM | ||
| 132 | /* 9bit * 1s/115200bit in milli seconds = 78.125ms*/ | ||
| 133 | #define TIME_CONST (9000000ul/115200ul) | ||
| 134 | #endif | ||
| 135 | |||
| 136 | |||
| 137 | /* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */ | ||
| 138 | #define SIR_TIMEOUT (HZ*5/100) | ||
| 139 | |||
| 140 | #ifndef LIRC_ON_SA1100 | ||
| 141 | #ifndef LIRC_IRQ | ||
| 142 | #define LIRC_IRQ 4 | ||
| 143 | #endif | ||
| 144 | #ifndef LIRC_PORT | ||
| 145 | /* for external dongles, default to com1 */ | ||
| 146 | #if defined(LIRC_SIR_ACTISYS_ACT200L) || \ | ||
| 147 | defined(LIRC_SIR_ACTISYS_ACT220L) || \ | ||
| 148 | defined(LIRC_SIR_TEKRAM) | ||
| 149 | #define LIRC_PORT 0x3f8 | ||
| 150 | #else | ||
| 151 | /* onboard sir ports are typically com3 */ | ||
| 152 | #define LIRC_PORT 0x3e8 | ||
| 153 | #endif | ||
| 154 | #endif | ||
| 155 | |||
| 156 | static int io = LIRC_PORT; | ||
| 157 | static int irq = LIRC_IRQ; | ||
| 158 | static int threshold = 3; | ||
| 159 | #endif | ||
| 160 | |||
| 161 | static DEFINE_SPINLOCK(timer_lock); | ||
| 162 | static struct timer_list timerlist; | ||
| 163 | /* time of last signal change detected */ | ||
| 164 | static struct timeval last_tv = {0, 0}; | ||
| 165 | /* time of last UART data ready interrupt */ | ||
| 166 | static struct timeval last_intr_tv = {0, 0}; | ||
| 167 | static int last_value; | ||
| 168 | |||
| 169 | static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); | ||
| 170 | |||
| 171 | static DEFINE_SPINLOCK(hardware_lock); | ||
| 172 | |||
| 173 | static int rx_buf[RBUF_LEN]; | ||
| 174 | static unsigned int rx_tail, rx_head; | ||
| 175 | |||
| 176 | static int debug; | ||
| 177 | #define dprintk(fmt, args...) \ | ||
| 178 | do { \ | ||
| 179 | if (debug) \ | ||
| 180 | printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ | ||
| 181 | fmt, ## args); \ | ||
| 182 | } while (0) | ||
| 183 | |||
| 184 | /* SECTION: Prototypes */ | ||
| 185 | |||
| 186 | /* Communication with user-space */ | ||
| 187 | static unsigned int lirc_poll(struct file *file, poll_table *wait); | ||
| 188 | static ssize_t lirc_read(struct file *file, char *buf, size_t count, | ||
| 189 | loff_t *ppos); | ||
| 190 | static ssize_t lirc_write(struct file *file, const char *buf, size_t n, | ||
| 191 | loff_t *pos); | ||
| 192 | static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | ||
| 193 | static void add_read_queue(int flag, unsigned long val); | ||
| 194 | static int init_chrdev(void); | ||
| 195 | static void drop_chrdev(void); | ||
| 196 | /* Hardware */ | ||
| 197 | static irqreturn_t sir_interrupt(int irq, void *dev_id); | ||
| 198 | static void send_space(unsigned long len); | ||
| 199 | static void send_pulse(unsigned long len); | ||
| 200 | static int init_hardware(void); | ||
| 201 | static void drop_hardware(void); | ||
| 202 | /* Initialisation */ | ||
| 203 | static int init_port(void); | ||
| 204 | static void drop_port(void); | ||
| 205 | |||
| 206 | #ifdef LIRC_ON_SA1100 | ||
| 207 | static void on(void) | ||
| 208 | { | ||
| 209 | PPSR |= PPC_TXD2; | ||
| 210 | } | ||
| 211 | |||
| 212 | static void off(void) | ||
| 213 | { | ||
| 214 | PPSR &= ~PPC_TXD2; | ||
| 215 | } | ||
| 216 | #else | ||
| 217 | static inline unsigned int sinp(int offset) | ||
| 218 | { | ||
| 219 | return inb(io + offset); | ||
| 220 | } | ||
| 221 | |||
| 222 | static inline void soutp(int offset, int value) | ||
| 223 | { | ||
| 224 | outb(value, io + offset); | ||
| 225 | } | ||
| 226 | #endif | ||
| 227 | |||
| 228 | #ifndef MAX_UDELAY_MS | ||
| 229 | #define MAX_UDELAY_US 5000 | ||
| 230 | #else | ||
| 231 | #define MAX_UDELAY_US (MAX_UDELAY_MS*1000) | ||
| 232 | #endif | ||
| 233 | |||
| 234 | static void safe_udelay(unsigned long usecs) | ||
| 235 | { | ||
| 236 | while (usecs > MAX_UDELAY_US) { | ||
| 237 | udelay(MAX_UDELAY_US); | ||
| 238 | usecs -= MAX_UDELAY_US; | ||
| 239 | } | ||
| 240 | udelay(usecs); | ||
| 241 | } | ||
| 242 | |||
| 243 | /* SECTION: Communication with user-space */ | ||
| 244 | |||
| 245 | static unsigned int lirc_poll(struct file *file, poll_table *wait) | ||
| 246 | { | ||
| 247 | poll_wait(file, &lirc_read_queue, wait); | ||
| 248 | if (rx_head != rx_tail) | ||
| 249 | return POLLIN | POLLRDNORM; | ||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | static ssize_t lirc_read(struct file *file, char *buf, size_t count, | ||
| 254 | loff_t *ppos) | ||
| 255 | { | ||
| 256 | int n = 0; | ||
| 257 | int retval = 0; | ||
| 258 | DECLARE_WAITQUEUE(wait, current); | ||
| 259 | |||
| 260 | if (count % sizeof(int)) | ||
| 261 | return -EINVAL; | ||
| 262 | |||
| 263 | add_wait_queue(&lirc_read_queue, &wait); | ||
| 264 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 265 | while (n < count) { | ||
| 266 | if (rx_head != rx_tail) { | ||
| 267 | if (copy_to_user((void *) buf + n, | ||
| 268 | (void *) (rx_buf + rx_head), | ||
| 269 | sizeof(int))) { | ||
| 270 | retval = -EFAULT; | ||
| 271 | break; | ||
| 272 | } | ||
| 273 | rx_head = (rx_head + 1) & (RBUF_LEN - 1); | ||
| 274 | n += sizeof(int); | ||
| 275 | } else { | ||
| 276 | if (file->f_flags & O_NONBLOCK) { | ||
| 277 | retval = -EAGAIN; | ||
| 278 | break; | ||
| 279 | } | ||
| 280 | if (signal_pending(current)) { | ||
| 281 | retval = -ERESTARTSYS; | ||
| 282 | break; | ||
| 283 | } | ||
| 284 | schedule(); | ||
| 285 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 286 | } | ||
| 287 | } | ||
| 288 | remove_wait_queue(&lirc_read_queue, &wait); | ||
| 289 | set_current_state(TASK_RUNNING); | ||
| 290 | return n ? n : retval; | ||
| 291 | } | ||
| 292 | static ssize_t lirc_write(struct file *file, const char *buf, size_t n, | ||
| 293 | loff_t *pos) | ||
| 294 | { | ||
| 295 | unsigned long flags; | ||
| 296 | int i, count; | ||
| 297 | int *tx_buf; | ||
| 298 | |||
| 299 | count = n / sizeof(int); | ||
| 300 | if (n % sizeof(int) || count % 2 == 0) | ||
| 301 | return -EINVAL; | ||
| 302 | tx_buf = memdup_user(buf, n); | ||
| 303 | if (IS_ERR(tx_buf)) | ||
| 304 | return PTR_ERR(tx_buf); | ||
| 305 | i = 0; | ||
| 306 | #ifdef LIRC_ON_SA1100 | ||
| 307 | /* disable receiver */ | ||
| 308 | Ser2UTCR3 = 0; | ||
| 309 | #endif | ||
| 310 | local_irq_save(flags); | ||
| 311 | while (1) { | ||
| 312 | if (i >= count) | ||
| 313 | break; | ||
| 314 | if (tx_buf[i]) | ||
| 315 | send_pulse(tx_buf[i]); | ||
| 316 | i++; | ||
| 317 | if (i >= count) | ||
| 318 | break; | ||
| 319 | if (tx_buf[i]) | ||
| 320 | send_space(tx_buf[i]); | ||
| 321 | i++; | ||
| 322 | } | ||
| 323 | local_irq_restore(flags); | ||
| 324 | #ifdef LIRC_ON_SA1100 | ||
| 325 | off(); | ||
| 326 | udelay(1000); /* wait 1ms for IR diode to recover */ | ||
| 327 | Ser2UTCR3 = 0; | ||
| 328 | /* clear status register to prevent unwanted interrupts */ | ||
| 329 | Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); | ||
| 330 | /* enable receiver */ | ||
| 331 | Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; | ||
| 332 | #endif | ||
| 333 | kfree(tx_buf); | ||
| 334 | return count; | ||
| 335 | } | ||
| 336 | |||
| 337 | static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) | ||
| 338 | { | ||
| 339 | int retval = 0; | ||
| 340 | __u32 value = 0; | ||
| 341 | #ifdef LIRC_ON_SA1100 | ||
| 342 | |||
| 343 | if (cmd == LIRC_GET_FEATURES) | ||
| 344 | value = LIRC_CAN_SEND_PULSE | | ||
| 345 | LIRC_CAN_SET_SEND_DUTY_CYCLE | | ||
| 346 | LIRC_CAN_SET_SEND_CARRIER | | ||
| 347 | LIRC_CAN_REC_MODE2; | ||
| 348 | else if (cmd == LIRC_GET_SEND_MODE) | ||
| 349 | value = LIRC_MODE_PULSE; | ||
| 350 | else if (cmd == LIRC_GET_REC_MODE) | ||
| 351 | value = LIRC_MODE_MODE2; | ||
| 352 | #else | ||
| 353 | if (cmd == LIRC_GET_FEATURES) | ||
| 354 | value = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; | ||
| 355 | else if (cmd == LIRC_GET_SEND_MODE) | ||
| 356 | value = LIRC_MODE_PULSE; | ||
| 357 | else if (cmd == LIRC_GET_REC_MODE) | ||
| 358 | value = LIRC_MODE_MODE2; | ||
| 359 | #endif | ||
| 360 | |||
| 361 | switch (cmd) { | ||
| 362 | case LIRC_GET_FEATURES: | ||
| 363 | case LIRC_GET_SEND_MODE: | ||
| 364 | case LIRC_GET_REC_MODE: | ||
| 365 | retval = put_user(value, (__u32 *) arg); | ||
| 366 | break; | ||
| 367 | |||
| 368 | case LIRC_SET_SEND_MODE: | ||
| 369 | case LIRC_SET_REC_MODE: | ||
| 370 | retval = get_user(value, (__u32 *) arg); | ||
| 371 | break; | ||
| 372 | #ifdef LIRC_ON_SA1100 | ||
| 373 | case LIRC_SET_SEND_DUTY_CYCLE: | ||
| 374 | retval = get_user(value, (__u32 *) arg); | ||
| 375 | if (retval) | ||
| 376 | return retval; | ||
| 377 | if (value <= 0 || value > 100) | ||
| 378 | return -EINVAL; | ||
| 379 | /* (value/100)*(1000000/freq) */ | ||
| 380 | duty_cycle = value; | ||
| 381 | pulse_width = (unsigned long) duty_cycle*10000/freq; | ||
| 382 | space_width = (unsigned long) 1000000L/freq-pulse_width; | ||
| 383 | if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) | ||
| 384 | pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; | ||
| 385 | if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) | ||
| 386 | space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; | ||
| 387 | break; | ||
| 388 | case LIRC_SET_SEND_CARRIER: | ||
| 389 | retval = get_user(value, (__u32 *) arg); | ||
| 390 | if (retval) | ||
| 391 | return retval; | ||
| 392 | if (value > 500000 || value < 20000) | ||
| 393 | return -EINVAL; | ||
| 394 | freq = value; | ||
| 395 | pulse_width = (unsigned long) duty_cycle*10000/freq; | ||
| 396 | space_width = (unsigned long) 1000000L/freq-pulse_width; | ||
| 397 | if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) | ||
| 398 | pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; | ||
| 399 | if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) | ||
| 400 | space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; | ||
| 401 | break; | ||
| 402 | #endif | ||
| 403 | default: | ||
| 404 | retval = -ENOIOCTLCMD; | ||
| 405 | |||
| 406 | } | ||
| 407 | |||
| 408 | if (retval) | ||
| 409 | return retval; | ||
| 410 | if (cmd == LIRC_SET_REC_MODE) { | ||
| 411 | if (value != LIRC_MODE_MODE2) | ||
| 412 | retval = -ENOSYS; | ||
| 413 | } else if (cmd == LIRC_SET_SEND_MODE) { | ||
| 414 | if (value != LIRC_MODE_PULSE) | ||
| 415 | retval = -ENOSYS; | ||
| 416 | } | ||
| 417 | |||
| 418 | return retval; | ||
| 419 | } | ||
| 420 | |||
| 421 | static void add_read_queue(int flag, unsigned long val) | ||
| 422 | { | ||
| 423 | unsigned int new_rx_tail; | ||
| 424 | int newval; | ||
| 425 | |||
| 426 | dprintk("add flag %d with val %lu\n", flag, val); | ||
| 427 | |||
| 428 | newval = val & PULSE_MASK; | ||
| 429 | |||
| 430 | /* | ||
| 431 | * statistically, pulses are ~TIME_CONST/2 too long. we could | ||
| 432 | * maybe make this more exact, but this is good enough | ||
| 433 | */ | ||
| 434 | if (flag) { | ||
| 435 | /* pulse */ | ||
| 436 | if (newval > TIME_CONST/2) | ||
| 437 | newval -= TIME_CONST/2; | ||
| 438 | else /* should not ever happen */ | ||
| 439 | newval = 1; | ||
| 440 | newval |= PULSE_BIT; | ||
| 441 | } else { | ||
| 442 | newval += TIME_CONST/2; | ||
| 443 | } | ||
| 444 | new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); | ||
| 445 | if (new_rx_tail == rx_head) { | ||
| 446 | dprintk("Buffer overrun.\n"); | ||
| 447 | return; | ||
| 448 | } | ||
| 449 | rx_buf[rx_tail] = newval; | ||
| 450 | rx_tail = new_rx_tail; | ||
| 451 | wake_up_interruptible(&lirc_read_queue); | ||
| 452 | } | ||
| 453 | |||
| 454 | static const struct file_operations lirc_fops = { | ||
| 455 | .owner = THIS_MODULE, | ||
| 456 | .read = lirc_read, | ||
| 457 | .write = lirc_write, | ||
| 458 | .poll = lirc_poll, | ||
| 459 | .unlocked_ioctl = lirc_ioctl, | ||
| 460 | #ifdef CONFIG_COMPAT | ||
| 461 | .compat_ioctl = lirc_ioctl, | ||
| 462 | #endif | ||
| 463 | .open = lirc_dev_fop_open, | ||
| 464 | .release = lirc_dev_fop_close, | ||
| 465 | .llseek = no_llseek, | ||
| 466 | }; | ||
| 467 | |||
| 468 | static int set_use_inc(void *data) | ||
| 469 | { | ||
| 470 | return 0; | ||
| 471 | } | ||
| 472 | |||
| 473 | static void set_use_dec(void *data) | ||
| 474 | { | ||
| 475 | } | ||
| 476 | |||
| 477 | static struct lirc_driver driver = { | ||
| 478 | .name = LIRC_DRIVER_NAME, | ||
| 479 | .minor = -1, | ||
| 480 | .code_length = 1, | ||
| 481 | .sample_rate = 0, | ||
| 482 | .data = NULL, | ||
| 483 | .add_to_buf = NULL, | ||
| 484 | .set_use_inc = set_use_inc, | ||
| 485 | .set_use_dec = set_use_dec, | ||
| 486 | .fops = &lirc_fops, | ||
| 487 | .dev = NULL, | ||
| 488 | .owner = THIS_MODULE, | ||
| 489 | }; | ||
| 490 | |||
| 491 | |||
| 492 | static int init_chrdev(void) | ||
| 493 | { | ||
| 494 | driver.minor = lirc_register_driver(&driver); | ||
| 495 | if (driver.minor < 0) { | ||
| 496 | printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); | ||
| 497 | return -EIO; | ||
| 498 | } | ||
| 499 | return 0; | ||
| 500 | } | ||
| 501 | |||
| 502 | static void drop_chrdev(void) | ||
| 503 | { | ||
| 504 | lirc_unregister_driver(driver.minor); | ||
| 505 | } | ||
| 506 | |||
| 507 | /* SECTION: Hardware */ | ||
| 508 | static long delta(struct timeval *tv1, struct timeval *tv2) | ||
| 509 | { | ||
| 510 | unsigned long deltv; | ||
| 511 | |||
| 512 | deltv = tv2->tv_sec - tv1->tv_sec; | ||
| 513 | if (deltv > 15) | ||
| 514 | deltv = 0xFFFFFF; | ||
| 515 | else | ||
| 516 | deltv = deltv*1000000 + | ||
| 517 | tv2->tv_usec - | ||
| 518 | tv1->tv_usec; | ||
| 519 | return deltv; | ||
| 520 | } | ||
| 521 | |||
| 522 | static void sir_timeout(unsigned long data) | ||
| 523 | { | ||
| 524 | /* | ||
| 525 | * if last received signal was a pulse, but receiving stopped | ||
| 526 | * within the 9 bit frame, we need to finish this pulse and | ||
| 527 | * simulate a signal change to from pulse to space. Otherwise | ||
| 528 | * upper layers will receive two sequences next time. | ||
| 529 | */ | ||
| 530 | |||
| 531 | unsigned long flags; | ||
| 532 | unsigned long pulse_end; | ||
| 533 | |||
| 534 | /* avoid interference with interrupt */ | ||
| 535 | spin_lock_irqsave(&timer_lock, flags); | ||
| 536 | if (last_value) { | ||
| 537 | #ifndef LIRC_ON_SA1100 | ||
| 538 | /* clear unread bits in UART and restart */ | ||
| 539 | outb(UART_FCR_CLEAR_RCVR, io + UART_FCR); | ||
| 540 | #endif | ||
| 541 | /* determine 'virtual' pulse end: */ | ||
| 542 | pulse_end = delta(&last_tv, &last_intr_tv); | ||
| 543 | dprintk("timeout add %d for %lu usec\n", last_value, pulse_end); | ||
| 544 | add_read_queue(last_value, pulse_end); | ||
| 545 | last_value = 0; | ||
| 546 | last_tv = last_intr_tv; | ||
| 547 | } | ||
| 548 | spin_unlock_irqrestore(&timer_lock, flags); | ||
| 549 | } | ||
| 550 | |||
| 551 | static irqreturn_t sir_interrupt(int irq, void *dev_id) | ||
| 552 | { | ||
| 553 | unsigned char data; | ||
| 554 | struct timeval curr_tv; | ||
| 555 | static unsigned long deltv; | ||
| 556 | #ifdef LIRC_ON_SA1100 | ||
| 557 | int status; | ||
| 558 | static int n; | ||
| 559 | |||
| 560 | status = Ser2UTSR0; | ||
| 561 | /* | ||
| 562 | * Deal with any receive errors first. The bytes in error may be | ||
| 563 | * the only bytes in the receive FIFO, so we do this first. | ||
| 564 | */ | ||
| 565 | while (status & UTSR0_EIF) { | ||
| 566 | int bstat; | ||
| 567 | |||
| 568 | if (debug) { | ||
| 569 | dprintk("EIF\n"); | ||
| 570 | bstat = Ser2UTSR1; | ||
| 571 | |||
| 572 | if (bstat & UTSR1_FRE) | ||
| 573 | dprintk("frame error\n"); | ||
| 574 | if (bstat & UTSR1_ROR) | ||
| 575 | dprintk("receive fifo overrun\n"); | ||
| 576 | if (bstat & UTSR1_PRE) | ||
| 577 | dprintk("parity error\n"); | ||
| 578 | } | ||
| 579 | |||
| 580 | bstat = Ser2UTDR; | ||
| 581 | n++; | ||
| 582 | status = Ser2UTSR0; | ||
| 583 | } | ||
| 584 | |||
| 585 | if (status & (UTSR0_RFS | UTSR0_RID)) { | ||
| 586 | do_gettimeofday(&curr_tv); | ||
| 587 | deltv = delta(&last_tv, &curr_tv); | ||
| 588 | do { | ||
| 589 | data = Ser2UTDR; | ||
| 590 | dprintk("%d data: %u\n", n, (unsigned int) data); | ||
| 591 | n++; | ||
| 592 | } while (status & UTSR0_RID && /* do not empty fifo in order to | ||
| 593 | * get UTSR0_RID in any case */ | ||
| 594 | Ser2UTSR1 & UTSR1_RNE); /* data ready */ | ||
| 595 | |||
| 596 | if (status&UTSR0_RID) { | ||
| 597 | add_read_queue(0 , deltv - n * TIME_CONST); /*space*/ | ||
| 598 | add_read_queue(1, n * TIME_CONST); /*pulse*/ | ||
| 599 | n = 0; | ||
| 600 | last_tv = curr_tv; | ||
| 601 | } | ||
| 602 | } | ||
| 603 | |||
| 604 | if (status & UTSR0_TFS) | ||
| 605 | printk(KERN_ERR "transmit fifo not full, shouldn't happen\n"); | ||
| 606 | |||
| 607 | /* We must clear certain bits. */ | ||
| 608 | status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); | ||
| 609 | if (status) | ||
| 610 | Ser2UTSR0 = status; | ||
| 611 | #else | ||
| 612 | unsigned long deltintrtv; | ||
| 613 | unsigned long flags; | ||
| 614 | int iir, lsr; | ||
| 615 | |||
| 616 | while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) { | ||
| 617 | switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */ | ||
| 618 | case UART_IIR_MSI: | ||
| 619 | (void) inb(io + UART_MSR); | ||
| 620 | break; | ||
| 621 | case UART_IIR_RLSI: | ||
| 622 | (void) inb(io + UART_LSR); | ||
| 623 | break; | ||
| 624 | case UART_IIR_THRI: | ||
| 625 | #if 0 | ||
| 626 | if (lsr & UART_LSR_THRE) /* FIFO is empty */ | ||
| 627 | outb(data, io + UART_TX) | ||
| 628 | #endif | ||
| 629 | break; | ||
| 630 | case UART_IIR_RDI: | ||
| 631 | /* avoid interference with timer */ | ||
| 632 | spin_lock_irqsave(&timer_lock, flags); | ||
| 633 | do { | ||
| 634 | del_timer(&timerlist); | ||
| 635 | data = inb(io + UART_RX); | ||
| 636 | do_gettimeofday(&curr_tv); | ||
| 637 | deltv = delta(&last_tv, &curr_tv); | ||
| 638 | deltintrtv = delta(&last_intr_tv, &curr_tv); | ||
| 639 | dprintk("t %lu, d %d\n", deltintrtv, (int)data); | ||
| 640 | /* | ||
| 641 | * if nothing came in last X cycles, | ||
| 642 | * it was gap | ||
| 643 | */ | ||
| 644 | if (deltintrtv > TIME_CONST * threshold) { | ||
| 645 | if (last_value) { | ||
| 646 | dprintk("GAP\n"); | ||
| 647 | /* simulate signal change */ | ||
| 648 | add_read_queue(last_value, | ||
| 649 | deltv - | ||
| 650 | deltintrtv); | ||
| 651 | last_value = 0; | ||
| 652 | last_tv.tv_sec = | ||
| 653 | last_intr_tv.tv_sec; | ||
| 654 | last_tv.tv_usec = | ||
| 655 | last_intr_tv.tv_usec; | ||
| 656 | deltv = deltintrtv; | ||
| 657 | } | ||
| 658 | } | ||
| 659 | data = 1; | ||
| 660 | if (data ^ last_value) { | ||
| 661 | /* | ||
| 662 | * deltintrtv > 2*TIME_CONST, remember? | ||
| 663 | * the other case is timeout | ||
| 664 | */ | ||
| 665 | add_read_queue(last_value, | ||
| 666 | deltv-TIME_CONST); | ||
| 667 | last_value = data; | ||
| 668 | last_tv = curr_tv; | ||
| 669 | if (last_tv.tv_usec >= TIME_CONST) { | ||
| 670 | last_tv.tv_usec -= TIME_CONST; | ||
| 671 | } else { | ||
| 672 | last_tv.tv_sec--; | ||
| 673 | last_tv.tv_usec += 1000000 - | ||
| 674 | TIME_CONST; | ||
| 675 | } | ||
| 676 | } | ||
| 677 | last_intr_tv = curr_tv; | ||
| 678 | if (data) { | ||
| 679 | /* | ||
| 680 | * start timer for end of | ||
| 681 | * sequence detection | ||
| 682 | */ | ||
| 683 | timerlist.expires = jiffies + | ||
| 684 | SIR_TIMEOUT; | ||
| 685 | add_timer(&timerlist); | ||
| 686 | } | ||
| 687 | |||
| 688 | lsr = inb(io + UART_LSR); | ||
| 689 | } while (lsr & UART_LSR_DR); /* data ready */ | ||
| 690 | spin_unlock_irqrestore(&timer_lock, flags); | ||
| 691 | break; | ||
| 692 | default: | ||
| 693 | break; | ||
| 694 | } | ||
| 695 | } | ||
| 696 | #endif | ||
| 697 | return IRQ_RETVAL(IRQ_HANDLED); | ||
| 698 | } | ||
| 699 | |||
| 700 | #ifdef LIRC_ON_SA1100 | ||
| 701 | static void send_pulse(unsigned long length) | ||
| 702 | { | ||
| 703 | unsigned long k, delay; | ||
| 704 | int flag; | ||
| 705 | |||
| 706 | if (length == 0) | ||
| 707 | return; | ||
| 708 | /* | ||
| 709 | * this won't give us the carrier frequency we really want | ||
| 710 | * due to integer arithmetic, but we can accept this inaccuracy | ||
| 711 | */ | ||
| 712 | |||
| 713 | for (k = flag = 0; k < length; k += delay, flag = !flag) { | ||
| 714 | if (flag) { | ||
| 715 | off(); | ||
| 716 | delay = space_width; | ||
| 717 | } else { | ||
| 718 | on(); | ||
| 719 | delay = pulse_width; | ||
| 720 | } | ||
| 721 | safe_udelay(delay); | ||
| 722 | } | ||
| 723 | off(); | ||
| 724 | } | ||
| 725 | |||
| 726 | static void send_space(unsigned long length) | ||
| 727 | { | ||
| 728 | if (length == 0) | ||
| 729 | return; | ||
| 730 | off(); | ||
| 731 | safe_udelay(length); | ||
| 732 | } | ||
| 733 | #else | ||
| 734 | static void send_space(unsigned long len) | ||
| 735 | { | ||
| 736 | safe_udelay(len); | ||
| 737 | } | ||
| 738 | |||
| 739 | static void send_pulse(unsigned long len) | ||
| 740 | { | ||
| 741 | long bytes_out = len / TIME_CONST; | ||
| 742 | |||
| 743 | if (bytes_out == 0) | ||
| 744 | bytes_out++; | ||
| 745 | |||
| 746 | while (bytes_out--) { | ||
| 747 | outb(PULSE, io + UART_TX); | ||
| 748 | /* FIXME treba seriozne cakanie z char/serial.c */ | ||
| 749 | while (!(inb(io + UART_LSR) & UART_LSR_THRE)) | ||
| 750 | ; | ||
| 751 | } | ||
| 752 | } | ||
| 753 | #endif | ||
| 754 | |||
| 755 | #ifdef CONFIG_SA1100_COLLIE | ||
| 756 | static int sa1100_irda_set_power_collie(int state) | ||
| 757 | { | ||
| 758 | if (state) { | ||
| 759 | /* | ||
| 760 | * 0 - off | ||
| 761 | * 1 - short range, lowest power | ||
| 762 | * 2 - medium range, medium power | ||
| 763 | * 3 - maximum range, high power | ||
| 764 | */ | ||
| 765 | ucb1200_set_io_direction(TC35143_GPIO_IR_ON, | ||
| 766 | TC35143_IODIR_OUTPUT); | ||
| 767 | ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW); | ||
| 768 | udelay(100); | ||
| 769 | } else { | ||
| 770 | /* OFF */ | ||
| 771 | ucb1200_set_io_direction(TC35143_GPIO_IR_ON, | ||
| 772 | TC35143_IODIR_OUTPUT); | ||
| 773 | ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_HIGH); | ||
| 774 | } | ||
| 775 | return 0; | ||
| 776 | } | ||
| 777 | #endif | ||
| 778 | |||
| 779 | static int init_hardware(void) | ||
| 780 | { | ||
| 781 | unsigned long flags; | ||
| 782 | |||
| 783 | spin_lock_irqsave(&hardware_lock, flags); | ||
| 784 | /* reset UART */ | ||
| 785 | #ifdef LIRC_ON_SA1100 | ||
| 786 | #ifdef CONFIG_SA1100_BITSY | ||
| 787 | if (machine_is_bitsy()) { | ||
| 788 | printk(KERN_INFO "Power on IR module\n"); | ||
| 789 | set_bitsy_egpio(EGPIO_BITSY_IR_ON); | ||
| 790 | } | ||
| 791 | #endif | ||
| 792 | #ifdef CONFIG_SA1100_COLLIE | ||
| 793 | sa1100_irda_set_power_collie(3); /* power on */ | ||
| 794 | #endif | ||
| 795 | sr.hscr0 = Ser2HSCR0; | ||
| 796 | |||
| 797 | sr.utcr0 = Ser2UTCR0; | ||
| 798 | sr.utcr1 = Ser2UTCR1; | ||
| 799 | sr.utcr2 = Ser2UTCR2; | ||
| 800 | sr.utcr3 = Ser2UTCR3; | ||
| 801 | sr.utcr4 = Ser2UTCR4; | ||
| 802 | |||
| 803 | sr.utdr = Ser2UTDR; | ||
| 804 | sr.utsr0 = Ser2UTSR0; | ||
| 805 | sr.utsr1 = Ser2UTSR1; | ||
| 806 | |||
| 807 | /* configure GPIO */ | ||
| 808 | /* output */ | ||
| 809 | PPDR |= PPC_TXD2; | ||
| 810 | PSDR |= PPC_TXD2; | ||
| 811 | /* set output to 0 */ | ||
| 812 | off(); | ||
| 813 | |||
| 814 | /* Enable HP-SIR modulation, and ensure that the port is disabled. */ | ||
| 815 | Ser2UTCR3 = 0; | ||
| 816 | Ser2HSCR0 = sr.hscr0 & (~HSCR0_HSSP); | ||
| 817 | |||
| 818 | /* clear status register to prevent unwanted interrupts */ | ||
| 819 | Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); | ||
| 820 | |||
| 821 | /* 7N1 */ | ||
| 822 | Ser2UTCR0 = UTCR0_1StpBit|UTCR0_7BitData; | ||
| 823 | /* 115200 */ | ||
| 824 | Ser2UTCR1 = 0; | ||
| 825 | Ser2UTCR2 = 1; | ||
| 826 | /* use HPSIR, 1.6 usec pulses */ | ||
| 827 | Ser2UTCR4 = UTCR4_HPSIR|UTCR4_Z1_6us; | ||
| 828 | |||
| 829 | /* enable receiver, receive fifo interrupt */ | ||
| 830 | Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; | ||
| 831 | |||
| 832 | /* clear status register to prevent unwanted interrupts */ | ||
| 833 | Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); | ||
| 834 | |||
| 835 | #elif defined(LIRC_SIR_TEKRAM) | ||
| 836 | /* disable FIFO */ | ||
| 837 | soutp(UART_FCR, | ||
| 838 | UART_FCR_CLEAR_RCVR| | ||
| 839 | UART_FCR_CLEAR_XMIT| | ||
| 840 | UART_FCR_TRIGGER_1); | ||
| 841 | |||
| 842 | /* Set DLAB 0. */ | ||
| 843 | soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); | ||
| 844 | |||
| 845 | /* First of all, disable all interrupts */ | ||
| 846 | soutp(UART_IER, sinp(UART_IER) & | ||
| 847 | (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); | ||
| 848 | |||
| 849 | /* Set DLAB 1. */ | ||
| 850 | soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); | ||
| 851 | |||
| 852 | /* Set divisor to 12 => 9600 Baud */ | ||
| 853 | soutp(UART_DLM, 0); | ||
| 854 | soutp(UART_DLL, 12); | ||
| 855 | |||
| 856 | /* Set DLAB 0. */ | ||
| 857 | soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); | ||
| 858 | |||
| 859 | /* power supply */ | ||
| 860 | soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); | ||
| 861 | safe_udelay(50*1000); | ||
| 862 | |||
| 863 | /* -DTR low -> reset PIC */ | ||
| 864 | soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); | ||
| 865 | udelay(1*1000); | ||
| 866 | |||
| 867 | soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); | ||
| 868 | udelay(100); | ||
| 869 | |||
| 870 | |||
| 871 | /* -RTS low -> send control byte */ | ||
| 872 | soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); | ||
| 873 | udelay(7); | ||
| 874 | soutp(UART_TX, TEKRAM_115200|TEKRAM_PW); | ||
| 875 | |||
| 876 | /* one byte takes ~1042 usec to transmit at 9600,8N1 */ | ||
| 877 | udelay(1500); | ||
| 878 | |||
| 879 | /* back to normal operation */ | ||
| 880 | soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); | ||
| 881 | udelay(50); | ||
| 882 | |||
| 883 | udelay(1500); | ||
| 884 | |||
| 885 | /* read previous control byte */ | ||
| 886 | printk(KERN_INFO LIRC_DRIVER_NAME | ||
| 887 | ": 0x%02x\n", sinp(UART_RX)); | ||
| 888 | |||
| 889 | /* Set DLAB 1. */ | ||
| 890 | soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); | ||
| 891 | |||
| 892 | /* Set divisor to 1 => 115200 Baud */ | ||
| 893 | soutp(UART_DLM, 0); | ||
| 894 | soutp(UART_DLL, 1); | ||
| 895 | |||
| 896 | /* Set DLAB 0, 8 Bit */ | ||
| 897 | soutp(UART_LCR, UART_LCR_WLEN8); | ||
| 898 | /* enable interrupts */ | ||
| 899 | soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); | ||
| 900 | #else | ||
| 901 | outb(0, io + UART_MCR); | ||
| 902 | outb(0, io + UART_IER); | ||
| 903 | /* init UART */ | ||
| 904 | /* set DLAB, speed = 115200 */ | ||
| 905 | outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR); | ||
| 906 | outb(1, io + UART_DLL); outb(0, io + UART_DLM); | ||
| 907 | /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */ | ||
| 908 | outb(UART_LCR_WLEN7, io + UART_LCR); | ||
| 909 | /* FIFO operation */ | ||
| 910 | outb(UART_FCR_ENABLE_FIFO, io + UART_FCR); | ||
| 911 | /* interrupts */ | ||
| 912 | /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */ | ||
| 913 | outb(UART_IER_RDI, io + UART_IER); | ||
| 914 | /* turn on UART */ | ||
| 915 | outb(UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2, io + UART_MCR); | ||
| 916 | #ifdef LIRC_SIR_ACTISYS_ACT200L | ||
| 917 | init_act200(); | ||
| 918 | #elif defined(LIRC_SIR_ACTISYS_ACT220L) | ||
| 919 | init_act220(); | ||
| 920 | #endif | ||
| 921 | #endif | ||
| 922 | spin_unlock_irqrestore(&hardware_lock, flags); | ||
| 923 | return 0; | ||
| 924 | } | ||
| 925 | |||
| 926 | static void drop_hardware(void) | ||
| 927 | { | ||
| 928 | unsigned long flags; | ||
| 929 | |||
| 930 | spin_lock_irqsave(&hardware_lock, flags); | ||
| 931 | |||
| 932 | #ifdef LIRC_ON_SA1100 | ||
| 933 | Ser2UTCR3 = 0; | ||
| 934 | |||
| 935 | Ser2UTCR0 = sr.utcr0; | ||
| 936 | Ser2UTCR1 = sr.utcr1; | ||
| 937 | Ser2UTCR2 = sr.utcr2; | ||
| 938 | Ser2UTCR4 = sr.utcr4; | ||
| 939 | Ser2UTCR3 = sr.utcr3; | ||
| 940 | |||
| 941 | Ser2HSCR0 = sr.hscr0; | ||
| 942 | #ifdef CONFIG_SA1100_BITSY | ||
| 943 | if (machine_is_bitsy()) | ||
| 944 | clr_bitsy_egpio(EGPIO_BITSY_IR_ON); | ||
| 945 | #endif | ||
| 946 | #ifdef CONFIG_SA1100_COLLIE | ||
| 947 | sa1100_irda_set_power_collie(0); /* power off */ | ||
| 948 | #endif | ||
| 949 | #else | ||
| 950 | /* turn off interrupts */ | ||
| 951 | outb(0, io + UART_IER); | ||
| 952 | #endif | ||
| 953 | spin_unlock_irqrestore(&hardware_lock, flags); | ||
| 954 | } | ||
| 955 | |||
| 956 | /* SECTION: Initialisation */ | ||
| 957 | |||
| 958 | static int init_port(void) | ||
| 959 | { | ||
| 960 | int retval; | ||
| 961 | |||
| 962 | /* get I/O port access and IRQ line */ | ||
| 963 | #ifndef LIRC_ON_SA1100 | ||
| 964 | if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { | ||
| 965 | printk(KERN_ERR LIRC_DRIVER_NAME | ||
| 966 | ": i/o port 0x%.4x already in use.\n", io); | ||
| 967 | return -EBUSY; | ||
| 968 | } | ||
| 969 | #endif | ||
| 970 | retval = request_irq(irq, sir_interrupt, IRQF_DISABLED, | ||
| 971 | LIRC_DRIVER_NAME, NULL); | ||
| 972 | if (retval < 0) { | ||
| 973 | # ifndef LIRC_ON_SA1100 | ||
| 974 | release_region(io, 8); | ||
| 975 | # endif | ||
| 976 | printk(KERN_ERR LIRC_DRIVER_NAME | ||
| 977 | ": IRQ %d already in use.\n", | ||
| 978 | irq); | ||
| 979 | return retval; | ||
| 980 | } | ||
| 981 | #ifndef LIRC_ON_SA1100 | ||
| 982 | printk(KERN_INFO LIRC_DRIVER_NAME | ||
| 983 | ": I/O port 0x%.4x, IRQ %d.\n", | ||
| 984 | io, irq); | ||
| 985 | #endif | ||
| 986 | |||
| 987 | init_timer(&timerlist); | ||
| 988 | timerlist.function = sir_timeout; | ||
| 989 | timerlist.data = 0xabadcafe; | ||
| 990 | |||
| 991 | return 0; | ||
| 992 | } | ||
| 993 | |||
| 994 | static void drop_port(void) | ||
| 995 | { | ||
| 996 | free_irq(irq, NULL); | ||
| 997 | del_timer_sync(&timerlist); | ||
| 998 | #ifndef LIRC_ON_SA1100 | ||
| 999 | release_region(io, 8); | ||
| 1000 | #endif | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | #ifdef LIRC_SIR_ACTISYS_ACT200L | ||
| 1004 | /* Crystal/Cirrus CS8130 IR transceiver, used in Actisys Act200L dongle */ | ||
| 1005 | /* some code borrowed from Linux IRDA driver */ | ||
| 1006 | |||
| 1007 | /* Register 0: Control register #1 */ | ||
| 1008 | #define ACT200L_REG0 0x00 | ||
| 1009 | #define ACT200L_TXEN 0x01 /* Enable transmitter */ | ||
| 1010 | #define ACT200L_RXEN 0x02 /* Enable receiver */ | ||
| 1011 | #define ACT200L_ECHO 0x08 /* Echo control chars */ | ||
| 1012 | |||
| 1013 | /* Register 1: Control register #2 */ | ||
| 1014 | #define ACT200L_REG1 0x10 | ||
| 1015 | #define ACT200L_LODB 0x01 /* Load new baud rate count value */ | ||
| 1016 | #define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */ | ||
| 1017 | |||
| 1018 | /* Register 3: Transmit mode register #2 */ | ||
| 1019 | #define ACT200L_REG3 0x30 | ||
| 1020 | #define ACT200L_B0 0x01 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ | ||
| 1021 | #define ACT200L_B1 0x02 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ | ||
| 1022 | #define ACT200L_CHSY 0x04 /* StartBit Synced 0=bittime, 1=startbit */ | ||
| 1023 | |||
| 1024 | /* Register 4: Output Power register */ | ||
| 1025 | #define ACT200L_REG4 0x40 | ||
| 1026 | #define ACT200L_OP0 0x01 /* Enable LED1C output */ | ||
| 1027 | #define ACT200L_OP1 0x02 /* Enable LED2C output */ | ||
| 1028 | #define ACT200L_BLKR 0x04 | ||
| 1029 | |||
| 1030 | /* Register 5: Receive Mode register */ | ||
| 1031 | #define ACT200L_REG5 0x50 | ||
| 1032 | #define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */ | ||
| 1033 | /*.. other various IRDA bit modes, and TV remote modes..*/ | ||
| 1034 | |||
| 1035 | /* Register 6: Receive Sensitivity register #1 */ | ||
| 1036 | #define ACT200L_REG6 0x60 | ||
| 1037 | #define ACT200L_RS0 0x01 /* receive threshold bit 0 */ | ||
| 1038 | #define ACT200L_RS1 0x02 /* receive threshold bit 1 */ | ||
| 1039 | |||
| 1040 | /* Register 7: Receive Sensitivity register #2 */ | ||
| 1041 | #define ACT200L_REG7 0x70 | ||
| 1042 | #define ACT200L_ENPOS 0x04 /* Ignore the falling edge */ | ||
| 1043 | |||
| 1044 | /* Register 8,9: Baud Rate Divider register #1,#2 */ | ||
| 1045 | #define ACT200L_REG8 0x80 | ||
| 1046 | #define ACT200L_REG9 0x90 | ||
| 1047 | |||
| 1048 | #define ACT200L_2400 0x5f | ||
| 1049 | #define ACT200L_9600 0x17 | ||
| 1050 | #define ACT200L_19200 0x0b | ||
| 1051 | #define ACT200L_38400 0x05 | ||
| 1052 | #define ACT200L_57600 0x03 | ||
| 1053 | #define ACT200L_115200 0x01 | ||
| 1054 | |||
| 1055 | /* Register 13: Control register #3 */ | ||
| 1056 | #define ACT200L_REG13 0xd0 | ||
| 1057 | #define ACT200L_SHDW 0x01 /* Enable access to shadow registers */ | ||
| 1058 | |||
| 1059 | /* Register 15: Status register */ | ||
| 1060 | #define ACT200L_REG15 0xf0 | ||
| 1061 | |||
| 1062 | /* Register 21: Control register #4 */ | ||
| 1063 | #define ACT200L_REG21 0x50 | ||
| 1064 | #define ACT200L_EXCK 0x02 /* Disable clock output driver */ | ||
| 1065 | #define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */ | ||
| 1066 | |||
| 1067 | static void init_act200(void) | ||
| 1068 | { | ||
| 1069 | int i; | ||
| 1070 | __u8 control[] = { | ||
| 1071 | ACT200L_REG15, | ||
| 1072 | ACT200L_REG13 | ACT200L_SHDW, | ||
| 1073 | ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL, | ||
| 1074 | ACT200L_REG13, | ||
| 1075 | ACT200L_REG7 | ACT200L_ENPOS, | ||
| 1076 | ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1, | ||
| 1077 | ACT200L_REG5 | ACT200L_RWIDL, | ||
| 1078 | ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR, | ||
| 1079 | ACT200L_REG3 | ACT200L_B0, | ||
| 1080 | ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN, | ||
| 1081 | ACT200L_REG8 | (ACT200L_115200 & 0x0f), | ||
| 1082 | ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f), | ||
| 1083 | ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE | ||
| 1084 | }; | ||
| 1085 | |||
| 1086 | /* Set DLAB 1. */ | ||
| 1087 | soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); | ||
| 1088 | |||
| 1089 | /* Set divisor to 12 => 9600 Baud */ | ||
| 1090 | soutp(UART_DLM, 0); | ||
| 1091 | soutp(UART_DLL, 12); | ||
| 1092 | |||
| 1093 | /* Set DLAB 0. */ | ||
| 1094 | soutp(UART_LCR, UART_LCR_WLEN8); | ||
| 1095 | /* Set divisor to 12 => 9600 Baud */ | ||
| 1096 | |||
| 1097 | /* power supply */ | ||
| 1098 | soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); | ||
| 1099 | for (i = 0; i < 50; i++) | ||
| 1100 | safe_udelay(1000); | ||
| 1101 | |||
| 1102 | /* Reset the dongle : set RTS low for 25 ms */ | ||
| 1103 | soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); | ||
| 1104 | for (i = 0; i < 25; i++) | ||
| 1105 | udelay(1000); | ||
| 1106 | |||
| 1107 | soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); | ||
| 1108 | udelay(100); | ||
| 1109 | |||
| 1110 | /* Clear DTR and set RTS to enter command mode */ | ||
| 1111 | soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); | ||
| 1112 | udelay(7); | ||
| 1113 | |||
| 1114 | /* send out the control register settings for 115K 7N1 SIR operation */ | ||
| 1115 | for (i = 0; i < sizeof(control); i++) { | ||
| 1116 | soutp(UART_TX, control[i]); | ||
| 1117 | /* one byte takes ~1042 usec to transmit at 9600,8N1 */ | ||
| 1118 | udelay(1500); | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | /* back to normal operation */ | ||
| 1122 | soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); | ||
| 1123 | udelay(50); | ||
| 1124 | |||
| 1125 | udelay(1500); | ||
| 1126 | soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); | ||
| 1127 | |||
| 1128 | /* Set DLAB 1. */ | ||
| 1129 | soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); | ||
| 1130 | |||
| 1131 | /* Set divisor to 1 => 115200 Baud */ | ||
| 1132 | soutp(UART_DLM, 0); | ||
| 1133 | soutp(UART_DLL, 1); | ||
| 1134 | |||
| 1135 | /* Set DLAB 0. */ | ||
| 1136 | soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); | ||
| 1137 | |||
| 1138 | /* Set DLAB 0, 7 Bit */ | ||
| 1139 | soutp(UART_LCR, UART_LCR_WLEN7); | ||
| 1140 | |||
| 1141 | /* enable interrupts */ | ||
| 1142 | soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); | ||
| 1143 | } | ||
| 1144 | #endif | ||
| 1145 | |||
| 1146 | #ifdef LIRC_SIR_ACTISYS_ACT220L | ||
| 1147 | /* | ||
| 1148 | * Derived from linux IrDA driver (net/irda/actisys.c) | ||
| 1149 | * Drop me a mail for any kind of comment: maxx@spaceboyz.net | ||
| 1150 | */ | ||
| 1151 | |||
| 1152 | void init_act220(void) | ||
| 1153 | { | ||
| 1154 | int i; | ||
| 1155 | |||
| 1156 | /* DLAB 1 */ | ||
| 1157 | soutp(UART_LCR, UART_LCR_DLAB|UART_LCR_WLEN7); | ||
| 1158 | |||
| 1159 | /* 9600 baud */ | ||
| 1160 | soutp(UART_DLM, 0); | ||
| 1161 | soutp(UART_DLL, 12); | ||
| 1162 | |||
| 1163 | /* DLAB 0 */ | ||
| 1164 | soutp(UART_LCR, UART_LCR_WLEN7); | ||
| 1165 | |||
| 1166 | /* reset the dongle, set DTR low for 10us */ | ||
| 1167 | soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); | ||
| 1168 | udelay(10); | ||
| 1169 | |||
| 1170 | /* back to normal (still 9600) */ | ||
| 1171 | soutp(UART_MCR, UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2); | ||
| 1172 | |||
| 1173 | /* | ||
| 1174 | * send RTS pulses until we reach 115200 | ||
| 1175 | * i hope this is really the same for act220l/act220l+ | ||
| 1176 | */ | ||
| 1177 | for (i = 0; i < 3; i++) { | ||
| 1178 | udelay(10); | ||
| 1179 | /* set RTS low for 10 us */ | ||
| 1180 | soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); | ||
| 1181 | udelay(10); | ||
| 1182 | /* set RTS high for 10 us */ | ||
| 1183 | soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | /* back to normal operation */ | ||
| 1187 | udelay(1500); /* better safe than sorry ;) */ | ||
| 1188 | |||
| 1189 | /* Set DLAB 1. */ | ||
| 1190 | soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); | ||
| 1191 | |||
| 1192 | /* Set divisor to 1 => 115200 Baud */ | ||
| 1193 | soutp(UART_DLM, 0); | ||
| 1194 | soutp(UART_DLL, 1); | ||
| 1195 | |||
| 1196 | /* Set DLAB 0, 7 Bit */ | ||
| 1197 | /* The dongle doesn't seem to have any problems with operation at 7N1 */ | ||
| 1198 | soutp(UART_LCR, UART_LCR_WLEN7); | ||
| 1199 | |||
| 1200 | /* enable interrupts */ | ||
| 1201 | soutp(UART_IER, UART_IER_RDI); | ||
| 1202 | } | ||
| 1203 | #endif | ||
| 1204 | |||
| 1205 | static int init_lirc_sir(void) | ||
| 1206 | { | ||
| 1207 | int retval; | ||
| 1208 | |||
| 1209 | init_waitqueue_head(&lirc_read_queue); | ||
| 1210 | retval = init_port(); | ||
| 1211 | if (retval < 0) | ||
| 1212 | return retval; | ||
| 1213 | init_hardware(); | ||
| 1214 | printk(KERN_INFO LIRC_DRIVER_NAME | ||
| 1215 | ": Installed.\n"); | ||
| 1216 | return 0; | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | |||
| 1220 | static int __init lirc_sir_init(void) | ||
| 1221 | { | ||
| 1222 | int retval; | ||
| 1223 | |||
| 1224 | retval = init_chrdev(); | ||
| 1225 | if (retval < 0) | ||
| 1226 | return retval; | ||
| 1227 | retval = init_lirc_sir(); | ||
| 1228 | if (retval) { | ||
| 1229 | drop_chrdev(); | ||
| 1230 | return retval; | ||
| 1231 | } | ||
| 1232 | return 0; | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | static void __exit lirc_sir_exit(void) | ||
| 1236 | { | ||
| 1237 | drop_hardware(); | ||
| 1238 | drop_chrdev(); | ||
| 1239 | drop_port(); | ||
| 1240 | printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | module_init(lirc_sir_init); | ||
| 1244 | module_exit(lirc_sir_exit); | ||
| 1245 | |||
| 1246 | #ifdef LIRC_SIR_TEKRAM | ||
| 1247 | MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210"); | ||
| 1248 | MODULE_AUTHOR("Christoph Bartelmus"); | ||
| 1249 | #elif defined(LIRC_ON_SA1100) | ||
| 1250 | MODULE_DESCRIPTION("LIRC driver for StrongARM SA1100 embedded microprocessor"); | ||
| 1251 | MODULE_AUTHOR("Christoph Bartelmus"); | ||
| 1252 | #elif defined(LIRC_SIR_ACTISYS_ACT200L) | ||
| 1253 | MODULE_DESCRIPTION("LIRC driver for Actisys Act200L"); | ||
| 1254 | MODULE_AUTHOR("Karl Bongers"); | ||
| 1255 | #elif defined(LIRC_SIR_ACTISYS_ACT220L) | ||
| 1256 | MODULE_DESCRIPTION("LIRC driver for Actisys Act220L(+)"); | ||
| 1257 | MODULE_AUTHOR("Jan Roemisch"); | ||
| 1258 | #else | ||
| 1259 | MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports"); | ||
| 1260 | MODULE_AUTHOR("Milan Pikula"); | ||
| 1261 | #endif | ||
| 1262 | MODULE_LICENSE("GPL"); | ||
| 1263 | |||
| 1264 | #ifdef LIRC_ON_SA1100 | ||
| 1265 | module_param(irq, int, S_IRUGO); | ||
| 1266 | MODULE_PARM_DESC(irq, "Interrupt (16)"); | ||
| 1267 | #else | ||
| 1268 | module_param(io, int, S_IRUGO); | ||
| 1269 | MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); | ||
| 1270 | |||
| 1271 | module_param(irq, int, S_IRUGO); | ||
| 1272 | MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); | ||
| 1273 | |||
| 1274 | module_param(threshold, int, S_IRUGO); | ||
| 1275 | MODULE_PARM_DESC(threshold, "space detection threshold (3)"); | ||
| 1276 | #endif | ||
| 1277 | |||
| 1278 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
| 1279 | MODULE_PARM_DESC(debug, "Enable debugging messages"); | ||
diff --git a/drivers/staging/lirc/lirc_ttusbir.c b/drivers/staging/lirc/lirc_ttusbir.c new file mode 100644 index 00000000000..e4b329b8caf --- /dev/null +++ b/drivers/staging/lirc/lirc_ttusbir.c | |||
| @@ -0,0 +1,395 @@ | |||
| 1 | /* | ||
| 2 | * lirc_ttusbir.c | ||
| 3 | * | ||
| 4 | * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver | ||
| 5 | * | ||
| 6 | * Copyright (C) 2007 Stefan Macher <st_maker-lirc@yahoo.de> | ||
| 7 | * | ||
| 8 | * This LIRC driver provides access to the TechnoTrend USB IR Receiver. | ||
| 9 | * The receiver delivers the IR signal as raw sampled true/false data in | ||
| 10 | * isochronous USB packets each of size 128 byte. | ||
| 11 | * Currently the driver reduces the sampling rate by factor of 8 as this | ||
| 12 | * is still more than enough to decode RC-5 - others should be analyzed. | ||
| 13 | * But the driver does not rely on RC-5 it should be able to decode every | ||
| 14 | * IR signal that is not too fast. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * This program is free software; you can redistribute it and/or modify | ||
| 19 | * it under the terms of the GNU General Public License as published by | ||
| 20 | * the Free Software Foundation; either version 2 of the License, or | ||
| 21 | * (at your option) any later version. | ||
| 22 | * | ||
| 23 | * This program is distributed in the hope that it will be useful, | ||
| 24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 26 | * GNU General Public License for more details. | ||
| 27 | * | ||
| 28 | * You should have received a copy of the GNU General Public License | ||
| 29 | * along with this program; if not, write to the Free Software | ||
| 30 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include <linux/kernel.h> | ||
| 34 | #include <linux/init.h> | ||
| 35 | #include <linux/module.h> | ||
| 36 | #include <linux/errno.h> | ||
| 37 | #include <linux/slab.h> | ||
| 38 | #include <linux/usb.h> | ||
| 39 | |||
| 40 | #include <media/lirc.h> | ||
| 41 | #include <media/lirc_dev.h> | ||
| 42 | |||
| 43 | MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC"); | ||
| 44 | MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)"); | ||
| 45 | MODULE_LICENSE("GPL"); | ||
| 46 | |||
| 47 | /* #define DEBUG */ | ||
| 48 | #ifdef DEBUG | ||
| 49 | #define DPRINTK printk | ||
| 50 | #else | ||
| 51 | #define DPRINTK(_x_, a...) | ||
| 52 | #endif | ||
| 53 | |||
| 54 | /* function declarations */ | ||
| 55 | static int probe(struct usb_interface *intf, const struct usb_device_id *id); | ||
| 56 | static void disconnect(struct usb_interface *intf); | ||
| 57 | static void urb_complete(struct urb *urb); | ||
| 58 | static int set_use_inc(void *data); | ||
| 59 | static void set_use_dec(void *data); | ||
| 60 | |||
| 61 | static int num_urbs = 2; | ||
| 62 | module_param(num_urbs, int, S_IRUGO); | ||
| 63 | MODULE_PARM_DESC(num_urbs, | ||
| 64 | "Number of URBs in queue. Try to increase to 4 in case " | ||
| 65 | "of problems (default: 2; minimum: 2)"); | ||
| 66 | |||
| 67 | /* table of devices that work with this driver */ | ||
| 68 | static struct usb_device_id device_id_table[] = { | ||
| 69 | /* TechnoTrend USB IR Receiver */ | ||
| 70 | { USB_DEVICE(0x0B48, 0x2003) }, | ||
| 71 | /* Terminating entry */ | ||
| 72 | { } | ||
| 73 | }; | ||
| 74 | MODULE_DEVICE_TABLE(usb, device_id_table); | ||
| 75 | |||
| 76 | /* USB driver definition */ | ||
| 77 | static struct usb_driver usb_driver = { | ||
| 78 | .name = "TTUSBIR", | ||
| 79 | .id_table = &(device_id_table[0]), | ||
| 80 | .probe = probe, | ||
| 81 | .disconnect = disconnect, | ||
| 82 | }; | ||
| 83 | |||
| 84 | /* USB device definition */ | ||
| 85 | struct ttusbir_device { | ||
| 86 | struct usb_driver *usb_driver; | ||
| 87 | struct usb_device *udev; | ||
| 88 | struct usb_interface *interf; | ||
| 89 | struct usb_class_driver class_driver; | ||
| 90 | unsigned int ifnum; /* Interface number to use */ | ||
| 91 | unsigned int alt_setting; /* alternate setting to use */ | ||
| 92 | unsigned int endpoint; /* Endpoint to use */ | ||
| 93 | struct urb **urb; /* num_urb URB pointers*/ | ||
| 94 | char **buffer; /* 128 byte buffer for each URB */ | ||
| 95 | struct lirc_buffer rbuf; /* Buffer towards LIRC */ | ||
| 96 | struct lirc_driver driver; | ||
| 97 | int minor; | ||
| 98 | int last_pulse; /* remembers if last received byte was pulse or space */ | ||
| 99 | int last_num; /* remembers how many last bytes appeared */ | ||
| 100 | int opened; | ||
| 101 | }; | ||
| 102 | |||
| 103 | /*** LIRC specific functions ***/ | ||
| 104 | static int set_use_inc(void *data) | ||
| 105 | { | ||
| 106 | int i, retval; | ||
| 107 | struct ttusbir_device *ttusbir = data; | ||
| 108 | |||
| 109 | DPRINTK("Sending first URBs\n"); | ||
| 110 | /* @TODO Do I need to check if I am already opened */ | ||
| 111 | ttusbir->opened = 1; | ||
| 112 | |||
| 113 | for (i = 0; i < num_urbs; i++) { | ||
| 114 | retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL); | ||
| 115 | if (retval) { | ||
| 116 | err("%s: usb_submit_urb failed on urb %d", | ||
| 117 | __func__, i); | ||
| 118 | return retval; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | static void set_use_dec(void *data) | ||
| 125 | { | ||
| 126 | struct ttusbir_device *ttusbir = data; | ||
| 127 | |||
| 128 | DPRINTK("Device closed\n"); | ||
| 129 | |||
| 130 | ttusbir->opened = 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | /*** USB specific functions ***/ | ||
| 134 | |||
| 135 | /* | ||
| 136 | * This mapping table is used to do a very simple filtering of the | ||
| 137 | * input signal. | ||
| 138 | * For a value with at least 4 bits set it returns 0xFF otherwise | ||
| 139 | * 0x00. For faster IR signals this can not be used. But for RC-5 we | ||
| 140 | * still have about 14 samples per pulse/space, i.e. we sample with 14 | ||
| 141 | * times higher frequency than the signal frequency | ||
| 142 | */ | ||
| 143 | const unsigned char map_table[] = { | ||
| 144 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 145 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 146 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 147 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, | ||
| 148 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 149 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, | ||
| 150 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, | ||
| 151 | 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, | ||
| 152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, | ||
| 154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, | ||
| 155 | 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, | ||
| 156 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, | ||
| 157 | 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, | ||
| 158 | 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, | ||
| 159 | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
| 160 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 161 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, | ||
| 162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, | ||
| 163 | 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, | ||
| 164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, | ||
| 165 | 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, | ||
| 166 | 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, | ||
| 167 | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
| 168 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, | ||
| 169 | 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, | ||
| 170 | 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, | ||
| 171 | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
| 172 | 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, | ||
| 173 | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
| 174 | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||
| 175 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF | ||
| 176 | }; | ||
| 177 | |||
| 178 | static void urb_complete(struct urb *urb) | ||
| 179 | { | ||
| 180 | struct ttusbir_device *ttusbir; | ||
| 181 | unsigned char *buf; | ||
| 182 | int i; | ||
| 183 | int l; | ||
| 184 | |||
| 185 | ttusbir = urb->context; | ||
| 186 | |||
| 187 | if (!ttusbir->opened) | ||
| 188 | return; | ||
| 189 | |||
| 190 | buf = (unsigned char *)urb->transfer_buffer; | ||
| 191 | |||
| 192 | for (i = 0; i < 128; i++) { | ||
| 193 | /* Here we do the filtering and some kind of down sampling */ | ||
| 194 | buf[i] = ~map_table[buf[i]]; | ||
| 195 | if (ttusbir->last_pulse == buf[i]) { | ||
| 196 | if (ttusbir->last_num < PULSE_MASK/63) | ||
| 197 | ttusbir->last_num++; | ||
| 198 | /* | ||
| 199 | * else we are in a idle period and do not need to | ||
| 200 | * increment any longer | ||
| 201 | */ | ||
| 202 | } else { | ||
| 203 | l = ttusbir->last_num * 62; /* about 62 = us/byte */ | ||
| 204 | if (ttusbir->last_pulse) /* pulse or space? */ | ||
| 205 | l |= PULSE_BIT; | ||
| 206 | if (!lirc_buffer_full(&ttusbir->rbuf)) { | ||
| 207 | lirc_buffer_write(&ttusbir->rbuf, (void *)&l); | ||
| 208 | wake_up_interruptible(&ttusbir->rbuf.wait_poll); | ||
| 209 | } | ||
| 210 | ttusbir->last_num = 0; | ||
| 211 | ttusbir->last_pulse = buf[i]; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */ | ||
| 215 | } | ||
| 216 | |||
| 217 | /* | ||
| 218 | * Called whenever the USB subsystem thinks we could be the right driver | ||
| 219 | * to handle this device | ||
| 220 | */ | ||
| 221 | static int probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
| 222 | { | ||
| 223 | int alt_set, endp; | ||
| 224 | int found = 0; | ||
| 225 | int i, j; | ||
| 226 | int struct_size; | ||
| 227 | struct usb_host_interface *host_interf; | ||
| 228 | struct usb_interface_descriptor *interf_desc; | ||
| 229 | struct usb_host_endpoint *host_endpoint; | ||
| 230 | struct ttusbir_device *ttusbir; | ||
| 231 | |||
| 232 | DPRINTK("Module ttusbir probe\n"); | ||
| 233 | |||
| 234 | /* To reduce memory fragmentation we use only one allocation */ | ||
| 235 | struct_size = sizeof(struct ttusbir_device) + | ||
| 236 | (sizeof(struct urb *) * num_urbs) + | ||
| 237 | (sizeof(char *) * num_urbs) + | ||
| 238 | (num_urbs * 128); | ||
| 239 | ttusbir = kzalloc(struct_size, GFP_KERNEL); | ||
| 240 | if (!ttusbir) | ||
| 241 | return -ENOMEM; | ||
| 242 | |||
| 243 | ttusbir->urb = (struct urb **)((char *)ttusbir + | ||
| 244 | sizeof(struct ttusbir_device)); | ||
| 245 | ttusbir->buffer = (char **)((char *)ttusbir->urb + | ||
| 246 | (sizeof(struct urb *) * num_urbs)); | ||
| 247 | for (i = 0; i < num_urbs; i++) | ||
| 248 | ttusbir->buffer[i] = (char *)ttusbir->buffer + | ||
| 249 | (sizeof(char *)*num_urbs) + (i * 128); | ||
| 250 | |||
| 251 | ttusbir->usb_driver = &usb_driver; | ||
| 252 | ttusbir->alt_setting = -1; | ||
| 253 | /* @TODO check if error can be returned */ | ||
| 254 | ttusbir->udev = usb_get_dev(interface_to_usbdev(intf)); | ||
| 255 | ttusbir->interf = intf; | ||
| 256 | ttusbir->last_pulse = 0x00; | ||
| 257 | ttusbir->last_num = 0; | ||
| 258 | |||
| 259 | /* | ||
| 260 | * Now look for interface setting we can handle | ||
| 261 | * We are searching for the alt setting where end point | ||
| 262 | * 0x82 has max packet size 16 | ||
| 263 | */ | ||
| 264 | for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) { | ||
| 265 | host_interf = &intf->altsetting[alt_set]; | ||
| 266 | interf_desc = &host_interf->desc; | ||
| 267 | for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) { | ||
| 268 | host_endpoint = &host_interf->endpoint[endp]; | ||
| 269 | if ((host_endpoint->desc.bEndpointAddress == 0x82) && | ||
| 270 | (host_endpoint->desc.wMaxPacketSize == 0x10)) { | ||
| 271 | ttusbir->alt_setting = alt_set; | ||
| 272 | ttusbir->endpoint = endp; | ||
| 273 | found = 1; | ||
| 274 | break; | ||
| 275 | } | ||
| 276 | } | ||
| 277 | } | ||
| 278 | if (ttusbir->alt_setting != -1) | ||
| 279 | DPRINTK("alt setting: %d\n", ttusbir->alt_setting); | ||
| 280 | else { | ||
| 281 | err("Could not find alternate setting\n"); | ||
| 282 | kfree(ttusbir); | ||
| 283 | return -EINVAL; | ||
| 284 | } | ||
| 285 | |||
| 286 | /* OK lets setup this interface setting */ | ||
| 287 | usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting); | ||
| 288 | |||
| 289 | /* Store device info in interface structure */ | ||
| 290 | usb_set_intfdata(intf, ttusbir); | ||
| 291 | |||
| 292 | /* Register as a LIRC driver */ | ||
| 293 | if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) { | ||
| 294 | err("Could not get memory for LIRC data buffer\n"); | ||
| 295 | usb_set_intfdata(intf, NULL); | ||
| 296 | kfree(ttusbir); | ||
| 297 | return -ENOMEM; | ||
| 298 | } | ||
| 299 | strcpy(ttusbir->driver.name, "TTUSBIR"); | ||
| 300 | ttusbir->driver.minor = -1; | ||
| 301 | ttusbir->driver.code_length = 1; | ||
| 302 | ttusbir->driver.sample_rate = 0; | ||
| 303 | ttusbir->driver.data = ttusbir; | ||
| 304 | ttusbir->driver.add_to_buf = NULL; | ||
| 305 | ttusbir->driver.rbuf = &ttusbir->rbuf; | ||
| 306 | ttusbir->driver.set_use_inc = set_use_inc; | ||
| 307 | ttusbir->driver.set_use_dec = set_use_dec; | ||
| 308 | ttusbir->driver.dev = &intf->dev; | ||
| 309 | ttusbir->driver.owner = THIS_MODULE; | ||
| 310 | ttusbir->driver.features = LIRC_CAN_REC_MODE2; | ||
| 311 | ttusbir->minor = lirc_register_driver(&ttusbir->driver); | ||
| 312 | if (ttusbir->minor < 0) { | ||
| 313 | err("Error registering as LIRC driver\n"); | ||
| 314 | usb_set_intfdata(intf, NULL); | ||
| 315 | lirc_buffer_free(&ttusbir->rbuf); | ||
| 316 | kfree(ttusbir); | ||
| 317 | return -EIO; | ||
| 318 | } | ||
| 319 | |||
| 320 | /* Allocate and setup the URB that we will use to talk to the device */ | ||
| 321 | for (i = 0; i < num_urbs; i++) { | ||
| 322 | ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL); | ||
| 323 | if (!ttusbir->urb[i]) { | ||
| 324 | err("Could not allocate memory for the URB\n"); | ||
| 325 | for (j = i - 1; j >= 0; j--) | ||
| 326 | kfree(ttusbir->urb[j]); | ||
| 327 | lirc_buffer_free(&ttusbir->rbuf); | ||
| 328 | lirc_unregister_driver(ttusbir->minor); | ||
| 329 | kfree(ttusbir); | ||
| 330 | usb_set_intfdata(intf, NULL); | ||
| 331 | return -ENOMEM; | ||
| 332 | } | ||
| 333 | ttusbir->urb[i]->dev = ttusbir->udev; | ||
| 334 | ttusbir->urb[i]->context = ttusbir; | ||
| 335 | ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev, | ||
| 336 | ttusbir->endpoint); | ||
| 337 | ttusbir->urb[i]->interval = 1; | ||
| 338 | ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP; | ||
| 339 | ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0]; | ||
| 340 | ttusbir->urb[i]->complete = urb_complete; | ||
| 341 | ttusbir->urb[i]->number_of_packets = 8; | ||
| 342 | ttusbir->urb[i]->transfer_buffer_length = 128; | ||
| 343 | for (j = 0; j < 8; j++) { | ||
| 344 | ttusbir->urb[i]->iso_frame_desc[j].offset = j*16; | ||
| 345 | ttusbir->urb[i]->iso_frame_desc[j].length = 16; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | return 0; | ||
| 349 | } | ||
| 350 | |||
| 351 | /** | ||
| 352 | * Called when the driver is unloaded or the device is unplugged | ||
| 353 | */ | ||
| 354 | static void disconnect(struct usb_interface *intf) | ||
| 355 | { | ||
| 356 | int i; | ||
| 357 | struct ttusbir_device *ttusbir; | ||
| 358 | |||
| 359 | DPRINTK("Module ttusbir disconnect\n"); | ||
| 360 | |||
| 361 | ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf); | ||
| 362 | usb_set_intfdata(intf, NULL); | ||
| 363 | lirc_unregister_driver(ttusbir->minor); | ||
| 364 | DPRINTK("unregistered\n"); | ||
| 365 | |||
| 366 | for (i = 0; i < num_urbs; i++) { | ||
| 367 | usb_kill_urb(ttusbir->urb[i]); | ||
| 368 | usb_free_urb(ttusbir->urb[i]); | ||
| 369 | } | ||
| 370 | DPRINTK("URBs killed\n"); | ||
| 371 | lirc_buffer_free(&ttusbir->rbuf); | ||
| 372 | kfree(ttusbir); | ||
| 373 | } | ||
| 374 | |||
| 375 | static int ttusbir_init_module(void) | ||
| 376 | { | ||
| 377 | int result; | ||
| 378 | |||
| 379 | DPRINTK(KERN_DEBUG "Module ttusbir init\n"); | ||
| 380 | |||
| 381 | /* register this driver with the USB subsystem */ | ||
| 382 | result = usb_register(&usb_driver); | ||
| 383 | if (result) | ||
| 384 | err("usb_register failed. Error number %d", result); | ||
| 385 | return result; | ||
| 386 | } | ||
| 387 | |||
| 388 | static void ttusbir_exit_module(void) | ||
| 389 | { | ||
| 390 | printk(KERN_DEBUG "Module ttusbir exit\n"); | ||
| 391 | usb_deregister(&usb_driver); | ||
| 392 | } | ||
| 393 | |||
| 394 | module_init(ttusbir_init_module); | ||
| 395 | module_exit(ttusbir_exit_module); | ||
diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c new file mode 100644 index 00000000000..0302d82a12f --- /dev/null +++ b/drivers/staging/lirc/lirc_zilog.c | |||
| @@ -0,0 +1,1676 @@ | |||
| 1 | /* | ||
| 2 | * i2c IR lirc driver for devices with zilog IR processors | ||
| 3 | * | ||
| 4 | * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> | ||
| 5 | * modified for PixelView (BT878P+W/FM) by | ||
| 6 | * Michal Kochanowicz <mkochano@pld.org.pl> | ||
| 7 | * Christoph Bartelmus <lirc@bartelmus.de> | ||
| 8 | * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by | ||
| 9 | * Ulrich Mueller <ulrich.mueller42@web.de> | ||
| 10 | * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by | ||
| 11 | * Stefan Jahn <stefan@lkcc.org> | ||
| 12 | * modified for inclusion into kernel sources by | ||
| 13 | * Jerome Brock <jbrock@users.sourceforge.net> | ||
| 14 | * modified for Leadtek Winfast PVR2000 by | ||
| 15 | * Thomas Reitmayr (treitmayr@yahoo.com) | ||
| 16 | * modified for Hauppauge PVR-150 IR TX device by | ||
| 17 | * Mark Weaver <mark@npsl.co.uk> | ||
| 18 | * changed name from lirc_pvr150 to lirc_zilog, works on more than pvr-150 | ||
| 19 | * Jarod Wilson <jarod@redhat.com> | ||
| 20 | * | ||
| 21 | * parts are cut&pasted from the lirc_i2c.c driver | ||
| 22 | * | ||
| 23 | * Numerous changes updating lirc_zilog.c in kernel 2.6.38 and later are | ||
| 24 | * Copyright (C) 2011 Andy Walls <awalls@md.metrocast.net> | ||
| 25 | * | ||
| 26 | * This program is free software; you can redistribute it and/or modify | ||
| 27 | * it under the terms of the GNU General Public License as published by | ||
| 28 | * the Free Software Foundation; either version 2 of the License, or | ||
| 29 | * (at your option) any later version. | ||
| 30 | * | ||
| 31 | * This program is distributed in the hope that it will be useful, | ||
| 32 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 33 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 34 | * GNU General Public License for more details. | ||
| 35 | * | ||
| 36 | * You should have received a copy of the GNU General Public License | ||
| 37 | * along with this program; if not, write to the Free Software | ||
| 38 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 39 | * | ||
| 40 | */ | ||
| 41 | |||
| 42 | #include <linux/module.h> | ||
| 43 | #include <linux/kmod.h> | ||
| 44 | #include <linux/kernel.h> | ||
| 45 | #include <linux/sched.h> | ||
| 46 | #include <linux/fs.h> | ||
| 47 | #include <linux/poll.h> | ||
| 48 | #include <linux/string.h> | ||
| 49 | #include <linux/timer.h> | ||
| 50 | #include <linux/delay.h> | ||
| 51 | #include <linux/completion.h> | ||
| 52 | #include <linux/errno.h> | ||
| 53 | #include <linux/slab.h> | ||
| 54 | #include <linux/i2c.h> | ||
| 55 | #include <linux/firmware.h> | ||
| 56 | #include <linux/vmalloc.h> | ||
| 57 | |||
| 58 | #include <linux/mutex.h> | ||
| 59 | #include <linux/kthread.h> | ||
| 60 | |||
| 61 | #include <media/lirc_dev.h> | ||
| 62 | #include <media/lirc.h> | ||
| 63 | |||
| 64 | struct IR; | ||
| 65 | |||
| 66 | struct IR_rx { | ||
| 67 | struct kref ref; | ||
| 68 | struct IR *ir; | ||
| 69 | |||
| 70 | /* RX device */ | ||
| 71 | struct mutex client_lock; | ||
| 72 | struct i2c_client *c; | ||
| 73 | |||
| 74 | /* RX polling thread data */ | ||
| 75 | struct task_struct *task; | ||
| 76 | |||
| 77 | /* RX read data */ | ||
| 78 | unsigned char b[3]; | ||
| 79 | bool hdpvr_data_fmt; | ||
| 80 | }; | ||
| 81 | |||
| 82 | struct IR_tx { | ||
| 83 | struct kref ref; | ||
| 84 | struct IR *ir; | ||
| 85 | |||
| 86 | /* TX device */ | ||
| 87 | struct mutex client_lock; | ||
| 88 | struct i2c_client *c; | ||
| 89 | |||
| 90 | /* TX additional actions needed */ | ||
| 91 | int need_boot; | ||
| 92 | bool post_tx_ready_poll; | ||
| 93 | }; | ||
| 94 | |||
| 95 | struct IR { | ||
| 96 | struct kref ref; | ||
| 97 | struct list_head list; | ||
| 98 | |||
| 99 | /* FIXME spinlock access to l.features */ | ||
| 100 | struct lirc_driver l; | ||
| 101 | struct lirc_buffer rbuf; | ||
| 102 | |||
| 103 | struct mutex ir_lock; | ||
| 104 | atomic_t open_count; | ||
| 105 | |||
| 106 | struct i2c_adapter *adapter; | ||
| 107 | |||
| 108 | spinlock_t rx_ref_lock; /* struct IR_rx kref get()/put() */ | ||
| 109 | struct IR_rx *rx; | ||
| 110 | |||
| 111 | spinlock_t tx_ref_lock; /* struct IR_tx kref get()/put() */ | ||
| 112 | struct IR_tx *tx; | ||
| 113 | }; | ||
| 114 | |||
| 115 | /* IR transceiver instance object list */ | ||
| 116 | /* | ||
| 117 | * This lock is used for the following: | ||
| 118 | * a. ir_devices_list access, insertions, deletions | ||
| 119 | * b. struct IR kref get()s and put()s | ||
| 120 | * c. serialization of ir_probe() for the two i2c_clients for a Z8 | ||
| 121 | */ | ||
| 122 | static DEFINE_MUTEX(ir_devices_lock); | ||
| 123 | static LIST_HEAD(ir_devices_list); | ||
| 124 | |||
| 125 | /* Block size for IR transmitter */ | ||
| 126 | #define TX_BLOCK_SIZE 99 | ||
| 127 | |||
| 128 | /* Hauppauge IR transmitter data */ | ||
| 129 | struct tx_data_struct { | ||
| 130 | /* Boot block */ | ||
| 131 | unsigned char *boot_data; | ||
| 132 | |||
| 133 | /* Start of binary data block */ | ||
| 134 | unsigned char *datap; | ||
| 135 | |||
| 136 | /* End of binary data block */ | ||
| 137 | unsigned char *endp; | ||
| 138 | |||
| 139 | /* Number of installed codesets */ | ||
| 140 | unsigned int num_code_sets; | ||
| 141 | |||
| 142 | /* Pointers to codesets */ | ||
| 143 | unsigned char **code_sets; | ||
| 144 | |||
| 145 | /* Global fixed data template */ | ||
| 146 | int fixed[TX_BLOCK_SIZE]; | ||
| 147 | }; | ||
| 148 | |||
| 149 | static struct tx_data_struct *tx_data; | ||
| 150 | static struct mutex tx_data_lock; | ||
| 151 | |||
| 152 | #define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \ | ||
| 153 | ## args) | ||
| 154 | #define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) | ||
| 155 | #define zilog_info(s, args...) printk(KERN_INFO KBUILD_MODNAME ": " s, ## args) | ||
| 156 | |||
| 157 | /* module parameters */ | ||
| 158 | static int debug; /* debug output */ | ||
| 159 | static int tx_only; /* only handle the IR Tx function */ | ||
| 160 | static int minor = -1; /* minor number */ | ||
| 161 | |||
| 162 | #define dprintk(fmt, args...) \ | ||
| 163 | do { \ | ||
| 164 | if (debug) \ | ||
| 165 | printk(KERN_DEBUG KBUILD_MODNAME ": " fmt, \ | ||
| 166 | ## args); \ | ||
| 167 | } while (0) | ||
| 168 | |||
| 169 | |||
| 170 | /* struct IR reference counting */ | ||
| 171 | static struct IR *get_ir_device(struct IR *ir, bool ir_devices_lock_held) | ||
| 172 | { | ||
| 173 | if (ir_devices_lock_held) { | ||
| 174 | kref_get(&ir->ref); | ||
| 175 | } else { | ||
| 176 | mutex_lock(&ir_devices_lock); | ||
| 177 | kref_get(&ir->ref); | ||
| 178 | mutex_unlock(&ir_devices_lock); | ||
| 179 | } | ||
| 180 | return ir; | ||
| 181 | } | ||
| 182 | |||
| 183 | static void release_ir_device(struct kref *ref) | ||
| 184 | { | ||
| 185 | struct IR *ir = container_of(ref, struct IR, ref); | ||
| 186 | |||
| 187 | /* | ||
| 188 | * Things should be in this state by now: | ||
| 189 | * ir->rx set to NULL and deallocated - happens before ir->rx->ir put() | ||
| 190 | * ir->rx->task kthread stopped - happens before ir->rx->ir put() | ||
| 191 | * ir->tx set to NULL and deallocated - happens before ir->tx->ir put() | ||
| 192 | * ir->open_count == 0 - happens on final close() | ||
| 193 | * ir_lock, tx_ref_lock, rx_ref_lock, all released | ||
| 194 | */ | ||
| 195 | if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) { | ||
| 196 | lirc_unregister_driver(ir->l.minor); | ||
| 197 | ir->l.minor = MAX_IRCTL_DEVICES; | ||
| 198 | } | ||
| 199 | if (ir->rbuf.fifo_initialized) | ||
| 200 | lirc_buffer_free(&ir->rbuf); | ||
| 201 | list_del(&ir->list); | ||
| 202 | kfree(ir); | ||
| 203 | } | ||
| 204 | |||
| 205 | static int put_ir_device(struct IR *ir, bool ir_devices_lock_held) | ||
| 206 | { | ||
| 207 | int released; | ||
| 208 | |||
| 209 | if (ir_devices_lock_held) | ||
| 210 | return kref_put(&ir->ref, release_ir_device); | ||
| 211 | |||
| 212 | mutex_lock(&ir_devices_lock); | ||
| 213 | released = kref_put(&ir->ref, release_ir_device); | ||
| 214 | mutex_unlock(&ir_devices_lock); | ||
| 215 | |||
| 216 | return released; | ||
| 217 | } | ||
| 218 | |||
| 219 | /* struct IR_rx reference counting */ | ||
| 220 | static struct IR_rx *get_ir_rx(struct IR *ir) | ||
| 221 | { | ||
| 222 | struct IR_rx *rx; | ||
| 223 | |||
| 224 | spin_lock(&ir->rx_ref_lock); | ||
| 225 | rx = ir->rx; | ||
| 226 | if (rx != NULL) | ||
| 227 | kref_get(&rx->ref); | ||
| 228 | spin_unlock(&ir->rx_ref_lock); | ||
| 229 | return rx; | ||
| 230 | } | ||
| 231 | |||
| 232 | static void destroy_rx_kthread(struct IR_rx *rx, bool ir_devices_lock_held) | ||
| 233 | { | ||
| 234 | /* end up polling thread */ | ||
| 235 | if (!IS_ERR_OR_NULL(rx->task)) { | ||
| 236 | kthread_stop(rx->task); | ||
| 237 | rx->task = NULL; | ||
| 238 | /* Put the ir ptr that ir_probe() gave to the rx poll thread */ | ||
| 239 | put_ir_device(rx->ir, ir_devices_lock_held); | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | static void release_ir_rx(struct kref *ref) | ||
| 244 | { | ||
| 245 | struct IR_rx *rx = container_of(ref, struct IR_rx, ref); | ||
| 246 | struct IR *ir = rx->ir; | ||
| 247 | |||
| 248 | /* | ||
| 249 | * This release function can't do all the work, as we want | ||
| 250 | * to keep the rx_ref_lock a spinlock, and killing the poll thread | ||
| 251 | * and releasing the ir reference can cause a sleep. That work is | ||
| 252 | * performed by put_ir_rx() | ||
| 253 | */ | ||
| 254 | ir->l.features &= ~LIRC_CAN_REC_LIRCCODE; | ||
| 255 | /* Don't put_ir_device(rx->ir) here; lock can't be freed yet */ | ||
| 256 | ir->rx = NULL; | ||
| 257 | /* Don't do the kfree(rx) here; we still need to kill the poll thread */ | ||
| 258 | return; | ||
| 259 | } | ||
| 260 | |||
| 261 | static int put_ir_rx(struct IR_rx *rx, bool ir_devices_lock_held) | ||
| 262 | { | ||
| 263 | int released; | ||
| 264 | struct IR *ir = rx->ir; | ||
| 265 | |||
| 266 | spin_lock(&ir->rx_ref_lock); | ||
| 267 | released = kref_put(&rx->ref, release_ir_rx); | ||
| 268 | spin_unlock(&ir->rx_ref_lock); | ||
| 269 | /* Destroy the rx kthread while not holding the spinlock */ | ||
| 270 | if (released) { | ||
| 271 | destroy_rx_kthread(rx, ir_devices_lock_held); | ||
| 272 | kfree(rx); | ||
| 273 | /* Make sure we're not still in a poll_table somewhere */ | ||
| 274 | wake_up_interruptible(&ir->rbuf.wait_poll); | ||
| 275 | } | ||
| 276 | /* Do a reference put() for the rx->ir reference, if we released rx */ | ||
| 277 | if (released) | ||
| 278 | put_ir_device(ir, ir_devices_lock_held); | ||
| 279 | return released; | ||
| 280 | } | ||
| 281 | |||
| 282 | /* struct IR_tx reference counting */ | ||
| 283 | static struct IR_tx *get_ir_tx(struct IR *ir) | ||
| 284 | { | ||
| 285 | struct IR_tx *tx; | ||
| 286 | |||
| 287 | spin_lock(&ir->tx_ref_lock); | ||
| 288 | tx = ir->tx; | ||
| 289 | if (tx != NULL) | ||
| 290 | kref_get(&tx->ref); | ||
| 291 | spin_unlock(&ir->tx_ref_lock); | ||
| 292 | return tx; | ||
| 293 | } | ||
| 294 | |||
| 295 | static void release_ir_tx(struct kref *ref) | ||
| 296 | { | ||
| 297 | struct IR_tx *tx = container_of(ref, struct IR_tx, ref); | ||
| 298 | struct IR *ir = tx->ir; | ||
| 299 | |||
| 300 | ir->l.features &= ~LIRC_CAN_SEND_PULSE; | ||
| 301 | /* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */ | ||
| 302 | ir->tx = NULL; | ||
| 303 | kfree(tx); | ||
| 304 | } | ||
| 305 | |||
| 306 | static int put_ir_tx(struct IR_tx *tx, bool ir_devices_lock_held) | ||
| 307 | { | ||
| 308 | int released; | ||
| 309 | struct IR *ir = tx->ir; | ||
| 310 | |||
| 311 | spin_lock(&ir->tx_ref_lock); | ||
| 312 | released = kref_put(&tx->ref, release_ir_tx); | ||
| 313 | spin_unlock(&ir->tx_ref_lock); | ||
| 314 | /* Do a reference put() for the tx->ir reference, if we released tx */ | ||
| 315 | if (released) | ||
| 316 | put_ir_device(ir, ir_devices_lock_held); | ||
| 317 | return released; | ||
| 318 | } | ||
| 319 | |||
| 320 | static int add_to_buf(struct IR *ir) | ||
| 321 | { | ||
| 322 | __u16 code; | ||
| 323 | unsigned char codes[2]; | ||
| 324 | unsigned char keybuf[6]; | ||
| 325 | int got_data = 0; | ||
| 326 | int ret; | ||
| 327 | int failures = 0; | ||
| 328 | unsigned char sendbuf[1] = { 0 }; | ||
| 329 | struct lirc_buffer *rbuf = ir->l.rbuf; | ||
| 330 | struct IR_rx *rx; | ||
| 331 | struct IR_tx *tx; | ||
| 332 | |||
| 333 | if (lirc_buffer_full(rbuf)) { | ||
| 334 | dprintk("buffer overflow\n"); | ||
| 335 | return -EOVERFLOW; | ||
| 336 | } | ||
| 337 | |||
| 338 | rx = get_ir_rx(ir); | ||
| 339 | if (rx == NULL) | ||
| 340 | return -ENXIO; | ||
| 341 | |||
| 342 | /* Ensure our rx->c i2c_client remains valid for the duration */ | ||
| 343 | mutex_lock(&rx->client_lock); | ||
| 344 | if (rx->c == NULL) { | ||
| 345 | mutex_unlock(&rx->client_lock); | ||
| 346 | put_ir_rx(rx, false); | ||
| 347 | return -ENXIO; | ||
| 348 | } | ||
| 349 | |||
| 350 | tx = get_ir_tx(ir); | ||
| 351 | |||
| 352 | /* | ||
| 353 | * service the device as long as it is returning | ||
| 354 | * data and we have space | ||
| 355 | */ | ||
| 356 | do { | ||
| 357 | if (kthread_should_stop()) { | ||
| 358 | ret = -ENODATA; | ||
| 359 | break; | ||
| 360 | } | ||
| 361 | |||
| 362 | /* | ||
| 363 | * Lock i2c bus for the duration. RX/TX chips interfere so | ||
| 364 | * this is worth it | ||
| 365 | */ | ||
| 366 | mutex_lock(&ir->ir_lock); | ||
| 367 | |||
| 368 | if (kthread_should_stop()) { | ||
| 369 | mutex_unlock(&ir->ir_lock); | ||
| 370 | ret = -ENODATA; | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | |||
| 374 | /* | ||
| 375 | * Send random "poll command" (?) Windows driver does this | ||
| 376 | * and it is a good point to detect chip failure. | ||
| 377 | */ | ||
| 378 | ret = i2c_master_send(rx->c, sendbuf, 1); | ||
| 379 | if (ret != 1) { | ||
| 380 | zilog_error("i2c_master_send failed with %d\n", ret); | ||
| 381 | if (failures >= 3) { | ||
| 382 | mutex_unlock(&ir->ir_lock); | ||
| 383 | zilog_error("unable to read from the IR chip " | ||
| 384 | "after 3 resets, giving up\n"); | ||
| 385 | break; | ||
| 386 | } | ||
| 387 | |||
| 388 | /* Looks like the chip crashed, reset it */ | ||
| 389 | zilog_error("polling the IR receiver chip failed, " | ||
| 390 | "trying reset\n"); | ||
| 391 | |||
| 392 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 393 | if (kthread_should_stop()) { | ||
| 394 | mutex_unlock(&ir->ir_lock); | ||
| 395 | ret = -ENODATA; | ||
| 396 | break; | ||
| 397 | } | ||
| 398 | schedule_timeout((100 * HZ + 999) / 1000); | ||
| 399 | if (tx != NULL) | ||
| 400 | tx->need_boot = 1; | ||
| 401 | |||
| 402 | ++failures; | ||
| 403 | mutex_unlock(&ir->ir_lock); | ||
| 404 | ret = 0; | ||
| 405 | continue; | ||
| 406 | } | ||
| 407 | |||
| 408 | if (kthread_should_stop()) { | ||
| 409 | mutex_unlock(&ir->ir_lock); | ||
| 410 | ret = -ENODATA; | ||
| 411 | break; | ||
| 412 | } | ||
| 413 | ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf)); | ||
| 414 | mutex_unlock(&ir->ir_lock); | ||
| 415 | if (ret != sizeof(keybuf)) { | ||
| 416 | zilog_error("i2c_master_recv failed with %d -- " | ||
| 417 | "keeping last read buffer\n", ret); | ||
| 418 | } else { | ||
| 419 | rx->b[0] = keybuf[3]; | ||
| 420 | rx->b[1] = keybuf[4]; | ||
| 421 | rx->b[2] = keybuf[5]; | ||
| 422 | dprintk("key (0x%02x/0x%02x)\n", rx->b[0], rx->b[1]); | ||
| 423 | } | ||
| 424 | |||
| 425 | /* key pressed ? */ | ||
| 426 | if (rx->hdpvr_data_fmt) { | ||
| 427 | if (got_data && (keybuf[0] == 0x80)) { | ||
| 428 | ret = 0; | ||
| 429 | break; | ||
| 430 | } else if (got_data && (keybuf[0] == 0x00)) { | ||
| 431 | ret = -ENODATA; | ||
| 432 | break; | ||
| 433 | } | ||
| 434 | } else if ((rx->b[0] & 0x80) == 0) { | ||
| 435 | ret = got_data ? 0 : -ENODATA; | ||
| 436 | break; | ||
| 437 | } | ||
| 438 | |||
| 439 | /* look what we have */ | ||
| 440 | code = (((__u16)rx->b[0] & 0x7f) << 6) | (rx->b[1] >> 2); | ||
| 441 | |||
| 442 | codes[0] = (code >> 8) & 0xff; | ||
| 443 | codes[1] = code & 0xff; | ||
| 444 | |||
| 445 | /* return it */ | ||
| 446 | lirc_buffer_write(rbuf, codes); | ||
| 447 | ++got_data; | ||
| 448 | ret = 0; | ||
| 449 | } while (!lirc_buffer_full(rbuf)); | ||
| 450 | |||
| 451 | mutex_unlock(&rx->client_lock); | ||
| 452 | if (tx != NULL) | ||
| 453 | put_ir_tx(tx, false); | ||
| 454 | put_ir_rx(rx, false); | ||
| 455 | return ret; | ||
| 456 | } | ||
| 457 | |||
| 458 | /* | ||
| 459 | * Main function of the polling thread -- from lirc_dev. | ||
| 460 | * We don't fit the LIRC model at all anymore. This is horrible, but | ||
| 461 | * basically we have a single RX/TX device with a nasty failure mode | ||
| 462 | * that needs to be accounted for across the pair. lirc lets us provide | ||
| 463 | * fops, but prevents us from using the internal polling, etc. if we do | ||
| 464 | * so. Hence the replication. Might be neater to extend the LIRC model | ||
| 465 | * to account for this but I'd think it's a very special case of seriously | ||
| 466 | * messed up hardware. | ||
| 467 | */ | ||
| 468 | static int lirc_thread(void *arg) | ||
| 469 | { | ||
| 470 | struct IR *ir = arg; | ||
| 471 | struct lirc_buffer *rbuf = ir->l.rbuf; | ||
| 472 | |||
| 473 | dprintk("poll thread started\n"); | ||
| 474 | |||
| 475 | while (!kthread_should_stop()) { | ||
| 476 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 477 | |||
| 478 | /* if device not opened, we can sleep half a second */ | ||
| 479 | if (atomic_read(&ir->open_count) == 0) { | ||
| 480 | schedule_timeout(HZ/2); | ||
| 481 | continue; | ||
| 482 | } | ||
| 483 | |||
| 484 | /* | ||
| 485 | * This is ~113*2 + 24 + jitter (2*repeat gap + code length). | ||
| 486 | * We use this interval as the chip resets every time you poll | ||
| 487 | * it (bad!). This is therefore just sufficient to catch all | ||
| 488 | * of the button presses. It makes the remote much more | ||
| 489 | * responsive. You can see the difference by running irw and | ||
| 490 | * holding down a button. With 100ms, the old polling | ||
| 491 | * interval, you'll notice breaks in the repeat sequence | ||
| 492 | * corresponding to lost keypresses. | ||
| 493 | */ | ||
| 494 | schedule_timeout((260 * HZ) / 1000); | ||
| 495 | if (kthread_should_stop()) | ||
| 496 | break; | ||
| 497 | if (!add_to_buf(ir)) | ||
| 498 | wake_up_interruptible(&rbuf->wait_poll); | ||
| 499 | } | ||
| 500 | |||
| 501 | dprintk("poll thread ended\n"); | ||
| 502 | return 0; | ||
| 503 | } | ||
| 504 | |||
| 505 | static int set_use_inc(void *data) | ||
| 506 | { | ||
| 507 | return 0; | ||
| 508 | } | ||
| 509 | |||
| 510 | static void set_use_dec(void *data) | ||
| 511 | { | ||
| 512 | return; | ||
| 513 | } | ||
| 514 | |||
| 515 | /* safe read of a uint32 (always network byte order) */ | ||
| 516 | static int read_uint32(unsigned char **data, | ||
| 517 | unsigned char *endp, unsigned int *val) | ||
| 518 | { | ||
| 519 | if (*data + 4 > endp) | ||
| 520 | return 0; | ||
| 521 | *val = ((*data)[0] << 24) | ((*data)[1] << 16) | | ||
| 522 | ((*data)[2] << 8) | (*data)[3]; | ||
| 523 | *data += 4; | ||
| 524 | return 1; | ||
| 525 | } | ||
| 526 | |||
| 527 | /* safe read of a uint8 */ | ||
| 528 | static int read_uint8(unsigned char **data, | ||
| 529 | unsigned char *endp, unsigned char *val) | ||
| 530 | { | ||
| 531 | if (*data + 1 > endp) | ||
| 532 | return 0; | ||
| 533 | *val = *((*data)++); | ||
| 534 | return 1; | ||
| 535 | } | ||
| 536 | |||
| 537 | /* safe skipping of N bytes */ | ||
| 538 | static int skip(unsigned char **data, | ||
| 539 | unsigned char *endp, unsigned int distance) | ||
| 540 | { | ||
| 541 | if (*data + distance > endp) | ||
| 542 | return 0; | ||
| 543 | *data += distance; | ||
| 544 | return 1; | ||
| 545 | } | ||
| 546 | |||
| 547 | /* decompress key data into the given buffer */ | ||
| 548 | static int get_key_data(unsigned char *buf, | ||
| 549 | unsigned int codeset, unsigned int key) | ||
| 550 | { | ||
| 551 | unsigned char *data, *endp, *diffs, *key_block; | ||
| 552 | unsigned char keys, ndiffs, id; | ||
| 553 | unsigned int base, lim, pos, i; | ||
| 554 | |||
| 555 | /* Binary search for the codeset */ | ||
| 556 | for (base = 0, lim = tx_data->num_code_sets; lim; lim >>= 1) { | ||
| 557 | pos = base + (lim >> 1); | ||
| 558 | data = tx_data->code_sets[pos]; | ||
| 559 | |||
| 560 | if (!read_uint32(&data, tx_data->endp, &i)) | ||
| 561 | goto corrupt; | ||
| 562 | |||
| 563 | if (i == codeset) | ||
| 564 | break; | ||
| 565 | else if (codeset > i) { | ||
| 566 | base = pos + 1; | ||
| 567 | --lim; | ||
| 568 | } | ||
| 569 | } | ||
| 570 | /* Not found? */ | ||
| 571 | if (!lim) | ||
| 572 | return -EPROTO; | ||
| 573 | |||
| 574 | /* Set end of data block */ | ||
| 575 | endp = pos < tx_data->num_code_sets - 1 ? | ||
| 576 | tx_data->code_sets[pos + 1] : tx_data->endp; | ||
| 577 | |||
| 578 | /* Read the block header */ | ||
| 579 | if (!read_uint8(&data, endp, &keys) || | ||
| 580 | !read_uint8(&data, endp, &ndiffs) || | ||
| 581 | ndiffs > TX_BLOCK_SIZE || keys == 0) | ||
| 582 | goto corrupt; | ||
| 583 | |||
| 584 | /* Save diffs & skip */ | ||
| 585 | diffs = data; | ||
| 586 | if (!skip(&data, endp, ndiffs)) | ||
| 587 | goto corrupt; | ||
| 588 | |||
| 589 | /* Read the id of the first key */ | ||
| 590 | if (!read_uint8(&data, endp, &id)) | ||
| 591 | goto corrupt; | ||
| 592 | |||
| 593 | /* Unpack the first key's data */ | ||
| 594 | for (i = 0; i < TX_BLOCK_SIZE; ++i) { | ||
| 595 | if (tx_data->fixed[i] == -1) { | ||
| 596 | if (!read_uint8(&data, endp, &buf[i])) | ||
| 597 | goto corrupt; | ||
| 598 | } else { | ||
| 599 | buf[i] = (unsigned char)tx_data->fixed[i]; | ||
| 600 | } | ||
| 601 | } | ||
| 602 | |||
| 603 | /* Early out key found/not found */ | ||
| 604 | if (key == id) | ||
| 605 | return 0; | ||
| 606 | if (keys == 1) | ||
| 607 | return -EPROTO; | ||
| 608 | |||
| 609 | /* Sanity check */ | ||
| 610 | key_block = data; | ||
| 611 | if (!skip(&data, endp, (keys - 1) * (ndiffs + 1))) | ||
| 612 | goto corrupt; | ||
| 613 | |||
| 614 | /* Binary search for the key */ | ||
| 615 | for (base = 0, lim = keys - 1; lim; lim >>= 1) { | ||
| 616 | /* Seek to block */ | ||
| 617 | unsigned char *key_data; | ||
| 618 | pos = base + (lim >> 1); | ||
| 619 | key_data = key_block + (ndiffs + 1) * pos; | ||
| 620 | |||
| 621 | if (*key_data == key) { | ||
| 622 | /* skip key id */ | ||
| 623 | ++key_data; | ||
| 624 | |||
| 625 | /* found, so unpack the diffs */ | ||
| 626 | for (i = 0; i < ndiffs; ++i) { | ||
| 627 | unsigned char val; | ||
| 628 | if (!read_uint8(&key_data, endp, &val) || | ||
| 629 | diffs[i] >= TX_BLOCK_SIZE) | ||
| 630 | goto corrupt; | ||
| 631 | buf[diffs[i]] = val; | ||
| 632 | } | ||
| 633 | |||
| 634 | return 0; | ||
| 635 | } else if (key > *key_data) { | ||
| 636 | base = pos + 1; | ||
| 637 | --lim; | ||
| 638 | } | ||
| 639 | } | ||
| 640 | /* Key not found */ | ||
| 641 | return -EPROTO; | ||
| 642 | |||
| 643 | corrupt: | ||
| 644 | zilog_error("firmware is corrupt\n"); | ||
| 645 | return -EFAULT; | ||
| 646 | } | ||
| 647 | |||
| 648 | /* send a block of data to the IR TX device */ | ||
| 649 | static int send_data_block(struct IR_tx *tx, unsigned char *data_block) | ||
| 650 | { | ||
| 651 | int i, j, ret; | ||
| 652 | unsigned char buf[5]; | ||
| 653 | |||
| 654 | for (i = 0; i < TX_BLOCK_SIZE;) { | ||
| 655 | int tosend = TX_BLOCK_SIZE - i; | ||
| 656 | if (tosend > 4) | ||
| 657 | tosend = 4; | ||
| 658 | buf[0] = (unsigned char)(i + 1); | ||
| 659 | for (j = 0; j < tosend; ++j) | ||
| 660 | buf[1 + j] = data_block[i + j]; | ||
| 661 | dprintk("%02x %02x %02x %02x %02x", | ||
| 662 | buf[0], buf[1], buf[2], buf[3], buf[4]); | ||
| 663 | ret = i2c_master_send(tx->c, buf, tosend + 1); | ||
| 664 | if (ret != tosend + 1) { | ||
| 665 | zilog_error("i2c_master_send failed with %d\n", ret); | ||
| 666 | return ret < 0 ? ret : -EFAULT; | ||
| 667 | } | ||
| 668 | i += tosend; | ||
| 669 | } | ||
| 670 | return 0; | ||
| 671 | } | ||
| 672 | |||
| 673 | /* send boot data to the IR TX device */ | ||
| 674 | static int send_boot_data(struct IR_tx *tx) | ||
| 675 | { | ||
| 676 | int ret, i; | ||
| 677 | unsigned char buf[4]; | ||
| 678 | |||
| 679 | /* send the boot block */ | ||
| 680 | ret = send_data_block(tx, tx_data->boot_data); | ||
| 681 | if (ret != 0) | ||
| 682 | return ret; | ||
| 683 | |||
| 684 | /* Hit the go button to activate the new boot data */ | ||
| 685 | buf[0] = 0x00; | ||
| 686 | buf[1] = 0x20; | ||
| 687 | ret = i2c_master_send(tx->c, buf, 2); | ||
| 688 | if (ret != 2) { | ||
| 689 | zilog_error("i2c_master_send failed with %d\n", ret); | ||
| 690 | return ret < 0 ? ret : -EFAULT; | ||
| 691 | } | ||
| 692 | |||
| 693 | /* | ||
| 694 | * Wait for zilog to settle after hitting go post boot block upload. | ||
| 695 | * Without this delay, the HD-PVR and HVR-1950 both return an -EIO | ||
| 696 | * upon attempting to get firmware revision, and tx probe thus fails. | ||
| 697 | */ | ||
| 698 | for (i = 0; i < 10; i++) { | ||
| 699 | ret = i2c_master_send(tx->c, buf, 1); | ||
| 700 | if (ret == 1) | ||
| 701 | break; | ||
| 702 | udelay(100); | ||
| 703 | } | ||
| 704 | |||
| 705 | if (ret != 1) { | ||
| 706 | zilog_error("i2c_master_send failed with %d\n", ret); | ||
| 707 | return ret < 0 ? ret : -EFAULT; | ||
| 708 | } | ||
| 709 | |||
| 710 | /* Here comes the firmware version... (hopefully) */ | ||
| 711 | ret = i2c_master_recv(tx->c, buf, 4); | ||
| 712 | if (ret != 4) { | ||
| 713 | zilog_error("i2c_master_recv failed with %d\n", ret); | ||
| 714 | return 0; | ||
| 715 | } | ||
| 716 | if ((buf[0] != 0x80) && (buf[0] != 0xa0)) { | ||
| 717 | zilog_error("unexpected IR TX init response: %02x\n", buf[0]); | ||
| 718 | return 0; | ||
| 719 | } | ||
| 720 | zilog_notify("Zilog/Hauppauge IR blaster firmware version " | ||
| 721 | "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]); | ||
| 722 | |||
| 723 | return 0; | ||
| 724 | } | ||
| 725 | |||
| 726 | /* unload "firmware", lock held */ | ||
| 727 | static void fw_unload_locked(void) | ||
| 728 | { | ||
| 729 | if (tx_data) { | ||
| 730 | if (tx_data->code_sets) | ||
| 731 | vfree(tx_data->code_sets); | ||
| 732 | |||
| 733 | if (tx_data->datap) | ||
| 734 | vfree(tx_data->datap); | ||
| 735 | |||
| 736 | vfree(tx_data); | ||
| 737 | tx_data = NULL; | ||
| 738 | dprintk("successfully unloaded IR blaster firmware\n"); | ||
| 739 | } | ||
| 740 | } | ||
| 741 | |||
| 742 | /* unload "firmware" for the IR TX device */ | ||
| 743 | static void fw_unload(void) | ||
| 744 | { | ||
| 745 | mutex_lock(&tx_data_lock); | ||
| 746 | fw_unload_locked(); | ||
| 747 | mutex_unlock(&tx_data_lock); | ||
| 748 | } | ||
| 749 | |||
| 750 | /* load "firmware" for the IR TX device */ | ||
| 751 | static int fw_load(struct IR_tx *tx) | ||
| 752 | { | ||
| 753 | int ret; | ||
| 754 | unsigned int i; | ||
| 755 | unsigned char *data, version, num_global_fixed; | ||
| 756 | const struct firmware *fw_entry; | ||
| 757 | |||
| 758 | /* Already loaded? */ | ||
| 759 | mutex_lock(&tx_data_lock); | ||
| 760 | if (tx_data) { | ||
| 761 | ret = 0; | ||
| 762 | goto out; | ||
| 763 | } | ||
| 764 | |||
| 765 | /* Request codeset data file */ | ||
| 766 | ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->l.dev); | ||
| 767 | if (ret != 0) { | ||
| 768 | zilog_error("firmware haup-ir-blaster.bin not available " | ||
| 769 | "(%d)\n", ret); | ||
| 770 | ret = ret < 0 ? ret : -EFAULT; | ||
| 771 | goto out; | ||
| 772 | } | ||
| 773 | dprintk("firmware of size %zu loaded\n", fw_entry->size); | ||
| 774 | |||
| 775 | /* Parse the file */ | ||
| 776 | tx_data = vmalloc(sizeof(*tx_data)); | ||
| 777 | if (tx_data == NULL) { | ||
| 778 | zilog_error("out of memory\n"); | ||
| 779 | release_firmware(fw_entry); | ||
| 780 | ret = -ENOMEM; | ||
| 781 | goto out; | ||
| 782 | } | ||
| 783 | tx_data->code_sets = NULL; | ||
| 784 | |||
| 785 | /* Copy the data so hotplug doesn't get confused and timeout */ | ||
| 786 | tx_data->datap = vmalloc(fw_entry->size); | ||
| 787 | if (tx_data->datap == NULL) { | ||
| 788 | zilog_error("out of memory\n"); | ||
| 789 | release_firmware(fw_entry); | ||
| 790 | vfree(tx_data); | ||
| 791 | ret = -ENOMEM; | ||
| 792 | goto out; | ||
| 793 | } | ||
| 794 | memcpy(tx_data->datap, fw_entry->data, fw_entry->size); | ||
| 795 | tx_data->endp = tx_data->datap + fw_entry->size; | ||
| 796 | release_firmware(fw_entry); fw_entry = NULL; | ||
| 797 | |||
| 798 | /* Check version */ | ||
| 799 | data = tx_data->datap; | ||
| 800 | if (!read_uint8(&data, tx_data->endp, &version)) | ||
| 801 | goto corrupt; | ||
| 802 | if (version != 1) { | ||
| 803 | zilog_error("unsupported code set file version (%u, expected" | ||
| 804 | "1) -- please upgrade to a newer driver", | ||
| 805 | version); | ||
| 806 | fw_unload_locked(); | ||
| 807 | ret = -EFAULT; | ||
| 808 | goto out; | ||
| 809 | } | ||
| 810 | |||
| 811 | /* Save boot block for later */ | ||
| 812 | tx_data->boot_data = data; | ||
| 813 | if (!skip(&data, tx_data->endp, TX_BLOCK_SIZE)) | ||
| 814 | goto corrupt; | ||
| 815 | |||
| 816 | if (!read_uint32(&data, tx_data->endp, | ||
| 817 | &tx_data->num_code_sets)) | ||
| 818 | goto corrupt; | ||
| 819 | |||
| 820 | dprintk("%u IR blaster codesets loaded\n", tx_data->num_code_sets); | ||
| 821 | |||
| 822 | tx_data->code_sets = vmalloc( | ||
| 823 | tx_data->num_code_sets * sizeof(char *)); | ||
| 824 | if (tx_data->code_sets == NULL) { | ||
| 825 | fw_unload_locked(); | ||
| 826 | ret = -ENOMEM; | ||
| 827 | goto out; | ||
| 828 | } | ||
| 829 | |||
| 830 | for (i = 0; i < TX_BLOCK_SIZE; ++i) | ||
| 831 | tx_data->fixed[i] = -1; | ||
| 832 | |||
| 833 | /* Read global fixed data template */ | ||
| 834 | if (!read_uint8(&data, tx_data->endp, &num_global_fixed) || | ||
| 835 | num_global_fixed > TX_BLOCK_SIZE) | ||
| 836 | goto corrupt; | ||
| 837 | for (i = 0; i < num_global_fixed; ++i) { | ||
| 838 | unsigned char pos, val; | ||
| 839 | if (!read_uint8(&data, tx_data->endp, &pos) || | ||
| 840 | !read_uint8(&data, tx_data->endp, &val) || | ||
| 841 | pos >= TX_BLOCK_SIZE) | ||
| 842 | goto corrupt; | ||
| 843 | tx_data->fixed[pos] = (int)val; | ||
| 844 | } | ||
| 845 | |||
| 846 | /* Filch out the position of each code set */ | ||
| 847 | for (i = 0; i < tx_data->num_code_sets; ++i) { | ||
| 848 | unsigned int id; | ||
| 849 | unsigned char keys; | ||
| 850 | unsigned char ndiffs; | ||
| 851 | |||
| 852 | /* Save the codeset position */ | ||
| 853 | tx_data->code_sets[i] = data; | ||
| 854 | |||
| 855 | /* Read header */ | ||
| 856 | if (!read_uint32(&data, tx_data->endp, &id) || | ||
| 857 | !read_uint8(&data, tx_data->endp, &keys) || | ||
| 858 | !read_uint8(&data, tx_data->endp, &ndiffs) || | ||
| 859 | ndiffs > TX_BLOCK_SIZE || keys == 0) | ||
| 860 | goto corrupt; | ||
| 861 | |||
| 862 | /* skip diff positions */ | ||
| 863 | if (!skip(&data, tx_data->endp, ndiffs)) | ||
| 864 | goto corrupt; | ||
| 865 | |||
| 866 | /* | ||
| 867 | * After the diffs we have the first key id + data - | ||
| 868 | * global fixed | ||
| 869 | */ | ||
| 870 | if (!skip(&data, tx_data->endp, | ||
| 871 | 1 + TX_BLOCK_SIZE - num_global_fixed)) | ||
| 872 | goto corrupt; | ||
| 873 | |||
| 874 | /* Then we have keys-1 blocks of key id+diffs */ | ||
| 875 | if (!skip(&data, tx_data->endp, | ||
| 876 | (ndiffs + 1) * (keys - 1))) | ||
| 877 | goto corrupt; | ||
| 878 | } | ||
| 879 | ret = 0; | ||
| 880 | goto out; | ||
| 881 | |||
| 882 | corrupt: | ||
| 883 | zilog_error("firmware is corrupt\n"); | ||
| 884 | fw_unload_locked(); | ||
| 885 | ret = -EFAULT; | ||
| 886 | |||
| 887 | out: | ||
| 888 | mutex_unlock(&tx_data_lock); | ||
| 889 | return ret; | ||
| 890 | } | ||
| 891 | |||
| 892 | /* copied from lirc_dev */ | ||
| 893 | static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) | ||
| 894 | { | ||
| 895 | struct IR *ir = filep->private_data; | ||
| 896 | struct IR_rx *rx; | ||
| 897 | struct lirc_buffer *rbuf = ir->l.rbuf; | ||
| 898 | int ret = 0, written = 0, retries = 0; | ||
| 899 | unsigned int m; | ||
| 900 | DECLARE_WAITQUEUE(wait, current); | ||
| 901 | |||
| 902 | dprintk("read called\n"); | ||
| 903 | if (n % rbuf->chunk_size) { | ||
| 904 | dprintk("read result = -EINVAL\n"); | ||
| 905 | return -EINVAL; | ||
| 906 | } | ||
| 907 | |||
| 908 | rx = get_ir_rx(ir); | ||
| 909 | if (rx == NULL) | ||
| 910 | return -ENXIO; | ||
| 911 | |||
| 912 | /* | ||
| 913 | * we add ourselves to the task queue before buffer check | ||
| 914 | * to avoid losing scan code (in case when queue is awaken somewhere | ||
| 915 | * between while condition checking and scheduling) | ||
| 916 | */ | ||
| 917 | add_wait_queue(&rbuf->wait_poll, &wait); | ||
| 918 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 919 | |||
| 920 | /* | ||
| 921 | * while we didn't provide 'length' bytes, device is opened in blocking | ||
| 922 | * mode and 'copy_to_user' is happy, wait for data. | ||
| 923 | */ | ||
| 924 | while (written < n && ret == 0) { | ||
| 925 | if (lirc_buffer_empty(rbuf)) { | ||
| 926 | /* | ||
| 927 | * According to the read(2) man page, 'written' can be | ||
| 928 | * returned as less than 'n', instead of blocking | ||
| 929 | * again, returning -EWOULDBLOCK, or returning | ||
| 930 | * -ERESTARTSYS | ||
| 931 | */ | ||
| 932 | if (written) | ||
| 933 | break; | ||
| 934 | if (filep->f_flags & O_NONBLOCK) { | ||
| 935 | ret = -EWOULDBLOCK; | ||
| 936 | break; | ||
| 937 | } | ||
| 938 | if (signal_pending(current)) { | ||
| 939 | ret = -ERESTARTSYS; | ||
| 940 | break; | ||
| 941 | } | ||
| 942 | schedule(); | ||
| 943 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 944 | } else { | ||
| 945 | unsigned char buf[rbuf->chunk_size]; | ||
| 946 | m = lirc_buffer_read(rbuf, buf); | ||
| 947 | if (m == rbuf->chunk_size) { | ||
| 948 | ret = copy_to_user((void *)outbuf+written, buf, | ||
| 949 | rbuf->chunk_size); | ||
| 950 | written += rbuf->chunk_size; | ||
| 951 | } else { | ||
| 952 | retries++; | ||
| 953 | } | ||
| 954 | if (retries >= 5) { | ||
| 955 | zilog_error("Buffer read failed!\n"); | ||
| 956 | ret = -EIO; | ||
| 957 | } | ||
| 958 | } | ||
| 959 | } | ||
| 960 | |||
| 961 | remove_wait_queue(&rbuf->wait_poll, &wait); | ||
| 962 | put_ir_rx(rx, false); | ||
| 963 | set_current_state(TASK_RUNNING); | ||
| 964 | |||
| 965 | dprintk("read result = %d (%s)\n", ret, ret ? "Error" : "OK"); | ||
| 966 | |||
| 967 | return ret ? ret : written; | ||
| 968 | } | ||
| 969 | |||
| 970 | /* send a keypress to the IR TX device */ | ||
| 971 | static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) | ||
| 972 | { | ||
| 973 | unsigned char data_block[TX_BLOCK_SIZE]; | ||
| 974 | unsigned char buf[2]; | ||
| 975 | int i, ret; | ||
| 976 | |||
| 977 | /* Get data for the codeset/key */ | ||
| 978 | ret = get_key_data(data_block, code, key); | ||
| 979 | |||
| 980 | if (ret == -EPROTO) { | ||
| 981 | zilog_error("failed to get data for code %u, key %u -- check " | ||
| 982 | "lircd.conf entries\n", code, key); | ||
| 983 | return ret; | ||
| 984 | } else if (ret != 0) | ||
| 985 | return ret; | ||
| 986 | |||
| 987 | /* Send the data block */ | ||
| 988 | ret = send_data_block(tx, data_block); | ||
| 989 | if (ret != 0) | ||
| 990 | return ret; | ||
| 991 | |||
| 992 | /* Send data block length? */ | ||
| 993 | buf[0] = 0x00; | ||
| 994 | buf[1] = 0x40; | ||
| 995 | ret = i2c_master_send(tx->c, buf, 2); | ||
| 996 | if (ret != 2) { | ||
| 997 | zilog_error("i2c_master_send failed with %d\n", ret); | ||
| 998 | return ret < 0 ? ret : -EFAULT; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | /* Give the z8 a moment to process data block */ | ||
| 1002 | for (i = 0; i < 10; i++) { | ||
| 1003 | ret = i2c_master_send(tx->c, buf, 1); | ||
| 1004 | if (ret == 1) | ||
| 1005 | break; | ||
| 1006 | udelay(100); | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | if (ret != 1) { | ||
| 1010 | zilog_error("i2c_master_send failed with %d\n", ret); | ||
| 1011 | return ret < 0 ? ret : -EFAULT; | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | /* Send finished download? */ | ||
| 1015 | ret = i2c_master_recv(tx->c, buf, 1); | ||
| 1016 | if (ret != 1) { | ||
| 1017 | zilog_error("i2c_master_recv failed with %d\n", ret); | ||
| 1018 | return ret < 0 ? ret : -EFAULT; | ||
| 1019 | } | ||
| 1020 | if (buf[0] != 0xA0) { | ||
| 1021 | zilog_error("unexpected IR TX response #1: %02x\n", | ||
| 1022 | buf[0]); | ||
| 1023 | return -EFAULT; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | /* Send prepare command? */ | ||
| 1027 | buf[0] = 0x00; | ||
| 1028 | buf[1] = 0x80; | ||
| 1029 | ret = i2c_master_send(tx->c, buf, 2); | ||
| 1030 | if (ret != 2) { | ||
| 1031 | zilog_error("i2c_master_send failed with %d\n", ret); | ||
| 1032 | return ret < 0 ? ret : -EFAULT; | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | /* | ||
| 1036 | * The sleep bits aren't necessary on the HD PVR, and in fact, the | ||
| 1037 | * last i2c_master_recv always fails with a -5, so for now, we're | ||
| 1038 | * going to skip this whole mess and say we're done on the HD PVR | ||
| 1039 | */ | ||
| 1040 | if (!tx->post_tx_ready_poll) { | ||
| 1041 | dprintk("sent code %u, key %u\n", code, key); | ||
| 1042 | return 0; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | /* | ||
| 1046 | * This bit NAKs until the device is ready, so we retry it | ||
| 1047 | * sleeping a bit each time. This seems to be what the windows | ||
| 1048 | * driver does, approximately. | ||
| 1049 | * Try for up to 1s. | ||
| 1050 | */ | ||
| 1051 | for (i = 0; i < 20; ++i) { | ||
| 1052 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 1053 | schedule_timeout((50 * HZ + 999) / 1000); | ||
| 1054 | ret = i2c_master_send(tx->c, buf, 1); | ||
| 1055 | if (ret == 1) | ||
| 1056 | break; | ||
| 1057 | dprintk("NAK expected: i2c_master_send " | ||
| 1058 | "failed with %d (try %d)\n", ret, i+1); | ||
| 1059 | } | ||
| 1060 | if (ret != 1) { | ||
| 1061 | zilog_error("IR TX chip never got ready: last i2c_master_send " | ||
| 1062 | "failed with %d\n", ret); | ||
| 1063 | return ret < 0 ? ret : -EFAULT; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | /* Seems to be an 'ok' response */ | ||
| 1067 | i = i2c_master_recv(tx->c, buf, 1); | ||
| 1068 | if (i != 1) { | ||
| 1069 | zilog_error("i2c_master_recv failed with %d\n", ret); | ||
| 1070 | return -EFAULT; | ||
| 1071 | } | ||
| 1072 | if (buf[0] != 0x80) { | ||
| 1073 | zilog_error("unexpected IR TX response #2: %02x\n", buf[0]); | ||
| 1074 | return -EFAULT; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | /* Oh good, it worked */ | ||
| 1078 | dprintk("sent code %u, key %u\n", code, key); | ||
| 1079 | return 0; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | /* | ||
| 1083 | * Write a code to the device. We take in a 32-bit number (an int) and then | ||
| 1084 | * decode this to a codeset/key index. The key data is then decompressed and | ||
| 1085 | * sent to the device. We have a spin lock as per i2c documentation to prevent | ||
| 1086 | * multiple concurrent sends which would probably cause the device to explode. | ||
| 1087 | */ | ||
| 1088 | static ssize_t write(struct file *filep, const char *buf, size_t n, | ||
| 1089 | loff_t *ppos) | ||
| 1090 | { | ||
| 1091 | struct IR *ir = filep->private_data; | ||
| 1092 | struct IR_tx *tx; | ||
| 1093 | size_t i; | ||
| 1094 | int failures = 0; | ||
| 1095 | |||
| 1096 | /* Validate user parameters */ | ||
| 1097 | if (n % sizeof(int)) | ||
| 1098 | return -EINVAL; | ||
| 1099 | |||
| 1100 | /* Get a struct IR_tx reference */ | ||
| 1101 | tx = get_ir_tx(ir); | ||
| 1102 | if (tx == NULL) | ||
| 1103 | return -ENXIO; | ||
| 1104 | |||
| 1105 | /* Ensure our tx->c i2c_client remains valid for the duration */ | ||
| 1106 | mutex_lock(&tx->client_lock); | ||
| 1107 | if (tx->c == NULL) { | ||
| 1108 | mutex_unlock(&tx->client_lock); | ||
| 1109 | put_ir_tx(tx, false); | ||
| 1110 | return -ENXIO; | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | /* Lock i2c bus for the duration */ | ||
| 1114 | mutex_lock(&ir->ir_lock); | ||
| 1115 | |||
| 1116 | /* Send each keypress */ | ||
| 1117 | for (i = 0; i < n;) { | ||
| 1118 | int ret = 0; | ||
| 1119 | int command; | ||
| 1120 | |||
| 1121 | if (copy_from_user(&command, buf + i, sizeof(command))) { | ||
| 1122 | mutex_unlock(&ir->ir_lock); | ||
| 1123 | mutex_unlock(&tx->client_lock); | ||
| 1124 | put_ir_tx(tx, false); | ||
| 1125 | return -EFAULT; | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | /* Send boot data first if required */ | ||
| 1129 | if (tx->need_boot == 1) { | ||
| 1130 | /* Make sure we have the 'firmware' loaded, first */ | ||
| 1131 | ret = fw_load(tx); | ||
| 1132 | if (ret != 0) { | ||
| 1133 | mutex_unlock(&ir->ir_lock); | ||
| 1134 | mutex_unlock(&tx->client_lock); | ||
| 1135 | put_ir_tx(tx, false); | ||
| 1136 | if (ret != -ENOMEM) | ||
| 1137 | ret = -EIO; | ||
| 1138 | return ret; | ||
| 1139 | } | ||
| 1140 | /* Prep the chip for transmitting codes */ | ||
| 1141 | ret = send_boot_data(tx); | ||
| 1142 | if (ret == 0) | ||
| 1143 | tx->need_boot = 0; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | /* Send the code */ | ||
| 1147 | if (ret == 0) { | ||
| 1148 | ret = send_code(tx, (unsigned)command >> 16, | ||
| 1149 | (unsigned)command & 0xFFFF); | ||
| 1150 | if (ret == -EPROTO) { | ||
| 1151 | mutex_unlock(&ir->ir_lock); | ||
| 1152 | mutex_unlock(&tx->client_lock); | ||
| 1153 | put_ir_tx(tx, false); | ||
| 1154 | return ret; | ||
| 1155 | } | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | /* | ||
| 1159 | * Hmm, a failure. If we've had a few then give up, otherwise | ||
| 1160 | * try a reset | ||
| 1161 | */ | ||
| 1162 | if (ret != 0) { | ||
| 1163 | /* Looks like the chip crashed, reset it */ | ||
| 1164 | zilog_error("sending to the IR transmitter chip " | ||
| 1165 | "failed, trying reset\n"); | ||
| 1166 | |||
| 1167 | if (failures >= 3) { | ||
| 1168 | zilog_error("unable to send to the IR chip " | ||
| 1169 | "after 3 resets, giving up\n"); | ||
| 1170 | mutex_unlock(&ir->ir_lock); | ||
| 1171 | mutex_unlock(&tx->client_lock); | ||
| 1172 | put_ir_tx(tx, false); | ||
| 1173 | return ret; | ||
| 1174 | } | ||
| 1175 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 1176 | schedule_timeout((100 * HZ + 999) / 1000); | ||
| 1177 | tx->need_boot = 1; | ||
| 1178 | ++failures; | ||
| 1179 | } else | ||
| 1180 | i += sizeof(int); | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | /* Release i2c bus */ | ||
| 1184 | mutex_unlock(&ir->ir_lock); | ||
| 1185 | |||
| 1186 | mutex_unlock(&tx->client_lock); | ||
| 1187 | |||
| 1188 | /* Give back our struct IR_tx reference */ | ||
| 1189 | put_ir_tx(tx, false); | ||
| 1190 | |||
| 1191 | /* All looks good */ | ||
| 1192 | return n; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | /* copied from lirc_dev */ | ||
| 1196 | static unsigned int poll(struct file *filep, poll_table *wait) | ||
| 1197 | { | ||
| 1198 | struct IR *ir = filep->private_data; | ||
| 1199 | struct IR_rx *rx; | ||
| 1200 | struct lirc_buffer *rbuf = ir->l.rbuf; | ||
| 1201 | unsigned int ret; | ||
| 1202 | |||
| 1203 | dprintk("poll called\n"); | ||
| 1204 | |||
| 1205 | rx = get_ir_rx(ir); | ||
| 1206 | if (rx == NULL) { | ||
| 1207 | /* | ||
| 1208 | * Revisit this, if our poll function ever reports writeable | ||
| 1209 | * status for Tx | ||
| 1210 | */ | ||
| 1211 | dprintk("poll result = POLLERR\n"); | ||
| 1212 | return POLLERR; | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | /* | ||
| 1216 | * Add our lirc_buffer's wait_queue to the poll_table. A wake up on | ||
| 1217 | * that buffer's wait queue indicates we may have a new poll status. | ||
| 1218 | */ | ||
| 1219 | poll_wait(filep, &rbuf->wait_poll, wait); | ||
| 1220 | |||
| 1221 | /* Indicate what ops could happen immediately without blocking */ | ||
| 1222 | ret = lirc_buffer_empty(rbuf) ? 0 : (POLLIN|POLLRDNORM); | ||
| 1223 | |||
| 1224 | dprintk("poll result = %s\n", ret ? "POLLIN|POLLRDNORM" : "none"); | ||
| 1225 | return ret; | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) | ||
| 1229 | { | ||
| 1230 | struct IR *ir = filep->private_data; | ||
| 1231 | int result; | ||
| 1232 | unsigned long mode, features; | ||
| 1233 | |||
| 1234 | features = ir->l.features; | ||
| 1235 | |||
| 1236 | switch (cmd) { | ||
| 1237 | case LIRC_GET_LENGTH: | ||
| 1238 | result = put_user((unsigned long)13, | ||
| 1239 | (unsigned long *)arg); | ||
| 1240 | break; | ||
| 1241 | case LIRC_GET_FEATURES: | ||
| 1242 | result = put_user(features, (unsigned long *) arg); | ||
| 1243 | break; | ||
| 1244 | case LIRC_GET_REC_MODE: | ||
| 1245 | if (!(features&LIRC_CAN_REC_MASK)) | ||
| 1246 | return -ENOSYS; | ||
| 1247 | |||
| 1248 | result = put_user(LIRC_REC2MODE | ||
| 1249 | (features&LIRC_CAN_REC_MASK), | ||
| 1250 | (unsigned long *)arg); | ||
| 1251 | break; | ||
| 1252 | case LIRC_SET_REC_MODE: | ||
| 1253 | if (!(features&LIRC_CAN_REC_MASK)) | ||
| 1254 | return -ENOSYS; | ||
| 1255 | |||
| 1256 | result = get_user(mode, (unsigned long *)arg); | ||
| 1257 | if (!result && !(LIRC_MODE2REC(mode) & features)) | ||
| 1258 | result = -EINVAL; | ||
| 1259 | break; | ||
| 1260 | case LIRC_GET_SEND_MODE: | ||
| 1261 | if (!(features&LIRC_CAN_SEND_MASK)) | ||
| 1262 | return -ENOSYS; | ||
| 1263 | |||
| 1264 | result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); | ||
| 1265 | break; | ||
| 1266 | case LIRC_SET_SEND_MODE: | ||
| 1267 | if (!(features&LIRC_CAN_SEND_MASK)) | ||
| 1268 | return -ENOSYS; | ||
| 1269 | |||
| 1270 | result = get_user(mode, (unsigned long *) arg); | ||
| 1271 | if (!result && mode != LIRC_MODE_PULSE) | ||
| 1272 | return -EINVAL; | ||
| 1273 | break; | ||
| 1274 | default: | ||
| 1275 | return -EINVAL; | ||
| 1276 | } | ||
| 1277 | return result; | ||
| 1278 | } | ||
| 1279 | |||
| 1280 | static struct IR *get_ir_device_by_minor(unsigned int minor) | ||
| 1281 | { | ||
| 1282 | struct IR *ir; | ||
| 1283 | struct IR *ret = NULL; | ||
| 1284 | |||
| 1285 | mutex_lock(&ir_devices_lock); | ||
| 1286 | |||
| 1287 | if (!list_empty(&ir_devices_list)) { | ||
| 1288 | list_for_each_entry(ir, &ir_devices_list, list) { | ||
| 1289 | if (ir->l.minor == minor) { | ||
| 1290 | ret = get_ir_device(ir, true); | ||
| 1291 | break; | ||
| 1292 | } | ||
| 1293 | } | ||
| 1294 | } | ||
| 1295 | |||
| 1296 | mutex_unlock(&ir_devices_lock); | ||
| 1297 | return ret; | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | /* | ||
| 1301 | * Open the IR device. Get hold of our IR structure and | ||
| 1302 | * stash it in private_data for the file | ||
| 1303 | */ | ||
| 1304 | static int open(struct inode *node, struct file *filep) | ||
| 1305 | { | ||
| 1306 | struct IR *ir; | ||
| 1307 | unsigned int minor = MINOR(node->i_rdev); | ||
| 1308 | |||
| 1309 | /* find our IR struct */ | ||
| 1310 | ir = get_ir_device_by_minor(minor); | ||
| 1311 | |||
| 1312 | if (ir == NULL) | ||
| 1313 | return -ENODEV; | ||
| 1314 | |||
| 1315 | atomic_inc(&ir->open_count); | ||
| 1316 | |||
| 1317 | /* stash our IR struct */ | ||
| 1318 | filep->private_data = ir; | ||
| 1319 | |||
| 1320 | nonseekable_open(node, filep); | ||
| 1321 | return 0; | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | /* Close the IR device */ | ||
| 1325 | static int close(struct inode *node, struct file *filep) | ||
| 1326 | { | ||
| 1327 | /* find our IR struct */ | ||
| 1328 | struct IR *ir = filep->private_data; | ||
| 1329 | if (ir == NULL) { | ||
| 1330 | zilog_error("close: no private_data attached to the file!\n"); | ||
| 1331 | return -ENODEV; | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | atomic_dec(&ir->open_count); | ||
| 1335 | |||
| 1336 | put_ir_device(ir, false); | ||
| 1337 | return 0; | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | static int ir_remove(struct i2c_client *client); | ||
| 1341 | static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id); | ||
| 1342 | |||
| 1343 | #define ID_FLAG_TX 0x01 | ||
| 1344 | #define ID_FLAG_HDPVR 0x02 | ||
| 1345 | |||
| 1346 | static const struct i2c_device_id ir_transceiver_id[] = { | ||
| 1347 | { "ir_tx_z8f0811_haup", ID_FLAG_TX }, | ||
| 1348 | { "ir_rx_z8f0811_haup", 0 }, | ||
| 1349 | { "ir_tx_z8f0811_hdpvr", ID_FLAG_HDPVR | ID_FLAG_TX }, | ||
| 1350 | { "ir_rx_z8f0811_hdpvr", ID_FLAG_HDPVR }, | ||
| 1351 | { } | ||
| 1352 | }; | ||
| 1353 | |||
| 1354 | static struct i2c_driver driver = { | ||
| 1355 | .driver = { | ||
| 1356 | .owner = THIS_MODULE, | ||
| 1357 | .name = "Zilog/Hauppauge i2c IR", | ||
| 1358 | }, | ||
| 1359 | .probe = ir_probe, | ||
| 1360 | .remove = ir_remove, | ||
| 1361 | .id_table = ir_transceiver_id, | ||
| 1362 | }; | ||
| 1363 | |||
| 1364 | static const struct file_operations lirc_fops = { | ||
| 1365 | .owner = THIS_MODULE, | ||
| 1366 | .llseek = no_llseek, | ||
| 1367 | .read = read, | ||
| 1368 | .write = write, | ||
| 1369 | .poll = poll, | ||
| 1370 | .unlocked_ioctl = ioctl, | ||
| 1371 | #ifdef CONFIG_COMPAT | ||
| 1372 | .compat_ioctl = ioctl, | ||
| 1373 | #endif | ||
| 1374 | .open = open, | ||
| 1375 | .release = close | ||
| 1376 | }; | ||
| 1377 | |||
| 1378 | static struct lirc_driver lirc_template = { | ||
| 1379 | .name = "lirc_zilog", | ||
| 1380 | .minor = -1, | ||
| 1381 | .code_length = 13, | ||
| 1382 | .buffer_size = BUFLEN / 2, | ||
| 1383 | .sample_rate = 0, /* tell lirc_dev to not start its own kthread */ | ||
| 1384 | .chunk_size = 2, | ||
| 1385 | .set_use_inc = set_use_inc, | ||
| 1386 | .set_use_dec = set_use_dec, | ||
| 1387 | .fops = &lirc_fops, | ||
| 1388 | .owner = THIS_MODULE, | ||
| 1389 | }; | ||
| 1390 | |||
| 1391 | static int ir_remove(struct i2c_client *client) | ||
| 1392 | { | ||
| 1393 | if (strncmp("ir_tx_z8", client->name, 8) == 0) { | ||
| 1394 | struct IR_tx *tx = i2c_get_clientdata(client); | ||
| 1395 | if (tx != NULL) { | ||
| 1396 | mutex_lock(&tx->client_lock); | ||
| 1397 | tx->c = NULL; | ||
| 1398 | mutex_unlock(&tx->client_lock); | ||
| 1399 | put_ir_tx(tx, false); | ||
| 1400 | } | ||
| 1401 | } else if (strncmp("ir_rx_z8", client->name, 8) == 0) { | ||
| 1402 | struct IR_rx *rx = i2c_get_clientdata(client); | ||
| 1403 | if (rx != NULL) { | ||
| 1404 | mutex_lock(&rx->client_lock); | ||
| 1405 | rx->c = NULL; | ||
| 1406 | mutex_unlock(&rx->client_lock); | ||
| 1407 | put_ir_rx(rx, false); | ||
| 1408 | } | ||
| 1409 | } | ||
| 1410 | return 0; | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | |||
| 1414 | /* ir_devices_lock must be held */ | ||
| 1415 | static struct IR *get_ir_device_by_adapter(struct i2c_adapter *adapter) | ||
| 1416 | { | ||
| 1417 | struct IR *ir; | ||
| 1418 | |||
| 1419 | if (list_empty(&ir_devices_list)) | ||
| 1420 | return NULL; | ||
| 1421 | |||
| 1422 | list_for_each_entry(ir, &ir_devices_list, list) | ||
| 1423 | if (ir->adapter == adapter) { | ||
| 1424 | get_ir_device(ir, true); | ||
| 1425 | return ir; | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | return NULL; | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
| 1432 | { | ||
| 1433 | struct IR *ir; | ||
| 1434 | struct IR_tx *tx; | ||
| 1435 | struct IR_rx *rx; | ||
| 1436 | struct i2c_adapter *adap = client->adapter; | ||
| 1437 | int ret; | ||
| 1438 | bool tx_probe = false; | ||
| 1439 | |||
| 1440 | dprintk("%s: %s on i2c-%d (%s), client addr=0x%02x\n", | ||
| 1441 | __func__, id->name, adap->nr, adap->name, client->addr); | ||
| 1442 | |||
| 1443 | /* | ||
| 1444 | * The IR receiver is at i2c address 0x71. | ||
| 1445 | * The IR transmitter is at i2c address 0x70. | ||
| 1446 | */ | ||
| 1447 | |||
| 1448 | if (id->driver_data & ID_FLAG_TX) | ||
| 1449 | tx_probe = true; | ||
| 1450 | else if (tx_only) /* module option */ | ||
| 1451 | return -ENXIO; | ||
| 1452 | |||
| 1453 | zilog_info("probing IR %s on %s (i2c-%d)\n", | ||
| 1454 | tx_probe ? "Tx" : "Rx", adap->name, adap->nr); | ||
| 1455 | |||
| 1456 | mutex_lock(&ir_devices_lock); | ||
| 1457 | |||
| 1458 | /* Use a single struct IR instance for both the Rx and Tx functions */ | ||
| 1459 | ir = get_ir_device_by_adapter(adap); | ||
| 1460 | if (ir == NULL) { | ||
| 1461 | ir = kzalloc(sizeof(struct IR), GFP_KERNEL); | ||
| 1462 | if (ir == NULL) { | ||
| 1463 | ret = -ENOMEM; | ||
| 1464 | goto out_no_ir; | ||
| 1465 | } | ||
| 1466 | kref_init(&ir->ref); | ||
| 1467 | |||
| 1468 | /* store for use in ir_probe() again, and open() later on */ | ||
| 1469 | INIT_LIST_HEAD(&ir->list); | ||
| 1470 | list_add_tail(&ir->list, &ir_devices_list); | ||
| 1471 | |||
| 1472 | ir->adapter = adap; | ||
| 1473 | mutex_init(&ir->ir_lock); | ||
| 1474 | atomic_set(&ir->open_count, 0); | ||
| 1475 | spin_lock_init(&ir->tx_ref_lock); | ||
| 1476 | spin_lock_init(&ir->rx_ref_lock); | ||
| 1477 | |||
| 1478 | /* set lirc_dev stuff */ | ||
| 1479 | memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); | ||
| 1480 | /* | ||
| 1481 | * FIXME this is a pointer reference to us, but no refcount. | ||
| 1482 | * | ||
| 1483 | * This OK for now, since lirc_dev currently won't touch this | ||
| 1484 | * buffer as we provide our own lirc_fops. | ||
| 1485 | * | ||
| 1486 | * Currently our own lirc_fops rely on this ir->l.rbuf pointer | ||
| 1487 | */ | ||
| 1488 | ir->l.rbuf = &ir->rbuf; | ||
| 1489 | ir->l.dev = &adap->dev; | ||
| 1490 | ret = lirc_buffer_init(ir->l.rbuf, | ||
| 1491 | ir->l.chunk_size, ir->l.buffer_size); | ||
| 1492 | if (ret) | ||
| 1493 | goto out_put_ir; | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | if (tx_probe) { | ||
| 1497 | /* Get the IR_rx instance for later, if already allocated */ | ||
| 1498 | rx = get_ir_rx(ir); | ||
| 1499 | |||
| 1500 | /* Set up a struct IR_tx instance */ | ||
| 1501 | tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL); | ||
| 1502 | if (tx == NULL) { | ||
| 1503 | ret = -ENOMEM; | ||
| 1504 | goto out_put_xx; | ||
| 1505 | } | ||
| 1506 | kref_init(&tx->ref); | ||
| 1507 | ir->tx = tx; | ||
| 1508 | |||
| 1509 | ir->l.features |= LIRC_CAN_SEND_PULSE; | ||
| 1510 | mutex_init(&tx->client_lock); | ||
| 1511 | tx->c = client; | ||
| 1512 | tx->need_boot = 1; | ||
| 1513 | tx->post_tx_ready_poll = | ||
| 1514 | (id->driver_data & ID_FLAG_HDPVR) ? false : true; | ||
| 1515 | |||
| 1516 | /* An ir ref goes to the struct IR_tx instance */ | ||
| 1517 | tx->ir = get_ir_device(ir, true); | ||
| 1518 | |||
| 1519 | /* A tx ref goes to the i2c_client */ | ||
| 1520 | i2c_set_clientdata(client, get_ir_tx(ir)); | ||
| 1521 | |||
| 1522 | /* | ||
| 1523 | * Load the 'firmware'. We do this before registering with | ||
| 1524 | * lirc_dev, so the first firmware load attempt does not happen | ||
| 1525 | * after a open() or write() call on the device. | ||
| 1526 | * | ||
| 1527 | * Failure here is not deemed catastrophic, so the receiver will | ||
| 1528 | * still be usable. Firmware load will be retried in write(), | ||
| 1529 | * if it is needed. | ||
| 1530 | */ | ||
| 1531 | fw_load(tx); | ||
| 1532 | |||
| 1533 | /* Proceed only if the Rx client is also ready or not needed */ | ||
| 1534 | if (rx == NULL && !tx_only) { | ||
| 1535 | zilog_info("probe of IR Tx on %s (i2c-%d) done. Waiting" | ||
| 1536 | " on IR Rx.\n", adap->name, adap->nr); | ||
| 1537 | goto out_ok; | ||
| 1538 | } | ||
| 1539 | } else { | ||
| 1540 | /* Get the IR_tx instance for later, if already allocated */ | ||
| 1541 | tx = get_ir_tx(ir); | ||
| 1542 | |||
| 1543 | /* Set up a struct IR_rx instance */ | ||
| 1544 | rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL); | ||
| 1545 | if (rx == NULL) { | ||
| 1546 | ret = -ENOMEM; | ||
| 1547 | goto out_put_xx; | ||
| 1548 | } | ||
| 1549 | kref_init(&rx->ref); | ||
| 1550 | ir->rx = rx; | ||
| 1551 | |||
| 1552 | ir->l.features |= LIRC_CAN_REC_LIRCCODE; | ||
| 1553 | mutex_init(&rx->client_lock); | ||
| 1554 | rx->c = client; | ||
| 1555 | rx->hdpvr_data_fmt = | ||
| 1556 | (id->driver_data & ID_FLAG_HDPVR) ? true : false; | ||
| 1557 | |||
| 1558 | /* An ir ref goes to the struct IR_rx instance */ | ||
| 1559 | rx->ir = get_ir_device(ir, true); | ||
| 1560 | |||
| 1561 | /* An rx ref goes to the i2c_client */ | ||
| 1562 | i2c_set_clientdata(client, get_ir_rx(ir)); | ||
| 1563 | |||
| 1564 | /* | ||
| 1565 | * Start the polling thread. | ||
| 1566 | * It will only perform an empty loop around schedule_timeout() | ||
| 1567 | * until we register with lirc_dev and the first user open() | ||
| 1568 | */ | ||
| 1569 | /* An ir ref goes to the new rx polling kthread */ | ||
| 1570 | rx->task = kthread_run(lirc_thread, get_ir_device(ir, true), | ||
| 1571 | "zilog-rx-i2c-%d", adap->nr); | ||
| 1572 | if (IS_ERR(rx->task)) { | ||
| 1573 | ret = PTR_ERR(rx->task); | ||
| 1574 | zilog_error("%s: could not start IR Rx polling thread" | ||
| 1575 | "\n", __func__); | ||
| 1576 | /* Failed kthread, so put back the ir ref */ | ||
| 1577 | put_ir_device(ir, true); | ||
| 1578 | /* Failure exit, so put back rx ref from i2c_client */ | ||
| 1579 | i2c_set_clientdata(client, NULL); | ||
| 1580 | put_ir_rx(rx, true); | ||
| 1581 | ir->l.features &= ~LIRC_CAN_REC_LIRCCODE; | ||
| 1582 | goto out_put_xx; | ||
| 1583 | } | ||
| 1584 | |||
| 1585 | /* Proceed only if the Tx client is also ready */ | ||
| 1586 | if (tx == NULL) { | ||
| 1587 | zilog_info("probe of IR Rx on %s (i2c-%d) done. Waiting" | ||
| 1588 | " on IR Tx.\n", adap->name, adap->nr); | ||
| 1589 | goto out_ok; | ||
| 1590 | } | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | /* register with lirc */ | ||
| 1594 | ir->l.minor = minor; /* module option: user requested minor number */ | ||
| 1595 | ir->l.minor = lirc_register_driver(&ir->l); | ||
| 1596 | if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) { | ||
| 1597 | zilog_error("%s: \"minor\" must be between 0 and %d (%d)!\n", | ||
| 1598 | __func__, MAX_IRCTL_DEVICES-1, ir->l.minor); | ||
| 1599 | ret = -EBADRQC; | ||
| 1600 | goto out_put_xx; | ||
| 1601 | } | ||
| 1602 | zilog_info("IR unit on %s (i2c-%d) registered as lirc%d and ready\n", | ||
| 1603 | adap->name, adap->nr, ir->l.minor); | ||
| 1604 | |||
| 1605 | out_ok: | ||
| 1606 | if (rx != NULL) | ||
| 1607 | put_ir_rx(rx, true); | ||
| 1608 | if (tx != NULL) | ||
| 1609 | put_ir_tx(tx, true); | ||
| 1610 | put_ir_device(ir, true); | ||
| 1611 | zilog_info("probe of IR %s on %s (i2c-%d) done\n", | ||
| 1612 | tx_probe ? "Tx" : "Rx", adap->name, adap->nr); | ||
| 1613 | mutex_unlock(&ir_devices_lock); | ||
| 1614 | return 0; | ||
| 1615 | |||
| 1616 | out_put_xx: | ||
| 1617 | if (rx != NULL) | ||
| 1618 | put_ir_rx(rx, true); | ||
| 1619 | if (tx != NULL) | ||
| 1620 | put_ir_tx(tx, true); | ||
| 1621 | out_put_ir: | ||
| 1622 | put_ir_device(ir, true); | ||
| 1623 | out_no_ir: | ||
| 1624 | zilog_error("%s: probing IR %s on %s (i2c-%d) failed with %d\n", | ||
| 1625 | __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr, | ||
| 1626 | ret); | ||
| 1627 | mutex_unlock(&ir_devices_lock); | ||
| 1628 | return ret; | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | static int __init zilog_init(void) | ||
| 1632 | { | ||
| 1633 | int ret; | ||
| 1634 | |||
| 1635 | zilog_notify("Zilog/Hauppauge IR driver initializing\n"); | ||
| 1636 | |||
| 1637 | mutex_init(&tx_data_lock); | ||
| 1638 | |||
| 1639 | request_module("firmware_class"); | ||
| 1640 | |||
| 1641 | ret = i2c_add_driver(&driver); | ||
| 1642 | if (ret) | ||
| 1643 | zilog_error("initialization failed\n"); | ||
| 1644 | else | ||
| 1645 | zilog_notify("initialization complete\n"); | ||
| 1646 | |||
| 1647 | return ret; | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | static void __exit zilog_exit(void) | ||
| 1651 | { | ||
| 1652 | i2c_del_driver(&driver); | ||
| 1653 | /* if loaded */ | ||
| 1654 | fw_unload(); | ||
| 1655 | zilog_notify("Zilog/Hauppauge IR driver unloaded\n"); | ||
| 1656 | } | ||
| 1657 | |||
| 1658 | module_init(zilog_init); | ||
| 1659 | module_exit(zilog_exit); | ||
| 1660 | |||
| 1661 | MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)"); | ||
| 1662 | MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, " | ||
| 1663 | "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver, " | ||
| 1664 | "Andy Walls"); | ||
| 1665 | MODULE_LICENSE("GPL"); | ||
| 1666 | /* for compat with old name, which isn't all that accurate anymore */ | ||
| 1667 | MODULE_ALIAS("lirc_pvr150"); | ||
| 1668 | |||
| 1669 | module_param(minor, int, 0444); | ||
| 1670 | MODULE_PARM_DESC(minor, "Preferred minor device number"); | ||
| 1671 | |||
| 1672 | module_param(debug, bool, 0644); | ||
| 1673 | MODULE_PARM_DESC(debug, "Enable debugging messages"); | ||
| 1674 | |||
| 1675 | module_param(tx_only, bool, 0644); | ||
| 1676 | MODULE_PARM_DESC(tx_only, "Only handle the IR transmit function"); | ||
