diff options
26 files changed, 261 insertions, 14137 deletions
diff --git a/.gitignore b/.gitignore index 79727843a..85d44c736 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ patch-*.bz2 clog *.rpm kernel-2.6.*/ -patch-2.6.35-git1.bz2 +patch-2.6.36-rc1.bz2 diff --git a/config-arm b/config-arm index d0ba0f376..8d7e46a49 100644 --- a/config-arm +++ b/config-arm @@ -120,3 +120,5 @@ CONFIG_AUTO_ZRELADDR=y # CONFIG_ARM_CHARLCD is not set # CONFIG_DEPRECATED_PARAM_STRUCT is not set + +# CONFIG_ARM_SP805_WATCHDOG is not set diff --git a/config-generic b/config-generic index 13dfa01e9..c6f5c4504 100644 --- a/config-generic +++ b/config-generic @@ -496,6 +496,7 @@ CONFIG_SCSI_SAS_HOST_SMP=y CONFIG_RAID_ATTRS=m CONFIG_ISCSI_TCP=m +CONFIG_ISCSI_BOOT_SYSFS=m # # SCSI low-level drivers @@ -719,6 +720,7 @@ CONFIG_FIREWIRE_OHCI=m CONFIG_FIREWIRE_SBP2=m CONFIG_FIREWIRE_NET=m CONFIG_FIREWIRE_OHCI_DEBUG=y +CONFIG_FIREWIRE_NOSY=m # CONFIG_FIREWIRE_OHCI_REMOTE_DMA is not set # @@ -845,6 +847,7 @@ CONFIG_DECNET_ROUTER=y # CONFIG_DECNET_NF_GRABULATOR is not set CONFIG_BRIDGE=m CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set CONFIG_NETFILTER=y CONFIG_NETFILTER_ADVANCED=y CONFIG_NF_CONNTRACK=y @@ -903,6 +906,10 @@ CONFIG_NETFILTER_XT_MATCH_U32=m CONFIG_NETFILTER_XT_MATCH_CLUSTER=m CONFIG_NETFILTER_XT_MATCH_HL=m CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m # CONFIG_NETFILTER_DEBUG is not set CONFIG_BRIDGE_NETFILTER=y @@ -1318,6 +1325,7 @@ CONFIG_CHELSIO_T1=m CONFIG_CHELSIO_T1_1G=y CONFIG_CHELSIO_T3=m CONFIG_CHELSIO_T4=m +CONFIG_CHELSIO_T4VF=m CONFIG_IP1000=m CONFIG_IXGB=m CONFIG_IXGBEVF=m @@ -1513,6 +1521,8 @@ CONFIG_WL1251=m CONFIG_WL1251_SPI=m CONFIG_WL1251_SDIO=m CONFIG_WL1271=m +CONFIG_WL1271_SDIO=m +CONFIG_WL1271_SPI=m # # Token Ring devices @@ -1565,6 +1575,7 @@ CONFIG_CAN_SJA1000_ISA=m CONFIG_CAN_SJA1000_PLATFORM=m CONFIG_CAN_EMS_PCI=m CONFIG_CAN_EMS_USB=m +CONFIG_CAN_ESD_USB2=m CONFIG_CAN_KVASER_PCI=m CONFIG_CAN_PLX_PCI=m CONFIG_NETROM=m @@ -1644,6 +1655,7 @@ CONFIG_BT_HCIBTUSB=m CONFIG_BT_HCIUART=m CONFIG_BT_HCIUART_H4=y CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_ATH3K=y CONFIG_BT_HCIDTL1=m CONFIG_BT_HCIBT3C=m CONFIG_BT_HCIBLUECARD=m @@ -1812,6 +1824,7 @@ CONFIG_INPUT_YEALINK=m CONFIG_INPUT_CM109=m CONFIG_INPUT_POLLDEV=m CONFIG_INPUT_SPARSEKMAP=m +# CONFIG_INPUT_ADXL34X is not set # # Input I/O drivers @@ -1846,6 +1859,7 @@ CONFIG_KEYBOARD_ATKBD=y # FIXME: Do we really need these keyboards enabled ? CONFIG_KEYBOARD_ADP5588=m CONFIG_KEYBOARD_MAX7359=m +# CONFIG_KEYBOARD_MCS is not set CONFIG_KEYBOARD_OPENCORES=m CONFIG_KEYBOARD_QT2160=m # CONFIG_KEYBOARD_TCA6416 is not set @@ -1909,6 +1923,8 @@ CONFIG_TOUCHSCREEN_USB_E2I=y CONFIG_TOUCHSCREEN_USB_COMPOSITE=m CONFIG_TOUCHSCREEN_DYNAPRO=m # CONFIG_TOUCHSCREEN_WM97XX is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_QT602240 is not set CONFIG_TOUCHSCREEN_EETI=m CONFIG_TOUCHSCREEN_W90X900=m CONFIG_TOUCHSCREEN_MCS5000=m @@ -1985,6 +2001,7 @@ CONFIG_CYCLADES=m # CONFIG_STALLION is not set # CONFIG_ISTALLION is not set CONFIG_SERIAL_JSM=m +# CONFIG_SERIAL_MFD_HSU is not set # CONFIG_SERIAL_ALTERA_JTAGUART is not set # CONFIG_SERIAL_ALTERA_UART is not set @@ -2008,6 +2025,8 @@ CONFIG_PPDEV=m CONFIG_I2C=m CONFIG_I2C_COMPAT=y CONFIG_I2C_CHARDEV=m +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_MUX_PCA954x is not set # # I2C Algorithms @@ -2153,6 +2172,13 @@ CONFIG_SENSORS_ADT7411=m CONFIG_SENSORS_ASC7621=m CONFIG_SENSORS_EMC1403=m CONFIG_SENSORS_TMP102=m +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_EMC2103 is not set + +# CONFIG_HMC6352 is not set +# CONFIG_BMP085 is not set CONFIG_W1=m CONFIG_W1_CON=y @@ -2308,6 +2334,7 @@ CONFIG_DRM_NOUVEAU=m CONFIG_DRM_NOUVEAU_BACKLIGHT=y CONFIG_DRM_NOUVEAU_DEBUG=y CONFIG_DRM_I2C_CH7006=m +CONFIG_DRM_I2C_SIL164=m CONFIG_DRM_VMWGFX=m # @@ -2974,6 +3001,8 @@ CONFIG_HID_TOPSEED=m CONFIG_HID_THRUSTMASTER=m CONFIG_HID_ZEROPLUS=m CONFIG_HID_ZYDACRON=m +CONFIG_HID_ACRUX_FF=m +CONFIG_HID_ELECOM=m # @@ -3038,6 +3067,7 @@ CONFIG_USB_KONICAWC=m CONFIG_USB_S2255=m CONFIG_USB_SE401=m # CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set # CONFIG_USB_STV680 is not set # CONFIG_USB_SN9C102 is not set CONFIG_USB_ZR364XX=m @@ -3165,6 +3195,7 @@ CONFIG_USB_SERIAL_XIRCOM=m CONFIG_USB_SERIAL_QCAUX=m CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_SERIAL_SSU100=m CONFIG_USB_EZUSB=y CONFIG_USB_EMI62=m @@ -3248,6 +3279,8 @@ CONFIG_INPUT_PCF50633_PMU=m CONFIG_INPUT_GPIO_ROTARY_ENCODER=m CONFIG_CHARGER_PCF50633=m CONFIG_RTC_DRV_PCF50633=m +CONFIG_RTC_DRV_DS3232=m +CONFIG_RTC_DRV_ISL12022=m CONFIG_MFD_SUPPORT=y CONFIG_MFD_SM501=m @@ -3391,7 +3424,8 @@ CONFIG_JFFS2_FS_POSIX_ACL=y CONFIG_JFFS2_FS_SECURITY=y CONFIG_CRAMFS=m CONFIG_SQUASHFS=m -CONFIG_SQUASHFS_XATTRS=y +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZO=y # CONFIG_SQUASHFS_EMBEDDED is not set CONFIG_VXFS_FS=m # CONFIG_HPFS_FS is not set @@ -3420,6 +3454,7 @@ CONFIG_NFSD_V3=y CONFIG_NFSD_V3_ACL=y CONFIG_NFSD_V4=y CONFIG_NFS_FSCACHE=y +# CONFIG_NFS_USE_LEGACY_DNS is not set CONFIG_LOCKD=m CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=m @@ -3591,6 +3626,7 @@ CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 CONFIG_SECURITY_SELINUX_AVC_STATS=y # CONFIG_SECURITY_SMACK is not set # CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set CONFIG_AUDIT=y CONFIG_AUDITSYSCALL=y @@ -3599,6 +3635,7 @@ CONFIG_AUDITSYSCALL=y # CONFIG_CRYPTO=y CONFIG_CRYPTO_FIPS=y +CONFIG_CRYPTO_MANAGER_TESTS=y CONFIG_CRYPTO_HW=y CONFIG_CRYPTO_BLKCIPHER=y CONFIG_CRYPTO_MANAGER=m @@ -4167,6 +4204,11 @@ CONFIG_USB_ATMEL=m # CONFIG_RAMZSWAP is not set # CONFIG_BATMAN_ADV is not set # CONFIG_FB_SM7XX is not set +# CONFIG_SPECTRA is not set +# CONFIG_ZRAM is not set +# CONFIG_EASYCAP is not set +# CONFIG_SOLO6X10 is not set +# CONFIG_ACPI_QUICKSTART is not set # # Android @@ -4214,6 +4256,8 @@ CONFIG_KSM=y CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 CONFIG_FSNOTIFY=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y CONFIG_IEEE802154=m CONFIG_IEEE802154_DRIVERS=m @@ -4253,6 +4297,8 @@ CONFIG_DEBUG_RODATA_TEST=y CONFIG_DEBUG_NX_TEST=m CONFIG_DEBUG_BOOT_PARAMS=y CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_DEBUG_INFO_REDUCED is not set # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set CONFIG_DETECT_HUNG_TASK=y # CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set @@ -4291,3 +4337,13 @@ CONFIG_PROFILE_KSYM_TRACER=y CONFIG_KPROBE_EVENT=y # CONFIG_RAMOOPS is not set + +CONFIG_IR_CORE=m +CONFIG_IR_ENE=m +CONFIG_IR_STREAMZAP=m + +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_TPS6586X is not set diff --git a/config-i686-PAE b/config-i686-PAE index 1e58e65b2..429853e32 100644 --- a/config-i686-PAE +++ b/config-i686-PAE @@ -1,5 +1,6 @@ # CONFIG_HIGHMEM4G is not set CONFIG_HIGHMEM64G=y +# CONFIG_OLPC_OPENFIRMWARE is not set CONFIG_XEN_DEV_EVTCHN=m CONFIG_XEN_SYS_HYPERVISOR=y diff --git a/config-ia64-generic b/config-ia64-generic index f1581b40c..a178b8a17 100644 --- a/config-ia64-generic +++ b/config-ia64-generic @@ -138,6 +138,7 @@ CONFIG_ACPI_THERMAL=y CONFIG_ACPI_VIDEO=m # CONFIG_ACPI_PROC_EVENT is not set CONFIG_ACPI_HED=m +CONFIG_ACPI_EC_DEBUGFS=m CONFIG_PM=y CONFIG_HOTPLUG_PCI=y diff --git a/config-powerpc-generic b/config-powerpc-generic index 430396dfc..0effe3d0d 100644 --- a/config-powerpc-generic +++ b/config-powerpc-generic @@ -332,3 +332,5 @@ CONFIG_SERIAL_GRLIB_GAISLER_APBUART=m # CONFIG_MFD_TC35892 is not set # CONFIG_GPIO_SCH is not set + +# CONFIG_PPC_MPC512x is not set diff --git a/config-powerpc32-generic b/config-powerpc32-generic index 07b450ad3..d2304955f 100644 --- a/config-powerpc32-generic +++ b/config-powerpc32-generic @@ -149,6 +149,7 @@ CONFIG_FSL_EMB_PERFMON=y CONFIG_MPC8272_ADS=y CONFIG_PQ2FADS=y CONFIG_EP8248E=y +CONFIG_MPC830x_RDB=y CONFIG_MPC831x_RDB=y CONFIG_MPC832x_MDS=y CONFIG_MPC832x_RDB=y diff --git a/config-s390x b/config-s390x index 0d3a14b06..d9294023d 100644 --- a/config-s390x +++ b/config-s390x @@ -226,3 +226,5 @@ CONFIG_SMSGIUCV_EVENT=m # CONFIG_PREEMPT_TRACER is not set CONFIG_VMCP=y + +CONFIG_ZFCP_DIF=y diff --git a/config-x86-generic b/config-x86-generic index 58a8cf11b..5f14f346a 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -393,6 +393,7 @@ CONFIG_SENSORS_I5K_AMB=m CONFIG_HP_WATCHDOG=m CONFIG_OLPC=y +CONFIG_OLPC_OPENFIRMWARE=y CONFIG_BATTERY_OLPC=y CONFIG_MOUSE_PS2_OLPC=y @@ -479,6 +480,20 @@ CONFIG_TOSHIBA_BT_RFKILL=m CONFIG_VGA_SWITCHEROO=y CONFIG_LPC_SCH=m -CONFIG_INTEL_IDLE=m - CONFIG_PCI_CNB20LE_QUIRK=y + +CONFIG_ACPI_EC_DEBUGFS=m +# CONFIG_ACPI_APEI_ERST_DEBUG is not set +CONFIG_INTEL_IDLE=y +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +CONFIG_SENSORS_PKGTEMP=m +CONFIG_F71808E_WDT=m +CONFIG_HPWDT_NMI_DECODING=y +# CONFIG_MFD_TPS6586X is not set +# CONFIG_INTEL_MID_DMAC is not set +CONFIG_PCH_DMA=m +CONFIG_XEN_PLATFORM_PCI=m +# CONFIG_ACPI_QUICKSTART is not set +CONFIG_IDEAPAD_ACPI=m +CONFIG_INTEL_IPS=m + diff --git a/config-x86_64-generic b/config-x86_64-generic index 204dfff62..27e242128 100644 --- a/config-x86_64-generic +++ b/config-x86_64-generic @@ -403,7 +403,21 @@ CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL=m CONFIG_VGA_SWITCHEROO=y CONFIG_LPC_SCH=m -CONFIG_INTEL_IDLE=m CONFIG_I7300_IDLE=m CONFIG_PCI_CNB20LE_QUIRK=y + +CONFIG_ACPI_EC_DEBUGFS=m +# CONFIG_ACPI_APEI_ERST_DEBUG is not set +CONFIG_INTEL_IDLE=y +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +CONFIG_SENSORS_PKGTEMP=m +CONFIG_F71808E_WDT=m +CONFIG_HPWDT_NMI_DECODING=y +# CONFIG_MFD_TPS6586X is not set +# CONFIG_INTEL_MID_DMAC is not set +CONFIG_PCH_DMA=m +CONFIG_XEN_PLATFORM_PCI=m +# CONFIG_ACPI_QUICKSTART is not set +CONFIG_IDEAPAD_ACPI=m +CONFIG_INTEL_IPS=m diff --git a/git-utrace.patch b/git-utrace.patch index 77b5fa749..1be088c50 100644 --- a/git-utrace.patch +++ b/git-utrace.patch @@ -1,348 +1,5 @@ -From c2f1645ae87d5b7fc5e5973c3a93a4ae1684a76b Mon Sep 17 00:00:00 2001 -From: Kyle McMartin <kyle@dreadnought.i.jkkm.org> -Date: Tue, 22 Jun 2010 11:31:13 +0100 -Subject: Merge remote branch 'utrace/utrace-ptrace' into rawhide - -% git log --oneline --no-merges 7e27d6e..a91f6b7 -f979955 utrace-ptrace: fix compiling ptrace_regset under CONFIG_UTRACE -b5f196b utrace-ptrace: copy PTRACE_GETREGSET code to utrace-ptrace -d83135e utrace: fix utrace_maybe_reap() vs find_matching_engine() race -9a2c607 utrace: move CONFIG_UTRACE after AUDITSYSCALL in init/Kconfig -62f4621 utrace: s/rmb/mb/ in tracehook_notify_resume() -65f5e9d utrace: fix utrace_maybe_reap logic -ed1f9c2 utrace: fix syntax nit for !CONFIG_UTRACE -71e3f39 ptrace: add utrace comment -e7afc73 utrace: use WARN with text -a8ced33 utrace: cosmetic restructure -4330b80 utrace: remove some inline keywords -d4be40a utrace: remove report_clone special priority for utrace_attach_task on child -8c56566 ptrace: updates for utrace API changes -1900135 utrace: streamline callback API -97662d3 utrace: more cosmetic trivia -fd414cd utrace: more cosmetic cleanup -f30f068 utrace: cosmetic trivia -cfebda7 utrace: fix the comments about rmb() in task_utrace_struct() -875858a utrace: improve the comment in tracehook_notify_resume() -76b49a5 utrace: fix the ->cloning check in utrace_attach_delay() -e0755bb utrace: kill mb() in tracehook_report_death() -9fdc988 fix __must_check warnings -3e02499 kill suppress_sigtrap() -f872e69 utrace: don't set ->ops = utrace_detached_ops lockless -938482e utrace: fix doc typo -7fae049 utrace: avoid BUG_ON when engine leaves bogus si_signo -71b7a85 utrace: trivial, move CONFIG_UTRACE into "General setup" -9c8dbe0 utrace: reset report action for UTRACE_SYSCALL_RESUMED iteration -4c7514e join PTRACE_EVENT_SYSCALL_XXX states -a8f782e export __ptrace_detach() and do_notify_parent_cldstop() -c3473e1 ptrace_signal: check PT_PTRACED before reporting a signal -b396f5e tracehooks: check PT_PTRACED before reporting the single-step -45667dd tracehooks: kill some PT_PTRACED checks -e8a2f23 ptrace: cleanup ptrace_init_task()->ptrace_link() path -611dab8 kill CONFIG_UTRACE_PTRACE -8d3833e rm kernel/ptrace-common.h -494deb7 export __ptrace_detach(), add "ifndef CONFIG_UTRACE" into ptrace.c -05cb325 (upstream) reorder the code in kernel/ptrace.c -eb10f13 restore the old kernel/ptrace.c -ddcc525 utrace_resume: Avoid finish_resume_report() for UTRACE_RESUME -47852f9 mv kernel/ptrace.c kernel/ptrace-utrace.c -de5a46e utrace: fix UTRACE_SYSCALL_RESUMED nits -3bd4be9 stepping, accommodate to utrace-cleanup changes -679be9e Revert "utrace: synthesize SIGTRAP for single-stepping at syscall-exit" -23ab966 utrace: barrier nits -d3800b8 utrace: tracehook_init_task -64daf14 utrace: task_utrace_struct() barrier -f19442c utrace: synthesize SIGTRAP for single-stepping at syscall-exit -2583b32 utrace: nit for utrace-ptrace -a88b467 ptrace: x86: change syscall_trace_leave() to rely on tracehook when stepping -e01acf4 ptrace: x86: implement user_single_step_siginfo() -462a57b ptrace: change tracehook_report_syscall_exit() to handle stepping -172590d ptrace: powerpc: implement user_single_step_siginfo() -d63b43d ptrace: introduce user_single_step_siginfo() helper -c575558 utrace: barriers for initializing struct utrace -89df3c7 utrace: utrace_attach_task() forgets to return when ->utrace == NULL -4d17e95 utrace: finish_report() must never set ->resume = UTRACE_STOP -212f67e utrace: utrace_get_signal() must check ->pending_attach -eff6ca8 change ptrace_report_signal() to use user_single_step_siginfo() -cba1272 don't send the unnecessary SIGTRAP after SYSCALL_EXIT -8aa71a6 revert "turn PTRACE_EVENT_SIGTRAP into PTRACE_EVENT_SIGNAL" -90c8237 utrace-ptrace: minimally handle UTRACE_SYSCALL_RESUMED -a7e9198 utrace: clean up resume-action handling -962eb2f utrace: update after merge -e2ced71 re-introduce utrace_finish_stop() to fix the race with SIGKILL -603e19c turn PTRACE_EVENT_SIGTRAP into PTRACE_EVENT_SIGNAL -ff87f65 introduce suppress_sigtrap() to prevent unwanted send_sigtrap() -6505e3c move ptrace_resume()->send_sigtrap() logic into ptrace_report_signal() -5261baa prepare ptrace_report_signal() to synthesize SIGTRAP -ef9534b ptrace_request: turn ptrace_resume() into default case -f50c776 s/context/ctx/ -228b2e3 ptrace_notify_stop: kill the temporary WARN_ON() -93e866a ptrace_request(PTRACE_KILL) should not(?) return -ESRCH -26fefca utrace: sticky resume action -28b2774b utrace: remove ->stopped field -9e0f357 utrace_set_events: nit clean up -6d0bad3 nits -48bab07 (utrace) utrace_get_signal: don't dequeue_signal() if ->group_stop_count -d4ef551 (upstream) signals: check ->group_stop_count after tracehook_get_signal() -6292daa ptrace_detach_task: don't use valid_signal() -c5a6a82 cosmetic, renames -e422a3f cosmetic, relocate some code in ptrace.c -b96e4db (upstream) introduce kernel/ptrace.h -7665564 (upstream) tracehook_signal_handler: check PT_PTRACED -7d708ca tracehooks: revert utrace-ptrace changes -4104e29 (upstream) ptrace_init_task: cleanup the usage of ptrace_link() -d04ccb7 revert all utrace-ptrace changes in ptrace.h -80786ce revert utrace-ptrace changes in kernel/signal.c -0b02f9e introduce PT_UTRACED to replace PT_PTRACED inside ptrace.c -030ce35 tracehooks: remove some PT_PTRACED checks -4b7b15a revert the clone() related changes in tracehook.h -769030e hack ptrace_check_attach() to make it almost correct -7aa5c3a cosmetic, fold do_ptrace_resume() into ptrace_resume() -d27ebc1 cosmetic, introduce ptrace_resume_action() -35fbca4 turn context->sysemu into PTRACE_O_SYSEMU -38a8c1f PTRACE_SYSEMU_SINGLESTEP support -4367836 PTRACE_SYSEMU support -16819db ptrace_report_clone: minor cleanups + comments -ac1afd8 ptrace_resume: rewrite request processing -6b0d4f6 do_ptrace_resume: always use ptrace_wake_up() -fa92ce3 do_ptrace_resume: consolidate multiple switch stmts -135d780 uglify the code again to report VFORK_DONE after VFORK -4e3f362 fix PTRACE_SYSCALL after PTRACE_EVENT_VFORK_DONE stop -3f95189 ptrace_report_clone: uglify even more to handle TRACEVFORKDONE without TRACEVFORK -66ca8b6 ptrace_report_clone: uglify CLONE_PTRACE/CLONE_UNTRACED behaviour to match upstream -fc82b2c pretend PTRACE_O_TRACEVFORKDONE doesn't exist -28aa15a utrace_set_events: never return -EINPROGRESS unless clearing some event bits -a7f4350 utrace_stop: do ptrace_notify_stop() unconditionally -cb78492 ptrace_report_exit: fix WARN_ON() condition -bb941c3 do_ptrace_notify_stop: document the usage of tracee->exit_code -383ba85 ptrace_wake_up: don't clear tracee->exit_code + update comments -3d5c221 ptrace_wake_up: add "bool force_wakeup" argument for implicit detach -be6862e ptrace_wake_up: clear context->stop_code -bfb40c8 detach: use ptrace_wake_up() instead of utrace_control() -7de148a shift context re-initialization from detach to reuse -464def3 cleanup/optimize reuse/attch in ptrace_attach_task() -50f56b9 ptrace_attach_task: rely on utrace_barrier(), don't check ->ops -03376fd use set_stop_code() in ptrace_report_signal(UTRACE_SIGNAL_HANDLER) -85f8b3a detach should reset the context of self-detaching engine -a27233a attach: try to re-use the self-detaching engine -8667615 ptrace_notify_stop: fix engine leak -3d5d053 ptrace_detach_task: don't use engine ptr before IS_ERR(engine) -01875c7 fold detach_signal() into ptrace_detach_task() -464c2b7 don't detach the engine with the parting signal -97b345c implement the basic detach-with-signal logic -a158247 rework access to context->siginfo -20ea83b introduce set_stop_code() helper -eb222ed cosmetic, misc renames -f83b2ca move "event << 8" into syscall_code() -4c99287 kill context->ev_name -df7c8f2 encode internal stop events in ->ev_code too -3f48297 introduce get_stop_code(context) helper -313bad1 introduce syscall_code(context) helper -47b5e2c don't clear context->ev_code for debugging -4e09fe3 convert ptrace_setsiginfo() to use ptrace_rw_siginfo() -53187be convert ptrace_getsiginfo() to use ptrace_rw_siginfo() -e7ac055 introduce ptrace_rw_siginfo() helper -c625793 move "resume signal" logic into the tracee's context -0768d89 UTRACE_SIGNAL_HANDLER should never see ->siginfo != NULL -e90cb71 don't use task_struct->ptrace_message -842684f do_ptrace_notify_stop: fix the race with SIGKILL -d0ed18d do_ptrace_notify_stop: backport the "sync wakeup" logic -08f4a21 fix the stepping over syscall -a55d174 implement the stacked SYSCALL_EXIT event -ba73824 ptrace_resume: don't ignore "data" argument -fbd4368 kill context->ev_array[] -3c6f822 Revert "ptrace_resume_signal() should use context->siginfo under ->siglock" -ee31432 Revert "UTRACE_SIGNAL_HANDLER should never see ->siginfo != NULL" -a4e5af1 Revert "introduce context_siginfo() helper" -9bc939a revert merge w/s change -6752625 introduce context_siginfo() helper -d43a453 UTRACE_SIGNAL_HANDLER should never see ->siginfo != NULL -e4e48df ptrace_resume_signal() should use context->siginfo under ->siglock -4492770 implement UTRACE_SIGNAL_HANDLER stepping -5f926a5 implement PTRACE_SINGLESTEP/PTRACE_SINGLEBLOCK -8b70ae1 ptrace_request: use ptrace_lookup_engine() -abd580d change ptrace_resume() to have the single "return" -85878ae introduce ptrace_lookup_engine() -74904f1 mv task_struct->last_siginfo ptrace_context->siginfo -2b17f4a pretens ptrace_detach(sig) works -075db41 ptrace_report_quiesce() can't trust fatal_signal_pending() -d583c87 remove the now unneeded code -69a6c83 break ptrace_report_signal() -d6a31ee do_ptrace_notify_stop: kill "->ev_message != 0" check -e194687 convert ptrace_report_exit() -8bf8304 PTRACE_EVENT_VFORK_DONE: set ev_options = PTRACE_O_TRACEVFORKDONE -b8f5e2a make sure PTRACE_SYSCALL reports SYSCALL_EXIT -258b27d make sure PTRACE_CONT "disables" SYSCALL_EXIT report -d26b659 introduce ptrace_event->ev_options -03a0fe3 convert ptrace_report_exec() -bea6139 convert ptrace_report_syscall_entry() -17dd96d cleanup/simplify stop/resume mess -97fc962 utrace: comments -c661ddb utrace: move struct utrace back where it belongs -95dcdee implement stacked stop events -8608da6 ptrace_report_syscall_exit: do not WARN() if killed -95a6b6b ptrace_report_clone: rework the stop/resume logic -25dd723 remove the current PTRACE_EVENT_VFORK_DONE logic -7d8900a ptrace_wake_up: fix the "compatibility bug" logic -9a50d27 ptrace_report_syscall_exit: return UTRACE_STOP, not UTRACE_RESUME -c07370d simplify utrace_add_engine() vs utrace_reap() protection -0f4d918 utrace_add_engine: cleanup -a24e891 fix utrace_reset() vs release_task() theoretical race -dfc0917 change attach/release to avoid unnecessary utrace_reap() -cbed668 utrace_attach_task: do no check ->exit_state -9d114a6 utrace_wakeup: do not check target->state -9368f18 utrace_wakeup: lock ->siglock directly -e9b58e9 convert ptrace_report_syscall_exit() to use ptrace_context -1d47e4d introduce context->resume_stopped() -c34d813 introduce context->stopped_code -b7edb5e introduce ptrace_notify_stop() -93b2e7e utrace_release_task: cosmetic -ac6e19c utrace_reap: loop lockless, do not clear ->ops and ->flags early -7852d10 utrace: slow_path -> pending_attach -c827b15 utrace_add_engine() should set ->utrace_flags |= REAP -2e12892 utrace_reap: fix missing callback -04852f3 utrace: do not force report on attach -37b68f7 kill ptrace_setoptions() and ptrace_update_utrace() -f1b39f3 use context->options instead of "->ptrace & PT_" -d05bf8e ptrace_set_options: use PTRACE_O_ instead of PT_ -167b56a "disable" tracehook_prepare_clone() -5e526f3 introduce ptrace_set_options() -4a50ac1 introduce ptrace_context->options -0457aa8 introduce the empty struct ptrace_context -a2bca6f utrace_reset: do not use "unsafe mode" -eac91f4 utrace_control: don't mark_engine_detached() before engine_wants_stop() -c2916fb utrace_control: fix utrace_reset(safe) usage when ->exit_state != 0 -c36a311 utrace_reset fix -8d2fc04 utrace: remove unused inline -64a8ca3 utrace_reset cleanup -d1a14ce utrace: change UTRACE_STOP bookkeeping -96fe3cc Revert "utrace_stop: fix UTRACE_DETACH race" -ceaae71 utrace: check QUIESCE before reporting UTRACE_SIGNAL_REPORT/HANDLER -fc30d20 utrace_do_stop: move "if (exit_state)" logic to the caller -9b655f7 utrace_do_stop: don't set ->stopped when ->exit_state -9ed6a39 utrace_set_events: never return -EINPROGRESS on a zombie -592d977 utrace_do_stop: cleanup the usage of ->siglock -7f51e58 utrace: fix utrace->signal_handler "leakage" -be5e266 utrace: utrace_finish_vfork: check ->vfork_stop lockless -c3580f1 utrace-ptrace: fix conditions in ptrace_do_detach -00932db utrace_stop: fix UTRACE_DETACH race -b032859 utrace: move utrace_stop down -a62ed15 utrace: consolidate utrace_reset callers -c8315d3 ptrace_do_detach: Fiddle code to avoid warnings. -e3635f1 utrace-ptrace: use WARN_ON(), suppress __must_check warning -8ba59d7 ptrace_attach_task: kill ->ptrace != 0 check -a18378e exit_ptrace: use ptrace_do_detach() -371c69c ptrace_detach: do ptrace_unlink() first -096f3ed ptrace_detach: kill the unconditional wakeup -d999521 ptrace_report_clone: rework auto-attaching -8cefebf move ->ptrace == 0 checks to ptrace_attach_task() -471d6f4 utrace_engine_ops: add release hook -78ca7e7 utrace_control: return -EINVAL for missing UTRACE_EVENT(QUIESCE) -fcb8fa0 change ptrace_traceme() to use the new helpers, kill prepare/finish attach -e82feff rework prepare_ptrace_attach/finish_ptrace_attach -3bea38f do not use engine->data -57cedd0 ptrace_detach_task: always do UTRACE_DETACH -2093f3a shift ptrace_utrace_exit() from tracehook_report_exit() to exit_ptrace() -33fb930 ptrace_resume()->send_sig() can crash -a7b05fd ptrace_check_attach: check child->parent -5ed4eff remove (almost all) !CONFIG_UTRACE_PTRACE code -fb9379c change utrace_stop() to return void -5bbbb41 kill utrace_report->killed -0b57f74 finish_utrace_stop: use __fatal_signal_pending(), dont take ->siglock -113a07e utrace: rework finish_report flag logic -8ad60bb utrace_stop: preserve report/interrupt requests across stop/resume -af3eb44 get_utrace_lock: do not check EXIT_DEAD -d87e8c4 finish_utrace_stop: check ->stopped lockless -3e0a686 utrace_report_jctl/utrace_get_signal: do not play with ->stopped -7d97118 utrace_do_stop: s/STOPPED/TRACED/ to protect against SIGCONT -ad2497a use tracehook_finish_jctl() to clear ->stopped -f99db9f utrace_report_jctl: do not play with the group-stop state -fd89498 introduce tracehook_finish_jctl() helper -ff6be89 do_signal_stop: do not call tracehook_notify_jctl() in TASK_STOPPED state -66e0705 utrace_stop: don't forget about SIGNAL_STOP_STOPPED -2edad7d utrace_wakeup: take ->group_stop_count into account -d4bcb57 utrace_reap: clear engine->flags when finishing detach -cf890ad utrace: fix utrace->reporting left set for no callback -cbe5188 More than one user has hit the -EEXIST problem when using utrace_attach_task and UTRACE_ATTACH_EXCLUSIVE without UTRACE_ATTACH_MATCH_DATA|_OPS. Document that a bit more. -52db080 UTRACE_SYSCALL_RESUMED repeat callback -5e67e22 utrace docbook: s/first/last/ braino -4bd78f8 utrace: reverse engine callback order for report_syscall_entry -1757088 utrace: WARN instead of BUG on misuse of UTRACE_*STEP without arch_has_*_step() check -5d4e97b utrace: restore tracehook_report_death comment misplaced in merges -cb49dcd utrace_report_syscall_entry: remove unnecessary recalc_sigpending() check -c0909b5 utrace_resume: fix potential TIF_SIGPENDING race -f0a1c64 utrace: use \t separator in /proc/pid/status -13a5838 utrace: init_task syntax nit -715d2a1 utrace: cosmetic -42de707 utrace_report_jctl: do splice_attaching -622013d utrace_resume: remove racy BUG_ON -282d685 whitespace fix -bec92f8 signals: tracehook_notify_jctl change -a7181aa utrace: simplify death report condition -4d8a6fd utrace: barrier between TIF_NOTIFY_RESUME check and utrace_flags/utrace->report checks -ae3096f utrace-ptrace: remove unsafe_exec and tracer_task hooks -325fecc utrace: get rid of tracer_task and unsafe_exec hooks -0084fc2 utrace: ensure UTRACE_REPORT callback return leads to callback after utrace_stop -5bdc6f1 utrace: cosmetic: DEAD_FLAGS_MASK macro -5c5bdbe utrace: cosmetic: _UTRACE_DEATH_EVENTS macro -f067223 utrace: make sure utrace_flags is nonzero before set_notify_resume at attach -e2d293e utrace: drop racy unlocked check in utrace_do_stop -68f3899 utrace: fix ->report_jctl @notify argument -c743327 utrace: avoid unnecessary list_for_each_safe -acd516b utrace_stop: trivial, kill the unnecessary assignment -81ed517 utrace_add_engine: add missing 'else' after 'if (utrace->reap)' -215a076 utrace: tracehook.h comment -a584c66 utrace: fix utrace_attach_delay() creator test -827ec3b utrace: comment ->reporting implementation -07732b4 utrace-ptrace: handle -ERESTARTNOINTR from utrace_attach_task -2233b06 utrace: finish utrace_reap conversion after indirect->direct struct utrace -dd30e86 utrace: fix utrace_attach_delay() to loop, remove struct utrace.cloning field -be4f357 get_utrace_lock: kill the bogus engine->kref.refcount check -c367207 utrace: clear struct in utrace_init_task -94f168c utrace: define UTRACE_API_VERSION -742f120 utrace: place struct utrace directly in task_struct -cb25a58 utrace: comment fixes -2b834a5 utrace-ptrace: struct utrace_attached_engine -> struct utrace_engine -6b8306a utrace: struct utrace_attached_engine -> struct utrace_engine -9fe3bac utrace-ptrace: Kconfig doc update -5bb0052 utrace: cosmetic changes -556a7e7 utrace-ptrace: fix resuming with blocked signal -3a9f4c8 utrace: order utrace_control() after callback return value processing -269150d Cosmetic reorganization to further simplify utrace pointer vs embedded-struct. -ea30176 Use task_utrace_struct() helper in utrace_interrupt_pending(). -ed2098a Use task_utrace_struct() helper -97d5cde cosmetic code reorganization -4e8a7ca Remove UTRACE_DEBUG hacks -25fb674 utrace: exclude PTRACE_TRACEME -f286be7 utrace-ptrace: remove utrace_engine_put stub -e0c36bd Disable mutual exclusion if CONFIG_UTRACE_PTRACE -c93d704 utrace/ptrace mutual exclusion -594f22c cond_resched() before race-restart in utrace_attach_task -0da72f3 Clean up utrace_attach_task code. -fd3d457 utrace: ptrace cooperation -f357a74 utrace core ---- - Documentation/DocBook/Makefile | 2 +- - Documentation/DocBook/utrace.tmpl | 590 +++++++++ - fs/proc/array.c | 3 + - include/linux/ptrace.h | 3 +- - include/linux/sched.h | 6 + - include/linux/tracehook.h | 97 ++- - include/linux/utrace.h | 692 +++++++++++ - init/Kconfig | 9 + - kernel/Makefile | 2 + - kernel/fork.c | 3 + - kernel/ptrace-utrace.c | 1127 +++++++++++++++++ - kernel/ptrace.c | 620 +++++----- - kernel/signal.c | 4 +- - kernel/utrace.c | 2452 +++++++++++++++++++++++++++++++++++++ - 14 files changed, 5291 insertions(+), 319 deletions(-) - create mode 100644 Documentation/DocBook/utrace.tmpl - create mode 100644 include/linux/utrace.h - create mode 100644 kernel/ptrace-utrace.c - create mode 100644 kernel/utrace.c - diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile -index c7e5dc7..e63f889 100644 +index 34929f2..884c36b 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \ @@ -356,10 +13,10 @@ index c7e5dc7..e63f889 100644 # The build process is as follows (targets): diff --git a/Documentation/DocBook/utrace.tmpl b/Documentation/DocBook/utrace.tmpl new file mode 100644 -index 0000000..e149f49 +index 0000000..0c40add --- /dev/null +++ b/Documentation/DocBook/utrace.tmpl -@@ -0,0 +1,590 @@ +@@ -0,0 +1,589 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" +"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []> @@ -719,13 +376,12 @@ index 0000000..e149f49 + after a successful call, no event callbacks not requested in the new + flags will be made. It fails with <constant>-EALREADY</constant> if + you try to clear <constant>UTRACE_EVENT(DEATH)</constant> when the -+ <function>report_death</function> callback may already have begun, if -+ you try to clear <constant>UTRACE_EVENT(REAP)</constant> when the -+ <function>report_reap</function> callback may already have begun, or if ++ <function>report_death</function> callback may already have begun, or if + you try to newly set <constant>UTRACE_EVENT(DEATH)</constant> or + <constant>UTRACE_EVENT(QUIESCE)</constant> when the target is already + dead or dying. Like <function>utrace_control</function>, it returns -+ <constant>-ESRCH</constant> when the thread has already been detached ++ <constant>-ESRCH</constant> when the <function>report_reap</function> ++ callback may already have begun, or the thread has already been detached + (including forcible detach on reaping). This lets the tracing engine + know for sure which event callbacks it will or won't see after + <function>utrace_set_events</function> has returned. By checking for @@ -951,7 +607,7 @@ index 0000000..e149f49 + +</book> diff --git a/fs/proc/array.c b/fs/proc/array.c -index 9b58d38..c7c7881 100644 +index fff6572..a67bd83 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -81,6 +81,7 @@ @@ -991,10 +647,10 @@ index 4272521..235c1b0 100644 extern void ptrace_disable(struct task_struct *); extern int ptrace_check_attach(struct task_struct *task, int kill); diff --git a/include/linux/sched.h b/include/linux/sched.h -index f118809..d3fef7a 100644 +index ce160d6..66a1ec8 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h -@@ -1348,6 +1348,11 @@ struct task_struct { +@@ -1339,6 +1339,11 @@ struct task_struct { #endif seccomp_t seccomp; @@ -1006,7 +662,7 @@ index f118809..d3fef7a 100644 /* Thread group tracking */ u32 parent_exec_id; u32 self_exec_id; -@@ -2033,6 +2038,7 @@ extern int kill_pgrp(struct pid *pid, int sig, int priv); +@@ -2030,6 +2035,7 @@ extern int kill_pgrp(struct pid *pid, int sig, int priv); extern int kill_pid(struct pid *pid, int sig, int priv); extern int kill_proc_info(int, struct siginfo *, pid_t); extern int do_notify_parent(struct task_struct *, int); @@ -1975,12 +1631,12 @@ index 0000000..f251efe + +#endif /* linux/utrace.h */ diff --git a/init/Kconfig b/init/Kconfig -index 5cff9a9..c0b7f81 100644 +index 2de5b1c..a283086 100644 --- a/init/Kconfig +++ b/init/Kconfig -@@ -328,6 +328,15 @@ config AUDIT_TREE +@@ -332,6 +332,15 @@ config AUDIT_TREE depends on AUDITSYSCALL - select INOTIFY + select FSNOTIFY +config UTRACE + bool "Infrastructure for tracing and debugging user processes" @@ -1995,7 +1651,7 @@ index 5cff9a9..c0b7f81 100644 choice diff --git a/kernel/Makefile b/kernel/Makefile -index 057472f..dfdc01c 100644 +index 0b72d1a..b09c9a5 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -70,6 +70,8 @@ obj-$(CONFIG_IKCONFIG) += configs.o @@ -2004,11 +1660,11 @@ index 057472f..dfdc01c 100644 obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o +obj-$(CONFIG_UTRACE) += utrace.o +obj-$(CONFIG_UTRACE) += ptrace-utrace.o - obj-$(CONFIG_AUDIT) += audit.o auditfilter.o audit_watch.o + obj-$(CONFIG_AUDIT) += audit.o auditfilter.o obj-$(CONFIG_AUDITSYSCALL) += auditsc.o - obj-$(CONFIG_GCOV_KERNEL) += gcov/ + obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o diff --git a/kernel/fork.c b/kernel/fork.c -index b6cce14..ac4a6ec 100644 +index 98b4508..3ceff6f 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -161,6 +161,7 @@ void free_task(struct task_struct *tsk) @@ -2019,7 +1675,7 @@ index b6cce14..ac4a6ec 100644 free_task_struct(tsk); } EXPORT_SYMBOL(free_task); -@@ -1007,6 +1008,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, +@@ -1008,6 +1009,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, if (!p) goto fork_out; @@ -2030,10 +1686,10 @@ index b6cce14..ac4a6ec 100644 rt_mutex_init_task(p); diff --git a/kernel/ptrace-utrace.c b/kernel/ptrace-utrace.c new file mode 100644 -index 0000000..86234ee +index 0000000..1a8ba5e --- /dev/null +++ b/kernel/ptrace-utrace.c -@@ -0,0 +1,1127 @@ +@@ -0,0 +1,1125 @@ +/* + * linux/kernel/ptrace.c + * @@ -2086,8 +1742,6 @@ index 0000000..86234ee + child->ptrace = 0; + child->parent = child->real_parent; + list_del_init(&child->ptrace_entry); -+ -+ arch_ptrace_untrace(child); +} + +struct ptrace_context { @@ -3162,7 +2816,7 @@ index 0000000..86234ee +} +#endif /* CONFIG_COMPAT */ diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 74a3d69..c77f9bf 100644 +index f34d798..daed9e8 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -23,7 +23,317 @@ @@ -3417,7 +3071,7 @@ index 74a3d69..c77f9bf 100644 + out: + return ret; +} -+ + +int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data) +{ + unsigned long tmp; @@ -3478,7 +3132,7 @@ index 74a3d69..c77f9bf 100644 + return ret; +} +#endif /* CONFIG_COMPAT */ - ++ +#ifndef CONFIG_UTRACE /* * ptrace a task: make the debugger its new parent and @@ -3537,10 +3191,47 @@ index 74a3d69..c77f9bf 100644 int ptrace_attach(struct task_struct *task) { int retval; -@@ -242,57 +505,6 @@ int ptrace_traceme(void) - return ret; - } +@@ -205,92 +468,41 @@ int ptrace_attach(struct task_struct *task) + send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); + retval = 0; +-unlock_tasklist: +- write_unlock_irq(&tasklist_lock); +-unlock_creds: +- mutex_unlock(&task->cred_guard_mutex); +-out: +- return retval; +-} +- +-/** +- * ptrace_traceme -- helper for PTRACE_TRACEME +- * +- * Performs checks and sets PT_PTRACED. +- * Should be used by all ptrace implementations for PTRACE_TRACEME. +- */ +-int ptrace_traceme(void) +-{ +- int ret = -EPERM; +- +- write_lock_irq(&tasklist_lock); +- /* Are we already being traced? */ +- if (!current->ptrace) { +- ret = security_ptrace_traceme(current->parent); +- /* +- * Check PF_EXITING to ensure ->real_parent has not passed +- * exit_ptrace(). Otherwise we don't report the error but +- * pretend ->real_parent untraces us right after return. +- */ +- if (!ret && !(current->real_parent->flags & PF_EXITING)) { +- current->ptrace = PT_PTRACED; +- __ptrace_link(current, current->real_parent); +- } +- } +- write_unlock_irq(&tasklist_lock); +- +- return ret; +-} +- -/* - * Called with irqs disabled, returns true if childs should reap themselves. - */ @@ -3563,16 +3254,30 @@ index 74a3d69..c77f9bf 100644 - * If it's a zombie, our attachedness prevented normal parent notification - * or self-reaping. Do notification now if it would have happened earlier. - * If it should reap itself, return true. -- * ++unlock_tasklist: ++ write_unlock_irq(&tasklist_lock); ++unlock_creds: ++ mutex_unlock(&task->cred_guard_mutex); ++out: ++ return retval; ++} ++ ++/** ++ * ptrace_traceme -- helper for PTRACE_TRACEME + * - * If it's our own child, there is no notification to do. But if our normal - * children self-reap, then this child was prevented by ptrace and we must - * reap it now, in that case we must also wake up sub-threads sleeping in - * do_wait(). -- */ ++ * Performs checks and sets PT_PTRACED. ++ * Should be used by all ptrace implementations for PTRACE_TRACEME. + */ -static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) --{ ++int ptrace_traceme(void) + { - __ptrace_unlink(p); -- ++ int ret = -EPERM; + - if (p->exit_state == EXIT_ZOMBIE) { - if (!task_detached(p) && thread_group_empty(p)) { - if (!same_thread_group(p->real_parent, tracer)) @@ -3586,17 +3291,29 @@ index 74a3d69..c77f9bf 100644 - /* Mark it as in the process of being reaped. */ - p->exit_state = EXIT_DEAD; - return true; -- } -- } -- ++ write_lock_irq(&tasklist_lock); ++ /* Are we already being traced? */ ++ if (!current->ptrace) { ++ ret = security_ptrace_traceme(current->parent); ++ /* ++ * Check PF_EXITING to ensure ->real_parent has not passed ++ * exit_ptrace(). Otherwise we don't report the error but ++ * pretend ->real_parent untraces us right after return. ++ */ ++ if (!ret && !(current->real_parent->flags & PF_EXITING)) { ++ current->ptrace = PT_PTRACED; ++ __ptrace_link(current, current->real_parent); + } + } ++ write_unlock_irq(&tasklist_lock); + - return false; --} -- ++ return ret; + } + int ptrace_detach(struct task_struct *child, unsigned int data) - { - bool dead = false; -@@ -346,56 +558,6 @@ void exit_ptrace(struct task_struct *tracer) - } +@@ -352,56 +564,6 @@ void exit_ptrace(struct task_struct *tracer) + write_lock_irq(&tasklist_lock); } -int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len) @@ -3652,7 +3369,7 @@ index 74a3d69..c77f9bf 100644 static int ptrace_setoptions(struct task_struct *child, long data) { child->ptrace &= ~PT_TRACE_MASK; -@@ -456,7 +618,6 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) +@@ -462,7 +624,6 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) return error; } @@ -3660,7 +3377,7 @@ index 74a3d69..c77f9bf 100644 #ifdef PTRACE_SINGLESTEP #define is_singlestep(request) ((request) == PTRACE_SINGLESTEP) #else -@@ -510,47 +671,6 @@ static int ptrace_resume(struct task_struct *child, long request, long data) +@@ -516,47 +677,6 @@ static int ptrace_resume(struct task_struct *child, long request, long data) return 0; } @@ -3708,7 +3425,7 @@ index 74a3d69..c77f9bf 100644 int ptrace_request(struct task_struct *child, long request, long addr, long data) { -@@ -666,88 +786,7 @@ int ptrace_request(struct task_struct *child, long request, +@@ -672,88 +792,7 @@ int ptrace_request(struct task_struct *child, long request, return ret; } @@ -3797,7 +3514,7 @@ index 74a3d69..c77f9bf 100644 int compat_ptrace_request(struct task_struct *child, compat_long_t request, compat_ulong_t addr, compat_ulong_t data) { -@@ -825,42 +864,5 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, +@@ -831,42 +870,5 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, return ret; } @@ -3842,10 +3559,10 @@ index 74a3d69..c77f9bf 100644 #endif /* CONFIG_COMPAT */ +#endif /* CONFIG_UTRACE */ diff --git a/kernel/signal.c b/kernel/signal.c -index 906ae5a..8087f13 100644 +index bded651..6d13d9f 100644 --- a/kernel/signal.c +++ b/kernel/signal.c -@@ -1518,7 +1518,7 @@ int do_notify_parent(struct task_struct *tsk, int sig) +@@ -1521,7 +1521,7 @@ int do_notify_parent(struct task_struct *tsk, int sig) return ret; } @@ -3854,7 +3571,7 @@ index 906ae5a..8087f13 100644 { struct siginfo info; unsigned long flags; -@@ -1788,7 +1788,7 @@ static int do_signal_stop(int signr) +@@ -1791,7 +1791,7 @@ static int do_signal_stop(int signr) static int ptrace_signal(int signr, siginfo_t *info, struct pt_regs *regs, void *cookie) { @@ -3865,10 +3582,10 @@ index 906ae5a..8087f13 100644 ptrace_signal_deliver(regs, cookie); diff --git a/kernel/utrace.c b/kernel/utrace.c new file mode 100644 -index 0000000..f5a9e2c +index 0000000..4d61096 --- /dev/null +++ b/kernel/utrace.c -@@ -0,0 +1,2452 @@ +@@ -0,0 +1,2450 @@ +/* + * utrace infrastructure interface for debugging user processes + * @@ -4099,6 +3816,7 @@ index 0000000..f5a9e2c + */ + list_add_tail(&engine->entry, &utrace->attaching); + utrace->pending_attach = 1; ++ utrace_engine_get(engine); + ret = 0; +unlock: + spin_unlock(&utrace->lock); @@ -4172,10 +3890,10 @@ index 0000000..f5a9e2c + return ERR_PTR(-ENOMEM); + + /* -+ * Initialize the new engine structure. It starts out with two -+ * refs: one ref to return, and one ref for being attached. ++ * Initialize the new engine structure. It starts out with one ref ++ * to return. utrace_add_engine() adds another for being attached. + */ -+ kref_set(&engine->kref, 2); ++ kref_init(&engine->kref); + engine->flags = 0; + engine->ops = ops; + engine->data = data; @@ -4188,6 +3906,7 @@ index 0000000..f5a9e2c + engine = ERR_PTR(ret); + } + ++ + return engine; +} +EXPORT_SYMBOL_GPL(utrace_attach_task); @@ -4292,7 +4011,7 @@ index 0000000..f5a9e2c + + utrace = task_utrace_struct(target); + spin_lock(&utrace->lock); -+ if (unlikely(!engine->ops) || ++ if (unlikely(utrace->reap) || unlikely(!engine->ops) || + unlikely(engine->ops == &utrace_detached_ops)) { + /* + * By the time we got the utrace lock, @@ -4358,13 +4077,12 @@ index 0000000..f5a9e2c + * + * This fails with -%EALREADY and does nothing if you try to clear + * %UTRACE_EVENT(%DEATH) when the @report_death callback may already have -+ * begun, if you try to clear %UTRACE_EVENT(%REAP) when the @report_reap -+ * callback may already have begun, or if you try to newly set -+ * %UTRACE_EVENT(%DEATH) or %UTRACE_EVENT(%QUIESCE) when @target is -+ * already dead or dying. ++ * begun, or if you try to newly set %UTRACE_EVENT(%DEATH) or ++ * %UTRACE_EVENT(%QUIESCE) when @target is already dead or dying. + * -+ * This can fail with -%ESRCH when @target has already been detached, -+ * including forcible detach on reaping. ++ * This fails with -%ESRCH if you try to clear %UTRACE_EVENT(%REAP) when ++ * the @report_reap callback may already have begun, or when @target has ++ * already been detached, including forcible detach on reaping. + * + * If @target was stopped before the call, then after a successful call, + * no event callbacks not requested in @events will be made; if @@ -4395,7 +4113,7 @@ index 0000000..f5a9e2c +{ + struct utrace *utrace; + unsigned long old_flags, old_utrace_flags; -+ int ret; ++ int ret = -EALREADY; + + /* + * We just ignore the internal bit, so callers can use @@ -4410,14 +4128,12 @@ index 0000000..f5a9e2c + old_utrace_flags = target->utrace_flags; + old_flags = engine->flags & ~ENGINE_STOP; + -+ if (target->exit_state && -+ (((events & ~old_flags) & _UTRACE_DEATH_EVENTS) || -+ (utrace->death && -+ ((old_flags & ~events) & _UTRACE_DEATH_EVENTS)) || -+ (utrace->reap && ((old_flags & ~events) & UTRACE_EVENT(REAP))))) { -+ spin_unlock(&utrace->lock); -+ return -EALREADY; -+ } ++ /* ++ * If utrace_report_death() is already progress now, ++ * it's too late to clear the death event bits. ++ */ ++ if (((old_flags & ~events) & _UTRACE_DEATH_EVENTS) && utrace->death) ++ goto unlock; + + /* + * When setting these flags, it's essential that we really @@ -4429,12 +4145,11 @@ index 0000000..f5a9e2c + * knows positively that utrace_report_death() will be called or + * that it won't. + */ -+ if ((events & ~old_utrace_flags) & _UTRACE_DEATH_EVENTS) { ++ if ((events & ~old_flags) & _UTRACE_DEATH_EVENTS) { + read_lock(&tasklist_lock); + if (unlikely(target->exit_state)) { + read_unlock(&tasklist_lock); -+ spin_unlock(&utrace->lock); -+ return -EALREADY; ++ goto unlock; + } + target->utrace_flags |= events; + read_unlock(&tasklist_lock); @@ -4462,7 +4177,7 @@ index 0000000..f5a9e2c + if (utrace->reporting == engine) + ret = -EINPROGRESS; + } -+ ++unlock: + spin_unlock(&utrace->lock); + + return ret; @@ -6321,6 +6036,3 @@ index 0000000..f5a9e2c +{ + seq_printf(m, "Utrace:\t%lx\n", p->utrace_flags); +} --- -1.7.0.1 - diff --git a/kernel.spec b/kernel.spec index 2967f43f3..deb81ef3d 100644 --- a/kernel.spec +++ b/kernel.spec @@ -79,9 +79,9 @@ Summary: The Linux kernel # The next upstream release sublevel (base_sublevel+1) %define upstream_sublevel %(echo $((%{base_sublevel} + 1))) # The rc snapshot level -%define rcrev 0 +%define rcrev 1 # The git snapshot level -%define gitrev 1 +%define gitrev 0 # Set rpm version accordingly %define rpmversion 2.6.%{upstream_sublevel} %endif @@ -149,7 +149,6 @@ Summary: The Linux kernel %define debugbuildsenabled 0 # Want to build a vanilla kernel build without any non-upstream patches? -# (well, almost none, we need nonintconfig for build purposes). Default to 0 (off). %define with_vanilla %{?_with_vanilla: 1} %{?!_with_vanilla: 0} # pkg_release is what we'll fill in for the rpm Release: field @@ -372,12 +371,12 @@ Summary: The Linux kernel %define vdso_arches ppc ppc64 %endif +# Should make listnewconfig fail if there's config options +# printed out? %if %{nopatches}%{using_upstream_branch} -# Ignore unknown options in our config-* files. -# Some options go with patches we're not applying. -%define oldconfig_target loose_nonint_oldconfig +%define listnewconfig_fail 0 %else -%define oldconfig_target nonint_oldconfig +%define listnewconfig_fail 1 %endif # To temporarily exclude an architecture from being built, add it to @@ -579,9 +578,6 @@ Patch00: patch-2.6.%{base_sublevel}-git%{gitrev}.bz2 Patch02: git-linus.diff -# we always need nonintconfig, even for -vanilla kernels -Patch03: linux-2.6-build-nonintconfig.patch - # we also need compile fixes for -vanilla Patch04: linux-2.6-compile-fixes.patch @@ -598,8 +594,6 @@ Patch09: linux-2.6-upstream-reverts.patch Patch20: linux-2.6-hotfixes.patch Patch30: git-utrace.patch -Patch31: utrace-ptrace-fix-build.patch -Patch32: utrace-remove-use-of-kref_set.patch Patch150: linux-2.6.29-sparc-IOC_TYPECHECK.patch @@ -614,8 +608,6 @@ Patch204: linux-2.6-debug-always-inline-kzalloc.patch Patch380: linux-2.6-defaults-pci_no_msi.patch Patch383: linux-2.6-defaults-aspm.patch -Patch384: pci-acpi-disable-aspm-if-no-osc.patch -Patch385: pci-aspm-dont-enable-too-early.patch Patch390: linux-2.6-defaults-acpi-video.patch Patch391: linux-2.6-acpi-video-dos.patch @@ -671,16 +663,12 @@ Patch2901: linux-2.6-v4l-dvb-experimental.patch Patch2902: linux-2.6-v4l-dvb-uvcvideo-update.patch Patch2910: linux-2.6-v4l-dvb-add-lgdt3304-support.patch -Patch2911: linux-2.6-v4l-dvb-add-kworld-a340-support.patch Patch2912: linux-2.6-v4l-dvb-ir-core-update.patch -Patch2913: linux-2.6-v4l-dvb-ir-core-memleak-fixes.patch -Patch2915: lirc-staging-2.6.36.patch #Patch2916: lirc-staging-2.6.36-fixes.patch Patch2917: hdpvr-ir-enable.patch # fs fixes -Patch3000: linux-2.6-ext4-fix-freeze-deadlock.patch # NFSv4 @@ -696,8 +684,6 @@ Patch12018: neuter_intel_microcode_load.patch Patch12030: ssb_check_for_sprom.patch -Patch12040: only-use-alpha2-regulatory-information-from-country-IE.patch - %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1099,11 +1085,6 @@ make -f %{SOURCE20} VERSION=%{version} configs ApplyOptionalPatch git-linus.diff -# This patch adds a "make nonint_oldconfig" which is non-interactive and -# also gives a list of missing options at the end. Useful for automated -# builds (as used in the buildsystem). -ApplyPatch linux-2.6-build-nonintconfig.patch - ApplyPatch linux-2.6-makefile-after_link.patch # @@ -1120,8 +1101,6 @@ ApplyPatch linux-2.6-hotfixes.patch # Roland's utrace ptrace replacement. ApplyPatch git-utrace.patch -ApplyPatch utrace-ptrace-fix-build.patch -ApplyPatch utrace-remove-use-of-kref_set.patch # Architecture patches # x86(-64) @@ -1150,7 +1129,6 @@ ApplyPatch linux-2.6-32bit-mmap-exec-randomization.patch # # ext4 -ApplyPatch linux-2.6-ext4-fix-freeze-deadlock.patch # xfs @@ -1175,7 +1153,7 @@ ApplyPatch linux-2.6-acpi-debug-infinite-loop.patch ApplyPatch linux-2.6-debug-sizeof-structs.patch ApplyPatch linux-2.6-debug-nmi-timeout.patch ApplyPatch linux-2.6-debug-taint-vm.patch -ApplyPatch linux-2.6-debug-vm-would-have-oomkilled.patch +###FIX###ApplyPatch linux-2.6-debug-vm-would-have-oomkilled.patch ApplyPatch linux-2.6-debug-always-inline-kzalloc.patch # @@ -1185,10 +1163,6 @@ ApplyPatch linux-2.6-debug-always-inline-kzalloc.patch ApplyPatch linux-2.6-defaults-pci_no_msi.patch # enable ASPM by default on hardware we expect to work ApplyPatch linux-2.6-defaults-aspm.patch -# disable aspm if acpi doesn't provide an _OSC method -ApplyPatch pci-acpi-disable-aspm-if-no-osc.patch -# allow drivers to disable aspm at load time -ApplyPatch pci-aspm-dont-enable-too-early.patch # # SCSI Bits. @@ -1242,7 +1216,7 @@ ApplyPatch fix_xen_guest_on_old_EC2.patch #ApplyPatch revert-drm-kms-toggle-poll-around-switcheroo.patch # Nouveau DRM + drm fixes -ApplyPatch drm-nouveau-updates.patch +#ApplyPatch drm-nouveau-updates.patch ApplyPatch drm-intel-big-hammer.patch ApplyOptionalPatch drm-intel-next.patch ApplyPatch drm-intel-make-lvds-work.patch @@ -1260,15 +1234,12 @@ ApplyPatch linux-2.6-silence-acpi-blacklist.patch ApplyOptionalPatch linux-2.6-v4l-dvb-fixes.patch ApplyOptionalPatch linux-2.6-v4l-dvb-update.patch ApplyOptionalPatch linux-2.6-v4l-dvb-experimental.patch -ApplyPatch linux-2.6-v4l-dvb-uvcvideo-update.patch +#ApplyPatch linux-2.6-v4l-dvb-uvcvideo-update.patch +#ApplyPatch linux-2.6-v4l-dvb-ir-core-update.patch -ApplyPatch linux-2.6-v4l-dvb-ir-core-update.patch -ApplyPatch linux-2.6-v4l-dvb-ir-core-memleak-fixes.patch -ApplyPatch linux-2.6-v4l-dvb-add-lgdt3304-support.patch -ApplyPatch linux-2.6-v4l-dvb-add-kworld-a340-support.patch +###FIX###ApplyPatch linux-2.6-v4l-dvb-add-lgdt3304-support.patch # http://www.lirc.org/ -ApplyPatch lirc-staging-2.6.36.patch #ApplyOptionalPatch lirc-staging-2.6.36-fixes.patch # enable IR receiver on Hauppauge HD PVR (v4l-dvb merge pending) ApplyPatch hdpvr-ir-enable.patch @@ -1281,8 +1252,6 @@ ApplyPatch neuter_intel_microcode_load.patch # rhbz#533746 #ApplyPatch ssb_check_for_sprom.patch -ApplyPatch only-use-alpha2-regulatory-information-from-country-IE.patch - # END OF PATCH APPLICATIONS %endif @@ -1314,7 +1283,14 @@ for i in *.config do mv $i .config Arch=`head -1 .config | cut -b 3-` - make ARCH=$Arch %{oldconfig_target} > /dev/null + make ARCH=$Arch listnewconfig | egrep '^CONFIG_' >.newoptions || true +%if %{listnewconfig_fail} + if [ -s .newoptions ]; then + cat .newoptions + exit 0 + fi +%endif + rm -f .newoptions echo "# $Arch" > configs/$i cat .config >> configs/$i done @@ -1391,7 +1367,7 @@ BuildKernel() { Arch=`head -1 .config | cut -b 3-` echo USING ARCH=$Arch - make -s ARCH=$Arch %{oldconfig_target} > /dev/null + make -s ARCH=$Arch oldnoconfig >/dev/null make -s ARCH=$Arch V=1 %{?_smp_mflags} $MakeTarget %{?sparse_mflags} make -s ARCH=$Arch V=1 %{?_smp_mflags} modules %{?sparse_mflags} || exit 1 @@ -1883,6 +1859,9 @@ fi %changelog * Tue Aug 17 2010 Kyle McMartin <kyle@redhat.com> +- Linux 2.6.36-rc1 + +* Tue Aug 17 2010 Kyle McMartin <kyle@redhat.com> - Prevent scripts/setlocalversion from mucking with our version numbers. diff --git a/linux-2.6-build-nonintconfig.patch b/linux-2.6-build-nonintconfig.patch deleted file mode 100644 index e88e0ea1e..000000000 --- a/linux-2.6-build-nonintconfig.patch +++ /dev/null @@ -1,128 +0,0 @@ -diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile -index 6d69c7c..ff84d12 100644 ---- a/scripts/kconfig/Makefile -+++ b/scripts/kconfig/Makefile -@@ -58,6 +58,11 @@ localyesconfig: $(obj)/streamline_config.pl $(obj)/conf - fi - $(Q)rm -f .tmp.config - -+nonint_oldconfig: $(obj)/conf -+ $< -b $(Kconfig) -+loose_nonint_oldconfig: $(obj)/conf -+ $< -B $(Kconfig) -+ - # Create new linux.pot file - # Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files - # The symlink is used to repair a deficiency in arch/um -diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c -index 9960d1c..ac8d455 100644 ---- a/scripts/kconfig/conf.c -+++ b/scripts/kconfig/conf.c -@@ -23,6 +23,8 @@ enum { - ask_all, - ask_new, - ask_silent, -+ dont_ask, -+ dont_ask_dont_tell, - set_default, - set_yes, - set_mod, -@@ -360,7 +362,10 @@ static void conf(struct menu *menu) - - switch (prop->type) { - case P_MENU: -- if (input_mode == ask_silent && rootEntry != menu) { -+ if ((input_mode == ask_silent || -+ input_mode == dont_ask || -+ input_mode == dont_ask_dont_tell) && -+ rootEntry != menu) { - check_conf(menu); - return; - } -@@ -406,6 +411,8 @@ conf_childs: - indent -= 2; - } - -+static int return_value; -+ - static void check_conf(struct menu *menu) - { - struct symbol *sym; -@@ -418,12 +425,21 @@ static void check_conf(struct menu *menu) - if (sym && !sym_has_value(sym)) { - if (sym_is_changable(sym) || - (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { -+ if (input_mode == dont_ask || -+ input_mode == dont_ask_dont_tell) { -+ if (input_mode == dont_ask && -+ sym->name && !sym_is_choice_value(sym)) { -+ fprintf(stderr,"CONFIG_%s\n",sym->name); -+ ++return_value; -+ } -+ } else { - if (!conf_cnt++) - printf(_("*\n* Restart config...\n*\n")); - rootEntry = menu_get_parent_menu(menu); - conf(rootEntry); - } - } -+ } - - for (child = menu->list; child; child = child->next) - check_conf(child); -@@ -439,7 +455,7 @@ int main(int ac, char **av) - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - -- while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) { -+ while ((opt = getopt(ac, av, "osbBdD:nmyrh")) != -1) { - switch (opt) { - case 'o': - input_mode = ask_silent; -@@ -448,6 +464,12 @@ int main(int ac, char **av) - input_mode = ask_silent; - sync_kconfig = 1; - break; -+ case 'b': -+ input_mode = dont_ask; -+ break; -+ case 'B': -+ input_mode = dont_ask_dont_tell; -+ break; - case 'd': - input_mode = set_default; - break; -@@ -525,6 +547,8 @@ int main(int ac, char **av) - case ask_silent: - case ask_all: - case ask_new: -+ case dont_ask: -+ case dont_ask_dont_tell: - conf_read(NULL); - break; - case set_no: -@@ -586,12 +610,16 @@ int main(int ac, char **av) - conf(&rootmenu); - input_mode = ask_silent; - /* fall through */ -+ case dont_ask: -+ case dont_ask_dont_tell: - case ask_silent: - /* Update until a loop caused no more changes */ - do { - conf_cnt = 0; - check_conf(&rootmenu); -- } while (conf_cnt); -+ } while (conf_cnt && -+ (input_mode != dont_ask && -+ input_mode != dont_ask_dont_tell)); - break; - } - -@@ -613,5 +641,5 @@ int main(int ac, char **av) - exit(1); - } - } -- return 0; -+ return return_value; - } diff --git a/linux-2.6-ext4-fix-freeze-deadlock.patch b/linux-2.6-ext4-fix-freeze-deadlock.patch deleted file mode 100644 index e7eb817af..000000000 --- a/linux-2.6-ext4-fix-freeze-deadlock.patch +++ /dev/null @@ -1,46 +0,0 @@ -[PATCH] ext4: fix freeze deadlock under IO - -Commit 6b0310fbf087ad6 caused a regression resulting in deadlocks -when freezing a filesystem which had active IO; the vfs_check_frozen -level (SB_FREEZE_WRITE) did not let the freeze-related IO syncing -through. Duh. - -Changing the test to FREEZE_TRANS should let the normal freeze -syncing get through the fs, but still block any transactions from -starting once the fs is completely frozen. - -I tested this by running fsstress in the background while periodically -snapshotting the fs and running fsck on the result. I ran into -occasional deadlocks, but different ones. I think this is a -fine fix for the problem at hand, and the other deadlocky things -will need more investigation. - -Reported-by: Phillip Susi <psusi@cfl.rr.com> -Signed-off-by: Eric Sandeen <sandeen@redhat.com> ---- - -diff --git a/fs/ext4/super.c b/fs/ext4/super.c -index 4e8983a..a45ced9 100644 ---- a/fs/ext4/super.c -+++ b/fs/ext4/super.c -@@ -241,7 +241,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) - if (sb->s_flags & MS_RDONLY) - return ERR_PTR(-EROFS); - -- vfs_check_frozen(sb, SB_FREEZE_WRITE); -+ vfs_check_frozen(sb, SB_FREEZE_TRANS); - /* Special case here: if the journal has aborted behind our - * backs (eg. EIO in the commit thread), then we still need to - * take the FS itself readonly cleanly. */ -@@ -3491,7 +3491,7 @@ int ext4_force_commit(struct super_block *sb) - - journal = EXT4_SB(sb)->s_journal; - if (journal) { -- vfs_check_frozen(sb, SB_FREEZE_WRITE); -+ vfs_check_frozen(sb, SB_FREEZE_TRANS); - ret = ext4_journal_force_commit(journal); - } - - - - diff --git a/linux-2.6-makefile-after_link.patch b/linux-2.6-makefile-after_link.patch index 94b71f9b1..d484388cd 100644 --- a/linux-2.6-makefile-after_link.patch +++ b/linux-2.6-makefile-after_link.patch @@ -42,16 +42,18 @@ index 79da65d..f11c21b 100644 cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $< diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile -index 6b4ffed..cbc3d05 100644 +index 4a2afa1..12ad9f7 100644 --- a/arch/x86/vdso/Makefile +++ b/arch/x86/vdso/Makefile -@@ -120,7 +120,8 @@ $(obj)/vdso32-syms.lds: $(vdso32.so-y:%=$(obj)/vdso32-%-syms.lds) FORCE +@@ -120,8 +120,9 @@ $(obj)/vdso32-syms.lds: $(vdso32.so-y:%=$(obj)/vdso32-%-syms.lds) FORCE quiet_cmd_vdso = VDSO $@ cmd_vdso = $(CC) -nostdlib -o $@ \ $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ -- -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) +- -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \ +- sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' + -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) \ -+ $(if $(AFTER_LINK),; $(AFTER_LINK)) ++ $(if $(AFTER_LINK),; $(AFTER_LINK)) && \ ++ sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) GCOV_PROFILE := n diff --git a/linux-2.6-silence-noise.patch b/linux-2.6-silence-noise.patch index d5de8f439..119a97769 100644 --- a/linux-2.6-silence-noise.patch +++ b/linux-2.6-silence-noise.patch @@ -64,26 +64,3 @@ Signed-off-by: Dave Jones <davej@redhat.com> } #endif -Some devices (like the nuforce udac) spew this quite a lot. -This patch kinda sucks, but it'll shut things up for now. - -Probably not an upstream candidate. I suspect the answer would be -"don't turn SND_DEBUG then" - ---- linux-2.6.34.noarch/sound/usb/clock.c~ 2010-07-16 22:11:41.000000000 -0400 -+++ linux-2.6.34.noarch/sound/usb/clock.c 2010-07-16 22:15:21.000000000 -0400 -@@ -212,8 +212,13 @@ static int set_sample_rate_v1(struct snd - - /* if endpoint doesn't have sampling rate control, bail out */ - if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) { -- snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", -+ static int once; -+ -+ if (!once) { -+ snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", - dev->devnum, iface, fmt->altsetting); -+ once = 1; -+ } - return 0; - } - diff --git a/linux-2.6-v4l-dvb-add-kworld-a340-support.patch b/linux-2.6-v4l-dvb-add-kworld-a340-support.patch deleted file mode 100644 index f1ac30793..000000000 --- a/linux-2.6-v4l-dvb-add-kworld-a340-support.patch +++ /dev/null @@ -1,165 +0,0 @@ -commit 611225f5e7f9d11c4b119fac224f1bd6903b0150 -Author: Jarod Wilson <jarod@redhat.com> -Date: Sun Mar 7 17:55:43 2010 -0300 - - V4L/DVB: dvb: add support for kworld 340u and ub435-q to em28xx-dvb - - This adds support for the KWorld PlusTV 340U and KWorld UB345-Q ATSC - sticks, which are really the same device. The sticks have an eMPIA - em2870 usb bridge chipset, an LG Electronics LGDT3304 ATSC/QAM - demodulator and an NXP TDA18271HD tuner -- early versions of the 340U - have a a TDA18271HD/C1, later models and the UB435-Q have a C2. - - The stick has been tested succesfully with both VSB_8 and QAM_256 signals. - Its using lgdt3304 support added to the lgdt3305 driver by a prior patch, - rather than the current lgdt3304 driver, as its severely lacking in - functionality by comparison (see said patch for details). - - Signed-off-by: Jarod Wilson <jarod@redhat.com> - Signed-off-by: Michael Krufky <mkrufky@kernellabs.com> - Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> - -diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx -index 3a623aa..5c56875 100644 ---- a/Documentation/video4linux/CARDLIST.em28xx -+++ b/Documentation/video4linux/CARDLIST.em28xx -@@ -72,3 +72,4 @@ - 73 -> Reddo DVB-C USB TV Box (em2870) - 74 -> Actionmaster/LinXcel/Digitus VC211A (em2800) - 75 -> Dikom DK300 (em2882) -+ 76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340] -diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c -index 3a4fd85..ffbe544 100644 ---- a/drivers/media/video/em28xx/em28xx-cards.c -+++ b/drivers/media/video/em28xx/em28xx-cards.c -@@ -158,6 +158,22 @@ static struct em28xx_reg_seq evga_indtube_digital[] = { - { -1, -1, -1, -1}, - }; - -+/* -+ * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map: -+ * EM_GPIO_0 - currently unknown -+ * EM_GPIO_1 - LED disable/enable (1 = off, 0 = on) -+ * EM_GPIO_2 - currently unknown -+ * EM_GPIO_3 - currently unknown -+ * EM_GPIO_4 - TDA18271HD/C1 tuner (1 = active, 0 = in reset) -+ * EM_GPIO_5 - LGDT3304 ATSC/QAM demod (1 = active, 0 = in reset) -+ * EM_GPIO_6 - currently unknown -+ * EM_GPIO_7 - currently unknown -+ */ -+static struct em28xx_reg_seq kworld_a340_digital[] = { -+ {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, -+ { -1, -1, -1, -1}, -+}; -+ - /* Pinnacle Hybrid Pro eb1a:2881 */ - static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = { - {EM28XX_R08_GPIO, 0xfd, ~EM_GPIO_4, 10}, -@@ -1667,6 +1683,16 @@ struct em28xx_board em28xx_boards[] = { - .tuner_gpio = reddo_dvb_c_usb_box, - .has_dvb = 1, - }, -+ /* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold -+ * initially as the KWorld PlusTV 340U, then as the UB435-Q. -+ * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */ -+ [EM2870_BOARD_KWORLD_A340] = { -+ .name = "KWorld PlusTV 340U or UB435-Q (ATSC)", -+ .tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */ -+ .has_dvb = 1, -+ .dvb_gpio = kworld_a340_digital, -+ .tuner_gpio = default_tuner_gpio, -+ }, - }; - const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); - -@@ -1788,6 +1814,8 @@ struct usb_device_id em28xx_id_table[] = { - .driver_info = EM2820_BOARD_IODATA_GVMVP_SZ }, - { USB_DEVICE(0xeb1a, 0x50a6), - .driver_info = EM2860_BOARD_GADMEI_UTV330 }, -+ { USB_DEVICE(0x1b80, 0xa340), -+ .driver_info = EM2870_BOARD_KWORLD_A340 }, - { }, - }; - MODULE_DEVICE_TABLE(usb, em28xx_id_table); -diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c -index cf1d8c3..3ac8d30 100644 ---- a/drivers/media/video/em28xx/em28xx-dvb.c -+++ b/drivers/media/video/em28xx/em28xx-dvb.c -@@ -30,11 +30,13 @@ - #include "tuner-simple.h" - - #include "lgdt330x.h" -+#include "lgdt3305.h" - #include "zl10353.h" - #include "s5h1409.h" - #include "mt352.h" - #include "mt352_priv.h" /* FIXME */ - #include "tda1002x.h" -+#include "tda18271.h" - - MODULE_DESCRIPTION("driver for em28xx based DVB cards"); - MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); -@@ -231,6 +233,18 @@ static struct lgdt330x_config em2880_lgdt3303_dev = { - .demod_chip = LGDT3303, - }; - -+static struct lgdt3305_config em2870_lgdt3304_dev = { -+ .i2c_addr = 0x0e, -+ .demod_chip = LGDT3304, -+ .spectral_inversion = 1, -+ .deny_i2c_rptr = 1, -+ .mpeg_mode = LGDT3305_MPEG_PARALLEL, -+ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, -+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, -+ .vsb_if_khz = 3250, -+ .qam_if_khz = 4000, -+}; -+ - static struct zl10353_config em28xx_zl10353_with_xc3028 = { - .demod_address = (0x1e >> 1), - .no_tuner = 1, -@@ -247,6 +261,17 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = { - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK - }; - -+static struct tda18271_std_map kworld_a340_std_map = { -+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 0, -+ .if_lvl = 1, .rfagc_top = 0x37, }, -+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 1, -+ .if_lvl = 1, .rfagc_top = 0x37, }, -+}; -+ -+static struct tda18271_config kworld_a340_config = { -+ .std_map = &kworld_a340_std_map, -+}; -+ - static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = { - .demod_address = (0x1e >> 1), - .no_tuner = 1, -@@ -572,6 +597,14 @@ static int dvb_init(struct em28xx *dev) - } - } - break; -+ case EM2870_BOARD_KWORLD_A340: -+ dvb->frontend = dvb_attach(lgdt3305_attach, -+ &em2870_lgdt3304_dev, -+ &dev->i2c_adap); -+ if (dvb->frontend != NULL) -+ dvb_attach(tda18271_attach, dvb->frontend, 0x60, -+ &dev->i2c_adap, &kworld_a340_config); -+ break; - default: - em28xx_errdev("/2: The frontend of your DVB/ATSC card" - " isn't supported yet\n"); -diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h -index 6216786..1c61a6b 100644 ---- a/drivers/media/video/em28xx/em28xx.h -+++ b/drivers/media/video/em28xx/em28xx.h -@@ -114,6 +114,7 @@ - #define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73 - #define EM2800_BOARD_VC211A 74 - #define EM2882_BOARD_DIKOM_DK300 75 -+#define EM2870_BOARD_KWORLD_A340 76 - - /* Limits minimum and default number of buffers */ - #define EM28XX_MIN_BUF 4 diff --git a/linux-2.6-v4l-dvb-ir-core-memleak-fixes.patch b/linux-2.6-v4l-dvb-ir-core-memleak-fixes.patch deleted file mode 100644 index 59ba20a43..000000000 --- a/linux-2.6-v4l-dvb-ir-core-memleak-fixes.patch +++ /dev/null @@ -1,142 +0,0 @@ - drivers/media/IR/imon.c | 20 +------------------- - drivers/media/IR/mceusb.c | 15 +-------------- - 2 files changed, 2 insertions(+), 33 deletions(-) - -diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c -index 65c125e..c185422 100644 ---- a/drivers/media/IR/imon.c -+++ b/drivers/media/IR/imon.c -@@ -87,7 +87,6 @@ static ssize_t lcd_write(struct file *file, const char *buf, - struct imon_context { - struct device *dev; - struct ir_dev_props *props; -- struct ir_input_dev *ir; - /* Newer devices have two interfaces */ - struct usb_device *usbdev_intf0; - struct usb_device *usbdev_intf1; -@@ -1656,7 +1655,6 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) - { - struct input_dev *idev; - struct ir_dev_props *props; -- struct ir_input_dev *ir; - int ret, i; - - idev = input_allocate_device(); -@@ -1671,12 +1669,6 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) - goto props_alloc_failed; - } - -- ir = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL); -- if (!ir) { -- dev_err(ictx->dev, "remote ir input dev allocation failed\n"); -- goto ir_dev_alloc_failed; -- } -- - snprintf(ictx->name_idev, sizeof(ictx->name_idev), - "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product); - idev->name = ictx->name_idev; -@@ -1706,14 +1698,9 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) - props->change_protocol = imon_ir_change_protocol; - ictx->props = props; - -- ictx->ir = ir; -- memcpy(&ir->dev, ictx->dev, sizeof(struct device)); -- - usb_to_input_id(ictx->usbdev_intf0, &idev->id); - idev->dev.parent = ictx->dev; - -- input_set_drvdata(idev, ir); -- - ret = ir_input_register(idev, RC_MAP_IMON_PAD, props, MOD_NAME); - if (ret < 0) { - dev_err(ictx->dev, "remote input dev register failed\n"); -@@ -1723,8 +1710,6 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) - return idev; - - idev_register_failed: -- kfree(ir); --ir_dev_alloc_failed: - kfree(props); - props_alloc_failed: - input_free_device(idev); -@@ -1944,7 +1929,6 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) - - urb_submit_failed: - ir_input_unregister(ictx->idev); -- input_free_device(ictx->idev); - idev_setup_failed: - find_endpoint_failed: - mutex_unlock(&ictx->lock); -@@ -2014,10 +1998,8 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, - return ictx; - - urb_submit_failed: -- if (ictx->touch) { -+ if (ictx->touch) - input_unregister_device(ictx->touch); -- input_free_device(ictx->touch); -- } - touch_setup_failed: - find_endpoint_failed: - mutex_unlock(&ictx->lock); -diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c -index 78bf7f7..65b0738 100644 ---- a/drivers/media/IR/mceusb.c -+++ b/drivers/media/IR/mceusb.c -@@ -228,7 +228,6 @@ static struct usb_device_id std_tx_mask_list[] = { - /* data structure for each usb transceiver */ - struct mceusb_dev { - /* ir-core bits */ -- struct ir_input_dev *irdev; - struct ir_dev_props *props; - struct ir_raw_event rawir; - -@@ -739,7 +738,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) - - if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { - ir->send_flags = SEND_FLAG_COMPLETE; -- dev_dbg(&ir->irdev->dev, "setup answer received %d bytes\n", -+ dev_dbg(ir->dev, "setup answer received %d bytes\n", - buf_len); - } - -@@ -861,7 +860,6 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) - { - struct input_dev *idev; - struct ir_dev_props *props; -- struct ir_input_dev *irdev; - struct device *dev = ir->dev; - int ret = -ENODEV; - -@@ -878,12 +876,6 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) - goto props_alloc_failed; - } - -- irdev = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL); -- if (!irdev) { -- dev_err(dev, "remote ir input dev allocation failed\n"); -- goto ir_dev_alloc_failed; -- } -- - snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome " - "Infrared Remote Transceiver (%04x:%04x)", - le16_to_cpu(ir->usbdev->descriptor.idVendor), -@@ -902,9 +894,6 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) - props->tx_ir = mceusb_tx_ir; - - ir->props = props; -- ir->irdev = irdev; -- -- input_set_drvdata(idev, irdev); - - ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME); - if (ret < 0) { -@@ -915,8 +904,6 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) - return idev; - - irdev_failed: -- kfree(irdev); --ir_dev_alloc_failed: - kfree(props); - props_alloc_failed: - input_free_device(idev); diff --git a/lirc-staging-2.6.36.patch b/lirc-staging-2.6.36.patch deleted file mode 100644 index 23c80bc0e..000000000 --- a/lirc-staging-2.6.36.patch +++ /dev/null @@ -1,12206 +0,0 @@ - drivers/staging/Kconfig | 2 + - drivers/staging/Makefile | 1 + - drivers/staging/lirc/Kconfig | 111 +++ - drivers/staging/lirc/Makefile | 19 + - drivers/staging/lirc/TODO | 8 + - drivers/staging/lirc/TODO.lirc_i2c | 3 + - drivers/staging/lirc/lirc_bt829.c | 383 +++++++++ - drivers/staging/lirc/lirc_ene0100.c | 646 ++++++++++++++ - drivers/staging/lirc/lirc_ene0100.h | 169 ++++ - drivers/staging/lirc/lirc_i2c.c | 536 ++++++++++++ - drivers/staging/lirc/lirc_igorplugusb.c | 555 ++++++++++++ - drivers/staging/lirc/lirc_imon.c | 1058 +++++++++++++++++++++++ - drivers/staging/lirc/lirc_it87.c | 1022 +++++++++++++++++++++++ - drivers/staging/lirc/lirc_it87.h | 116 +++ - drivers/staging/lirc/lirc_ite8709.c | 542 ++++++++++++ - drivers/staging/lirc/lirc_parallel.c | 705 ++++++++++++++++ - drivers/staging/lirc/lirc_parallel.h | 26 + - drivers/staging/lirc/lirc_sasem.c | 933 +++++++++++++++++++++ - drivers/staging/lirc/lirc_serial.c | 1313 +++++++++++++++++++++++++++++ - drivers/staging/lirc/lirc_sir.c | 1282 ++++++++++++++++++++++++++++ - drivers/staging/lirc/lirc_streamzap.c | 821 ++++++++++++++++++ - drivers/staging/lirc/lirc_ttusbir.c | 396 +++++++++ - drivers/staging/lirc/lirc_zilog.c | 1387 +++++++++++++++++++++++++++++++ - 23 files changed, 12034 insertions(+), 0 deletions(-) - -diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig -index 984a754..9296517 100644 ---- a/drivers/staging/Kconfig -+++ b/drivers/staging/Kconfig -@@ -147,5 +147,7 @@ source "drivers/staging/mrst-touchscreen/Kconfig" - - source "drivers/staging/msm/Kconfig" - -+source "drivers/staging/lirc/Kconfig" -+ - endif # !STAGING_EXCLUDE_BUILD - endif # STAGING -diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile -index 9fa2513..6c5b523 100644 ---- a/drivers/staging/Makefile -+++ b/drivers/staging/Makefile -@@ -8,6 +8,7 @@ obj-$(CONFIG_SLICOSS) += slicoss/ - obj-$(CONFIG_VIDEO_GO7007) += go7007/ - obj-$(CONFIG_VIDEO_CX25821) += cx25821/ - obj-$(CONFIG_VIDEO_TM6000) += tm6000/ -+obj-$(CONFIG_LIRC_STAGING) += lirc/ - obj-$(CONFIG_USB_IP_COMMON) += usbip/ - obj-$(CONFIG_W35UND) += winbond/ - obj-$(CONFIG_PRISM2_USB) += wlan-ng/ -diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig -new file mode 100644 -index 0000000..ab30a09 ---- /dev/null -+++ b/drivers/staging/lirc/Kconfig -@@ -0,0 +1,111 @@ -+# -+# LIRC driver(s) configuration -+# -+menuconfig LIRC_STAGING -+ bool "Linux Infrared Remote Control IR receiver/transmitter drivers" -+ depends on LIRC -+ help -+ Say Y here, and all supported Linux Infrared Remote Control IR and -+ RF receiver and transmitter drivers will be displayed. When paired -+ with a remote control and the lirc daemon, the receiver drivers -+ allow control of your Linux system via remote control. -+ -+if LIRC_STAGING -+ -+config LIRC_BT829 -+ tristate "BT829 based hardware" -+ depends on LIRC_STAGING && PCI -+ help -+ Driver for the IR interface on BT829-based hardware -+ -+config LIRC_ENE0100 -+ tristate "ENE KB3924/ENE0100 CIR Port Reciever" -+ depends on LIRC_STAGING && PNP -+ help -+ This is a driver for CIR port handled by ENE KB3924 embedded -+ controller found on some notebooks. -+ It appears on PNP list as ENE0100. -+ -+config LIRC_I2C -+ tristate "I2C Based IR Receivers" -+ depends on LIRC_STAGING && I2C -+ help -+ Driver for I2C-based IR receivers, such as those commonly -+ found onboard Hauppauge PVR-150/250/350 video capture cards -+ -+config LIRC_IGORPLUGUSB -+ tristate "Igor Cesko's USB IR Receiver" -+ depends on LIRC_STAGING && USB -+ help -+ Driver for Igor Cesko's USB IR Receiver -+ -+config LIRC_IMON -+ tristate "Legacy SoundGraph iMON Receiver and Display" -+ depends on LIRC_STAGING && USB -+ help -+ Driver for the original SoundGraph iMON IR Receiver and Display -+ -+ Current generation iMON devices use the input layer imon driver. -+ -+config LIRC_IT87 -+ tristate "ITE IT87XX CIR Port Receiver" -+ depends on LIRC_STAGING && PNP -+ help -+ Driver for the ITE IT87xx IR Receiver -+ -+config LIRC_ITE8709 -+ tristate "ITE8709 CIR Port Receiver" -+ depends on LIRC_STAGING && PNP -+ help -+ Driver for the ITE8709 IR Receiver -+ -+config LIRC_PARALLEL -+ tristate "Homebrew Parallel Port Receiver" -+ depends on LIRC_STAGING && PARPORT && !SMP -+ help -+ Driver for Homebrew Parallel Port Receivers -+ -+config LIRC_SASEM -+ tristate "Sasem USB IR Remote" -+ depends on LIRC_STAGING && USB -+ help -+ Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module -+ -+config LIRC_SERIAL -+ tristate "Homebrew Serial Port Receiver" -+ depends on LIRC_STAGING -+ help -+ Driver for Homebrew Serial Port Receivers -+ -+config LIRC_SERIAL_TRANSMITTER -+ bool "Serial Port Transmitter" -+ default y -+ depends on LIRC_SERIAL -+ help -+ Serial Port Transmitter support -+ -+config LIRC_SIR -+ tristate "Built-in SIR IrDA port" -+ depends on LIRC_STAGING -+ help -+ Driver for the SIR IrDA port -+ -+config LIRC_STREAMZAP -+ tristate "Streamzap PC Receiver" -+ depends on LIRC_STAGING && USB -+ help -+ Driver for the Streamzap PC Receiver -+ -+config LIRC_TTUSBIR -+ tristate "Technotrend USB IR Receiver" -+ depends on LIRC_STAGING && USB -+ help -+ Driver for the Technotrend USB IR Receiver -+ -+config LIRC_ZILOG -+ tristate "Zilog/Hauppauge IR Transmitter" -+ depends on LIRC_STAGING && I2C -+ help -+ Driver for the Zilog/Hauppauge IR Transmitter, found on -+ PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards -+endif -diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/lirc/Makefile -new file mode 100644 -index 0000000..a019182 ---- /dev/null -+++ b/drivers/staging/lirc/Makefile -@@ -0,0 +1,19 @@ -+# Makefile for the lirc drivers. -+# -+ -+# Each configuration option enables a list of files. -+ -+obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o -+obj-$(CONFIG_LIRC_ENE0100) += lirc_ene0100.o -+obj-$(CONFIG_LIRC_I2C) += lirc_i2c.o -+obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o -+obj-$(CONFIG_LIRC_IMON) += lirc_imon.o -+obj-$(CONFIG_LIRC_IT87) += lirc_it87.o -+obj-$(CONFIG_LIRC_ITE8709) += lirc_ite8709.o -+obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o -+obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o -+obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o -+obj-$(CONFIG_LIRC_SIR) += lirc_sir.o -+obj-$(CONFIG_LIRC_STREAMZAP) += lirc_streamzap.o -+obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o -+obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o -diff --git a/drivers/staging/lirc/TODO b/drivers/staging/lirc/TODO -new file mode 100644 -index 0000000..b6cb593 ---- /dev/null -+++ b/drivers/staging/lirc/TODO -@@ -0,0 +1,8 @@ -+- All drivers should either be ported to ir-core, or dropped entirely -+ (see drivers/media/IR/mceusb.c vs. lirc_mceusb.c in lirc cvs for an -+ example of a previously completed port). -+ -+Please send patches to: -+Jarod Wilson <jarod@wilsonet.com> -+Greg Kroah-Hartman <greg@kroah.com> -+ -diff --git a/drivers/staging/lirc/TODO.lirc_i2c b/drivers/staging/lirc/TODO.lirc_i2c -new file mode 100644 -index 0000000..1f0a6ff ---- /dev/null -+++ b/drivers/staging/lirc/TODO.lirc_i2c -@@ -0,0 +1,3 @@ -+lirc_i2c provides support for some drivers that have already a RC -+driver under drivers/media/video. It should be integrated into those -+drivers, in special with drivers/media/video/ir-kbd-i2c.c. -diff --git a/drivers/staging/lirc/lirc_bt829.c b/drivers/staging/lirc/lirc_bt829.c -new file mode 100644 -index 0000000..3388102 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_bt829.c -@@ -0,0 +1,383 @@ -+/* -+ * Remote control driver for the TV-card based on bt829 -+ * -+ * by Leonid Froenchenko <lfroen@galileo.co.il> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+*/ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/threads.h> -+#include <linux/sched.h> -+#include <linux/ioport.h> -+#include <linux/pci.h> -+#include <linux/delay.h> -+ -+#include <media/lirc_dev.h> -+ -+static int poll_main(void); -+static int atir_init_start(void); -+ -+static void write_index(unsigned char index, unsigned int value); -+static unsigned int read_index(unsigned char index); -+ -+static void do_i2c_start(void); -+static void do_i2c_stop(void); -+ -+static void seems_wr_byte(unsigned char al); -+static unsigned char seems_rd_byte(void); -+ -+static unsigned int read_index(unsigned char al); -+static void write_index(unsigned char ah, unsigned int edx); -+ -+static void cycle_delay(int cycle); -+ -+static void do_set_bits(unsigned char bl); -+static unsigned char do_get_bits(void); -+ -+#define DATA_PCI_OFF 0x7FFC00 -+#define WAIT_CYCLE 20 -+ -+#define DRIVER_NAME "lirc_bt829" -+ -+static int debug; -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG DRIVER_NAME ": "fmt, ## args); \ -+ } while (0) -+ -+static int atir_minor; -+static unsigned long pci_addr_phys; -+static unsigned char *pci_addr_lin; -+ -+static struct lirc_driver atir_driver; -+ -+static struct pci_dev *do_pci_probe(void) -+{ -+ struct pci_dev *my_dev; -+ my_dev = pci_get_device(PCI_VENDOR_ID_ATI, -+ PCI_DEVICE_ID_ATI_264VT, NULL); -+ if (my_dev) { -+ printk(KERN_ERR DRIVER_NAME ": Using device: %s\n", -+ pci_name(my_dev)); -+ pci_addr_phys = 0; -+ if (my_dev->resource[0].flags & IORESOURCE_MEM) { -+ pci_addr_phys = my_dev->resource[0].start; -+ printk(KERN_INFO DRIVER_NAME ": memory at 0x%08X\n", -+ (unsigned int)pci_addr_phys); -+ } -+ if (pci_addr_phys == 0) { -+ printk(KERN_ERR DRIVER_NAME ": no memory resource ?\n"); -+ return NULL; -+ } -+ } else { -+ printk(KERN_ERR DRIVER_NAME ": pci_probe failed\n"); -+ return NULL; -+ } -+ return my_dev; -+} -+ -+static int atir_add_to_buf(void *data, struct lirc_buffer *buf) -+{ -+ unsigned char key; -+ int status; -+ status = poll_main(); -+ key = (status >> 8) & 0xFF; -+ if (status & 0xFF) { -+ dprintk("reading key %02X\n", key); -+ lirc_buffer_write(buf, &key); -+ return 0; -+ } -+ return -ENODATA; -+} -+ -+static int atir_set_use_inc(void *data) -+{ -+ dprintk("driver is opened\n"); -+ return 0; -+} -+ -+static void atir_set_use_dec(void *data) -+{ -+ dprintk("driver is closed\n"); -+} -+ -+int init_module(void) -+{ -+ struct pci_dev *pdev; -+ -+ pdev = do_pci_probe(); -+ if (pdev == NULL) -+ return 1; -+ -+ if (!atir_init_start()) -+ return 1; -+ -+ strcpy(atir_driver.name, "ATIR"); -+ atir_driver.minor = -1; -+ atir_driver.code_length = 8; -+ atir_driver.sample_rate = 10; -+ atir_driver.data = 0; -+ atir_driver.add_to_buf = atir_add_to_buf; -+ atir_driver.set_use_inc = atir_set_use_inc; -+ atir_driver.set_use_dec = atir_set_use_dec; -+ atir_driver.dev = &pdev->dev; -+ atir_driver.owner = THIS_MODULE; -+ -+ atir_minor = lirc_register_driver(&atir_driver); -+ if (atir_minor < 0) { -+ printk(KERN_ERR DRIVER_NAME ": failed to register driver!\n"); -+ return atir_minor; -+ } -+ dprintk("driver is registered on minor %d\n", atir_minor); -+ -+ return 0; -+} -+ -+ -+void cleanup_module(void) -+{ -+ lirc_unregister_driver(atir_minor); -+} -+ -+ -+static int atir_init_start(void) -+{ -+ pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400); -+ if (pci_addr_lin == 0) { -+ printk(KERN_INFO DRIVER_NAME ": pci mem must be mapped\n"); -+ return 0; -+ } -+ return 1; -+} -+ -+static void cycle_delay(int cycle) -+{ -+ udelay(WAIT_CYCLE*cycle); -+} -+ -+ -+static int poll_main() -+{ -+ unsigned char status_high, status_low; -+ -+ do_i2c_start(); -+ -+ seems_wr_byte(0xAA); -+ seems_wr_byte(0x01); -+ -+ do_i2c_start(); -+ -+ seems_wr_byte(0xAB); -+ -+ status_low = seems_rd_byte(); -+ status_high = seems_rd_byte(); -+ -+ do_i2c_stop(); -+ -+ return (status_high << 8) | status_low; -+} -+ -+static void do_i2c_start(void) -+{ -+ do_set_bits(3); -+ cycle_delay(4); -+ -+ do_set_bits(1); -+ cycle_delay(7); -+ -+ do_set_bits(0); -+ cycle_delay(2); -+} -+ -+static void do_i2c_stop(void) -+{ -+ unsigned char bits; -+ bits = do_get_bits() & 0xFD; -+ do_set_bits(bits); -+ cycle_delay(1); -+ -+ bits |= 1; -+ do_set_bits(bits); -+ cycle_delay(2); -+ -+ bits |= 2; -+ do_set_bits(bits); -+ bits = 3; -+ do_set_bits(bits); -+ cycle_delay(2); -+} -+ -+static void seems_wr_byte(unsigned char value) -+{ -+ int i; -+ unsigned char reg; -+ -+ reg = do_get_bits(); -+ for (i = 0; i < 8; i++) { -+ if (value & 0x80) -+ reg |= 0x02; -+ else -+ reg &= 0xFD; -+ -+ do_set_bits(reg); -+ cycle_delay(1); -+ -+ reg |= 1; -+ do_set_bits(reg); -+ cycle_delay(1); -+ -+ reg &= 0xFE; -+ do_set_bits(reg); -+ cycle_delay(1); -+ value <<= 1; -+ } -+ cycle_delay(2); -+ -+ reg |= 2; -+ do_set_bits(reg); -+ -+ reg |= 1; -+ do_set_bits(reg); -+ -+ cycle_delay(1); -+ do_get_bits(); -+ -+ reg &= 0xFE; -+ do_set_bits(reg); -+ cycle_delay(3); -+} -+ -+static unsigned char seems_rd_byte(void) -+{ -+ int i; -+ int rd_byte; -+ unsigned char bits_2, bits_1; -+ -+ bits_1 = do_get_bits() | 2; -+ do_set_bits(bits_1); -+ -+ rd_byte = 0; -+ for (i = 0; i < 8; i++) { -+ bits_1 &= 0xFE; -+ do_set_bits(bits_1); -+ cycle_delay(2); -+ -+ bits_1 |= 1; -+ do_set_bits(bits_1); -+ cycle_delay(1); -+ -+ bits_2 = do_get_bits(); -+ if (bits_2 & 2) -+ rd_byte |= 1; -+ -+ rd_byte <<= 1; -+ } -+ -+ bits_1 = 0; -+ if (bits_2 == 0) -+ bits_1 |= 2; -+ -+ do_set_bits(bits_1); -+ cycle_delay(2); -+ -+ bits_1 |= 1; -+ do_set_bits(bits_1); -+ cycle_delay(3); -+ -+ bits_1 &= 0xFE; -+ do_set_bits(bits_1); -+ cycle_delay(2); -+ -+ rd_byte >>= 1; -+ rd_byte &= 0xFF; -+ return rd_byte; -+} -+ -+static void do_set_bits(unsigned char new_bits) -+{ -+ int reg_val; -+ reg_val = read_index(0x34); -+ if (new_bits & 2) { -+ reg_val &= 0xFFFFFFDF; -+ reg_val |= 1; -+ } else { -+ reg_val &= 0xFFFFFFFE; -+ reg_val |= 0x20; -+ } -+ reg_val |= 0x10; -+ write_index(0x34, reg_val); -+ -+ reg_val = read_index(0x31); -+ if (new_bits & 1) -+ reg_val |= 0x1000000; -+ else -+ reg_val &= 0xFEFFFFFF; -+ -+ reg_val |= 0x8000000; -+ write_index(0x31, reg_val); -+} -+ -+static unsigned char do_get_bits(void) -+{ -+ unsigned char bits; -+ int reg_val; -+ -+ reg_val = read_index(0x34); -+ reg_val |= 0x10; -+ reg_val &= 0xFFFFFFDF; -+ write_index(0x34, reg_val); -+ -+ reg_val = read_index(0x34); -+ bits = 0; -+ if (reg_val & 8) -+ bits |= 2; -+ else -+ bits &= 0xFD; -+ -+ reg_val = read_index(0x31); -+ if (reg_val & 0x1000000) -+ bits |= 1; -+ else -+ bits &= 0xFE; -+ -+ return bits; -+} -+ -+static unsigned int read_index(unsigned char index) -+{ -+ unsigned char *addr; -+ unsigned int value; -+ /* addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */ -+ addr = pci_addr_lin + ((index & 0xFF) << 2); -+ value = readl(addr); -+ return value; -+} -+ -+static void write_index(unsigned char index, unsigned int reg_val) -+{ -+ unsigned char *addr; -+ addr = pci_addr_lin + ((index & 0xFF) << 2); -+ writel(reg_val, addr); -+} -+ -+MODULE_AUTHOR("Froenchenko Leonid"); -+MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards"); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug enabled or not"); -diff --git a/drivers/staging/lirc/lirc_ene0100.c b/drivers/staging/lirc/lirc_ene0100.c -new file mode 100644 -index 0000000..a152c52 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_ene0100.c -@@ -0,0 +1,646 @@ -+/* -+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) -+ * -+ * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@gmail.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -+ * USA -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/pnp.h> -+#include <linux/io.h> -+#include <linux/interrupt.h> -+#include <linux/sched.h> -+#include "lirc_ene0100.h" -+ -+static int sample_period = 75; -+static int enable_idle = 1; -+static int enable_learning; -+ -+static void ene_set_idle(struct ene_device *dev, int idle); -+static void ene_set_inputs(struct ene_device *dev, int enable); -+ -+/* read a hardware register */ -+static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg) -+{ -+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); -+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); -+ return inb(dev->hw_io + ENE_IO); -+} -+ -+/* write a hardware register */ -+static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value) -+{ -+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); -+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); -+ outb(value, dev->hw_io + ENE_IO); -+} -+ -+/* change specific bits in hardware register */ -+static void ene_hw_write_reg_mask(struct ene_device *dev, -+ u16 reg, u8 value, u8 mask) -+{ -+ u8 regvalue; -+ -+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); -+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); -+ -+ regvalue = inb(dev->hw_io + ENE_IO) & ~mask; -+ regvalue |= (value & mask); -+ outb(regvalue, dev->hw_io + ENE_IO); -+} -+ -+/* read irq status and ack it */ -+static int ene_hw_irq_status(struct ene_device *dev, int *buffer_pointer) -+{ -+ u8 irq_status; -+ u8 fw_flags1, fw_flags2; -+ -+ fw_flags2 = ene_hw_read_reg(dev, ENE_FW2); -+ -+ if (buffer_pointer) -+ *buffer_pointer = 4 * (fw_flags2 & ENE_FW2_BUF_HIGH); -+ -+ if (dev->hw_revision < ENE_HW_C) { -+ irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS); -+ -+ if (!(irq_status & ENEB_IRQ_STATUS_IR)) -+ return 0; -+ ene_hw_write_reg(dev, ENEB_IRQ_STATUS, -+ irq_status & ~ENEB_IRQ_STATUS_IR); -+ -+ /* rev B support only recieving */ -+ return ENE_IRQ_RX; -+ } -+ -+ irq_status = ene_hw_read_reg(dev, ENEC_IRQ); -+ -+ if (!(irq_status & ENEC_IRQ_STATUS)) -+ return 0; -+ -+ /* original driver does that twice - a workaround ? */ -+ ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); -+ ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); -+ -+ /* clear unknown flag in F8F9 */ -+ if (fw_flags2 & ENE_FW2_IRQ_CLR) -+ ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR); -+ -+ /* check if this is a TX interrupt */ -+ fw_flags1 = ene_hw_read_reg(dev, ENE_FW1); -+ -+ if (fw_flags1 & ENE_FW1_TXIRQ) { -+ ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ); -+ return ENE_IRQ_TX; -+ } else -+ return ENE_IRQ_RX; -+} -+ -+static int ene_hw_detect(struct ene_device *dev) -+{ -+ u8 chip_major, chip_minor; -+ u8 hw_revision, old_ver; -+ u8 tmp; -+ u8 fw_capabilities; -+ -+ tmp = ene_hw_read_reg(dev, ENE_HW_UNK); -+ ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR); -+ -+ chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR); -+ chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR); -+ -+ ene_hw_write_reg(dev, ENE_HW_UNK, tmp); -+ hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION); -+ old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD); -+ -+ if (hw_revision == 0xFF) { -+ -+ ene_printk(KERN_WARNING, "device seems to be disabled\n"); -+ ene_printk(KERN_WARNING, -+ "send a mail to lirc-list@lists.sourceforge.net\n"); -+ ene_printk(KERN_WARNING, "please attach output of acpidump\n"); -+ -+ return -ENODEV; -+ } -+ -+ if (chip_major == 0x33) { -+ ene_printk(KERN_WARNING, "chips 0x33xx aren't supported yet\n"); -+ return -ENODEV; -+ } -+ -+ if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { -+ dev->hw_revision = ENE_HW_C; -+ ene_printk(KERN_WARNING, -+ "KB3926C detected, driver support is not complete!\n"); -+ -+ } else if (old_ver == 0x24 && hw_revision == 0xC0) { -+ dev->hw_revision = ENE_HW_B; -+ ene_printk(KERN_NOTICE, "KB3926B detected\n"); -+ } else { -+ dev->hw_revision = ENE_HW_D; -+ ene_printk(KERN_WARNING, -+ "unknown ENE chip detected, assuming KB3926D\n"); -+ ene_printk(KERN_WARNING, "driver support incomplete"); -+ -+ } -+ -+ ene_printk(KERN_DEBUG, "chip is 0x%02x%02x - 0x%02x, 0x%02x\n", -+ chip_major, chip_minor, old_ver, hw_revision); -+ -+ -+ /* detect features hardware supports */ -+ -+ if (dev->hw_revision < ENE_HW_C) -+ return 0; -+ -+ fw_capabilities = ene_hw_read_reg(dev, ENE_FW2); -+ -+ dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN; -+ dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING; -+ -+ dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable && -+ fw_capabilities & ENE_FW2_FAN_AS_NRML_IN; -+ -+ ene_printk(KERN_NOTICE, "hardware features:\n"); -+ ene_printk(KERN_NOTICE, -+ "learning and tx %s, gpio40_learn %s, fan_in %s\n", -+ dev->hw_learning_and_tx_capable ? "on" : "off", -+ dev->hw_gpio40_learning ? "on" : "off", -+ dev->hw_fan_as_normal_input ? "on" : "off"); -+ -+ if (!dev->hw_learning_and_tx_capable && enable_learning) -+ enable_learning = 0; -+ -+ if (dev->hw_learning_and_tx_capable) { -+ ene_printk(KERN_WARNING, -+ "Device supports transmitting, but the driver doesn't\n"); -+ ene_printk(KERN_WARNING, -+ "due to lack of hardware to test against.\n"); -+ ene_printk(KERN_WARNING, -+ "Send a mail to: lirc-list@lists.sourceforge.net\n"); -+ } -+ return 0; -+} -+ -+/* hardware initialization */ -+static int ene_hw_init(void *data) -+{ -+ u8 reg_value; -+ struct ene_device *dev = (struct ene_device *)data; -+ dev->in_use = 1; -+ -+ if (dev->hw_revision < ENE_HW_C) { -+ ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1); -+ ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01); -+ } else { -+ reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0; -+ reg_value |= ENEC_IRQ_UNK_EN; -+ reg_value &= ~ENEC_IRQ_STATUS; -+ reg_value |= (dev->irq & ENEC_IRQ_MASK); -+ ene_hw_write_reg(dev, ENEC_IRQ, reg_value); -+ ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63); -+ } -+ -+ ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00); -+ ene_set_inputs(dev, enable_learning); -+ -+ /* set sampling period */ -+ ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period); -+ -+ /* ack any pending irqs - just in case */ -+ ene_hw_irq_status(dev, NULL); -+ -+ /* enter idle mode */ -+ ene_set_idle(dev, 1); -+ -+ /* enable firmware bits */ -+ ene_hw_write_reg_mask(dev, ENE_FW1, -+ ENE_FW1_ENABLE | ENE_FW1_IRQ, -+ ENE_FW1_ENABLE | ENE_FW1_IRQ); -+ /* clear stats */ -+ dev->sample = 0; -+ return 0; -+} -+ -+/* this enables gpio40 signal, used if connected to wide band input*/ -+static void ene_enable_gpio40(struct ene_device *dev, int enable) -+{ -+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, enable ? -+ 0 : ENE_CIR_CONF2_GPIO40DIS, -+ ENE_CIR_CONF2_GPIO40DIS); -+} -+ -+/* this enables the classic sampler */ -+static void ene_enable_normal_recieve(struct ene_device *dev, int enable) -+{ -+ ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_ADC_ON : 0); -+} -+ -+/* this enables recieve via fan input */ -+static void ene_enable_fan_recieve(struct ene_device *dev, int enable) -+{ -+ if (!enable) -+ ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0); -+ else { -+ ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN); -+ ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN); -+ } -+ dev->fan_input_inuse = enable; -+} -+ -+/* determine which input to use*/ -+static void ene_set_inputs(struct ene_device *dev, int learning_enable) -+{ -+ ene_enable_normal_recieve(dev, 1); -+ -+ /* old hardware doesn't support learning mode for sure */ -+ if (dev->hw_revision <= ENE_HW_B) -+ return; -+ -+ /* reciever not learning capable, still set gpio40 correctly */ -+ if (!dev->hw_learning_and_tx_capable) { -+ ene_enable_gpio40(dev, !dev->hw_gpio40_learning); -+ return; -+ } -+ -+ /* enable learning mode */ -+ if (learning_enable) { -+ ene_enable_gpio40(dev, dev->hw_gpio40_learning); -+ -+ /* fan input is not used for learning */ -+ if (dev->hw_fan_as_normal_input) -+ ene_enable_fan_recieve(dev, 0); -+ -+ /* disable learning mode */ -+ } else { -+ if (dev->hw_fan_as_normal_input) { -+ ene_enable_fan_recieve(dev, 1); -+ ene_enable_normal_recieve(dev, 0); -+ } else -+ ene_enable_gpio40(dev, !dev->hw_gpio40_learning); -+ } -+ -+ /* set few additional settings for this mode */ -+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_enable ? -+ ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1); -+ -+ ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_enable ? -+ ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2); -+} -+ -+/* deinitialization */ -+static void ene_hw_deinit(void *data) -+{ -+ struct ene_device *dev = (struct ene_device *)data; -+ -+ /* disable samplers */ -+ ene_enable_normal_recieve(dev, 0); -+ -+ if (dev->hw_fan_as_normal_input) -+ ene_enable_fan_recieve(dev, 0); -+ -+ /* disable hardware IRQ and firmware flag */ -+ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ); -+ -+ ene_set_idle(dev, 1); -+ dev->in_use = 0; -+} -+ -+/* sends current sample to userspace */ -+static void send_sample(struct ene_device *dev) -+{ -+ int value = abs(dev->sample) & PULSE_MASK; -+ -+ if (dev->sample > 0) -+ value |= PULSE_BIT; -+ -+ if (!lirc_buffer_full(dev->lirc_driver->rbuf)) { -+ lirc_buffer_write(dev->lirc_driver->rbuf, (void *)&value); -+ wake_up(&dev->lirc_driver->rbuf->wait_poll); -+ } -+ dev->sample = 0; -+} -+ -+/* this updates current sample */ -+static void update_sample(struct ene_device *dev, int sample) -+{ -+ if (!dev->sample) -+ dev->sample = sample; -+ else if (same_sign(dev->sample, sample)) -+ dev->sample += sample; -+ else { -+ send_sample(dev); -+ dev->sample = sample; -+ } -+} -+ -+/* enable or disable idle mode */ -+static void ene_set_idle(struct ene_device *dev, int idle) -+{ -+ struct timeval now; -+ int disable = idle && enable_idle && (dev->hw_revision < ENE_HW_C); -+ -+ ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD, -+ disable ? 0 : ENE_CIR_SAMPLE_OVERFLOW, -+ ENE_CIR_SAMPLE_OVERFLOW); -+ dev->idle = idle; -+ -+ /* remember when we have entered the idle mode */ -+ if (idle) { -+ do_gettimeofday(&dev->gap_start); -+ return; -+ } -+ -+ /* send the gap between keypresses now */ -+ do_gettimeofday(&now); -+ -+ if (now.tv_sec - dev->gap_start.tv_sec > 16) -+ dev->sample = space(PULSE_MASK); -+ else -+ dev->sample = dev->sample + -+ space(1000000ull * (now.tv_sec - dev->gap_start.tv_sec)) -+ + space(now.tv_usec - dev->gap_start.tv_usec); -+ -+ if (abs(dev->sample) > PULSE_MASK) -+ dev->sample = space(PULSE_MASK); -+ send_sample(dev); -+} -+ -+/* interrupt handler */ -+static irqreturn_t ene_hw_irq(int irq, void *data) -+{ -+ u16 hw_value; -+ int i, hw_sample; -+ int space; -+ int buffer_pointer; -+ int irq_status; -+ -+ struct ene_device *dev = (struct ene_device *)data; -+ irq_status = ene_hw_irq_status(dev, &buffer_pointer); -+ -+ if (!irq_status) -+ return IRQ_NONE; -+ -+ /* TODO: only RX for now */ -+ if (irq_status == ENE_IRQ_TX) -+ return IRQ_HANDLED; -+ -+ for (i = 0; i < ENE_SAMPLES_SIZE; i++) { -+ -+ hw_value = ene_hw_read_reg(dev, -+ ENE_SAMPLE_BUFFER + buffer_pointer + i); -+ -+ if (dev->fan_input_inuse) { -+ /* read high part of the sample */ -+ hw_value |= ene_hw_read_reg(dev, -+ ENE_SAMPLE_BUFFER_FAN + buffer_pointer + i) << 8; -+ -+ /* test for _space_ bit */ -+ space = !(hw_value & ENE_FAN_SMPL_PULS_MSK); -+ -+ /* clear space bit, and other unused bits */ -+ hw_value &= ENE_FAN_VALUE_MASK; -+ hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN; -+ -+ } else { -+ space = hw_value & ENE_SAMPLE_SPC_MASK; -+ hw_value &= ENE_SAMPLE_VALUE_MASK; -+ hw_sample = hw_value * sample_period; -+ } -+ -+ /* no more data */ -+ if (!(hw_value)) -+ break; -+ -+ if (space) -+ hw_sample *= -1; -+ -+ /* overflow sample recieved, handle it */ -+ -+ if (!dev->fan_input_inuse && hw_value == ENE_SAMPLE_OVERFLOW) { -+ -+ if (dev->idle) -+ continue; -+ -+ if (dev->sample > 0 || abs(dev->sample) <= ENE_MAXGAP) -+ update_sample(dev, hw_sample); -+ else -+ ene_set_idle(dev, 1); -+ -+ continue; -+ } -+ -+ /* normal first sample recieved */ -+ if (!dev->fan_input_inuse && dev->idle) { -+ ene_set_idle(dev, 0); -+ -+ /* discard first recieved value, its random -+ since its the time signal was off before -+ first pulse if idle mode is enabled, HW -+ does that for us */ -+ -+ if (!enable_idle) -+ continue; -+ } -+ update_sample(dev, hw_sample); -+ send_sample(dev); -+ } -+ return IRQ_HANDLED; -+} -+ -+static int ene_probe(struct pnp_dev *pnp_dev, -+ const struct pnp_device_id *dev_id) -+{ -+ struct ene_device *dev; -+ struct lirc_driver *lirc_driver; -+ int error = -ENOMEM; -+ -+ dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); -+ -+ if (!dev) -+ goto err1; -+ -+ dev->pnp_dev = pnp_dev; -+ pnp_set_drvdata(pnp_dev, dev); -+ -+ -+ /* prepare lirc interface */ -+ error = -ENOMEM; -+ lirc_driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ -+ if (!lirc_driver) -+ goto err2; -+ -+ dev->lirc_driver = lirc_driver; -+ -+ strcpy(lirc_driver->name, ENE_DRIVER_NAME); -+ lirc_driver->minor = -1; -+ lirc_driver->code_length = sizeof(int) * 8; -+ lirc_driver->features = LIRC_CAN_REC_MODE2; -+ lirc_driver->data = dev; -+ lirc_driver->set_use_inc = ene_hw_init; -+ lirc_driver->set_use_dec = ene_hw_deinit; -+ lirc_driver->dev = &pnp_dev->dev; -+ lirc_driver->owner = THIS_MODULE; -+ -+ lirc_driver->rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ -+ if (!lirc_driver->rbuf) -+ goto err3; -+ -+ if (lirc_buffer_init(lirc_driver->rbuf, sizeof(int), sizeof(int) * 256)) -+ goto err4; -+ -+ error = -ENODEV; -+ if (lirc_register_driver(lirc_driver)) -+ goto err5; -+ -+ /* validate resources */ -+ if (!pnp_port_valid(pnp_dev, 0) || -+ pnp_port_len(pnp_dev, 0) < ENE_MAX_IO) -+ goto err6; -+ -+ if (!pnp_irq_valid(pnp_dev, 0)) -+ goto err6; -+ -+ dev->hw_io = pnp_port_start(pnp_dev, 0); -+ dev->irq = pnp_irq(pnp_dev, 0); -+ -+ /* claim the resources */ -+ error = -EBUSY; -+ if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME)) -+ goto err6; -+ -+ if (request_irq(dev->irq, ene_hw_irq, -+ IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) -+ goto err7; -+ -+ /* detect hardware version and features */ -+ error = ene_hw_detect(dev); -+ if (error) -+ goto err8; -+ -+ ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n"); -+ return 0; -+ -+err8: -+ free_irq(dev->irq, dev); -+err7: -+ release_region(dev->hw_io, ENE_MAX_IO); -+err6: -+ lirc_unregister_driver(lirc_driver->minor); -+err5: -+ lirc_buffer_free(lirc_driver->rbuf); -+err4: -+ kfree(lirc_driver->rbuf); -+err3: -+ kfree(lirc_driver); -+err2: -+ kfree(dev); -+err1: -+ return error; -+} -+ -+static void ene_remove(struct pnp_dev *pnp_dev) -+{ -+ struct ene_device *dev = pnp_get_drvdata(pnp_dev); -+ ene_hw_deinit(dev); -+ free_irq(dev->irq, dev); -+ release_region(dev->hw_io, ENE_MAX_IO); -+ lirc_unregister_driver(dev->lirc_driver->minor); -+ lirc_buffer_free(dev->lirc_driver->rbuf); -+ kfree(dev->lirc_driver); -+ kfree(dev); -+} -+ -+#ifdef CONFIG_PM -+ -+/* TODO: make 'wake on IR' configurable and add .shutdown */ -+/* currently impossible due to lack of kernel support */ -+ -+static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state) -+{ -+ struct ene_device *dev = pnp_get_drvdata(pnp_dev); -+ ene_hw_write_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, ENE_FW1_WAKE); -+ return 0; -+} -+ -+static int ene_resume(struct pnp_dev *pnp_dev) -+{ -+ struct ene_device *dev = pnp_get_drvdata(pnp_dev); -+ if (dev->in_use) -+ ene_hw_init(dev); -+ -+ ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_WAKE); -+ return 0; -+} -+ -+#endif -+ -+static const struct pnp_device_id ene_ids[] = { -+ {.id = "ENE0100",}, -+ {}, -+}; -+ -+static struct pnp_driver ene_driver = { -+ .name = ENE_DRIVER_NAME, -+ .id_table = ene_ids, -+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, -+ -+ .probe = ene_probe, -+ .remove = __devexit_p(ene_remove), -+ -+#ifdef CONFIG_PM -+ .suspend = ene_suspend, -+ .resume = ene_resume, -+#endif -+}; -+ -+static int __init ene_init(void) -+{ -+ if (sample_period < 5) { -+ ene_printk(KERN_ERR, "sample period must be at\n"); -+ ene_printk(KERN_ERR, "least 5 us, (at least 30 recommended)\n"); -+ return -EINVAL; -+ } -+ return pnp_register_driver(&ene_driver); -+} -+ -+static void ene_exit(void) -+{ -+ pnp_unregister_driver(&ene_driver); -+} -+ -+module_param(sample_period, int, S_IRUGO); -+MODULE_PARM_DESC(sample_period, "Hardware sample period (75 us default)"); -+ -+module_param(enable_idle, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(enable_idle, -+ "Enables turning off signal sampling after long inactivity time; " -+ "if disabled might help detecting input signal (default: enabled)"); -+ -+module_param(enable_learning, bool, S_IRUGO); -+MODULE_PARM_DESC(enable_learning, "Use wide band (learning) reciever"); -+ -+MODULE_DEVICE_TABLE(pnp, ene_ids); -+MODULE_DESCRIPTION -+ ("LIRC driver for KB3926B/KB3926C/KB3926D (aka ENE0100) CIR port"); -+MODULE_AUTHOR("Maxim Levitsky"); -+MODULE_LICENSE("GPL"); -+ -+module_init(ene_init); -+module_exit(ene_exit); -diff --git a/drivers/staging/lirc/lirc_ene0100.h b/drivers/staging/lirc/lirc_ene0100.h -new file mode 100644 -index 0000000..776b693 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_ene0100.h -@@ -0,0 +1,169 @@ -+/* -+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) -+ * -+ * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@gmail.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -+ * USA -+ */ -+ -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+ -+/* hardware address */ -+#define ENE_STATUS 0 /* hardware status - unused */ -+#define ENE_ADDR_HI 1 /* hi byte of register address */ -+#define ENE_ADDR_LO 2 /* low byte of register address */ -+#define ENE_IO 3 /* read/write window */ -+#define ENE_MAX_IO 4 -+ -+/* 8 bytes of samples, divided in 2 halfs*/ -+#define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */ -+#define ENE_SAMPLE_SPC_MASK (1 << 7) /* sample is space */ -+#define ENE_SAMPLE_VALUE_MASK 0x7F -+#define ENE_SAMPLE_OVERFLOW 0x7F -+#define ENE_SAMPLES_SIZE 4 -+ -+/* fan input sample buffer */ -+#define ENE_SAMPLE_BUFFER_FAN 0xF8FB /* this buffer holds high byte of */ -+ /* each sample of normal buffer */ -+ -+#define ENE_FAN_SMPL_PULS_MSK 0x8000 /* this bit of combined sample */ -+ /* if set, says that sample is pulse */ -+#define ENE_FAN_VALUE_MASK 0x0FFF /* mask for valid bits of the value */ -+ -+/* first firmware register */ -+#define ENE_FW1 0xF8F8 -+#define ENE_FW1_ENABLE (1 << 0) /* enable fw processing */ -+#define ENE_FW1_TXIRQ (1 << 1) /* TX interrupt pending */ -+#define ENE_FW1_WAKE (1 << 6) /* enable wake from S3 */ -+#define ENE_FW1_IRQ (1 << 7) /* enable interrupt */ -+ -+/* second firmware register */ -+#define ENE_FW2 0xF8F9 -+#define ENE_FW2_BUF_HIGH (1 << 0) /* which half of the buffer to read */ -+#define ENE_FW2_IRQ_CLR (1 << 2) /* clear this on IRQ */ -+#define ENE_FW2_GP40_AS_LEARN (1 << 4) /* normal input is used as */ -+ /* learning input */ -+#define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */ -+#define ENE_FW2_LEARNING (1 << 7) /* hardware supports learning and TX */ -+ -+/* fan as input settings - only if learning capable */ -+#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */ -+#define ENE_FAN_AS_IN1_EN 0xCD -+#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */ -+#define ENE_FAN_AS_IN2_EN 0x03 -+#define ENE_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */ -+ -+/* IRQ registers block (for revision B) */ -+#define ENEB_IRQ 0xFD09 /* IRQ number */ -+#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */ -+#define ENEB_IRQ_STATUS 0xFD80 /* irq status */ -+#define ENEB_IRQ_STATUS_IR (1 << 5) /* IR irq */ -+ -+/* IRQ registers block (for revision C,D) */ -+#define ENEC_IRQ 0xFE9B /* new irq settings register */ -+#define ENEC_IRQ_MASK 0x0F /* irq number mask */ -+#define ENEC_IRQ_UNK_EN (1 << 4) /* always enabled */ -+#define ENEC_IRQ_STATUS (1 << 5) /* irq status and ACK */ -+ -+/* CIR block settings */ -+#define ENE_CIR_CONF1 0xFEC0 -+#define ENE_CIR_CONF1_ADC_ON 0x7 /* reciever on gpio40 enabled */ -+#define ENE_CIR_CONF1_LEARN1 (1 << 3) /* enabled on learning mode */ -+#define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */ -+#define ENE_CIR_CONF1_TX_CARR (1 << 7) /* send TX carrier or not */ -+ -+#define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */ -+#define ENE_CIR_CONF2_LEARN2 (1 << 4) /* set on enable learning */ -+#define ENE_CIR_CONF2_GPIO40DIS (1 << 5) /* disable normal input via gpio40 */ -+ -+#define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */ -+#define ENE_CIR_SAMPLE_OVERFLOW (1 << 7) /* interrupt on overflows if set */ -+ -+ -+/* transmitter - not implemented yet */ -+/* KB3926C and higher */ -+/* transmission is very similiar to recieving, a byte is written to */ -+/* ENE_TX_INPUT, in same manner as it is read from sample buffer */ -+/* sample period is fixed*/ -+ -+ -+/* transmitter ports */ -+#define ENE_TX_PORT1 0xFC01 /* this enables one or both */ -+#define ENE_TX_PORT1_EN (1 << 5) /* TX ports */ -+#define ENE_TX_PORT2 0xFC08 -+#define ENE_TX_PORT2_EN (1 << 1) -+ -+#define ENE_TX_INPUT 0xFEC9 /* next byte to transmit */ -+#define ENE_TX_SPC_MASK (1 << 7) /* Transmitted sample is space */ -+#define ENE_TX_UNK1 0xFECB /* set to 0x63 */ -+#define ENE_TX_SMPL_PERIOD 50 /* transmit sample period */ -+ -+ -+#define ENE_TX_CARRIER 0xFECE /* TX carrier * 2 (khz) */ -+#define ENE_TX_CARRIER_UNKBIT 0x80 /* This bit set on transmit */ -+#define ENE_TX_CARRIER_LOW 0xFECF /* TX carrier / 2 */ -+ -+/* Hardware versions */ -+#define ENE_HW_VERSION 0xFF00 /* hardware revision */ -+#define ENE_HW_UNK 0xFF1D -+#define ENE_HW_UNK_CLR (1 << 2) -+#define ENE_HW_VER_MAJOR 0xFF1E /* chip version */ -+#define ENE_HW_VER_MINOR 0xFF1F -+#define ENE_HW_VER_OLD 0xFD00 -+ -+#define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0)) -+ -+#define ENE_DRIVER_NAME "enecir" -+#define ENE_MAXGAP 250000 /* this is amount of time we wait -+ before turning the sampler, chosen -+ arbitry */ -+ -+#define space(len) (-(len)) /* add a space */ -+ -+/* software defines */ -+#define ENE_IRQ_RX 1 -+#define ENE_IRQ_TX 2 -+ -+#define ENE_HW_B 1 /* 3926B */ -+#define ENE_HW_C 2 /* 3926C */ -+#define ENE_HW_D 3 /* 3926D */ -+ -+#define ene_printk(level, text, ...) \ -+ printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__) -+ -+struct ene_device { -+ struct pnp_dev *pnp_dev; -+ struct lirc_driver *lirc_driver; -+ -+ /* hw settings */ -+ unsigned long hw_io; -+ int irq; -+ -+ int hw_revision; /* hardware revision */ -+ int hw_learning_and_tx_capable; /* learning capable */ -+ int hw_gpio40_learning; /* gpio40 is learning */ -+ int hw_fan_as_normal_input; /* fan input is used as regular input */ -+ -+ /* device data */ -+ int idle; -+ int fan_input_inuse; -+ -+ int sample; -+ int in_use; -+ -+ struct timeval gap_start; -+}; -diff --git a/drivers/staging/lirc/lirc_i2c.c b/drivers/staging/lirc/lirc_i2c.c -new file mode 100644 -index 0000000..6df2c0e ---- /dev/null -+++ b/drivers/staging/lirc/lirc_i2c.c -@@ -0,0 +1,536 @@ -+/* -+ * lirc_i2c.c -+ * -+ * i2c IR driver for the onboard IR port on many TV tuner cards, including: -+ * -Flavors of the Hauppauge PVR-150/250/350 -+ * -Hauppauge HVR-1300 -+ * -PixelView (BT878P+W/FM) -+ * -KNC ONE TV Station/Anubis Typhoon TView Tuner -+ * -Asus TV-Box and Creative/VisionTek BreakOut-Box -+ * -Leadtek Winfast PVR2000 -+ * -+ * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> -+ * modified for PixelView (BT878P+W/FM) by -+ * Michal Kochanowicz <mkochano@pld.org.pl> -+ * Christoph Bartelmus <lirc@bartelmus.de> -+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by -+ * Ulrich Mueller <ulrich.mueller42@web.de> -+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by -+ * Stefan Jahn <stefan@lkcc.org> -+ * modified for inclusion into kernel sources by -+ * Jerome Brock <jbrock@users.sourceforge.net> -+ * modified for Leadtek Winfast PVR2000 by -+ * Thomas Reitmayr (treitmayr@yahoo.com) -+ * modified for Hauppauge HVR-1300 by -+ * Jan Frey (jfrey@gmx.de) -+ * -+ * parts are cut&pasted from the old lirc_haup.c driver -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+ -+#include <linux/version.h> -+#include <linux/module.h> -+#include <linux/kmod.h> -+#include <linux/kernel.h> -+#include <linux/sched.h> -+#include <linux/string.h> -+#include <linux/timer.h> -+#include <linux/delay.h> -+#include <linux/errno.h> -+#include <linux/slab.h> -+#include <linux/i2c.h> -+#include <linux/i2c-algo-bit.h> -+ -+#include <media/lirc_dev.h> -+ -+struct IR { -+ struct lirc_driver l; -+ struct i2c_client c; -+ int nextkey; -+ unsigned char b[3]; -+ unsigned char bits; -+ unsigned char flag; -+}; -+ -+#define DEVICE_NAME "lirc_i2c" -+ -+/* module parameters */ -+static int debug; /* debug output */ -+static int minor = -1; /* minor number */ -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG DEVICE_NAME ": " fmt, \ -+ ## args); \ -+ } while (0) -+ -+static int reverse(int data, int bits) -+{ -+ int i; -+ int c; -+ -+ for (c = 0, i = 0; i < bits; i++) -+ c |= ((data & (1<<i)) ? 1 : 0) << (bits-1-i); -+ -+ return c; -+} -+ -+static int add_to_buf_adap(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ unsigned char keybuf[4]; -+ -+ keybuf[0] = 0x00; -+ i2c_master_send(&ir->c, keybuf, 1); -+ /* poll IR chip */ -+ if (i2c_master_recv(&ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) { -+ dprintk("read error\n"); -+ return -EIO; -+ } -+ -+ dprintk("key (0x%02x%02x%02x%02x)\n", -+ keybuf[0], keybuf[1], keybuf[2], keybuf[3]); -+ -+ /* key pressed ? */ -+ if (keybuf[2] == 0xff) -+ return -ENODATA; -+ -+ /* remove repeat bit */ -+ keybuf[2] &= 0x7f; -+ keybuf[3] |= 0x80; -+ -+ lirc_buffer_write(buf, keybuf); -+ return 0; -+} -+ -+static int add_to_buf_pcf8574(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ int rc; -+ unsigned char all, mask; -+ unsigned char key; -+ -+ /* compute all valid bits (key code + pressed/release flag) */ -+ all = ir->bits | ir->flag; -+ -+ /* save IR writable mask bits */ -+ mask = i2c_smbus_read_byte(&ir->c) & ~all; -+ -+ /* send bit mask */ -+ rc = i2c_smbus_write_byte(&ir->c, (0xff & all) | mask); -+ -+ /* receive scan code */ -+ rc = i2c_smbus_read_byte(&ir->c); -+ -+ if (rc == -1) { -+ dprintk("%s read error\n", ir->c.name); -+ return -EIO; -+ } -+ -+ /* drop duplicate polls */ -+ if (ir->b[0] == (rc & all)) -+ return -ENODATA; -+ -+ ir->b[0] = rc & all; -+ -+ dprintk("%s key 0x%02X %s\n", ir->c.name, rc & ir->bits, -+ (rc & ir->flag) ? "released" : "pressed"); -+ -+ /* ignore released buttons */ -+ if (rc & ir->flag) -+ return -ENODATA; -+ -+ /* set valid key code */ -+ key = rc & ir->bits; -+ lirc_buffer_write(buf, &key); -+ return 0; -+} -+ -+/* common for Hauppauge IR receivers */ -+static int add_to_buf_haup_common(void *data, struct lirc_buffer *buf, -+ unsigned char *keybuf, int size, int offset) -+{ -+ struct IR *ir = data; -+ __u16 code; -+ unsigned char codes[2]; -+ int ret; -+ -+ /* poll IR chip */ -+ ret = i2c_master_recv(&ir->c, keybuf, size); -+ if (ret == size) { -+ ir->b[0] = keybuf[offset]; -+ ir->b[1] = keybuf[offset+1]; -+ ir->b[2] = keybuf[offset+2]; -+ if (ir->b[0] != 0x00 && ir->b[1] != 0x00) -+ dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]); -+ } else { -+ dprintk("read error (ret=%d)\n", ret); -+ /* keep last successful read buffer */ -+ } -+ -+ /* key pressed ? */ -+ if ((ir->b[0] & 0x80) == 0) -+ return -ENODATA; -+ -+ /* look what we have */ -+ code = (((__u16)ir->b[0]&0x7f)<<6) | (ir->b[1]>>2); -+ -+ codes[0] = (code >> 8) & 0xff; -+ codes[1] = code & 0xff; -+ -+ /* return it */ -+ dprintk("sending code 0x%02x%02x to lirc\n", codes[0], codes[1]); -+ lirc_buffer_write(buf, codes); -+ return 0; -+} -+ -+/* specific for the Hauppauge PVR150 IR receiver */ -+static int add_to_buf_haup_pvr150(void *data, struct lirc_buffer *buf) -+{ -+ unsigned char keybuf[6]; -+ /* fetch 6 bytes, first relevant is at offset 3 */ -+ return add_to_buf_haup_common(data, buf, keybuf, 6, 3); -+} -+ -+/* used for all Hauppauge IR receivers but the PVR150 */ -+static int add_to_buf_haup(void *data, struct lirc_buffer *buf) -+{ -+ unsigned char keybuf[3]; -+ /* fetch 3 bytes, first relevant is at offset 0 */ -+ return add_to_buf_haup_common(data, buf, keybuf, 3, 0); -+} -+ -+ -+static int add_to_buf_pvr2000(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ unsigned char key; -+ s32 flags; -+ s32 code; -+ -+ /* poll IR chip */ -+ flags = i2c_smbus_read_byte_data(&ir->c, 0x10); -+ if (-1 == flags) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ /* key pressed ? */ -+ if (0 == (flags & 0x80)) -+ return -ENODATA; -+ -+ /* read actual key code */ -+ code = i2c_smbus_read_byte_data(&ir->c, 0x00); -+ if (-1 == code) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ -+ key = code & 0xFF; -+ -+ dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", key, flags & 0xFF); -+ -+ /* return it */ -+ lirc_buffer_write(buf, &key); -+ return 0; -+} -+ -+static int add_to_buf_pixelview(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ unsigned char key; -+ -+ /* poll IR chip */ -+ if (1 != i2c_master_recv(&ir->c, &key, 1)) { -+ dprintk("read error\n"); -+ return -1; -+ } -+ dprintk("key %02x\n", key); -+ -+ /* return it */ -+ lirc_buffer_write(buf, &key); -+ return 0; -+} -+ -+static int add_to_buf_pv951(void *data, struct lirc_buffer *buf) -+{ -+ struct IR *ir = data; -+ unsigned char key; -+ unsigned char codes[4]; -+ -+ /* poll IR chip */ -+ if (1 != i2c_master_recv(&ir->c, &key, 1)) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ /* ignore 0xaa */ -+ if (key == 0xaa) -+ return -ENODATA; -+ dprintk("key %02x\n", key); -+ -+ codes[0] = 0x61; -+ codes[1] = 0xD6; -+ codes[2] = reverse(key, 8); -+ codes[3] = (~codes[2])&0xff; -+ -+ lirc_buffer_write(buf, codes); -+ return 0; -+} -+ -+static int add_to_buf_knc1(void *data, struct lirc_buffer *buf) -+{ -+ static unsigned char last_key = 0xFF; -+ struct IR *ir = data; -+ unsigned char key; -+ -+ /* poll IR chip */ -+ if (1 != i2c_master_recv(&ir->c, &key, 1)) { -+ dprintk("read error\n"); -+ return -ENODATA; -+ } -+ -+ /* -+ * it seems that 0xFE indicates that a button is still held -+ * down, while 0xFF indicates that no button is held -+ * down. 0xFE sequences are sometimes interrupted by 0xFF -+ */ -+ -+ dprintk("key %02x\n", key); -+ -+ if (key == 0xFF) -+ return -ENODATA; -+ -+ if (key == 0xFE) -+ key = last_key; -+ -+ last_key = key; -+ lirc_buffer_write(buf, &key); -+ -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ struct IR *ir = data; -+ -+ dprintk("%s called\n", __func__); -+ -+ /* lock bttv in memory while /dev/lirc is in use */ -+ i2c_use_client(&ir->c); -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct IR *ir = data; -+ -+ dprintk("%s called\n", __func__); -+ -+ i2c_release_client(&ir->c); -+} -+ -+static struct lirc_driver lirc_template = { -+ .name = "lirc_i2c", -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id); -+static int ir_remove(struct i2c_client *client); -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg); -+ -+static const struct i2c_device_id ir_receiver_id[] = { -+ /* Generic entry for any IR receiver */ -+ { "ir_video", 0 }, -+ /* IR device specific entries could be added here */ -+ { } -+}; -+ -+static struct i2c_driver driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "i2c ir driver", -+ }, -+ .probe = ir_probe, -+ .remove = ir_remove, -+ .id_table = ir_receiver_id, -+ .command = ir_command, -+}; -+ -+static void pcf_probe(struct i2c_client *client, struct IR *ir) -+{ -+ int ret1, ret2, ret3, ret4; -+ -+ ret1 = i2c_smbus_write_byte(client, 0xff); -+ ret2 = i2c_smbus_read_byte(client); -+ ret3 = i2c_smbus_write_byte(client, 0x00); -+ ret4 = i2c_smbus_read_byte(client); -+ -+ /* in the Asus TV-Box: bit 1-0 */ -+ if (((ret2 & 0x03) == 0x03) && ((ret4 & 0x03) == 0x00)) { -+ ir->bits = (unsigned char) ~0x07; -+ ir->flag = 0x04; -+ /* in the Creative/VisionTek BreakOut-Box: bit 7-6 */ -+ } else if (((ret2 & 0xc0) == 0xc0) && ((ret4 & 0xc0) == 0x00)) { -+ ir->bits = (unsigned char) ~0xe0; -+ ir->flag = 0x20; -+ } -+ -+ return; -+} -+ -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct IR *ir; -+ struct i2c_adapter *adap = client->adapter; -+ unsigned short addr = client->addr; -+ int retval; -+ -+ ir = kzalloc(sizeof(struct IR), GFP_KERNEL); -+ if (!ir) -+ return -ENOMEM; -+ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); -+ memcpy(&ir->c, client, sizeof(struct i2c_client)); -+ -+ i2c_set_clientdata(client, ir); -+ ir->l.data = ir; -+ ir->l.minor = minor; -+ ir->l.sample_rate = 10; -+ ir->l.dev = &ir->c.dev; -+ ir->nextkey = -1; -+ -+ switch (addr) { -+ case 0x64: -+ strlcpy(ir->c.name, "Pixelview IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_pixelview; -+ break; -+ case 0x4b: -+ strlcpy(ir->c.name, "PV951 IR", I2C_NAME_SIZE); -+ ir->l.code_length = 32; -+ ir->l.add_to_buf = add_to_buf_pv951; -+ break; -+ case 0x71: -+ if (adap->id == I2C_HW_B_CX2388x) -+ strlcpy(ir->c.name, "Hauppauge HVR1300", I2C_NAME_SIZE); -+ else /* bt8xx or cx2341x */ -+ /* -+ * The PVR150 IR receiver uses the same protocol as -+ * other Hauppauge cards, but the data flow is -+ * different, so we need to deal with it by its own. -+ */ -+ strlcpy(ir->c.name, "Hauppauge PVR150", I2C_NAME_SIZE); -+ ir->l.code_length = 13; -+ ir->l.add_to_buf = add_to_buf_haup_pvr150; -+ break; -+ case 0x6b: -+ strlcpy(ir->c.name, "Adaptec IR", I2C_NAME_SIZE); -+ ir->l.code_length = 32; -+ ir->l.add_to_buf = add_to_buf_adap; -+ break; -+ case 0x18: -+ case 0x1a: -+ if (adap->id == I2C_HW_B_CX2388x) { -+ strlcpy(ir->c.name, "Leadtek IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_pvr2000; -+ } else { /* bt8xx or cx2341x */ -+ strlcpy(ir->c.name, "Hauppauge IR", I2C_NAME_SIZE); -+ ir->l.code_length = 13; -+ ir->l.add_to_buf = add_to_buf_haup; -+ } -+ break; -+ case 0x30: -+ strlcpy(ir->c.name, "KNC ONE IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_knc1; -+ break; -+ case 0x21: -+ case 0x23: -+ pcf_probe(client, ir); -+ strlcpy(ir->c.name, "TV-Box IR", I2C_NAME_SIZE); -+ ir->l.code_length = 8; -+ ir->l.add_to_buf = add_to_buf_pcf8574; -+ break; -+ default: -+ /* shouldn't happen */ -+ printk("lirc_i2c: Huh? unknown i2c address (0x%02x)?\n", addr); -+ kfree(ir); -+ return -EINVAL; -+ } -+ printk(KERN_INFO "lirc_i2c: chip 0x%x found @ 0x%02x (%s)\n", -+ adap->id, addr, ir->c.name); -+ -+ retval = lirc_register_driver(&ir->l); -+ -+ if (retval < 0) { -+ printk(KERN_ERR "lirc_i2c: failed to register driver!\n"); -+ kfree(ir); -+ return retval; -+ } -+ -+ ir->l.minor = retval; -+ -+ return 0; -+} -+ -+static int ir_remove(struct i2c_client *client) -+{ -+ struct IR *ir = i2c_get_clientdata(client); -+ -+ /* unregister device */ -+ lirc_unregister_driver(ir->l.minor); -+ -+ /* free memory */ -+ kfree(ir); -+ return 0; -+} -+ -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg) -+{ -+ /* nothing */ -+ return 0; -+} -+ -+static int __init lirc_i2c_init(void) -+{ -+ i2c_add_driver(&driver); -+ return 0; -+} -+ -+static void __exit lirc_i2c_exit(void) -+{ -+ i2c_del_driver(&driver); -+} -+ -+MODULE_DESCRIPTION("Infrared receiver driver for Hauppauge and " -+ "Pixelview cards (i2c stack)"); -+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, " -+ "Ulrich Mueller, Stefan Jahn, Jerome Brock"); -+MODULE_LICENSE("GPL"); -+ -+module_param(minor, int, S_IRUGO); -+MODULE_PARM_DESC(minor, "Preferred minor device number"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_init(lirc_i2c_init); -+module_exit(lirc_i2c_exit); -diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/lirc/lirc_igorplugusb.c -new file mode 100644 -index 0000000..bce600e ---- /dev/null -+++ b/drivers/staging/lirc/lirc_igorplugusb.c -@@ -0,0 +1,555 @@ -+/* -+ * lirc_igorplugusb - USB remote support for LIRC -+ * -+ * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware. -+ * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm -+ * -+ * The device can only record bursts of up to 36 pulses/spaces. -+ * Works fine with RC5. Longer commands lead to device buffer overrun. -+ * (Maybe a better firmware or a microcontroller with more ram can help?) -+ * -+ * Version 0.1 [beta status] -+ * -+ * Copyright (C) 2004 Jan M. Hochstein -+ * <hochstein@algo.informatik.tu-darmstadt.de> -+ * -+ * This driver was derived from: -+ * Paul Miller <pmiller9@users.sourceforge.net> -+ * "lirc_atiusb" module -+ * Vladimir Dergachev <volodya@minspring.com>'s 2002 -+ * "USB ATI Remote support" (input device) -+ * Adrian Dewhurst <sailor-lk@sailorfrag.net>'s 2002 -+ * "USB StreamZap remote driver" (LIRC) -+ * Artur Lipowski <alipowski@kki.net.pl>'s 2002 -+ * "lirc_dev" and "lirc_gpio" LIRC modules -+ */ -+ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include <linux/module.h> -+#include <linux/kernel.h> -+#include <linux/kmod.h> -+#include <linux/sched.h> -+#include <linux/errno.h> -+#include <linux/fs.h> -+#include <linux/usb.h> -+#include <linux/time.h> -+ -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+ -+ -+/* module identification */ -+#define DRIVER_VERSION "0.1" -+#define DRIVER_AUTHOR \ -+ "Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>" -+#define DRIVER_DESC "USB remote driver for LIRC" -+#define DRIVER_NAME "lirc_igorplugusb" -+ -+/* debugging support */ -+#ifdef CONFIG_USB_DEBUG -+static int debug = 1; -+#else -+static int debug; -+#endif -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG fmt, ## args); \ -+ } while (0) -+ -+/* One mode2 pulse/space has 4 bytes. */ -+#define CODE_LENGTH sizeof(int) -+ -+/* Igor's firmware cannot record bursts longer than 36. */ -+#define DEVICE_BUFLEN 36 -+ -+/* -+ * Header at the beginning of the device's buffer: -+ * unsigned char data_length -+ * unsigned char data_start (!=0 means ring-buffer overrun) -+ * unsigned char counter (incremented by each burst) -+ */ -+#define DEVICE_HEADERLEN 3 -+ -+/* This is for the gap */ -+#define ADDITIONAL_LIRC_BYTES 2 -+ -+/* times to poll per second */ -+#define SAMPLE_RATE 100 -+static int sample_rate = SAMPLE_RATE; -+ -+ -+/**** Igor's USB Request Codes */ -+ -+#define SET_INFRABUFFER_EMPTY 1 -+/** -+ * Params: none -+ * Answer: empty -+ */ -+ -+#define GET_INFRACODE 2 -+/** -+ * Params: -+ * wValue: offset to begin reading infra buffer -+ * -+ * Answer: infra data -+ */ -+ -+#define SET_DATAPORT_DIRECTION 3 -+/** -+ * Params: -+ * wValue: (byte) 1 bit for each data port pin (0=in, 1=out) -+ * -+ * Answer: empty -+ */ -+ -+#define GET_DATAPORT_DIRECTION 4 -+/** -+ * Params: none -+ * -+ * Answer: (byte) 1 bit for each data port pin (0=in, 1=out) -+ */ -+ -+#define SET_OUT_DATAPORT 5 -+/** -+ * Params: -+ * wValue: byte to write to output data port -+ * -+ * Answer: empty -+ */ -+ -+#define GET_OUT_DATAPORT 6 -+/** -+ * Params: none -+ * -+ * Answer: least significant 3 bits read from output data port -+ */ -+ -+#define GET_IN_DATAPORT 7 -+/** -+ * Params: none -+ * -+ * Answer: least significant 3 bits read from input data port -+ */ -+ -+#define READ_EEPROM 8 -+/** -+ * Params: -+ * wValue: offset to begin reading EEPROM -+ * -+ * Answer: EEPROM bytes -+ */ -+ -+#define WRITE_EEPROM 9 -+/** -+ * Params: -+ * wValue: offset to EEPROM byte -+ * wIndex: byte to write -+ * -+ * Answer: empty -+ */ -+ -+#define SEND_RS232 10 -+/** -+ * Params: -+ * wValue: byte to send -+ * -+ * Answer: empty -+ */ -+ -+#define RECV_RS232 11 -+/** -+ * Params: none -+ * -+ * Answer: byte received -+ */ -+ -+#define SET_RS232_BAUD 12 -+/** -+ * Params: -+ * wValue: byte to write to UART bit rate register (UBRR) -+ * -+ * Answer: empty -+ */ -+ -+#define GET_RS232_BAUD 13 -+/** -+ * Params: none -+ * -+ * Answer: byte read from UART bit rate register (UBRR) -+ */ -+ -+ -+/* data structure for each usb remote */ -+struct igorplug { -+ -+ /* usb */ -+ struct usb_device *usbdev; -+ struct urb *urb_in; -+ int devnum; -+ -+ unsigned char *buf_in; -+ unsigned int len_in; -+ int in_space; -+ struct timeval last_time; -+ -+ dma_addr_t dma_in; -+ -+ /* lirc */ -+ struct lirc_driver *d; -+ -+ /* handle sending (init strings) */ -+ int send_flags; -+ wait_queue_head_t wait_out; -+}; -+ -+static int unregister_from_lirc(struct igorplug *ir) -+{ -+ struct lirc_driver *d = ir->d; -+ int devnum; -+ -+ if (!ir->d) -+ return -EINVAL; -+ -+ devnum = ir->devnum; -+ dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum); -+ -+ lirc_unregister_driver(d->minor); -+ -+ printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum); -+ -+ kfree(d); -+ ir->d = NULL; -+ kfree(ir); -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ struct igorplug *ir = data; -+ -+ if (!ir) { -+ printk(DRIVER_NAME "[?]: set_use_inc called with no context\n"); -+ return -EIO; -+ } -+ dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum); -+ -+ if (!ir->usbdev) -+ return -ENODEV; -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct igorplug *ir = data; -+ -+ if (!ir) { -+ printk(DRIVER_NAME "[?]: set_use_dec called with no context\n"); -+ return; -+ } -+ dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum); -+} -+ -+ -+/** -+ * Called in user context. -+ * return 0 if data was added to the buffer and -+ * -ENODATA if none was available. This should add some number of bits -+ * evenly divisible by code_length to the buffer -+ */ -+static int usb_remote_poll(void *data, struct lirc_buffer *buf) -+{ -+ int ret; -+ struct igorplug *ir = (struct igorplug *)data; -+ -+ if (!ir->usbdev) /* Has the device been removed? */ -+ return -ENODEV; -+ -+ memset(ir->buf_in, 0, ir->len_in); -+ -+ ret = usb_control_msg( -+ ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ GET_INFRACODE, USB_TYPE_VENDOR|USB_DIR_IN, -+ 0/* offset */, /*unused*/0, -+ ir->buf_in, ir->len_in, -+ /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); -+ if (ret > 0) { -+ int i = DEVICE_HEADERLEN; -+ int code, timediff; -+ struct timeval now; -+ -+ if (ret <= 1) /* ACK packet has 1 byte --> ignore */ -+ return -ENODATA; -+ -+ dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n", -+ ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]); -+ -+ if (ir->buf_in[2] != 0) { -+ printk(DRIVER_NAME "[%d]: Device buffer overrun.\n", -+ ir->devnum); -+ /* start at earliest byte */ -+ i = DEVICE_HEADERLEN + ir->buf_in[2]; -+ /* where are we now? space, gap or pulse? */ -+ } -+ -+ do_gettimeofday(&now); -+ timediff = now.tv_sec - ir->last_time.tv_sec; -+ if (timediff + 1 > PULSE_MASK / 1000000) -+ timediff = PULSE_MASK; -+ else { -+ timediff *= 1000000; -+ timediff += now.tv_usec - ir->last_time.tv_usec; -+ } -+ ir->last_time.tv_sec = now.tv_sec; -+ ir->last_time.tv_usec = now.tv_usec; -+ -+ /* create leading gap */ -+ code = timediff; -+ lirc_buffer_write(buf, (unsigned char *)&code); -+ ir->in_space = 1; /* next comes a pulse */ -+ -+ /* MODE2: pulse/space (PULSE_BIT) in 1us units */ -+ -+ while (i < ret) { -+ /* 1 Igor-tick = 85.333333 us */ -+ code = (unsigned int)ir->buf_in[i] * 85 -+ + (unsigned int)ir->buf_in[i] / 3; -+ if (ir->in_space) -+ code |= PULSE_BIT; -+ lirc_buffer_write(buf, (unsigned char *)&code); -+ /* 1 chunk = CODE_LENGTH bytes */ -+ ir->in_space ^= 1; -+ ++i; -+ } -+ -+ ret = usb_control_msg( -+ ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, -+ /*unused*/0, /*unused*/0, -+ /*dummy*/ir->buf_in, /*dummy*/ir->len_in, -+ /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); -+ if (ret < 0) -+ printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: " -+ "error %d\n", ir->devnum, ret); -+ return 0; -+ } else if (ret < 0) -+ printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n", -+ ir->devnum, ret); -+ -+ return -ENODATA; -+} -+ -+ -+ -+static int usb_remote_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *dev = NULL; -+ struct usb_host_interface *idesc = NULL; -+ struct usb_host_endpoint *ep_ctl2; -+ struct igorplug *ir = NULL; -+ struct lirc_driver *driver = NULL; -+ int devnum, pipe, maxp; -+ int minor = 0; -+ char buf[63], name[128] = ""; -+ int mem_failure = 0; -+ int ret; -+ -+ dprintk(DRIVER_NAME ": usb probe called.\n"); -+ -+ dev = interface_to_usbdev(intf); -+ -+ idesc = intf->cur_altsetting; -+ -+ if (idesc->desc.bNumEndpoints != 1) -+ return -ENODEV; -+ ep_ctl2 = idesc->endpoint; -+ if (((ep_ctl2->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ != USB_DIR_IN) -+ || (ep_ctl2->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ != USB_ENDPOINT_XFER_CONTROL) -+ return -ENODEV; -+ pipe = usb_rcvctrlpipe(dev, ep_ctl2->desc.bEndpointAddress); -+ devnum = dev->devnum; -+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); -+ -+ dprintk(DRIVER_NAME "[%d]: bytes_in_key=%lu maxp=%d\n", -+ devnum, CODE_LENGTH, maxp); -+ -+ -+ mem_failure = 0; -+ ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL); -+ if (!ir) { -+ mem_failure = 1; -+ goto mem_failure_switch; -+ } -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) { -+ mem_failure = 2; -+ goto mem_failure_switch; -+ } -+ -+ ir->buf_in = usb_alloc_coherent(dev, -+ DEVICE_BUFLEN+DEVICE_HEADERLEN, -+ GFP_ATOMIC, &ir->dma_in); -+ if (!ir->buf_in) { -+ mem_failure = 3; -+ goto mem_failure_switch; -+ } -+ -+ strcpy(driver->name, DRIVER_NAME " "); -+ driver->minor = -1; -+ driver->code_length = CODE_LENGTH * 8; /* in bits */ -+ driver->features = LIRC_CAN_REC_MODE2; -+ driver->data = ir; -+ driver->chunk_size = CODE_LENGTH; -+ driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES; -+ driver->set_use_inc = &set_use_inc; -+ driver->set_use_dec = &set_use_dec; -+ driver->sample_rate = sample_rate; /* per second */ -+ driver->add_to_buf = &usb_remote_poll; -+ driver->dev = &intf->dev; -+ driver->owner = THIS_MODULE; -+ -+ init_waitqueue_head(&ir->wait_out); -+ -+ minor = lirc_register_driver(driver); -+ if (minor < 0) -+ mem_failure = 9; -+ -+mem_failure_switch: -+ -+ switch (mem_failure) { -+ case 9: -+ usb_free_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN, -+ ir->buf_in, ir->dma_in); -+ case 3: -+ kfree(driver); -+ case 2: -+ kfree(ir); -+ case 1: -+ printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n", -+ devnum, mem_failure); -+ return -ENOMEM; -+ } -+ -+ driver->minor = minor; -+ ir->d = driver; -+ ir->devnum = devnum; -+ ir->usbdev = dev; -+ ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN; -+ ir->in_space = 1; /* First mode2 event is a space. */ -+ do_gettimeofday(&ir->last_time); -+ -+ if (dev->descriptor.iManufacturer -+ && usb_string(dev, dev->descriptor.iManufacturer, -+ buf, sizeof(buf)) > 0) -+ strlcpy(name, buf, sizeof(name)); -+ if (dev->descriptor.iProduct -+ && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0) -+ snprintf(name + strlen(name), sizeof(name) - strlen(name), -+ " %s", buf); -+ printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name, -+ dev->bus->busnum, devnum); -+ -+ /* clear device buffer */ -+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, -+ /*unused*/0, /*unused*/0, -+ /*dummy*/ir->buf_in, /*dummy*/ir->len_in, -+ /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); -+ if (ret < 0) -+ printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n", -+ devnum, ret); -+ -+ usb_set_intfdata(intf, ir); -+ return 0; -+} -+ -+ -+static void usb_remote_disconnect(struct usb_interface *intf) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct igorplug *ir = usb_get_intfdata(intf); -+ usb_set_intfdata(intf, NULL); -+ -+ if (!ir || !ir->d) -+ return; -+ -+ ir->usbdev = NULL; -+ wake_up_all(&ir->wait_out); -+ -+ usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); -+ -+ unregister_from_lirc(ir); -+} -+ -+static struct usb_device_id usb_remote_id_table[] = { -+ /* Igor Plug USB (Atmel's Manufact. ID) */ -+ { USB_DEVICE(0x03eb, 0x0002) }, -+ -+ /* Terminating entry */ -+ { } -+}; -+ -+static struct usb_driver usb_remote_driver = { -+ .name = DRIVER_NAME, -+ .probe = usb_remote_probe, -+ .disconnect = usb_remote_disconnect, -+ .id_table = usb_remote_id_table -+}; -+ -+static int __init usb_remote_init(void) -+{ -+ int i; -+ -+ printk(KERN_INFO "\n" -+ DRIVER_NAME ": " DRIVER_DESC " v" DRIVER_VERSION "\n"); -+ printk(DRIVER_NAME ": " DRIVER_AUTHOR "\n"); -+ dprintk(DRIVER_NAME ": debug mode enabled\n"); -+ -+ i = usb_register(&usb_remote_driver); -+ if (i < 0) { -+ printk(DRIVER_NAME ": usb register failed, result = %d\n", i); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static void __exit usb_remote_exit(void) -+{ -+ usb_deregister(&usb_remote_driver); -+} -+ -+module_init(usb_remote_init); -+module_exit(usb_remote_exit); -+ -+#include <linux/vermagic.h> -+MODULE_INFO(vermagic, VERMAGIC_STRING); -+ -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_AUTHOR(DRIVER_AUTHOR); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(usb, usb_remote_id_table); -+ -+module_param(sample_rate, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)"); -+ -diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c -new file mode 100644 -index 0000000..6649325 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_imon.c -@@ -0,0 +1,1058 @@ -+/* -+ * lirc_imon.c: LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD -+ * including the iMON PAD model -+ * -+ * Copyright(C) 2004 Venky Raju(dev@venky.ws) -+ * Copyright(C) 2009 Jarod Wilson <jarod@wilsonet.com> -+ * -+ * lirc_imon is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/usb.h> -+ -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+ -+ -+#define MOD_AUTHOR "Venky Raju <dev@venky.ws>" -+#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" -+#define MOD_NAME "lirc_imon" -+#define MOD_VERSION "0.8" -+ -+#define DISPLAY_MINOR_BASE 144 -+#define DEVICE_NAME "lcd%d" -+ -+#define BUF_CHUNK_SIZE 4 -+#define BUF_SIZE 128 -+ -+#define BIT_DURATION 250 /* each bit received is 250us */ -+ -+/*** P R O T O T Y P E S ***/ -+ -+/* USB Callback prototypes */ -+static int imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id); -+static void imon_disconnect(struct usb_interface *interface); -+static void usb_rx_callback(struct urb *urb); -+static void usb_tx_callback(struct urb *urb); -+ -+/* suspend/resume support */ -+static int imon_resume(struct usb_interface *intf); -+static int imon_suspend(struct usb_interface *intf, pm_message_t message); -+ -+/* Display file_operations function prototypes */ -+static int display_open(struct inode *inode, struct file *file); -+static int display_close(struct inode *inode, struct file *file); -+ -+/* VFD write operation */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/* LIRC driver function prototypes */ -+static int ir_open(void *data); -+static void ir_close(void *data); -+ -+/* Driver init/exit prototypes */ -+static int __init imon_init(void); -+static void __exit imon_exit(void); -+ -+/*** G L O B A L S ***/ -+#define IMON_DATA_BUF_SZ 35 -+ -+struct imon_context { -+ struct usb_device *usbdev; -+ /* Newer devices have two interfaces */ -+ int display; /* not all controllers do */ -+ int display_isopen; /* display port has been opened */ -+ int ir_isopen; /* IR port open */ -+ int dev_present; /* USB device presence */ -+ struct mutex ctx_lock; /* to lock this object */ -+ wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ -+ -+ int vfd_proto_6p; /* some VFD require a 6th packet */ -+ -+ struct lirc_driver *driver; -+ struct usb_endpoint_descriptor *rx_endpoint; -+ struct usb_endpoint_descriptor *tx_endpoint; -+ struct urb *rx_urb; -+ struct urb *tx_urb; -+ unsigned char usb_rx_buf[8]; -+ unsigned char usb_tx_buf[8]; -+ -+ struct rx_data { -+ int count; /* length of 0 or 1 sequence */ -+ int prev_bit; /* logic level of sequence */ -+ int initial_space; /* initial space flag */ -+ } rx; -+ -+ struct tx_t { -+ unsigned char data_buf[IMON_DATA_BUF_SZ]; /* user data buffer */ -+ struct completion finished; /* wait for write to finish */ -+ atomic_t busy; /* write in progress */ -+ int status; /* status of tx completion */ -+ } tx; -+}; -+ -+static const struct file_operations display_fops = { -+ .owner = THIS_MODULE, -+ .open = &display_open, -+ .write = &vfd_write, -+ .release = &display_close -+}; -+ -+/* -+ * USB Device ID for iMON USB Control Boards -+ * -+ * The Windows drivers contain 6 different inf files, more or less one for -+ * each new device until the 0x0034-0x0046 devices, which all use the same -+ * driver. Some of the devices in the 34-46 range haven't been definitively -+ * identified yet. Early devices have either a TriGem Computer, Inc. or a -+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later -+ * devices use the SoundGraph vendor ID (0x15c2). -+ */ -+static struct usb_device_id imon_usb_id_table[] = { -+ /* TriGem iMON (IR only) -- TG_iMON.inf */ -+ { USB_DEVICE(0x0aa8, 0x8001) }, -+ -+ /* SoundGraph iMON (IR only) -- sg_imon.inf */ -+ { USB_DEVICE(0x04e8, 0xff30) }, -+ -+ /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */ -+ { USB_DEVICE(0x0aa8, 0xffda) }, -+ -+ /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */ -+ { USB_DEVICE(0x15c2, 0xffda) }, -+ -+ {} -+}; -+ -+/* Some iMON VFD models requires a 6th packet for VFD writes */ -+static struct usb_device_id vfd_proto_6p_list[] = { -+ { USB_DEVICE(0x15c2, 0xffda) }, -+ {} -+}; -+ -+/* Some iMON devices have no lcd/vfd, don't set one up */ -+static struct usb_device_id ir_only_list[] = { -+ { USB_DEVICE(0x0aa8, 0x8001) }, -+ { USB_DEVICE(0x04e8, 0xff30) }, -+ {} -+}; -+ -+/* USB Device data */ -+static struct usb_driver imon_driver = { -+ .name = MOD_NAME, -+ .probe = imon_probe, -+ .disconnect = imon_disconnect, -+ .suspend = imon_suspend, -+ .resume = imon_resume, -+ .id_table = imon_usb_id_table, -+}; -+ -+static struct usb_class_driver imon_class = { -+ .name = DEVICE_NAME, -+ .fops = &display_fops, -+ .minor_base = DISPLAY_MINOR_BASE, -+}; -+ -+/* to prevent races between open() and disconnect(), probing, etc */ -+static DEFINE_MUTEX(driver_lock); -+ -+static int debug; -+ -+/*** M O D U L E C O D E ***/ -+ -+MODULE_AUTHOR(MOD_AUTHOR); -+MODULE_DESCRIPTION(MOD_DESC); -+MODULE_VERSION(MOD_VERSION); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(usb, imon_usb_id_table); -+module_param(debug, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)"); -+ -+static void free_imon_context(struct imon_context *context) -+{ -+ struct device *dev = context->driver->dev; -+ usb_free_urb(context->tx_urb); -+ usb_free_urb(context->rx_urb); -+ lirc_buffer_free(context->driver->rbuf); -+ kfree(context->driver->rbuf); -+ kfree(context->driver); -+ kfree(context); -+ -+ dev_dbg(dev, "%s: iMON context freed\n", __func__); -+} -+ -+static void deregister_from_lirc(struct imon_context *context) -+{ -+ int retval; -+ int minor = context->driver->minor; -+ -+ retval = lirc_unregister_driver(minor); -+ if (retval) -+ err("%s: unable to deregister from lirc(%d)", -+ __func__, retval); -+ else -+ printk(KERN_INFO MOD_NAME ": Deregistered iMON driver " -+ "(minor:%d)\n", minor); -+ -+} -+ -+/** -+ * Called when the Display device (e.g. /dev/lcd0) -+ * is opened by the application. -+ */ -+static int display_open(struct inode *inode, struct file *file) -+{ -+ struct usb_interface *interface; -+ struct imon_context *context = NULL; -+ int subminor; -+ int retval = 0; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&driver_lock); -+ -+ subminor = iminor(inode); -+ interface = usb_find_interface(&imon_driver, subminor); -+ if (!interface) { -+ err("%s: could not find interface for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ context = usb_get_intfdata(interface); -+ -+ if (!context) { -+ err("%s: no context found for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->display) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (context->display_isopen) { -+ err("%s: display port is already open", __func__); -+ retval = -EBUSY; -+ } else { -+ context->display_isopen = 1; -+ file->private_data = context; -+ dev_info(context->driver->dev, "display port opened\n"); -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ -+exit: -+ mutex_unlock(&driver_lock); -+ return retval; -+} -+ -+/** -+ * Called when the display device (e.g. /dev/lcd0) -+ * is closed by the application. -+ */ -+static int display_close(struct inode *inode, struct file *file) -+{ -+ struct imon_context *context = NULL; -+ int retval = 0; -+ -+ context = (struct imon_context *)file->private_data; -+ -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->display) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (!context->display_isopen) { -+ err("%s: display is not open", __func__); -+ retval = -EIO; -+ } else { -+ context->display_isopen = 0; -+ dev_info(context->driver->dev, "display port closed\n"); -+ if (!context->dev_present && !context->ir_isopen) { -+ /* -+ * Device disconnected before close and IR port is not -+ * open. If IR port is open, context will be deleted by -+ * ir_close. -+ */ -+ mutex_unlock(&context->ctx_lock); -+ free_imon_context(context); -+ return retval; -+ } -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return retval; -+} -+ -+/** -+ * Sends a packet to the device -- this function must be called -+ * with context->ctx_lock held. -+ */ -+static int send_packet(struct imon_context *context) -+{ -+ unsigned int pipe; -+ int interval = 0; -+ int retval = 0; -+ struct usb_ctrlrequest *control_req = NULL; -+ -+ /* Check if we need to use control or interrupt urb */ -+ pipe = usb_sndintpipe(context->usbdev, -+ context->tx_endpoint->bEndpointAddress); -+ interval = context->tx_endpoint->bInterval; -+ -+ usb_fill_int_urb(context->tx_urb, context->usbdev, pipe, -+ context->usb_tx_buf, -+ sizeof(context->usb_tx_buf), -+ usb_tx_callback, context, interval); -+ -+ context->tx_urb->actual_length = 0; -+ -+ init_completion(&context->tx.finished); -+ atomic_set(&(context->tx.busy), 1); -+ -+ retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); -+ if (retval) { -+ atomic_set(&(context->tx.busy), 0); -+ err("%s: error submitting urb(%d)", __func__, retval); -+ } else { -+ /* Wait for transmission to complete (or abort) */ -+ mutex_unlock(&context->ctx_lock); -+ retval = wait_for_completion_interruptible( -+ &context->tx.finished); -+ if (retval) -+ err("%s: task interrupted", __func__); -+ mutex_lock(&context->ctx_lock); -+ -+ retval = context->tx.status; -+ if (retval) -+ err("%s: packet tx failed (%d)", __func__, retval); -+ } -+ -+ kfree(control_req); -+ -+ return retval; -+} -+ -+/** -+ * Writes data to the VFD. The iMON VFD is 2x16 characters -+ * and requires data in 5 consecutive USB interrupt packets, -+ * each packet but the last carrying 7 bytes. -+ * -+ * I don't know if the VFD board supports features such as -+ * scrolling, clearing rows, blanking, etc. so at -+ * the caller must provide a full screen of data. If fewer -+ * than 32 bytes are provided spaces will be appended to -+ * generate a full screen. -+ */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int i; -+ int offset; -+ int seq; -+ int retval = 0; -+ struct imon_context *context; -+ const unsigned char vfd_packet6[] = { -+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; -+ int *data_buf; -+ -+ context = (struct imon_context *)file->private_data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->dev_present) { -+ err("%s: no iMON device present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) { -+ err("%s: invalid payload size", __func__); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ data_buf = memdup_user(buf, n_bytes); -+ if (IS_ERR(data_buf)) { -+ retval = PTR_ERR(data_buf); -+ goto exit; -+ } -+ -+ memcpy(context->tx.data_buf, data_buf, n_bytes); -+ -+ /* Pad with spaces */ -+ for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i) -+ context->tx.data_buf[i] = ' '; -+ -+ for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i) -+ context->tx.data_buf[i] = 0xFF; -+ -+ offset = 0; -+ seq = 0; -+ -+ do { -+ memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7); -+ context->usb_tx_buf[7] = (unsigned char) seq; -+ -+ retval = send_packet(context); -+ if (retval) { -+ err("%s: send packet failed for packet #%d", -+ __func__, seq/2); -+ goto exit; -+ } else { -+ seq += 2; -+ offset += 7; -+ } -+ -+ } while (offset < IMON_DATA_BUF_SZ); -+ -+ if (context->vfd_proto_6p) { -+ /* Send packet #6 */ -+ memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6)); -+ context->usb_tx_buf[7] = (unsigned char) seq; -+ retval = send_packet(context); -+ if (retval) -+ err("%s: send packet failed for packet #%d", -+ __func__, seq/2); -+ } -+ -+exit: -+ mutex_unlock(&context->ctx_lock); -+ -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Callback function for USB core API: transmit data -+ */ -+static void usb_tx_callback(struct urb *urb) -+{ -+ struct imon_context *context; -+ -+ if (!urb) -+ return; -+ context = (struct imon_context *)urb->context; -+ if (!context) -+ return; -+ -+ context->tx.status = urb->status; -+ -+ /* notify waiters that write has finished */ -+ atomic_set(&context->tx.busy, 0); -+ complete(&context->tx.finished); -+ -+ return; -+} -+ -+/** -+ * Called by lirc_dev when the application opens /dev/lirc -+ */ -+static int ir_open(void *data) -+{ -+ int retval = 0; -+ struct imon_context *context; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&driver_lock); -+ -+ context = (struct imon_context *)data; -+ -+ /* initial IR protocol decode variables */ -+ context->rx.count = 0; -+ context->rx.initial_space = 1; -+ context->rx.prev_bit = 0; -+ -+ context->ir_isopen = 1; -+ dev_info(context->driver->dev, "IR port opened\n"); -+ -+ mutex_unlock(&driver_lock); -+ return retval; -+} -+ -+/** -+ * Called by lirc_dev when the application closes /dev/lirc -+ */ -+static void ir_close(void *data) -+{ -+ struct imon_context *context; -+ -+ context = (struct imon_context *)data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ context->ir_isopen = 0; -+ dev_info(context->driver->dev, "IR port closed\n"); -+ -+ if (!context->dev_present) { -+ /* -+ * Device disconnected while IR port was still open. Driver -+ * was not deregistered at disconnect time, so do it now. -+ */ -+ deregister_from_lirc(context); -+ -+ if (!context->display_isopen) { -+ mutex_unlock(&context->ctx_lock); -+ free_imon_context(context); -+ return; -+ } -+ /* -+ * If display port is open, context will be deleted by -+ * display_close -+ */ -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return; -+} -+ -+/** -+ * Convert bit count to time duration (in us) and submit -+ * the value to lirc_dev. -+ */ -+static void submit_data(struct imon_context *context) -+{ -+ unsigned char buf[4]; -+ int value = context->rx.count; -+ int i; -+ -+ dev_dbg(context->driver->dev, "submitting data to LIRC\n"); -+ -+ value *= BIT_DURATION; -+ value &= PULSE_MASK; -+ if (context->rx.prev_bit) -+ value |= PULSE_BIT; -+ -+ for (i = 0; i < 4; ++i) -+ buf[i] = value>>(i*8); -+ -+ lirc_buffer_write(context->driver->rbuf, buf); -+ wake_up(&context->driver->rbuf->wait_poll); -+ return; -+} -+ -+static inline int tv2int(const struct timeval *a, const struct timeval *b) -+{ -+ int usecs = 0; -+ int sec = 0; -+ -+ if (b->tv_usec > a->tv_usec) { -+ usecs = 1000000; -+ sec--; -+ } -+ -+ usecs += a->tv_usec - b->tv_usec; -+ -+ sec += a->tv_sec - b->tv_sec; -+ sec *= 1000; -+ usecs /= 1000; -+ sec += usecs; -+ -+ if (sec < 0) -+ sec = 1000; -+ -+ return sec; -+} -+ -+/** -+ * Process the incoming packet -+ */ -+static void imon_incoming_packet(struct imon_context *context, -+ struct urb *urb, int intf) -+{ -+ int len = urb->actual_length; -+ unsigned char *buf = urb->transfer_buffer; -+ struct device *dev = context->driver->dev; -+ int octet, bit; -+ unsigned char mask; -+ int i, chunk_num; -+ -+ /* -+ * just bail out if no listening IR client -+ */ -+ if (!context->ir_isopen) -+ return; -+ -+ if (len != 8) { -+ dev_warn(dev, "imon %s: invalid incoming packet " -+ "size (len = %d, intf%d)\n", __func__, len, intf); -+ return; -+ } -+ -+ if (debug) { -+ printk(KERN_INFO "raw packet: "); -+ for (i = 0; i < len; ++i) -+ printk("%02x ", buf[i]); -+ printk("\n"); -+ } -+ -+ /* -+ * Translate received data to pulse and space lengths. -+ * Received data is active low, i.e. pulses are 0 and -+ * spaces are 1. -+ * -+ * My original algorithm was essentially similar to -+ * Changwoo Ryu's with the exception that he switched -+ * the incoming bits to active high and also fed an -+ * initial space to LIRC at the start of a new sequence -+ * if the previous bit was a pulse. -+ * -+ * I've decided to adopt his algorithm. -+ */ -+ -+ if (buf[7] == 1 && context->rx.initial_space) { -+ /* LIRC requires a leading space */ -+ context->rx.prev_bit = 0; -+ context->rx.count = 4; -+ submit_data(context); -+ context->rx.count = 0; -+ } -+ -+ for (octet = 0; octet < 5; ++octet) { -+ mask = 0x80; -+ for (bit = 0; bit < 8; ++bit) { -+ int curr_bit = !(buf[octet] & mask); -+ if (curr_bit != context->rx.prev_bit) { -+ if (context->rx.count) { -+ submit_data(context); -+ context->rx.count = 0; -+ } -+ context->rx.prev_bit = curr_bit; -+ } -+ ++context->rx.count; -+ mask >>= 1; -+ } -+ } -+ -+ if (chunk_num == 10) { -+ if (context->rx.count) { -+ submit_data(context); -+ context->rx.count = 0; -+ } -+ context->rx.initial_space = context->rx.prev_bit; -+ } -+} -+ -+/** -+ * Callback function for USB core API: receive data -+ */ -+static void usb_rx_callback(struct urb *urb) -+{ -+ struct imon_context *context; -+ unsigned char *buf; -+ int len; -+ int intfnum = 0; -+ -+ if (!urb) -+ return; -+ -+ context = (struct imon_context *)urb->context; -+ if (!context) -+ return; -+ -+ buf = urb->transfer_buffer; -+ len = urb->actual_length; -+ -+ switch (urb->status) { -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case 0: -+ imon_incoming_packet(context, urb, intfnum); -+ break; -+ -+ default: -+ dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(context->rx_urb, GFP_ATOMIC); -+ -+ return; -+} -+ -+/** -+ * Callback function for USB core API: Probe -+ */ -+static int imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *usbdev = NULL; -+ struct usb_host_interface *iface_desc = NULL; -+ struct usb_endpoint_descriptor *rx_endpoint = NULL; -+ struct usb_endpoint_descriptor *tx_endpoint = NULL; -+ struct urb *rx_urb = NULL; -+ struct urb *tx_urb = NULL; -+ struct lirc_driver *driver = NULL; -+ struct lirc_buffer *rbuf = NULL; -+ struct device *dev = &interface->dev; -+ int ifnum; -+ int lirc_minor = 0; -+ int num_endpts; -+ int retval = 0; -+ int display_ep_found = 0; -+ int ir_ep_found = 0; -+ int alloc_status = 0; -+ int vfd_proto_6p = 0; -+ int code_length; -+ struct imon_context *context = NULL; -+ int i; -+ u16 vendor, product; -+ -+ context = kzalloc(sizeof(struct imon_context), GFP_KERNEL); -+ if (!context) { -+ err("%s: kzalloc failed for context", __func__); -+ alloc_status = 1; -+ goto alloc_status_switch; -+ } -+ -+ /* -+ * Try to auto-detect the type of display if the user hasn't set -+ * it by hand via the display_type modparam. Default is VFD. -+ */ -+ if (usb_match_id(interface, ir_only_list)) -+ context->display = 0; -+ else -+ context->display = 1; -+ -+ code_length = BUF_CHUNK_SIZE * 8; -+ -+ usbdev = usb_get_dev(interface_to_usbdev(interface)); -+ iface_desc = interface->cur_altsetting; -+ num_endpts = iface_desc->desc.bNumEndpoints; -+ ifnum = iface_desc->desc.bInterfaceNumber; -+ vendor = le16_to_cpu(usbdev->descriptor.idVendor); -+ product = le16_to_cpu(usbdev->descriptor.idProduct); -+ -+ dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n", -+ __func__, vendor, product, ifnum); -+ -+ /* prevent races probing devices w/multiple interfaces */ -+ mutex_lock(&driver_lock); -+ -+ /* -+ * Scan the endpoint list and set: -+ * first input endpoint = IR endpoint -+ * first output endpoint = display endpoint -+ */ -+ for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { -+ struct usb_endpoint_descriptor *ep; -+ int ep_dir; -+ int ep_type; -+ ep = &iface_desc->endpoint[i].desc; -+ ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; -+ ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ -+ if (!ir_ep_found && -+ ep_dir == USB_DIR_IN && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ rx_endpoint = ep; -+ ir_ep_found = 1; -+ dev_dbg(dev, "%s: found IR endpoint\n", __func__); -+ -+ } else if (!display_ep_found && ep_dir == USB_DIR_OUT && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ tx_endpoint = ep; -+ display_ep_found = 1; -+ dev_dbg(dev, "%s: found display endpoint\n", __func__); -+ } -+ } -+ -+ /* -+ * Some iMON receivers have no display. Unfortunately, it seems -+ * that SoundGraph recycles device IDs between devices both with -+ * and without... :\ -+ */ -+ if (context->display == 0) { -+ display_ep_found = 0; -+ dev_dbg(dev, "%s: device has no display\n", __func__); -+ } -+ -+ /* Input endpoint is mandatory */ -+ if (!ir_ep_found) { -+ err("%s: no valid input (IR) endpoint found.", __func__); -+ retval = -ENODEV; -+ alloc_status = 2; -+ goto alloc_status_switch; -+ } -+ -+ /* Determine if display requires 6 packets */ -+ if (display_ep_found) { -+ if (usb_match_id(interface, vfd_proto_6p_list)) -+ vfd_proto_6p = 1; -+ -+ dev_dbg(dev, "%s: vfd_proto_6p: %d\n", -+ __func__, vfd_proto_6p); -+ } -+ -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) { -+ err("%s: kzalloc failed for lirc_driver", __func__); -+ alloc_status = 2; -+ goto alloc_status_switch; -+ } -+ rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!rbuf) { -+ err("%s: kmalloc failed for lirc_buffer", __func__); -+ alloc_status = 3; -+ goto alloc_status_switch; -+ } -+ if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { -+ err("%s: lirc_buffer_init failed", __func__); -+ alloc_status = 4; -+ goto alloc_status_switch; -+ } -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ err("%s: usb_alloc_urb failed for IR urb", __func__); -+ alloc_status = 5; -+ goto alloc_status_switch; -+ } -+ tx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!tx_urb) { -+ err("%s: usb_alloc_urb failed for display urb", -+ __func__); -+ alloc_status = 6; -+ goto alloc_status_switch; -+ } -+ -+ mutex_init(&context->ctx_lock); -+ context->vfd_proto_6p = vfd_proto_6p; -+ -+ strcpy(driver->name, MOD_NAME); -+ driver->minor = -1; -+ driver->code_length = sizeof(int) * 8; -+ driver->sample_rate = 0; -+ driver->features = LIRC_CAN_REC_MODE2; -+ driver->data = context; -+ driver->rbuf = rbuf; -+ driver->set_use_inc = ir_open; -+ driver->set_use_dec = ir_close; -+ driver->dev = &interface->dev; -+ driver->owner = THIS_MODULE; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ context->driver = driver; -+ /* start out in keyboard mode */ -+ -+ lirc_minor = lirc_register_driver(driver); -+ if (lirc_minor < 0) { -+ err("%s: lirc_register_driver failed", __func__); -+ alloc_status = 7; -+ goto alloc_status_switch; -+ } else -+ dev_info(dev, "Registered iMON driver " -+ "(lirc minor: %d)\n", lirc_minor); -+ -+ /* Needed while unregistering! */ -+ driver->minor = lirc_minor; -+ -+ context->usbdev = usbdev; -+ context->dev_present = 1; -+ context->rx_endpoint = rx_endpoint; -+ context->rx_urb = rx_urb; -+ -+ /* -+ * tx is used to send characters to lcd/vfd, associate RF -+ * remotes, set IR protocol, and maybe more... -+ */ -+ context->tx_endpoint = tx_endpoint; -+ context->tx_urb = tx_urb; -+ -+ if (display_ep_found) -+ context->display = 1; -+ -+ usb_fill_int_urb(context->rx_urb, context->usbdev, -+ usb_rcvintpipe(context->usbdev, -+ context->rx_endpoint->bEndpointAddress), -+ context->usb_rx_buf, sizeof(context->usb_rx_buf), -+ usb_rx_callback, context, -+ context->rx_endpoint->bInterval); -+ -+ retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); -+ -+ if (retval) { -+ err("%s: usb_submit_urb failed for intf0 (%d)", -+ __func__, retval); -+ mutex_unlock(&context->ctx_lock); -+ goto exit; -+ } -+ -+ usb_set_intfdata(interface, context); -+ -+ if (context->display && ifnum == 0) { -+ dev_dbg(dev, "%s: Registering iMON display with sysfs\n", -+ __func__); -+ -+ if (usb_register_dev(interface, &imon_class)) { -+ /* Not a fatal error, so ignore */ -+ dev_info(dev, "%s: could not get a minor number for " -+ "display\n", __func__); -+ } -+ } -+ -+ dev_info(dev, "iMON device (%04x:%04x, intf%d) on " -+ "usb<%d:%d> initialized\n", vendor, product, ifnum, -+ usbdev->bus->busnum, usbdev->devnum); -+ -+alloc_status_switch: -+ mutex_unlock(&context->ctx_lock); -+ -+ switch (alloc_status) { -+ case 7: -+ usb_free_urb(tx_urb); -+ case 6: -+ usb_free_urb(rx_urb); -+ case 5: -+ if (rbuf) -+ lirc_buffer_free(rbuf); -+ case 4: -+ kfree(rbuf); -+ case 3: -+ kfree(driver); -+ case 2: -+ kfree(context); -+ context = NULL; -+ case 1: -+ if (retval != -ENODEV) -+ retval = -ENOMEM; -+ break; -+ case 0: -+ retval = 0; -+ } -+ -+exit: -+ mutex_unlock(&driver_lock); -+ -+ return retval; -+} -+ -+/** -+ * Callback function for USB core API: disconnect -+ */ -+static void imon_disconnect(struct usb_interface *interface) -+{ -+ struct imon_context *context; -+ int ifnum; -+ -+ /* prevent races with ir_open()/display_open() */ -+ mutex_lock(&driver_lock); -+ -+ context = usb_get_intfdata(interface); -+ ifnum = interface->cur_altsetting->desc.bInterfaceNumber; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ usb_set_intfdata(interface, NULL); -+ -+ /* Abort ongoing write */ -+ if (atomic_read(&context->tx.busy)) { -+ usb_kill_urb(context->tx_urb); -+ complete_all(&context->tx.finished); -+ } -+ -+ context->dev_present = 0; -+ usb_kill_urb(context->rx_urb); -+ if (context->display) -+ usb_deregister_dev(interface, &imon_class); -+ -+ if (!context->ir_isopen && !context->dev_present) { -+ deregister_from_lirc(context); -+ mutex_unlock(&context->ctx_lock); -+ if (!context->display_isopen) -+ free_imon_context(context); -+ } else -+ mutex_unlock(&context->ctx_lock); -+ -+ mutex_unlock(&driver_lock); -+ -+ printk(KERN_INFO "%s: iMON device (intf%d) disconnected\n", -+ __func__, ifnum); -+} -+ -+static int imon_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct imon_context *context = usb_get_intfdata(intf); -+ -+ usb_kill_urb(context->rx_urb); -+ -+ return 0; -+} -+ -+static int imon_resume(struct usb_interface *intf) -+{ -+ int rc = 0; -+ struct imon_context *context = usb_get_intfdata(intf); -+ -+ usb_fill_int_urb(context->rx_urb, context->usbdev, -+ usb_rcvintpipe(context->usbdev, -+ context->rx_endpoint->bEndpointAddress), -+ context->usb_rx_buf, sizeof(context->usb_rx_buf), -+ usb_rx_callback, context, -+ context->rx_endpoint->bInterval); -+ -+ rc = usb_submit_urb(context->rx_urb, GFP_ATOMIC); -+ -+ return rc; -+} -+ -+static int __init imon_init(void) -+{ -+ int rc; -+ -+ printk(KERN_INFO MOD_NAME ": " MOD_DESC ", v" MOD_VERSION "\n"); -+ -+ rc = usb_register(&imon_driver); -+ if (rc) { -+ err("%s: usb register failed(%d)", __func__, rc); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static void __exit imon_exit(void) -+{ -+ usb_deregister(&imon_driver); -+ printk(KERN_INFO MOD_NAME ": module removed. Goodbye!\n"); -+} -+ -+module_init(imon_init); -+module_exit(imon_exit); -diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c -new file mode 100644 -index 0000000..ec11c0e ---- /dev/null -+++ b/drivers/staging/lirc/lirc_it87.c -@@ -0,0 +1,1022 @@ -+/* -+ * LIRC driver for ITE IT8712/IT8705 CIR port -+ * -+ * Copyright (C) 2001 Hans-Gunter Lutke Uphues <hg_lu@web.de> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -+ * USA -+ * -+ * ITE IT8705 and IT8712(not tested) and IT8720 CIR-port support for lirc based -+ * via cut and paste from lirc_sir.c (C) 2000 Milan Pikula -+ * -+ * Attention: Sendmode only tested with debugging logs -+ * -+ * 2001/02/27 Christoph Bartelmus <lirc@bartelmus.de> : -+ * reimplemented read function -+ * 2005/06/05 Andrew Calkin implemented support for Asus Digimatrix, -+ * based on work of the following member of the Outertrack Digimatrix -+ * Forum: Art103 <r_tay@hotmail.com> -+ * 2009/12/24 James Edwards <jimbo-lirc@edwardsclan.net> implemeted support -+ * for ITE8704/ITE8718, on my machine, the DSDT reports 8704, but the -+ * chip identifies as 18. -+ */ -+ -+#include <linux/module.h> -+#include <linux/sched.h> -+#include <linux/errno.h> -+#include <linux/signal.h> -+#include <linux/fs.h> -+#include <linux/interrupt.h> -+#include <linux/ioport.h> -+#include <linux/kernel.h> -+#include <linux/time.h> -+#include <linux/string.h> -+#include <linux/types.h> -+#include <linux/wait.h> -+#include <linux/mm.h> -+#include <linux/delay.h> -+#include <linux/poll.h> -+#include <asm/system.h> -+#include <linux/io.h> -+#include <linux/irq.h> -+#include <linux/fcntl.h> -+ -+#include <linux/timer.h> -+#include <linux/pnp.h> -+ -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+ -+#include "lirc_it87.h" -+ -+#ifdef LIRC_IT87_DIGIMATRIX -+static int digimatrix = 1; -+static int it87_freq = 36; /* kHz */ -+static int irq = 9; -+#else -+static int digimatrix; -+static int it87_freq = 38; /* kHz */ -+static int irq = IT87_CIR_DEFAULT_IRQ; -+#endif -+ -+static unsigned long it87_bits_in_byte_out; -+static unsigned long it87_send_counter; -+static unsigned char it87_RXEN_mask = IT87_CIR_RCR_RXEN; -+ -+#define RBUF_LEN 1024 -+ -+#define LIRC_DRIVER_NAME "lirc_it87" -+ -+/* timeout for sequences in jiffies (=5/100s) */ -+/* must be longer than TIME_CONST */ -+#define IT87_TIMEOUT (HZ*5/100) -+ -+/* module parameters */ -+static int debug; -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+static int io = IT87_CIR_DEFAULT_IOBASE; -+/* receiver demodulator default: off */ -+static int it87_enable_demodulator; -+ -+static int timer_enabled; -+static DEFINE_SPINLOCK(timer_lock); -+static struct timer_list timerlist; -+/* time of last signal change detected */ -+static struct timeval last_tv = {0, 0}; -+/* time of last UART data ready interrupt */ -+static struct timeval last_intr_tv = {0, 0}; -+static int last_value; -+ -+static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); -+ -+static DEFINE_SPINLOCK(hardware_lock); -+static DEFINE_SPINLOCK(dev_lock); -+static bool device_open; -+ -+static int rx_buf[RBUF_LEN]; -+unsigned int rx_tail, rx_head; -+ -+static struct pnp_driver it87_pnp_driver; -+ -+/* SECTION: Prototypes */ -+ -+/* Communication with user-space */ -+static int lirc_open(struct inode *inode, struct file *file); -+static int lirc_close(struct inode *inode, struct file *file); -+static unsigned int lirc_poll(struct file *file, poll_table *wait); -+static ssize_t lirc_read(struct file *file, char *buf, -+ size_t count, loff_t *ppos); -+static ssize_t lirc_write(struct file *file, const char *buf, -+ size_t n, loff_t *pos); -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); -+static void add_read_queue(int flag, unsigned long val); -+static int init_chrdev(void); -+static void drop_chrdev(void); -+/* Hardware */ -+static irqreturn_t it87_interrupt(int irq, void *dev_id); -+static void send_space(unsigned long len); -+static void send_pulse(unsigned long len); -+static void init_send(void); -+static void terminate_send(unsigned long len); -+static int init_hardware(void); -+static void drop_hardware(void); -+/* Initialisation */ -+static int init_port(void); -+static void drop_port(void); -+ -+ -+/* SECTION: Communication with user-space */ -+ -+static int lirc_open(struct inode *inode, struct file *file) -+{ -+ spin_lock(&dev_lock); -+ if (device_open) { -+ spin_unlock(&dev_lock); -+ return -EBUSY; -+ } -+ device_open = true; -+ spin_unlock(&dev_lock); -+ return 0; -+} -+ -+ -+static int lirc_close(struct inode *inode, struct file *file) -+{ -+ spin_lock(&dev_lock); -+ device_open = false; -+ spin_unlock(&dev_lock); -+ return 0; -+} -+ -+ -+static unsigned int lirc_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &lirc_read_queue, wait); -+ if (rx_head != rx_tail) -+ return POLLIN | POLLRDNORM; -+ return 0; -+} -+ -+ -+static ssize_t lirc_read(struct file *file, char *buf, -+ size_t count, loff_t *ppos) -+{ -+ int n = 0; -+ int retval = 0; -+ -+ while (n < count) { -+ if (file->f_flags & O_NONBLOCK && rx_head == rx_tail) { -+ retval = -EAGAIN; -+ break; -+ } -+ retval = wait_event_interruptible(lirc_read_queue, -+ rx_head != rx_tail); -+ if (retval) -+ break; -+ -+ if (copy_to_user((void *) buf + n, (void *) (rx_buf + rx_head), -+ sizeof(int))) { -+ retval = -EFAULT; -+ break; -+ } -+ rx_head = (rx_head + 1) & (RBUF_LEN - 1); -+ n += sizeof(int); -+ } -+ if (n) -+ return n; -+ return retval; -+} -+ -+ -+static ssize_t lirc_write(struct file *file, const char *buf, -+ size_t n, loff_t *pos) -+{ -+ int i = 0; -+ int *tx_buf; -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ tx_buf = memdup_user(buf, n); -+ if (IS_ERR(tx_buf)) -+ return PTR_ERR(tx_buf); -+ n /= sizeof(int); -+ init_send(); -+ while (1) { -+ if (i >= n) -+ break; -+ if (tx_buf[i]) -+ send_pulse(tx_buf[i]); -+ i++; -+ if (i >= n) -+ break; -+ if (tx_buf[i]) -+ send_space(tx_buf[i]); -+ i++; -+ } -+ terminate_send(tx_buf[i - 1]); -+ return n; -+} -+ -+ -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -+{ -+ int retval = 0; -+ unsigned long value = 0; -+ unsigned int ivalue; -+ unsigned long hw_flags; -+ -+ if (cmd == LIRC_GET_FEATURES) -+ value = LIRC_CAN_SEND_PULSE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_REC_MODE2; -+ else if (cmd == LIRC_GET_SEND_MODE) -+ value = LIRC_MODE_PULSE; -+ else if (cmd == LIRC_GET_REC_MODE) -+ value = LIRC_MODE_MODE2; -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ case LIRC_GET_SEND_MODE: -+ case LIRC_GET_REC_MODE: -+ retval = put_user(value, (unsigned long *) arg); -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ case LIRC_SET_REC_MODE: -+ retval = get_user(value, (unsigned long *) arg); -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ retval = get_user(ivalue, (unsigned int *) arg); -+ if (retval) -+ return retval; -+ ivalue /= 1000; -+ if (ivalue > IT87_CIR_FREQ_MAX || -+ ivalue < IT87_CIR_FREQ_MIN) -+ return -EINVAL; -+ -+ it87_freq = ivalue; -+ -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ outb(((inb(io + IT87_CIR_TCR2) & IT87_CIR_TCR2_TXMPW) | -+ (it87_freq - IT87_CIR_FREQ_MIN) << 3), -+ io + IT87_CIR_TCR2); -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ dprintk("demodulation frequency: %d kHz\n", it87_freq); -+ -+ break; -+ -+ default: -+ retval = -EINVAL; -+ } -+ -+ if (retval) -+ return retval; -+ -+ if (cmd == LIRC_SET_REC_MODE) { -+ if (value != LIRC_MODE_MODE2) -+ retval = -ENOSYS; -+ } else if (cmd == LIRC_SET_SEND_MODE) { -+ if (value != LIRC_MODE_PULSE) -+ retval = -ENOSYS; -+ } -+ return retval; -+} -+ -+static void add_read_queue(int flag, unsigned long val) -+{ -+ unsigned int new_rx_tail; -+ int newval; -+ -+ dprintk("add flag %d with val %lu\n", flag, val); -+ -+ newval = val & PULSE_MASK; -+ -+ /* -+ * statistically, pulses are ~TIME_CONST/2 too long. we could -+ * maybe make this more exact, but this is good enough -+ */ -+ if (flag) { -+ /* pulse */ -+ if (newval > TIME_CONST / 2) -+ newval -= TIME_CONST / 2; -+ else /* should not ever happen */ -+ newval = 1; -+ newval |= PULSE_BIT; -+ } else -+ newval += TIME_CONST / 2; -+ new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); -+ if (new_rx_tail == rx_head) { -+ dprintk("Buffer overrun.\n"); -+ return; -+ } -+ rx_buf[rx_tail] = newval; -+ rx_tail = new_rx_tail; -+ wake_up_interruptible(&lirc_read_queue); -+} -+ -+ -+static const struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .read = lirc_read, -+ .write = lirc_write, -+ .poll = lirc_poll, -+ .unlocked_ioctl = lirc_ioctl, -+ .open = lirc_open, -+ .release = lirc_close, -+}; -+ -+static int set_use_inc(void *data) -+{ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+} -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+ -+static int init_chrdev(void) -+{ -+ driver.minor = lirc_register_driver(&driver); -+ -+ if (driver.minor < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); -+ return -EIO; -+ } -+ return 0; -+} -+ -+ -+static void drop_chrdev(void) -+{ -+ lirc_unregister_driver(driver.minor); -+} -+ -+ -+/* SECTION: Hardware */ -+static long delta(struct timeval *tv1, struct timeval *tv2) -+{ -+ unsigned long deltv; -+ -+ deltv = tv2->tv_sec - tv1->tv_sec; -+ if (deltv > 15) -+ deltv = 0xFFFFFF; -+ else -+ deltv = deltv*1000000 + tv2->tv_usec - tv1->tv_usec; -+ return deltv; -+} -+ -+static void it87_timeout(unsigned long data) -+{ -+ unsigned long flags; -+ -+ /* avoid interference with interrupt */ -+ spin_lock_irqsave(&timer_lock, flags); -+ -+ if (digimatrix) { -+ /* We have timed out. Disable the RX mechanism. */ -+ -+ outb((inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN) | -+ IT87_CIR_RCR_RXACT, io + IT87_CIR_RCR); -+ if (it87_RXEN_mask) -+ outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ dprintk(" TIMEOUT\n"); -+ timer_enabled = 0; -+ -+ /* fifo clear */ -+ outb(inb(io + IT87_CIR_TCR1) | IT87_CIR_TCR1_FIFOCLR, -+ io+IT87_CIR_TCR1); -+ -+ } else { -+ /* -+ * if last received signal was a pulse, but receiving stopped -+ * within the 9 bit frame, we need to finish this pulse and -+ * simulate a signal change to from pulse to space. Otherwise -+ * upper layers will receive two sequences next time. -+ */ -+ -+ if (last_value) { -+ unsigned long pulse_end; -+ -+ /* determine 'virtual' pulse end: */ -+ pulse_end = delta(&last_tv, &last_intr_tv); -+ dprintk("timeout add %d for %lu usec\n", -+ last_value, pulse_end); -+ add_read_queue(last_value, pulse_end); -+ last_value = 0; -+ last_tv = last_intr_tv; -+ } -+ } -+ spin_unlock_irqrestore(&timer_lock, flags); -+} -+ -+static irqreturn_t it87_interrupt(int irq, void *dev_id) -+{ -+ unsigned char data; -+ struct timeval curr_tv; -+ static unsigned long deltv; -+ unsigned long deltintrtv; -+ unsigned long flags, hw_flags; -+ int iir, lsr; -+ int fifo = 0; -+ static char lastbit; -+ char bit; -+ -+ /* Bit duration in microseconds */ -+ const unsigned long bit_duration = 1000000ul / -+ (115200 / IT87_CIR_BAUDRATE_DIVISOR); -+ -+ -+ iir = inb(io + IT87_CIR_IIR); -+ -+ switch (iir & IT87_CIR_IIR_IID) { -+ case 0x4: -+ case 0x6: -+ lsr = inb(io + IT87_CIR_RSR) & (IT87_CIR_RSR_RXFTO | -+ IT87_CIR_RSR_RXFBC); -+ fifo = lsr & IT87_CIR_RSR_RXFBC; -+ dprintk("iir: 0x%x fifo: 0x%x\n", iir, lsr); -+ -+ /* avoid interference with timer */ -+ spin_lock_irqsave(&timer_lock, flags); -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ if (digimatrix) { -+ static unsigned long acc_pulse; -+ static unsigned long acc_space; -+ -+ do { -+ data = inb(io + IT87_CIR_DR); -+ data = ~data; -+ fifo--; -+ if (data != 0x00) { -+ if (timer_enabled) -+ del_timer(&timerlist); -+ /* -+ * start timer for end of -+ * sequence detection -+ */ -+ timerlist.expires = jiffies + -+ IT87_TIMEOUT; -+ add_timer(&timerlist); -+ timer_enabled = 1; -+ } -+ /* Loop through */ -+ for (bit = 0; bit < 8; ++bit) { -+ if ((data >> bit) & 1) { -+ ++acc_pulse; -+ if (lastbit == 0) { -+ add_read_queue(0, -+ acc_space * -+ bit_duration); -+ acc_space = 0; -+ } -+ } else { -+ ++acc_space; -+ if (lastbit == 1) { -+ add_read_queue(1, -+ acc_pulse * -+ bit_duration); -+ acc_pulse = 0; -+ } -+ } -+ lastbit = (data >> bit) & 1; -+ } -+ -+ } while (fifo != 0); -+ } else { /* Normal Operation */ -+ do { -+ del_timer(&timerlist); -+ data = inb(io + IT87_CIR_DR); -+ -+ dprintk("data=%02x\n", data); -+ do_gettimeofday(&curr_tv); -+ deltv = delta(&last_tv, &curr_tv); -+ deltintrtv = delta(&last_intr_tv, &curr_tv); -+ -+ dprintk("t %lu , d %d\n", -+ deltintrtv, (int)data); -+ -+ /* -+ * if nothing came in last 2 cycles, -+ * it was gap -+ */ -+ if (deltintrtv > TIME_CONST * 2) { -+ if (last_value) { -+ dprintk("GAP\n"); -+ -+ /* simulate signal change */ -+ add_read_queue(last_value, -+ deltv - -+ deltintrtv); -+ last_value = 0; -+ last_tv.tv_sec = -+ last_intr_tv.tv_sec; -+ last_tv.tv_usec = -+ last_intr_tv.tv_usec; -+ deltv = deltintrtv; -+ } -+ } -+ data = 1; -+ if (data ^ last_value) { -+ /* -+ * deltintrtv > 2*TIME_CONST, -+ * remember ? the other case is -+ * timeout -+ */ -+ add_read_queue(last_value, -+ deltv-TIME_CONST); -+ last_value = data; -+ last_tv = curr_tv; -+ if (last_tv.tv_usec >= TIME_CONST) -+ last_tv.tv_usec -= TIME_CONST; -+ else { -+ last_tv.tv_sec--; -+ last_tv.tv_usec += 1000000 - -+ TIME_CONST; -+ } -+ } -+ last_intr_tv = curr_tv; -+ if (data) { -+ /* -+ * start timer for end of -+ * sequence detection -+ */ -+ timerlist.expires = -+ jiffies + IT87_TIMEOUT; -+ add_timer(&timerlist); -+ } -+ outb((inb(io + IT87_CIR_RCR) & -+ ~IT87_CIR_RCR_RXEN) | -+ IT87_CIR_RCR_RXACT, -+ io + IT87_CIR_RCR); -+ if (it87_RXEN_mask) -+ outb(inb(io + IT87_CIR_RCR) | -+ IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ fifo--; -+ } while (fifo != 0); -+ } -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ spin_unlock_irqrestore(&timer_lock, flags); -+ -+ return IRQ_RETVAL(IRQ_HANDLED); -+ -+ default: -+ /* not our irq */ -+ dprintk("unknown IRQ (shouldn't happen) !!\n"); -+ return IRQ_RETVAL(IRQ_NONE); -+ } -+} -+ -+ -+static void send_it87(unsigned long len, unsigned long stime, -+ unsigned char send_byte, unsigned int count_bits) -+{ -+ long count = len / stime; -+ long time_left = 0; -+ static unsigned char byte_out; -+ unsigned long hw_flags; -+ -+ dprintk("%s: len=%ld, sb=%d\n", __func__, len, send_byte); -+ -+ time_left = (long)len - (long)count * (long)stime; -+ count += ((2 * time_left) / stime); -+ while (count) { -+ long i = 0; -+ for (i = 0; i < count_bits; i++) { -+ byte_out = (byte_out << 1) | (send_byte & 1); -+ it87_bits_in_byte_out++; -+ } -+ if (it87_bits_in_byte_out == 8) { -+ dprintk("out=0x%x, tsr_txfbc: 0x%x\n", -+ byte_out, -+ inb(io + IT87_CIR_TSR) & -+ IT87_CIR_TSR_TXFBC); -+ -+ while ((inb(io + IT87_CIR_TSR) & -+ IT87_CIR_TSR_TXFBC) >= IT87_CIR_FIFO_SIZE) -+ ; -+ -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ outb(byte_out, io + IT87_CIR_DR); -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ -+ it87_bits_in_byte_out = 0; -+ it87_send_counter++; -+ byte_out = 0; -+ } -+ count--; -+ } -+} -+ -+ -+/*TODO: maybe exchange space and pulse because it8705 only modulates 0-bits */ -+ -+static void send_space(unsigned long len) -+{ -+ send_it87(len, TIME_CONST, IT87_CIR_SPACE, IT87_CIR_BAUDRATE_DIVISOR); -+} -+ -+static void send_pulse(unsigned long len) -+{ -+ send_it87(len, TIME_CONST, IT87_CIR_PULSE, IT87_CIR_BAUDRATE_DIVISOR); -+} -+ -+ -+static void init_send() -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ /* RXEN=0: receiver disable */ -+ it87_RXEN_mask = 0; -+ outb(inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ spin_unlock_irqrestore(&hardware_lock, flags); -+ it87_bits_in_byte_out = 0; -+ it87_send_counter = 0; -+} -+ -+ -+static void terminate_send(unsigned long len) -+{ -+ unsigned long flags; -+ unsigned long last = 0; -+ -+ last = it87_send_counter; -+ /* make sure all necessary data has been sent */ -+ while (last == it87_send_counter) -+ send_space(len); -+ /* wait until all data sent */ -+ while ((inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC) != 0) -+ ; -+ /* then re-enable receiver */ -+ spin_lock_irqsave(&hardware_lock, flags); -+ it87_RXEN_mask = IT87_CIR_RCR_RXEN; -+ outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, -+ io + IT87_CIR_RCR); -+ spin_unlock_irqrestore(&hardware_lock, flags); -+} -+ -+ -+static int init_hardware(void) -+{ -+ unsigned long flags; -+ unsigned char it87_rcr = 0; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ /* init cir-port */ -+ /* enable r/w-access to Baudrate-Register */ -+ outb(IT87_CIR_IER_BR, io + IT87_CIR_IER); -+ outb(IT87_CIR_BAUDRATE_DIVISOR % 0x100, io+IT87_CIR_BDLR); -+ outb(IT87_CIR_BAUDRATE_DIVISOR / 0x100, io+IT87_CIR_BDHR); -+ /* Baudrate Register off, define IRQs: Input only */ -+ if (digimatrix) { -+ outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RFOIE, io + IT87_CIR_IER); -+ /* RX: HCFS=0, RXDCR = 001b (33,75..38,25 kHz), RXEN=1 */ -+ } else { -+ outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RDAIE, io + IT87_CIR_IER); -+ /* RX: HCFS=0, RXDCR = 001b (35,6..40,3 kHz), RXEN=1 */ -+ } -+ it87_rcr = (IT87_CIR_RCR_RXEN & it87_RXEN_mask) | 0x1; -+ if (it87_enable_demodulator) -+ it87_rcr |= IT87_CIR_RCR_RXEND; -+ outb(it87_rcr, io + IT87_CIR_RCR); -+ if (digimatrix) { -+ /* Set FIFO depth to 1 byte, and disable TX */ -+ outb(inb(io + IT87_CIR_TCR1) | 0x00, -+ io + IT87_CIR_TCR1); -+ -+ /* -+ * TX: it87_freq (36kHz), 'reserved' sensitivity -+ * setting (0x00) -+ */ -+ outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x00, -+ io + IT87_CIR_TCR2); -+ } else { -+ /* TX: 38kHz, 13,3us (pulse-width) */ -+ outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x06, -+ io + IT87_CIR_TCR2); -+ } -+ spin_unlock_irqrestore(&hardware_lock, flags); -+ return 0; -+} -+ -+ -+static void drop_hardware(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ disable_irq(irq); -+ /* receiver disable */ -+ it87_RXEN_mask = 0; -+ outb(0x1, io + IT87_CIR_RCR); -+ /* turn off irqs */ -+ outb(0, io + IT87_CIR_IER); -+ /* fifo clear */ -+ outb(IT87_CIR_TCR1_FIFOCLR, io+IT87_CIR_TCR1); -+ /* reset */ -+ outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); -+ enable_irq(irq); -+ spin_unlock_irqrestore(&hardware_lock, flags); -+} -+ -+ -+static unsigned char it87_read(unsigned char port) -+{ -+ outb(port, IT87_ADRPORT); -+ return inb(IT87_DATAPORT); -+} -+ -+ -+static void it87_write(unsigned char port, unsigned char data) -+{ -+ outb(port, IT87_ADRPORT); -+ outb(data, IT87_DATAPORT); -+} -+ -+ -+/* SECTION: Initialisation */ -+ -+static int init_port(void) -+{ -+ unsigned long hw_flags; -+ int retval = 0; -+ -+ unsigned char init_bytes[4] = IT87_INIT; -+ unsigned char it87_chipid = 0; -+ unsigned char ldn = 0; -+ unsigned int it87_io = 0; -+ unsigned int it87_irq = 0; -+ -+ /* Enter MB PnP Mode */ -+ outb(init_bytes[0], IT87_ADRPORT); -+ outb(init_bytes[1], IT87_ADRPORT); -+ outb(init_bytes[2], IT87_ADRPORT); -+ outb(init_bytes[3], IT87_ADRPORT); -+ -+ /* 8712 or 8705 ? */ -+ it87_chipid = it87_read(IT87_CHIP_ID1); -+ if (it87_chipid != 0x87) { -+ retval = -ENXIO; -+ return retval; -+ } -+ it87_chipid = it87_read(IT87_CHIP_ID2); -+ if ((it87_chipid != 0x05) && -+ (it87_chipid != 0x12) && -+ (it87_chipid != 0x18) && -+ (it87_chipid != 0x20)) { -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": no IT8704/05/12/18/20 found (claimed IT87%02x), " -+ "exiting..\n", it87_chipid); -+ retval = -ENXIO; -+ return retval; -+ } -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": found IT87%02x.\n", -+ it87_chipid); -+ -+ /* get I/O-Port and IRQ */ -+ if (it87_chipid == 0x12 || it87_chipid == 0x18) -+ ldn = IT8712_CIR_LDN; -+ else -+ ldn = IT8705_CIR_LDN; -+ it87_write(IT87_LDN, ldn); -+ -+ it87_io = it87_read(IT87_CIR_BASE_MSB) * 256 + -+ it87_read(IT87_CIR_BASE_LSB); -+ if (it87_io == 0) { -+ if (io == 0) -+ io = IT87_CIR_DEFAULT_IOBASE; -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": set default io 0x%x\n", -+ io); -+ it87_write(IT87_CIR_BASE_MSB, io / 0x100); -+ it87_write(IT87_CIR_BASE_LSB, io % 0x100); -+ } else -+ io = it87_io; -+ -+ it87_irq = it87_read(IT87_CIR_IRQ); -+ if (digimatrix || it87_irq == 0) { -+ if (irq == 0) -+ irq = IT87_CIR_DEFAULT_IRQ; -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": set default irq 0x%x\n", -+ irq); -+ it87_write(IT87_CIR_IRQ, irq); -+ } else -+ irq = it87_irq; -+ -+ spin_lock_irqsave(&hardware_lock, hw_flags); -+ /* reset */ -+ outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); -+ /* fifo clear */ -+ outb(IT87_CIR_TCR1_FIFOCLR | -+ /* IT87_CIR_TCR1_ILE | */ -+ IT87_CIR_TCR1_TXRLE | -+ IT87_CIR_TCR1_TXENDF, io+IT87_CIR_TCR1); -+ spin_unlock_irqrestore(&hardware_lock, hw_flags); -+ -+ /* get I/O port access and IRQ line */ -+ if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": i/o port 0x%.4x already in use.\n", io); -+ /* Leaving MB PnP Mode */ -+ it87_write(IT87_CFGCTRL, 0x2); -+ return -EBUSY; -+ } -+ -+ /* activate CIR-Device */ -+ it87_write(IT87_CIR_ACT, 0x1); -+ -+ /* Leaving MB PnP Mode */ -+ it87_write(IT87_CFGCTRL, 0x2); -+ -+ retval = request_irq(irq, it87_interrupt, 0 /*IRQF_DISABLED*/, -+ LIRC_DRIVER_NAME, NULL); -+ if (retval < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": IRQ %d already in use.\n", -+ irq); -+ release_region(io, 8); -+ return retval; -+ } -+ -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": I/O port 0x%.4x, IRQ %d.\n", io, irq); -+ -+ init_timer(&timerlist); -+ timerlist.function = it87_timeout; -+ timerlist.data = 0xabadcafe; -+ -+ return 0; -+} -+ -+ -+static void drop_port(void) -+{ -+#if 0 -+ unsigned char init_bytes[4] = IT87_INIT; -+ -+ /* Enter MB PnP Mode */ -+ outb(init_bytes[0], IT87_ADRPORT); -+ outb(init_bytes[1], IT87_ADRPORT); -+ outb(init_bytes[2], IT87_ADRPORT); -+ outb(init_bytes[3], IT87_ADRPORT); -+ -+ /* deactivate CIR-Device */ -+ it87_write(IT87_CIR_ACT, 0x0); -+ -+ /* Leaving MB PnP Mode */ -+ it87_write(IT87_CFGCTRL, 0x2); -+#endif -+ -+ del_timer_sync(&timerlist); -+ free_irq(irq, NULL); -+ release_region(io, 8); -+} -+ -+ -+static int init_lirc_it87(void) -+{ -+ int retval; -+ -+ init_waitqueue_head(&lirc_read_queue); -+ retval = init_port(); -+ if (retval < 0) -+ return retval; -+ init_hardware(); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Installed.\n"); -+ return 0; -+} -+ -+static int it87_probe(struct pnp_dev *pnp_dev, -+ const struct pnp_device_id *dev_id) -+{ -+ int retval; -+ -+ driver.dev = &pnp_dev->dev; -+ -+ retval = init_chrdev(); -+ if (retval < 0) -+ return retval; -+ -+ retval = init_lirc_it87(); -+ if (retval) -+ goto init_lirc_it87_failed; -+ -+ return 0; -+ -+init_lirc_it87_failed: -+ drop_chrdev(); -+ -+ return retval; -+} -+ -+static int __init lirc_it87_init(void) -+{ -+ return pnp_register_driver(&it87_pnp_driver); -+} -+ -+ -+static void __exit lirc_it87_exit(void) -+{ -+ drop_hardware(); -+ drop_chrdev(); -+ drop_port(); -+ pnp_unregister_driver(&it87_pnp_driver); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); -+} -+ -+/* SECTION: PNP for ITE8704/18 */ -+ -+static const struct pnp_device_id pnp_dev_table[] = { -+ {"ITE8704", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -+ -+static struct pnp_driver it87_pnp_driver = { -+ .name = LIRC_DRIVER_NAME, -+ .id_table = pnp_dev_table, -+ .probe = it87_probe, -+}; -+ -+module_init(lirc_it87_init); -+module_exit(lirc_it87_exit); -+ -+MODULE_DESCRIPTION("LIRC driver for ITE IT8704/05/12/18/20 CIR port"); -+MODULE_AUTHOR("Hans-Gunter Lutke Uphues"); -+MODULE_LICENSE("GPL"); -+ -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O base address (default: 0x310)"); -+ -+module_param(irq, int, S_IRUGO); -+#ifdef LIRC_IT87_DIGIMATRIX -+MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 9)"); -+#else -+MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 7)"); -+#endif -+ -+module_param(it87_enable_demodulator, bool, S_IRUGO); -+MODULE_PARM_DESC(it87_enable_demodulator, -+ "Receiver demodulator enable/disable (1/0), default: 0"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_param(digimatrix, bool, S_IRUGO | S_IWUSR); -+#ifdef LIRC_IT87_DIGIMATRIX -+MODULE_PARM_DESC(digimatrix, -+ "Asus Digimatrix it87 compat. enable/disable (1/0), default: 1"); -+#else -+MODULE_PARM_DESC(digimatrix, -+ "Asus Digimatrix it87 compat. enable/disable (1/0), default: 0"); -+#endif -+ -+ -+module_param(it87_freq, int, S_IRUGO); -+#ifdef LIRC_IT87_DIGIMATRIX -+MODULE_PARM_DESC(it87_freq, -+ "Carrier demodulator frequency (kHz), (default: 36)"); -+#else -+MODULE_PARM_DESC(it87_freq, -+ "Carrier demodulator frequency (kHz), (default: 38)"); -+#endif -diff --git a/drivers/staging/lirc/lirc_it87.h b/drivers/staging/lirc/lirc_it87.h -new file mode 100644 -index 0000000..cf021c8 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_it87.h -@@ -0,0 +1,116 @@ -+/* lirc_it87.h */ -+/* SECTION: Definitions */ -+ -+/********************************* ITE IT87xx ************************/ -+ -+/* based on the following documentation from ITE: -+ a) IT8712F Preliminary CIR Programming Guide V0.1 -+ b) IT8705F Simple LPC I/O Preliminary Specification V0.3 -+ c) IT8712F EC-LPC I/O Preliminary Specification V0.5 -+*/ -+ -+/* IT8712/05 Ports: */ -+#define IT87_ADRPORT 0x2e -+#define IT87_DATAPORT 0x2f -+#define IT87_INIT {0x87, 0x01, 0x55, 0x55} -+ -+/* alternate Ports: */ -+/* -+#define IT87_ADRPORT 0x4e -+#define IT87_DATAPORT 0x4f -+#define IT87_INIT {0x87, 0x01, 0x55, 0xaa} -+ */ -+ -+/* IT8712/05 Registers */ -+#define IT87_CFGCTRL 0x2 -+#define IT87_LDN 0x7 -+#define IT87_CHIP_ID1 0x20 -+#define IT87_CHIP_ID2 0x21 -+#define IT87_CFG_VERSION 0x22 -+#define IT87_SWSUSPEND 0x23 -+ -+#define IT8712_CIR_LDN 0xa -+#define IT8705_CIR_LDN 0x7 -+ -+/* CIR Configuration Registers: */ -+#define IT87_CIR_ACT 0x30 -+#define IT87_CIR_BASE_MSB 0x60 -+#define IT87_CIR_BASE_LSB 0x61 -+#define IT87_CIR_IRQ 0x70 -+#define IT87_CIR_CONFIG 0xf0 -+ -+/* List of IT87_CIR registers: offset to BaseAddr */ -+#define IT87_CIR_DR 0 -+#define IT87_CIR_IER 1 -+#define IT87_CIR_RCR 2 -+#define IT87_CIR_TCR1 3 -+#define IT87_CIR_TCR2 4 -+#define IT87_CIR_TSR 5 -+#define IT87_CIR_RSR 6 -+#define IT87_CIR_BDLR 5 -+#define IT87_CIR_BDHR 6 -+#define IT87_CIR_IIR 7 -+ -+/* Bit Definition */ -+/* IER: */ -+#define IT87_CIR_IER_TM_EN 0x80 -+#define IT87_CIR_IER_RESEVED 0x40 -+#define IT87_CIR_IER_RESET 0x20 -+#define IT87_CIR_IER_BR 0x10 -+#define IT87_CIR_IER_IEC 0x8 -+#define IT87_CIR_IER_RFOIE 0x4 -+#define IT87_CIR_IER_RDAIE 0x2 -+#define IT87_CIR_IER_TLDLIE 0x1 -+ -+/* RCR: */ -+#define IT87_CIR_RCR_RDWOS 0x80 -+#define IT87_CIR_RCR_HCFS 0x40 -+#define IT87_CIR_RCR_RXEN 0x20 -+#define IT87_CIR_RCR_RXEND 0x10 -+#define IT87_CIR_RCR_RXACT 0x8 -+#define IT87_CIR_RCR_RXDCR 0x7 -+ -+/* TCR1: */ -+#define IT87_CIR_TCR1_FIFOCLR 0x80 -+#define IT87_CIR_TCR1_ILE 0x40 -+#define IT87_CIR_TCR1_FIFOTL 0x30 -+#define IT87_CIR_TCR1_TXRLE 0x8 -+#define IT87_CIR_TCR1_TXENDF 0x4 -+#define IT87_CIR_TCR1_TXMPM 0x3 -+ -+/* TCR2: */ -+#define IT87_CIR_TCR2_CFQ 0xf8 -+#define IT87_CIR_TCR2_TXMPW 0x7 -+ -+/* TSR: */ -+#define IT87_CIR_TSR_RESERVED 0xc0 -+#define IT87_CIR_TSR_TXFBC 0x3f -+ -+/* RSR: */ -+#define IT87_CIR_RSR_RXFTO 0x80 -+#define IT87_CIR_RSR_RESERVED 0x40 -+#define IT87_CIR_RSR_RXFBC 0x3f -+ -+/* IIR: */ -+#define IT87_CIR_IIR_RESERVED 0xf8 -+#define IT87_CIR_IIR_IID 0x6 -+#define IT87_CIR_IIR_IIP 0x1 -+ -+/* TM: */ -+#define IT87_CIR_TM_IL_SEL 0x80 -+#define IT87_CIR_TM_RESERVED 0x40 -+#define IT87_CIR_TM_TM_REG 0x3f -+ -+#define IT87_CIR_FIFO_SIZE 32 -+ -+/* Baudratedivisor for IT87: power of 2: only 1,2,4 or 8) */ -+#define IT87_CIR_BAUDRATE_DIVISOR 0x1 -+#define IT87_CIR_DEFAULT_IOBASE 0x310 -+#define IT87_CIR_DEFAULT_IRQ 0x7 -+#define IT87_CIR_SPACE 0x00 -+#define IT87_CIR_PULSE 0xff -+#define IT87_CIR_FREQ_MIN 27 -+#define IT87_CIR_FREQ_MAX 58 -+#define TIME_CONST (IT87_CIR_BAUDRATE_DIVISOR * 8000000ul / 115200ul) -+ -+/********************************* ITE IT87xx ************************/ -diff --git a/drivers/staging/lirc/lirc_ite8709.c b/drivers/staging/lirc/lirc_ite8709.c -new file mode 100644 -index 0000000..9352f45 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_ite8709.c -@@ -0,0 +1,542 @@ -+/* -+ * LIRC driver for ITE8709 CIR port -+ * -+ * Copyright (C) 2008 Grégory Lardière <spmf2004-lirc@yahoo.fr> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of the -+ * License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -+ * USA -+ */ -+ -+#include <linux/module.h> -+#include <linux/interrupt.h> -+#include <linux/sched.h> -+#include <linux/delay.h> -+#include <linux/pnp.h> -+#include <linux/io.h> -+ -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+ -+#define LIRC_DRIVER_NAME "lirc_ite8709" -+ -+#define BUF_CHUNK_SIZE sizeof(int) -+#define BUF_SIZE (128*BUF_CHUNK_SIZE) -+ -+/* -+ * The ITE8709 device seems to be the combination of IT8512 superIO chip and -+ * a specific firmware running on the IT8512's embedded micro-controller. -+ * In addition of the embedded micro-controller, the IT8512 chip contains a -+ * CIR module and several other modules. A few modules are directly accessible -+ * by the host CPU, but most of them are only accessible by the -+ * micro-controller. The CIR module is only accessible by the micro-controller. -+ * The battery-backed SRAM module is accessible by the host CPU and the -+ * micro-controller. So one of the MC's firmware role is to act as a bridge -+ * between the host CPU and the CIR module. The firmware implements a kind of -+ * communication protocol using the SRAM module as a shared memory. The IT8512 -+ * specification is publicly available on ITE's web site, but the communication -+ * protocol is not, so it was reverse-engineered. -+ */ -+ -+/* ITE8709 Registers addresses and values (reverse-engineered) */ -+#define ITE8709_MODE 0x1a -+#define ITE8709_REG_ADR 0x1b -+#define ITE8709_REG_VAL 0x1c -+#define ITE8709_IIR 0x1e /* Interrupt identification register */ -+#define ITE8709_RFSR 0x1f /* Receiver FIFO status register */ -+#define ITE8709_FIFO_START 0x20 -+ -+#define ITE8709_MODE_READY 0X00 -+#define ITE8709_MODE_WRITE 0X01 -+#define ITE8709_MODE_READ 0X02 -+#define ITE8709_IIR_RDAI 0x02 /* Receiver data available interrupt */ -+#define ITE8709_IIR_RFOI 0x04 /* Receiver FIFO overrun interrupt */ -+#define ITE8709_RFSR_MASK 0x3f /* FIFO byte count mask */ -+ -+/* -+ * IT8512 CIR-module registers addresses and values -+ * (from IT8512 E/F specification v0.4.1) -+ */ -+#define IT8512_REG_MSTCR 0x01 /* Master control register */ -+#define IT8512_REG_IER 0x02 /* Interrupt enable register */ -+#define IT8512_REG_CFR 0x04 /* Carrier frequency register */ -+#define IT8512_REG_RCR 0x05 /* Receive control register */ -+#define IT8512_REG_BDLR 0x08 /* Baud rate divisor low byte register */ -+#define IT8512_REG_BDHR 0x09 /* Baud rate divisor high byte register */ -+ -+#define IT8512_MSTCR_RESET 0x01 /* Reset registers to default value */ -+#define IT8512_MSTCR_FIFOCLR 0x02 /* Clear FIFO */ -+#define IT8512_MSTCR_FIFOTL_7 0x04 /* FIFO threshold level : 7 */ -+#define IT8512_MSTCR_FIFOTL_25 0x0c /* FIFO threshold level : 25 */ -+#define IT8512_IER_RDAIE 0x02 /* Enable data interrupt request */ -+#define IT8512_IER_RFOIE 0x04 /* Enable FIFO overrun interrupt req */ -+#define IT8512_IER_IEC 0x80 /* Enable interrupt request */ -+#define IT8512_CFR_CF_36KHZ 0x09 /* Carrier freq : low speed, 36kHz */ -+#define IT8512_RCR_RXDCR_1 0x01 /* Demodulation carrier range : 1 */ -+#define IT8512_RCR_RXACT 0x08 /* Receiver active */ -+#define IT8512_RCR_RXEN 0x80 /* Receiver enable */ -+#define IT8512_BDR_6 6 /* Baud rate divisor : 6 */ -+ -+/* Actual values used by this driver */ -+#define CFG_FIFOTL IT8512_MSTCR_FIFOTL_25 -+#define CFG_CR_FREQ IT8512_CFR_CF_36KHZ -+#define CFG_DCR IT8512_RCR_RXDCR_1 -+#define CFG_BDR IT8512_BDR_6 -+#define CFG_TIMEOUT 100000 /* Rearm interrupt when a space is > 100 ms */ -+ -+static int debug; -+ -+struct ite8709_device { -+ int use_count; -+ int io; -+ int irq; -+ spinlock_t hardware_lock; -+ unsigned long long acc_pulse; -+ unsigned long long acc_space; -+ char lastbit; -+ struct timeval last_tv; -+ struct lirc_driver driver; -+ struct tasklet_struct tasklet; -+ char force_rearm; -+ char rearmed; -+ char device_busy; -+}; -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+ -+static unsigned char ite8709_read(struct ite8709_device *dev, -+ unsigned char port) -+{ -+ outb(port, dev->io); -+ return inb(dev->io+1); -+} -+ -+static void ite8709_write(struct ite8709_device *dev, unsigned char port, -+ unsigned char data) -+{ -+ outb(port, dev->io); -+ outb(data, dev->io+1); -+} -+ -+static void ite8709_wait_device(struct ite8709_device *dev) -+{ -+ int i = 0; -+ /* -+ * loop until device tells it's ready to continue -+ * iterations count is usually ~750 but can sometimes achieve 13000 -+ */ -+ for (i = 0; i < 15000; i++) { -+ udelay(2); -+ if (ite8709_read(dev, ITE8709_MODE) == ITE8709_MODE_READY) -+ break; -+ } -+} -+ -+static void ite8709_write_register(struct ite8709_device *dev, -+ unsigned char reg_adr, unsigned char reg_value) -+{ -+ ite8709_wait_device(dev); -+ -+ ite8709_write(dev, ITE8709_REG_VAL, reg_value); -+ ite8709_write(dev, ITE8709_REG_ADR, reg_adr); -+ ite8709_write(dev, ITE8709_MODE, ITE8709_MODE_WRITE); -+} -+ -+static void ite8709_init_hardware(struct ite8709_device *dev) -+{ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 1; -+ spin_unlock_irq(&dev->hardware_lock); -+ -+ ite8709_write_register(dev, IT8512_REG_BDHR, (CFG_BDR >> 8) & 0xff); -+ ite8709_write_register(dev, IT8512_REG_BDLR, CFG_BDR & 0xff); -+ ite8709_write_register(dev, IT8512_REG_CFR, CFG_CR_FREQ); -+ ite8709_write_register(dev, IT8512_REG_IER, -+ IT8512_IER_IEC | IT8512_IER_RFOIE | IT8512_IER_RDAIE); -+ ite8709_write_register(dev, IT8512_REG_RCR, CFG_DCR); -+ ite8709_write_register(dev, IT8512_REG_MSTCR, -+ CFG_FIFOTL | IT8512_MSTCR_FIFOCLR); -+ ite8709_write_register(dev, IT8512_REG_RCR, -+ IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR); -+ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 0; -+ spin_unlock_irq(&dev->hardware_lock); -+ -+ tasklet_enable(&dev->tasklet); -+} -+ -+static void ite8709_drop_hardware(struct ite8709_device *dev) -+{ -+ tasklet_disable(&dev->tasklet); -+ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 1; -+ spin_unlock_irq(&dev->hardware_lock); -+ -+ ite8709_write_register(dev, IT8512_REG_RCR, 0); -+ ite8709_write_register(dev, IT8512_REG_MSTCR, -+ IT8512_MSTCR_RESET | IT8512_MSTCR_FIFOCLR); -+ -+ spin_lock_irq(&dev->hardware_lock); -+ dev->device_busy = 0; -+ spin_unlock_irq(&dev->hardware_lock); -+} -+ -+static int ite8709_set_use_inc(void *data) -+{ -+ struct ite8709_device *dev; -+ dev = data; -+ if (dev->use_count == 0) -+ ite8709_init_hardware(dev); -+ dev->use_count++; -+ return 0; -+} -+ -+static void ite8709_set_use_dec(void *data) -+{ -+ struct ite8709_device *dev; -+ dev = data; -+ dev->use_count--; -+ if (dev->use_count == 0) -+ ite8709_drop_hardware(dev); -+} -+ -+static void ite8709_add_read_queue(struct ite8709_device *dev, int flag, -+ unsigned long long val) -+{ -+ int value; -+ -+ dprintk("add a %llu usec %s\n", val, flag ? "pulse" : "space"); -+ -+ value = (val > PULSE_MASK) ? PULSE_MASK : val; -+ if (flag) -+ value |= PULSE_BIT; -+ -+ if (!lirc_buffer_full(dev->driver.rbuf)) { -+ lirc_buffer_write(dev->driver.rbuf, (void *) &value); -+ wake_up(&dev->driver.rbuf->wait_poll); -+ } -+} -+ -+static irqreturn_t ite8709_interrupt(int irq, void *dev_id) -+{ -+ unsigned char data; -+ int iir, rfsr, i; -+ int fifo = 0; -+ char bit; -+ struct timeval curr_tv; -+ -+ /* Bit duration in microseconds */ -+ const unsigned long bit_duration = 1000000ul / (115200 / CFG_BDR); -+ -+ struct ite8709_device *dev; -+ dev = dev_id; -+ -+ /* -+ * If device is busy, we simply discard data because we are in one of -+ * these two cases : shutting down or rearming the device, so this -+ * doesn't really matter and this avoids waiting too long in IRQ ctx -+ */ -+ spin_lock(&dev->hardware_lock); -+ if (dev->device_busy) { -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_HANDLED); -+ } -+ -+ iir = ite8709_read(dev, ITE8709_IIR); -+ -+ switch (iir) { -+ case ITE8709_IIR_RFOI: -+ dprintk("fifo overrun, scheduling forced rearm just in case\n"); -+ dev->force_rearm = 1; -+ tasklet_schedule(&dev->tasklet); -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_HANDLED); -+ -+ case ITE8709_IIR_RDAI: -+ rfsr = ite8709_read(dev, ITE8709_RFSR); -+ fifo = rfsr & ITE8709_RFSR_MASK; -+ if (fifo > 32) -+ fifo = 32; -+ dprintk("iir: 0x%x rfsr: 0x%x fifo: %d\n", iir, rfsr, fifo); -+ -+ if (dev->rearmed) { -+ do_gettimeofday(&curr_tv); -+ dev->acc_space += 1000000ull -+ * (curr_tv.tv_sec - dev->last_tv.tv_sec) -+ + (curr_tv.tv_usec - dev->last_tv.tv_usec); -+ dev->rearmed = 0; -+ } -+ for (i = 0; i < fifo; i++) { -+ data = ite8709_read(dev, i+ITE8709_FIFO_START); -+ data = ~data; -+ /* Loop through */ -+ for (bit = 0; bit < 8; ++bit) { -+ if ((data >> bit) & 1) { -+ dev->acc_pulse += bit_duration; -+ if (dev->lastbit == 0) { -+ ite8709_add_read_queue(dev, 0, -+ dev->acc_space); -+ dev->acc_space = 0; -+ } -+ } else { -+ dev->acc_space += bit_duration; -+ if (dev->lastbit == 1) { -+ ite8709_add_read_queue(dev, 1, -+ dev->acc_pulse); -+ dev->acc_pulse = 0; -+ } -+ } -+ dev->lastbit = (data >> bit) & 1; -+ } -+ } -+ ite8709_write(dev, ITE8709_RFSR, 0); -+ -+ if (dev->acc_space > CFG_TIMEOUT) { -+ dprintk("scheduling rearm IRQ\n"); -+ do_gettimeofday(&dev->last_tv); -+ dev->force_rearm = 0; -+ tasklet_schedule(&dev->tasklet); -+ } -+ -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_HANDLED); -+ -+ default: -+ /* not our irq */ -+ dprintk("unknown IRQ (shouldn't happen) !!\n"); -+ spin_unlock(&dev->hardware_lock); -+ return IRQ_RETVAL(IRQ_NONE); -+ } -+} -+ -+static void ite8709_rearm_irq(unsigned long data) -+{ -+ struct ite8709_device *dev; -+ unsigned long flags; -+ dev = (struct ite8709_device *) data; -+ -+ spin_lock_irqsave(&dev->hardware_lock, flags); -+ dev->device_busy = 1; -+ spin_unlock_irqrestore(&dev->hardware_lock, flags); -+ -+ if (dev->force_rearm || dev->acc_space > CFG_TIMEOUT) { -+ dprintk("rearming IRQ\n"); -+ ite8709_write_register(dev, IT8512_REG_RCR, -+ IT8512_RCR_RXACT | CFG_DCR); -+ ite8709_write_register(dev, IT8512_REG_MSTCR, -+ CFG_FIFOTL | IT8512_MSTCR_FIFOCLR); -+ ite8709_write_register(dev, IT8512_REG_RCR, -+ IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR); -+ if (!dev->force_rearm) -+ dev->rearmed = 1; -+ dev->force_rearm = 0; -+ } -+ -+ spin_lock_irqsave(&dev->hardware_lock, flags); -+ dev->device_busy = 0; -+ spin_unlock_irqrestore(&dev->hardware_lock, flags); -+} -+ -+static int ite8709_cleanup(struct ite8709_device *dev, int stage, int errno, -+ char *msg) -+{ -+ if (msg != NULL) -+ printk(KERN_ERR LIRC_DRIVER_NAME ": %s\n", msg); -+ -+ switch (stage) { -+ case 6: -+ if (dev->use_count > 0) -+ ite8709_drop_hardware(dev); -+ case 5: -+ free_irq(dev->irq, dev); -+ case 4: -+ release_region(dev->io, 2); -+ case 3: -+ lirc_unregister_driver(dev->driver.minor); -+ case 2: -+ lirc_buffer_free(dev->driver.rbuf); -+ kfree(dev->driver.rbuf); -+ case 1: -+ kfree(dev); -+ case 0: -+ ; -+ } -+ -+ return errno; -+} -+ -+static int __devinit ite8709_pnp_probe(struct pnp_dev *dev, -+ const struct pnp_device_id *dev_id) -+{ -+ struct lirc_driver *driver; -+ struct ite8709_device *ite8709_dev; -+ int ret; -+ -+ /* Check resources validity */ -+ if (!pnp_irq_valid(dev, 0)) -+ return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IRQ"); -+ if (!pnp_port_valid(dev, 2)) -+ return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IO port"); -+ -+ /* Allocate memory for device struct */ -+ ite8709_dev = kzalloc(sizeof(struct ite8709_device), GFP_KERNEL); -+ if (ite8709_dev == NULL) -+ return ite8709_cleanup(NULL, 0, -ENOMEM, "kzalloc failed"); -+ pnp_set_drvdata(dev, ite8709_dev); -+ -+ /* Initialize device struct */ -+ ite8709_dev->use_count = 0; -+ ite8709_dev->irq = pnp_irq(dev, 0); -+ ite8709_dev->io = pnp_port_start(dev, 2); -+ ite8709_dev->hardware_lock = -+ __SPIN_LOCK_UNLOCKED(ite8709_dev->hardware_lock); -+ ite8709_dev->acc_pulse = 0; -+ ite8709_dev->acc_space = 0; -+ ite8709_dev->lastbit = 0; -+ do_gettimeofday(&ite8709_dev->last_tv); -+ tasklet_init(&ite8709_dev->tasklet, ite8709_rearm_irq, -+ (long) ite8709_dev); -+ ite8709_dev->force_rearm = 0; -+ ite8709_dev->rearmed = 0; -+ ite8709_dev->device_busy = 0; -+ -+ /* Initialize driver struct */ -+ driver = &ite8709_dev->driver; -+ strcpy(driver->name, LIRC_DRIVER_NAME); -+ driver->minor = -1; -+ driver->code_length = sizeof(int) * 8; -+ driver->sample_rate = 0; -+ driver->features = LIRC_CAN_REC_MODE2; -+ driver->data = ite8709_dev; -+ driver->add_to_buf = NULL; -+ driver->set_use_inc = ite8709_set_use_inc; -+ driver->set_use_dec = ite8709_set_use_dec; -+ driver->dev = &dev->dev; -+ driver->owner = THIS_MODULE; -+ -+ /* Initialize LIRC buffer */ -+ driver->rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!driver->rbuf) -+ return ite8709_cleanup(ite8709_dev, 1, -ENOMEM, -+ "can't allocate lirc_buffer"); -+ if (lirc_buffer_init(driver->rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) -+ return ite8709_cleanup(ite8709_dev, 1, -ENOMEM, -+ "lirc_buffer_init() failed"); -+ -+ /* Register LIRC driver */ -+ ret = lirc_register_driver(driver); -+ if (ret < 0) -+ return ite8709_cleanup(ite8709_dev, 2, ret, -+ "lirc_register_driver() failed"); -+ -+ /* Reserve I/O port access */ -+ if (!request_region(ite8709_dev->io, 2, LIRC_DRIVER_NAME)) -+ return ite8709_cleanup(ite8709_dev, 3, -EBUSY, -+ "i/o port already in use"); -+ -+ /* Reserve IRQ line */ -+ ret = request_irq(ite8709_dev->irq, ite8709_interrupt, 0, -+ LIRC_DRIVER_NAME, ite8709_dev); -+ if (ret < 0) -+ return ite8709_cleanup(ite8709_dev, 4, ret, -+ "IRQ already in use"); -+ -+ /* Initialize hardware */ -+ ite8709_drop_hardware(ite8709_dev); /* Shutdown hw until first use */ -+ -+ printk(KERN_INFO LIRC_DRIVER_NAME ": device found : irq=%d io=0x%x\n", -+ ite8709_dev->irq, ite8709_dev->io); -+ -+ return 0; -+} -+ -+static void __devexit ite8709_pnp_remove(struct pnp_dev *dev) -+{ -+ struct ite8709_device *ite8709_dev; -+ ite8709_dev = pnp_get_drvdata(dev); -+ -+ ite8709_cleanup(ite8709_dev, 6, 0, NULL); -+ -+ printk(KERN_INFO LIRC_DRIVER_NAME ": device removed\n"); -+} -+ -+#ifdef CONFIG_PM -+static int ite8709_pnp_suspend(struct pnp_dev *dev, pm_message_t state) -+{ -+ struct ite8709_device *ite8709_dev; -+ ite8709_dev = pnp_get_drvdata(dev); -+ -+ if (ite8709_dev->use_count > 0) -+ ite8709_drop_hardware(ite8709_dev); -+ -+ return 0; -+} -+ -+static int ite8709_pnp_resume(struct pnp_dev *dev) -+{ -+ struct ite8709_device *ite8709_dev; -+ ite8709_dev = pnp_get_drvdata(dev); -+ -+ if (ite8709_dev->use_count > 0) -+ ite8709_init_hardware(ite8709_dev); -+ -+ return 0; -+} -+#else -+#define ite8709_pnp_suspend NULL -+#define ite8709_pnp_resume NULL -+#endif -+ -+static const struct pnp_device_id pnp_dev_table[] = { -+ {"ITE8709", 0}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -+ -+static struct pnp_driver ite8709_pnp_driver = { -+ .name = LIRC_DRIVER_NAME, -+ .probe = ite8709_pnp_probe, -+ .remove = __devexit_p(ite8709_pnp_remove), -+ .suspend = ite8709_pnp_suspend, -+ .resume = ite8709_pnp_resume, -+ .id_table = pnp_dev_table, -+}; -+ -+static int __init ite8709_init_module(void) -+{ -+ return pnp_register_driver(&ite8709_pnp_driver); -+} -+module_init(ite8709_init_module); -+ -+static void __exit ite8709_cleanup_module(void) -+{ -+ pnp_unregister_driver(&ite8709_pnp_driver); -+} -+module_exit(ite8709_cleanup_module); -+ -+MODULE_DESCRIPTION("LIRC driver for ITE8709 CIR port"); -+MODULE_AUTHOR("Grégory Lardière"); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c -new file mode 100644 -index 0000000..6da4a8c ---- /dev/null -+++ b/drivers/staging/lirc/lirc_parallel.c -@@ -0,0 +1,705 @@ -+/* -+ * lirc_parallel.c -+ * -+ * lirc_parallel - device driver for infra-red signal receiving and -+ * transmitting unit built by the author -+ * -+ * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+/*** Includes ***/ -+ -+#ifdef CONFIG_SMP -+#error "--- Sorry, this driver is not SMP safe. ---" -+#endif -+ -+#include <linux/module.h> -+#include <linux/sched.h> -+#include <linux/errno.h> -+#include <linux/signal.h> -+#include <linux/fs.h> -+#include <linux/kernel.h> -+#include <linux/ioport.h> -+#include <linux/time.h> -+#include <linux/mm.h> -+#include <linux/delay.h> -+ -+#include <linux/io.h> -+#include <linux/signal.h> -+#include <linux/irq.h> -+#include <linux/uaccess.h> -+#include <asm/div64.h> -+ -+#include <linux/poll.h> -+#include <linux/parport.h> -+ -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+ -+#include "lirc_parallel.h" -+ -+#define LIRC_DRIVER_NAME "lirc_parallel" -+ -+#ifndef LIRC_IRQ -+#define LIRC_IRQ 7 -+#endif -+#ifndef LIRC_PORT -+#define LIRC_PORT 0x378 -+#endif -+#ifndef LIRC_TIMER -+#define LIRC_TIMER 65536 -+#endif -+ -+/*** Global Variables ***/ -+ -+static int debug; -+static int check_pselecd; -+ -+unsigned int irq = LIRC_IRQ; -+unsigned int io = LIRC_PORT; -+#ifdef LIRC_TIMER -+unsigned int timer; -+unsigned int default_timer = LIRC_TIMER; -+#endif -+ -+#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */ -+ -+static int rbuf[RBUF_SIZE]; -+ -+DECLARE_WAIT_QUEUE_HEAD(lirc_wait); -+ -+unsigned int rptr; -+unsigned int wptr; -+unsigned int lost_irqs; -+int is_open; -+ -+struct parport *pport; -+struct pardevice *ppdevice; -+int is_claimed; -+ -+unsigned int tx_mask = 1; -+ -+/*** Internal Functions ***/ -+ -+static unsigned int in(int offset) -+{ -+ switch (offset) { -+ case LIRC_LP_BASE: -+ return parport_read_data(pport); -+ case LIRC_LP_STATUS: -+ return parport_read_status(pport); -+ case LIRC_LP_CONTROL: -+ return parport_read_control(pport); -+ } -+ return 0; /* make compiler happy */ -+} -+ -+static void out(int offset, int value) -+{ -+ switch (offset) { -+ case LIRC_LP_BASE: -+ parport_write_data(pport, value); -+ break; -+ case LIRC_LP_CONTROL: -+ parport_write_control(pport, value); -+ break; -+ case LIRC_LP_STATUS: -+ printk(KERN_INFO "%s: attempt to write to status register\n", -+ LIRC_DRIVER_NAME); -+ break; -+ } -+} -+ -+static unsigned int lirc_get_timer(void) -+{ -+ return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT; -+} -+ -+static unsigned int lirc_get_signal(void) -+{ -+ return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT; -+} -+ -+static void lirc_on(void) -+{ -+ out(LIRC_PORT_DATA, tx_mask); -+} -+ -+static void lirc_off(void) -+{ -+ out(LIRC_PORT_DATA, 0); -+} -+ -+static unsigned int init_lirc_timer(void) -+{ -+ struct timeval tv, now; -+ unsigned int level, newlevel, timeelapsed, newtimer; -+ int count = 0; -+ -+ do_gettimeofday(&tv); -+ tv.tv_sec++; /* wait max. 1 sec. */ -+ level = lirc_get_timer(); -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ count++; -+ level = newlevel; -+ do_gettimeofday(&now); -+ } while (count < 1000 && (now.tv_sec < tv.tv_sec -+ || (now.tv_sec == tv.tv_sec -+ && now.tv_usec < tv.tv_usec))); -+ -+ timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000 -+ + (now.tv_usec - tv.tv_usec)); -+ if (count >= 1000 && timeelapsed > 0) { -+ if (default_timer == 0) { -+ /* autodetect timer */ -+ newtimer = (1000000*count)/timeelapsed; -+ printk(KERN_INFO "%s: %u Hz timer detected\n", -+ LIRC_DRIVER_NAME, newtimer); -+ return newtimer; -+ } else { -+ newtimer = (1000000*count)/timeelapsed; -+ if (abs(newtimer - default_timer) > default_timer/10) { -+ /* bad timer */ -+ printk(KERN_NOTICE "%s: bad timer: %u Hz\n", -+ LIRC_DRIVER_NAME, newtimer); -+ printk(KERN_NOTICE "%s: using default timer: " -+ "%u Hz\n", -+ LIRC_DRIVER_NAME, default_timer); -+ return default_timer; -+ } else { -+ printk(KERN_INFO "%s: %u Hz timer detected\n", -+ LIRC_DRIVER_NAME, newtimer); -+ return newtimer; /* use detected value */ -+ } -+ } -+ } else { -+ printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME); -+ return 0; -+ } -+} -+ -+static int lirc_claim(void) -+{ -+ if (parport_claim(ppdevice) != 0) { -+ printk(KERN_WARNING "%s: could not claim port\n", -+ LIRC_DRIVER_NAME); -+ printk(KERN_WARNING "%s: waiting for port becoming available" -+ "\n", LIRC_DRIVER_NAME); -+ if (parport_claim_or_block(ppdevice) < 0) { -+ printk(KERN_NOTICE "%s: could not claim port, giving" -+ " up\n", LIRC_DRIVER_NAME); -+ return 0; -+ } -+ } -+ out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); -+ is_claimed = 1; -+ return 1; -+} -+ -+/*** interrupt handler ***/ -+ -+static void rbuf_write(int signal) -+{ -+ unsigned int nwptr; -+ -+ nwptr = (wptr + 1) & (RBUF_SIZE - 1); -+ if (nwptr == rptr) { -+ /* no new signals will be accepted */ -+ lost_irqs++; -+ printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME); -+ return; -+ } -+ rbuf[wptr] = signal; -+ wptr = nwptr; -+} -+ -+static void irq_handler(void *blah) -+{ -+ struct timeval tv; -+ static struct timeval lasttv; -+ static int init; -+ long signal; -+ int data; -+ unsigned int level, newlevel; -+ unsigned int timeout; -+ -+ if (!is_open) -+ return; -+ -+ if (!is_claimed) -+ return; -+ -+#if 0 -+ /* disable interrupt */ -+ disable_irq(irq); -+ out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN)); -+#endif -+ if (check_pselecd && (in(1) & LP_PSELECD)) -+ return; -+ -+#ifdef LIRC_TIMER -+ if (init) { -+ do_gettimeofday(&tv); -+ -+ signal = tv.tv_sec - lasttv.tv_sec; -+ if (signal > 15) -+ /* really long time */ -+ data = PULSE_MASK; -+ else -+ data = (int) (signal*1000000 + -+ tv.tv_usec - lasttv.tv_usec + -+ LIRC_SFH506_DELAY); -+ -+ rbuf_write(data); /* space */ -+ } else { -+ if (timer == 0) { -+ /* -+ * wake up; we'll lose this signal, but it will be -+ * garbage if the device is turned on anyway -+ */ -+ timer = init_lirc_timer(); -+ /* enable_irq(irq); */ -+ return; -+ } -+ init = 1; -+ } -+ -+ timeout = timer/10; /* timeout after 1/10 sec. */ -+ signal = 1; -+ level = lirc_get_timer(); -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ signal++; -+ level = newlevel; -+ -+ /* giving up */ -+ if (signal > timeout -+ || (check_pselecd && (in(1) & LP_PSELECD))) { -+ signal = 0; -+ printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME); -+ break; -+ } -+ } while (lirc_get_signal()); -+ -+ if (signal != 0) { -+ /* ajust value to usecs */ -+ unsigned long long helper; -+ -+ helper = ((unsigned long long) signal)*1000000; -+ do_div(helper, timer); -+ signal = (long) helper; -+ -+ if (signal > LIRC_SFH506_DELAY) -+ data = signal - LIRC_SFH506_DELAY; -+ else -+ data = 1; -+ rbuf_write(PULSE_BIT|data); /* pulse */ -+ } -+ do_gettimeofday(&lasttv); -+#else -+ /* add your code here */ -+#endif -+ -+ wake_up_interruptible(&lirc_wait); -+ -+ /* enable interrupt */ -+ /* -+ enable_irq(irq); -+ out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN); -+ */ -+} -+ -+/*** file operations ***/ -+ -+static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig) -+{ -+ return -ESPIPE; -+} -+ -+static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos) -+{ -+ int result = 0; -+ int count = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ -+ add_wait_queue(&lirc_wait, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ while (count < n) { -+ if (rptr != wptr) { -+ if (copy_to_user(buf+count, (char *) &rbuf[rptr], -+ sizeof(int))) { -+ result = -EFAULT; -+ break; -+ } -+ rptr = (rptr + 1) & (RBUF_SIZE - 1); -+ count += sizeof(int); -+ } else { -+ if (filep->f_flags & O_NONBLOCK) { -+ result = -EAGAIN; -+ break; -+ } -+ if (signal_pending(current)) { -+ result = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ } -+ } -+ remove_wait_queue(&lirc_wait, &wait); -+ set_current_state(TASK_RUNNING); -+ return count ? count : result; -+} -+ -+static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, -+ loff_t *ppos) -+{ -+ int count; -+ unsigned int i; -+ unsigned int level, newlevel; -+ unsigned long flags; -+ int counttimer; -+ int *wbuf; -+ -+ if (!is_claimed) -+ return -EBUSY; -+ -+ count = n / sizeof(int); -+ -+ if (n % sizeof(int) || count % 2 == 0) -+ return -EINVAL; -+ -+ wbuf = memdup_user(buf, n); -+ if (IS_ERR(wbuf)) -+ return PTR_ERR(wbuf); -+ -+#ifdef LIRC_TIMER -+ if (timer == 0) { -+ /* try again if device is ready */ -+ timer = init_lirc_timer(); -+ if (timer == 0) -+ return -EIO; -+ } -+ -+ /* adjust values from usecs */ -+ for (i = 0; i < count; i++) { -+ unsigned long long helper; -+ -+ helper = ((unsigned long long) wbuf[i])*timer; -+ do_div(helper, 1000000); -+ wbuf[i] = (int) helper; -+ } -+ -+ local_irq_save(flags); -+ i = 0; -+ while (i < count) { -+ level = lirc_get_timer(); -+ counttimer = 0; -+ lirc_on(); -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ counttimer++; -+ level = newlevel; -+ if (check_pselecd && (in(1) & LP_PSELECD)) { -+ lirc_off(); -+ local_irq_restore(flags); -+ return -EIO; -+ } -+ } while (counttimer < wbuf[i]); -+ i++; -+ -+ lirc_off(); -+ if (i == count) -+ break; -+ counttimer = 0; -+ do { -+ newlevel = lirc_get_timer(); -+ if (level == 0 && newlevel != 0) -+ counttimer++; -+ level = newlevel; -+ if (check_pselecd && (in(1) & LP_PSELECD)) { -+ local_irq_restore(flags); -+ return -EIO; -+ } -+ } while (counttimer < wbuf[i]); -+ i++; -+ } -+ local_irq_restore(flags); -+#else -+ /* place code that handles write without external timer here */ -+#endif -+ return n; -+} -+ -+static unsigned int lirc_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &lirc_wait, wait); -+ if (rptr != wptr) -+ return POLLIN | POLLRDNORM; -+ return 0; -+} -+ -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -+{ -+ int result; -+ unsigned long features = LIRC_CAN_SET_TRANSMITTER_MASK | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; -+ unsigned long mode; -+ unsigned int ivalue; -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ result = put_user(features, (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ case LIRC_GET_SEND_MODE: -+ result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ case LIRC_GET_REC_MODE: -+ result = put_user(LIRC_MODE_MODE2, (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ case LIRC_SET_SEND_MODE: -+ result = get_user(mode, (unsigned long *) arg); -+ if (result) -+ return result; -+ if (mode != LIRC_MODE_PULSE) -+ return -EINVAL; -+ break; -+ case LIRC_SET_REC_MODE: -+ result = get_user(mode, (unsigned long *) arg); -+ if (result) -+ return result; -+ if (mode != LIRC_MODE_MODE2) -+ return -ENOSYS; -+ break; -+ case LIRC_SET_TRANSMITTER_MASK: -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ if ((ivalue & LIRC_PARALLEL_TRANSMITTER_MASK) != ivalue) -+ return LIRC_PARALLEL_MAX_TRANSMITTERS; -+ tx_mask = ivalue; -+ break; -+ default: -+ return -ENOIOCTLCMD; -+ } -+ return 0; -+} -+ -+static int lirc_open(struct inode *node, struct file *filep) -+{ -+ if (is_open || !lirc_claim()) -+ return -EBUSY; -+ -+ parport_enable_irq(pport); -+ -+ /* init read ptr */ -+ rptr = 0; -+ wptr = 0; -+ lost_irqs = 0; -+ -+ is_open = 1; -+ return 0; -+} -+ -+static int lirc_close(struct inode *node, struct file *filep) -+{ -+ if (is_claimed) { -+ is_claimed = 0; -+ parport_release(ppdevice); -+ } -+ is_open = 0; -+ return 0; -+} -+ -+static const struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .llseek = lirc_lseek, -+ .read = lirc_read, -+ .write = lirc_write, -+ .poll = lirc_poll, -+ .unlocked_ioctl = lirc_ioctl, -+ .open = lirc_open, -+ .release = lirc_close -+}; -+ -+static int set_use_inc(void *data) -+{ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+} -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+static int pf(void *handle); -+static void kf(void *handle); -+ -+static struct timer_list poll_timer; -+static void poll_state(unsigned long ignored); -+ -+static void poll_state(unsigned long ignored) -+{ -+ printk(KERN_NOTICE "%s: time\n", -+ LIRC_DRIVER_NAME); -+ del_timer(&poll_timer); -+ if (is_claimed) -+ return; -+ kf(NULL); -+ if (!is_claimed) { -+ printk(KERN_NOTICE "%s: could not claim port, giving up\n", -+ LIRC_DRIVER_NAME); -+ init_timer(&poll_timer); -+ poll_timer.expires = jiffies + HZ; -+ poll_timer.data = (unsigned long)current; -+ poll_timer.function = poll_state; -+ add_timer(&poll_timer); -+ } -+} -+ -+static int pf(void *handle) -+{ -+ parport_disable_irq(pport); -+ is_claimed = 0; -+ return 0; -+} -+ -+static void kf(void *handle) -+{ -+ if (!is_open) -+ return; -+ if (!lirc_claim()) -+ return; -+ parport_enable_irq(pport); -+ lirc_off(); -+ /* this is a bit annoying when you actually print...*/ -+ /* -+ printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME); -+ */ -+} -+ -+/*** module initialization and cleanup ***/ -+ -+static int __init lirc_parallel_init(void) -+{ -+ pport = parport_find_base(io); -+ if (pport == NULL) { -+ printk(KERN_NOTICE "%s: no port at %x found\n", -+ LIRC_DRIVER_NAME, io); -+ return -ENXIO; -+ } -+ ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME, -+ pf, kf, irq_handler, 0, NULL); -+ parport_put_port(pport); -+ if (ppdevice == NULL) { -+ printk(KERN_NOTICE "%s: parport_register_device() failed\n", -+ LIRC_DRIVER_NAME); -+ return -ENXIO; -+ } -+ if (parport_claim(ppdevice) != 0) -+ goto skip_init; -+ is_claimed = 1; -+ out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); -+ -+#ifdef LIRC_TIMER -+ if (debug) -+ out(LIRC_PORT_DATA, tx_mask); -+ -+ timer = init_lirc_timer(); -+ -+#if 0 /* continue even if device is offline */ -+ if (timer == 0) { -+ is_claimed = 0; -+ parport_release(pport); -+ parport_unregister_device(ppdevice); -+ return -EIO; -+ } -+ -+#endif -+ if (debug) -+ out(LIRC_PORT_DATA, 0); -+#endif -+ -+ is_claimed = 0; -+ parport_release(ppdevice); -+ skip_init: -+ driver.minor = lirc_register_driver(&driver); -+ if (driver.minor < 0) { -+ printk(KERN_NOTICE "%s: register_chrdev() failed\n", -+ LIRC_DRIVER_NAME); -+ parport_unregister_device(ppdevice); -+ return -EIO; -+ } -+ printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n", -+ LIRC_DRIVER_NAME, io, irq); -+ return 0; -+} -+ -+static void __exit lirc_parallel_exit(void) -+{ -+ parport_unregister_device(ppdevice); -+ lirc_unregister_driver(driver.minor); -+} -+ -+module_init(lirc_parallel_init); -+module_exit(lirc_parallel_exit); -+ -+MODULE_DESCRIPTION("Infrared receiver driver for parallel ports."); -+MODULE_AUTHOR("Christoph Bartelmus"); -+MODULE_LICENSE("GPL"); -+ -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)"); -+ -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (7 or 5)"); -+ -+module_param(tx_mask, int, S_IRUGO); -+MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_param(check_pselecd, bool, S_IRUGO | S_IWUSR); -+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 0000000..4bed6af ---- /dev/null -+++ b/drivers/staging/lirc/lirc_parallel.h -@@ -0,0 +1,26 @@ -+/* lirc_parallel.h */ -+ -+#ifndef _LIRC_PARALLEL_H -+#define _LIRC_PARALLEL_H -+ -+#include <linux/lp.h> -+ -+#define LIRC_PORT_LEN 3 -+ -+#define LIRC_LP_BASE 0 -+#define LIRC_LP_STATUS 1 -+#define LIRC_LP_CONTROL 2 -+ -+#define LIRC_PORT_DATA LIRC_LP_BASE /* base */ -+#define LIRC_PORT_TIMER LIRC_LP_STATUS /* status port */ -+#define LIRC_PORT_TIMER_BIT LP_PBUSY /* busy signal */ -+#define LIRC_PORT_SIGNAL LIRC_LP_STATUS /* status port */ -+#define LIRC_PORT_SIGNAL_BIT LP_PACK /* ack signal */ -+#define LIRC_PORT_IRQ LIRC_LP_CONTROL /* control port */ -+ -+#define LIRC_SFH506_DELAY 0 /* delay t_phl in usecs */ -+ -+#define LIRC_PARALLEL_MAX_TRANSMITTERS 8 -+#define LIRC_PARALLEL_TRANSMITTER_MASK ((1<<LIRC_PARALLEL_MAX_TRANSMITTERS) - 1) -+ -+#endif -diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/lirc/lirc_sasem.c -new file mode 100644 -index 0000000..73166c3 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_sasem.c -@@ -0,0 +1,933 @@ -+/* -+ * lirc_sasem.c - USB remote support for LIRC -+ * Version 0.5 -+ * -+ * Copyright (C) 2004-2005 Oliver Stabel <oliver.stabel@gmx.de> -+ * Tim Davies <tim@opensystems.net.au> -+ * -+ * This driver was derived from: -+ * Venky Raju <dev@venky.ws> -+ * "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD" -+ * Paul Miller <pmiller9@users.sourceforge.net>'s 2003-2004 -+ * "lirc_atiusb - USB remote support for LIRC" -+ * Culver Consulting Services <henry@culcon.com>'s 2003 -+ * "Sasem OnAir VFD/IR USB driver" -+ * -+ * -+ * NOTE - The LCDproc iMon driver should work with this module. More info at -+ * http://www.frogstorm.info/sasem -+ */ -+ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/usb.h> -+ -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+ -+ -+#define MOD_AUTHOR "Oliver Stabel <oliver.stabel@gmx.de>, " \ -+ "Tim Davies <tim@opensystems.net.au>" -+#define MOD_DESC "USB Driver for Sasem Remote Controller V1.1" -+#define MOD_NAME "lirc_sasem" -+#define MOD_VERSION "0.5" -+ -+#define VFD_MINOR_BASE 144 /* Same as LCD */ -+#define DEVICE_NAME "lcd%d" -+ -+#define BUF_CHUNK_SIZE 8 -+#define BUF_SIZE 128 -+ -+#define IOCTL_LCD_CONTRAST 1 -+ -+/*** P R O T O T Y P E S ***/ -+ -+/* USB Callback prototypes */ -+static int sasem_probe(struct usb_interface *interface, -+ const struct usb_device_id *id); -+static void sasem_disconnect(struct usb_interface *interface); -+static void usb_rx_callback(struct urb *urb); -+static void usb_tx_callback(struct urb *urb); -+ -+/* VFD file_operations function prototypes */ -+static int vfd_open(struct inode *inode, struct file *file); -+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg); -+static int vfd_close(struct inode *inode, struct file *file); -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/* LIRC driver function prototypes */ -+static int ir_open(void *data); -+static void ir_close(void *data); -+ -+/* Driver init/exit prototypes */ -+static int __init sasem_init(void); -+static void __exit sasem_exit(void); -+ -+/*** G L O B A L S ***/ -+#define SASEM_DATA_BUF_SZ 32 -+ -+struct sasem_context { -+ -+ struct usb_device *dev; -+ int vfd_isopen; /* VFD port has been opened */ -+ unsigned int vfd_contrast; /* VFD contrast */ -+ int ir_isopen; /* IR port has been opened */ -+ int dev_present; /* USB device presence */ -+ struct mutex ctx_lock; /* to lock this object */ -+ wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ -+ -+ struct lirc_driver *driver; -+ struct usb_endpoint_descriptor *rx_endpoint; -+ struct usb_endpoint_descriptor *tx_endpoint; -+ struct urb *rx_urb; -+ struct urb *tx_urb; -+ unsigned char usb_rx_buf[8]; -+ unsigned char usb_tx_buf[8]; -+ -+ struct tx_t { -+ unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data buffer */ -+ struct completion finished; /* wait for write to finish */ -+ atomic_t busy; /* write in progress */ -+ int status; /* status of tx completion */ -+ } tx; -+ -+ /* for dealing with repeat codes (wish there was a toggle bit!) */ -+ struct timeval presstime; -+ char lastcode[8]; -+ int codesaved; -+}; -+ -+/* VFD file operations */ -+static const struct file_operations vfd_fops = { -+ .owner = THIS_MODULE, -+ .open = &vfd_open, -+ .write = &vfd_write, -+ .unlocked_ioctl = &vfd_ioctl, -+ .release = &vfd_close, -+}; -+ -+/* USB Device ID for Sasem USB Control Board */ -+static struct usb_device_id sasem_usb_id_table[] = { -+ /* Sasem USB Control Board */ -+ { USB_DEVICE(0x11ba, 0x0101) }, -+ /* Terminating entry */ -+ {} -+}; -+ -+/* USB Device data */ -+static struct usb_driver sasem_driver = { -+ .name = MOD_NAME, -+ .probe = sasem_probe, -+ .disconnect = sasem_disconnect, -+ .id_table = sasem_usb_id_table, -+}; -+ -+static struct usb_class_driver sasem_class = { -+ .name = DEVICE_NAME, -+ .fops = &vfd_fops, -+ .minor_base = VFD_MINOR_BASE, -+}; -+ -+/* to prevent races between open() and disconnect() */ -+static DEFINE_MUTEX(disconnect_lock); -+ -+static int debug; -+ -+ -+/*** M O D U L E C O D E ***/ -+ -+MODULE_AUTHOR(MOD_AUTHOR); -+MODULE_DESCRIPTION(MOD_DESC); -+MODULE_LICENSE("GPL"); -+module_param(debug, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)"); -+ -+static void delete_context(struct sasem_context *context) -+{ -+ usb_free_urb(context->tx_urb); /* VFD */ -+ usb_free_urb(context->rx_urb); /* IR */ -+ lirc_buffer_free(context->driver->rbuf); -+ kfree(context->driver->rbuf); -+ kfree(context->driver); -+ kfree(context); -+ -+ if (debug) -+ printk(KERN_INFO "%s: context deleted\n", __func__); -+} -+ -+static void deregister_from_lirc(struct sasem_context *context) -+{ -+ int retval; -+ int minor = context->driver->minor; -+ -+ retval = lirc_unregister_driver(minor); -+ if (retval) -+ err("%s: unable to deregister from lirc (%d)", -+ __func__, retval); -+ else -+ printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n", -+ minor); -+ -+} -+ -+/** -+ * Called when the VFD device (e.g. /dev/usb/lcd) -+ * is opened by the application. -+ */ -+static int vfd_open(struct inode *inode, struct file *file) -+{ -+ struct usb_interface *interface; -+ struct sasem_context *context = NULL; -+ int subminor; -+ int retval = 0; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&disconnect_lock); -+ -+ subminor = iminor(inode); -+ interface = usb_find_interface(&sasem_driver, subminor); -+ if (!interface) { -+ err("%s: could not find interface for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ context = usb_get_intfdata(interface); -+ -+ if (!context) { -+ err("%s: no context found for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (context->vfd_isopen) { -+ err("%s: VFD port is already open", __func__); -+ retval = -EBUSY; -+ } else { -+ context->vfd_isopen = 1; -+ file->private_data = context; -+ printk(KERN_INFO "VFD port opened\n"); -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ -+exit: -+ mutex_unlock(&disconnect_lock); -+ return retval; -+} -+ -+/** -+ * Called when the VFD device (e.g. /dev/usb/lcd) -+ * is closed by the application. -+ */ -+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg) -+{ -+ struct sasem_context *context = NULL; -+ -+ context = (struct sasem_context *) file->private_data; -+ -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ switch (cmd) { -+ case IOCTL_LCD_CONTRAST: -+ if (arg > 1000) -+ arg = 1000; -+ context->vfd_contrast = (unsigned int)arg; -+ break; -+ default: -+ printk(KERN_INFO "Unknown IOCTL command\n"); -+ mutex_unlock(&context->ctx_lock); -+ return -ENOIOCTLCMD; /* not supported */ -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return 0; -+} -+ -+/** -+ * Called when the VFD device (e.g. /dev/usb/lcd) -+ * is closed by the application. -+ */ -+static int vfd_close(struct inode *inode, struct file *file) -+{ -+ struct sasem_context *context = NULL; -+ int retval = 0; -+ -+ context = (struct sasem_context *) file->private_data; -+ -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->vfd_isopen) { -+ err("%s: VFD is not open", __func__); -+ retval = -EIO; -+ } else { -+ context->vfd_isopen = 0; -+ printk(KERN_INFO "VFD port closed\n"); -+ if (!context->dev_present && !context->ir_isopen) { -+ -+ /* Device disconnected before close and IR port is -+ * not open. If IR port is open, context will be -+ * deleted by ir_close. */ -+ mutex_unlock(&context->ctx_lock); -+ delete_context(context); -+ return retval; -+ } -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return retval; -+} -+ -+/** -+ * Sends a packet to the VFD. -+ */ -+static int send_packet(struct sasem_context *context) -+{ -+ unsigned int pipe; -+ int interval = 0; -+ int retval = 0; -+ -+ pipe = usb_sndintpipe(context->dev, -+ context->tx_endpoint->bEndpointAddress); -+ interval = context->tx_endpoint->bInterval; -+ -+ usb_fill_int_urb(context->tx_urb, context->dev, pipe, -+ context->usb_tx_buf, sizeof(context->usb_tx_buf), -+ usb_tx_callback, context, interval); -+ -+ context->tx_urb->actual_length = 0; -+ -+ init_completion(&context->tx.finished); -+ atomic_set(&(context->tx.busy), 1); -+ -+ retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); -+ if (retval) { -+ atomic_set(&(context->tx.busy), 0); -+ err("%s: error submitting urb (%d)", __func__, retval); -+ } else { -+ /* Wait for transmission to complete (or abort) */ -+ mutex_unlock(&context->ctx_lock); -+ wait_for_completion(&context->tx.finished); -+ mutex_lock(&context->ctx_lock); -+ -+ retval = context->tx.status; -+ if (retval) -+ err("%s: packet tx failed (%d)", __func__, retval); -+ } -+ -+ return retval; -+} -+ -+/** -+ * Writes data to the VFD. The Sasem VFD is 2x16 characters -+ * and requires data in 9 consecutive USB interrupt packets, -+ * each packet carrying 8 bytes. -+ */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int i; -+ int retval = 0; -+ struct sasem_context *context; -+ int *data_buf; -+ -+ context = (struct sasem_context *) file->private_data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (!context->dev_present) { -+ err("%s: no Sasem device present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) { -+ err("%s: invalid payload size", __func__); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ data_buf = memdup_user(buf, n_bytes); -+ if (PTR_ERR(data_buf)) -+ return PTR_ERR(data_buf); -+ -+ memcpy(context->tx.data_buf, data_buf, n_bytes); -+ -+ /* Pad with spaces */ -+ for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i) -+ context->tx.data_buf[i] = ' '; -+ -+ /* Nine 8 byte packets to be sent */ -+ /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0" -+ * will clear the VFD */ -+ for (i = 0; i < 9; i++) { -+ switch (i) { -+ case 0: -+ memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8); -+ context->usb_tx_buf[1] = (context->vfd_contrast) ? -+ (0x2B - (context->vfd_contrast - 1) / 250) -+ : 0x2B; -+ break; -+ case 1: -+ memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); -+ break; -+ case 2: -+ memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8); -+ break; -+ case 3: -+ memcpy(context->usb_tx_buf, context->tx.data_buf, 8); -+ break; -+ case 4: -+ memcpy(context->usb_tx_buf, -+ context->tx.data_buf + 8, 8); -+ break; -+ case 5: -+ memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8); -+ break; -+ case 6: -+ memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8); -+ break; -+ case 7: -+ memcpy(context->usb_tx_buf, -+ context->tx.data_buf + 16, 8); -+ break; -+ case 8: -+ memcpy(context->usb_tx_buf, -+ context->tx.data_buf + 24, 8); -+ break; -+ } -+ retval = send_packet(context); -+ if (retval) { -+ -+ err("%s: send packet failed for packet #%d", -+ __func__, i); -+ goto exit; -+ } -+ } -+exit: -+ -+ mutex_unlock(&context->ctx_lock); -+ -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Callback function for USB core API: transmit data -+ */ -+static void usb_tx_callback(struct urb *urb) -+{ -+ struct sasem_context *context; -+ -+ if (!urb) -+ return; -+ context = (struct sasem_context *) urb->context; -+ if (!context) -+ return; -+ -+ context->tx.status = urb->status; -+ -+ /* notify waiters that write has finished */ -+ atomic_set(&context->tx.busy, 0); -+ complete(&context->tx.finished); -+ -+ return; -+} -+ -+/** -+ * Called by lirc_dev when the application opens /dev/lirc -+ */ -+static int ir_open(void *data) -+{ -+ int retval = 0; -+ struct sasem_context *context; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&disconnect_lock); -+ -+ context = (struct sasem_context *) data; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ if (context->ir_isopen) { -+ err("%s: IR port is already open", __func__); -+ retval = -EBUSY; -+ goto exit; -+ } -+ -+ usb_fill_int_urb(context->rx_urb, context->dev, -+ usb_rcvintpipe(context->dev, -+ context->rx_endpoint->bEndpointAddress), -+ context->usb_rx_buf, sizeof(context->usb_rx_buf), -+ usb_rx_callback, context, context->rx_endpoint->bInterval); -+ -+ retval = usb_submit_urb(context->rx_urb, GFP_KERNEL); -+ -+ if (retval) -+ err("%s: usb_submit_urb failed for ir_open (%d)", -+ __func__, retval); -+ else { -+ context->ir_isopen = 1; -+ printk(KERN_INFO "IR port opened\n"); -+ } -+ -+exit: -+ mutex_unlock(&context->ctx_lock); -+ -+ mutex_unlock(&disconnect_lock); -+ return 0; -+} -+ -+/** -+ * Called by lirc_dev when the application closes /dev/lirc -+ */ -+static void ir_close(void *data) -+{ -+ struct sasem_context *context; -+ -+ context = (struct sasem_context *)data; -+ if (!context) { -+ err("%s: no context for device", __func__); -+ return; -+ } -+ -+ mutex_lock(&context->ctx_lock); -+ -+ usb_kill_urb(context->rx_urb); -+ context->ir_isopen = 0; -+ printk(KERN_INFO "IR port closed\n"); -+ -+ if (!context->dev_present) { -+ -+ /* -+ * Device disconnected while IR port was -+ * still open. Driver was not deregistered -+ * at disconnect time, so do it now. -+ */ -+ deregister_from_lirc(context); -+ -+ if (!context->vfd_isopen) { -+ -+ mutex_unlock(&context->ctx_lock); -+ delete_context(context); -+ return; -+ } -+ /* If VFD port is open, context will be deleted by vfd_close */ -+ } -+ -+ mutex_unlock(&context->ctx_lock); -+ return; -+} -+ -+/** -+ * Process the incoming packet -+ */ -+static void incoming_packet(struct sasem_context *context, -+ struct urb *urb) -+{ -+ int len = urb->actual_length; -+ unsigned char *buf = urb->transfer_buffer; -+ long ms; -+ struct timeval tv; -+ -+ if (len != 8) { -+ printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n", -+ __func__, len); -+ return; -+ } -+ -+#ifdef DEBUG -+ int i; -+ for (i = 0; i < 8; ++i) -+ printk(KERN_INFO "%02x ", buf[i]); -+ printk(KERN_INFO "\n"); -+#endif -+ -+ /* -+ * Lirc could deal with the repeat code, but we really need to block it -+ * if it arrives too late. Otherwise we could repeat the wrong code. -+ */ -+ -+ /* get the time since the last button press */ -+ do_gettimeofday(&tv); -+ ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 + -+ (tv.tv_usec - context->presstime.tv_usec) / 1000; -+ -+ if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) { -+ /* -+ * the repeat code is being sent, so we copy -+ * the old code to LIRC -+ */ -+ -+ /* -+ * NOTE: Only if the last code was less than 250ms ago -+ * - no one should be able to push another (undetected) button -+ * in that time and then get a false repeat of the previous -+ * press but it is long enough for a genuine repeat -+ */ -+ if ((ms < 250) && (context->codesaved != 0)) { -+ memcpy(buf, &context->lastcode, 8); -+ context->presstime.tv_sec = tv.tv_sec; -+ context->presstime.tv_usec = tv.tv_usec; -+ } -+ } else { -+ /* save the current valid code for repeats */ -+ memcpy(&context->lastcode, buf, 8); -+ /* -+ * set flag to signal a valid code was save; -+ * just for safety reasons -+ */ -+ context->codesaved = 1; -+ context->presstime.tv_sec = tv.tv_sec; -+ context->presstime.tv_usec = tv.tv_usec; -+ } -+ -+ lirc_buffer_write(context->driver->rbuf, buf); -+ wake_up(&context->driver->rbuf->wait_poll); -+} -+ -+/** -+ * Callback function for USB core API: receive data -+ */ -+static void usb_rx_callback(struct urb *urb) -+{ -+ struct sasem_context *context; -+ -+ if (!urb) -+ return; -+ context = (struct sasem_context *) urb->context; -+ if (!context) -+ return; -+ -+ switch (urb->status) { -+ -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case 0: -+ if (context->ir_isopen) -+ incoming_packet(context, urb); -+ break; -+ -+ default: -+ printk(KERN_WARNING "%s: status (%d): ignored", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(context->rx_urb, GFP_ATOMIC); -+ return; -+} -+ -+ -+ -+/** -+ * Callback function for USB core API: Probe -+ */ -+static int sasem_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *dev = NULL; -+ struct usb_host_interface *iface_desc = NULL; -+ struct usb_endpoint_descriptor *rx_endpoint = NULL; -+ struct usb_endpoint_descriptor *tx_endpoint = NULL; -+ struct urb *rx_urb = NULL; -+ struct urb *tx_urb = NULL; -+ struct lirc_driver *driver = NULL; -+ struct lirc_buffer *rbuf = NULL; -+ int lirc_minor = 0; -+ int num_endpoints; -+ int retval = 0; -+ int vfd_ep_found; -+ int ir_ep_found; -+ int alloc_status; -+ struct sasem_context *context = NULL; -+ int i; -+ -+ printk(KERN_INFO "%s: found Sasem device\n", __func__); -+ -+ -+ dev = usb_get_dev(interface_to_usbdev(interface)); -+ iface_desc = interface->cur_altsetting; -+ num_endpoints = iface_desc->desc.bNumEndpoints; -+ -+ /* -+ * Scan the endpoint list and set: -+ * first input endpoint = IR endpoint -+ * first output endpoint = VFD endpoint -+ */ -+ -+ ir_ep_found = 0; -+ vfd_ep_found = 0; -+ -+ for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) { -+ -+ struct usb_endpoint_descriptor *ep; -+ int ep_dir; -+ int ep_type; -+ ep = &iface_desc->endpoint [i].desc; -+ ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; -+ ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ -+ if (!ir_ep_found && -+ ep_dir == USB_DIR_IN && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ rx_endpoint = ep; -+ ir_ep_found = 1; -+ if (debug) -+ printk(KERN_INFO "%s: found IR endpoint\n", -+ __func__); -+ -+ } else if (!vfd_ep_found && -+ ep_dir == USB_DIR_OUT && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ tx_endpoint = ep; -+ vfd_ep_found = 1; -+ if (debug) -+ printk(KERN_INFO "%s: found VFD endpoint\n", -+ __func__); -+ } -+ } -+ -+ /* Input endpoint is mandatory */ -+ if (!ir_ep_found) { -+ -+ err("%s: no valid input (IR) endpoint found.", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (!vfd_ep_found) -+ printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n", -+ __func__); -+ -+ -+ /* Allocate memory */ -+ alloc_status = 0; -+ -+ context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL); -+ if (!context) { -+ err("%s: kzalloc failed for context", __func__); -+ alloc_status = 1; -+ goto alloc_status_switch; -+ } -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) { -+ err("%s: kzalloc failed for lirc_driver", __func__); -+ alloc_status = 2; -+ goto alloc_status_switch; -+ } -+ rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!rbuf) { -+ err("%s: kmalloc failed for lirc_buffer", __func__); -+ alloc_status = 3; -+ goto alloc_status_switch; -+ } -+ if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) { -+ err("%s: lirc_buffer_init failed", __func__); -+ alloc_status = 4; -+ goto alloc_status_switch; -+ } -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ err("%s: usb_alloc_urb failed for IR urb", __func__); -+ alloc_status = 5; -+ goto alloc_status_switch; -+ } -+ if (vfd_ep_found) { -+ tx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!tx_urb) { -+ err("%s: usb_alloc_urb failed for VFD urb", -+ __func__); -+ alloc_status = 6; -+ goto alloc_status_switch; -+ } -+ } -+ -+ mutex_init(&context->ctx_lock); -+ -+ strcpy(driver->name, MOD_NAME); -+ driver->minor = -1; -+ driver->code_length = 64; -+ driver->sample_rate = 0; -+ driver->features = LIRC_CAN_REC_LIRCCODE; -+ driver->data = context; -+ driver->rbuf = rbuf; -+ driver->set_use_inc = ir_open; -+ driver->set_use_dec = ir_close; -+ driver->dev = &interface->dev; -+ driver->owner = THIS_MODULE; -+ -+ mutex_lock(&context->ctx_lock); -+ -+ lirc_minor = lirc_register_driver(driver); -+ if (lirc_minor < 0) { -+ err("%s: lirc_register_driver failed", __func__); -+ alloc_status = 7; -+ mutex_unlock(&context->ctx_lock); -+ } else -+ printk(KERN_INFO "%s: Registered Sasem driver (minor:%d)\n", -+ __func__, lirc_minor); -+ -+alloc_status_switch: -+ -+ switch (alloc_status) { -+ -+ case 7: -+ if (vfd_ep_found) -+ usb_free_urb(tx_urb); -+ case 6: -+ usb_free_urb(rx_urb); -+ case 5: -+ lirc_buffer_free(rbuf); -+ case 4: -+ kfree(rbuf); -+ case 3: -+ kfree(driver); -+ case 2: -+ kfree(context); -+ context = NULL; -+ case 1: -+ retval = -ENOMEM; -+ goto exit; -+ } -+ -+ /* Needed while unregistering! */ -+ driver->minor = lirc_minor; -+ -+ context->dev = dev; -+ context->dev_present = 1; -+ context->rx_endpoint = rx_endpoint; -+ context->rx_urb = rx_urb; -+ if (vfd_ep_found) { -+ context->tx_endpoint = tx_endpoint; -+ context->tx_urb = tx_urb; -+ context->vfd_contrast = 1000; /* range 0 - 1000 */ -+ } -+ context->driver = driver; -+ -+ usb_set_intfdata(interface, context); -+ -+ if (vfd_ep_found) { -+ -+ if (debug) -+ printk(KERN_INFO "Registering VFD with sysfs\n"); -+ if (usb_register_dev(interface, &sasem_class)) -+ /* Not a fatal error, so ignore */ -+ printk(KERN_INFO "%s: could not get a minor number " -+ "for VFD\n", __func__); -+ } -+ -+ printk(KERN_INFO "%s: Sasem device on usb<%d:%d> initialized\n", -+ __func__, dev->bus->busnum, dev->devnum); -+ -+ mutex_unlock(&context->ctx_lock); -+exit: -+ return retval; -+} -+ -+/** -+ * Callback function for USB core API: disonnect -+ */ -+static void sasem_disconnect(struct usb_interface *interface) -+{ -+ struct sasem_context *context; -+ -+ /* prevent races with ir_open()/vfd_open() */ -+ mutex_lock(&disconnect_lock); -+ -+ context = usb_get_intfdata(interface); -+ mutex_lock(&context->ctx_lock); -+ -+ printk(KERN_INFO "%s: Sasem device disconnected\n", __func__); -+ -+ usb_set_intfdata(interface, NULL); -+ context->dev_present = 0; -+ -+ /* Stop reception */ -+ usb_kill_urb(context->rx_urb); -+ -+ /* Abort ongoing write */ -+ if (atomic_read(&context->tx.busy)) { -+ -+ usb_kill_urb(context->tx_urb); -+ wait_for_completion(&context->tx.finished); -+ } -+ -+ /* De-register from lirc_dev if IR port is not open */ -+ if (!context->ir_isopen) -+ deregister_from_lirc(context); -+ -+ usb_deregister_dev(interface, &sasem_class); -+ -+ mutex_unlock(&context->ctx_lock); -+ -+ if (!context->ir_isopen && !context->vfd_isopen) -+ delete_context(context); -+ -+ mutex_unlock(&disconnect_lock); -+} -+ -+static int __init sasem_init(void) -+{ -+ int rc; -+ -+ printk(KERN_INFO MOD_DESC ", v" MOD_VERSION "\n"); -+ printk(KERN_INFO MOD_AUTHOR "\n"); -+ -+ rc = usb_register(&sasem_driver); -+ if (rc < 0) { -+ err("%s: usb register failed (%d)", __func__, rc); -+ return -ENODEV; -+ } -+ return 0; -+} -+ -+static void __exit sasem_exit(void) -+{ -+ usb_deregister(&sasem_driver); -+ printk(KERN_INFO "module removed. Goodbye!\n"); -+} -+ -+ -+module_init(sasem_init); -+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 0000000..9456f8e ---- /dev/null -+++ b/drivers/staging/lirc/lirc_serial.c -@@ -0,0 +1,1313 @@ -+/* -+ * lirc_serial.c -+ * -+ * lirc_serial - Device driver that records pulse- and pause-lengths -+ * (space-lengths) between DDCD event on a serial port. -+ * -+ * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de> -+ * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu> -+ * Copyright (C) 1998 Ben Pfaff <blp@gnu.org> -+ * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de> -+ * Copyright (C) 2007 Andrei Tanas <andrei@tanas.ca> (suspend/resume support) -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+/* -+ * Steve's changes to improve transmission fidelity: -+ * - for systems with the rdtsc instruction and the clock counter, a -+ * send_pule that times the pulses directly using the counter. -+ * This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is -+ * not needed. Measurement shows very stable waveform, even where -+ * PCI activity slows the access to the UART, which trips up other -+ * versions. -+ * - For other system, non-integer-microsecond pulse/space lengths, -+ * done using fixed point binary. So, much more accurate carrier -+ * frequency. -+ * - fine tuned transmitter latency, taking advantage of fractional -+ * microseconds in previous change -+ * - Fixed bug in the way transmitter latency was accounted for by -+ * tuning the pulse lengths down - the send_pulse routine ignored -+ * this overhead as it timed the overall pulse length - so the -+ * pulse frequency was right but overall pulse length was too -+ * long. Fixed by accounting for latency on each pulse/space -+ * iteration. -+ * -+ * Steve Davies <steve@daviesfam.org> July 2001 -+ */ -+ -+#include <linux/module.h> -+#include <linux/errno.h> -+#include <linux/signal.h> -+#include <linux/sched.h> -+#include <linux/fs.h> -+#include <linux/interrupt.h> -+#include <linux/ioport.h> -+#include <linux/kernel.h> -+#include <linux/serial_reg.h> -+#include <linux/time.h> -+#include <linux/string.h> -+#include <linux/types.h> -+#include <linux/wait.h> -+#include <linux/mm.h> -+#include <linux/delay.h> -+#include <linux/poll.h> -+#include <linux/platform_device.h> -+ -+#include <asm/system.h> -+#include <linux/io.h> -+#include <linux/irq.h> -+#include <linux/fcntl.h> -+#include <linux/spinlock.h> -+ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+#include <asm/hardware.h> -+#endif -+/* From Intel IXP42X Developer's Manual (#252480-005): */ -+/* ftp://download.intel.com/design/network/manuals/25248005.pdf */ -+#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ -+#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ -+ -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+ -+#define LIRC_DRIVER_NAME "lirc_serial" -+ -+struct lirc_serial { -+ int signal_pin; -+ int signal_pin_change; -+ u8 on; -+ u8 off; -+ long (*send_pulse)(unsigned long length); -+ void (*send_space)(long length); -+ int features; -+ spinlock_t lock; -+}; -+ -+#define LIRC_HOMEBREW 0 -+#define LIRC_IRDEO 1 -+#define LIRC_IRDEO_REMOTE 2 -+#define LIRC_ANIMAX 3 -+#define LIRC_IGOR 4 -+#define LIRC_NSLU2 5 -+ -+/*** module parameters ***/ -+static int type; -+static int io; -+static int irq; -+static int iommap; -+static int ioshift; -+static int softcarrier = 1; -+static int share_irq; -+static int debug; -+static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ -+static int txsense; /* 0 = active high, 1 = active low */ -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+/* forward declarations */ -+static long send_pulse_irdeo(unsigned long length); -+static long send_pulse_homebrew(unsigned long length); -+static void send_space_irdeo(long length); -+static void send_space_homebrew(long length); -+ -+static struct lirc_serial hardware[] = { -+ [LIRC_HOMEBREW] = { -+ .signal_pin = UART_MSR_DCD, -+ .signal_pin_change = UART_MSR_DDCD, -+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), -+ .off = (UART_MCR_RTS | UART_MCR_OUT2), -+ .send_pulse = send_pulse_homebrew, -+ .send_space = send_space_homebrew, -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+#else -+ .features = LIRC_CAN_REC_MODE2 -+#endif -+ }, -+ -+ [LIRC_IRDEO] = { -+ .signal_pin = UART_MSR_DSR, -+ .signal_pin_change = UART_MSR_DDSR, -+ .on = UART_MCR_OUT2, -+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .send_pulse = send_pulse_irdeo, -+ .send_space = send_space_irdeo, -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+ }, -+ -+ [LIRC_IRDEO_REMOTE] = { -+ .signal_pin = UART_MSR_DSR, -+ .signal_pin_change = UART_MSR_DDSR, -+ .on = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .send_pulse = send_pulse_irdeo, -+ .send_space = send_space_irdeo, -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+ }, -+ -+ [LIRC_ANIMAX] = { -+ .signal_pin = UART_MSR_DCD, -+ .signal_pin_change = UART_MSR_DDCD, -+ .on = 0, -+ .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), -+ .send_pulse = NULL, -+ .send_space = NULL, -+ .features = LIRC_CAN_REC_MODE2 -+ }, -+ -+ [LIRC_IGOR] = { -+ .signal_pin = UART_MSR_DSR, -+ .signal_pin_change = UART_MSR_DDSR, -+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), -+ .off = (UART_MCR_RTS | UART_MCR_OUT2), -+ .send_pulse = send_pulse_homebrew, -+ .send_space = send_space_homebrew, -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+#else -+ .features = LIRC_CAN_REC_MODE2 -+#endif -+ }, -+ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ /* -+ * Modified Linksys Network Storage Link USB 2.0 (NSLU2): -+ * We receive on CTS of the 2nd serial port (R142,LHS), we -+ * transmit with a IR diode between GPIO[1] (green status LED), -+ * and ground (Matthias Goebl <matthias.goebl@goebl.net>). -+ * See also http://www.nslu2-linux.org for this device -+ */ -+ [LIRC_NSLU2] = { -+ .signal_pin = UART_MSR_CTS, -+ .signal_pin_change = UART_MSR_DCTS, -+ .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), -+ .off = (UART_MCR_RTS | UART_MCR_OUT2), -+ .send_pulse = send_pulse_homebrew, -+ .send_space = send_space_homebrew, -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+ .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -+#else -+ .features = LIRC_CAN_REC_MODE2 -+#endif -+ }, -+#endif -+ -+}; -+ -+#define RS_ISR_PASS_LIMIT 256 -+ -+/* -+ * A long pulse code from a remote might take up to 300 bytes. The -+ * daemon should read the bytes as soon as they are generated, so take -+ * the number of keys you think you can push before the daemon runs -+ * and multiply by 300. The driver will warn you if you overrun this -+ * buffer. If you have a slow computer or non-busmastering IDE disks, -+ * maybe you will need to increase this. -+ */ -+ -+/* This MUST be a power of two! It has to be larger than 1 as well. */ -+ -+#define RBUF_LEN 256 -+ -+static struct timeval lasttv = {0, 0}; -+ -+static struct lirc_buffer rbuf; -+ -+static unsigned int freq = 38000; -+static unsigned int duty_cycle = 50; -+ -+/* Initialized in init_timing_params() */ -+static unsigned long period; -+static unsigned long pulse_width; -+static unsigned long space_width; -+ -+#if defined(__i386__) -+/* -+ * From: -+ * Linux I/O port programming mini-HOWTO -+ * Author: Riku Saikkonen <Riku.Saikkonen@hut.fi> -+ * v, 28 December 1997 -+ * -+ * [...] -+ * Actually, a port I/O instruction on most ports in the 0-0x3ff range -+ * takes almost exactly 1 microsecond, so if you're, for example, using -+ * the parallel port directly, just do additional inb()s from that port -+ * to delay. -+ * [...] -+ */ -+/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from -+ * comment above plus trimming to match actual measured frequency. -+ * This will be sensitive to cpu speed, though hopefully most of the 1.5us -+ * is spent in the uart access. Still - for reference test machine was a -+ * 1.13GHz Athlon system - Steve -+ */ -+ -+/* -+ * changed from 400 to 450 as this works better on slower machines; -+ * faster machines will use the rdtsc code anyway -+ */ -+#define LIRC_SERIAL_TRANSMITTER_LATENCY 450 -+ -+#else -+ -+/* does anybody have information on other platforms ? */ -+/* 256 = 1<<8 */ -+#define LIRC_SERIAL_TRANSMITTER_LATENCY 256 -+ -+#endif /* __i386__ */ -+/* -+ * FIXME: should we be using hrtimers instead of this -+ * LIRC_SERIAL_TRANSMITTER_LATENCY nonsense? -+ */ -+ -+/* fetch serial input packet (1 byte) from register offset */ -+static u8 sinp(int offset) -+{ -+ if (iommap != 0) -+ /* the register is memory-mapped */ -+ offset <<= ioshift; -+ -+ return inb(io + offset); -+} -+ -+/* write serial output packet (1 byte) of value to register offset */ -+static void soutp(int offset, u8 value) -+{ -+ if (iommap != 0) -+ /* the register is memory-mapped */ -+ offset <<= ioshift; -+ -+ outb(value, io + offset); -+} -+ -+static void on(void) -+{ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ /* -+ * On NSLU2, we put the transmit diode between the output of the green -+ * status LED and ground -+ */ -+ if (type == LIRC_NSLU2) { -+ gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW); -+ return; -+ } -+#endif -+ if (txsense) -+ soutp(UART_MCR, hardware[type].off); -+ else -+ soutp(UART_MCR, hardware[type].on); -+} -+ -+static void off(void) -+{ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ if (type == LIRC_NSLU2) { -+ gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH); -+ return; -+ } -+#endif -+ if (txsense) -+ soutp(UART_MCR, hardware[type].on); -+ else -+ soutp(UART_MCR, hardware[type].off); -+} -+ -+#ifndef MAX_UDELAY_MS -+#define MAX_UDELAY_US 5000 -+#else -+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) -+#endif -+ -+static void safe_udelay(unsigned long usecs) -+{ -+ while (usecs > MAX_UDELAY_US) { -+ udelay(MAX_UDELAY_US); -+ usecs -= MAX_UDELAY_US; -+ } -+ udelay(usecs); -+} -+ -+#ifdef USE_RDTSC -+/* -+ * This is an overflow/precision juggle, complicated in that we can't -+ * do long long divide in the kernel -+ */ -+ -+/* -+ * When we use the rdtsc instruction to measure clocks, we keep the -+ * pulse and space widths as clock cycles. As this is CPU speed -+ * dependent, the widths must be calculated in init_port and ioctl -+ * time -+ */ -+ -+/* So send_pulse can quickly convert microseconds to clocks */ -+static unsigned long conv_us_to_clocks; -+ -+static int init_timing_params(unsigned int new_duty_cycle, -+ unsigned int new_freq) -+{ -+ unsigned long long loops_per_sec, work; -+ -+ duty_cycle = new_duty_cycle; -+ freq = new_freq; -+ -+ loops_per_sec = current_cpu_data.loops_per_jiffy; -+ loops_per_sec *= HZ; -+ -+ /* How many clocks in a microsecond?, avoiding long long divide */ -+ work = loops_per_sec; -+ work *= 4295; /* 4295 = 2^32 / 1e6 */ -+ conv_us_to_clocks = (work >> 32); -+ -+ /* -+ * Carrier period in clocks, approach good up to 32GHz clock, -+ * gets carrier frequency within 8Hz -+ */ -+ period = loops_per_sec >> 3; -+ period /= (freq >> 3); -+ -+ /* Derive pulse and space from the period */ -+ pulse_width = period * duty_cycle / 100; -+ space_width = period - pulse_width; -+ dprintk("in init_timing_params, freq=%d, duty_cycle=%d, " -+ "clk/jiffy=%ld, pulse=%ld, space=%ld, " -+ "conv_us_to_clocks=%ld\n", -+ freq, duty_cycle, current_cpu_data.loops_per_jiffy, -+ pulse_width, space_width, conv_us_to_clocks); -+ return 0; -+} -+#else /* ! USE_RDTSC */ -+static int init_timing_params(unsigned int new_duty_cycle, -+ unsigned int new_freq) -+{ -+/* -+ * period, pulse/space width are kept with 8 binary places - -+ * IE multiplied by 256. -+ */ -+ if (256 * 1000000L / new_freq * new_duty_cycle / 100 <= -+ LIRC_SERIAL_TRANSMITTER_LATENCY) -+ return -EINVAL; -+ if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= -+ LIRC_SERIAL_TRANSMITTER_LATENCY) -+ return -EINVAL; -+ duty_cycle = new_duty_cycle; -+ freq = new_freq; -+ period = 256 * 1000000L / freq; -+ pulse_width = period * duty_cycle / 100; -+ space_width = period - pulse_width; -+ dprintk("in init_timing_params, freq=%d pulse=%ld, " -+ "space=%ld\n", freq, pulse_width, space_width); -+ return 0; -+} -+#endif /* USE_RDTSC */ -+ -+ -+/* return value: space length delta */ -+ -+static long send_pulse_irdeo(unsigned long length) -+{ -+ long rawbits, ret; -+ int i; -+ unsigned char output; -+ unsigned char chunk, shifted; -+ -+ /* how many bits have to be sent ? */ -+ rawbits = length * 1152 / 10000; -+ if (duty_cycle > 50) -+ chunk = 3; -+ else -+ chunk = 1; -+ for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) { -+ shifted = chunk << (i * 3); -+ shifted >>= 1; -+ output &= (~shifted); -+ i++; -+ if (i == 3) { -+ soutp(UART_TX, output); -+ while (!(sinp(UART_LSR) & UART_LSR_THRE)) -+ ; -+ output = 0x7f; -+ i = 0; -+ } -+ } -+ if (i != 0) { -+ soutp(UART_TX, output); -+ while (!(sinp(UART_LSR) & UART_LSR_TEMT)) -+ ; -+ } -+ -+ if (i == 0) -+ ret = (-rawbits) * 10000 / 1152; -+ else -+ ret = (3 - i) * 3 * 10000 / 1152 + (-rawbits) * 10000 / 1152; -+ -+ return ret; -+} -+ -+#ifdef USE_RDTSC -+/* Version that uses Pentium rdtsc instruction to measure clocks */ -+ -+/* -+ * This version does sub-microsecond timing using rdtsc instruction, -+ * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY -+ * Implicitly i586 architecture... - Steve -+ */ -+ -+static long send_pulse_homebrew_softcarrier(unsigned long length) -+{ -+ int flag; -+ unsigned long target, start, now; -+ -+ /* Get going quick as we can */ -+ rdtscl(start); -+ on(); -+ /* Convert length from microseconds to clocks */ -+ length *= conv_us_to_clocks; -+ /* And loop till time is up - flipping at right intervals */ -+ now = start; -+ target = pulse_width; -+ flag = 1; -+ /* -+ * FIXME: This looks like a hard busy wait, without even an occasional, -+ * polite, cpu_relax() call. There's got to be a better way? -+ * -+ * The i2c code has the result of a lot of bit-banging work, I wonder if -+ * there's something there which could be helpful here. -+ */ -+ while ((now - start) < length) { -+ /* Delay till flip time */ -+ do { -+ rdtscl(now); -+ } while ((now - start) < target); -+ -+ /* flip */ -+ if (flag) { -+ rdtscl(now); -+ off(); -+ target += space_width; -+ } else { -+ rdtscl(now); on(); -+ target += pulse_width; -+ } -+ flag = !flag; -+ } -+ rdtscl(now); -+ return ((now - start) - length) / conv_us_to_clocks; -+} -+#else /* ! USE_RDTSC */ -+/* Version using udelay() */ -+ -+/* -+ * here we use fixed point arithmetic, with 8 -+ * fractional bits. that gets us within 0.1% or so of the right average -+ * frequency, albeit with some jitter in pulse length - Steve -+ */ -+ -+/* To match 8 fractional bits used for pulse/space length */ -+ -+static long send_pulse_homebrew_softcarrier(unsigned long length) -+{ -+ int flag; -+ unsigned long actual, target, d; -+ length <<= 8; -+ -+ actual = 0; target = 0; flag = 0; -+ while (actual < length) { -+ if (flag) { -+ off(); -+ target += space_width; -+ } else { -+ on(); -+ target += pulse_width; -+ } -+ d = (target - actual - -+ LIRC_SERIAL_TRANSMITTER_LATENCY + 128) >> 8; -+ /* -+ * Note - we've checked in ioctl that the pulse/space -+ * widths are big enough so that d is > 0 -+ */ -+ udelay(d); -+ actual += (d << 8) + LIRC_SERIAL_TRANSMITTER_LATENCY; -+ flag = !flag; -+ } -+ return (actual-length) >> 8; -+} -+#endif /* USE_RDTSC */ -+ -+static long send_pulse_homebrew(unsigned long length) -+{ -+ if (length <= 0) -+ return 0; -+ -+ if (softcarrier) -+ return send_pulse_homebrew_softcarrier(length); -+ else { -+ on(); -+ safe_udelay(length); -+ return 0; -+ } -+} -+ -+static void send_space_irdeo(long length) -+{ -+ if (length <= 0) -+ return; -+ -+ safe_udelay(length); -+} -+ -+static void send_space_homebrew(long length) -+{ -+ off(); -+ if (length <= 0) -+ return; -+ safe_udelay(length); -+} -+ -+static void rbwrite(int l) -+{ -+ if (lirc_buffer_full(&rbuf)) { -+ /* no new signals will be accepted */ -+ dprintk("Buffer overrun\n"); -+ return; -+ } -+ lirc_buffer_write(&rbuf, (void *)&l); -+} -+ -+static void frbwrite(int l) -+{ -+ /* simple noise filter */ -+ static int pulse, space; -+ static unsigned int ptr; -+ -+ if (ptr > 0 && (l & PULSE_BIT)) { -+ pulse += l & PULSE_MASK; -+ if (pulse > 250) { -+ rbwrite(space); -+ rbwrite(pulse | PULSE_BIT); -+ ptr = 0; -+ pulse = 0; -+ } -+ return; -+ } -+ if (!(l & PULSE_BIT)) { -+ if (ptr == 0) { -+ if (l > 20000) { -+ space = l; -+ ptr++; -+ return; -+ } -+ } else { -+ if (l > 20000) { -+ space += pulse; -+ if (space > PULSE_MASK) -+ space = PULSE_MASK; -+ space += l; -+ if (space > PULSE_MASK) -+ space = PULSE_MASK; -+ pulse = 0; -+ return; -+ } -+ rbwrite(space); -+ rbwrite(pulse | PULSE_BIT); -+ ptr = 0; -+ pulse = 0; -+ } -+ } -+ rbwrite(l); -+} -+ -+static irqreturn_t irq_handler(int i, void *blah) -+{ -+ struct timeval tv; -+ int counter, dcd; -+ u8 status; -+ long deltv; -+ int data; -+ static int last_dcd = -1; -+ -+ if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { -+ /* not our interrupt */ -+ return IRQ_NONE; -+ } -+ -+ counter = 0; -+ do { -+ counter++; -+ status = sinp(UART_MSR); -+ if (counter > RS_ISR_PASS_LIMIT) { -+ printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: " -+ "We're caught!\n"); -+ break; -+ } -+ if ((status & hardware[type].signal_pin_change) -+ && sense != -1) { -+ /* get current time */ -+ do_gettimeofday(&tv); -+ -+ /* New mode, written by Trent Piepho -+ <xyzzy@u.washington.edu>. */ -+ -+ /* -+ * The old format was not very portable. -+ * We now use an int to pass pulses -+ * and spaces to user space. -+ * -+ * If PULSE_BIT is set a pulse has been -+ * received, otherwise a space has been -+ * received. The driver needs to know if your -+ * receiver is active high or active low, or -+ * the space/pulse sense could be -+ * inverted. The bits denoted by PULSE_MASK are -+ * the length in microseconds. Lengths greater -+ * than or equal to 16 seconds are clamped to -+ * PULSE_MASK. All other bits are unused. -+ * This is a much simpler interface for user -+ * programs, as well as eliminating "out of -+ * phase" errors with space/pulse -+ * autodetection. -+ */ -+ -+ /* calc time since last interrupt in microseconds */ -+ dcd = (status & hardware[type].signal_pin) ? 1 : 0; -+ -+ if (dcd == last_dcd) { -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": ignoring spike: %d %d %lx %lx %lx %lx\n", -+ dcd, sense, -+ tv.tv_sec, lasttv.tv_sec, -+ tv.tv_usec, lasttv.tv_usec); -+ continue; -+ } -+ -+ deltv = tv.tv_sec-lasttv.tv_sec; -+ if (tv.tv_sec < lasttv.tv_sec || -+ (tv.tv_sec == lasttv.tv_sec && -+ tv.tv_usec < lasttv.tv_usec)) { -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": AIEEEE: your clock just jumped " -+ "backwards\n"); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": %d %d %lx %lx %lx %lx\n", -+ dcd, sense, -+ tv.tv_sec, lasttv.tv_sec, -+ tv.tv_usec, lasttv.tv_usec); -+ data = PULSE_MASK; -+ } else if (deltv > 15) { -+ data = PULSE_MASK; /* really long time */ -+ if (!(dcd^sense)) { -+ /* sanity check */ -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": AIEEEE: " -+ "%d %d %lx %lx %lx %lx\n", -+ dcd, sense, -+ tv.tv_sec, lasttv.tv_sec, -+ tv.tv_usec, lasttv.tv_usec); -+ /* -+ * detecting pulse while this -+ * MUST be a space! -+ */ -+ sense = sense ? 0 : 1; -+ } -+ } else -+ data = (int) (deltv*1000000 + -+ tv.tv_usec - -+ lasttv.tv_usec); -+ frbwrite(dcd^sense ? data : (data|PULSE_BIT)); -+ lasttv = tv; -+ last_dcd = dcd; -+ wake_up_interruptible(&rbuf.wait_poll); -+ } -+ } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ -+ return IRQ_HANDLED; -+} -+ -+ -+static int hardware_init_port(void) -+{ -+ u8 scratch, scratch2, scratch3; -+ -+ /* -+ * This is a simple port existence test, borrowed from the autoconfig -+ * function in drivers/serial/8250.c -+ */ -+ scratch = sinp(UART_IER); -+ soutp(UART_IER, 0); -+#ifdef __i386__ -+ outb(0xff, 0x080); -+#endif -+ scratch2 = sinp(UART_IER) & 0x0f; -+ soutp(UART_IER, 0x0f); -+#ifdef __i386__ -+ outb(0x00, 0x080); -+#endif -+ scratch3 = sinp(UART_IER) & 0x0f; -+ soutp(UART_IER, scratch); -+ if (scratch2 != 0 || scratch3 != 0x0f) { -+ /* we fail, there's nothing here */ -+ printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test " -+ "failed, cannot continue\n"); -+ return -EINVAL; -+ } -+ -+ -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* First of all, disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ -+ /* Clear registers. */ -+ sinp(UART_LSR); -+ sinp(UART_RX); -+ sinp(UART_IIR); -+ sinp(UART_MSR); -+ -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ if (type == LIRC_NSLU2) { -+ /* Setup NSLU2 UART */ -+ -+ /* Enable UART */ -+ soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE); -+ /* Disable Receiver data Time out interrupt */ -+ soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE); -+ /* set out2 = interrupt unmask; off() doesn't set MCR -+ on NSLU2 */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ } -+#endif -+ -+ /* Set line for power source */ -+ off(); -+ -+ /* Clear registers again to be sure. */ -+ sinp(UART_LSR); -+ sinp(UART_RX); -+ sinp(UART_IIR); -+ sinp(UART_MSR); -+ -+ switch (type) { -+ case LIRC_IRDEO: -+ case LIRC_IRDEO_REMOTE: -+ /* setup port to 7N1 @ 115200 Baud */ -+ /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ /* Set DLAB 0 + 7N1 */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ /* THR interrupt already disabled at this point */ -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static int init_port(void) -+{ -+ int i, nlow, nhigh; -+ -+ /* Reserve io region. */ -+ /* -+ * Future MMAP-Developers: Attention! -+ * For memory mapped I/O you *might* need to use ioremap() first, -+ * for the NSLU2 it's done in boot code. -+ */ -+ if (((iommap != 0) -+ && (request_mem_region(iommap, 8 << ioshift, -+ LIRC_DRIVER_NAME) == NULL)) -+ || ((iommap == 0) -+ && (request_region(io, 8, LIRC_DRIVER_NAME) == NULL))) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": port %04x already in use\n", io); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": use 'setserial /dev/ttySX uart none'\n"); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": or compile the serial port driver as module and\n"); -+ printk(KERN_WARNING LIRC_DRIVER_NAME -+ ": make sure this module is loaded first\n"); -+ return -EBUSY; -+ } -+ -+ if (hardware_init_port() < 0) -+ return -EINVAL; -+ -+ /* Initialize pulse/space widths */ -+ init_timing_params(duty_cycle, freq); -+ -+ /* If pin is high, then this must be an active low receiver. */ -+ if (sense == -1) { -+ /* wait 1/2 sec for the power supply */ -+ msleep(500); -+ -+ /* -+ * probe 9 times every 0.04s, collect "votes" for -+ * active high/low -+ */ -+ nlow = 0; -+ nhigh = 0; -+ for (i = 0; i < 9; i++) { -+ if (sinp(UART_MSR) & hardware[type].signal_pin) -+ nlow++; -+ else -+ nhigh++; -+ msleep(40); -+ } -+ sense = (nlow >= nhigh ? 1 : 0); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": auto-detected active " -+ "%s receiver\n", sense ? "low" : "high"); -+ } else -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " -+ "%s receiver\n", sense ? "low" : "high"); -+ -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ int result; -+ unsigned long flags; -+ -+ /* initialize timestamp */ -+ do_gettimeofday(&lasttv); -+ -+ result = request_irq(irq, irq_handler, -+ IRQF_DISABLED | (share_irq ? IRQF_SHARED : 0), -+ LIRC_DRIVER_NAME, (void *)&hardware); -+ -+ switch (result) { -+ case -EBUSY: -+ printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); -+ return -EBUSY; -+ case -EINVAL: -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": Bad irq number or handler\n"); -+ return -EINVAL; -+ default: -+ dprintk("Interrupt %d, port %04x obtained\n", irq, io); -+ break; -+ }; -+ -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); -+ -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* First of all, disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ -+ free_irq(irq, (void *)&hardware); -+ -+ dprintk("freed IRQ %d\n", irq); -+} -+ -+static ssize_t lirc_write(struct file *file, const char *buf, -+ size_t n, loff_t *ppos) -+{ -+ int i, count; -+ unsigned long flags; -+ long delta = 0; -+ int *wbuf; -+ -+ if (!(hardware[type].features & LIRC_CAN_SEND_PULSE)) -+ return -EBADF; -+ -+ count = n / sizeof(int); -+ if (n % sizeof(int) || count % 2 == 0) -+ return -EINVAL; -+ wbuf = memdup_user(buf, n); -+ if (PTR_ERR(wbuf)) -+ return PTR_ERR(wbuf); -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ if (type == LIRC_IRDEO) { -+ /* DTR, RTS down */ -+ on(); -+ } -+ for (i = 0; i < count; i++) { -+ if (i%2) -+ hardware[type].send_space(wbuf[i] - delta); -+ else -+ delta = hardware[type].send_pulse(wbuf[i]); -+ } -+ off(); -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ return n; -+} -+ -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -+{ -+ int result; -+ unsigned long value; -+ unsigned int ivalue; -+ -+ switch (cmd) { -+ case LIRC_GET_SEND_MODE: -+ if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) -+ return -ENOIOCTLCMD; -+ -+ result = put_user(LIRC_SEND2MODE -+ (hardware[type].features&LIRC_CAN_SEND_MASK), -+ (unsigned long *) arg); -+ if (result) -+ return result; -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) -+ return -ENOIOCTLCMD; -+ -+ result = get_user(value, (unsigned long *) arg); -+ if (result) -+ return result; -+ /* only LIRC_MODE_PULSE supported */ -+ if (value != LIRC_MODE_PULSE) -+ return -ENOSYS; -+ break; -+ -+ case LIRC_GET_LENGTH: -+ return -ENOSYS; -+ break; -+ -+ case LIRC_SET_SEND_DUTY_CYCLE: -+ dprintk("SET_SEND_DUTY_CYCLE\n"); -+ if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE)) -+ return -ENOIOCTLCMD; -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ if (ivalue <= 0 || ivalue > 100) -+ return -EINVAL; -+ return init_timing_params(ivalue, freq); -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ dprintk("SET_SEND_CARRIER\n"); -+ if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER)) -+ return -ENOIOCTLCMD; -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ if (ivalue > 500000 || ivalue < 20000) -+ return -EINVAL; -+ return init_timing_params(duty_cycle, ivalue); -+ break; -+ -+ default: -+ return lirc_dev_fop_ioctl(filep, cmd, arg); -+ } -+ return 0; -+} -+ -+static const struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .write = lirc_write, -+ .unlocked_ioctl = lirc_ioctl, -+ .read = lirc_dev_fop_read, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .rbuf = &rbuf, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+static struct platform_device *lirc_serial_dev; -+ -+static int __devinit lirc_serial_probe(struct platform_device *dev) -+{ -+ return 0; -+} -+ -+static int __devexit lirc_serial_remove(struct platform_device *dev) -+{ -+ return 0; -+} -+ -+static int lirc_serial_suspend(struct platform_device *dev, -+ pm_message_t state) -+{ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* Disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ -+ /* Clear registers. */ -+ sinp(UART_LSR); -+ sinp(UART_RX); -+ sinp(UART_IIR); -+ sinp(UART_MSR); -+ -+ return 0; -+} -+ -+/* twisty maze... need a forward-declaration here... */ -+static void lirc_serial_exit(void); -+ -+static int lirc_serial_resume(struct platform_device *dev) -+{ -+ unsigned long flags; -+ -+ if (hardware_init_port() < 0) { -+ lirc_serial_exit(); -+ return -EINVAL; -+ } -+ -+ spin_lock_irqsave(&hardware[type].lock, flags); -+ /* Enable Interrupt */ -+ do_gettimeofday(&lasttv); -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); -+ off(); -+ -+ lirc_buffer_clear(&rbuf); -+ -+ spin_unlock_irqrestore(&hardware[type].lock, flags); -+ -+ return 0; -+} -+ -+static struct platform_driver lirc_serial_driver = { -+ .probe = lirc_serial_probe, -+ .remove = __devexit_p(lirc_serial_remove), -+ .suspend = lirc_serial_suspend, -+ .resume = lirc_serial_resume, -+ .driver = { -+ .name = "lirc_serial", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init lirc_serial_init(void) -+{ -+ int result; -+ -+ /* Init read buffer. */ -+ result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN); -+ if (result < 0) -+ return -ENOMEM; -+ -+ result = platform_driver_register(&lirc_serial_driver); -+ if (result) { -+ printk("lirc register returned %d\n", result); -+ goto exit_buffer_free; -+ } -+ -+ lirc_serial_dev = platform_device_alloc("lirc_serial", 0); -+ if (!lirc_serial_dev) { -+ result = -ENOMEM; -+ goto exit_driver_unregister; -+ } -+ -+ result = platform_device_add(lirc_serial_dev); -+ if (result) -+ goto exit_device_put; -+ -+ return 0; -+ -+exit_device_put: -+ platform_device_put(lirc_serial_dev); -+exit_driver_unregister: -+ platform_driver_unregister(&lirc_serial_driver); -+exit_buffer_free: -+ lirc_buffer_free(&rbuf); -+ return result; -+} -+ -+static void lirc_serial_exit(void) -+{ -+ platform_device_unregister(lirc_serial_dev); -+ platform_driver_unregister(&lirc_serial_driver); -+ lirc_buffer_free(&rbuf); -+} -+ -+static int __init lirc_serial_init_module(void) -+{ -+ int result; -+ -+ result = lirc_serial_init(); -+ if (result) -+ return result; -+ -+ switch (type) { -+ case LIRC_HOMEBREW: -+ case LIRC_IRDEO: -+ case LIRC_IRDEO_REMOTE: -+ case LIRC_ANIMAX: -+ case LIRC_IGOR: -+ /* if nothing specified, use ttyS0/com1 and irq 4 */ -+ io = io ? io : 0x3f8; -+ irq = irq ? irq : 4; -+ break; -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ case LIRC_NSLU2: -+ io = io ? io : IRQ_IXP4XX_UART2; -+ irq = irq ? irq : (IXP4XX_UART2_BASE_VIRT + REG_OFFSET); -+ iommap = iommap ? iommap : IXP4XX_UART2_BASE_PHYS; -+ ioshift = ioshift ? ioshift : 2; -+ break; -+#endif -+ default: -+ result = -EINVAL; -+ goto exit_serial_exit; -+ } -+ if (!softcarrier) { -+ switch (type) { -+ case LIRC_HOMEBREW: -+ case LIRC_IGOR: -+#ifdef CONFIG_LIRC_SERIAL_NSLU2 -+ case LIRC_NSLU2: -+#endif -+ hardware[type].features &= -+ ~(LIRC_CAN_SET_SEND_DUTY_CYCLE| -+ LIRC_CAN_SET_SEND_CARRIER); -+ break; -+ } -+ } -+ -+ result = init_port(); -+ if (result < 0) -+ goto exit_serial_exit; -+ driver.features = hardware[type].features; -+ driver.dev = &lirc_serial_dev->dev; -+ driver.minor = lirc_register_driver(&driver); -+ if (driver.minor < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": register_chrdev failed!\n"); -+ result = -EIO; -+ goto exit_release; -+ } -+ return 0; -+exit_release: -+ release_region(io, 8); -+exit_serial_exit: -+ lirc_serial_exit(); -+ return result; -+} -+ -+static void __exit lirc_serial_exit_module(void) -+{ -+ lirc_serial_exit(); -+ if (iommap != 0) -+ release_mem_region(iommap, 8 << ioshift); -+ else -+ release_region(io, 8); -+ lirc_unregister_driver(driver.minor); -+ dprintk("cleaned up module\n"); -+} -+ -+ -+module_init(lirc_serial_init_module); -+module_exit(lirc_serial_exit_module); -+ -+MODULE_DESCRIPTION("Infra-red receiver driver for serial ports."); -+MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, " -+ "Christoph Bartelmus, Andrei Tanas"); -+MODULE_LICENSE("GPL"); -+ -+module_param(type, int, S_IRUGO); -+MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo," -+ " 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug," -+ " 5 = NSLU2 RX:CTS2/TX:GreenLED)"); -+ -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); -+ -+/* some architectures (e.g. intel xscale) have memory mapped registers */ -+module_param(iommap, bool, S_IRUGO); -+MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O" -+ " (0 = no memory mapped io)"); -+ -+/* -+ * some architectures (e.g. intel xscale) align the 8bit serial registers -+ * on 32bit word boundaries. -+ * See linux-kernel/serial/8250.c serial_in()/out() -+ */ -+module_param(ioshift, int, S_IRUGO); -+MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)"); -+ -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); -+ -+module_param(share_irq, bool, S_IRUGO); -+MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)"); -+ -+module_param(sense, bool, S_IRUGO); -+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit" -+ " (0 = active high, 1 = active low )"); -+ -+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -+module_param(txsense, bool, S_IRUGO); -+MODULE_PARM_DESC(txsense, "Sense of transmitter circuit" -+ " (0 = active high, 1 = active low )"); -+#endif -+ -+module_param(softcarrier, bool, S_IRUGO); -+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+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 0000000..eb08fa7 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_sir.c -@@ -0,0 +1,1282 @@ -+/* -+ * LIRC SIR driver, (C) 2000 Milan Pikula <www@fornax.sk> -+ * -+ * lirc_sir - Device driver for use with SIR (serial infra red) -+ * mode of IrDA on many notebooks. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * -+ * 2000/09/16 Frank Przybylski <mail@frankprzybylski.de> : -+ * added timeout and relaxed pulse detection, removed gap bug -+ * -+ * 2000/12/15 Christoph Bartelmus <lirc@bartelmus.de> : -+ * added support for Tekram Irmate 210 (sending does not work yet, -+ * kind of disappointing that nobody was able to implement that -+ * before), -+ * major clean-up -+ * -+ * 2001/02/27 Christoph Bartelmus <lirc@bartelmus.de> : -+ * added support for StrongARM SA1100 embedded microprocessor -+ * parts cut'n'pasted from sa1100_ir.c (C) 2000 Russell King -+ */ -+ -+#include <linux/module.h> -+#include <linux/sched.h> -+#include <linux/errno.h> -+#include <linux/signal.h> -+#include <linux/fs.h> -+#include <linux/interrupt.h> -+#include <linux/ioport.h> -+#include <linux/kernel.h> -+#include <linux/serial_reg.h> -+#include <linux/time.h> -+#include <linux/string.h> -+#include <linux/types.h> -+#include <linux/wait.h> -+#include <linux/mm.h> -+#include <linux/delay.h> -+#include <linux/poll.h> -+#include <asm/system.h> -+#include <linux/io.h> -+#include <asm/irq.h> -+#include <linux/fcntl.h> -+#ifdef LIRC_ON_SA1100 -+#include <asm/hardware.h> -+#ifdef CONFIG_SA1100_COLLIE -+#include <asm/arch/tc35143.h> -+#include <asm/ucb1200.h> -+#endif -+#endif -+ -+#include <linux/timer.h> -+ -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+ -+/* SECTION: Definitions */ -+ -+/*** Tekram dongle ***/ -+#ifdef LIRC_SIR_TEKRAM -+/* stolen from kernel source */ -+/* definitions for Tekram dongle */ -+#define TEKRAM_115200 0x00 -+#define TEKRAM_57600 0x01 -+#define TEKRAM_38400 0x02 -+#define TEKRAM_19200 0x03 -+#define TEKRAM_9600 0x04 -+#define TEKRAM_2400 0x08 -+ -+#define TEKRAM_PW 0x10 /* Pulse select bit */ -+ -+/* 10bit * 1s/115200bit in milliseconds = 87ms*/ -+#define TIME_CONST (10000000ul/115200ul) -+ -+#endif -+ -+#ifdef LIRC_SIR_ACTISYS_ACT200L -+static void init_act200(void); -+#elif defined(LIRC_SIR_ACTISYS_ACT220L) -+static void init_act220(void); -+#endif -+ -+/*** SA1100 ***/ -+#ifdef LIRC_ON_SA1100 -+struct sa1100_ser2_registers { -+ /* HSSP control register */ -+ unsigned char hscr0; -+ /* UART registers */ -+ unsigned char utcr0; -+ unsigned char utcr1; -+ unsigned char utcr2; -+ unsigned char utcr3; -+ unsigned char utcr4; -+ unsigned char utdr; -+ unsigned char utsr0; -+ unsigned char utsr1; -+} sr; -+ -+static int irq = IRQ_Ser2ICP; -+ -+#define LIRC_ON_SA1100_TRANSMITTER_LATENCY 0 -+ -+/* pulse/space ratio of 50/50 */ -+static unsigned long pulse_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); -+/* 1000000/freq-pulse_width */ -+static unsigned long space_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY); -+static unsigned int freq = 38000; /* modulation frequency */ -+static unsigned int duty_cycle = 50; /* duty cycle of 50% */ -+ -+#endif -+ -+#define RBUF_LEN 1024 -+#define WBUF_LEN 1024 -+ -+#define LIRC_DRIVER_NAME "lirc_sir" -+ -+#define PULSE '[' -+ -+#ifndef LIRC_SIR_TEKRAM -+/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/ -+#define TIME_CONST (9000000ul/115200ul) -+#endif -+ -+ -+/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */ -+#define SIR_TIMEOUT (HZ*5/100) -+ -+#ifndef LIRC_ON_SA1100 -+#ifndef LIRC_IRQ -+#define LIRC_IRQ 4 -+#endif -+#ifndef LIRC_PORT -+/* for external dongles, default to com1 */ -+#if defined(LIRC_SIR_ACTISYS_ACT200L) || \ -+ defined(LIRC_SIR_ACTISYS_ACT220L) || \ -+ defined(LIRC_SIR_TEKRAM) -+#define LIRC_PORT 0x3f8 -+#else -+/* onboard sir ports are typically com3 */ -+#define LIRC_PORT 0x3e8 -+#endif -+#endif -+ -+static int io = LIRC_PORT; -+static int irq = LIRC_IRQ; -+static int threshold = 3; -+#endif -+ -+static DEFINE_SPINLOCK(timer_lock); -+static struct timer_list timerlist; -+/* time of last signal change detected */ -+static struct timeval last_tv = {0, 0}; -+/* time of last UART data ready interrupt */ -+static struct timeval last_intr_tv = {0, 0}; -+static int last_value; -+ -+static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); -+ -+static DEFINE_SPINLOCK(hardware_lock); -+ -+static int rx_buf[RBUF_LEN]; -+static unsigned int rx_tail, rx_head; -+ -+static int debug; -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ -+ fmt, ## args); \ -+ } while (0) -+ -+/* SECTION: Prototypes */ -+ -+/* Communication with user-space */ -+static unsigned int lirc_poll(struct file *file, poll_table *wait); -+static ssize_t lirc_read(struct file *file, char *buf, size_t count, -+ loff_t *ppos); -+static ssize_t lirc_write(struct file *file, const char *buf, size_t n, -+ loff_t *pos); -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); -+static void add_read_queue(int flag, unsigned long val); -+static int init_chrdev(void); -+static void drop_chrdev(void); -+/* Hardware */ -+static irqreturn_t sir_interrupt(int irq, void *dev_id); -+static void send_space(unsigned long len); -+static void send_pulse(unsigned long len); -+static int init_hardware(void); -+static void drop_hardware(void); -+/* Initialisation */ -+static int init_port(void); -+static void drop_port(void); -+ -+#ifdef LIRC_ON_SA1100 -+static void on(void) -+{ -+ PPSR |= PPC_TXD2; -+} -+ -+static void off(void) -+{ -+ PPSR &= ~PPC_TXD2; -+} -+#else -+static inline unsigned int sinp(int offset) -+{ -+ return inb(io + offset); -+} -+ -+static inline void soutp(int offset, int value) -+{ -+ outb(value, io + offset); -+} -+#endif -+ -+#ifndef MAX_UDELAY_MS -+#define MAX_UDELAY_US 5000 -+#else -+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) -+#endif -+ -+static void safe_udelay(unsigned long usecs) -+{ -+ while (usecs > MAX_UDELAY_US) { -+ udelay(MAX_UDELAY_US); -+ usecs -= MAX_UDELAY_US; -+ } -+ udelay(usecs); -+} -+ -+/* SECTION: Communication with user-space */ -+ -+static unsigned int lirc_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &lirc_read_queue, wait); -+ if (rx_head != rx_tail) -+ return POLLIN | POLLRDNORM; -+ return 0; -+} -+ -+static ssize_t lirc_read(struct file *file, char *buf, size_t count, -+ loff_t *ppos) -+{ -+ int n = 0; -+ int retval = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ if (count % sizeof(int)) -+ return -EINVAL; -+ -+ add_wait_queue(&lirc_read_queue, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ while (n < count) { -+ if (rx_head != rx_tail) { -+ if (copy_to_user((void *) buf + n, -+ (void *) (rx_buf + rx_head), -+ sizeof(int))) { -+ retval = -EFAULT; -+ break; -+ } -+ rx_head = (rx_head + 1) & (RBUF_LEN - 1); -+ n += sizeof(int); -+ } else { -+ if (file->f_flags & O_NONBLOCK) { -+ retval = -EAGAIN; -+ break; -+ } -+ if (signal_pending(current)) { -+ retval = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ } -+ } -+ remove_wait_queue(&lirc_read_queue, &wait); -+ set_current_state(TASK_RUNNING); -+ return n ? n : retval; -+} -+static ssize_t lirc_write(struct file *file, const char *buf, size_t n, -+ loff_t *pos) -+{ -+ unsigned long flags; -+ int i, count; -+ int *tx_buf; -+ -+ count = n / sizeof(int); -+ if (n % sizeof(int) || count % 2 == 0) -+ return -EINVAL; -+ tx_buf = memdup_user(buf, n); -+ if (IS_ERR(tx_buf)) -+ return PTR_ERR(tx_buf); -+ i = 0; -+#ifdef LIRC_ON_SA1100 -+ /* disable receiver */ -+ Ser2UTCR3 = 0; -+#endif -+ local_irq_save(flags); -+ while (1) { -+ if (i >= count) -+ break; -+ if (tx_buf[i]) -+ send_pulse(tx_buf[i]); -+ i++; -+ if (i >= count) -+ break; -+ if (tx_buf[i]) -+ send_space(tx_buf[i]); -+ i++; -+ } -+ local_irq_restore(flags); -+#ifdef LIRC_ON_SA1100 -+ off(); -+ udelay(1000); /* wait 1ms for IR diode to recover */ -+ Ser2UTCR3 = 0; -+ /* clear status register to prevent unwanted interrupts */ -+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ /* enable receiver */ -+ Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; -+#endif -+ return count; -+} -+ -+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -+{ -+ int retval = 0; -+ unsigned long value = 0; -+#ifdef LIRC_ON_SA1100 -+ unsigned int ivalue; -+ -+ if (cmd == LIRC_GET_FEATURES) -+ value = LIRC_CAN_SEND_PULSE | -+ LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ LIRC_CAN_SET_SEND_CARRIER | -+ LIRC_CAN_REC_MODE2; -+ else if (cmd == LIRC_GET_SEND_MODE) -+ value = LIRC_MODE_PULSE; -+ else if (cmd == LIRC_GET_REC_MODE) -+ value = LIRC_MODE_MODE2; -+#else -+ if (cmd == LIRC_GET_FEATURES) -+ value = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; -+ else if (cmd == LIRC_GET_SEND_MODE) -+ value = LIRC_MODE_PULSE; -+ else if (cmd == LIRC_GET_REC_MODE) -+ value = LIRC_MODE_MODE2; -+#endif -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ case LIRC_GET_SEND_MODE: -+ case LIRC_GET_REC_MODE: -+ retval = put_user(value, (unsigned long *) arg); -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ case LIRC_SET_REC_MODE: -+ retval = get_user(value, (unsigned long *) arg); -+ break; -+#ifdef LIRC_ON_SA1100 -+ case LIRC_SET_SEND_DUTY_CYCLE: -+ retval = get_user(ivalue, (unsigned int *) arg); -+ if (retval) -+ return retval; -+ if (ivalue <= 0 || ivalue > 100) -+ return -EINVAL; -+ /* (ivalue/100)*(1000000/freq) */ -+ duty_cycle = ivalue; -+ pulse_width = (unsigned long) duty_cycle*10000/freq; -+ space_width = (unsigned long) 1000000L/freq-pulse_width; -+ if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ break; -+ case LIRC_SET_SEND_CARRIER: -+ retval = get_user(ivalue, (unsigned int *) arg); -+ if (retval) -+ return retval; -+ if (ivalue > 500000 || ivalue < 20000) -+ return -EINVAL; -+ freq = ivalue; -+ pulse_width = (unsigned long) duty_cycle*10000/freq; -+ space_width = (unsigned long) 1000000L/freq-pulse_width; -+ if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY) -+ space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY; -+ break; -+#endif -+ default: -+ retval = -ENOIOCTLCMD; -+ -+ } -+ -+ if (retval) -+ return retval; -+ if (cmd == LIRC_SET_REC_MODE) { -+ if (value != LIRC_MODE_MODE2) -+ retval = -ENOSYS; -+ } else if (cmd == LIRC_SET_SEND_MODE) { -+ if (value != LIRC_MODE_PULSE) -+ retval = -ENOSYS; -+ } -+ -+ return retval; -+} -+ -+static void add_read_queue(int flag, unsigned long val) -+{ -+ unsigned int new_rx_tail; -+ int newval; -+ -+ dprintk("add flag %d with val %lu\n", flag, val); -+ -+ newval = val & PULSE_MASK; -+ -+ /* -+ * statistically, pulses are ~TIME_CONST/2 too long. we could -+ * maybe make this more exact, but this is good enough -+ */ -+ if (flag) { -+ /* pulse */ -+ if (newval > TIME_CONST/2) -+ newval -= TIME_CONST/2; -+ else /* should not ever happen */ -+ newval = 1; -+ newval |= PULSE_BIT; -+ } else { -+ newval += TIME_CONST/2; -+ } -+ new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); -+ if (new_rx_tail == rx_head) { -+ dprintk("Buffer overrun.\n"); -+ return; -+ } -+ rx_buf[rx_tail] = newval; -+ rx_tail = new_rx_tail; -+ wake_up_interruptible(&lirc_read_queue); -+} -+ -+static const struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .read = lirc_read, -+ .write = lirc_write, -+ .poll = lirc_poll, -+ .unlocked_ioctl = lirc_ioctl, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int set_use_inc(void *data) -+{ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+} -+ -+static struct lirc_driver driver = { -+ .name = LIRC_DRIVER_NAME, -+ .minor = -1, -+ .code_length = 1, -+ .sample_rate = 0, -+ .data = NULL, -+ .add_to_buf = NULL, -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .fops = &lirc_fops, -+ .dev = NULL, -+ .owner = THIS_MODULE, -+}; -+ -+ -+static int init_chrdev(void) -+{ -+ driver.minor = lirc_register_driver(&driver); -+ if (driver.minor < 0) { -+ printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); -+ return -EIO; -+ } -+ return 0; -+} -+ -+static void drop_chrdev(void) -+{ -+ lirc_unregister_driver(driver.minor); -+} -+ -+/* SECTION: Hardware */ -+static long delta(struct timeval *tv1, struct timeval *tv2) -+{ -+ unsigned long deltv; -+ -+ deltv = tv2->tv_sec - tv1->tv_sec; -+ if (deltv > 15) -+ deltv = 0xFFFFFF; -+ else -+ deltv = deltv*1000000 + -+ tv2->tv_usec - -+ tv1->tv_usec; -+ return deltv; -+} -+ -+static void sir_timeout(unsigned long data) -+{ -+ /* -+ * if last received signal was a pulse, but receiving stopped -+ * within the 9 bit frame, we need to finish this pulse and -+ * simulate a signal change to from pulse to space. Otherwise -+ * upper layers will receive two sequences next time. -+ */ -+ -+ unsigned long flags; -+ unsigned long pulse_end; -+ -+ /* avoid interference with interrupt */ -+ spin_lock_irqsave(&timer_lock, flags); -+ if (last_value) { -+#ifndef LIRC_ON_SA1100 -+ /* clear unread bits in UART and restart */ -+ outb(UART_FCR_CLEAR_RCVR, io + UART_FCR); -+#endif -+ /* determine 'virtual' pulse end: */ -+ pulse_end = delta(&last_tv, &last_intr_tv); -+ dprintk("timeout add %d for %lu usec\n", last_value, pulse_end); -+ add_read_queue(last_value, pulse_end); -+ last_value = 0; -+ last_tv = last_intr_tv; -+ } -+ spin_unlock_irqrestore(&timer_lock, flags); -+} -+ -+static irqreturn_t sir_interrupt(int irq, void *dev_id) -+{ -+ unsigned char data; -+ struct timeval curr_tv; -+ static unsigned long deltv; -+#ifdef LIRC_ON_SA1100 -+ int status; -+ static int n; -+ -+ status = Ser2UTSR0; -+ /* -+ * Deal with any receive errors first. The bytes in error may be -+ * the only bytes in the receive FIFO, so we do this first. -+ */ -+ while (status & UTSR0_EIF) { -+ int bstat; -+ -+ if (debug) { -+ dprintk("EIF\n"); -+ bstat = Ser2UTSR1; -+ -+ if (bstat & UTSR1_FRE) -+ dprintk("frame error\n"); -+ if (bstat & UTSR1_ROR) -+ dprintk("receive fifo overrun\n"); -+ if (bstat & UTSR1_PRE) -+ dprintk("parity error\n"); -+ } -+ -+ bstat = Ser2UTDR; -+ n++; -+ status = Ser2UTSR0; -+ } -+ -+ if (status & (UTSR0_RFS | UTSR0_RID)) { -+ do_gettimeofday(&curr_tv); -+ deltv = delta(&last_tv, &curr_tv); -+ do { -+ data = Ser2UTDR; -+ dprintk("%d data: %u\n", n, (unsigned int) data); -+ n++; -+ } while (status & UTSR0_RID && /* do not empty fifo in order to -+ * get UTSR0_RID in any case */ -+ Ser2UTSR1 & UTSR1_RNE); /* data ready */ -+ -+ if (status&UTSR0_RID) { -+ add_read_queue(0 , deltv - n * TIME_CONST); /*space*/ -+ add_read_queue(1, n * TIME_CONST); /*pulse*/ -+ n = 0; -+ last_tv = curr_tv; -+ } -+ } -+ -+ if (status & UTSR0_TFS) -+ printk(KERN_ERR "transmit fifo not full, shouldn't happen\n"); -+ -+ /* We must clear certain bits. */ -+ status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ if (status) -+ Ser2UTSR0 = status; -+#else -+ unsigned long deltintrtv; -+ unsigned long flags; -+ int iir, lsr; -+ -+ while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) { -+ switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */ -+ case UART_IIR_MSI: -+ (void) inb(io + UART_MSR); -+ break; -+ case UART_IIR_RLSI: -+ (void) inb(io + UART_LSR); -+ break; -+ case UART_IIR_THRI: -+#if 0 -+ if (lsr & UART_LSR_THRE) /* FIFO is empty */ -+ outb(data, io + UART_TX) -+#endif -+ break; -+ case UART_IIR_RDI: -+ /* avoid interference with timer */ -+ spin_lock_irqsave(&timer_lock, flags); -+ do { -+ del_timer(&timerlist); -+ data = inb(io + UART_RX); -+ do_gettimeofday(&curr_tv); -+ deltv = delta(&last_tv, &curr_tv); -+ deltintrtv = delta(&last_intr_tv, &curr_tv); -+ dprintk("t %lu, d %d\n", deltintrtv, (int)data); -+ /* -+ * if nothing came in last X cycles, -+ * it was gap -+ */ -+ if (deltintrtv > TIME_CONST * threshold) { -+ if (last_value) { -+ dprintk("GAP\n"); -+ /* simulate signal change */ -+ add_read_queue(last_value, -+ deltv - -+ deltintrtv); -+ last_value = 0; -+ last_tv.tv_sec = -+ last_intr_tv.tv_sec; -+ last_tv.tv_usec = -+ last_intr_tv.tv_usec; -+ deltv = deltintrtv; -+ } -+ } -+ data = 1; -+ if (data ^ last_value) { -+ /* -+ * deltintrtv > 2*TIME_CONST, remember? -+ * the other case is timeout -+ */ -+ add_read_queue(last_value, -+ deltv-TIME_CONST); -+ last_value = data; -+ last_tv = curr_tv; -+ if (last_tv.tv_usec >= TIME_CONST) { -+ last_tv.tv_usec -= TIME_CONST; -+ } else { -+ last_tv.tv_sec--; -+ last_tv.tv_usec += 1000000 - -+ TIME_CONST; -+ } -+ } -+ last_intr_tv = curr_tv; -+ if (data) { -+ /* -+ * start timer for end of -+ * sequence detection -+ */ -+ timerlist.expires = jiffies + -+ SIR_TIMEOUT; -+ add_timer(&timerlist); -+ } -+ -+ lsr = inb(io + UART_LSR); -+ } while (lsr & UART_LSR_DR); /* data ready */ -+ spin_unlock_irqrestore(&timer_lock, flags); -+ break; -+ default: -+ break; -+ } -+ } -+#endif -+ return IRQ_RETVAL(IRQ_HANDLED); -+} -+ -+#ifdef LIRC_ON_SA1100 -+static void send_pulse(unsigned long length) -+{ -+ unsigned long k, delay; -+ int flag; -+ -+ if (length == 0) -+ return; -+ /* -+ * this won't give us the carrier frequency we really want -+ * due to integer arithmetic, but we can accept this inaccuracy -+ */ -+ -+ for (k = flag = 0; k < length; k += delay, flag = !flag) { -+ if (flag) { -+ off(); -+ delay = space_width; -+ } else { -+ on(); -+ delay = pulse_width; -+ } -+ safe_udelay(delay); -+ } -+ off(); -+} -+ -+static void send_space(unsigned long length) -+{ -+ if (length == 0) -+ return; -+ off(); -+ safe_udelay(length); -+} -+#else -+static void send_space(unsigned long len) -+{ -+ safe_udelay(len); -+} -+ -+static void send_pulse(unsigned long len) -+{ -+ long bytes_out = len / TIME_CONST; -+ long time_left; -+ -+ time_left = (long)len - (long)bytes_out * (long)TIME_CONST; -+ if (bytes_out == 0) { -+ bytes_out++; -+ time_left = 0; -+ } -+ while (bytes_out--) { -+ outb(PULSE, io + UART_TX); -+ /* FIXME treba seriozne cakanie z char/serial.c */ -+ while (!(inb(io + UART_LSR) & UART_LSR_THRE)) -+ ; -+ } -+#if 0 -+ if (time_left > 0) -+ safe_udelay(time_left); -+#endif -+} -+#endif -+ -+#ifdef CONFIG_SA1100_COLLIE -+static int sa1100_irda_set_power_collie(int state) -+{ -+ if (state) { -+ /* -+ * 0 - off -+ * 1 - short range, lowest power -+ * 2 - medium range, medium power -+ * 3 - maximum range, high power -+ */ -+ ucb1200_set_io_direction(TC35143_GPIO_IR_ON, -+ TC35143_IODIR_OUTPUT); -+ ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW); -+ udelay(100); -+ } else { -+ /* OFF */ -+ ucb1200_set_io_direction(TC35143_GPIO_IR_ON, -+ TC35143_IODIR_OUTPUT); -+ ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_HIGH); -+ } -+ return 0; -+} -+#endif -+ -+static int init_hardware(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ /* reset UART */ -+#ifdef LIRC_ON_SA1100 -+#ifdef CONFIG_SA1100_BITSY -+ if (machine_is_bitsy()) { -+ printk(KERN_INFO "Power on IR module\n"); -+ set_bitsy_egpio(EGPIO_BITSY_IR_ON); -+ } -+#endif -+#ifdef CONFIG_SA1100_COLLIE -+ sa1100_irda_set_power_collie(3); /* power on */ -+#endif -+ sr.hscr0 = Ser2HSCR0; -+ -+ sr.utcr0 = Ser2UTCR0; -+ sr.utcr1 = Ser2UTCR1; -+ sr.utcr2 = Ser2UTCR2; -+ sr.utcr3 = Ser2UTCR3; -+ sr.utcr4 = Ser2UTCR4; -+ -+ sr.utdr = Ser2UTDR; -+ sr.utsr0 = Ser2UTSR0; -+ sr.utsr1 = Ser2UTSR1; -+ -+ /* configure GPIO */ -+ /* output */ -+ PPDR |= PPC_TXD2; -+ PSDR |= PPC_TXD2; -+ /* set output to 0 */ -+ off(); -+ -+ /* Enable HP-SIR modulation, and ensure that the port is disabled. */ -+ Ser2UTCR3 = 0; -+ Ser2HSCR0 = sr.hscr0 & (~HSCR0_HSSP); -+ -+ /* clear status register to prevent unwanted interrupts */ -+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ -+ /* 7N1 */ -+ Ser2UTCR0 = UTCR0_1StpBit|UTCR0_7BitData; -+ /* 115200 */ -+ Ser2UTCR1 = 0; -+ Ser2UTCR2 = 1; -+ /* use HPSIR, 1.6 usec pulses */ -+ Ser2UTCR4 = UTCR4_HPSIR|UTCR4_Z1_6us; -+ -+ /* enable receiver, receive fifo interrupt */ -+ Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; -+ -+ /* clear status register to prevent unwanted interrupts */ -+ Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); -+ -+#elif defined(LIRC_SIR_TEKRAM) -+ /* disable FIFO */ -+ soutp(UART_FCR, -+ UART_FCR_CLEAR_RCVR| -+ UART_FCR_CLEAR_XMIT| -+ UART_FCR_TRIGGER_1); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* First of all, disable all interrupts */ -+ soutp(UART_IER, sinp(UART_IER) & -+ (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ -+ /* Set divisor to 12 => 9600 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 12); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* power supply */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ safe_udelay(50*1000); -+ -+ /* -DTR low -> reset PIC */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ udelay(1*1000); -+ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(100); -+ -+ -+ /* -RTS low -> send control byte */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(7); -+ soutp(UART_TX, TEKRAM_115200|TEKRAM_PW); -+ -+ /* one byte takes ~1042 usec to transmit at 9600,8N1 */ -+ udelay(1500); -+ -+ /* back to normal operation */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(50); -+ -+ udelay(1500); -+ -+ /* read previous control byte */ -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": 0x%02x\n", sinp(UART_RX)); -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ -+ /* Set DLAB 0, 8 Bit */ -+ soutp(UART_LCR, UART_LCR_WLEN8); -+ /* enable interrupts */ -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); -+#else -+ outb(0, io + UART_MCR); -+ outb(0, io + UART_IER); -+ /* init UART */ -+ /* set DLAB, speed = 115200 */ -+ outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR); -+ outb(1, io + UART_DLL); outb(0, io + UART_DLM); -+ /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */ -+ outb(UART_LCR_WLEN7, io + UART_LCR); -+ /* FIFO operation */ -+ outb(UART_FCR_ENABLE_FIFO, io + UART_FCR); -+ /* interrupts */ -+ /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */ -+ outb(UART_IER_RDI, io + UART_IER); -+ /* turn on UART */ -+ outb(UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2, io + UART_MCR); -+#ifdef LIRC_SIR_ACTISYS_ACT200L -+ init_act200(); -+#elif defined(LIRC_SIR_ACTISYS_ACT220L) -+ init_act220(); -+#endif -+#endif -+ spin_unlock_irqrestore(&hardware_lock, flags); -+ return 0; -+} -+ -+static void drop_hardware(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hardware_lock, flags); -+ -+#ifdef LIRC_ON_SA1100 -+ Ser2UTCR3 = 0; -+ -+ Ser2UTCR0 = sr.utcr0; -+ Ser2UTCR1 = sr.utcr1; -+ Ser2UTCR2 = sr.utcr2; -+ Ser2UTCR4 = sr.utcr4; -+ Ser2UTCR3 = sr.utcr3; -+ -+ Ser2HSCR0 = sr.hscr0; -+#ifdef CONFIG_SA1100_BITSY -+ if (machine_is_bitsy()) -+ clr_bitsy_egpio(EGPIO_BITSY_IR_ON); -+#endif -+#ifdef CONFIG_SA1100_COLLIE -+ sa1100_irda_set_power_collie(0); /* power off */ -+#endif -+#else -+ /* turn off interrupts */ -+ outb(0, io + UART_IER); -+#endif -+ spin_unlock_irqrestore(&hardware_lock, flags); -+} -+ -+/* SECTION: Initialisation */ -+ -+static int init_port(void) -+{ -+ int retval; -+ -+ /* get I/O port access and IRQ line */ -+#ifndef LIRC_ON_SA1100 -+ if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": i/o port 0x%.4x already in use.\n", io); -+ return -EBUSY; -+ } -+#endif -+ retval = request_irq(irq, sir_interrupt, IRQF_DISABLED, -+ LIRC_DRIVER_NAME, NULL); -+ if (retval < 0) { -+# ifndef LIRC_ON_SA1100 -+ release_region(io, 8); -+# endif -+ printk(KERN_ERR LIRC_DRIVER_NAME -+ ": IRQ %d already in use.\n", -+ irq); -+ return retval; -+ } -+#ifndef LIRC_ON_SA1100 -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": I/O port 0x%.4x, IRQ %d.\n", -+ io, irq); -+#endif -+ -+ init_timer(&timerlist); -+ timerlist.function = sir_timeout; -+ timerlist.data = 0xabadcafe; -+ -+ return 0; -+} -+ -+static void drop_port(void) -+{ -+ free_irq(irq, NULL); -+ del_timer_sync(&timerlist); -+#ifndef LIRC_ON_SA1100 -+ release_region(io, 8); -+#endif -+} -+ -+#ifdef LIRC_SIR_ACTISYS_ACT200L -+/* Crystal/Cirrus CS8130 IR transceiver, used in Actisys Act200L dongle */ -+/* some code borrowed from Linux IRDA driver */ -+ -+/* Register 0: Control register #1 */ -+#define ACT200L_REG0 0x00 -+#define ACT200L_TXEN 0x01 /* Enable transmitter */ -+#define ACT200L_RXEN 0x02 /* Enable receiver */ -+#define ACT200L_ECHO 0x08 /* Echo control chars */ -+ -+/* Register 1: Control register #2 */ -+#define ACT200L_REG1 0x10 -+#define ACT200L_LODB 0x01 /* Load new baud rate count value */ -+#define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */ -+ -+/* Register 3: Transmit mode register #2 */ -+#define ACT200L_REG3 0x30 -+#define ACT200L_B0 0x01 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ -+#define ACT200L_B1 0x02 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P) */ -+#define ACT200L_CHSY 0x04 /* StartBit Synced 0=bittime, 1=startbit */ -+ -+/* Register 4: Output Power register */ -+#define ACT200L_REG4 0x40 -+#define ACT200L_OP0 0x01 /* Enable LED1C output */ -+#define ACT200L_OP1 0x02 /* Enable LED2C output */ -+#define ACT200L_BLKR 0x04 -+ -+/* Register 5: Receive Mode register */ -+#define ACT200L_REG5 0x50 -+#define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */ -+ /*.. other various IRDA bit modes, and TV remote modes..*/ -+ -+/* Register 6: Receive Sensitivity register #1 */ -+#define ACT200L_REG6 0x60 -+#define ACT200L_RS0 0x01 /* receive threshold bit 0 */ -+#define ACT200L_RS1 0x02 /* receive threshold bit 1 */ -+ -+/* Register 7: Receive Sensitivity register #2 */ -+#define ACT200L_REG7 0x70 -+#define ACT200L_ENPOS 0x04 /* Ignore the falling edge */ -+ -+/* Register 8,9: Baud Rate Divider register #1,#2 */ -+#define ACT200L_REG8 0x80 -+#define ACT200L_REG9 0x90 -+ -+#define ACT200L_2400 0x5f -+#define ACT200L_9600 0x17 -+#define ACT200L_19200 0x0b -+#define ACT200L_38400 0x05 -+#define ACT200L_57600 0x03 -+#define ACT200L_115200 0x01 -+ -+/* Register 13: Control register #3 */ -+#define ACT200L_REG13 0xd0 -+#define ACT200L_SHDW 0x01 /* Enable access to shadow registers */ -+ -+/* Register 15: Status register */ -+#define ACT200L_REG15 0xf0 -+ -+/* Register 21: Control register #4 */ -+#define ACT200L_REG21 0x50 -+#define ACT200L_EXCK 0x02 /* Disable clock output driver */ -+#define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */ -+ -+static void init_act200(void) -+{ -+ int i; -+ __u8 control[] = { -+ ACT200L_REG15, -+ ACT200L_REG13 | ACT200L_SHDW, -+ ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL, -+ ACT200L_REG13, -+ ACT200L_REG7 | ACT200L_ENPOS, -+ ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1, -+ ACT200L_REG5 | ACT200L_RWIDL, -+ ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR, -+ ACT200L_REG3 | ACT200L_B0, -+ ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN, -+ ACT200L_REG8 | (ACT200L_115200 & 0x0f), -+ ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f), -+ ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE -+ }; -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); -+ -+ /* Set divisor to 12 => 9600 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 12); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, UART_LCR_WLEN8); -+ /* Set divisor to 12 => 9600 Baud */ -+ -+ /* power supply */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ for (i = 0; i < 50; i++) -+ safe_udelay(1000); -+ -+ /* Reset the dongle : set RTS low for 25 ms */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); -+ for (i = 0; i < 25; i++) -+ udelay(1000); -+ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(100); -+ -+ /* Clear DTR and set RTS to enter command mode */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ udelay(7); -+ -+ /* send out the control register settings for 115K 7N1 SIR operation */ -+ for (i = 0; i < sizeof(control); i++) { -+ soutp(UART_TX, control[i]); -+ /* one byte takes ~1042 usec to transmit at 9600,8N1 */ -+ udelay(1500); -+ } -+ -+ /* back to normal operation */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(50); -+ -+ udelay(1500); -+ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); -+ -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ -+ /* Set DLAB 0. */ -+ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); -+ -+ /* Set DLAB 0, 7 Bit */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ -+ /* enable interrupts */ -+ soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI); -+} -+#endif -+ -+#ifdef LIRC_SIR_ACTISYS_ACT220L -+/* -+ * Derived from linux IrDA driver (net/irda/actisys.c) -+ * Drop me a mail for any kind of comment: maxx@spaceboyz.net -+ */ -+ -+void init_act220(void) -+{ -+ int i; -+ -+ /* DLAB 1 */ -+ soutp(UART_LCR, UART_LCR_DLAB|UART_LCR_WLEN7); -+ -+ /* 9600 baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 12); -+ -+ /* DLAB 0 */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ -+ /* reset the dongle, set DTR low for 10us */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2); -+ udelay(10); -+ -+ /* back to normal (still 9600) */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2); -+ -+ /* -+ * send RTS pulses until we reach 115200 -+ * i hope this is really the same for act220l/act220l+ -+ */ -+ for (i = 0; i < 3; i++) { -+ udelay(10); -+ /* set RTS low for 10 us */ -+ soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2); -+ udelay(10); -+ /* set RTS high for 10 us */ -+ soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2); -+ } -+ -+ /* back to normal operation */ -+ udelay(1500); /* better safe than sorry ;) */ -+ -+ /* Set DLAB 1. */ -+ soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7); -+ -+ /* Set divisor to 1 => 115200 Baud */ -+ soutp(UART_DLM, 0); -+ soutp(UART_DLL, 1); -+ -+ /* Set DLAB 0, 7 Bit */ -+ /* The dongle doesn't seem to have any problems with operation at 7N1 */ -+ soutp(UART_LCR, UART_LCR_WLEN7); -+ -+ /* enable interrupts */ -+ soutp(UART_IER, UART_IER_RDI); -+} -+#endif -+ -+static int init_lirc_sir(void) -+{ -+ int retval; -+ -+ init_waitqueue_head(&lirc_read_queue); -+ retval = init_port(); -+ if (retval < 0) -+ return retval; -+ init_hardware(); -+ printk(KERN_INFO LIRC_DRIVER_NAME -+ ": Installed.\n"); -+ return 0; -+} -+ -+ -+static int __init lirc_sir_init(void) -+{ -+ int retval; -+ -+ retval = init_chrdev(); -+ if (retval < 0) -+ return retval; -+ retval = init_lirc_sir(); -+ if (retval) { -+ drop_chrdev(); -+ return retval; -+ } -+ return 0; -+} -+ -+static void __exit lirc_sir_exit(void) -+{ -+ drop_hardware(); -+ drop_chrdev(); -+ drop_port(); -+ printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); -+} -+ -+module_init(lirc_sir_init); -+module_exit(lirc_sir_exit); -+ -+#ifdef LIRC_SIR_TEKRAM -+MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210"); -+MODULE_AUTHOR("Christoph Bartelmus"); -+#elif defined(LIRC_ON_SA1100) -+MODULE_DESCRIPTION("LIRC driver for StrongARM SA1100 embedded microprocessor"); -+MODULE_AUTHOR("Christoph Bartelmus"); -+#elif defined(LIRC_SIR_ACTISYS_ACT200L) -+MODULE_DESCRIPTION("LIRC driver for Actisys Act200L"); -+MODULE_AUTHOR("Karl Bongers"); -+#elif defined(LIRC_SIR_ACTISYS_ACT220L) -+MODULE_DESCRIPTION("LIRC driver for Actisys Act220L(+)"); -+MODULE_AUTHOR("Jan Roemisch"); -+#else -+MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports"); -+MODULE_AUTHOR("Milan Pikula"); -+#endif -+MODULE_LICENSE("GPL"); -+ -+#ifdef LIRC_ON_SA1100 -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (16)"); -+#else -+module_param(io, int, S_IRUGO); -+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); -+ -+module_param(irq, int, S_IRUGO); -+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); -+ -+module_param(threshold, int, S_IRUGO); -+MODULE_PARM_DESC(threshold, "space detection threshold (3)"); -+#endif -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff --git a/drivers/staging/lirc/lirc_streamzap.c b/drivers/staging/lirc/lirc_streamzap.c -new file mode 100644 -index 0000000..be09c10 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_streamzap.c -@@ -0,0 +1,821 @@ -+/* -+ * Streamzap Remote Control driver -+ * -+ * Copyright (c) 2005 Christoph Bartelmus <lirc@bartelmus.de> -+ * -+ * This driver was based on the work of Greg Wickham and Adrian -+ * Dewhurst. It was substantially rewritten to support correct signal -+ * gaps and now maintains a delay buffer, which is used to present -+ * consistent timing behaviour to user space applications. Without the -+ * delay buffer an ugly hack would be required in lircd, which can -+ * cause sluggish signal decoding in certain situations. -+ * -+ * This driver is based on the USB skeleton driver packaged with the -+ * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/slab.h> -+#include <linux/module.h> -+#include <linux/smp_lock.h> -+#include <linux/completion.h> -+#include <linux/uaccess.h> -+#include <linux/usb.h> -+ -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+ -+#define DRIVER_VERSION "1.28" -+#define DRIVER_NAME "lirc_streamzap" -+#define DRIVER_DESC "Streamzap Remote Control driver" -+ -+static int debug; -+ -+#define USB_STREAMZAP_VENDOR_ID 0x0e9c -+#define USB_STREAMZAP_PRODUCT_ID 0x0000 -+ -+/* Use our own dbg macro */ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG DRIVER_NAME "[%d]: " \ -+ fmt "\n", ## args); \ -+ } while (0) -+ -+/* table of devices that work with this driver */ -+static struct usb_device_id streamzap_table[] = { -+ /* Streamzap Remote Control */ -+ { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) }, -+ /* Terminating entry */ -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(usb, streamzap_table); -+ -+#define STREAMZAP_PULSE_MASK 0xf0 -+#define STREAMZAP_SPACE_MASK 0x0f -+#define STREAMZAP_TIMEOUT 0xff -+#define STREAMZAP_RESOLUTION 256 -+ -+/* number of samples buffered */ -+#define STREAMZAP_BUF_LEN 128 -+ -+enum StreamzapDecoderState { -+ PulseSpace, -+ FullPulse, -+ FullSpace, -+ IgnorePulse -+}; -+ -+/* Structure to hold all of our device specific stuff -+ * -+ * some remarks regarding locking: -+ * theoretically this struct can be accessed from three threads: -+ * -+ * - from lirc_dev through set_use_inc/set_use_dec -+ * -+ * - from the USB layer throuh probe/disconnect/irq -+ * -+ * Careful placement of lirc_register_driver/lirc_unregister_driver -+ * calls will prevent conflicts. lirc_dev makes sure that -+ * set_use_inc/set_use_dec are not being executed and will not be -+ * called after lirc_unregister_driver returns. -+ * -+ * - by the timer callback -+ * -+ * The timer is only running when the device is connected and the -+ * LIRC device is open. Making sure the timer is deleted by -+ * set_use_dec will make conflicts impossible. -+ */ -+struct usb_streamzap { -+ -+ /* usb */ -+ /* save off the usb device pointer */ -+ struct usb_device *udev; -+ /* the interface for this device */ -+ struct usb_interface *interface; -+ -+ /* buffer & dma */ -+ unsigned char *buf_in; -+ dma_addr_t dma_in; -+ unsigned int buf_in_len; -+ -+ struct usb_endpoint_descriptor *endpoint; -+ -+ /* IRQ */ -+ struct urb *urb_in; -+ -+ /* lirc */ -+ struct lirc_driver *driver; -+ struct lirc_buffer *delay_buf; -+ -+ /* timer used to support delay buffering */ -+ struct timer_list delay_timer; -+ int timer_running; -+ spinlock_t timer_lock; -+ -+ /* tracks whether we are currently receiving some signal */ -+ int idle; -+ /* sum of signal lengths received since signal start */ -+ unsigned long sum; -+ /* start time of signal; necessary for gap tracking */ -+ struct timeval signal_last; -+ struct timeval signal_start; -+ enum StreamzapDecoderState decoder_state; -+ struct timer_list flush_timer; -+ int flush; -+ int in_use; -+ int timeout_enabled; -+}; -+ -+ -+/* local function prototypes */ -+static int streamzap_probe(struct usb_interface *interface, -+ const struct usb_device_id *id); -+static void streamzap_disconnect(struct usb_interface *interface); -+static void usb_streamzap_irq(struct urb *urb); -+static int streamzap_use_inc(void *data); -+static void streamzap_use_dec(void *data); -+static long streamzap_ioctl(struct file *filep, unsigned int cmd, -+ unsigned long arg); -+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message); -+static int streamzap_resume(struct usb_interface *intf); -+ -+/* usb specific object needed to register this driver with the usb subsystem */ -+ -+static struct usb_driver streamzap_driver = { -+ .name = DRIVER_NAME, -+ .probe = streamzap_probe, -+ .disconnect = streamzap_disconnect, -+ .suspend = streamzap_suspend, -+ .resume = streamzap_resume, -+ .id_table = streamzap_table, -+}; -+ -+static void stop_timer(struct usb_streamzap *sz) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ if (sz->timer_running) { -+ sz->timer_running = 0; -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+ del_timer_sync(&sz->delay_timer); -+ } else { -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+ } -+} -+ -+static void flush_timeout(unsigned long arg) -+{ -+ struct usb_streamzap *sz = (struct usb_streamzap *) arg; -+ -+ /* finally start accepting data */ -+ sz->flush = 0; -+} -+static void delay_timeout(unsigned long arg) -+{ -+ unsigned long flags; -+ /* deliver data every 10 ms */ -+ static unsigned long timer_inc = -+ (10000/(1000000/HZ)) == 0 ? 1 : (10000/(1000000/HZ)); -+ struct usb_streamzap *sz = (struct usb_streamzap *) arg; -+ int data; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ -+ if (!lirc_buffer_empty(sz->delay_buf) && -+ !lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_read(sz->delay_buf, (unsigned char *) &data); -+ lirc_buffer_write(sz->driver->rbuf, (unsigned char *) &data); -+ } -+ if (!lirc_buffer_empty(sz->delay_buf)) { -+ while (lirc_buffer_available(sz->delay_buf) < -+ STREAMZAP_BUF_LEN / 2 && -+ !lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_read(sz->delay_buf, -+ (unsigned char *) &data); -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &data); -+ } -+ if (sz->timer_running) { -+ sz->delay_timer.expires = jiffies + timer_inc; -+ add_timer(&sz->delay_timer); -+ } -+ } else { -+ sz->timer_running = 0; -+ } -+ -+ if (!lirc_buffer_empty(sz->driver->rbuf)) -+ wake_up(&sz->driver->rbuf->wait_poll); -+ -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+} -+ -+static void flush_delay_buffer(struct usb_streamzap *sz) -+{ -+ int data; -+ int empty = 1; -+ -+ while (!lirc_buffer_empty(sz->delay_buf)) { -+ empty = 0; -+ lirc_buffer_read(sz->delay_buf, (unsigned char *) &data); -+ if (!lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &data); -+ } else { -+ dprintk("buffer overflow", sz->driver->minor); -+ } -+ } -+ if (!empty) -+ wake_up(&sz->driver->rbuf->wait_poll); -+} -+ -+static void push(struct usb_streamzap *sz, unsigned char *data) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sz->timer_lock, flags); -+ if (lirc_buffer_full(sz->delay_buf)) { -+ int read_data; -+ -+ lirc_buffer_read(sz->delay_buf, -+ (unsigned char *) &read_data); -+ if (!lirc_buffer_full(sz->driver->rbuf)) { -+ lirc_buffer_write(sz->driver->rbuf, -+ (unsigned char *) &read_data); -+ } else { -+ dprintk("buffer overflow", sz->driver->minor); -+ } -+ } -+ -+ lirc_buffer_write(sz->delay_buf, data); -+ -+ if (!sz->timer_running) { -+ sz->delay_timer.expires = jiffies + HZ/10; -+ add_timer(&sz->delay_timer); -+ sz->timer_running = 1; -+ } -+ -+ spin_unlock_irqrestore(&sz->timer_lock, flags); -+} -+ -+static void push_full_pulse(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ int pulse; -+ -+ if (sz->idle) { -+ long deltv; -+ int tmp; -+ -+ sz->signal_last = sz->signal_start; -+ do_gettimeofday(&sz->signal_start); -+ -+ deltv = sz->signal_start.tv_sec-sz->signal_last.tv_sec; -+ if (deltv > 15) { -+ /* really long time */ -+ tmp = LIRC_SPACE(LIRC_VALUE_MASK); -+ } else { -+ tmp = (int) (deltv*1000000+ -+ sz->signal_start.tv_usec - -+ sz->signal_last.tv_usec); -+ tmp -= sz->sum; -+ tmp = LIRC_SPACE(tmp); -+ } -+ dprintk("ls %u", sz->driver->minor, tmp); -+ push(sz, (char *)&tmp); -+ -+ sz->idle = 0; -+ sz->sum = 0; -+ } -+ -+ pulse = ((int) value) * STREAMZAP_RESOLUTION; -+ pulse += STREAMZAP_RESOLUTION / 2; -+ sz->sum += pulse; -+ pulse = LIRC_PULSE(pulse); -+ -+ dprintk("p %u", sz->driver->minor, pulse & PULSE_MASK); -+ push(sz, (char *)&pulse); -+} -+ -+static void push_half_pulse(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK)>>4); -+} -+ -+static void push_full_space(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ int space; -+ -+ space = ((int) value)*STREAMZAP_RESOLUTION; -+ space += STREAMZAP_RESOLUTION/2; -+ sz->sum += space; -+ space = LIRC_SPACE(space); -+ dprintk("s %u", sz->driver->minor, space); -+ push(sz, (char *)&space); -+} -+ -+static void push_half_space(struct usb_streamzap *sz, -+ unsigned char value) -+{ -+ push_full_space(sz, value & STREAMZAP_SPACE_MASK); -+} -+ -+/** -+ * usb_streamzap_irq - IRQ handler -+ * -+ * This procedure is invoked on reception of data from -+ * the usb remote. -+ */ -+static void usb_streamzap_irq(struct urb *urb) -+{ -+ struct usb_streamzap *sz; -+ int len; -+ unsigned int i = 0; -+ -+ if (!urb) -+ return; -+ -+ sz = urb->context; -+ len = urb->actual_length; -+ -+ switch (urb->status) { -+ case -ECONNRESET: -+ case -ENOENT: -+ case -ESHUTDOWN: -+ /* -+ * this urb is terminated, clean up. -+ * sz might already be invalid at this point -+ */ -+ dprintk("urb status: %d", -1, urb->status); -+ return; -+ default: -+ break; -+ } -+ -+ dprintk("received %d", sz->driver->minor, urb->actual_length); -+ if (!sz->flush) { -+ for (i = 0; i < urb->actual_length; i++) { -+ dprintk("%d: %x", sz->driver->minor, -+ i, (unsigned char) sz->buf_in[i]); -+ switch (sz->decoder_state) { -+ case PulseSpace: -+ if ((sz->buf_in[i]&STREAMZAP_PULSE_MASK) == -+ STREAMZAP_PULSE_MASK) { -+ sz->decoder_state = FullPulse; -+ continue; -+ } else if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) -+ == STREAMZAP_SPACE_MASK) { -+ push_half_pulse(sz, sz->buf_in[i]); -+ sz->decoder_state = FullSpace; -+ continue; -+ } else { -+ push_half_pulse(sz, sz->buf_in[i]); -+ push_half_space(sz, sz->buf_in[i]); -+ } -+ break; -+ case FullPulse: -+ push_full_pulse(sz, sz->buf_in[i]); -+ sz->decoder_state = IgnorePulse; -+ break; -+ case FullSpace: -+ if (sz->buf_in[i] == STREAMZAP_TIMEOUT) { -+ sz->idle = 1; -+ stop_timer(sz); -+ if (sz->timeout_enabled) { -+ int timeout = -+ LIRC_TIMEOUT -+ (STREAMZAP_TIMEOUT * -+ STREAMZAP_RESOLUTION); -+ push(sz, (char *)&timeout); -+ } -+ flush_delay_buffer(sz); -+ } else -+ push_full_space(sz, sz->buf_in[i]); -+ sz->decoder_state = PulseSpace; -+ break; -+ case IgnorePulse: -+ if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) == -+ STREAMZAP_SPACE_MASK) { -+ sz->decoder_state = FullSpace; -+ continue; -+ } -+ push_half_space(sz, sz->buf_in[i]); -+ sz->decoder_state = PulseSpace; -+ break; -+ } -+ } -+ } -+ -+ usb_submit_urb(urb, GFP_ATOMIC); -+ -+ return; -+} -+ -+static const struct file_operations streamzap_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = streamzap_ioctl, -+ .read = lirc_dev_fop_read, -+ .write = lirc_dev_fop_write, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+ -+/** -+ * streamzap_probe -+ * -+ * Called by usb-core to associated with a candidate device -+ * On any failure the return value is the ERROR -+ * On success return 0 -+ */ -+static int streamzap_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *udev = interface_to_usbdev(interface); -+ struct usb_host_interface *iface_host; -+ struct usb_streamzap *sz; -+ struct lirc_driver *driver; -+ struct lirc_buffer *lirc_buf; -+ struct lirc_buffer *delay_buf; -+ char buf[63], name[128] = ""; -+ int retval = -ENOMEM; -+ int minor = 0; -+ -+ /* Allocate space for device driver specific data */ -+ sz = kzalloc(sizeof(struct usb_streamzap), GFP_KERNEL); -+ if (sz == NULL) -+ return -ENOMEM; -+ -+ sz->udev = udev; -+ sz->interface = interface; -+ -+ /* Check to ensure endpoint information matches requirements */ -+ iface_host = interface->cur_altsetting; -+ -+ if (iface_host->desc.bNumEndpoints != 1) { -+ err("%s: Unexpected desc.bNumEndpoints (%d)", __func__, -+ iface_host->desc.bNumEndpoints); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ sz->endpoint = &(iface_host->endpoint[0].desc); -+ if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ != USB_DIR_IN) { -+ err("%s: endpoint doesn't match input device 02%02x", -+ __func__, sz->endpoint->bEndpointAddress); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ != USB_ENDPOINT_XFER_INT) { -+ err("%s: endpoint attributes don't match xfer 02%02x", -+ __func__, sz->endpoint->bmAttributes); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ if (sz->endpoint->wMaxPacketSize == 0) { -+ err("%s: endpoint message size==0? ", __func__); -+ retval = -ENODEV; -+ goto free_sz; -+ } -+ -+ /* Allocate the USB buffer and IRQ URB */ -+ -+ sz->buf_in_len = sz->endpoint->wMaxPacketSize; -+ sz->buf_in = usb_alloc_coherent(sz->udev, sz->buf_in_len, -+ GFP_ATOMIC, &sz->dma_in); -+ if (sz->buf_in == NULL) -+ goto free_sz; -+ -+ sz->urb_in = usb_alloc_urb(0, GFP_KERNEL); -+ if (sz->urb_in == NULL) -+ goto free_sz; -+ -+ /* Connect this device to the LIRC sub-system */ -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) -+ goto free_sz; -+ -+ lirc_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!lirc_buf) -+ goto free_driver; -+ if (lirc_buffer_init(lirc_buf, sizeof(int), STREAMZAP_BUF_LEN)) -+ goto kfree_lirc_buf; -+ -+ delay_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!delay_buf) -+ goto free_lirc_buf; -+ if (lirc_buffer_init(delay_buf, sizeof(int), STREAMZAP_BUF_LEN)) -+ goto kfree_delay_buf; -+ -+ sz->driver = driver; -+ strcpy(sz->driver->name, DRIVER_NAME); -+ sz->driver->minor = -1; -+ sz->driver->sample_rate = 0; -+ sz->driver->code_length = sizeof(int) * 8; -+ sz->driver->features = LIRC_CAN_REC_MODE2 | -+ LIRC_CAN_GET_REC_RESOLUTION | -+ LIRC_CAN_SET_REC_TIMEOUT; -+ sz->driver->data = sz; -+ sz->driver->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION; -+ sz->driver->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION; -+ sz->driver->rbuf = lirc_buf; -+ sz->delay_buf = delay_buf; -+ sz->driver->set_use_inc = &streamzap_use_inc; -+ sz->driver->set_use_dec = &streamzap_use_dec; -+ sz->driver->fops = &streamzap_fops; -+ sz->driver->dev = &interface->dev; -+ sz->driver->owner = THIS_MODULE; -+ -+ sz->idle = 1; -+ sz->decoder_state = PulseSpace; -+ init_timer(&sz->delay_timer); -+ sz->delay_timer.function = delay_timeout; -+ sz->delay_timer.data = (unsigned long) sz; -+ sz->timer_running = 0; -+ spin_lock_init(&sz->timer_lock); -+ -+ init_timer(&sz->flush_timer); -+ sz->flush_timer.function = flush_timeout; -+ sz->flush_timer.data = (unsigned long) sz; -+ /* Complete final initialisations */ -+ -+ usb_fill_int_urb(sz->urb_in, udev, -+ usb_rcvintpipe(udev, sz->endpoint->bEndpointAddress), -+ sz->buf_in, sz->buf_in_len, usb_streamzap_irq, sz, -+ sz->endpoint->bInterval); -+ sz->urb_in->transfer_dma = sz->dma_in; -+ sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ if (udev->descriptor.iManufacturer -+ && usb_string(udev, udev->descriptor.iManufacturer, -+ buf, sizeof(buf)) > 0) -+ strlcpy(name, buf, sizeof(name)); -+ -+ if (udev->descriptor.iProduct -+ && usb_string(udev, udev->descriptor.iProduct, -+ buf, sizeof(buf)) > 0) -+ snprintf(name + strlen(name), sizeof(name) - strlen(name), -+ " %s", buf); -+ -+ minor = lirc_register_driver(driver); -+ -+ if (minor < 0) -+ goto free_delay_buf; -+ -+ sz->driver->minor = minor; -+ -+ usb_set_intfdata(interface, sz); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: %s on usb%d:%d attached\n", -+ sz->driver->minor, name, -+ udev->bus->busnum, sz->udev->devnum); -+ -+ return 0; -+ -+free_delay_buf: -+ lirc_buffer_free(sz->delay_buf); -+kfree_delay_buf: -+ kfree(delay_buf); -+free_lirc_buf: -+ lirc_buffer_free(sz->driver->rbuf); -+kfree_lirc_buf: -+ kfree(lirc_buf); -+free_driver: -+ kfree(driver); -+free_sz: -+ if (retval == -ENOMEM) -+ err("Out of memory"); -+ -+ if (sz) { -+ usb_free_urb(sz->urb_in); -+ usb_free_coherent(udev, sz->buf_in_len, sz->buf_in, sz->dma_in); -+ kfree(sz); -+ } -+ -+ return retval; -+} -+ -+static int streamzap_use_inc(void *data) -+{ -+ struct usb_streamzap *sz = data; -+ -+ if (!sz) { -+ dprintk("%s called with no context", -1, __func__); -+ return -EINVAL; -+ } -+ dprintk("set use inc", sz->driver->minor); -+ -+ lirc_buffer_clear(sz->driver->rbuf); -+ lirc_buffer_clear(sz->delay_buf); -+ -+ sz->flush_timer.expires = jiffies + HZ; -+ sz->flush = 1; -+ add_timer(&sz->flush_timer); -+ -+ sz->urb_in->dev = sz->udev; -+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { -+ dprintk("open result = -EIO error submitting urb", -+ sz->driver->minor); -+ return -EIO; -+ } -+ sz->in_use++; -+ -+ return 0; -+} -+ -+static void streamzap_use_dec(void *data) -+{ -+ struct usb_streamzap *sz = data; -+ -+ if (!sz) { -+ dprintk("%s called with no context", -1, __func__); -+ return; -+ } -+ dprintk("set use dec", sz->driver->minor); -+ -+ if (sz->flush) { -+ sz->flush = 0; -+ del_timer_sync(&sz->flush_timer); -+ } -+ -+ usb_kill_urb(sz->urb_in); -+ -+ stop_timer(sz); -+ -+ sz->in_use--; -+} -+ -+static long streamzap_ioctl(struct file *filep, unsigned int cmd, -+ unsigned long arg) -+{ -+ int result = 0; -+ int val; -+ struct usb_streamzap *sz = lirc_get_pdata(filep); -+ -+ switch (cmd) { -+ case LIRC_GET_REC_RESOLUTION: -+ result = put_user(STREAMZAP_RESOLUTION, (unsigned int *) arg); -+ break; -+ case LIRC_SET_REC_TIMEOUT: -+ result = get_user(val, (int *)arg); -+ if (result == 0) { -+ if (val == STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) -+ sz->timeout_enabled = 1; -+ else if (val == 0) -+ sz->timeout_enabled = 0; -+ else -+ result = -EINVAL; -+ } -+ break; -+ default: -+ return lirc_dev_fop_ioctl(filep, cmd, arg); -+ } -+ return result; -+} -+ -+/** -+ * streamzap_disconnect -+ * -+ * Called by the usb core when the device is removed from the system. -+ * -+ * This routine guarantees that the driver will not submit any more urbs -+ * by clearing dev->udev. It is also supposed to terminate any currently -+ * active urbs. Unfortunately, usb_bulk_msg(), used in streamzap_read(), -+ * does not provide any way to do this. -+ */ -+static void streamzap_disconnect(struct usb_interface *interface) -+{ -+ struct usb_streamzap *sz; -+ int errnum; -+ int minor; -+ -+ sz = usb_get_intfdata(interface); -+ -+ /* unregister from the LIRC sub-system */ -+ -+ errnum = lirc_unregister_driver(sz->driver->minor); -+ if (errnum != 0) -+ dprintk("error in lirc_unregister: (returned %d)", -+ sz->driver->minor, errnum); -+ -+ lirc_buffer_free(sz->delay_buf); -+ lirc_buffer_free(sz->driver->rbuf); -+ -+ /* unregister from the USB sub-system */ -+ -+ usb_free_urb(sz->urb_in); -+ -+ usb_free_coherent(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in); -+ -+ minor = sz->driver->minor; -+ kfree(sz->driver->rbuf); -+ kfree(sz->driver); -+ kfree(sz->delay_buf); -+ kfree(sz); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: disconnected\n", minor); -+} -+ -+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct usb_streamzap *sz = usb_get_intfdata(intf); -+ -+ printk(KERN_INFO DRIVER_NAME "[%d]: suspend\n", sz->driver->minor); -+ if (sz->in_use) { -+ if (sz->flush) { -+ sz->flush = 0; -+ del_timer_sync(&sz->flush_timer); -+ } -+ -+ stop_timer(sz); -+ -+ usb_kill_urb(sz->urb_in); -+ } -+ return 0; -+} -+ -+static int streamzap_resume(struct usb_interface *intf) -+{ -+ struct usb_streamzap *sz = usb_get_intfdata(intf); -+ -+ lirc_buffer_clear(sz->driver->rbuf); -+ lirc_buffer_clear(sz->delay_buf); -+ -+ if (sz->in_use) { -+ sz->flush_timer.expires = jiffies + HZ; -+ sz->flush = 1; -+ add_timer(&sz->flush_timer); -+ -+ sz->urb_in->dev = sz->udev; -+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { -+ dprintk("open result = -EIO error submitting urb", -+ sz->driver->minor); -+ return -EIO; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * usb_streamzap_init -+ */ -+static int __init usb_streamzap_init(void) -+{ -+ int result; -+ -+ /* register this driver with the USB subsystem */ -+ result = usb_register(&streamzap_driver); -+ -+ if (result) { -+ err("usb_register failed. Error number %d", -+ result); -+ return result; -+ } -+ -+ printk(KERN_INFO DRIVER_NAME " " DRIVER_VERSION " registered\n"); -+ return 0; -+} -+ -+/** -+ * usb_streamzap_exit -+ */ -+static void __exit usb_streamzap_exit(void) -+{ -+ usb_deregister(&streamzap_driver); -+} -+ -+ -+module_init(usb_streamzap_init); -+module_exit(usb_streamzap_exit); -+ -+MODULE_AUTHOR("Christoph Bartelmus, Greg Wickham, Adrian Dewhurst"); -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+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 0000000..e345ab9 ---- /dev/null -+++ b/drivers/staging/lirc/lirc_ttusbir.c -@@ -0,0 +1,396 @@ -+/* -+ * lirc_ttusbir.c -+ * -+ * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver -+ * -+ * Copyright (C) 2007 Stefan Macher <st_maker-lirc@yahoo.de> -+ * -+ * This LIRC driver provides access to the TechnoTrend USB IR Receiver. -+ * The receiver delivers the IR signal as raw sampled true/false data in -+ * isochronous USB packets each of size 128 byte. -+ * Currently the driver reduces the sampling rate by factor of 8 as this -+ * is still more than enough to decode RC-5 - others should be analyzed. -+ * But the driver does not rely on RC-5 it should be able to decode every -+ * IR signal that is not too fast. -+ */ -+ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include <linux/version.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/errno.h> -+#include <linux/slab.h> -+#include <linux/usb.h> -+ -+#include <media/lirc.h> -+#include <media/lirc_dev.h> -+ -+MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC"); -+MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)"); -+MODULE_LICENSE("GPL"); -+ -+/* #define DEBUG */ -+#ifdef DEBUG -+#define DPRINTK printk -+#else -+#define DPRINTK(_x_, a...) -+#endif -+ -+/* function declarations */ -+static int probe(struct usb_interface *intf, const struct usb_device_id *id); -+static void disconnect(struct usb_interface *intf); -+static void urb_complete(struct urb *urb); -+static int set_use_inc(void *data); -+static void set_use_dec(void *data); -+ -+static int num_urbs = 2; -+module_param(num_urbs, int, S_IRUGO); -+MODULE_PARM_DESC(num_urbs, -+ "Number of URBs in queue. Try to increase to 4 in case " -+ "of problems (default: 2; minimum: 2)"); -+ -+/* table of devices that work with this driver */ -+static struct usb_device_id device_id_table[] = { -+ /* TechnoTrend USB IR Receiver */ -+ { USB_DEVICE(0x0B48, 0x2003) }, -+ /* Terminating entry */ -+ { } -+}; -+MODULE_DEVICE_TABLE(usb, device_id_table); -+ -+/* USB driver definition */ -+static struct usb_driver usb_driver = { -+ .name = "TTUSBIR", -+ .id_table = &(device_id_table[0]), -+ .probe = probe, -+ .disconnect = disconnect, -+}; -+ -+/* USB device definition */ -+struct ttusbir_device { -+ struct usb_driver *usb_driver; -+ struct usb_device *udev; -+ struct usb_interface *interf; -+ struct usb_class_driver class_driver; -+ unsigned int ifnum; /* Interface number to use */ -+ unsigned int alt_setting; /* alternate setting to use */ -+ unsigned int endpoint; /* Endpoint to use */ -+ struct urb **urb; /* num_urb URB pointers*/ -+ char **buffer; /* 128 byte buffer for each URB */ -+ struct lirc_buffer rbuf; /* Buffer towards LIRC */ -+ struct lirc_driver driver; -+ int minor; -+ int last_pulse; /* remembers if last received byte was pulse or space */ -+ int last_num; /* remembers how many last bytes appeared */ -+ int opened; -+}; -+ -+/*** LIRC specific functions ***/ -+static int set_use_inc(void *data) -+{ -+ int i, retval; -+ struct ttusbir_device *ttusbir = data; -+ -+ DPRINTK("Sending first URBs\n"); -+ /* @TODO Do I need to check if I am already opened */ -+ ttusbir->opened = 1; -+ -+ for (i = 0; i < num_urbs; i++) { -+ retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL); -+ if (retval) { -+ err("%s: usb_submit_urb failed on urb %d", -+ __func__, i); -+ return retval; -+ } -+ } -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct ttusbir_device *ttusbir = data; -+ -+ DPRINTK("Device closed\n"); -+ -+ ttusbir->opened = 0; -+} -+ -+/*** USB specific functions ***/ -+ -+/* -+ * This mapping table is used to do a very simple filtering of the -+ * input signal. -+ * For a value with at least 4 bits set it returns 0xFF otherwise -+ * 0x00. For faster IR signals this can not be used. But for RC-5 we -+ * still have about 14 samples per pulse/space, i.e. we sample with 14 -+ * times higher frequency than the signal frequency -+ */ -+const unsigned char map_table[] = { -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -+}; -+ -+static void urb_complete(struct urb *urb) -+{ -+ struct ttusbir_device *ttusbir; -+ unsigned char *buf; -+ int i; -+ int l; -+ -+ ttusbir = urb->context; -+ -+ if (!ttusbir->opened) -+ return; -+ -+ buf = (unsigned char *)urb->transfer_buffer; -+ -+ for (i = 0; i < 128; i++) { -+ /* Here we do the filtering and some kind of down sampling */ -+ buf[i] = ~map_table[buf[i]]; -+ if (ttusbir->last_pulse == buf[i]) { -+ if (ttusbir->last_num < PULSE_MASK/63) -+ ttusbir->last_num++; -+ /* -+ * else we are in a idle period and do not need to -+ * increment any longer -+ */ -+ } else { -+ l = ttusbir->last_num * 62; /* about 62 = us/byte */ -+ if (ttusbir->last_pulse) /* pulse or space? */ -+ l |= PULSE_BIT; -+ if (!lirc_buffer_full(&ttusbir->rbuf)) { -+ lirc_buffer_write(&ttusbir->rbuf, (void *)&l); -+ wake_up_interruptible(&ttusbir->rbuf.wait_poll); -+ } -+ ttusbir->last_num = 0; -+ ttusbir->last_pulse = buf[i]; -+ } -+ } -+ usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */ -+} -+ -+/* -+ * Called whenever the USB subsystem thinks we could be the right driver -+ * to handle this device -+ */ -+static int probe(struct usb_interface *intf, const struct usb_device_id *id) -+{ -+ int alt_set, endp; -+ int found = 0; -+ int i, j; -+ int struct_size; -+ struct usb_host_interface *host_interf; -+ struct usb_interface_descriptor *interf_desc; -+ struct usb_host_endpoint *host_endpoint; -+ struct ttusbir_device *ttusbir; -+ -+ DPRINTK("Module ttusbir probe\n"); -+ -+ /* To reduce memory fragmentation we use only one allocation */ -+ struct_size = sizeof(struct ttusbir_device) + -+ (sizeof(struct urb *) * num_urbs) + -+ (sizeof(char *) * num_urbs) + -+ (num_urbs * 128); -+ ttusbir = kzalloc(struct_size, GFP_KERNEL); -+ if (!ttusbir) -+ return -ENOMEM; -+ -+ ttusbir->urb = (struct urb **)((char *)ttusbir + -+ sizeof(struct ttusbir_device)); -+ ttusbir->buffer = (char **)((char *)ttusbir->urb + -+ (sizeof(struct urb *) * num_urbs)); -+ for (i = 0; i < num_urbs; i++) -+ ttusbir->buffer[i] = (char *)ttusbir->buffer + -+ (sizeof(char *)*num_urbs) + (i * 128); -+ -+ ttusbir->usb_driver = &usb_driver; -+ ttusbir->alt_setting = -1; -+ /* @TODO check if error can be returned */ -+ ttusbir->udev = usb_get_dev(interface_to_usbdev(intf)); -+ ttusbir->interf = intf; -+ ttusbir->last_pulse = 0x00; -+ ttusbir->last_num = 0; -+ -+ /* -+ * Now look for interface setting we can handle -+ * We are searching for the alt setting where end point -+ * 0x82 has max packet size 16 -+ */ -+ for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) { -+ host_interf = &intf->altsetting[alt_set]; -+ interf_desc = &host_interf->desc; -+ for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) { -+ host_endpoint = &host_interf->endpoint[endp]; -+ if ((host_endpoint->desc.bEndpointAddress == 0x82) && -+ (host_endpoint->desc.wMaxPacketSize == 0x10)) { -+ ttusbir->alt_setting = alt_set; -+ ttusbir->endpoint = endp; -+ found = 1; -+ break; -+ } -+ } -+ } -+ if (ttusbir->alt_setting != -1) -+ DPRINTK("alt setting: %d\n", ttusbir->alt_setting); -+ else { -+ err("Could not find alternate setting\n"); -+ kfree(ttusbir); -+ return -EINVAL; -+ } -+ -+ /* OK lets setup this interface setting */ -+ usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting); -+ -+ /* Store device info in interface structure */ -+ usb_set_intfdata(intf, ttusbir); -+ -+ /* Register as a LIRC driver */ -+ if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) { -+ err("Could not get memory for LIRC data buffer\n"); -+ usb_set_intfdata(intf, NULL); -+ kfree(ttusbir); -+ return -ENOMEM; -+ } -+ strcpy(ttusbir->driver.name, "TTUSBIR"); -+ ttusbir->driver.minor = -1; -+ ttusbir->driver.code_length = 1; -+ ttusbir->driver.sample_rate = 0; -+ ttusbir->driver.data = ttusbir; -+ ttusbir->driver.add_to_buf = NULL; -+ ttusbir->driver.rbuf = &ttusbir->rbuf; -+ ttusbir->driver.set_use_inc = set_use_inc; -+ ttusbir->driver.set_use_dec = set_use_dec; -+ ttusbir->driver.dev = &intf->dev; -+ ttusbir->driver.owner = THIS_MODULE; -+ ttusbir->driver.features = LIRC_CAN_REC_MODE2; -+ ttusbir->minor = lirc_register_driver(&ttusbir->driver); -+ if (ttusbir->minor < 0) { -+ err("Error registering as LIRC driver\n"); -+ usb_set_intfdata(intf, NULL); -+ lirc_buffer_free(&ttusbir->rbuf); -+ kfree(ttusbir); -+ return -EIO; -+ } -+ -+ /* Allocate and setup the URB that we will use to talk to the device */ -+ for (i = 0; i < num_urbs; i++) { -+ ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL); -+ if (!ttusbir->urb[i]) { -+ err("Could not allocate memory for the URB\n"); -+ for (j = i - 1; j >= 0; j--) -+ kfree(ttusbir->urb[j]); -+ lirc_buffer_free(&ttusbir->rbuf); -+ lirc_unregister_driver(ttusbir->minor); -+ kfree(ttusbir); -+ usb_set_intfdata(intf, NULL); -+ return -ENOMEM; -+ } -+ ttusbir->urb[i]->dev = ttusbir->udev; -+ ttusbir->urb[i]->context = ttusbir; -+ ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev, -+ ttusbir->endpoint); -+ ttusbir->urb[i]->interval = 1; -+ ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP; -+ ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0]; -+ ttusbir->urb[i]->complete = urb_complete; -+ ttusbir->urb[i]->number_of_packets = 8; -+ ttusbir->urb[i]->transfer_buffer_length = 128; -+ for (j = 0; j < 8; j++) { -+ ttusbir->urb[i]->iso_frame_desc[j].offset = j*16; -+ ttusbir->urb[i]->iso_frame_desc[j].length = 16; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * Called when the driver is unloaded or the device is unplugged -+ */ -+static void disconnect(struct usb_interface *intf) -+{ -+ int i; -+ struct ttusbir_device *ttusbir; -+ -+ DPRINTK("Module ttusbir disconnect\n"); -+ -+ ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf); -+ usb_set_intfdata(intf, NULL); -+ lirc_unregister_driver(ttusbir->minor); -+ DPRINTK("unregistered\n"); -+ -+ for (i = 0; i < num_urbs; i++) { -+ usb_kill_urb(ttusbir->urb[i]); -+ usb_free_urb(ttusbir->urb[i]); -+ } -+ DPRINTK("URBs killed\n"); -+ lirc_buffer_free(&ttusbir->rbuf); -+ kfree(ttusbir); -+} -+ -+static int ttusbir_init_module(void) -+{ -+ int result; -+ -+ DPRINTK(KERN_DEBUG "Module ttusbir init\n"); -+ -+ /* register this driver with the USB subsystem */ -+ result = usb_register(&usb_driver); -+ if (result) -+ err("usb_register failed. Error number %d", result); -+ return result; -+} -+ -+static void ttusbir_exit_module(void) -+{ -+ printk(KERN_DEBUG "Module ttusbir exit\n"); -+ usb_deregister(&usb_driver); -+} -+ -+module_init(ttusbir_init_module); -+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 0000000..100caab ---- /dev/null -+++ b/drivers/staging/lirc/lirc_zilog.c -@@ -0,0 +1,1387 @@ -+/* -+ * i2c IR lirc driver for devices with zilog IR processors -+ * -+ * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> -+ * modified for PixelView (BT878P+W/FM) by -+ * Michal Kochanowicz <mkochano@pld.org.pl> -+ * Christoph Bartelmus <lirc@bartelmus.de> -+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by -+ * Ulrich Mueller <ulrich.mueller42@web.de> -+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by -+ * Stefan Jahn <stefan@lkcc.org> -+ * modified for inclusion into kernel sources by -+ * Jerome Brock <jbrock@users.sourceforge.net> -+ * modified for Leadtek Winfast PVR2000 by -+ * Thomas Reitmayr (treitmayr@yahoo.com) -+ * modified for Hauppauge PVR-150 IR TX device by -+ * Mark Weaver <mark@npsl.co.uk> -+ * changed name from lirc_pvr150 to lirc_zilog, works on more than pvr-150 -+ * Jarod Wilson <jarod@redhat.com> -+ * -+ * parts are cut&pasted from the lirc_i2c.c driver -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+ -+#include <linux/version.h> -+#include <linux/module.h> -+#include <linux/kmod.h> -+#include <linux/kernel.h> -+#include <linux/sched.h> -+#include <linux/fs.h> -+#include <linux/poll.h> -+#include <linux/string.h> -+#include <linux/timer.h> -+#include <linux/delay.h> -+#include <linux/completion.h> -+#include <linux/errno.h> -+#include <linux/slab.h> -+#include <linux/i2c.h> -+#include <linux/firmware.h> -+#include <linux/vmalloc.h> -+ -+#include <linux/mutex.h> -+#include <linux/kthread.h> -+ -+#include <media/lirc_dev.h> -+#include <media/lirc.h> -+ -+struct IR { -+ struct lirc_driver l; -+ -+ /* Device info */ -+ struct mutex ir_lock; -+ int open; -+ -+ /* RX device */ -+ struct i2c_client c_rx; -+ int have_rx; -+ -+ /* RX device buffer & lock */ -+ struct lirc_buffer buf; -+ struct mutex buf_lock; -+ -+ /* RX polling thread data */ -+ struct completion *t_notify; -+ struct completion *t_notify2; -+ int shutdown; -+ struct task_struct *task; -+ -+ /* RX read data */ -+ unsigned char b[3]; -+ -+ /* TX device */ -+ struct i2c_client c_tx; -+ int need_boot; -+ int have_tx; -+}; -+ -+/* Minor -> data mapping */ -+static struct IR *ir_devices[MAX_IRCTL_DEVICES]; -+ -+/* Block size for IR transmitter */ -+#define TX_BLOCK_SIZE 99 -+ -+/* Hauppauge IR transmitter data */ -+struct tx_data_struct { -+ /* Boot block */ -+ unsigned char *boot_data; -+ -+ /* Start of binary data block */ -+ unsigned char *datap; -+ -+ /* End of binary data block */ -+ unsigned char *endp; -+ -+ /* Number of installed codesets */ -+ unsigned int num_code_sets; -+ -+ /* Pointers to codesets */ -+ unsigned char **code_sets; -+ -+ /* Global fixed data template */ -+ int fixed[TX_BLOCK_SIZE]; -+}; -+ -+static struct tx_data_struct *tx_data; -+static struct mutex tx_data_lock; -+ -+#define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \ -+ ## args) -+#define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args) -+ -+#define ZILOG_HAUPPAUGE_IR_RX_NAME "Zilog/Hauppauge IR RX" -+#define ZILOG_HAUPPAUGE_IR_TX_NAME "Zilog/Hauppauge IR TX" -+ -+/* module parameters */ -+static int debug; /* debug output */ -+static int disable_rx; /* disable RX device */ -+static int disable_tx; /* disable TX device */ -+static int minor = -1; /* minor number */ -+ -+#define dprintk(fmt, args...) \ -+ do { \ -+ if (debug) \ -+ printk(KERN_DEBUG KBUILD_MODNAME ": " fmt, \ -+ ## args); \ -+ } while (0) -+ -+static int add_to_buf(struct IR *ir) -+{ -+ __u16 code; -+ unsigned char codes[2]; -+ unsigned char keybuf[6]; -+ int got_data = 0; -+ int ret; -+ int failures = 0; -+ unsigned char sendbuf[1] = { 0 }; -+ -+ if (lirc_buffer_full(&ir->buf)) { -+ dprintk("buffer overflow\n"); -+ return -EOVERFLOW; -+ } -+ -+ /* -+ * service the device as long as it is returning -+ * data and we have space -+ */ -+ do { -+ /* -+ * Lock i2c bus for the duration. RX/TX chips interfere so -+ * this is worth it -+ */ -+ mutex_lock(&ir->ir_lock); -+ -+ /* -+ * Send random "poll command" (?) Windows driver does this -+ * and it is a good point to detect chip failure. -+ */ -+ ret = i2c_master_send(&ir->c_rx, sendbuf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ if (failures >= 3) { -+ mutex_unlock(&ir->ir_lock); -+ zilog_error("unable to read from the IR chip " -+ "after 3 resets, giving up\n"); -+ return ret; -+ } -+ -+ /* Looks like the chip crashed, reset it */ -+ zilog_error("polling the IR receiver chip failed, " -+ "trying reset\n"); -+ -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout((100 * HZ + 999) / 1000); -+ ir->need_boot = 1; -+ -+ ++failures; -+ mutex_unlock(&ir->ir_lock); -+ continue; -+ } -+ -+ ret = i2c_master_recv(&ir->c_rx, keybuf, sizeof(keybuf)); -+ mutex_unlock(&ir->ir_lock); -+ if (ret != sizeof(keybuf)) { -+ zilog_error("i2c_master_recv failed with %d -- " -+ "keeping last read buffer\n", ret); -+ } else { -+ ir->b[0] = keybuf[3]; -+ ir->b[1] = keybuf[4]; -+ ir->b[2] = keybuf[5]; -+ dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]); -+ } -+ -+ /* key pressed ? */ -+#ifdef I2C_HW_B_HDPVR -+ if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR) { -+ if (got_data && (keybuf[0] == 0x80)) -+ return 0; -+ else if (got_data && (keybuf[0] == 0x00)) -+ return -ENODATA; -+ } else if ((ir->b[0] & 0x80) == 0) -+#else -+ if ((ir->b[0] & 0x80) == 0) -+#endif -+ return got_data ? 0 : -ENODATA; -+ -+ /* look what we have */ -+ code = (((__u16)ir->b[0] & 0x7f) << 6) | (ir->b[1] >> 2); -+ -+ codes[0] = (code >> 8) & 0xff; -+ codes[1] = code & 0xff; -+ -+ /* return it */ -+ lirc_buffer_write(&ir->buf, codes); -+ ++got_data; -+ } while (!lirc_buffer_full(&ir->buf)); -+ -+ return 0; -+} -+ -+/* -+ * Main function of the polling thread -- from lirc_dev. -+ * We don't fit the LIRC model at all anymore. This is horrible, but -+ * basically we have a single RX/TX device with a nasty failure mode -+ * that needs to be accounted for across the pair. lirc lets us provide -+ * fops, but prevents us from using the internal polling, etc. if we do -+ * so. Hence the replication. Might be neater to extend the LIRC model -+ * to account for this but I'd think it's a very special case of seriously -+ * messed up hardware. -+ */ -+static int lirc_thread(void *arg) -+{ -+ struct IR *ir = arg; -+ -+ if (ir->t_notify != NULL) -+ complete(ir->t_notify); -+ -+ dprintk("poll thread started\n"); -+ -+ do { -+ if (ir->open) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ /* -+ * This is ~113*2 + 24 + jitter (2*repeat gap + -+ * code length). We use this interval as the chip -+ * resets every time you poll it (bad!). This is -+ * therefore just sufficient to catch all of the -+ * button presses. It makes the remote much more -+ * responsive. You can see the difference by -+ * running irw and holding down a button. With -+ * 100ms, the old polling interval, you'll notice -+ * breaks in the repeat sequence corresponding to -+ * lost keypresses. -+ */ -+ schedule_timeout((260 * HZ) / 1000); -+ if (ir->shutdown) -+ break; -+ if (!add_to_buf(ir)) -+ wake_up_interruptible(&ir->buf.wait_poll); -+ } else { -+ /* if device not opened so we can sleep half a second */ -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(HZ/2); -+ } -+ } while (!ir->shutdown); -+ -+ if (ir->t_notify2 != NULL) -+ wait_for_completion(ir->t_notify2); -+ -+ ir->task = NULL; -+ if (ir->t_notify != NULL) -+ complete(ir->t_notify); -+ -+ dprintk("poll thread ended\n"); -+ return 0; -+} -+ -+static int set_use_inc(void *data) -+{ -+ struct IR *ir = data; -+ -+ if (ir->l.owner == NULL || try_module_get(ir->l.owner) == 0) -+ return -ENODEV; -+ -+ /* lock bttv in memory while /dev/lirc is in use */ -+ /* -+ * this is completely broken code. lirc_unregister_driver() -+ * must be possible even when the device is open -+ */ -+ if (ir->c_rx.addr) -+ i2c_use_client(&ir->c_rx); -+ if (ir->c_tx.addr) -+ i2c_use_client(&ir->c_tx); -+ -+ return 0; -+} -+ -+static void set_use_dec(void *data) -+{ -+ struct IR *ir = data; -+ -+ if (ir->c_rx.addr) -+ i2c_release_client(&ir->c_rx); -+ if (ir->c_tx.addr) -+ i2c_release_client(&ir->c_tx); -+ if (ir->l.owner != NULL) -+ module_put(ir->l.owner); -+} -+ -+/* safe read of a uint32 (always network byte order) */ -+static int read_uint32(unsigned char **data, -+ unsigned char *endp, unsigned int *val) -+{ -+ if (*data + 4 > endp) -+ return 0; -+ *val = ((*data)[0] << 24) | ((*data)[1] << 16) | -+ ((*data)[2] << 8) | (*data)[3]; -+ *data += 4; -+ return 1; -+} -+ -+/* safe read of a uint8 */ -+static int read_uint8(unsigned char **data, -+ unsigned char *endp, unsigned char *val) -+{ -+ if (*data + 1 > endp) -+ return 0; -+ *val = *((*data)++); -+ return 1; -+} -+ -+/* safe skipping of N bytes */ -+static int skip(unsigned char **data, -+ unsigned char *endp, unsigned int distance) -+{ -+ if (*data + distance > endp) -+ return 0; -+ *data += distance; -+ return 1; -+} -+ -+/* decompress key data into the given buffer */ -+static int get_key_data(unsigned char *buf, -+ unsigned int codeset, unsigned int key) -+{ -+ unsigned char *data, *endp, *diffs, *key_block; -+ unsigned char keys, ndiffs, id; -+ unsigned int base, lim, pos, i; -+ -+ /* Binary search for the codeset */ -+ for (base = 0, lim = tx_data->num_code_sets; lim; lim >>= 1) { -+ pos = base + (lim >> 1); -+ data = tx_data->code_sets[pos]; -+ -+ if (!read_uint32(&data, tx_data->endp, &i)) -+ goto corrupt; -+ -+ if (i == codeset) -+ break; -+ else if (codeset > i) { -+ base = pos + 1; -+ --lim; -+ } -+ } -+ /* Not found? */ -+ if (!lim) -+ return -EPROTO; -+ -+ /* Set end of data block */ -+ endp = pos < tx_data->num_code_sets - 1 ? -+ tx_data->code_sets[pos + 1] : tx_data->endp; -+ -+ /* Read the block header */ -+ if (!read_uint8(&data, endp, &keys) || -+ !read_uint8(&data, endp, &ndiffs) || -+ ndiffs > TX_BLOCK_SIZE || keys == 0) -+ goto corrupt; -+ -+ /* Save diffs & skip */ -+ diffs = data; -+ if (!skip(&data, endp, ndiffs)) -+ goto corrupt; -+ -+ /* Read the id of the first key */ -+ if (!read_uint8(&data, endp, &id)) -+ goto corrupt; -+ -+ /* Unpack the first key's data */ -+ for (i = 0; i < TX_BLOCK_SIZE; ++i) { -+ if (tx_data->fixed[i] == -1) { -+ if (!read_uint8(&data, endp, &buf[i])) -+ goto corrupt; -+ } else { -+ buf[i] = (unsigned char)tx_data->fixed[i]; -+ } -+ } -+ -+ /* Early out key found/not found */ -+ if (key == id) -+ return 0; -+ if (keys == 1) -+ return -EPROTO; -+ -+ /* Sanity check */ -+ key_block = data; -+ if (!skip(&data, endp, (keys - 1) * (ndiffs + 1))) -+ goto corrupt; -+ -+ /* Binary search for the key */ -+ for (base = 0, lim = keys - 1; lim; lim >>= 1) { -+ /* Seek to block */ -+ unsigned char *key_data; -+ pos = base + (lim >> 1); -+ key_data = key_block + (ndiffs + 1) * pos; -+ -+ if (*key_data == key) { -+ /* skip key id */ -+ ++key_data; -+ -+ /* found, so unpack the diffs */ -+ for (i = 0; i < ndiffs; ++i) { -+ unsigned char val; -+ if (!read_uint8(&key_data, endp, &val) || -+ diffs[i] >= TX_BLOCK_SIZE) -+ goto corrupt; -+ buf[diffs[i]] = val; -+ } -+ -+ return 0; -+ } else if (key > *key_data) { -+ base = pos + 1; -+ --lim; -+ } -+ } -+ /* Key not found */ -+ return -EPROTO; -+ -+corrupt: -+ zilog_error("firmware is corrupt\n"); -+ return -EFAULT; -+} -+ -+/* send a block of data to the IR TX device */ -+static int send_data_block(struct IR *ir, unsigned char *data_block) -+{ -+ int i, j, ret; -+ unsigned char buf[5]; -+ -+ for (i = 0; i < TX_BLOCK_SIZE;) { -+ int tosend = TX_BLOCK_SIZE - i; -+ if (tosend > 4) -+ tosend = 4; -+ buf[0] = (unsigned char)(i + 1); -+ for (j = 0; j < tosend; ++j) -+ buf[1 + j] = data_block[i + j]; -+ dprintk("%02x %02x %02x %02x %02x", -+ buf[0], buf[1], buf[2], buf[3], buf[4]); -+ ret = i2c_master_send(&ir->c_tx, buf, tosend + 1); -+ if (ret != tosend + 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ i += tosend; -+ } -+ return 0; -+} -+ -+/* send boot data to the IR TX device */ -+static int send_boot_data(struct IR *ir) -+{ -+ int ret; -+ unsigned char buf[4]; -+ -+ /* send the boot block */ -+ ret = send_data_block(ir, tx_data->boot_data); -+ if (ret != 0) -+ return ret; -+ -+ /* kick it off? */ -+ buf[0] = 0x00; -+ buf[1] = 0x20; -+ ret = i2c_master_send(&ir->c_tx, buf, 2); -+ if (ret != 2) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ ret = i2c_master_send(&ir->c_tx, buf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+ /* Here comes the firmware version... (hopefully) */ -+ ret = i2c_master_recv(&ir->c_tx, buf, 4); -+ if (ret != 4) { -+ zilog_error("i2c_master_recv failed with %d\n", ret); -+ return 0; -+ } -+ if (buf[0] != 0x80) { -+ zilog_error("unexpected IR TX response: %02x\n", buf[0]); -+ return 0; -+ } -+ zilog_notify("Zilog/Hauppauge IR blaster firmware version " -+ "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]); -+ -+ return 0; -+} -+ -+/* unload "firmware", lock held */ -+static void fw_unload_locked(void) -+{ -+ if (tx_data) { -+ if (tx_data->code_sets) -+ vfree(tx_data->code_sets); -+ -+ if (tx_data->datap) -+ vfree(tx_data->datap); -+ -+ vfree(tx_data); -+ tx_data = NULL; -+ dprintk("successfully unloaded IR blaster firmware\n"); -+ } -+} -+ -+/* unload "firmware" for the IR TX device */ -+static void fw_unload(void) -+{ -+ mutex_lock(&tx_data_lock); -+ fw_unload_locked(); -+ mutex_unlock(&tx_data_lock); -+} -+ -+/* load "firmware" for the IR TX device */ -+static int fw_load(struct IR *ir) -+{ -+ int ret; -+ unsigned int i; -+ unsigned char *data, version, num_global_fixed; -+ const struct firmware *fw_entry; -+ -+ /* Already loaded? */ -+ mutex_lock(&tx_data_lock); -+ if (tx_data) { -+ ret = 0; -+ goto out; -+ } -+ -+ /* Request codeset data file */ -+ ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &ir->c_tx.dev); -+ if (ret != 0) { -+ zilog_error("firmware haup-ir-blaster.bin not available " -+ "(%d)\n", ret); -+ ret = ret < 0 ? ret : -EFAULT; -+ goto out; -+ } -+ dprintk("firmware of size %zu loaded\n", fw_entry->size); -+ -+ /* Parse the file */ -+ tx_data = vmalloc(sizeof(*tx_data)); -+ if (tx_data == NULL) { -+ zilog_error("out of memory\n"); -+ release_firmware(fw_entry); -+ ret = -ENOMEM; -+ goto out; -+ } -+ tx_data->code_sets = NULL; -+ -+ /* Copy the data so hotplug doesn't get confused and timeout */ -+ tx_data->datap = vmalloc(fw_entry->size); -+ if (tx_data->datap == NULL) { -+ zilog_error("out of memory\n"); -+ release_firmware(fw_entry); -+ vfree(tx_data); -+ ret = -ENOMEM; -+ goto out; -+ } -+ memcpy(tx_data->datap, fw_entry->data, fw_entry->size); -+ tx_data->endp = tx_data->datap + fw_entry->size; -+ release_firmware(fw_entry); fw_entry = NULL; -+ -+ /* Check version */ -+ data = tx_data->datap; -+ if (!read_uint8(&data, tx_data->endp, &version)) -+ goto corrupt; -+ if (version != 1) { -+ zilog_error("unsupported code set file version (%u, expected" -+ "1) -- please upgrade to a newer driver", -+ version); -+ fw_unload_locked(); -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ /* Save boot block for later */ -+ tx_data->boot_data = data; -+ if (!skip(&data, tx_data->endp, TX_BLOCK_SIZE)) -+ goto corrupt; -+ -+ if (!read_uint32(&data, tx_data->endp, -+ &tx_data->num_code_sets)) -+ goto corrupt; -+ -+ dprintk("%u IR blaster codesets loaded\n", tx_data->num_code_sets); -+ -+ tx_data->code_sets = vmalloc( -+ tx_data->num_code_sets * sizeof(char *)); -+ if (tx_data->code_sets == NULL) { -+ fw_unload_locked(); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ for (i = 0; i < TX_BLOCK_SIZE; ++i) -+ tx_data->fixed[i] = -1; -+ -+ /* Read global fixed data template */ -+ if (!read_uint8(&data, tx_data->endp, &num_global_fixed) || -+ num_global_fixed > TX_BLOCK_SIZE) -+ goto corrupt; -+ for (i = 0; i < num_global_fixed; ++i) { -+ unsigned char pos, val; -+ if (!read_uint8(&data, tx_data->endp, &pos) || -+ !read_uint8(&data, tx_data->endp, &val) || -+ pos >= TX_BLOCK_SIZE) -+ goto corrupt; -+ tx_data->fixed[pos] = (int)val; -+ } -+ -+ /* Filch out the position of each code set */ -+ for (i = 0; i < tx_data->num_code_sets; ++i) { -+ unsigned int id; -+ unsigned char keys; -+ unsigned char ndiffs; -+ -+ /* Save the codeset position */ -+ tx_data->code_sets[i] = data; -+ -+ /* Read header */ -+ if (!read_uint32(&data, tx_data->endp, &id) || -+ !read_uint8(&data, tx_data->endp, &keys) || -+ !read_uint8(&data, tx_data->endp, &ndiffs) || -+ ndiffs > TX_BLOCK_SIZE || keys == 0) -+ goto corrupt; -+ -+ /* skip diff positions */ -+ if (!skip(&data, tx_data->endp, ndiffs)) -+ goto corrupt; -+ -+ /* -+ * After the diffs we have the first key id + data - -+ * global fixed -+ */ -+ if (!skip(&data, tx_data->endp, -+ 1 + TX_BLOCK_SIZE - num_global_fixed)) -+ goto corrupt; -+ -+ /* Then we have keys-1 blocks of key id+diffs */ -+ if (!skip(&data, tx_data->endp, -+ (ndiffs + 1) * (keys - 1))) -+ goto corrupt; -+ } -+ ret = 0; -+ goto out; -+ -+corrupt: -+ zilog_error("firmware is corrupt\n"); -+ fw_unload_locked(); -+ ret = -EFAULT; -+ -+out: -+ mutex_unlock(&tx_data_lock); -+ return ret; -+} -+ -+/* initialise the IR TX device */ -+static int tx_init(struct IR *ir) -+{ -+ int ret; -+ -+ /* Load 'firmware' */ -+ ret = fw_load(ir); -+ if (ret != 0) -+ return ret; -+ -+ /* Send boot block */ -+ ret = send_boot_data(ir); -+ if (ret != 0) -+ return ret; -+ ir->need_boot = 0; -+ -+ /* Looks good */ -+ return 0; -+} -+ -+/* do nothing stub to make LIRC happy */ -+static loff_t lseek(struct file *filep, loff_t offset, int orig) -+{ -+ return -ESPIPE; -+} -+ -+/* copied from lirc_dev */ -+static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ unsigned char buf[ir->buf.chunk_size]; -+ int ret = 0, written = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ dprintk("read called\n"); -+ if (ir->c_rx.addr == 0) -+ return -ENODEV; -+ -+ if (mutex_lock_interruptible(&ir->buf_lock)) -+ return -ERESTARTSYS; -+ -+ if (n % ir->buf.chunk_size) { -+ dprintk("read result = -EINVAL\n"); -+ mutex_unlock(&ir->buf_lock); -+ return -EINVAL; -+ } -+ -+ /* -+ * we add ourselves to the task queue before buffer check -+ * to avoid losing scan code (in case when queue is awaken somewhere -+ * between while condition checking and scheduling) -+ */ -+ add_wait_queue(&ir->buf.wait_poll, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ /* -+ * while we didn't provide 'length' bytes, device is opened in blocking -+ * mode and 'copy_to_user' is happy, wait for data. -+ */ -+ while (written < n && ret == 0) { -+ if (lirc_buffer_empty(&ir->buf)) { -+ /* -+ * According to the read(2) man page, 'written' can be -+ * returned as less than 'n', instead of blocking -+ * again, returning -EWOULDBLOCK, or returning -+ * -ERESTARTSYS -+ */ -+ if (written) -+ break; -+ if (filep->f_flags & O_NONBLOCK) { -+ ret = -EWOULDBLOCK; -+ break; -+ } -+ if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ } else { -+ lirc_buffer_read(&ir->buf, buf); -+ ret = copy_to_user((void *)outbuf+written, buf, -+ ir->buf.chunk_size); -+ written += ir->buf.chunk_size; -+ } -+ } -+ -+ remove_wait_queue(&ir->buf.wait_poll, &wait); -+ set_current_state(TASK_RUNNING); -+ mutex_unlock(&ir->buf_lock); -+ -+ dprintk("read result = %s (%d)\n", -+ ret ? "-EFAULT" : "OK", ret); -+ -+ return ret ? ret : written; -+} -+ -+/* send a keypress to the IR TX device */ -+static int send_code(struct IR *ir, unsigned int code, unsigned int key) -+{ -+ unsigned char data_block[TX_BLOCK_SIZE]; -+ unsigned char buf[2]; -+ int i, ret; -+ -+ /* Get data for the codeset/key */ -+ ret = get_key_data(data_block, code, key); -+ -+ if (ret == -EPROTO) { -+ zilog_error("failed to get data for code %u, key %u -- check " -+ "lircd.conf entries\n", code, key); -+ return ret; -+ } else if (ret != 0) -+ return ret; -+ -+ /* Send the data block */ -+ ret = send_data_block(ir, data_block); -+ if (ret != 0) -+ return ret; -+ -+ /* Send data block length? */ -+ buf[0] = 0x00; -+ buf[1] = 0x40; -+ ret = i2c_master_send(&ir->c_tx, buf, 2); -+ if (ret != 2) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ ret = i2c_master_send(&ir->c_tx, buf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+ /* Send finished download? */ -+ ret = i2c_master_recv(&ir->c_tx, buf, 1); -+ if (ret != 1) { -+ zilog_error("i2c_master_recv failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ if (buf[0] != 0xA0) { -+ zilog_error("unexpected IR TX response #1: %02x\n", -+ buf[0]); -+ return -EFAULT; -+ } -+ -+ /* Send prepare command? */ -+ buf[0] = 0x00; -+ buf[1] = 0x80; -+ ret = i2c_master_send(&ir->c_tx, buf, 2); -+ if (ret != 2) { -+ zilog_error("i2c_master_send failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+#ifdef I2C_HW_B_HDPVR -+ /* -+ * The sleep bits aren't necessary on the HD PVR, and in fact, the -+ * last i2c_master_recv always fails with a -5, so for now, we're -+ * going to skip this whole mess and say we're done on the HD PVR -+ */ -+ if (ir->c_rx.adapter->id == I2C_HW_B_HDPVR) -+ goto done; -+#endif -+ -+ /* -+ * This bit NAKs until the device is ready, so we retry it -+ * sleeping a bit each time. This seems to be what the windows -+ * driver does, approximately. -+ * Try for up to 1s. -+ */ -+ for (i = 0; i < 20; ++i) { -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout((50 * HZ + 999) / 1000); -+ ret = i2c_master_send(&ir->c_tx, buf, 1); -+ if (ret == 1) -+ break; -+ dprintk("NAK expected: i2c_master_send " -+ "failed with %d (try %d)\n", ret, i+1); -+ } -+ if (ret != 1) { -+ zilog_error("IR TX chip never got ready: last i2c_master_send " -+ "failed with %d\n", ret); -+ return ret < 0 ? ret : -EFAULT; -+ } -+ -+ /* Seems to be an 'ok' response */ -+ i = i2c_master_recv(&ir->c_tx, buf, 1); -+ if (i != 1) { -+ zilog_error("i2c_master_recv failed with %d\n", ret); -+ return -EFAULT; -+ } -+ if (buf[0] != 0x80) { -+ zilog_error("unexpected IR TX response #2: %02x\n", buf[0]); -+ return -EFAULT; -+ } -+ -+done: -+ /* Oh good, it worked */ -+ dprintk("sent code %u, key %u\n", code, key); -+ return 0; -+} -+ -+/* -+ * Write a code to the device. We take in a 32-bit number (an int) and then -+ * decode this to a codeset/key index. The key data is then decompressed and -+ * sent to the device. We have a spin lock as per i2c documentation to prevent -+ * multiple concurrent sends which would probably cause the device to explode. -+ */ -+static ssize_t write(struct file *filep, const char *buf, size_t n, -+ loff_t *ppos) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ size_t i; -+ int failures = 0; -+ -+ if (ir->c_tx.addr == 0) -+ return -ENODEV; -+ -+ /* Validate user parameters */ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ -+ /* Lock i2c bus for the duration */ -+ mutex_lock(&ir->ir_lock); -+ -+ /* Send each keypress */ -+ for (i = 0; i < n;) { -+ int ret = 0; -+ int command; -+ -+ if (copy_from_user(&command, buf + i, sizeof(command))) { -+ mutex_unlock(&ir->ir_lock); -+ return -EFAULT; -+ } -+ -+ /* Send boot data first if required */ -+ if (ir->need_boot == 1) { -+ ret = send_boot_data(ir); -+ if (ret == 0) -+ ir->need_boot = 0; -+ } -+ -+ /* Send the code */ -+ if (ret == 0) { -+ ret = send_code(ir, (unsigned)command >> 16, -+ (unsigned)command & 0xFFFF); -+ if (ret == -EPROTO) { -+ mutex_unlock(&ir->ir_lock); -+ return ret; -+ } -+ } -+ -+ /* -+ * Hmm, a failure. If we've had a few then give up, otherwise -+ * try a reset -+ */ -+ if (ret != 0) { -+ /* Looks like the chip crashed, reset it */ -+ zilog_error("sending to the IR transmitter chip " -+ "failed, trying reset\n"); -+ -+ if (failures >= 3) { -+ zilog_error("unable to send to the IR chip " -+ "after 3 resets, giving up\n"); -+ mutex_unlock(&ir->ir_lock); -+ return ret; -+ } -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout((100 * HZ + 999) / 1000); -+ ir->need_boot = 1; -+ ++failures; -+ } else -+ i += sizeof(int); -+ } -+ -+ /* Release i2c bus */ -+ mutex_unlock(&ir->ir_lock); -+ -+ /* All looks good */ -+ return n; -+} -+ -+/* copied from lirc_dev */ -+static unsigned int poll(struct file *filep, poll_table *wait) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ unsigned int ret; -+ -+ dprintk("poll called\n"); -+ if (ir->c_rx.addr == 0) -+ return -ENODEV; -+ -+ mutex_lock(&ir->buf_lock); -+ -+ poll_wait(filep, &ir->buf.wait_poll, wait); -+ -+ dprintk("poll result = %s\n", -+ lirc_buffer_empty(&ir->buf) ? "0" : "POLLIN|POLLRDNORM"); -+ -+ ret = lirc_buffer_empty(&ir->buf) ? 0 : (POLLIN|POLLRDNORM); -+ -+ mutex_unlock(&ir->buf_lock); -+ return ret; -+} -+ -+static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -+{ -+ struct IR *ir = (struct IR *)filep->private_data; -+ int result; -+ unsigned long mode, features = 0; -+ -+ if (ir->c_rx.addr != 0) -+ features |= LIRC_CAN_REC_LIRCCODE; -+ if (ir->c_tx.addr != 0) -+ features |= LIRC_CAN_SEND_PULSE; -+ -+ switch (cmd) { -+ case LIRC_GET_LENGTH: -+ result = put_user((unsigned long)13, -+ (unsigned long *)arg); -+ break; -+ case LIRC_GET_FEATURES: -+ result = put_user(features, (unsigned long *) arg); -+ break; -+ case LIRC_GET_REC_MODE: -+ if (!(features&LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = put_user(LIRC_REC2MODE -+ (features&LIRC_CAN_REC_MASK), -+ (unsigned long *)arg); -+ break; -+ case LIRC_SET_REC_MODE: -+ if (!(features&LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = get_user(mode, (unsigned long *)arg); -+ if (!result && !(LIRC_MODE2REC(mode) & features)) -+ result = -EINVAL; -+ break; -+ case LIRC_GET_SEND_MODE: -+ if (!(features&LIRC_CAN_SEND_MASK)) -+ return -ENOSYS; -+ -+ result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); -+ break; -+ case LIRC_SET_SEND_MODE: -+ if (!(features&LIRC_CAN_SEND_MASK)) -+ return -ENOSYS; -+ -+ result = get_user(mode, (unsigned long *) arg); -+ if (!result && mode != LIRC_MODE_PULSE) -+ return -EINVAL; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return result; -+} -+ -+/* -+ * Open the IR device. Get hold of our IR structure and -+ * stash it in private_data for the file -+ */ -+static int open(struct inode *node, struct file *filep) -+{ -+ struct IR *ir; -+ int ret; -+ -+ /* find our IR struct */ -+ unsigned minor = MINOR(node->i_rdev); -+ if (minor >= MAX_IRCTL_DEVICES) { -+ dprintk("minor %d: open result = -ENODEV\n", -+ minor); -+ return -ENODEV; -+ } -+ ir = ir_devices[minor]; -+ -+ /* increment in use count */ -+ mutex_lock(&ir->ir_lock); -+ ++ir->open; -+ ret = set_use_inc(ir); -+ if (ret != 0) { -+ --ir->open; -+ mutex_unlock(&ir->ir_lock); -+ return ret; -+ } -+ mutex_unlock(&ir->ir_lock); -+ -+ /* stash our IR struct */ -+ filep->private_data = ir; -+ -+ return 0; -+} -+ -+/* Close the IR device */ -+static int close(struct inode *node, struct file *filep) -+{ -+ /* find our IR struct */ -+ struct IR *ir = (struct IR *)filep->private_data; -+ if (ir == NULL) { -+ zilog_error("close: no private_data attached to the file!\n"); -+ return -ENODEV; -+ } -+ -+ /* decrement in use count */ -+ mutex_lock(&ir->ir_lock); -+ --ir->open; -+ set_use_dec(ir); -+ mutex_unlock(&ir->ir_lock); -+ -+ return 0; -+} -+ -+static struct lirc_driver lirc_template = { -+ .name = "lirc_zilog", -+ .set_use_inc = set_use_inc, -+ .set_use_dec = set_use_dec, -+ .owner = THIS_MODULE -+}; -+ -+static int ir_remove(struct i2c_client *client); -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id); -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg); -+ -+static const struct i2c_device_id ir_transceiver_id[] = { -+ /* Generic entry for any IR transceiver */ -+ { "ir_video", 0 }, -+ /* IR device specific entries should be added here */ -+ { "ir_tx_z8f0811_haup", 0 }, -+ { "ir_rx_z8f0811_haup", 0 }, -+ { } -+}; -+ -+static struct i2c_driver driver = { -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "Zilog/Hauppauge i2c IR", -+ }, -+ .probe = ir_probe, -+ .remove = ir_remove, -+ .command = ir_command, -+ .id_table = ir_transceiver_id, -+}; -+ -+static const struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .llseek = lseek, -+ .read = read, -+ .write = write, -+ .poll = poll, -+ .unlocked_ioctl = ioctl, -+ .open = open, -+ .release = close -+}; -+ -+static int ir_remove(struct i2c_client *client) -+{ -+ struct IR *ir = i2c_get_clientdata(client); -+ -+ mutex_lock(&ir->ir_lock); -+ -+ if (ir->have_rx || ir->have_tx) { -+ DECLARE_COMPLETION(tn); -+ DECLARE_COMPLETION(tn2); -+ -+ /* end up polling thread */ -+ if (ir->task && !IS_ERR(ir->task)) { -+ ir->t_notify = &tn; -+ ir->t_notify2 = &tn2; -+ ir->shutdown = 1; -+ wake_up_process(ir->task); -+ complete(&tn2); -+ wait_for_completion(&tn); -+ ir->t_notify = NULL; -+ ir->t_notify2 = NULL; -+ } -+ -+ } else { -+ mutex_unlock(&ir->ir_lock); -+ zilog_error("%s: detached from something we didn't " -+ "attach to\n", __func__); -+ return -ENODEV; -+ } -+ -+ /* unregister lirc driver */ -+ if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) { -+ lirc_unregister_driver(ir->l.minor); -+ ir_devices[ir->l.minor] = NULL; -+ } -+ -+ /* free memory */ -+ lirc_buffer_free(&ir->buf); -+ mutex_unlock(&ir->ir_lock); -+ kfree(ir); -+ -+ return 0; -+} -+ -+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ struct IR *ir = NULL; -+ struct i2c_adapter *adap = client->adapter; -+ char buf; -+ int ret; -+ int have_rx = 0, have_tx = 0; -+ -+ dprintk("%s: adapter id=0x%x, client addr=0x%02x\n", -+ __func__, adap->id, client->addr); -+ -+ /* -+ * The external IR receiver is at i2c address 0x71. -+ * The IR transmitter is at 0x70. -+ */ -+ client->addr = 0x70; -+ -+ if (!disable_tx) { -+ if (i2c_master_recv(client, &buf, 1) == 1) -+ have_tx = 1; -+ dprintk("probe 0x70 @ %s: %s\n", -+ adap->name, have_tx ? "success" : "failed"); -+ } -+ -+ if (!disable_rx) { -+ client->addr = 0x71; -+ if (i2c_master_recv(client, &buf, 1) == 1) -+ have_rx = 1; -+ dprintk("probe 0x71 @ %s: %s\n", -+ adap->name, have_rx ? "success" : "failed"); -+ } -+ -+ if (!(have_rx || have_tx)) { -+ zilog_error("%s: no devices found\n", adap->name); -+ goto out_nodev; -+ } -+ -+ printk(KERN_INFO "lirc_zilog: chip found with %s\n", -+ have_rx && have_tx ? "RX and TX" : -+ have_rx ? "RX only" : "TX only"); -+ -+ ir = kzalloc(sizeof(struct IR), GFP_KERNEL); -+ -+ if (!ir) -+ goto out_nomem; -+ -+ ret = lirc_buffer_init(&ir->buf, 2, BUFLEN / 2); -+ if (ret) -+ goto out_nomem; -+ -+ mutex_init(&ir->ir_lock); -+ mutex_init(&ir->buf_lock); -+ ir->need_boot = 1; -+ -+ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); -+ ir->l.minor = -1; -+ -+ /* I2C attach to device */ -+ i2c_set_clientdata(client, ir); -+ -+ /* initialise RX device */ -+ if (have_rx) { -+ DECLARE_COMPLETION(tn); -+ memcpy(&ir->c_rx, client, sizeof(struct i2c_client)); -+ -+ ir->c_rx.addr = 0x71; -+ strlcpy(ir->c_rx.name, ZILOG_HAUPPAUGE_IR_RX_NAME, -+ I2C_NAME_SIZE); -+ -+ /* try to fire up polling thread */ -+ ir->t_notify = &tn; -+ ir->task = kthread_run(lirc_thread, ir, "lirc_zilog"); -+ if (IS_ERR(ir->task)) { -+ ret = PTR_ERR(ir->task); -+ zilog_error("lirc_register_driver: cannot run " -+ "poll thread %d\n", ret); -+ goto err; -+ } -+ wait_for_completion(&tn); -+ ir->t_notify = NULL; -+ ir->have_rx = 1; -+ } -+ -+ /* initialise TX device */ -+ if (have_tx) { -+ memcpy(&ir->c_tx, client, sizeof(struct i2c_client)); -+ ir->c_tx.addr = 0x70; -+ strlcpy(ir->c_tx.name, ZILOG_HAUPPAUGE_IR_TX_NAME, -+ I2C_NAME_SIZE); -+ ir->have_tx = 1; -+ } -+ -+ /* set lirc_dev stuff */ -+ ir->l.code_length = 13; -+ ir->l.rbuf = &ir->buf; -+ ir->l.fops = &lirc_fops; -+ ir->l.data = ir; -+ ir->l.minor = minor; -+ ir->l.dev = &adap->dev; -+ ir->l.sample_rate = 0; -+ -+ /* register with lirc */ -+ ir->l.minor = lirc_register_driver(&ir->l); -+ if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) { -+ zilog_error("ir_attach: \"minor\" must be between 0 and %d " -+ "(%d)!\n", MAX_IRCTL_DEVICES-1, ir->l.minor); -+ ret = -EBADRQC; -+ goto err; -+ } -+ -+ /* store this for getting back in open() later on */ -+ ir_devices[ir->l.minor] = ir; -+ -+ /* -+ * if we have the tx device, load the 'firmware'. We do this -+ * after registering with lirc as otherwise hotplug seems to take -+ * 10s to create the lirc device. -+ */ -+ if (have_tx) { -+ /* Special TX init */ -+ ret = tx_init(ir); -+ if (ret != 0) -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ /* undo everything, hopefully... */ -+ if (ir->c_rx.addr) -+ ir_remove(&ir->c_rx); -+ if (ir->c_tx.addr) -+ ir_remove(&ir->c_tx); -+ return ret; -+ -+out_nodev: -+ zilog_error("no device found\n"); -+ return -ENODEV; -+ -+out_nomem: -+ zilog_error("memory allocation failure\n"); -+ kfree(ir); -+ return -ENOMEM; -+} -+ -+static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg) -+{ -+ /* nothing */ -+ return 0; -+} -+ -+static int __init zilog_init(void) -+{ -+ int ret; -+ -+ zilog_notify("Zilog/Hauppauge IR driver initializing\n"); -+ -+ mutex_init(&tx_data_lock); -+ -+ request_module("firmware_class"); -+ -+ ret = i2c_add_driver(&driver); -+ if (ret) -+ zilog_error("initialization failed\n"); -+ else -+ zilog_notify("initialization complete\n"); -+ -+ return ret; -+} -+ -+static void __exit zilog_exit(void) -+{ -+ i2c_del_driver(&driver); -+ /* if loaded */ -+ fw_unload(); -+ zilog_notify("Zilog/Hauppauge IR driver unloaded\n"); -+} -+ -+module_init(zilog_init); -+module_exit(zilog_exit); -+ -+MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)"); -+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, " -+ "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver"); -+MODULE_LICENSE("GPL"); -+/* for compat with old name, which isn't all that accurate anymore */ -+MODULE_ALIAS("lirc_pvr150"); -+ -+module_param(minor, int, 0444); -+MODULE_PARM_DESC(minor, "Preferred minor device number"); -+ -+module_param(debug, bool, 0644); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -+ -+module_param(disable_rx, bool, 0644); -+MODULE_PARM_DESC(disable_rx, "Disable the IR receiver device"); -+ -+module_param(disable_tx, bool, 0644); -+MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device"); diff --git a/only-use-alpha2-regulatory-information-from-country-IE.patch b/only-use-alpha2-regulatory-information-from-country-IE.patch deleted file mode 100644 index 5e7459cf8..000000000 --- a/only-use-alpha2-regulatory-information-from-country-IE.patch +++ /dev/null @@ -1,788 +0,0 @@ -From linville@tuxdriver.com Thu Jul 15 15:40:22 2010 -From: "John W. Linville" <linville@tuxdriver.com> -Subject: [RFC] wireless: only use alpha2 regulatory information from country IE -Date: Thu, 15 Jul 2010 15:06:47 -0400 - -The meaning and/or usage of the country IE is somewhat poorly defined. -In practice, this means that regulatory rulesets in a country IE are -often incomplete and might be untrustworthy. This removes the code -associated with interpreting those rulesets while preserving respect -for country "alpha2" codes also contained in the country IE. - -Signed-off-by: John W. Linville <linville@tuxdriver.com> ---- -This patch is compile-tested only! Please feel free to suggest that -I have left something out or missed some nuance of our regulatory -enforcement code... - - include/net/regulatory.h | 1 - - net/wireless/reg.c | 625 +--------------------------------------------- - 2 files changed, 12 insertions(+), 614 deletions(-) - -diff --git a/include/net/regulatory.h b/include/net/regulatory.h -index f873ee3..9e103a4 100644 ---- a/include/net/regulatory.h -+++ b/include/net/regulatory.h -@@ -54,7 +54,6 @@ struct regulatory_request { - enum nl80211_reg_initiator initiator; - char alpha2[2]; - bool intersect; -- u32 country_ie_checksum; - enum environment_cap country_ie_env; - struct list_head list; - }; -diff --git a/net/wireless/reg.c b/net/wireless/reg.c -index 1ac2bdd..678d0bd 100644 ---- a/net/wireless/reg.c -+++ b/net/wireless/reg.c -@@ -67,17 +67,9 @@ static struct platform_device *reg_pdev; - const struct ieee80211_regdomain *cfg80211_regdomain; - - /* -- * We use this as a place for the rd structure built from the -- * last parsed country IE to rest until CRDA gets back to us with -- * what it thinks should apply for the same country -- */ --static const struct ieee80211_regdomain *country_ie_regdomain; -- --/* - * Protects static reg.c components: - * - cfg80211_world_regdom - * - cfg80211_regdom -- * - country_ie_regdomain - * - last_request - */ - static DEFINE_MUTEX(reg_mutex); -@@ -275,25 +267,6 @@ static bool is_user_regdom_saved(void) - return true; - } - --/** -- * country_ie_integrity_changes - tells us if the country IE has changed -- * @checksum: checksum of country IE of fields we are interested in -- * -- * If the country IE has not changed you can ignore it safely. This is -- * useful to determine if two devices are seeing two different country IEs -- * even on the same alpha2. Note that this will return false if no IE has -- * been set on the wireless core yet. -- */ --static bool country_ie_integrity_changes(u32 checksum) --{ -- /* If no IE has been set then the checksum doesn't change */ -- if (unlikely(!last_request->country_ie_checksum)) -- return false; -- if (unlikely(last_request->country_ie_checksum != checksum)) -- return true; -- return false; --} -- - static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, - const struct ieee80211_regdomain *src_regd) - { -@@ -506,471 +479,6 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, - } - - /* -- * This is a work around for sanity checking ieee80211_channel_to_frequency()'s -- * work. ieee80211_channel_to_frequency() can for example currently provide a -- * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be -- * an AP providing channel 8 on a country IE triplet when it sent this on the -- * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz -- * channel. -- * -- * This can be removed once ieee80211_channel_to_frequency() takes in a band. -- */ --static bool chan_in_band(int chan, enum ieee80211_band band) --{ -- int center_freq = ieee80211_channel_to_frequency(chan); -- -- switch (band) { -- case IEEE80211_BAND_2GHZ: -- if (center_freq <= 2484) -- return true; -- return false; -- case IEEE80211_BAND_5GHZ: -- if (center_freq >= 5005) -- return true; -- return false; -- default: -- return false; -- } --} -- --/* -- * Some APs may send a country IE triplet for each channel they -- * support and while this is completely overkill and silly we still -- * need to support it. We avoid making a single rule for each channel -- * though and to help us with this we use this helper to find the -- * actual subband end channel. These type of country IE triplet -- * scenerios are handled then, all yielding two regulaotry rules from -- * parsing a country IE: -- * -- * [1] -- * [2] -- * [36] -- * [40] -- * -- * [1] -- * [2-4] -- * [5-12] -- * [36] -- * [40-44] -- * -- * [1-4] -- * [5-7] -- * [36-44] -- * [48-64] -- * -- * [36-36] -- * [40-40] -- * [44-44] -- * [48-48] -- * [52-52] -- * [56-56] -- * [60-60] -- * [64-64] -- * [100-100] -- * [104-104] -- * [108-108] -- * [112-112] -- * [116-116] -- * [120-120] -- * [124-124] -- * [128-128] -- * [132-132] -- * [136-136] -- * [140-140] -- * -- * Returns 0 if the IE has been found to be invalid in the middle -- * somewhere. -- */ --static int max_subband_chan(enum ieee80211_band band, -- int orig_cur_chan, -- int orig_end_channel, -- s8 orig_max_power, -- u8 **country_ie, -- u8 *country_ie_len) --{ -- u8 *triplets_start = *country_ie; -- u8 len_at_triplet = *country_ie_len; -- int end_subband_chan = orig_end_channel; -- -- /* -- * We'll deal with padding for the caller unless -- * its not immediate and we don't process any channels -- */ -- if (*country_ie_len == 1) { -- *country_ie += 1; -- *country_ie_len -= 1; -- return orig_end_channel; -- } -- -- /* Move to the next triplet and then start search */ -- *country_ie += 3; -- *country_ie_len -= 3; -- -- if (!chan_in_band(orig_cur_chan, band)) -- return 0; -- -- while (*country_ie_len >= 3) { -- int end_channel = 0; -- struct ieee80211_country_ie_triplet *triplet = -- (struct ieee80211_country_ie_triplet *) *country_ie; -- int cur_channel = 0, next_expected_chan; -- -- /* means last triplet is completely unrelated to this one */ -- if (triplet->ext.reg_extension_id >= -- IEEE80211_COUNTRY_EXTENSION_ID) { -- *country_ie -= 3; -- *country_ie_len += 3; -- break; -- } -- -- if (triplet->chans.first_channel == 0) { -- *country_ie += 1; -- *country_ie_len -= 1; -- if (*country_ie_len != 0) -- return 0; -- break; -- } -- -- if (triplet->chans.num_channels == 0) -- return 0; -- -- /* Monitonically increasing channel order */ -- if (triplet->chans.first_channel <= end_subband_chan) -- return 0; -- -- if (!chan_in_band(triplet->chans.first_channel, band)) -- return 0; -- -- /* 2 GHz */ -- if (triplet->chans.first_channel <= 14) { -- end_channel = triplet->chans.first_channel + -- triplet->chans.num_channels - 1; -- } -- else { -- end_channel = triplet->chans.first_channel + -- (4 * (triplet->chans.num_channels - 1)); -- } -- -- if (!chan_in_band(end_channel, band)) -- return 0; -- -- if (orig_max_power != triplet->chans.max_power) { -- *country_ie -= 3; -- *country_ie_len += 3; -- break; -- } -- -- cur_channel = triplet->chans.first_channel; -- -- /* The key is finding the right next expected channel */ -- if (band == IEEE80211_BAND_2GHZ) -- next_expected_chan = end_subband_chan + 1; -- else -- next_expected_chan = end_subband_chan + 4; -- -- if (cur_channel != next_expected_chan) { -- *country_ie -= 3; -- *country_ie_len += 3; -- break; -- } -- -- end_subband_chan = end_channel; -- -- /* Move to the next one */ -- *country_ie += 3; -- *country_ie_len -= 3; -- -- /* -- * Padding needs to be dealt with if we processed -- * some channels. -- */ -- if (*country_ie_len == 1) { -- *country_ie += 1; -- *country_ie_len -= 1; -- break; -- } -- -- /* If seen, the IE is invalid */ -- if (*country_ie_len == 2) -- return 0; -- } -- -- if (end_subband_chan == orig_end_channel) { -- *country_ie = triplets_start; -- *country_ie_len = len_at_triplet; -- return orig_end_channel; -- } -- -- return end_subband_chan; --} -- --/* -- * Converts a country IE to a regulatory domain. A regulatory domain -- * structure has a lot of information which the IE doesn't yet have, -- * so for the other values we use upper max values as we will intersect -- * with our userspace regulatory agent to get lower bounds. -- */ --static struct ieee80211_regdomain *country_ie_2_rd( -- enum ieee80211_band band, -- u8 *country_ie, -- u8 country_ie_len, -- u32 *checksum) --{ -- struct ieee80211_regdomain *rd = NULL; -- unsigned int i = 0; -- char alpha2[2]; -- u32 flags = 0; -- u32 num_rules = 0, size_of_regd = 0; -- u8 *triplets_start = NULL; -- u8 len_at_triplet = 0; -- /* the last channel we have registered in a subband (triplet) */ -- int last_sub_max_channel = 0; -- -- *checksum = 0xDEADBEEF; -- -- /* Country IE requirements */ -- BUG_ON(country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN || -- country_ie_len & 0x01); -- -- alpha2[0] = country_ie[0]; -- alpha2[1] = country_ie[1]; -- -- /* -- * Third octet can be: -- * 'I' - Indoor -- * 'O' - Outdoor -- * -- * anything else we assume is no restrictions -- */ -- if (country_ie[2] == 'I') -- flags = NL80211_RRF_NO_OUTDOOR; -- else if (country_ie[2] == 'O') -- flags = NL80211_RRF_NO_INDOOR; -- -- country_ie += 3; -- country_ie_len -= 3; -- -- triplets_start = country_ie; -- len_at_triplet = country_ie_len; -- -- *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8); -- -- /* -- * We need to build a reg rule for each triplet, but first we must -- * calculate the number of reg rules we will need. We will need one -- * for each channel subband -- */ -- while (country_ie_len >= 3) { -- int end_channel = 0; -- struct ieee80211_country_ie_triplet *triplet = -- (struct ieee80211_country_ie_triplet *) country_ie; -- int cur_sub_max_channel = 0, cur_channel = 0; -- -- if (triplet->ext.reg_extension_id >= -- IEEE80211_COUNTRY_EXTENSION_ID) { -- country_ie += 3; -- country_ie_len -= 3; -- continue; -- } -- -- /* -- * APs can add padding to make length divisible -- * by two, required by the spec. -- */ -- if (triplet->chans.first_channel == 0) { -- country_ie++; -- country_ie_len--; -- /* This is expected to be at the very end only */ -- if (country_ie_len != 0) -- return NULL; -- break; -- } -- -- if (triplet->chans.num_channels == 0) -- return NULL; -- -- if (!chan_in_band(triplet->chans.first_channel, band)) -- return NULL; -- -- /* 2 GHz */ -- if (band == IEEE80211_BAND_2GHZ) -- end_channel = triplet->chans.first_channel + -- triplet->chans.num_channels - 1; -- else -- /* -- * 5 GHz -- For example in country IEs if the first -- * channel given is 36 and the number of channels is 4 -- * then the individual channel numbers defined for the -- * 5 GHz PHY by these parameters are: 36, 40, 44, and 48 -- * and not 36, 37, 38, 39. -- * -- * See: http://tinyurl.com/11d-clarification -- */ -- end_channel = triplet->chans.first_channel + -- (4 * (triplet->chans.num_channels - 1)); -- -- cur_channel = triplet->chans.first_channel; -- -- /* -- * Enhancement for APs that send a triplet for every channel -- * or for whatever reason sends triplets with multiple channels -- * separated when in fact they should be together. -- */ -- end_channel = max_subband_chan(band, -- cur_channel, -- end_channel, -- triplet->chans.max_power, -- &country_ie, -- &country_ie_len); -- if (!end_channel) -- return NULL; -- -- if (!chan_in_band(end_channel, band)) -- return NULL; -- -- cur_sub_max_channel = end_channel; -- -- /* Basic sanity check */ -- if (cur_sub_max_channel < cur_channel) -- return NULL; -- -- /* -- * Do not allow overlapping channels. Also channels -- * passed in each subband must be monotonically -- * increasing -- */ -- if (last_sub_max_channel) { -- if (cur_channel <= last_sub_max_channel) -- return NULL; -- if (cur_sub_max_channel <= last_sub_max_channel) -- return NULL; -- } -- -- /* -- * When dot11RegulatoryClassesRequired is supported -- * we can throw ext triplets as part of this soup, -- * for now we don't care when those change as we -- * don't support them -- */ -- *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) | -- ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) | -- ((triplet->chans.max_power ^ cur_sub_max_channel) << 24); -- -- last_sub_max_channel = cur_sub_max_channel; -- -- num_rules++; -- -- if (country_ie_len >= 3) { -- country_ie += 3; -- country_ie_len -= 3; -- } -- -- /* -- * Note: this is not a IEEE requirement but -- * simply a memory requirement -- */ -- if (num_rules > NL80211_MAX_SUPP_REG_RULES) -- return NULL; -- } -- -- country_ie = triplets_start; -- country_ie_len = len_at_triplet; -- -- size_of_regd = sizeof(struct ieee80211_regdomain) + -- (num_rules * sizeof(struct ieee80211_reg_rule)); -- -- rd = kzalloc(size_of_regd, GFP_KERNEL); -- if (!rd) -- return NULL; -- -- rd->n_reg_rules = num_rules; -- rd->alpha2[0] = alpha2[0]; -- rd->alpha2[1] = alpha2[1]; -- -- /* This time around we fill in the rd */ -- while (country_ie_len >= 3) { -- int end_channel = 0; -- struct ieee80211_country_ie_triplet *triplet = -- (struct ieee80211_country_ie_triplet *) country_ie; -- struct ieee80211_reg_rule *reg_rule = NULL; -- struct ieee80211_freq_range *freq_range = NULL; -- struct ieee80211_power_rule *power_rule = NULL; -- -- /* -- * Must parse if dot11RegulatoryClassesRequired is true, -- * we don't support this yet -- */ -- if (triplet->ext.reg_extension_id >= -- IEEE80211_COUNTRY_EXTENSION_ID) { -- country_ie += 3; -- country_ie_len -= 3; -- continue; -- } -- -- if (triplet->chans.first_channel == 0) { -- country_ie++; -- country_ie_len--; -- break; -- } -- -- reg_rule = &rd->reg_rules[i]; -- freq_range = ®_rule->freq_range; -- power_rule = ®_rule->power_rule; -- -- reg_rule->flags = flags; -- -- /* 2 GHz */ -- if (band == IEEE80211_BAND_2GHZ) -- end_channel = triplet->chans.first_channel + -- triplet->chans.num_channels -1; -- else -- end_channel = triplet->chans.first_channel + -- (4 * (triplet->chans.num_channels - 1)); -- -- end_channel = max_subband_chan(band, -- triplet->chans.first_channel, -- end_channel, -- triplet->chans.max_power, -- &country_ie, -- &country_ie_len); -- -- /* -- * The +10 is since the regulatory domain expects -- * the actual band edge, not the center of freq for -- * its start and end freqs, assuming 20 MHz bandwidth on -- * the channels passed -- */ -- freq_range->start_freq_khz = -- MHZ_TO_KHZ(ieee80211_channel_to_frequency( -- triplet->chans.first_channel) - 10); -- freq_range->end_freq_khz = -- MHZ_TO_KHZ(ieee80211_channel_to_frequency( -- end_channel) + 10); -- -- /* -- * These are large arbitrary values we use to intersect later. -- * Increment this if we ever support >= 40 MHz channels -- * in IEEE 802.11 -- */ -- freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); -- power_rule->max_antenna_gain = DBI_TO_MBI(100); -- power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power); -- -- i++; -- -- if (country_ie_len >= 3) { -- country_ie += 3; -- country_ie_len -= 3; -- } -- -- BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); -- } -- -- return rd; --} -- -- --/* - * Helper for regdom_intersect(), this does the real - * mathematical intersection fun - */ -@@ -1191,7 +699,6 @@ static int freq_reg_info_regd(struct wiphy *wiphy, - - return -EINVAL; - } --EXPORT_SYMBOL(freq_reg_info); - - int freq_reg_info(struct wiphy *wiphy, - u32 center_freq, -@@ -1205,6 +712,7 @@ int freq_reg_info(struct wiphy *wiphy, - reg_rule, - NULL); - } -+EXPORT_SYMBOL(freq_reg_info); - - /* - * Note that right now we assume the desired channel bandwidth -@@ -1243,41 +751,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, - desired_bw_khz, - ®_rule); - -- if (r) { -- /* -- * This means no regulatory rule was found in the country IE -- * with a frequency range on the center_freq's band, since -- * IEEE-802.11 allows for a country IE to have a subset of the -- * regulatory information provided in a country we ignore -- * disabling the channel unless at least one reg rule was -- * found on the center_freq's band. For details see this -- * clarification: -- * -- * http://tinyurl.com/11d-clarification -- */ -- if (r == -ERANGE && -- last_request->initiator == -- NL80211_REGDOM_SET_BY_COUNTRY_IE) { -- REG_DBG_PRINT("cfg80211: Leaving channel %d MHz " -- "intact on %s - no rule found in band on " -- "Country IE\n", -- chan->center_freq, wiphy_name(wiphy)); -- } else { -- /* -- * In this case we know the country IE has at least one reg rule -- * for the band so we respect its band definitions -- */ -- if (last_request->initiator == -- NL80211_REGDOM_SET_BY_COUNTRY_IE) -- REG_DBG_PRINT("cfg80211: Disabling " -- "channel %d MHz on %s due to " -- "Country IE\n", -- chan->center_freq, wiphy_name(wiphy)); -- flags |= IEEE80211_CHAN_DISABLED; -- chan->flags = flags; -- } -+ if (r) - return; -- } - - power_rule = ®_rule->power_rule; - freq_range = ®_rule->freq_range; -@@ -2010,7 +1485,7 @@ EXPORT_SYMBOL(regulatory_hint); - - /* Caller must hold reg_mutex */ - static bool reg_same_country_ie_hint(struct wiphy *wiphy, -- u32 country_ie_checksum) -+ char *alpha2, enum environment_cap env) - { - struct wiphy *request_wiphy; - -@@ -2026,13 +1501,17 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, - return false; - - if (likely(request_wiphy != wiphy)) -- return !country_ie_integrity_changes(country_ie_checksum); -+ return (last_request->alpha2[0] == alpha2[0] && -+ last_request->alpha2[1] == alpha2[1] && -+ last_request->country_ie_env == env); - /* - * We should not have let these through at this point, they - * should have been picked up earlier by the first alpha2 check - * on the device - */ -- if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum))) -+ if (WARN_ON((last_request->alpha2[0] == alpha2[0] && -+ last_request->alpha2[1] == alpha2[1] && -+ last_request->country_ie_env == env ))) - return true; - return false; - } -@@ -2048,7 +1527,6 @@ void regulatory_hint_11d(struct wiphy *wiphy, - { - struct ieee80211_regdomain *rd = NULL; - char alpha2[2]; -- u32 checksum = 0; - enum environment_cap env = ENVIRON_ANY; - struct regulatory_request *request; - -@@ -2064,14 +1542,6 @@ void regulatory_hint_11d(struct wiphy *wiphy, - if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) - goto out; - -- /* -- * Pending country IE processing, this can happen after we -- * call CRDA and wait for a response if a beacon was received before -- * we were able to process the last regulatory_hint_11d() call -- */ -- if (country_ie_regdomain) -- goto out; -- - alpha2[0] = country_ie[0]; - alpha2[1] = country_ie[1]; - -@@ -2090,12 +1560,6 @@ void regulatory_hint_11d(struct wiphy *wiphy, - wiphy_idx_valid(last_request->wiphy_idx))) - goto out; - -- rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum); -- if (!rd) { -- REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n"); -- goto out; -- } -- - /* - * This will not happen right now but we leave it here for the - * the future when we want to add suspend/resume support and having -@@ -2105,24 +1569,17 @@ void regulatory_hint_11d(struct wiphy *wiphy, - * If we hit this before we add this support we want to be informed of - * it as it would indicate a mistake in the current design - */ -- if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum))) -+ if (WARN_ON(reg_same_country_ie_hint(wiphy, alpha2, env))) - goto free_rd_out; - - request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); - if (!request) - goto free_rd_out; - -- /* -- * We keep this around for when CRDA comes back with a response so -- * we can intersect with that -- */ -- country_ie_regdomain = rd; -- - request->wiphy_idx = get_wiphy_idx(wiphy); -- request->alpha2[0] = rd->alpha2[0]; -- request->alpha2[1] = rd->alpha2[1]; -+ request->alpha2[0] = alpha2[0]; -+ request->alpha2[1] = alpha2[1]; - request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE; -- request->country_ie_checksum = checksum; - request->country_ie_env = env; - - mutex_unlock(®_mutex); -@@ -2383,33 +1840,6 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd) - print_rd_rules(rd); - } - --#ifdef CONFIG_CFG80211_REG_DEBUG --static void reg_country_ie_process_debug( -- const struct ieee80211_regdomain *rd, -- const struct ieee80211_regdomain *country_ie_regdomain, -- const struct ieee80211_regdomain *intersected_rd) --{ -- printk(KERN_DEBUG "cfg80211: Received country IE:\n"); -- print_regdomain_info(country_ie_regdomain); -- printk(KERN_DEBUG "cfg80211: CRDA thinks this should applied:\n"); -- print_regdomain_info(rd); -- if (intersected_rd) { -- printk(KERN_DEBUG "cfg80211: We intersect both of these " -- "and get:\n"); -- print_regdomain_info(intersected_rd); -- return; -- } -- printk(KERN_DEBUG "cfg80211: Intersection between both failed\n"); --} --#else --static inline void reg_country_ie_process_debug( -- const struct ieee80211_regdomain *rd, -- const struct ieee80211_regdomain *country_ie_regdomain, -- const struct ieee80211_regdomain *intersected_rd) --{ --} --#endif -- - /* Takes ownership of rd only if it doesn't fail */ - static int __set_regdom(const struct ieee80211_regdomain *rd) - { -@@ -2521,34 +1951,6 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) - return 0; - } - -- /* -- * Country IE requests are handled a bit differently, we intersect -- * the country IE rd with what CRDA believes that country should have -- */ -- -- /* -- * Userspace could have sent two replies with only -- * one kernel request. By the second reply we would have -- * already processed and consumed the country_ie_regdomain. -- */ -- if (!country_ie_regdomain) -- return -EALREADY; -- BUG_ON(rd == country_ie_regdomain); -- -- /* -- * Intersect what CRDA returned and our what we -- * had built from the Country IE received -- */ -- -- intersected_rd = regdom_intersect(rd, country_ie_regdomain); -- -- reg_country_ie_process_debug(rd, -- country_ie_regdomain, -- intersected_rd); -- -- kfree(country_ie_regdomain); -- country_ie_regdomain = NULL; -- - if (!intersected_rd) - return -EINVAL; - -@@ -2688,9 +2090,6 @@ void /* __init_or_exit */ regulatory_exit(void) - - reset_regdomains(); - -- kfree(country_ie_regdomain); -- country_ie_regdomain = NULL; -- - kfree(last_request); - - platform_device_unregister(reg_pdev); --- -1.7.1.1 - - diff --git a/pci-acpi-disable-aspm-if-no-osc.patch b/pci-acpi-disable-aspm-if-no-osc.patch deleted file mode 100644 index 044f38964..000000000 --- a/pci-acpi-disable-aspm-if-no-osc.patch +++ /dev/null @@ -1,53 +0,0 @@ -From: Matthew Garrett <mjg@redhat.com> -Subject: ACPI: Disable ASPM if the platform won't provide _OSC control for PCIe - -ACPI: Disable ASPM if the platform won't provide _OSC control for PCIe - -The PCI SIG documentation for the _OSC OS/firmware handshaking interface -states: - -"If the _OSC control method is absent from the scope of a host bridge -device, then the operating system must not enable or attempt to use any -features defined in this section for the hierarchy originated by the host -bridge." - -The obvious interpretation of this is that the OS should not attempt to use -PCIe hotplug, PME or AER - however, the specification also notes that an -_OSC method is *required* for PCIe hierarchies, and experimental validation -with An Alternative OS indicates that it doesn't use any PCIe functionality -if the _OSC method is missing. That arguably means we shouldn't be using -MSI or extended config space, but right now our problems seem to be limited -to vendors being surprised when ASPM gets enabled on machines when other -OSs refuse to do so. So, for now, let's just disable ASPM if the _OSC -method doesn't exist or refuses to hand over PCIe capability control. - -Signed-off-by: Matthew Garrett <mjg@redhat.com> ---- - -diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c -index 4eac593..1f67057 100644 ---- a/drivers/acpi/pci_root.c -+++ b/drivers/acpi/pci_root.c -@@ -33,6 +33,7 @@ - #include <linux/pm_runtime.h> - #include <linux/pci.h> - #include <linux/pci-acpi.h> -+#include <linux/pci-aspm.h> - #include <linux/acpi.h> - #include <linux/slab.h> - #include <acpi/acpi_bus.h> -@@ -543,6 +544,14 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) - if (flags != base_flags) - acpi_pci_osc_support(root, flags); - -+ status = acpi_pci_osc_control_set(root->device->handle, -+ 0); -+ -+ if (status == AE_NOT_EXIST) { -+ printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n"); -+ pcie_no_aspm(); -+ } -+ - pci_acpi_add_bus_pm_notifier(device, root->bus); - if (device->wakeup.flags.run_wake) - device_set_run_wake(root->bus->bridge, true); diff --git a/pci-aspm-dont-enable-too-early.patch b/pci-aspm-dont-enable-too-early.patch deleted file mode 100644 index ea91a2554..000000000 --- a/pci-aspm-dont-enable-too-early.patch +++ /dev/null @@ -1,50 +0,0 @@ -From: Matthew Garrett <mjg@redhat.com> -Date: Wed, 9 Jun 2010 20:05:07 +0000 (-0400) -Subject: PCI: Don't enable aspm before drivers have had a chance to veto it -X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fjbarnes%2Fpci-2.6.git;a=commitdiff_plain;h=8f0b08c29f1df91315e48adce04462eb23671099 - -PCI: Don't enable aspm before drivers have had a chance to veto it - -The aspm code will currently set the configured aspm policy before drivers -have had an opportunity to indicate that their hardware doesn't support it. -Unfortunately, putting some hardware in L0 or L1 can result in the hardware -no longer responding to any requests, even after aspm is disabled. It makes -more sense to leave aspm policy at the BIOS defaults at initial setup time, -reconfiguring it after pci_enable_device() is called. This allows the -driver to blacklist individual devices beforehand. - -Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> -Signed-off-by: Matthew Garrett <mjg@redhat.com> -Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> ---- - -diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c -index be53d98..7122281 100644 ---- a/drivers/pci/pcie/aspm.c -+++ b/drivers/pci/pcie/aspm.c -@@ -588,11 +588,23 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) - * update through pcie_aspm_cap_init(). - */ - pcie_aspm_cap_init(link, blacklist); -- pcie_config_aspm_path(link); - - /* Setup initial Clock PM state */ - pcie_clkpm_cap_init(link, blacklist); -- pcie_set_clkpm(link, policy_to_clkpm_state(link)); -+ -+ /* -+ * At this stage drivers haven't had an opportunity to change the -+ * link policy setting. Enabling ASPM on broken hardware can cripple -+ * it even before the driver has had a chance to disable ASPM, so -+ * default to a safe level right now. If we're enabling ASPM beyond -+ * the BIOS's expectation, we'll do so once pci_enable_device() is -+ * called. -+ */ -+ if (aspm_policy != POLICY_POWERSAVE) { -+ pcie_config_aspm_path(link); -+ pcie_set_clkpm(link, policy_to_clkpm_state(link)); -+ } -+ - unlock: - mutex_unlock(&aspm_lock); - out: diff --git a/scripts/pull-upstreams.sh b/scripts/pull-upstreams.sh index e94fcfd48..11df40466 100755 --- a/scripts/pull-upstreams.sh +++ b/scripts/pull-upstreams.sh @@ -1,7 +1,6 @@ #!/bin/bash utrace_base=2.6-current -utrace_base=2.6.34 url=http://people.redhat.com/roland/utrace/${1:-$utrace_base} @@ -1,2 +1,2 @@ 091abeb4684ce03d1d936851618687b6 linux-2.6.35.tar.bz2 -1e730019937132cd4d0bcf2c35384e86 patch-2.6.35-git1.bz2 +4f51963b5e076fb87ab32bda229a524f patch-2.6.36-rc1.bz2 diff --git a/utrace-ptrace-fix-build.patch b/utrace-ptrace-fix-build.patch deleted file mode 100644 index c0de8764d..000000000 --- a/utrace-ptrace-fix-build.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 9b7ec0e07ce85c377b76626cef552d27d59cc405 Mon Sep 17 00:00:00 2001 -From: Kyle McMartin <kyle@dreadnought.i.jkkm.org> -Date: Tue, 22 Jun 2010 13:57:47 +0100 -Subject: utrace-ptrace: removed defunct arch_ptrace_untrace call - -commit faa4602e removed the unused BTS code which had added -this hook. - -Signed-off-by: Kyle McMartin <kyle@redhat.com> ---- - kernel/ptrace-utrace.c | 2 -- - 1 files changed, 0 insertions(+), 2 deletions(-) - -diff --git a/kernel/ptrace-utrace.c b/kernel/ptrace-utrace.c -index 86234ee..1a8ba5e 100644 ---- a/kernel/ptrace-utrace.c -+++ b/kernel/ptrace-utrace.c -@@ -50,8 +50,6 @@ void __ptrace_unlink(struct task_struct *child) - child->ptrace = 0; - child->parent = child->real_parent; - list_del_init(&child->ptrace_entry); -- -- arch_ptrace_untrace(child); - } - - struct ptrace_context { --- -1.7.0.1 - diff --git a/utrace-remove-use-of-kref_set.patch b/utrace-remove-use-of-kref_set.patch deleted file mode 100644 index f696f81fb..000000000 --- a/utrace-remove-use-of-kref_set.patch +++ /dev/null @@ -1,32 +0,0 @@ -From ad778e66100e4b76bab6b939e3d0c781da82d980 Mon Sep 17 00:00:00 2001 -From: Kyle McMartin <kyle@dreadnought.i.jkkm.org> -Date: Tue, 22 Jun 2010 14:09:30 +0100 -Subject: utrace: remove use of kref_set - -Unfortunatey db1afffa which removed kref_set did not anticipate -anyone would actually like to use a kref which starts with a refcnt -above 1. Replace kref_set in utrace with a kref_init + kref_get to -immediately bump the reference count. - -Signed-off-by: Kyle McMartin <kyle@redhat.com> ---- - kernel/utrace.c | 3 ++- - 1 files changed, 2 insertions(+), 1 deletions(-) - -diff --git a/kernel/utrace.c b/kernel/utrace.c -index f5a9e2c..cc864d5 100644 ---- a/kernel/utrace.c -+++ b/kernel/utrace.c -@@ -304,7 +304,8 @@ struct utrace_engine *utrace_attach_task( - * Initialize the new engine structure. It starts out with two - * refs: one ref to return, and one ref for being attached. - */ -- kref_set(&engine->kref, 2); -+ kref_init(&engine->kref); -+ kref_get(&engine->kref); - engine->flags = 0; - engine->ops = ops; - engine->data = data; --- -1.7.0.1 - |