From 905eca2d2416856a6e9d18cc123e410cd5336bb5 Mon Sep 17 00:00:00 2001 From: Ian Date: Mon, 4 Dec 2006 03:22:23 +0000 Subject: [PATCH] sync hh.org --- arch/mips/kernel/dma-no-isa.c | 28 ++ drivers/mmc/omap.h | 55 +++ drivers/net/wireless/acx/htcblueangel_acx.c | 111 ++++++ drivers/scsi/aic94xx/aic94xx.h | 2 +- drivers/scsi/aic94xx/aic94xx_dev.c | 2 +- drivers/soc/Kconfig | 5 + drivers/soc/Makefile | 1 + drivers/soc/tsc2200.c | 250 ++++++++++++ drivers/soc/tsc2200_keys.c | 231 ++++++++++++ drivers/soc/tsc2200_ts.c | 230 +++++++++++ include/asm-arm/arch-pxa/htcblueangel-asic.h | 26 +- include/asm-arm/arch-pxa/htcblueangel-gpio.h | 7 +- include/linux/divert.h | 132 +++++++ include/linux/soc/tsc2200.h | 217 +++++++++++ net/atm/ipcommon.c | 63 ++++ net/atm/ipcommon.h | 22 ++ net/core/dv.c | 546 +++++++++++++++++++++++++++ 17 files changed, 1916 insertions(+), 12 deletions(-) create mode 100644 arch/mips/kernel/dma-no-isa.c create mode 100644 drivers/mmc/omap.h create mode 100644 drivers/net/wireless/acx/htcblueangel_acx.c create mode 100644 drivers/soc/tsc2200.c create mode 100644 drivers/soc/tsc2200_keys.c create mode 100644 drivers/soc/tsc2200_ts.c create mode 100644 include/linux/divert.h create mode 100644 include/linux/soc/tsc2200.h create mode 100644 net/atm/ipcommon.c create mode 100644 net/atm/ipcommon.h create mode 100644 net/core/dv.c diff --git a/arch/mips/kernel/dma-no-isa.c b/arch/mips/kernel/dma-no-isa.c new file mode 100644 index 0000000000..6df8b07741 --- /dev/null +++ b/arch/mips/kernel/dma-no-isa.c @@ -0,0 +1,28 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004 by Ralf Baechle + * + * Dummy ISA DMA functions for systems that don't have ISA but share drivers + * with ISA such as legacy free PCI. + */ +#include +#include +#include + +DEFINE_SPINLOCK(dma_spin_lock); + +int request_dma(unsigned int dmanr, const char * device_id) +{ + return -EINVAL; +} + +void free_dma(unsigned int dmanr) +{ +} + +EXPORT_SYMBOL(dma_spin_lock); +EXPORT_SYMBOL(request_dma); +EXPORT_SYMBOL(free_dma); diff --git a/drivers/mmc/omap.h b/drivers/mmc/omap.h new file mode 100644 index 0000000000..c954d355a5 --- /dev/null +++ b/drivers/mmc/omap.h @@ -0,0 +1,55 @@ +#ifndef DRIVERS_MEDIA_MMC_OMAP_H +#define DRIVERS_MEDIA_MMC_OMAP_H + +#define OMAP_MMC_REG_CMD 0x00 +#define OMAP_MMC_REG_ARGL 0x04 +#define OMAP_MMC_REG_ARGH 0x08 +#define OMAP_MMC_REG_CON 0x0c +#define OMAP_MMC_REG_STAT 0x10 +#define OMAP_MMC_REG_IE 0x14 +#define OMAP_MMC_REG_CTO 0x18 +#define OMAP_MMC_REG_DTO 0x1c +#define OMAP_MMC_REG_DATA 0x20 +#define OMAP_MMC_REG_BLEN 0x24 +#define OMAP_MMC_REG_NBLK 0x28 +#define OMAP_MMC_REG_BUF 0x2c +#define OMAP_MMC_REG_SDIO 0x34 +#define OMAP_MMC_REG_REV 0x3c +#define OMAP_MMC_REG_RSP0 0x40 +#define OMAP_MMC_REG_RSP1 0x44 +#define OMAP_MMC_REG_RSP2 0x48 +#define OMAP_MMC_REG_RSP3 0x4c +#define OMAP_MMC_REG_RSP4 0x50 +#define OMAP_MMC_REG_RSP5 0x54 +#define OMAP_MMC_REG_RSP6 0x58 +#define OMAP_MMC_REG_RSP7 0x5c +#define OMAP_MMC_REG_IOSR 0x60 +#define OMAP_MMC_REG_SYSC 0x64 +#define OMAP_MMC_REG_SYSS 0x68 + +#define OMAP_MMC_STAT_CARD_ERR (1 << 14) +#define OMAP_MMC_STAT_CARD_IRQ (1 << 13) +#define OMAP_MMC_STAT_OCR_BUSY (1 << 12) +#define OMAP_MMC_STAT_A_EMPTY (1 << 11) +#define OMAP_MMC_STAT_A_FULL (1 << 10) +#define OMAP_MMC_STAT_CMD_CRC (1 << 8) +#define OMAP_MMC_STAT_CMD_TOUT (1 << 7) +#define OMAP_MMC_STAT_DATA_CRC (1 << 6) +#define OMAP_MMC_STAT_DATA_TOUT (1 << 5) +#define OMAP_MMC_STAT_END_BUSY (1 << 4) +#define OMAP_MMC_STAT_END_OF_DATA (1 << 3) +#define OMAP_MMC_STAT_CARD_BUSY (1 << 2) +#define OMAP_MMC_STAT_END_OF_CMD (1 << 0) + +#define OMAP_MMC_READ(base, reg) __raw_readw((base) + OMAP_MMC_REG_##reg) +#define OMAP_MMC_WRITE(base, reg, val) __raw_writew((val), (base) + OMAP_MMC_REG_##reg) + +/* + * Command types + */ +#define OMAP_MMC_CMDTYPE_BC 0 +#define OMAP_MMC_CMDTYPE_BCR 1 +#define OMAP_MMC_CMDTYPE_AC 2 +#define OMAP_MMC_CMDTYPE_ADTC 3 + +#endif diff --git a/drivers/net/wireless/acx/htcblueangel_acx.c b/drivers/net/wireless/acx/htcblueangel_acx.c new file mode 100644 index 0000000000..40e823cd7c --- /dev/null +++ b/drivers/net/wireless/acx/htcblueangel_acx.c @@ -0,0 +1,111 @@ +/* + * WLAN (TI TNETW1100B) support in the Blueangel. + * + * Copyright (c) 2006 SDG Systems, LLC + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * 28-March-2006 Todd Blumer + */ + + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "acx_hw.h" + +#define WLAN_OFFSET 0x1000000 +#define WLAN_BASE (PXA_CS5_PHYS+WLAN_OFFSET) +//#define WLAN_BASE 0x2c000000 + + +extern struct platform_device blueangel_asic3; + +static int +htcblueangel_wlan_start( void ) +{ + disable_irq(IRQ_GPIO(17)); + asic3_set_gpio_out_b (&blueangel_asic3.dev, GPIOA_WLAN_RESET, 1); + mdelay(5); + asic3_set_gpio_out_a (&blueangel_asic3.dev, GPIOA_WLAN_PWR1, GPIOA_WLAN_PWR1); + mdelay(100); + asic3_set_gpio_out_a (&blueangel_asic3.dev, GPIOA_WLAN_PWR2, GPIOA_WLAN_PWR2); + mdelay(150); + asic3_set_gpio_out_b (&blueangel_asic3.dev, GPIOB_WLAN_PWR3, GPIOB_WLAN_PWR3); + mdelay(100); + asic3_set_gpio_out_b (&blueangel_asic3.dev, GPIOA_WLAN_RESET, 0); + mdelay(100); + enable_irq(IRQ_GPIO(17)); + return 0; +} + +static int +htcblueangel_wlan_stop( void ) +{ + asic3_set_gpio_out_b (&blueangel_asic3.dev, GPIOA_WLAN_RESET, 0); + mdelay(50); + asic3_set_gpio_out_a (&blueangel_asic3.dev, GPIOA_WLAN_PWR1, 0); + asic3_set_gpio_out_a (&blueangel_asic3.dev, GPIOA_WLAN_PWR2, 0); + asic3_set_gpio_out_b (&blueangel_asic3.dev, GPIOB_WLAN_PWR3, 0); + disable_irq(IRQ_GPIO(17)); + return 0; +} + +static struct resource acx_resources[] = { + [0] = { + .start = WLAN_BASE, + .end = WLAN_BASE + 0x20, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_GPIO(17), + .end = IRQ_GPIO(17), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct acx_hardware_data acx_data = { + .start_hw = htcblueangel_wlan_start, + .stop_hw = htcblueangel_wlan_stop, +}; + +static struct platform_device acx_device = { + .name = "acx-mem", + .dev = { + .platform_data = &acx_data, + }, + .num_resources = ARRAY_SIZE( acx_resources ), + .resource = acx_resources, +}; + +static int __init +htcblueangel_wlan_init( void ) +{ + printk( "htcblueangel_wlan_init: acx-mem platform_device_register\n" ); + return platform_device_register( &acx_device ); +} + + +static void __exit +htcblueangel_wlan_exit( void ) +{ + platform_device_unregister( &acx_device ); +} + +module_init( htcblueangel_wlan_init ); +module_exit( htcblueangel_wlan_exit ); + +MODULE_AUTHOR( "Todd Blumer " ); +MODULE_DESCRIPTION( "WLAN driver for HTC Blueangel" ); +MODULE_LICENSE( "GPL" ); + diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h index f7d9d1b57f..71a031df7a 100644 --- a/drivers/scsi/aic94xx/aic94xx.h +++ b/drivers/scsi/aic94xx/aic94xx.h @@ -22,7 +22,7 @@ * along with the aic94xx driver; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * - * $Id: aic94xx.h,v 1.1 2006/12/02 04:15:21 pfalcon Exp $ + * $Id: //depot/aic94xx/aic94xx.h#31 $ */ #ifndef _AIC94XX_H_ diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c index 728aab3c6d..6f8901b748 100644 --- a/drivers/scsi/aic94xx/aic94xx_dev.c +++ b/drivers/scsi/aic94xx/aic94xx_dev.c @@ -22,7 +22,7 @@ * along with the aic94xx driver; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * - * $Id: aic94xx_dev.c,v 1.1 2006/12/02 04:15:21 pfalcon Exp $ + * $Id: //depot/aic94xx/aic94xx_dev.c#21 $ */ #include "aic94xx.h" diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index bc16e5b144..9cd17d3f06 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -79,4 +79,9 @@ config SOC_TSC2101 help Support for TI TSC2101 Touchscreen and Audio Codec +config SOC_TSC2200 + tristate "Support for TI TSC21200 Touchscreen, Battery and Keypad" + help + Support for TI TSC2101 Touchscreen, Battery and Keypad + endmenu diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 7b83d3d8d2..849c1460b5 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_HTC_ASIC3) += asic3_base.o obj-$(CONFIG_IPAQ_MICRO) += micro.o obj-$(CONFIG_SOC_TSC2101) += tsc2101.o +obj-$(CONFIG_SOC_TSC2200) += tsc2200.o tsc2200_keys.o tsc2200_ts.o diff --git a/drivers/soc/tsc2200.c b/drivers/soc/tsc2200.c new file mode 100644 index 0000000000..fa396d23c7 --- /dev/null +++ b/drivers/soc/tsc2200.c @@ -0,0 +1,250 @@ +/* + * TI TSC2200 Common Code + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +unsigned short tsc2200_read(struct device *dev, unsigned short reg) +{ + + struct tsc2200_data *devdata = dev_get_drvdata(dev); + + reg |= TSC2200_REG_READ; + + return devdata->platform->send(reg, 0); +} +EXPORT_SYMBOL(tsc2200_read); + +void tsc2200_write(struct device *dev, unsigned short reg, unsigned short value) +{ + struct tsc2200_data *devdata = dev_get_drvdata(dev); + +// int reg=value; + devdata->platform->send(reg, value); + return; +} +EXPORT_SYMBOL(tsc2200_write); + +unsigned short tsc2200_dav(struct device *dev) +{ + return ( tsc2200_read(dev, TSC2200_CTRLREG_CONFIG) & TSC2200_CTRLREG_CONFIG_DAV ) ? 0 : 1; +} +EXPORT_SYMBOL(tsc2200_dav); + +void tsc2200_lock( struct device *dev ) +{ + unsigned long flags=0; + struct tsc2200_data *devdata = dev_get_drvdata(dev); + spin_lock_irqsave(&devdata->lock, flags); +} +EXPORT_SYMBOL(tsc2200_lock); + +void tsc2200_unlock( struct device *dev ) +{ + unsigned long flags=0; + struct tsc2200_data *devdata = dev_get_drvdata(dev); + spin_unlock_irqrestore(&devdata->lock, flags); +} +EXPORT_SYMBOL(tsc2200_unlock); + +void tsc2200_stop(struct device *dev ) { + printk("TSC2200_ADC: %d\n", tsc2200_read( dev, TSC2200_CTRLREG_ADC ) ); + tsc2200_write( dev, TSC2200_CTRLREG_ADC, 0); + printk("TSC2200_ADC: %d\n", tsc2200_read( dev, TSC2200_CTRLREG_ADC ) ); +} +EXPORT_SYMBOL( tsc2200_stop ); + +void tsc2200_reset( struct device *dev ) +{ + unsigned long flags; + struct tsc2200_data *devdata = dev_get_drvdata(dev); + + spin_lock_irqsave(&devdata->lock, flags); + + tsc2200_write(dev, TSC2200_CTRLREG_RESET, 0xBBFF); + + printk("%s: %X.\n", __FUNCTION__, tsc2200_read(dev, TSC2200_CTRLREG_ADC)); + msleep(100); + printk("%s: %X.\n", __FUNCTION__, tsc2200_read(dev, TSC2200_CTRLREG_ADC)); + + tsc2200_write(dev, TSC2200_CTRLREG_REF, 0x1F); + tsc2200_write(dev, TSC2200_CTRLREG_CONFIG, 0xA); + + spin_unlock_irqrestore(&devdata->lock, flags); +} + +static int tsc2200_suspend(struct device *dev, pm_message_t state) +{ + struct tsc2200_data *devdata = dev_get_drvdata(dev); + if (devdata->platform->exit) { + devdata->platform->exit(); + } + return 0; +} + +static int tsc2200_resume(struct device *dev) +{ + struct tsc2200_data *devdata = dev_get_drvdata(dev); + if (devdata->platform->init) { + devdata->platform->init(); + } +// tsc2200_reset( dev ); + return 0; +} + +static void tsc2200_register_button_driver ( struct device *dev ) { + + struct tsc2200_data *devdata = dev_get_drvdata(dev); + struct tsc2200_platform_info *platform_info = devdata->platform; + + struct platform_device *sdev = kzalloc (sizeof (*sdev), GFP_KERNEL); + struct tsc2200_buttons_data *buttons_devdata = kzalloc (sizeof (*buttons_devdata), GFP_KERNEL); + + + // Prepare some platform info for the tsc2200 buttons + sdev->name = "tsc2200-keys"; + sdev->dev.platform_data = buttons_devdata; + + buttons_devdata->tsc2200_dev = dev; + buttons_devdata->platform_info = platform_info->buttons_info; + + platform_device_register( sdev ); + + devdata->buttons_dev = sdev; + +} + +static void tsc2200_unregister_button_driver (struct device *dev ) { + struct tsc2200_data *devdata = dev_get_drvdata(dev); + //struct tsc2200_platform_info *platform_info = devdata->platform; + + kfree (devdata->buttons_dev->dev.platform_data); + kfree (devdata->buttons_dev); + +} + +static void tsc2200_register_ts_driver ( struct device *dev ) { + + struct tsc2200_data *devdata = dev_get_drvdata(dev); + struct tsc2200_platform_info *platform_info = devdata->platform; + + struct platform_device *sdev = kzalloc (sizeof (*sdev), GFP_KERNEL); + struct tsc2200_ts_data *ts_devdata = kzalloc (sizeof (*ts_devdata), GFP_KERNEL); + + + // Prepare some platform info for the tsc2200 buttons + sdev->name = "tsc2200-ts"; + sdev->dev.platform_data = ts_devdata; + + ts_devdata->tsc2200_dev = dev; + ts_devdata->platform_info = platform_info->touchscreen_info; + + platform_device_register( sdev ); + + devdata->ts_dev = sdev; + +} + +static void tsc2200_unregister_ts_driver (struct device *dev ) { + struct tsc2200_data *devdata = dev_get_drvdata(dev); + //struct tsc2200_platform_info *platform_info = devdata->platform; + + kfree (devdata->ts_dev->dev.platform_data); + kfree (devdata->ts_dev); +} + + +static int __init tsc2200_probe(struct device *dev) +{ + struct tsc2200_data *devdata; + + if (!(devdata = kcalloc(1, sizeof(struct tsc2200_data), GFP_KERNEL))) + return -ENOMEM; + + dev_set_drvdata(dev, devdata); + spin_lock_init(&devdata->lock); + devdata->platform = dev->platform_data; + + if (devdata->platform->init) { + devdata->platform->init(); + } + + udelay(300); +// tsc2200_reset( dev ); + udelay(300); + + printk("%s: SPI: cr0 %08x cr1 %08x sr: %08x it: %08x to: %08x ps: %08x\n", + __FUNCTION__, + SSCR0_P2, SSCR1_P2, SSSR_P2, SSITR_P2, SSTO_P2, SSPSP_P2); + + // Are there keys on this device? + if (devdata->platform->buttons_info) { + tsc2200_register_button_driver( dev ); + } + + // Is there a touchscreen on this device? + if (devdata->platform->touchscreen_info) { + tsc2200_register_ts_driver( dev ); + } + + + return 0; +} + + +static int __exit tsc2200_remove(struct device *dev) +{ + struct tsc2200_data *devdata = dev_get_drvdata(dev); + + // Are there keys on this device? + if (devdata->platform->buttons_info) { + tsc2200_unregister_button_driver( dev ); + } + + // Is there a touchscreen on this device? + if (devdata->platform->touchscreen_info) { + tsc2200_unregister_ts_driver( dev ); + } + + kfree(devdata); + return 0; +} + +static struct platform_driver tsc2200_driver = { + .driver = { + .name = "tsc2200", + .bus = &platform_bus_type, + .probe = tsc2200_probe, + .remove = __exit_p(tsc2200_remove), + .suspend = tsc2200_suspend, + .resume = tsc2200_resume, + } +}; + +static int __init tsc2200_init(void) +{ + return platform_driver_register(&tsc2200_driver); +} + +static void __exit tsc2200_exit(void) +{ + platform_driver_unregister(&tsc2200_driver); +} + +module_init(tsc2200_init); +module_exit(tsc2200_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/tsc2200_keys.c b/drivers/soc/tsc2200_keys.c new file mode 100644 index 0000000000..44dc6f2c97 --- /dev/null +++ b/drivers/soc/tsc2200_keys.c @@ -0,0 +1,231 @@ +/* + * LED interface for Himalaya, the HTC PocketPC. + * + * License: GPL + * + * Author: Luke Kenneth Casson Leighton, Copyright(C) 2004 + * + * Copyright(C) 2004, Luke Kenneth Casson Leighton. + * + * History: + * + * 2004-02-19 Luke Kenneth Casson Leighton created. + * + */ + +#include + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef DEBUG +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + +#define KP_POLL_TIME 30 /* milliseconds */ + +static void +blueangel_kp_check_keys( struct tsc2200_buttons_data *devdata, int new) +{ + struct tsc2200_buttons_platform_info *platform_info = devdata->platform_info; + + int i, pressed, xor; + struct tsc2200_key *k; + + xor = new ^ devdata->keydata; + for (i = 0 ; i < platform_info->num_keys ; i++) { + k = &platform_info->keys[i]; + if ((xor & (1 << k->key_index))) + { + pressed = new & (1 << k->key_index); + input_report_key(devdata->input_dev, k->keycode, pressed); + input_sync(devdata->input_dev); + + if (pressed) + printk("%s pressed\n", k->name); + else + printk("%s released\n", k->name); + + } + } + devdata->keydata = new; +} + +static void +blueangel_kp_getkey( struct tsc2200_buttons_data *devdata ) +{ + struct tsc2200_buttons_platform_info *platform_info = devdata->platform_info; + + int status, keys; + +// tsc2200_lock( devdata->tsc2200_dev ); + status = tsc2200_read( devdata->tsc2200_dev, TSC2200_CTRLREG_KEY); + + if (status & 0x8000) { + keys = tsc2200_read( devdata->tsc2200_dev, TSC2200_DATAREG_KPDATA ); + } else { + keys = 0; + } + +// tsc2200_unlock( devdata->tsc2200_dev ); + + blueangel_kp_check_keys(devdata, keys); + + if (keys) { + mod_timer (&devdata->timer, jiffies + (KP_POLL_TIME * HZ) / 1000); + } else { + enable_irq(platform_info->irq); + } + + return; +} + +static void +tsc2200_buttons_timer(void *data) +{ + struct tsc2200_buttons_data *devdata = data; + + printk("t"); + blueangel_kp_getkey(devdata); +} + +static irqreturn_t tsc2200_buttons_irq(int irq, void *data, struct pt_regs *regs) +{ + struct tsc2200_buttons_data *devdata = data; + struct tsc2200_buttons_platform_info *platform_info = devdata->platform_info; + + printk("i"); + + disable_irq( platform_info->irq ); + + blueangel_kp_getkey(devdata); + + return IRQ_HANDLED; +} + +static int tsc2200_buttons_probe (struct device *dev ) +{ + struct tsc2200_buttons_data *devdata = dev->platform_data; + struct tsc2200_buttons_platform_info *platform_info = devdata->platform_info; + + int i; + struct tsc2200_key *k; + + printk("%x", platform_info->num_keys); + dprintk("%s\n", __FUNCTION__); + + // Allocate input device + devdata->input_dev = input_allocate_device(); + //init_input_dev(devdata->input_dev); + set_bit(EV_KEY, devdata->input_dev->evbit); + + //devdata->input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + + for (i = 0 ; i < platform_info->num_keys ; i++) { + k = &platform_info->keys[i]; + set_bit(k->keycode, devdata->input_dev->keybit); + } + + devdata->input_dev->name = "tsc2200-keys"; + input_register_device(devdata->input_dev); + +// tsc2200_write(devdata->tsc2200_dev, +// TSC2200_CTRLREG_ADC, +// TSC2200_CTRLREG_ADC_AD3 | +// TSC2200_CTRLREG_ADC_AD1 | +// TSC2200_CTRLREG_ADC_AD0 | +// TSC2200_CTRLREG_ADC_RES (TSC2200_CTRLREG_ADC_RES_12BIT) | +// TSC2200_CTRLREG_ADC_AVG (TSC2200_CTRLREG_ADC_16AVG) | +// TSC2200_CTRLREG_ADC_CL (TSC2200_CTRLREG_ADC_CL_4MHZ_10BIT) | +// TSC2200_CTRLREG_ADC_PV (TSC2200_CTRLREG_ADC_PV_1mS) ); + + // Wait for keypress interrupt from the tsc2200 + request_irq( platform_info->irq, tsc2200_buttons_irq, SA_SAMPLE_RANDOM, "tsc2200-keys", devdata); + enable_irq( platform_info->irq ); + set_irq_type( platform_info->irq, IRQT_FALLING); + + // Initialize timer for buttons + init_timer(&devdata->timer); + devdata->timer.function = tsc2200_buttons_timer; + devdata->timer.data = devdata; + + return 0; +} + +static int tsc2200_buttons_suspend( struct device *dev, pm_message_t state) { + struct tsc2200_buttons_data *devdata = dev->platform_data; + struct tsc2200_buttons_platform_info *platform_info = devdata->platform_info; + + disable_irq(platform_info->irq); + + return 0; +} + +static int tsc2200_buttons_resume ( struct device *dev ) { + struct tsc2200_buttons_data *devdata = dev->platform_data; + struct tsc2200_buttons_platform_info *platform_info = devdata->platform_info; + + enable_irq(platform_info->irq); + + return 0; +} + +static int tsc2200_buttons_remove (struct device *dev) +{ + struct tsc2200_buttons_data *devdata = dev->platform_data; + struct tsc2200_buttons_platform_info *platform_info = devdata->platform_info; + + dprintk("%s\n", __FUNCTION__); + input_unregister_device(devdata->input_dev); + + disable_irq( platform_info->irq ); + free_irq( platform_info->irq, NULL); + + del_timer_sync (&devdata->timer); + return 0; +} + +static struct platform_driver tsc2200_buttons = { + .driver = { + .name = "tsc2200-keys", + .probe = tsc2200_buttons_probe, + .remove = tsc2200_buttons_remove, + .suspend = tsc2200_buttons_suspend, + .resume = tsc2200_buttons_resume, + } +}; + +static int tsc2200_buttons_init(void) { + printk("Registering tsc2200 buttons driver\n"); + return platform_driver_register(&tsc2200_buttons); +} + +static void tsc2200_buttons_exit(void) { + printk("Deregistering tsc2200 buttons driver\n"); + platform_driver_unregister(&tsc2200_buttons); +} + + +module_init (tsc2200_buttons_init); +module_exit (tsc2200_buttons_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/tsc2200_ts.c b/drivers/soc/tsc2200_ts.c new file mode 100644 index 0000000000..befe8f1172 --- /dev/null +++ b/drivers/soc/tsc2200_ts.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2003 Joshua Wise + * Copyright (c) 2002,2003 SHARP Corporation + * Copyright (C) 2005 Pawel Kolodziejski + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HAL code based on h5400_asic_io.c, which is + * Copyright (C) 2003 Compaq Computer Corporation. + * + * Author: Joshua Wise + * June 2003 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define SAMPLE_TIMEOUT 20 /* sample every 20ms */ + +//extern struct platform_device h4000_asic3; +//#define asic3 &h4000_asic3.dev + +//#define TS_IRQ_N 16 +//#define TS_IRQ IRQ_GPIO(TS_IRQ_N) +static struct timer_list timer_pen; +static struct input_dev *idev; + +//static spinlock_t ts_lock; +static int irq_disable; +static int touch_pressed; + +static void report_touchpanel(int x, int y, int pressure) +{ + printk("report: x=%04d y=%04d pressure=%04d\n", + x, + y, + pressure + ); + +// input_report_key(idev, BTN_TOUCH, pressure != 0); + input_report_abs(idev, ABS_PRESSURE, pressure); + input_report_abs(idev, ABS_X, x); + input_report_abs(idev, ABS_Y, y); + input_sync(idev); +} + +static void ts_check( struct tsc2200_ts_data *devdata ) { + + struct tsc2200_ts_platform_info *platform_info = devdata->platform_info; + + unsigned short x_pos, y_pos, pressure; + + int touched = tsc2200_read(devdata->tsc2200_dev, TSC2200_CTRLREG_ADC) & TSC2200_CTRLREG_ADC_PSM_TSC2200; + + if ( touched ) { + + tsc2200_write(devdata->tsc2200_dev, + TSC2200_CTRLREG_ADC, + TSC2200_CTRLREG_ADC_AD1 | + TSC2200_CTRLREG_ADC_RES (TSC2200_CTRLREG_ADC_RES_12BIT) | + TSC2200_CTRLREG_ADC_AVG (TSC2200_CTRLREG_ADC_16AVG) | + TSC2200_CTRLREG_ADC_CL (TSC2200_CTRLREG_ADC_CL_4MHZ_10BIT) | + TSC2200_CTRLREG_ADC_PV (TSC2200_CTRLREG_ADC_PV_1mS) ); + + + + x_pos = tsc2200_read(devdata->tsc2200_dev, TSC2200_DATAREG_X); + y_pos = tsc2200_read(devdata->tsc2200_dev, TSC2200_DATAREG_Y); + + printk("%d\n", tsc2200_read(devdata->tsc2200_dev, TSC2200_DATAREG_KPDATA)); + + // pressure = tsc2200_read(devdata->tsc2200_dev, TSC2200_DATAREG_Z2) - + // tsc2200_read(devdata->tsc2200_dev, TSC2200_DATAREG_Z1); + pressure = 0; + report_touchpanel(x_pos, y_pos, 1); + + mod_timer(&timer_pen, jiffies + (SAMPLE_TIMEOUT * HZ) / 1000); + } else { + //tsc2200_stop( devdata->tsc2200_dev ); + report_touchpanel(0, 0, 0); + //printk("touch released irq=%d\n", platform_info->irq); + enable_irq(platform_info->irq); + printk("touch released irq=%d\n", platform_info->irq); + } + +} + +static irqreturn_t tsc2200_stylus(int irq, void* data, struct pt_regs *regs) +{ + struct tsc2200_ts_data *devdata = data; + struct tsc2200_ts_platform_info *platform_info = devdata->platform_info; + + disable_irq( platform_info->irq ); + printk("touch pressed\n"); + ts_check( devdata ); + + return IRQ_HANDLED; +}; + +static void tsc2200_ts_timer(unsigned long data) +{ + struct tsc2200_ts_data *devdata = (void*) data; + //struct tsc2200_ts_platform_info *platform_info = devdata->platform_info; + + ts_check( devdata ); +} + +int tsc2200_ts_probe(struct device *dev) +{ + struct tsc2200_ts_data *devdata = dev->platform_data; + struct tsc2200_ts_platform_info *platform_info = devdata->platform_info; + + printk("tsc2200_ts_probe IRQ: %d\n", platform_info->irq); + + init_timer(&timer_pen); + timer_pen.function = tsc2200_ts_timer; + timer_pen.data = (unsigned long) devdata; + + idev = input_allocate_device(); + if (!idev) + return -ENOMEM; + + + // idev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + set_bit(EV_ABS, idev->evbit); + set_bit(ABS_X, idev->absbit); + set_bit(ABS_Y, idev->absbit); + set_bit(ABS_PRESSURE, idev->absbit); +// set_bit(BTN_TOUCH, idev->keybit); + + input_set_abs_params(idev, ABS_X, 0, 5000, 0, 0); + input_set_abs_params(idev, ABS_Y, 0, 5000, 0, 0); + input_set_abs_params(idev, ABS_PRESSURE, 0, 1, 0 ,0); + + idev->name = "tsc2200-ts"; + idev->phys = "touchscreen/tsc2200-ts"; + + touch_pressed = 0; + irq_disable = 0; + + request_irq(platform_info->irq, tsc2200_stylus, SA_ONESHOT, "tsc2200-ts", devdata); + set_irq_type(platform_info->irq, IRQT_FALLING); + enable_irq(platform_info->irq); + + input_register_device(idev); + + + return 0; +} + +static int tsc2200_ts_remove(struct device *dev) +{ + struct tsc2200_ts_data *devdata = dev->platform_data; + struct tsc2200_ts_platform_info *platform_info = devdata->platform_info; + + printk("tsc2200_ts: Removing...\n"); + del_timer_sync(&timer_pen); + disable_irq(platform_info->irq); + free_irq(platform_info->irq, NULL); + + input_unregister_device(idev); + + printk("tsc2200_ts: done!\n"); + return 0; +} + +#ifdef CONFIG_PM +static int tsc2200_ts_resume(struct device *dev) +{ + return 0; +} +#else +#define h4000_ts_resume NULL +#endif + +static struct platform_driver tsc2200_ts_driver = { + .driver = { + .name = "tsc2200-ts", + .probe = tsc2200_ts_probe, + .remove = tsc2200_ts_remove, + #ifdef CONFIG_PM + .suspend = NULL, + .resume = tsc2200_ts_resume, + #endif + } +}; + +//struct platform_device z = { .name = "h4000_ts", }; + +static int __init tsc2200_ts_init(void) +{ + return platform_driver_register(&tsc2200_ts_driver); +} + +static void __exit tsc2200_ts_exit(void) +{ + platform_driver_unregister(&tsc2200_ts_driver); +} + +module_init(tsc2200_ts_init) +module_exit(tsc2200_ts_exit) + +//EXPORT_SYMBOL(h4000_spi_putget); + +MODULE_AUTHOR("Joshua Wise, Pawel Kolodziejski"); +MODULE_DESCRIPTION("Touchscreen support for the iPAQ h4xxx"); +MODULE_LICENSE("GPL"); diff --git a/include/asm-arm/arch-pxa/htcblueangel-asic.h b/include/asm-arm/arch-pxa/htcblueangel-asic.h index 52febef8b9..6d351579c0 100644 --- a/include/asm-arm/arch-pxa/htcblueangel-asic.h +++ b/include/asm-arm/arch-pxa/htcblueangel-asic.h @@ -26,6 +26,9 @@ #define GPIOA_BT_PWR1_ON (1 << 0) #define GPIOA_MIC_PWR_ON (1 << 7) +#define GPIOA_WLAN_PWR1 (1 << 3) +#define GPIOA_WLAN_RESET (1 << 4) +#define GPIOA_WLAN_PWR2 (1 << 5) #define GPIOB_LCD_PWR1_ON (1 << 3) #define GPIOB_LCD_PWR2_ON (1 << 4) @@ -33,24 +36,29 @@ #define GPIOB_FL_PWR_ON (1 << 6) /* Frontlight power on */ #define GPIOB_PHONEL_PWR_ON (1 << 7) #define GPIOB_VIBRA_PWR_ON (1 << 9) +#define GPIOB_OWM_EN (1 << 10) #define GPIOB_BT_PWR2_ON (1 << 12) +#define GPIOB_WLAN_PWR3 (1 << 13) #define GPIOB_SPK_PWR_ON (1 << 15) #define GPIOC_USB_PULLUP_N (1 << 10) +#define GPIOC_HEADPHONE_IN (1 << 12) #define GPIOC_KEYBL_PWR_ON (1 << 13) #define GPIOC_LCD_PWR4_ON (1 << 14) #define GPIOC_LCD_PWR5_ON (1 << 15) #define GPIOD_QKBD_IRQ 4 -#define GPIOD_AC_CHARGER_N (1 << 3) -#define GPIOD_BUTTON_MENU (1 << 5) -#define GPIOD_BUTTON_OK (1 << 7) -#define GPIOD_BUTTON_WINDOWS (1 << 8) -#define GPIOD_BUTTON_RECORD (1 << 9) -#define GPIOD_BUTTON_CAMERA (1 << 10) -#define GPIOD_BUTTON_VOL_UP (1 << 11) -#define GPIOD_BUTTON_VOL_DOWN (1 << 12) -#define GPIOD_BUTTON_MAIL (1 << 15) +#define GPIOD_AC_CHARGER_N 3 +#define GPIOD_OWM_EN (1 << 10) + +#define BLUEANGEL_WWW_BTN_IRQ (ASIC3_GPIOD_IRQ_BASE+5) +#define BLUEANGEL_OK_BTN_IRQ (ASIC3_GPIOD_IRQ_BASE+7) +#define BLUEANGEL_WINDOWS_BTN_IRQ (ASIC3_GPIOD_IRQ_BASE+8) +#define BLUEANGEL_RECORD_BTN_IRQ (ASIC3_GPIOD_IRQ_BASE+9) +#define BLUEANGEL_CAMERA_BTN_IRQ (ASIC3_GPIOD_IRQ_BASE+10) +#define BLUEANGEL_VOL_UP_BTN_IRQ (ASIC3_GPIOD_IRQ_BASE+11) +#define BLUEANGEL_VOL_DOWN_BTN_IRQ (ASIC3_GPIOD_IRQ_BASE+12) +#define BLUEANGEL_MAIL_BTN_IRQ (ASIC3_GPIOD_IRQ_BASE+15) #define BLUEANGEL_WWW_BTN_IRQ (ASIC3_GPIOD_IRQ_BASE+5) #define BLUEANGEL_OK_BTN_IRQ (ASIC3_GPIOD_IRQ_BASE+7) diff --git a/include/asm-arm/arch-pxa/htcblueangel-gpio.h b/include/asm-arm/arch-pxa/htcblueangel-gpio.h index 355ab39699..eb87cc1db1 100644 --- a/include/asm-arm/arch-pxa/htcblueangel-gpio.h +++ b/include/asm-arm/arch-pxa/htcblueangel-gpio.h @@ -24,7 +24,7 @@ #define GPIO_NR_BLUEANGEL_GSM_ALERTING 6 #define GPIO_NR_BLUEANGEL_USB_DETECT_N 8 #define GPIO_NR_BLUEANGEL_SD_IRQ_N 11 -#define GPIO_NR_BLUEANGEL_TS_IRQ_N 16 +#define GPIO_NR_BLUEANGEL_TSC2200_IRQ_N 16 #define GPIO_NR_BLUEANGEL_BOARDID3 21 #define GPIO_NR_BLUEANGEL_BOARDID0 66 #define GPIO_NR_BLUEANGEL_BOARDID1 67 @@ -32,12 +32,17 @@ #define GPIO_NR_BLUEANGEL_DPRAM_TX_EMPTY_N 69 #define GPIO_NR_BLUEANGEL_BOARDID2 76 +#define GPIO_NR_BLUEANGEL_WLAN_IRQ_N 17 /* Blueangel seem to use GPIO 17 for wireless IRQ */ +//#define GPIO_NR_BLUEANGEL_WLAN_IRQ2 75 + #define IRQ_NR_BLUEANGEL_POWER_BUTTON IRQ_GPIO(GPIO_NR_BLUEANGEL_POWER_BUTTON_N) #define IRQ_NR_BLUEANGEL_TSC2200_KB IRQ_GPIO(GPIO_NR_BLUEANGEL_TSC2200_KB_N) #define IRQ_NR_BLUEANGEL_ASIC3 IRQ_GPIO(GPIO_NR_BLUEANGEL_ASIC3_IRQ) #define IRQ_NR_BLUEANGEL_GSM_ALERTING IRQ_GPIO(GPIO_NR_BLUEANGEL_GSM_ALERTING) #define IRQ_NR_BLUEANGEL_RX_FULL IRQ_GPIO(GPIO_NR_BLUEANGEL_DPRAM_RX_FULL_N) #define IRQ_NR_BLUEANGEL_TX_EMPTY IRQ_GPIO(GPIO_NR_BLUEANGEL_DPRAM_TX_EMPTY_N) +#define IRQ_NR_BLUEANGEL_WLAN IRQ_GPIO(GPIO_NR_BLUEANGEL_WLAN_IRQ_N) +#define IRQ_NR_BLUEANGEL_TSC2200_TS IRQ_GPIO(GPIO_NR_BLUEANGEL_TSC2200_IRQ_N) #define BLUEANGEL_ASIC3_GPIO_PHYS 0x0c000000 #define BLUEANGEL_ASIC3_MMC_PHYS 0x0e000000 diff --git a/include/linux/divert.h b/include/linux/divert.h new file mode 100644 index 0000000000..8fb4e9de68 --- /dev/null +++ b/include/linux/divert.h @@ -0,0 +1,132 @@ +/* + * Frame Diversion, Benoit Locher + * + * Changes: + * 06/09/2000 BL: initial version + * + */ + +#ifndef _LINUX_DIVERT_H +#define _LINUX_DIVERT_H + +#include + +#define MAX_DIVERT_PORTS 8 /* Max number of ports to divert (tcp, udp) */ + +/* Divertable protocols */ +#define DIVERT_PROTO_NONE 0x0000 +#define DIVERT_PROTO_IP 0x0001 +#define DIVERT_PROTO_ICMP 0x0002 +#define DIVERT_PROTO_TCP 0x0004 +#define DIVERT_PROTO_UDP 0x0008 + +/* + * This is an Ethernet Frame Diverter option block + */ +struct divert_blk +{ + int divert; /* are we active */ + unsigned int protos; /* protocols */ + __u16 tcp_dst[MAX_DIVERT_PORTS]; /* specific tcp dst ports to divert */ + __u16 tcp_src[MAX_DIVERT_PORTS]; /* specific tcp src ports to divert */ + __u16 udp_dst[MAX_DIVERT_PORTS]; /* specific udp dst ports to divert */ + __u16 udp_src[MAX_DIVERT_PORTS]; /* specific udp src ports to divert */ +}; + +/* + * Diversion control block, for configuration with the userspace tool + * divert + */ + +typedef union _divert_cf_arg +{ + __s16 int16; + __u16 uint16; + __s32 int32; + __u32 uint32; + __s64 int64; + __u64 uint64; + void __user *ptr; +} divert_cf_arg; + + +struct divert_cf +{ + int cmd; /* Command */ + divert_cf_arg arg1, + arg2, + arg3; + int dev_index; /* device index (eth0=0, etc...) */ +}; + + +/* Diversion commands */ +#define DIVCMD_DIVERT 1 /* ENABLE/DISABLE diversion */ +#define DIVCMD_IP 2 /* ENABLE/DISABLE whold IP diversion */ +#define DIVCMD_TCP 3 /* ENABLE/DISABLE whold TCP diversion */ +#define DIVCMD_TCPDST 4 /* ADD/REMOVE TCP DST port for diversion */ +#define DIVCMD_TCPSRC 5 /* ADD/REMOVE TCP SRC port for diversion */ +#define DIVCMD_UDP 6 /* ENABLE/DISABLE whole UDP diversion */ +#define DIVCMD_UDPDST 7 /* ADD/REMOVE UDP DST port for diversion */ +#define DIVCMD_UDPSRC 8 /* ADD/REMOVE UDP SRC port for diversion */ +#define DIVCMD_ICMP 9 /* ENABLE/DISABLE whole ICMP diversion */ +#define DIVCMD_GETSTATUS 10 /* GET the status of the diverter */ +#define DIVCMD_RESET 11 /* Reset the diverter on the specified dev */ +#define DIVCMD_GETVERSION 12 /* Retrieve the diverter code version (char[32]) */ + +/* General syntax of the commands: + * + * DIVCMD_xxxxxx(arg1, arg2, arg3, dev_index) + * + * SIOCSIFDIVERT: + * DIVCMD_DIVERT(DIVARG1_ENABLE|DIVARG1_DISABLE, , ,ifindex) + * DIVCMD_IP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) + * DIVCMD_TCP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) + * DIVCMD_TCPDST(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) + * DIVCMD_TCPSRC(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) + * DIVCMD_UDP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) + * DIVCMD_UDPDST(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) + * DIVCMD_UDPSRC(DIVARG1_ADD|DIVARG1_REMOVE, port, , ifindex) + * DIVCMD_ICMP(DIVARG1_ENABLE|DIVARG1_DISABLE, , , ifindex) + * DIVCMD_RESET(, , , ifindex) + * + * SIOGIFDIVERT: + * DIVCMD_GETSTATUS(divert_blk, , , ifindex) + * DIVCMD_GETVERSION(string[3]) + */ + + +/* Possible values for arg1 */ +#define DIVARG1_ENABLE 0 /* ENABLE something */ +#define DIVARG1_DISABLE 1 /* DISABLE something */ +#define DIVARG1_ADD 2 /* ADD something */ +#define DIVARG1_REMOVE 3 /* REMOVE something */ + + +#ifdef __KERNEL__ + +/* diverter functions */ +#include + +#ifdef CONFIG_NET_DIVERT +#include + +int alloc_divert_blk(struct net_device *); +void free_divert_blk(struct net_device *); +int divert_ioctl(unsigned int cmd, struct divert_cf __user *arg); +void divert_frame(struct sk_buff *skb); +static inline void handle_diverter(struct sk_buff *skb) +{ + /* if diversion is supported on device, then divert */ + if (skb->dev->divert && skb->dev->divert->divert) + divert_frame(skb); +} + +#else +# define alloc_divert_blk(dev) (0) +# define free_divert_blk(dev) do {} while (0) +# define divert_ioctl(cmd, arg) (-ENOPKG) +# define handle_diverter(skb) do {} while (0) +#endif +#endif +#endif /* _LINUX_DIVERT_H */ diff --git a/include/linux/soc/tsc2200.h b/include/linux/soc/tsc2200.h new file mode 100644 index 0000000000..95a23a717d --- /dev/null +++ b/include/linux/soc/tsc2200.h @@ -0,0 +1,217 @@ +/* + * TI TSC2101 Structure Definitions + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +/* + * see http://focus.ti.com/docs/prod/folders/print/tsc2200.html + * it's a texas instruments TSC 2200 A-D converter with interrupts + * and keypad interrupts and everything. + */ + +#define TSC2200_REG_READ (1<<15) // read register +#define TSC2200_PAGEMASK (0xf<<11) // page of device's memory to be addressed + // see table II +#define TSC2200_PAGE(x) ((x<<11) & TSC2200_PAGEMASK) + +#define TSC2200_REG_ADDRMASK (0x1f<<5) // memory address mask +#define TSC2200_REG_ADDR(x) ((x<<5) & TSC2200_REG_ADDRMASK) + +#define TSC2200_DATAREG_PAGEADDR (0) // datareg page address +#define TSC2200_CTRLREG_PAGEADDR (1) // control reg page address + +#define TSC2200_DATAREG(x) (TSC2200_PAGE(TSC2200_DATAREG_PAGEADDR) | TSC2200_REG_ADDR(x)) + +// these are data registers, in page 0, so they are addressed +// using e.g. TSC2200_REG_ADDR(TSC2200_DATAREG_PAGEADDR) + +#define TSC2200_DATAREG_X TSC2200_DATAREG(0) +#define TSC2200_DATAREG_Y TSC2200_DATAREG(1) +#define TSC2200_DATAREG_Z1 TSC2200_DATAREG(2) +#define TSC2200_DATAREG_Z2 TSC2200_DATAREG(3) +#define TSC2200_DATAREG_KPDATA TSC2200_DATAREG(4) +#define TSC2200_DATAREG_BAT1 TSC2200_DATAREG(5) +#define TSC2200_DATAREG_BAT2 TSC2200_DATAREG(6) +#define TSC2200_DATAREG_AUX1 TSC2200_DATAREG(7) +#define TSC2200_DATAREG_AUX2 TSC2200_DATAREG(8) +#define TSC2200_DATAREG_TEMP1 TSC2200_DATAREG(9) +#define TSC2200_DATAREG_TEMP2 TSC2200_DATAREG(0xa) +#define TSC2200_DATAREG_DAC TSC2200_DATAREG(0xb) +#define TSC2200_DATAREG_ZERO TSC2200_DATAREG(0x10) + +// these are control registers, in page 1, address using +// using e.g. TSC2200_REG_ADDR(TSC2200_CTRLREG_PAGEADDR) + +#define TSC2200_CTRLREG(x) (TSC2200_PAGE(TSC2200_CTRLREG_PAGEADDR) | TSC2200_REG_ADDR(x)) + +#define TSC2200_CTRLREG_ADC TSC2200_CTRLREG(0) +#define TSC2200_CTRLREG_KEY TSC2200_CTRLREG(1) +#define TSC2200_CTRLREG_DACCTL TSC2200_CTRLREG(2) +#define TSC2200_CTRLREG_REF TSC2200_CTRLREG(3) +#define TSC2200_CTRLREG_RESET TSC2200_CTRLREG(4) +#define TSC2200_CTRLREG_CONFIG TSC2200_CTRLREG(5) +#define TSC2200_CTRLREG_KPMASK TSC2200_CTRLREG(0x10) + +// these are relevant for when you access page1's adc register +#define TSC2200_CTRLREG_ADC_PSM_TSC2200 (1<<15) // pen status mode on ctrlreg adc +#define TSC2200_CTRLREG_ADC_STS (1<<14) // stop continuous scanning. +#define TSC2200_CTRLREG_ADC_AD3 (1<<13) // +#define TSC2200_CTRLREG_ADC_AD2 (1<<12) // +#define TSC2200_CTRLREG_ADC_AD1 (1<<11) // +#define TSC2200_CTRLREG_ADC_AD0 (1<<10) // +#define TSC2200_CTRLREG_ADC_RES(x) ((x<<8) & TSC2200_CTRLREG_ADC_RES_MASK ) +#define TSC2200_CTRLREG_ADC_RES_MASK (0x3<<8) +#define TSC2200_CTRLREG_ADC_RES_12BITP (0) // 12-bit ADC resolution (default) +#define TSC2200_CTRLREG_ADC_RES_8BIT (1) // 8-bit ADC resolution +#define TSC2200_CTRLREG_ADC_RES_10BIT (2) // 10-bit ADC resolution +#define TSC2200_CTRLREG_ADC_RES_12BIT (3) // 12-bit ADC resolution + +#define TSC2200_CTRLREG_ADC_AVG(x) ((x<<6) & TSC2200_CTRLREG_ADC_AVG_MASK ) +#define TSC2200_CTRLREG_ADC_AVG_MASK (0x3<<6) +#define TSC2200_CTRLREG_ADC_NOAVG (0) // a-d does no averaging +#define TSC2200_CTRLREG_ADC_4AVG (1) // a-d does averaging of 4 samples +#define TSC2200_CTRLREG_ADC_8AVG (2) // a-d does averaging of 8 samples +#define TSC2200_CTRLREG_ADC_16AVG (3) // a-d does averaging of 16 samples + +#define TSC2200_CTRLREG_ADC_CL(x) ((x<<4) & TSC2200_CTRLREG_ADC_CL_MASK ) +#define TSC2200_CTRLREG_ADC_CL_MASK (0x3<<4) +#define TSC2200_CTRLREG_ADC_CL_8MHZ_8BIT (0) +#define TSC2200_CTRLREG_ADC_CL_4MHZ_10BIT (1) +#define TSC2200_CTRLREG_ADC_CL_2MHZ_12BIT (2) +#define TSC2200_CTRLREG_ADC_CL_1MHZ_12BIT (3) +#define TSC2200_CTRLREG_ADC_CL0 (1<< 4) // + +#define TSC2200_CTRLREG_ADC_PV(x) ((x<<1) & TSC2200_CTRLREG_ADC_PV_MASK ) +#define TSC2200_CTRLREG_ADC_PV_MASK (0x7<<1) +#define TSC2200_CTRLREG_ADC_PV_100mS (0x7) // 100ms panel voltage stabilisation +// .... +#define TSC2200_CTRLREG_ADC_PV_5mS (0x4) // 5ms panel voltage stabilisation +#define TSC2200_CTRLREG_ADC_PV_1mS (0x3) // 1ms panel voltage stabilisation +#define TSC2200_CTRLREG_ADC_PV_500uS (0x2) // 500us panel voltage stabilisation +#define TSC2200_CTRLREG_ADC_PV_100uS (0x1) // 100us panel voltage stabilisation +#define TSC2200_CTRLREG_ADC_PV_0S (0x0) // zero seconds stabilisation + +#define TSC2200_CTRLREG_ADC_x (1<< 0) // don't care + +#define TSC2200_CTRLREG_CONFIG_DAV (1<<6) + +#define TSC2200_CTRLREG_KEY_STC (1<<15) // keypad status +#define TSC2200_CTRLREG_KEY_SCS (1<<14) // keypad scan status + +/* + * public interface. + * + * the tsc2200 driver is timer-interrupt-driven and pen-irq driven. + * + * it only needs to know how to read and write to the NSSP, via + * the send_cmd and recv_cmd functions in the nssp_tsc2200_struct. + * + */ + +//extern struct device_driver tsc2200_device_driver; +//extern struct semaphore tsc2200_sem; +//void tsc2200_reset(void); +//int tsc2200_dev (void); +//unsigned short tsc2200_read(unsigned short reg); +//void tsc2200_write(unsigned short reg, unsigned short val); +//int tsc2200_dav(void); + + + +#include +/* +struct tsc2200_ts_event { + short p; + short x; + short y; +}; +*/ +//struct tsc2200_misc_data { +// short bat; +// short aux1; +// short aux2; +// short temp1; +// short temp2; +//}; + +/* + * Keyboard definitions + */ + + +struct tsc2200_key { + char *name; + int key_index; + int keycode; +}; + +struct tsc2200_buttons_platform_info { + struct tsc2200_key *keys; + int num_keys; + int irq; +}; + +struct tsc2200_buttons_data { + struct tsc2200_buttons_platform_info *platform_info; + struct device *tsc2200_dev; + + struct timer_list timer; + struct input_dev *input_dev; + int keydata; + +}; + +/* + * Touch screen definitions + */ + +struct tsc2200_ts_platform_info { + int irq; +}; + +struct tsc2200_ts_data { + struct tsc2200_ts_platform_info *platform_info; + struct device *tsc2200_dev; + + struct timer_list timer; + struct input_dev *input_dev; +}; + + +struct tsc2200_data { + spinlock_t lock; + struct tsc2200_platform_info *platform; + struct platform_device *buttons_dev; + struct platform_device *ts_dev; +}; + +struct tsc2200_platform_info { + unsigned short (*send)(unsigned short reg, unsigned short value); + void (*init)(void); +// int (*suspend) (void); +// int (*resume) (void); + void (*exit)(void); + + struct tsc2200_buttons_platform_info *buttons_info; + struct tsc2200_ts_platform_info *touchscreen_info; + +}; + +extern void tsc2200_write(struct device *dev, unsigned short regnum, unsigned short value); +extern unsigned short tsc2200_read(struct device *dev, unsigned short reg); +extern unsigned short tsc2200_dav(struct device *dev); + +extern void tsc2200_stop(struct device *dev); +extern void tsc2200_lock(struct device *dev); +extern void tsc2200_unlock(struct device *dev); + + + diff --git a/net/atm/ipcommon.c b/net/atm/ipcommon.c new file mode 100644 index 0000000000..1d3de42fad --- /dev/null +++ b/net/atm/ipcommon.c @@ -0,0 +1,63 @@ +/* net/atm/ipcommon.c - Common items for all ways of doing IP over ATM */ + +/* Written 1996-2000 by Werner Almesberger, EPFL LRC/ICA */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "ipcommon.h" + + +#if 0 +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +/* + * skb_migrate appends the list at "from" to "to", emptying "from" in the + * process. skb_migrate is atomic with respect to all other skb operations on + * "from" and "to". Note that it locks both lists at the same time, so to deal + * with the lock ordering, the locks are taken in address order. + * + * This function should live in skbuff.c or skbuff.h. + */ + + +void skb_migrate(struct sk_buff_head *from, struct sk_buff_head *to) +{ + unsigned long flags; + struct sk_buff *skb_from = (struct sk_buff *) from; + struct sk_buff *skb_to = (struct sk_buff *) to; + struct sk_buff *prev; + + if ((unsigned long) from < (unsigned long) to) { + spin_lock_irqsave(&from->lock, flags); + spin_lock_nested(&to->lock, SINGLE_DEPTH_NESTING); + } else { + spin_lock_irqsave(&to->lock, flags); + spin_lock_nested(&from->lock, SINGLE_DEPTH_NESTING); + } + prev = from->prev; + from->next->prev = to->prev; + prev->next = skb_to; + to->prev->next = from->next; + to->prev = from->prev; + to->qlen += from->qlen; + spin_unlock(&to->lock); + from->prev = skb_from; + from->next = skb_from; + from->qlen = 0; + spin_unlock_irqrestore(&from->lock, flags); +} + + +EXPORT_SYMBOL(skb_migrate); diff --git a/net/atm/ipcommon.h b/net/atm/ipcommon.h new file mode 100644 index 0000000000..d72165f609 --- /dev/null +++ b/net/atm/ipcommon.h @@ -0,0 +1,22 @@ +/* net/atm/ipcommon.h - Common items for all ways of doing IP over ATM */ + +/* Written 1996-2000 by Werner Almesberger, EPFL LRC/ICA */ + + +#ifndef NET_ATM_IPCOMMON_H +#define NET_ATM_IPCOMMON_H + + +#include +#include +#include +#include + +/* + * Appends all skbs from "from" to "to". The operation is atomic with respect + * to all other skb operations on "from" or "to". + */ + +void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to); + +#endif diff --git a/net/core/dv.c b/net/core/dv.c new file mode 100644 index 0000000000..29ee77f159 --- /dev/null +++ b/net/core/dv.c @@ -0,0 +1,546 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Generic frame diversion + * + * Authors: + * Benoit LOCHER: initial integration within the kernel with support for ethernet + * Dave Miller: improvement on the code (correctness, performance and source files) + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char sysctl_divert_version[32]="0.46"; /* Current version */ + +static int __init dv_init(void) +{ + return 0; +} +module_init(dv_init); + +/* + * Allocate a divert_blk for a device. This must be an ethernet nic. + */ +int alloc_divert_blk(struct net_device *dev) +{ + int alloc_size = (sizeof(struct divert_blk) + 3) & ~3; + + dev->divert = NULL; + if (dev->type == ARPHRD_ETHER) { + dev->divert = kzalloc(alloc_size, GFP_KERNEL); + if (dev->divert == NULL) { + printk(KERN_INFO "divert: unable to allocate divert_blk for %s\n", + dev->name); + return -ENOMEM; + } + dev_hold(dev); + } + + return 0; +} + +/* + * Free a divert_blk allocated by the above function, if it was + * allocated on that device. + */ +void free_divert_blk(struct net_device *dev) +{ + if (dev->divert) { + kfree(dev->divert); + dev->divert=NULL; + dev_put(dev); + } +} + +/* + * Adds a tcp/udp (source or dest) port to an array + */ +static int add_port(u16 ports[], u16 port) +{ + int i; + + if (port == 0) + return -EINVAL; + + /* Storing directly in network format for performance, + * thanks Dave :) + */ + port = htons(port); + + for (i = 0; i < MAX_DIVERT_PORTS; i++) { + if (ports[i] == port) + return -EALREADY; + } + + for (i = 0; i < MAX_DIVERT_PORTS; i++) { + if (ports[i] == 0) { + ports[i] = port; + return 0; + } + } + + return -ENOBUFS; +} + +/* + * Removes a port from an array tcp/udp (source or dest) + */ +static int remove_port(u16 ports[], u16 port) +{ + int i; + + if (port == 0) + return -EINVAL; + + /* Storing directly in network format for performance, + * thanks Dave ! + */ + port = htons(port); + + for (i = 0; i < MAX_DIVERT_PORTS; i++) { + if (ports[i] == port) { + ports[i] = 0; + return 0; + } + } + + return -EINVAL; +} + +/* Some basic sanity checks on the arguments passed to divert_ioctl() */ +static int check_args(struct divert_cf *div_cf, struct net_device **dev) +{ + char devname[32]; + int ret; + + if (dev == NULL) + return -EFAULT; + + /* GETVERSION: all other args are unused */ + if (div_cf->cmd == DIVCMD_GETVERSION) + return 0; + + /* Network device index should reasonably be between 0 and 1000 :) */ + if (div_cf->dev_index < 0 || div_cf->dev_index > 1000) + return -EINVAL; + + /* Let's try to find the ifname */ + sprintf(devname, "eth%d", div_cf->dev_index); + *dev = dev_get_by_name(devname); + + /* dev should NOT be null */ + if (*dev == NULL) + return -EINVAL; + + ret = 0; + + /* user issuing the ioctl must be a super one :) */ + if (!capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + goto out; + } + + /* Device must have a divert_blk member NOT null */ + if ((*dev)->divert == NULL) + ret = -EINVAL; +out: + dev_put(*dev); + return ret; +} + +/* + * control function of the diverter + */ +#if 0 +#define DVDBG(a) \ + printk(KERN_DEBUG "divert_ioctl() line %d %s\n", __LINE__, (a)) +#else +#define DVDBG(a) +#endif + +int divert_ioctl(unsigned int cmd, struct divert_cf __user *arg) +{ + struct divert_cf div_cf; + struct divert_blk *div_blk; + struct net_device *dev; + int ret; + + switch (cmd) { + case SIOCGIFDIVERT: + DVDBG("SIOCGIFDIVERT, copy_from_user"); + if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf))) + return -EFAULT; + DVDBG("before check_args"); + ret = check_args(&div_cf, &dev); + if (ret) + return ret; + DVDBG("after checkargs"); + div_blk = dev->divert; + + DVDBG("befre switch()"); + switch (div_cf.cmd) { + case DIVCMD_GETSTATUS: + /* Now, just give the user the raw divert block + * for him to play with :) + */ + if (copy_to_user(div_cf.arg1.ptr, dev->divert, + sizeof(struct divert_blk))) + return -EFAULT; + break; + + case DIVCMD_GETVERSION: + DVDBG("GETVERSION: checking ptr"); + if (div_cf.arg1.ptr == NULL) + return -EINVAL; + DVDBG("GETVERSION: copying data to userland"); + if (copy_to_user(div_cf.arg1.ptr, + sysctl_divert_version, 32)) + return -EFAULT; + DVDBG("GETVERSION: data copied"); + break; + + default: + return -EINVAL; + } + + break; + + case SIOCSIFDIVERT: + if (copy_from_user(&div_cf, arg, sizeof(struct divert_cf))) + return -EFAULT; + + ret = check_args(&div_cf, &dev); + if (ret) + return ret; + + div_blk = dev->divert; + + switch(div_cf.cmd) { + case DIVCMD_RESET: + div_blk->divert = 0; + div_blk->protos = DIVERT_PROTO_NONE; + memset(div_blk->tcp_dst, 0, + MAX_DIVERT_PORTS * sizeof(u16)); + memset(div_blk->tcp_src, 0, + MAX_DIVERT_PORTS * sizeof(u16)); + memset(div_blk->udp_dst, 0, + MAX_DIVERT_PORTS * sizeof(u16)); + memset(div_blk->udp_src, 0, + MAX_DIVERT_PORTS * sizeof(u16)); + return 0; + + case DIVCMD_DIVERT: + switch(div_cf.arg1.int32) { + case DIVARG1_ENABLE: + if (div_blk->divert) + return -EALREADY; + div_blk->divert = 1; + break; + + case DIVARG1_DISABLE: + if (!div_blk->divert) + return -EALREADY; + div_blk->divert = 0; + break; + + default: + return -EINVAL; + } + + break; + + case DIVCMD_IP: + switch(div_cf.arg1.int32) { + case DIVARG1_ENABLE: + if (div_blk->protos & DIVERT_PROTO_IP) + return -EALREADY; + div_blk->protos |= DIVERT_PROTO_IP; + break; + + case DIVARG1_DISABLE: + if (!(div_blk->protos & DIVERT_PROTO_IP)) + return -EALREADY; + div_blk->protos &= ~DIVERT_PROTO_IP; + break; + + default: + return -EINVAL; + } + + break; + + case DIVCMD_TCP: + switch(div_cf.arg1.int32) { + case DIVARG1_ENABLE: + if (div_blk->protos & DIVERT_PROTO_TCP) + return -EALREADY; + div_blk->protos |= DIVERT_PROTO_TCP; + break; + + case DIVARG1_DISABLE: + if (!(div_blk->protos & DIVERT_PROTO_TCP)) + return -EALREADY; + div_blk->protos &= ~DIVERT_PROTO_TCP; + break; + + default: + return -EINVAL; + } + + break; + + case DIVCMD_TCPDST: + switch(div_cf.arg1.int32) { + case DIVARG1_ADD: + return add_port(div_blk->tcp_dst, + div_cf.arg2.uint16); + + case DIVARG1_REMOVE: + return remove_port(div_blk->tcp_dst, + div_cf.arg2.uint16); + + default: + return -EINVAL; + } + + break; + + case DIVCMD_TCPSRC: + switch(div_cf.arg1.int32) { + case DIVARG1_ADD: + return add_port(div_blk->tcp_src, + div_cf.arg2.uint16); + + case DIVARG1_REMOVE: + return remove_port(div_blk->tcp_src, + div_cf.arg2.uint16); + + default: + return -EINVAL; + } + + break; + + case DIVCMD_UDP: + switch(div_cf.arg1.int32) { + case DIVARG1_ENABLE: + if (div_blk->protos & DIVERT_PROTO_UDP) + return -EALREADY; + div_blk->protos |= DIVERT_PROTO_UDP; + break; + + case DIVARG1_DISABLE: + if (!(div_blk->protos & DIVERT_PROTO_UDP)) + return -EALREADY; + div_blk->protos &= ~DIVERT_PROTO_UDP; + break; + + default: + return -EINVAL; + } + + break; + + case DIVCMD_UDPDST: + switch(div_cf.arg1.int32) { + case DIVARG1_ADD: + return add_port(div_blk->udp_dst, + div_cf.arg2.uint16); + + case DIVARG1_REMOVE: + return remove_port(div_blk->udp_dst, + div_cf.arg2.uint16); + + default: + return -EINVAL; + } + + break; + + case DIVCMD_UDPSRC: + switch(div_cf.arg1.int32) { + case DIVARG1_ADD: + return add_port(div_blk->udp_src, + div_cf.arg2.uint16); + + case DIVARG1_REMOVE: + return remove_port(div_blk->udp_src, + div_cf.arg2.uint16); + + default: + return -EINVAL; + } + + break; + + case DIVCMD_ICMP: + switch(div_cf.arg1.int32) { + case DIVARG1_ENABLE: + if (div_blk->protos & DIVERT_PROTO_ICMP) + return -EALREADY; + div_blk->protos |= DIVERT_PROTO_ICMP; + break; + + case DIVARG1_DISABLE: + if (!(div_blk->protos & DIVERT_PROTO_ICMP)) + return -EALREADY; + div_blk->protos &= ~DIVERT_PROTO_ICMP; + break; + + default: + return -EINVAL; + } + + break; + + default: + return -EINVAL; + } + + break; + + default: + return -EINVAL; + } + + return 0; +} + + +/* + * Check if packet should have its dest mac address set to the box itself + * for diversion + */ + +#define ETH_DIVERT_FRAME(skb) \ + memcpy(eth_hdr(skb), skb->dev->dev_addr, ETH_ALEN); \ + skb->pkt_type=PACKET_HOST + +void divert_frame(struct sk_buff *skb) +{ + struct ethhdr *eth = eth_hdr(skb); + struct iphdr *iph; + struct tcphdr *tcph; + struct udphdr *udph; + struct divert_blk *divert = skb->dev->divert; + int i, src, dst; + unsigned char *skb_data_end = skb->data + skb->len; + + /* Packet is already aimed at us, return */ + if (!compare_ether_addr(eth->h_dest, skb->dev->dev_addr)) + return; + + /* proto is not IP, do nothing */ + if (eth->h_proto != htons(ETH_P_IP)) + return; + + /* Divert all IP frames ? */ + if (divert->protos & DIVERT_PROTO_IP) { + ETH_DIVERT_FRAME(skb); + return; + } + + /* Check for possible (maliciously) malformed IP frame (thanks Dave) */ + iph = (struct iphdr *) skb->data; + if (((iph->ihl<<2)+(unsigned char*)(iph)) >= skb_data_end) { + printk(KERN_INFO "divert: malformed IP packet !\n"); + return; + } + + switch (iph->protocol) { + /* Divert all ICMP frames ? */ + case IPPROTO_ICMP: + if (divert->protos & DIVERT_PROTO_ICMP) { + ETH_DIVERT_FRAME(skb); + return; + } + break; + + /* Divert all TCP frames ? */ + case IPPROTO_TCP: + if (divert->protos & DIVERT_PROTO_TCP) { + ETH_DIVERT_FRAME(skb); + return; + } + + /* Check for possible (maliciously) malformed IP + * frame (thanx Dave) + */ + tcph = (struct tcphdr *) + (((unsigned char *)iph) + (iph->ihl<<2)); + if (((unsigned char *)(tcph+1)) >= skb_data_end) { + printk(KERN_INFO "divert: malformed TCP packet !\n"); + return; + } + + /* Divert some tcp dst/src ports only ?*/ + for (i = 0; i < MAX_DIVERT_PORTS; i++) { + dst = divert->tcp_dst[i]; + src = divert->tcp_src[i]; + if ((dst && dst == tcph->dest) || + (src && src == tcph->source)) { + ETH_DIVERT_FRAME(skb); + return; + } + } + break; + + /* Divert all UDP frames ? */ + case IPPROTO_UDP: + if (divert->protos & DIVERT_PROTO_UDP) { + ETH_DIVERT_FRAME(skb); + return; + } + + /* Check for possible (maliciously) malformed IP + * packet (thanks Dave) + */ + udph = (struct udphdr *) + (((unsigned char *)iph) + (iph->ihl<<2)); + if (((unsigned char *)(udph+1)) >= skb_data_end) { + printk(KERN_INFO + "divert: malformed UDP packet !\n"); + return; + } + + /* Divert some udp dst/src ports only ? */ + for (i = 0; i < MAX_DIVERT_PORTS; i++) { + dst = divert->udp_dst[i]; + src = divert->udp_src[i]; + if ((dst && dst == udph->dest) || + (src && src == udph->source)) { + ETH_DIVERT_FRAME(skb); + return; + } + } + break; + } +} -- 2.11.4.GIT