diff options
Diffstat (limited to 'recipes/linux/linux-mtx-2-2.4.27/35-sb2-slic.patch')
-rw-r--r-- | recipes/linux/linux-mtx-2-2.4.27/35-sb2-slic.patch | 761 |
1 files changed, 761 insertions, 0 deletions
diff --git a/recipes/linux/linux-mtx-2-2.4.27/35-sb2-slic.patch b/recipes/linux/linux-mtx-2-2.4.27/35-sb2-slic.patch new file mode 100644 index 0000000000..9d985da878 --- /dev/null +++ b/recipes/linux/linux-mtx-2-2.4.27/35-sb2-slic.patch @@ -0,0 +1,761 @@ +--- linux-org/arch/mips/au1000/mtx-2/Makefile 2006-05-01 13:34:12.664217250 +0200 ++++ linux/arch/mips/au1000/mtx-2/Makefile 2006-05-01 13:33:35.609901500 +0200 +@@ -15,6 +15,6 @@ + + O_TARGET := mtx-2.o + +-obj-y := init.o board_setup.o irqmap.o ++obj-y := init.o board_setup.o irqmap.o slic.o + + include $(TOPDIR)/Rules.make +--- linux-org/arch/mips/au1000/mtx-2/slic.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux/arch/mips/au1000/mtx-2/slic.c 2006-06-20 13:46:05.321244750 +0200 +@@ -0,0 +1,704 @@ ++/* ++ * Driver for the SLIC ++ * ++ * After the module is loaded there is a device /dev/misc/slic ++ * that can be read. A read returns if the DETECT-line has been toggled, ++ * indicating an offhook-event. ++ * ++ * Commands to be written to the device: ++ * P1 - Power on ++ * P0 - Power off ++ * ID - Idle state ++ * AC - Active state ++ * AR - Active state with reverse polarity ++ * R1 - Ringing on ++ * R0 - Ringing off ++ */ ++ ++#include <linux/config.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/irq.h> ++#include <linux/kernel.h> ++#include <linux/miscdevice.h> ++#include <linux/module.h> ++#include <linux/poll.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/timer.h> ++#include <linux/interrupt.h> ++#include <linux/types.h> ++#include <linux/version.h> ++#include <asm/uaccess.h> ++#include <asm/au1000.h> ++#include <linux/slic.h> ++ ++/* #define DEBUG */ ++#ifdef DEBUG ++#define debug(args...) printk(args) ++#else /* DEBUG */ ++#define debug(args...) ++#endif /* DEBUG */ ++ ++/*---------[ declarations ]-----------------*/ ++ ++#ifdef CONFIG_MIPS_MTX1 ++ ++//#define SLIC_D0 (AU1500_GPIO_205) /* D0 - D3 */ ++//#define SLIC_D1 (AU1500_GPIO_206) ++//#define SLIC_D2 (AU1500_GPIO_208) ++//#define SLIC_PD (AU1500_GPIO_209) /* Power down */ ++#define SLIC_D0_GPIO (5) ++#define SLIC_D1_GPIO (6) ++#define SLIC_D2_GPIO (8) ++#define SLIC_PD_GPIO (9) ++#define SLIC_OH (AU1000_GPIO_8) /* Off hook */ ++#define SLIC_OH_GPIO (8) /* GPIO-pin */ ++#define SLIC_D0 (AU1500_GPIO_205) /* D0 - D3 */ ++#define SLIC_D1 (AU1500_GPIO_206) ++#define SLIC_D2 (AU1500_GPIO_208) ++#define SLIC_PD (AU1500_GPIO_209) /* Power down */ ++#define SLIC_DP_DIR (GPIO2_DIR) /* Direction-register */ ++#define SLIC_DP_OUT (GPIO2_OUTPUT) /* Output-register */ ++#define SLIC_DP_PINSTATE (GPIO2_PINSTATE) /* Input-register */ ++ ++inline void gpio_init(void) { ++ au_writel(au_readl(SYS_TRIOUTCLR) & ~SLIC_OH_GPIO, SYS_TRIOUTCLR); // SLIC_OH_GPIO as tristate ++ au_writel((au_readl(SLIC_DP_DIR) | ((1 << SLIC_PD_GPIO)|(1 << SLIC_D0_GPIO)|(1 << SLIC_D1_GPIO)|(1 << SLIC_D2_GPIO))), SLIC_DP_DIR); ++} ++ ++inline void gpio_write(unsigned short bitmask, unsigned short value) { ++ au_writel((bitmask << 16) | value, SLIC_DP_OUT); ++} ++inline short gpio_read(unsigned short pin) { ++ return (au_readl(SLIC_DP_PINSTATE) >> pin) & 1; ++} ++ ++inline short gpio2_read(unsigned short pin) { ++ return (au_readl(SYS_PINSTATERD) >> pin) & 1; ++} ++#elif defined CONFIG_MIPS_MTX2 ++ ++//#define SLIC_D0 (AU1000_GPIO_10) /* D0 - D3 */ ++//#define SLIC_D1 (AU1000_GPIO_11) ++//#define SLIC_D2 (AU1000_GPIO_12) ++//#define SLIC_PD (AU1000_GPIO_13) /* Power down */ ++#define SLIC_D0_GPIO (10) /* GPIO-pins */ ++#define SLIC_D1_GPIO (11) ++#define SLIC_D2_GPIO (12) ++#define SLIC_PD_GPIO (13) ++ ++#define SLIC_OH (AU1000_GPIO_9) /* Off hook */ ++#define SLIC_OH_GPIO (9) /* GPIO-pin */ ++ ++inline void gpio_init(void) { ++ au_writel(au_readl(SYS_PINFUNC) & ~SYS_PF_U3, SYS_PINFUNC); // configure GPIO9-14 as GPIO ++ au_writel(1<<SLIC_OH_GPIO, SYS_TRIOUTCLR); /* SLIC_OH_GPIO as tristate */ ++} ++ ++ ++inline void gpio_write(unsigned int bitmask, unsigned int value) { ++ au_writel(bitmask & ~value, SYS_OUTPUTCLR); ++ au_writel(bitmask & value, SYS_OUTPUTSET); ++} ++ ++inline short gpio_read(unsigned short pin) { ++ return (au_readl(SYS_PINSTATERD)>>pin) & 1; ++} ++ ++inline short gpio2_read(unsigned short pin) { ++ return (au_readl(SYS_PINSTATERD)>>pin) & 1; ++} ++#else ++#error Cannot find hardware platform ++#endif ++ ++ ++/* States of SLIC-device, set via PD- and Dx-Pins */ ++/* ---------------------------------------------- */ ++#define SLIC_BITMASK ((1 << SLIC_PD_GPIO)|(1 << SLIC_D0_GPIO)|(1 << SLIC_D1_GPIO)|(1 << SLIC_D2_GPIO)) ++/* Hi-Z-state, for onhook-condition, only detects offhook-event, minimum power-usage */ ++#define SLIC_STATE_IDLE (1 << SLIC_PD_GPIO) ++/* Active-state, for offhook-condition and other states where phone needs to be powered */ ++#define SLIC_STATE_ACTIVE ((1 << SLIC_PD_GPIO)|(1 << SLIC_D1_GPIO)) ++/* Active-state with reverse polarity */ ++#define SLIC_STATE_REVERSE ((1 << SLIC_PD_GPIO)|(1 << SLIC_D1_GPIO)|(1 << SLIC_D2_GPIO)) ++/* Ringing-state */ ++#define SLIC_STATE_RINGING ((1 << SLIC_PD_GPIO)|(1 << SLIC_D0_GPIO)) ++/* Powerdown-state */ ++#define SLIC_STATE_POWERDOWN (0) ++ ++#define SLIC_SET_STATE(x) do { \ ++ current_state = x; \ ++ gpio_write(SLIC_BITMASK, x); \ ++ } while (0) ++ ++enum Slic_State { ONHOOK, OFFHOOK }; ++ ++enum Event { evONHOOK, evOFFHOOK, evFLASH }; ++ ++static DECLARE_WAIT_QUEUE_HEAD(slic_wait_queue); ++static int slic_minor = -1; ++static char is_inuse = 0; ++static char state_changed = 0; ++static enum Event last_value = 0; ++static unsigned long event_time = 0; ++static enum Slic_State event_value = 0; ++static u32 current_state = 0; ++static char active_reverse = 0; ++ ++/* Timer-stuff */ ++static char restart_timer = 1; /* Bool, if true, timer will be restarted by timer-function. */ ++static char timer_started = 0; /* Bool, if true, timer was added. */ ++static struct timer_list slic_ring_timer; ++static struct timer_list slic_timer; ++ ++#define RING_TIMER_INTERVALL (HZ/50) /* 25 Hz */ ++#define RINGOFF_TIME (4*HZ) ++#define RINGON_TIME (1*HZ) ++ ++static void irq_taskletFunc(unsigned long dummy); ++DECLARE_TASKLET(irq_tasklet, irq_taskletFunc, (unsigned long)&state_changed); ++ ++enum Timer_Task { DEBOUNCE_ONHOOK, DETECT_FLASH_MIN, DETECT_FLASH_MAX, POWERON }; ++ ++inline enum Slic_State get_current_slic_state(void) { ++ return gpio2_read(SLIC_OH_GPIO) ? ONHOOK : OFFHOOK; ++} ++ ++#define DEBOUNCE_TIME 200 ++#define FLASH_MIN_TIME 170 ++#define FLASH_MAX_TIME 310 ++#define POWERON_TIME 200 ++ ++unsigned int flash_min_t = FLASH_MIN_TIME; ++unsigned int flash_max_t = FLASH_MAX_TIME; ++ ++ ++static void slic_start_timer (unsigned long time_base, unsigned int timeout, enum Timer_Task timer_task ); ++ ++/*---------[ Timer functions ]--------------------*/ ++ ++/* The timer is used to toggle the d2-pin with 25 Hz. This generates the ++ ring-tone in the phone. */ ++ ++static unsigned long ringtone = 0; ++static unsigned long ringpause = RINGOFF_TIME; ++static unsigned long ringsignal = RINGON_TIME; ++ ++static void slic_do_ring (unsigned long data) ++{ ++ /* Debug-output */ ++ /* ++ static int count = 0; ++ if (((++count) % 50) == 0) ++ debug("."); ++ */ ++ ++ /* Toggle d2-pin */ ++ u32 tmp = gpio_read(SLIC_D2_GPIO); ++ gpio_write((1 << SLIC_D2_GPIO), (tmp ? 0 : 1) << SLIC_D2_GPIO); ++ ++ if (restart_timer) { ++ if ( jiffies<ringtone ) { ++ slic_ring_timer.expires += RING_TIMER_INTERVALL; ++ } else { ++ slic_ring_timer.expires += ringpause; ++ ringtone += ringpause + ringsignal; ++ } ++ add_timer(&slic_ring_timer); ++ } ++} ++ ++static void slic_start_ring_timer (void) ++{ ++ if (timer_started) ++ return; ++ timer_started = 1; ++ restart_timer = 1; /* Reenable self-reschedule */ ++ ringtone = jiffies + ringsignal; ++ slic_ring_timer.expires = jiffies; ++ slic_do_ring(0); ++} ++ ++static void slic_stop_ring_timer (void) ++{ ++ if (!timer_started) ++ return; ++ restart_timer = 0; /* Timer-func mustn't reschedule itself while being stopped */ ++ del_timer_sync(&slic_ring_timer); ++ timer_started = 0; ++} ++ ++ ++/*---------[ SLIC Functions ]-----------------*/ ++ ++/* Sets the SLIC to Hi-Z-state for powersaving. */ ++static void slic_idle (void) ++{ ++ slic_stop_ring_timer(); ++ SLIC_SET_STATE(SLIC_STATE_IDLE); ++} ++ ++/* Sets slic to active state. */ ++static void slic_active (void) ++{ ++ slic_stop_ring_timer(); ++ if ( active_reverse ) ++ SLIC_SET_STATE(SLIC_STATE_REVERSE); ++ else ++ SLIC_SET_STATE(SLIC_STATE_ACTIVE); ++} ++ ++/* Starts the timer-controlled toggling of the d-pins, which generates the ++ ringtone on the analog phone. */ ++static void slic_ring_on (void) ++{ ++ if ( current_state != SLIC_STATE_RINGING ) { ++ SLIC_SET_STATE(SLIC_STATE_RINGING); ++ slic_start_ring_timer(); /* start ringing */ ++ } ++} ++ ++/* Stops the timer to pause the ringing. */ ++static void slic_ring_off (void) ++{ ++ if ( current_state == SLIC_STATE_RINGING ) { ++ slic_stop_ring_timer(); ++ //SLIC_SET_STATE(SLIC_STATE_IDLE); <-- generates an irq!? ++ gpio_write((1 << SLIC_D2_GPIO), 0); ++ current_state = SLIC_STATE_IDLE; ++ } ++} ++ ++/* Powers up the slic device */ ++static void slic_power_on (void) ++{ ++ // this can generate a wrong off-hook event, so we 'debounce' the power on ++ event_time = jiffies; // this stops irq from generating off-hook event ++ SLIC_SET_STATE(SLIC_STATE_IDLE); ++ slic_start_timer(event_time, POWERON_TIME, POWERON); ++} ++ ++/* Shuts down the slic-device */ ++static void slic_power_off (void) ++{ ++ slic_stop_ring_timer(); ++ SLIC_SET_STATE(SLIC_STATE_POWERDOWN); ++} ++ ++#ifdef DEBUG ++/* Testing: Turn on single pin */ ++static void slic_test (int pin) ++{ ++ switch (pin) { ++ case '0': ++ SLIC_SET_STATE(1 << SLIC_PD_GPIO); ++ break; ++ case '1': ++ SLIC_SET_STATE(1 << SLIC_D0_GPIO); ++ break; ++ case '2': ++ SLIC_SET_STATE(1 << SLIC_D1_GPIO); ++ break; ++ case '3': ++ SLIC_SET_STATE(1 << SLIC_D2_GPIO); ++ break; ++ default: ++ break; ++ } ++} ++#endif ++ ++/*---------[ Interrupt handling ]-----------------*/ ++ ++static void generate_event(enum Event ev) { ++ // storing only the current event, can lead to a event loss if the application ++ // doesn't read an event before the next occurs -> use an event queue to deliver ++ // events in sequence !! ++ debug("event: %i\n", ev); ++ last_value = ev; ++ state_changed = 1; ++ wake_up (&slic_wait_queue); ++} ++ ++// timeout in ms ; if timebase is 0 timeout is increased, otherwise absolute time_base+timeout is used ++static void slic_start_timer (unsigned long time_base, unsigned int timeout, enum Timer_Task timer_task ) ++{ ++ if ( time_base == 0 ) ++ slic_timer.expires += (timeout * HZ)/ 1000; ++ else ++ slic_timer.expires = time_base + (timeout * HZ)/ 1000; ++ slic_timer.data = (unsigned long) timer_task; ++ add_timer(&slic_timer); ++} ++ ++// timer used for - debouncing offhook (setting slic active, results in a onhook offhook irq) ++// - distinguish between onhook and flash ++static void slic_do_timer (unsigned long timer_task) { ++ enum Slic_State current = get_current_slic_state(); ++ int done = 0; ++ ++ switch ( timer_task ) { ++ case DEBOUNCE_ONHOOK: ++ if ( current == OFFHOOK ) { ++ // done, stable onhook state reached ++ done = 1; ++ } else { // current == ONHOOK ++ slic_start_timer(0, flash_min_t, DETECT_FLASH_MIN); ++ } ++ break; ++ case DETECT_FLASH_MIN: ++ if ( current == ONHOOK ) { ++ slic_start_timer(0, flash_max_t - flash_min_t, DETECT_FLASH_MAX); ++ } else { // current == OFFHOOK ++ // offhook too short for flash, ignore ++ done = 1; ++ } ++ break; ++ case DETECT_FLASH_MAX: ++ if ( current == ONHOOK ) { ++ // off-hook state reached ++ slic_idle(); ++ generate_event(evONHOOK); ++ done = 1; ++ } else { // current == OFFHOOK ++ // flash signal detected ++ generate_event(evFLASH); ++ done = 1; ++ } ++ break; ++ case POWERON: ++ if ( current == ONHOOK ) { ++ done = 1; // power on event 'debounced' ++ } else if ( current == OFFHOOK ) { ++ // probably we were off-hook when activating the slic; go off-hook now ++ slic_active(); ++ generate_event(evOFFHOOK); ++ slic_start_timer(event_time, DEBOUNCE_TIME, DEBOUNCE_ONHOOK); ++ } ++ } ++ ++ if ( done ) { ++ //re-enable irq and be careful to not loose a state change ++ event_time = 0; ++ if ( current != get_current_slic_state() && event_time==0 ) { ++ event_time = jiffies; ++ event_value = get_current_slic_state(); ++ tasklet_schedule(&irq_tasklet); ++ } ++ } ++} ++ ++static void irq_taskletFunc(unsigned long dummy) ++{ ++ if ( (current_state == SLIC_STATE_IDLE || current_state == SLIC_STATE_RINGING) && ++ event_value == OFFHOOK ) { ++ slic_active(); ++ generate_event(evOFFHOOK); ++ slic_start_timer(event_time, DEBOUNCE_TIME, DEBOUNCE_ONHOOK); ++ } else if ( ( current_state == SLIC_STATE_ACTIVE || current_state == SLIC_STATE_REVERSE ) && ++ event_value == ONHOOK ) { ++ slic_start_timer(event_time, flash_min_t, DETECT_FLASH_MIN); ++ } else { ++ // ignore event ++ event_time = 0; ++ } ++} ++ ++/* The interrupt is raised by a state-change on the DET-pin. This signals an ++ offhook-condition on the phone. */ ++static void slic_irq (int irq, void *private, struct pt_regs *regs) ++{ ++ if ( !event_time ) { ++ event_time = jiffies; ++ event_value = get_current_slic_state(); ++ tasklet_schedule(&irq_tasklet); ++ } ++} ++ ++static int slic_startirq (void) ++{ ++ if (request_irq(SLIC_OH, slic_irq, SA_INTERRUPT, "slic", (void *) &state_changed) < 0) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int slic_stopirq (void) ++{ ++ free_irq (SLIC_OH, (void *) &state_changed); ++ return 0; ++} ++ ++/*---------[ File Functions ]-----------------*/ ++ ++static int slic_open (struct inode *inode, struct file *file) ++{ ++ if (MINOR(inode->i_rdev) != slic_minor) ++ return -ENODEV; ++ if (is_inuse) ++ return -EBUSY; ++ is_inuse = 1; ++ state_changed = 0; ++ MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++static int slic_release (struct inode *inode, struct file *file) ++{ ++ if (MINOR(inode->i_rdev) == slic_minor) { ++ is_inuse = 0; ++ } ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static ssize_t slic_read (struct file *file, char *buf, size_t count, loff_t *ppos) ++{ ++ if (count < 1) ++ return -EINVAL; ++ if (!state_changed) ++ interruptible_sleep_on (&slic_wait_queue); ++ ++ state_changed = 0; ++ if (copy_to_user(buf, &last_value, 1)) { ++ return -EFAULT; ++ } ++ return 1; ++} ++ ++/* The SLIC is controlled with 2-byte commands. The first byte selects the type ++ of the command, the second is an additional parameter or ignored. */ ++static ssize_t slic_write (struct file *file, const char *buf, size_t count, loff_t *ppos) ++{ ++ char localbuff[2]; ++ size_t bytes_read = 0; ++ if (count < 2 || (count % 2)) ++ return -EINVAL; ++ while (bytes_read < count) { ++ if (copy_from_user(localbuff, buf + bytes_read, 2)) ++ return -EFAULT; ++ bytes_read += 2; ++ debug("SLIC: "); ++ switch (localbuff[0]) { ++ case 'P': ++ /* Power-command */ ++ if (localbuff[1] == '0') { ++ debug("Power off\n"); ++ slic_power_off(); ++ } else { ++ debug("Power on\n"); ++ slic_power_on(); ++ } ++ break; ++ case 'R': ++ /* Ring-command */ ++ if (localbuff[1] == '0') { ++ debug("Ring off\n"); ++ slic_ring_off(); ++ } else { ++ debug("Ring on\n"); ++ slic_ring_on(); ++ } ++ break; ++ case 'M': ++ /* Mode-command: 0 - active standard mode, 1 - active reverse mode */ ++ if (localbuff[1] == '0') { ++ debug("Active default\n"); ++ active_reverse = 0; ++ if ( current_state == SLIC_STATE_REVERSE ) ++ slic_active(); ++ } else { ++ debug("Active reverse default\n"); ++ active_reverse = 1; ++ if ( current_state == SLIC_STATE_ACTIVE ) ++ slic_active(); ++ } ++ break; ++ ++#ifdef DEBUG ++ case 'A': ++ /* Active-command */ ++ debug("Active\n"); ++ slic_active(); ++ break; ++ case 'I': ++ /* Idle-command */ ++ debug("Idle\n"); ++ slic_idle(); ++ break; ++ case 'T': ++ /* Test-command */ ++ debug("Test %c\n", localbuff[1]); ++ slic_test(localbuff[1]); ++ break; ++#endif ++ default: ++ return -EFAULT; ++ } ++ } ++ return count; /* Everything read */ ++} ++ ++static int ++slic_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ // don't using file information for now; only one slic supported ++ int ret = 0; ++ ++ /* ++ * extract the type and number bitfields, and don't decode ++ * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() ++ */ ++ if (_IOC_TYPE(cmd) != SLIC_IOC_MAGIC) return -ENOTTY; ++ if (_IOC_NR(cmd) > SLIC_IOC_MAXNR) return -ENOTTY; ++ ++ switch (cmd) { ++ case IOC_SLIC_POWER: ++ /* Power-command */ ++ if ( arg ) { ++ debug("Power on\n"); ++ slic_power_on(); ++ } else { ++ debug("Power off\n"); ++ slic_power_off(); ++ } ++ break; ++ case IOC_SLIC_RING: ++ /* Ring-command */ ++ if ( arg ) { ++ debug("Ring on\n"); ++ slic_ring_on(); ++ } else { ++ debug("Ring off\n"); ++ slic_ring_off(); ++ } ++ break; ++ case IOC_SLIC_MODE: ++ /* Mode-command: 0 - active standard mode, 1 - active reverse mode */ ++ if ( arg ) { ++ debug("Active reverse default\n"); ++ active_reverse = 1; ++ if ( current_state == SLIC_STATE_ACTIVE ) ++ slic_active(); ++ } else { ++ debug("Active default\n"); ++ active_reverse = 0; ++ if ( current_state == SLIC_STATE_REVERSE ) ++ slic_active(); ++ } ++ break; ++ case IOC_SLIC_HOOKFLASH: ++ /* set hook-flash time */ ++ { ++ int min = arg & 0xffff; ++ int max = arg>>16; ++ if ( min<max && min >= 20 && max <= 1000 ) { ++ flash_min_t = min; ++ flash_max_t = max; ++ } else { ++ ret = -EINVAL; ++ } ++ } ++ break; ++ ++#ifdef DEBUG ++ case IOC_SLIC_TEST: ++ /* Test-command */ ++ debug("Test %li\n", arg & SLIC_BITMASK); ++ SLIC_SET_STATE(arg); ++ break; ++#endif ++ default: ++ ret = -ENOTTY; ++ } ++ ++ return ret; ++} ++ ++static unsigned int slic_poll (struct file *file, poll_table * wait) ++{ ++ unsigned int mask = 0; ++ ++ poll_wait (file, &slic_wait_queue, wait); ++ if (state_changed) /* state changed since last time. */ ++ mask |= POLLIN | POLLRDNORM; ++ return mask; ++} ++ ++/*---------[ Module stuff ]-----------------*/ ++ ++static struct file_operations slic_fops = { ++ .owner = THIS_MODULE, ++ .llseek = NULL, ++ .read = slic_read, ++ .write = slic_write, ++ .readdir = NULL, ++ .poll = slic_poll, ++ .ioctl = slic_ioctl, ++ .mmap = NULL, ++ .open = slic_open, ++ .flush = NULL, ++ .release = slic_release ++}; ++ ++static struct miscdevice slic_miscdev = { ++ MISC_DYNAMIC_MINOR, ++ "slic", ++ &slic_fops ++}; ++ ++void __exit slic_cleanup (void) ++{ ++ is_inuse = 1; ++ slic_stop_ring_timer(); ++ slic_stopirq(); ++ misc_deregister(&slic_miscdev); ++} ++ ++int __init slic_init (void) ++{ ++ printk("Surfbox2 SLIC driver\n"); ++ debug(" with debug\n"); ++ ++ is_inuse = 1; ++ ++ // prepare time for handling RING ++ init_timer(&slic_ring_timer); ++ slic_ring_timer.function = slic_do_ring; ++ slic_ring_timer.data = 0; ++ ++ // prepare time for onhook/offhook debounce and flash detection ++ init_timer(&slic_timer); ++ slic_timer.function = slic_do_timer; ++ slic_timer.data = 0; ++ ++ /* Set GPIOs for Dx- and PD-pins as output */ ++ gpio_init(); ++ ++ /* Set initial state */ ++ slic_power_off(); ++ ++ /* Register device */ ++ if (misc_register(&slic_miscdev) >= 0) { ++ slic_minor = slic_miscdev.minor; ++ if (slic_startirq () == 0) { ++ /* Everything fine */ ++ is_inuse = 0; ++ return 0; ++ } ++ /* Error */ ++ misc_deregister(&slic_miscdev); ++ } ++ return 1; ++} ++ ++module_init(slic_init); ++module_exit(slic_cleanup); ++ ++MODULE_AUTHOR("Ingo Salzmann"); ++MODULE_DESCRIPTION("Driver for MTX SLIC"); ++MODULE_LICENSE("GPL"); ++EXPORT_NO_SYMBOLS; +--- linux-org/include/linux/slic.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux/include/linux/slic.h 2006-06-20 13:46:05.321244750 +0200 +@@ -0,0 +1,41 @@ ++/** ++ * @file slic.h ++ * @author Thomas Geffert <geffert@4g-systems.com> ++ * @date Tue Jun 20 13:22:01 2006 ++ * ++ * @brief Some ioctl declarations for the mtx slic driver ++ * ++ * ++ */ ++ ++/* ++ * (c) COPYRIGHT 2006 by 4G Systems GmbH Germany ++ * All rights reserved. ++ */ ++ ++ ++#ifndef SLIC__H__ ++#define SLIC__H__ ++ ++#define SLIC_IOC_MAGIC 0xC1 /// an arbitrary number for identifying slic ioctls ++ ++// ioctl argument: arg == 0 -> power off, arg == 1 -> power on ++#define IOC_SLIC_POWER _IOW(SLIC_IOC_MAGIC, 0x00, unsigned int) ++ ++// ioctl argument: arg == 0 -> ring off, arg == 1 -> ring on ++#define IOC_SLIC_RING _IOW(SLIC_IOC_MAGIC, 0x01, unsigned int) ++ ++// ioctl argument: arg == 0 -> active, arg == 1 -> active reverse ++#define IOC_SLIC_MODE _IOW(SLIC_IOC_MAGIC, 0x02, unsigned int) ++ ++// ioctl argument: set hook-flash time; arg&0xffff is min time in ms, arg>>16 is max time in ms ++// 20 <= min < max <= 1000 ++#define IOC_SLIC_HOOKFLASH _IOW(SLIC_IOC_MAGIC, 0x04, unsigned int) ++ ++// ioctl argument: write arg to slic register ; only available if slic driver compiled with DEBUG ++#define IOC_SLIC_TEST _IOW(SLIC_IOC_MAGIC, 0x03, unsigned int) ++ ++#define SLIC_IOC_MAXNR 0x04 /// max number of supported ioctl calls ++ ++ ++#endif /* SLIC__H__ */ |