diff options
Diffstat (limited to 'target/linux')
-rw-r--r-- | target/linux/config/Config.in.block | 9 | ||||
-rw-r--r-- | target/linux/config/Config.in.debug | 3 | ||||
-rw-r--r-- | target/linux/config/Config.in.fs | 3 | ||||
-rw-r--r-- | target/linux/config/Config.in.input | 3 | ||||
-rw-r--r-- | target/linux/config/Config.in.kernel | 18 | ||||
-rw-r--r-- | target/linux/config/Config.in.netdevice | 6 | ||||
-rw-r--r-- | target/linux/config/Config.in.usb | 18 | ||||
-rw-r--r-- | target/linux/patches/2.6.39/cris.patch | 7493 |
8 files changed, 42 insertions, 7511 deletions
diff --git a/target/linux/config/Config.in.block b/target/linux/config/Config.in.block index 7e7d6cd9c..78e7b1bd5 100644 --- a/target/linux/config/Config.in.block +++ b/target/linux/config/Config.in.block @@ -274,8 +274,7 @@ config ADK_KPACKAGE_KMOD_BLK_DEV_MD tristate depends on !ADK_KERNEL_BLK_DEV_MD select ADK_KERNEL_MD - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX help config ADK_KERNEL_MD_RAID0 @@ -310,8 +309,7 @@ config ADK_KPACKAGE_KMOD_BLK_DEV_DM prompt "kmod-blk-dev-dm................... Device Mapper support" select ADK_KERNEL_MD depends on !ADK_KERNEL_BLK_DEV_DM - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX tristate help Device-mapper is a low level volume manager. It works by allowing @@ -359,8 +357,7 @@ config ADK_KPACKAGE_KMOD_BLK_DEV_DRBD tristate select ADK_KERNEL_BLK_DEV select ADK_KERNEL_CONNECTOR - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX help DRBD - http://www.drbd.org diff --git a/target/linux/config/Config.in.debug b/target/linux/config/Config.in.debug index 891a00c6e..0aed48de9 100644 --- a/target/linux/config/Config.in.debug +++ b/target/linux/config/Config.in.debug @@ -60,8 +60,7 @@ config ADK_KPACKAGE_KMOD_OPROFILE prompt "kernel support for oprofile" tristate select ADK_KERNEL_PROFILING - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default n help use oprofile package to make use of the kernel support. diff --git a/target/linux/config/Config.in.fs b/target/linux/config/Config.in.fs index ee2adc39f..60b331755 100644 --- a/target/linux/config/Config.in.fs +++ b/target/linux/config/Config.in.fs @@ -190,8 +190,7 @@ config ADK_KPACKAGE_KMOD_XFS_FS tristate select ADK_KERNEL_EXPORTFS depends on !ADK_KERNEL_XFS_FS - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default n help XFS is a high performance journaling filesystem which originated diff --git a/target/linux/config/Config.in.input b/target/linux/config/Config.in.input index 4a18af573..b8566e569 100644 --- a/target/linux/config/Config.in.input +++ b/target/linux/config/Config.in.input @@ -61,8 +61,7 @@ config ADK_KPACKAGE_KMOD_USB_HID select ADK_KERNEL_INPUT select ADK_KERNEL_HID select ADK_PACKAGE_KMOD_USB_CONTROLLER - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX depends on ADK_TARGET_WITH_USB default n diff --git a/target/linux/config/Config.in.kernel b/target/linux/config/Config.in.kernel index 0400d8db6..696f7afc9 100644 --- a/target/linux/config/Config.in.kernel +++ b/target/linux/config/Config.in.kernel @@ -3,21 +3,21 @@ config ADK_KERNEL_EXPERIMENTAL config ADK_KERNEL_ETRAX_MTD_SIZE hex - depends on ADK_TARGET_SYSTEM_FOXBOARD_LX416 || ADK_TARGET_SYSTEM_FOXBOARD_LX832 - default "0x00400000" if ADK_TARGET_SYSTEM_FOXBOARD_LX416 - default "0x00800000" if ADK_TARGET_SYSTEM_FOXBOARD_LX832 + depends on ADK_TARGET_SYSTEM_FOXBOARD_LX + default "0x00400000" if ADK_TARGET_FOXBOARD_MODEL_LX416 + default "0x00800000" if ADK_TARGET_FOXBOARD_MODEL_LX832 config ADK_KERNEL_ETRAX_DRAM_SIZE int - depends on ADK_TARGET_SYSTEM_FOXBOARD_LX416 || ADK_TARGET_SYSTEM_FOXBOARD_LX832 - default "16" if ADK_TARGET_SYSTEM_FOXBOARD_LX416 - default "32" if ADK_TARGET_SYSTEM_FOXBOARD_LX832 + depends on ADK_TARGET_SYSTEM_FOXBOARD_LX + default "16" if ADK_TARGET_FOXBOARD_MODEL_LX416 + default "32" if ADK_TARGET_FOXBOARD_MODEL_LX832 config ADK_KERNEL_ETRAX_DEF_R_SDRAM_TIMING hex - depends on ADK_TARGET_SYSTEM_FOXBOARD_LX416 || ADK_TARGET_SYSTEM_FOXBOARD_LX832 - default "0x80608002" if ADK_TARGET_SYSTEM_FOXBOARD_LX416 - default "0x80008002" if ADK_TARGET_SYSTEM_FOXBOARD_LX832 + depends on ADK_TARGET_SYSTEM_FOXBOARD_LX + default "0x80608002" if ADK_TARGET_FOXBOARD_MODEL_LX416 + default "0x80008002" if ADK_TARGET_FOXBOARD_MODEL_LX832 config ADK_KERNEL_BLK_DEV_INITRD boolean diff --git a/target/linux/config/Config.in.netdevice b/target/linux/config/Config.in.netdevice index 14820b810..1a84f6bcc 100644 --- a/target/linux/config/Config.in.netdevice +++ b/target/linux/config/Config.in.netdevice @@ -244,6 +244,7 @@ config ADK_KPACKAGE_KMOD_R8169 endmenu config ADK_KERNEL_WIRELESS + select ADK_KERNEL_NETDEVICES boolean config ADK_KERNEL_WIRELESS_EXT @@ -373,8 +374,7 @@ config ADK_KPACKAGE_KMOD_RTL8187 prompt "kmod-rtl8187................. Realtek RTL8187/RTL8187B wireless cards" tristate depends on ADK_TARGET_WITH_USB - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default n help Driver for Realtek RTL8187/RTL8187B wireless chips. @@ -389,8 +389,6 @@ config ADK_KPACKAGE_KMOD_P54_USB select ADK_KPACKAGE_KMOD_MAC80211 select ADK_KPACKAGE_KMOD_CRC_CCITT depends on ADK_PACKAGE_KMOD_USB_CONTROLLER - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 default n help Driver for Prism54 USB adaptors. diff --git a/target/linux/config/Config.in.usb b/target/linux/config/Config.in.usb index 2bc8d73db..f16ef7dab 100644 --- a/target/linux/config/Config.in.usb +++ b/target/linux/config/Config.in.usb @@ -30,7 +30,6 @@ config ADK_KPACKAGE_KMOD_USB tristate select ADK_KERNEL_NLS depends on !ADK_KERNEL_USB - #depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D2 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D13 @@ -38,6 +37,7 @@ config ADK_KPACKAGE_KMOD_USB default y if ADK_NATIVE_SYSTEM_IBM_X40 default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG default y if ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 + default y if ADK_TARGET_SYSTEM_FOXBOARD_LX default n help Universal Serial Bus (USB) is a specification for a serial bus @@ -75,8 +75,7 @@ config ADK_KPACKAGE_KMOD_USB_UHCI_HCD depends on ADK_KPACKAGE_KMOD_USB depends on !ADK_KERNEL_USB_UHCI_HCD depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_NATIVE_SYSTEM_IBM_X40 default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG @@ -97,8 +96,7 @@ config ADK_KPACKAGE_KMOD_USB_OHCI_HCD select ADK_PACKAGE_KMOD_USB_CONTROLLER depends on ADK_KPACKAGE_KMOD_USB #depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D2 default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D13 @@ -120,8 +118,7 @@ config ADK_KPACKAGE_KMOD_USB_ISP116X_HCD select ADK_PACKAGE_KMOD_USB_CONTROLLER depends on ADK_KPACKAGE_KMOD_USB depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default n help The ISP1160 and ISP1161 chips are USB host controllers. Enable this @@ -135,8 +132,7 @@ config ADK_KPACKAGE_KMOD_USB_SL811_HCD select ADK_PACKAGE_KMOD_USB_CONTROLLER depends on ADK_KPACKAGE_KMOD_USB depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX default n help The SL811HS is a single-port USB controller that supports either @@ -151,8 +147,7 @@ config ADK_KPACKAGE_KMOD_USB_EHCI_HCD select ADK_PACKAGE_KMOD_USB_CONTROLLER depends on !ADK_KERNEL_USB_EHCI_HCD depends on !ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX832 - depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX416 + depends on !ADK_TARGET_SYSTEM_FOXBOARD_LX depends on ADK_KPACKAGE_KMOD_USB default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX1C default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX2D2 @@ -183,6 +178,7 @@ config ADK_KPACKAGE_KMOD_USB_EHCI_HCD config ADK_PACKAGE_KMOD_USB_CONTROLLER tristate default y if ADK_TARGET_SYSTEM_ACMESYSTEMS_FOXG20 + default y if ADK_TARGET_SYSTEM_FOXBOARD_LX default n config ADK_KPACKAGE_KMOD_USB_ACM diff --git a/target/linux/patches/2.6.39/cris.patch b/target/linux/patches/2.6.39/cris.patch index f58391a5d..3bdc0acb8 100644 --- a/target/linux/patches/2.6.39/cris.patch +++ b/target/linux/patches/2.6.39/cris.patch @@ -1,6 +1,6 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/axisflashmap.c linux-2.6.39/arch/cris/arch-v10/drivers/axisflashmap.c --- linux-2.6.39.orig/arch/cris/arch-v10/drivers/axisflashmap.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/arch-v10/drivers/axisflashmap.c 2011-07-28 16:16:35.633425525 +0200 ++++ linux-2.6.39/arch/cris/arch-v10/drivers/axisflashmap.c 2011-08-22 08:58:55.057980882 +0200 @@ -113,7 +113,7 @@ /* If no partition-table was found, we use this default-set. */ @@ -146,443 +146,9 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/axisflashmap.c linux-2.6. return err; } -diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/axisflashmap.c.orig linux-2.6.39/arch/cris/arch-v10/drivers/axisflashmap.c.orig ---- linux-2.6.39.orig/arch/cris/arch-v10/drivers/axisflashmap.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/cris/arch-v10/drivers/axisflashmap.c.orig 2011-05-19 06:06:34.000000000 +0200 -@@ -0,0 +1,430 @@ -+/* -+ * Physical mapping layer for MTD using the Axis partitiontable format -+ * -+ * Copyright (c) 2001, 2002 Axis Communications AB -+ * -+ * This file is under the GPL. -+ * -+ * First partition is always sector 0 regardless of if we find a partitiontable -+ * or not. In the start of the next sector, there can be a partitiontable that -+ * tells us what other partitions to define. If there isn't, we use a default -+ * partition split defined below. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/slab.h> -+ -+#include <linux/mtd/concat.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/mtdram.h> -+#include <linux/mtd/partitions.h> -+ -+#include <asm/axisflashmap.h> -+#include <asm/mmu.h> -+#include <arch/sv_addr_ag.h> -+ -+#ifdef CONFIG_CRIS_LOW_MAP -+#define FLASH_UNCACHED_ADDR KSEG_8 -+#define FLASH_CACHED_ADDR KSEG_5 -+#else -+#define FLASH_UNCACHED_ADDR KSEG_E -+#define FLASH_CACHED_ADDR KSEG_F -+#endif -+ -+#if CONFIG_ETRAX_FLASH_BUSWIDTH==1 -+#define flash_data __u8 -+#elif CONFIG_ETRAX_FLASH_BUSWIDTH==2 -+#define flash_data __u16 -+#elif CONFIG_ETRAX_FLASH_BUSWIDTH==4 -+#define flash_data __u32 -+#endif -+ -+/* From head.S */ -+extern unsigned long romfs_start, romfs_length, romfs_in_flash; -+ -+/* The master mtd for the entire flash. */ -+struct mtd_info* axisflash_mtd = NULL; -+ -+/* Map driver functions. */ -+ -+static map_word flash_read(struct map_info *map, unsigned long ofs) -+{ -+ map_word tmp; -+ tmp.x[0] = *(flash_data *)(map->map_priv_1 + ofs); -+ return tmp; -+} -+ -+static void flash_copy_from(struct map_info *map, void *to, -+ unsigned long from, ssize_t len) -+{ -+ memcpy(to, (void *)(map->map_priv_1 + from), len); -+} -+ -+static void flash_write(struct map_info *map, map_word d, unsigned long adr) -+{ -+ *(flash_data *)(map->map_priv_1 + adr) = (flash_data)d.x[0]; -+} -+ -+/* -+ * The map for chip select e0. -+ * -+ * We run into tricky coherence situations if we mix cached with uncached -+ * accesses to we only use the uncached version here. -+ * -+ * The size field is the total size where the flash chips may be mapped on the -+ * chip select. MTD probes should find all devices there and it does not matter -+ * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD -+ * probes will ignore them. -+ * -+ * The start address in map_priv_1 is in virtual memory so we cannot use -+ * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start -+ * address of cse0. -+ */ -+static struct map_info map_cse0 = { -+ .name = "cse0", -+ .size = MEM_CSE0_SIZE, -+ .bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH, -+ .read = flash_read, -+ .copy_from = flash_copy_from, -+ .write = flash_write, -+ .map_priv_1 = FLASH_UNCACHED_ADDR -+}; -+ -+/* -+ * The map for chip select e1. -+ * -+ * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong -+ * address, but there isn't. -+ */ -+static struct map_info map_cse1 = { -+ .name = "cse1", -+ .size = MEM_CSE1_SIZE, -+ .bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH, -+ .read = flash_read, -+ .copy_from = flash_copy_from, -+ .write = flash_write, -+ .map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE -+}; -+ -+/* If no partition-table was found, we use this default-set. */ -+#define MAX_PARTITIONS 7 -+#define NUM_DEFAULT_PARTITIONS 3 -+ -+/* -+ * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the -+ * size of one flash block and "filesystem"-partition needs 5 blocks to be able -+ * to use JFFS. -+ */ -+static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { -+ { -+ .name = "boot firmware", -+ .size = CONFIG_ETRAX_PTABLE_SECTOR, -+ .offset = 0 -+ }, -+ { -+ .name = "kernel", -+ .size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR), -+ .offset = CONFIG_ETRAX_PTABLE_SECTOR -+ }, -+ { -+ .name = "filesystem", -+ .size = 5 * CONFIG_ETRAX_PTABLE_SECTOR, -+ .offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR) -+ } -+}; -+ -+/* Initialize the ones normally used. */ -+static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { -+ { -+ .name = "part0", -+ .size = CONFIG_ETRAX_PTABLE_SECTOR, -+ .offset = 0 -+ }, -+ { -+ .name = "part1", -+ .size = 0, -+ .offset = 0 -+ }, -+ { -+ .name = "part2", -+ .size = 0, -+ .offset = 0 -+ }, -+ { -+ .name = "part3", -+ .size = 0, -+ .offset = 0 -+ }, -+ { -+ .name = "part4", -+ .size = 0, -+ .offset = 0 -+ }, -+ { -+ .name = "part5", -+ .size = 0, -+ .offset = 0 -+ }, -+ { -+ .name = "part6", -+ .size = 0, -+ .offset = 0 -+ }, -+}; -+ -+#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE -+/* Main flash device */ -+static struct mtd_partition main_partition = { -+ .name = "main", -+ .size = 0, -+ .offset = 0 -+}; -+#endif -+ -+/* -+ * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash -+ * chips in that order (because the amd_flash-driver is faster). -+ */ -+static struct mtd_info *probe_cs(struct map_info *map_cs) -+{ -+ struct mtd_info *mtd_cs = NULL; -+ -+ printk(KERN_INFO -+ "%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n", -+ map_cs->name, map_cs->size, map_cs->map_priv_1); -+ -+#ifdef CONFIG_MTD_CFI -+ mtd_cs = do_map_probe("cfi_probe", map_cs); -+#endif -+#ifdef CONFIG_MTD_JEDECPROBE -+ if (!mtd_cs) -+ mtd_cs = do_map_probe("jedec_probe", map_cs); -+#endif -+ -+ return mtd_cs; -+} -+ -+/* -+ * Probe each chip select individually for flash chips. If there are chips on -+ * both cse0 and cse1, the mtd_info structs will be concatenated to one struct -+ * so that MTD partitions can cross chip boundries. -+ * -+ * The only known restriction to how you can mount your chips is that each -+ * chip select must hold similar flash chips. But you need external hardware -+ * to do that anyway and you can put totally different chips on cse0 and cse1 -+ * so it isn't really much of a restriction. -+ */ -+static struct mtd_info *flash_probe(void) -+{ -+ struct mtd_info *mtd_cse0; -+ struct mtd_info *mtd_cse1; -+ struct mtd_info *mtd_cse; -+ -+ mtd_cse0 = probe_cs(&map_cse0); -+ mtd_cse1 = probe_cs(&map_cse1); -+ -+ if (!mtd_cse0 && !mtd_cse1) { -+ /* No chip found. */ -+ return NULL; -+ } -+ -+ if (mtd_cse0 && mtd_cse1) { -+ struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 }; -+ -+ /* Since the concatenation layer adds a small overhead we -+ * could try to figure out if the chips in cse0 and cse1 are -+ * identical and reprobe the whole cse0+cse1 window. But since -+ * flash chips are slow, the overhead is relatively small. -+ * So we use the MTD concatenation layer instead of further -+ * complicating the probing procedure. -+ */ -+ mtd_cse = mtd_concat_create(mtds, ARRAY_SIZE(mtds), -+ "cse0+cse1"); -+ if (!mtd_cse) { -+ printk(KERN_ERR "%s and %s: Concatenation failed!\n", -+ map_cse0.name, map_cse1.name); -+ -+ /* The best we can do now is to only use what we found -+ * at cse0. -+ */ -+ mtd_cse = mtd_cse0; -+ map_destroy(mtd_cse1); -+ } -+ } else { -+ mtd_cse = mtd_cse0? mtd_cse0 : mtd_cse1; -+ } -+ -+ return mtd_cse; -+} -+ -+/* -+ * Probe the flash chip(s) and, if it succeeds, read the partition-table -+ * and register the partitions with MTD. -+ */ -+static int __init init_axis_flash(void) -+{ -+ struct mtd_info *mymtd; -+ int err = 0; -+ int pidx = 0; -+ struct partitiontable_head *ptable_head = NULL; -+ struct partitiontable_entry *ptable; -+ int use_default_ptable = 1; /* Until proven otherwise. */ -+ const char pmsg[] = " /dev/flash%d at 0x%08x, size 0x%08x\n"; -+ -+ if (!(mymtd = flash_probe())) { -+ /* There's no reason to use this module if no flash chip can -+ * be identified. Make sure that's understood. -+ */ -+ printk(KERN_INFO "axisflashmap: Found no flash chip.\n"); -+ } else { -+ printk(KERN_INFO "%s: 0x%08x bytes of flash memory.\n", -+ mymtd->name, mymtd->size); -+ axisflash_mtd = mymtd; -+ } -+ -+ if (mymtd) { -+ mymtd->owner = THIS_MODULE; -+ ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + -+ CONFIG_ETRAX_PTABLE_SECTOR + -+ PARTITION_TABLE_OFFSET); -+ } -+ pidx++; /* First partition is always set to the default. */ -+ -+ if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC) -+ && (ptable_head->size < -+ (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + -+ PARTITIONTABLE_END_MARKER_SIZE)) -+ && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + -+ ptable_head->size - -+ PARTITIONTABLE_END_MARKER_SIZE) -+ == PARTITIONTABLE_END_MARKER)) { -+ /* Looks like a start, sane length and end of a -+ * partition table, lets check csum etc. -+ */ -+ int ptable_ok = 0; -+ struct partitiontable_entry *max_addr = -+ (struct partitiontable_entry *) -+ ((unsigned long)ptable_head + sizeof(*ptable_head) + -+ ptable_head->size); -+ unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR; -+ unsigned char *p; -+ unsigned long csum = 0; -+ -+ ptable = (struct partitiontable_entry *) -+ ((unsigned long)ptable_head + sizeof(*ptable_head)); -+ -+ /* Lets be PARANOID, and check the checksum. */ -+ p = (unsigned char*) ptable; -+ -+ while (p <= (unsigned char*)max_addr) { -+ csum += *p++; -+ csum += *p++; -+ csum += *p++; -+ csum += *p++; -+ } -+ ptable_ok = (csum == ptable_head->checksum); -+ -+ /* Read the entries and use/show the info. */ -+ printk(KERN_INFO " Found a%s partition table at 0x%p-0x%p.\n", -+ (ptable_ok ? " valid" : "n invalid"), ptable_head, -+ max_addr); -+ -+ /* We have found a working bootblock. Now read the -+ * partition table. Scan the table. It ends when -+ * there is 0xffffffff, that is, empty flash. -+ */ -+ while (ptable_ok -+ && ptable->offset != 0xffffffff -+ && ptable < max_addr -+ && pidx < MAX_PARTITIONS) { -+ -+ axis_partitions[pidx].offset = offset + ptable->offset; -+ axis_partitions[pidx].size = ptable->size; -+ -+ printk(pmsg, pidx, axis_partitions[pidx].offset, -+ axis_partitions[pidx].size); -+ pidx++; -+ ptable++; -+ } -+ use_default_ptable = !ptable_ok; -+ } -+ -+ if (romfs_in_flash) { -+ /* Add an overlapping device for the root partition (romfs). */ -+ -+ axis_partitions[pidx].name = "romfs"; -+ axis_partitions[pidx].size = romfs_length; -+ axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR; -+ axis_partitions[pidx].mask_flags |= MTD_WRITEABLE; -+ -+ printk(KERN_INFO -+ " Adding readonly flash partition for romfs image:\n"); -+ printk(pmsg, pidx, axis_partitions[pidx].offset, -+ axis_partitions[pidx].size); -+ pidx++; -+ } -+ -+#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE -+ if (mymtd) { -+ main_partition.size = mymtd->size; -+ err = add_mtd_partitions(mymtd, &main_partition, 1); -+ if (err) -+ panic("axisflashmap: Could not initialize " -+ "partition for whole main mtd device!\n"); -+ } -+#endif -+ -+ if (mymtd) { -+ if (use_default_ptable) { -+ printk(KERN_INFO " Using default partition table.\n"); -+ err = add_mtd_partitions(mymtd, axis_default_partitions, -+ NUM_DEFAULT_PARTITIONS); -+ } else { -+ err = add_mtd_partitions(mymtd, axis_partitions, pidx); -+ } -+ -+ if (err) -+ panic("axisflashmap could not add MTD partitions!\n"); -+ } -+ -+ if (!romfs_in_flash) { -+ /* Create an RAM device for the root partition (romfs). */ -+ -+#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0) -+ /* No use trying to boot this kernel from RAM. Panic! */ -+ printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM " -+ "device due to kernel (mis)configuration!\n"); -+ panic("This kernel cannot boot from RAM!\n"); -+#else -+ struct mtd_info *mtd_ram; -+ -+ mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); -+ if (!mtd_ram) -+ panic("axisflashmap couldn't allocate memory for " -+ "mtd_info!\n"); -+ -+ printk(KERN_INFO " Adding RAM partition for romfs image:\n"); -+ printk(pmsg, pidx, (unsigned)romfs_start, -+ (unsigned)romfs_length); -+ -+ err = mtdram_init_device(mtd_ram, -+ (void *)romfs_start, -+ romfs_length, -+ "romfs"); -+ if (err) -+ panic("axisflashmap could not initialize MTD RAM " -+ "device!\n"); -+#endif -+ } -+ return err; -+} -+ -+/* This adds the above to the kernels init-call chain. */ -+module_init(init_axis_flash); -+ -+EXPORT_SYMBOL(axisflash_mtd); diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/ds1302.c linux-2.6.39/arch/cris/arch-v10/drivers/ds1302.c --- linux-2.6.39.orig/arch/cris/arch-v10/drivers/ds1302.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/arch-v10/drivers/ds1302.c 2011-07-28 16:16:35.863415658 +0200 ++++ linux-2.6.39/arch/cris/arch-v10/drivers/ds1302.c 2011-08-22 08:58:55.157980341 +0200 @@ -22,6 +22,7 @@ #include <linux/mutex.h> #include <linux/bcd.h> @@ -617,7 +183,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/ds1302.c linux-2.6.39/arc } diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/gpio.c linux-2.6.39/arch/cris/arch-v10/drivers/gpio.c --- linux-2.6.39.orig/arch/cris/arch-v10/drivers/gpio.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/arch-v10/drivers/gpio.c 2011-07-28 16:16:36.023425394 +0200 ++++ linux-2.6.39/arch/cris/arch-v10/drivers/gpio.c 2011-08-22 08:58:55.227980067 +0200 @@ -20,6 +20,7 @@ #include <linux/poll.h> #include <linux/init.h> @@ -653,7 +219,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/drivers/gpio.c linux-2.6.39/arch/ CRIS_LED_NETWORK_SET(0); diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/lib/hw_settings.S linux-2.6.39/arch/cris/arch-v10/lib/hw_settings.S --- linux-2.6.39.orig/arch/cris/arch-v10/lib/hw_settings.S 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/arch-v10/lib/hw_settings.S 2011-07-28 16:16:36.163758404 +0200 ++++ linux-2.6.39/arch/cris/arch-v10/lib/hw_settings.S 2011-08-22 08:58:55.287980084 +0200 @@ -58,3 +58,5 @@ .dword R_PORT_PB_SET .dword PB_SET_VALUE @@ -662,7 +228,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/lib/hw_settings.S linux-2.6.39/ar + .dword 0xdeadc0de diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/mm/init.c linux-2.6.39/arch/cris/arch-v10/mm/init.c --- linux-2.6.39.orig/arch/cris/arch-v10/mm/init.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/arch-v10/mm/init.c 2011-07-28 16:16:36.313421347 +0200 ++++ linux-2.6.39/arch/cris/arch-v10/mm/init.c 2011-08-22 08:58:55.347981214 +0200 @@ -184,6 +184,9 @@ free_area_init_node(0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0); @@ -675,7 +241,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/arch-v10/mm/init.c linux-2.6.39/arch/cris/ * is called before any driver is initialized. diff -Nur linux-2.6.39.orig/arch/cris/boot/compressed/Makefile linux-2.6.39/arch/cris/boot/compressed/Makefile --- linux-2.6.39.orig/arch/cris/boot/compressed/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/boot/compressed/Makefile 2011-07-28 16:16:36.453421314 +0200 ++++ linux-2.6.39/arch/cris/boot/compressed/Makefile 2011-08-22 08:58:55.427980567 +0200 @@ -18,7 +18,7 @@ OBJECTS-$(CONFIG_ETRAX_ARCH_V32) = $(obj)/head_v32.o OBJECTS-$(CONFIG_ETRAX_ARCH_V10) = $(obj)/head_v10.o @@ -687,7 +253,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/boot/compressed/Makefile linux-2.6.39/arch cmd_image = cat $(obj)/decompress.bin $(obj)/piggy.gz > $@ diff -Nur linux-2.6.39.orig/arch/cris/boot/Makefile linux-2.6.39/arch/cris/boot/Makefile --- linux-2.6.39.orig/arch/cris/boot/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/boot/Makefile 2011-07-28 16:16:36.573671907 +0200 ++++ linux-2.6.39/arch/cris/boot/Makefile 2011-08-22 08:58:55.507980367 +0200 @@ -5,7 +5,7 @@ objcopyflags-$(CONFIG_ETRAX_ARCH_V10) += -R .note -R .comment objcopyflags-$(CONFIG_ETRAX_ARCH_V32) += --remove-section=.bss --remove-section=.note.gnu.build-id @@ -707,7 +273,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/boot/Makefile linux-2.6.39/arch/cris/boot/ @cp $< $@ diff -Nur linux-2.6.39.orig/arch/cris/Kconfig linux-2.6.39/arch/cris/Kconfig --- linux-2.6.39.orig/arch/cris/Kconfig 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/Kconfig 2011-07-28 16:16:36.713417234 +0200 ++++ linux-2.6.39/arch/cris/Kconfig 2011-08-22 08:58:55.587980284 +0200 @@ -168,6 +168,12 @@ help Size of DRAM (decimal in MB) typically 2, 8 or 16. @@ -751,703 +317,9 @@ diff -Nur linux-2.6.39.orig/arch/cris/Kconfig linux-2.6.39/arch/cris/Kconfig source "drivers/usb/Kconfig" source "drivers/uwb/Kconfig" -diff -Nur linux-2.6.39.orig/arch/cris/Kconfig.orig linux-2.6.39/arch/cris/Kconfig.orig ---- linux-2.6.39.orig/arch/cris/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/arch/cris/Kconfig.orig 2011-05-19 06:06:34.000000000 +0200 -@@ -0,0 +1,690 @@ -+config MMU -+ bool -+ default y -+ -+config ZONE_DMA -+ bool -+ default y -+ -+config RWSEM_GENERIC_SPINLOCK -+ bool -+ default y -+ -+config RWSEM_XCHGADD_ALGORITHM -+ bool -+ -+config GENERIC_CMOS_UPDATE -+ def_bool y -+ -+config ARCH_USES_GETTIMEOFFSET -+ def_bool n -+ -+config GENERIC_IOMAP -+ bool -+ default y -+ -+config ARCH_HAS_ILOG2_U32 -+ bool -+ default n -+ -+config ARCH_HAS_ILOG2_U64 -+ bool -+ default n -+ -+config GENERIC_FIND_NEXT_BIT -+ bool -+ default y -+ -+config GENERIC_HWEIGHT -+ bool -+ default y -+ -+config GENERIC_CALIBRATE_DELAY -+ bool -+ default y -+ -+config NO_IOPORT -+ def_bool y -+ -+config FORCE_MAX_ZONEORDER -+ int -+ default 6 -+ -+config CRIS -+ bool -+ default y -+ select HAVE_IDE -+ select HAVE_GENERIC_HARDIRQS -+ select GENERIC_IRQ_SHOW -+ -+config HZ -+ int -+ default 100 -+ -+source "init/Kconfig" -+ -+source "kernel/Kconfig.freezer" -+ -+menu "General setup" -+ -+source "fs/Kconfig.binfmt" -+ -+config ETRAX_CMDLINE -+ string "Kernel command line" -+ default "root=/dev/mtdblock3" -+ help -+ Pass additional commands to the kernel. -+ -+config ETRAX_WATCHDOG -+ bool "Enable ETRAX watchdog" -+ help -+ Enable the built-in watchdog timer support on ETRAX based embedded -+ network computers. -+ -+config ETRAX_WATCHDOG_NICE_DOGGY -+ bool "Disable watchdog during Oops printouts" -+ depends on ETRAX_WATCHDOG -+ help -+ By enabling this you make sure that the watchdog does not bite while -+ printing oopses. Recommended for development systems but not for -+ production releases. -+ -+config ETRAX_FAST_TIMER -+ bool "Enable ETRAX fast timer API" -+ help -+ This options enables the API to a fast timer implementation using -+ timer1 to get sub jiffie resolution timers (primarily one-shot -+ timers). -+ This is needed if CONFIG_ETRAX_SERIAL_FAST_TIMER is enabled. -+ -+config ETRAX_KMALLOCED_MODULES -+ bool "Enable module allocation with kmalloc" -+ help -+ Enable module allocation with kmalloc instead of vmalloc. -+ -+config OOM_REBOOT -+ bool "Enable reboot at out of memory" -+ -+source "kernel/Kconfig.preempt" -+ -+source mm/Kconfig -+ -+endmenu -+ -+menu "Hardware setup" -+ -+choice -+ prompt "Processor type" -+ default ETRAX100LX -+ -+config ETRAX100LX -+ bool "ETRAX-100LX-v1" -+ select ARCH_USES_GETTIMEOFFSET -+ help -+ Support version 1 of the ETRAX 100LX. -+ -+config ETRAX100LX_V2 -+ bool "ETRAX-100LX-v2" -+ select ARCH_USES_GETTIMEOFFSET -+ help -+ Support version 2 of the ETRAX 100LX. -+ -+config SVINTO_SIM -+ bool "ETRAX-100LX-for-xsim-simulator" -+ select ARCH_USES_GETTIMEOFFSET -+ help -+ Support the xsim ETRAX Simulator. -+ -+config ETRAXFS -+ bool "ETRAX-FS-V32" -+ help -+ Support CRIS V32. -+ -+config CRIS_MACH_ARTPEC3 -+ bool "ARTPEC-3" -+ help -+ Support Axis ARTPEC-3. -+ -+endchoice -+ -+config ETRAX_VCS_SIM -+ bool "VCS Simulator" -+ help -+ Setup hardware to be run in the VCS simulator. -+ -+config ETRAX_ARCH_V10 -+ bool -+ default y if ETRAX100LX || ETRAX100LX_V2 -+ default n if !(ETRAX100LX || ETRAX100LX_V2) -+ -+config ETRAX_ARCH_V32 -+ bool -+ default y if (ETRAXFS || CRIS_MACH_ARTPEC3) -+ default n if !(ETRAXFS || CRIS_MACH_ARTPEC3) -+ -+config ETRAX_DRAM_SIZE -+ int "DRAM size (dec, in MB)" -+ default "8" -+ help -+ Size of DRAM (decimal in MB) typically 2, 8 or 16. -+ -+config ETRAX_VMEM_SIZE -+ int "Video memory size (dec, in MB)" -+ depends on ETRAX_ARCH_V32 && !ETRAXFS -+ default 8 if !ETRAXFS -+ help -+ Size of Video accessible memory (decimal, in MB). -+ -+config ETRAX_FLASH_BUSWIDTH -+ int "Buswidth of NOR flash in bytes" -+ default "2" -+ help -+ Width in bytes of the NOR Flash bus (1, 2 or 4). Is usually 2. -+ -+config ETRAX_NANDFLASH_BUSWIDTH -+ int "Buswidth of NAND flash in bytes" -+ default "1" -+ help -+ Width in bytes of the NAND flash (1 or 2). -+ -+config ETRAX_FLASH1_SIZE -+ int "FLASH1 size (dec, in MB. 0 = Unknown)" -+ default "0" -+ -+choice -+ prompt "Product debug-port" -+ default ETRAX_DEBUG_PORT0 -+ -+config ETRAX_DEBUG_PORT0 -+ bool "Serial-0" -+ help -+ Choose a serial port for the ETRAX debug console. Default to -+ port 0. -+ -+config ETRAX_DEBUG_PORT1 -+ bool "Serial-1" -+ help -+ Use serial port 1 for the console. -+ -+config ETRAX_DEBUG_PORT2 -+ bool "Serial-2" -+ help -+ Use serial port 2 for the console. -+ -+config ETRAX_DEBUG_PORT3 -+ bool "Serial-3" -+ help -+ Use serial port 3 for the console. -+ -+config ETRAX_DEBUG_PORT_NULL -+ bool "disabled" -+ help -+ Disable serial-port debugging. -+ -+endchoice -+ -+choice -+ prompt "Kernel GDB port" -+ depends on ETRAX_KGDB -+ default ETRAX_KGDB_PORT0 -+ help -+ Choose a serial port for kernel debugging. NOTE: This port should -+ not be enabled under Drivers for built-in interfaces (as it has its -+ own initialization code) and should not be the same as the debug port. -+ -+config ETRAX_KGDB_PORT0 -+ bool "Serial-0" -+ help -+ Use serial port 0 for kernel debugging. -+ -+config ETRAX_KGDB_PORT1 -+ bool "Serial-1" -+ help -+ Use serial port 1 for kernel debugging. -+ -+config ETRAX_KGDB_PORT2 -+ bool "Serial-2" -+ help -+ Use serial port 2 for kernel debugging. -+ -+config ETRAX_KGDB_PORT3 -+ bool "Serial-3" -+ help -+ Use serial port 3 for kernel debugging. -+ -+endchoice -+ -+source arch/cris/arch-v10/Kconfig -+source arch/cris/arch-v32/Kconfig -+ -+endmenu -+ -+source "net/Kconfig" -+ -+# bring in ETRAX built-in drivers -+menu "Drivers for built-in interfaces" -+source arch/cris/arch-v10/drivers/Kconfig -+source arch/cris/arch-v32/drivers/Kconfig -+ -+config ETRAX_AXISFLASHMAP -+ bool "Axis flash-map support" -+ select MTD -+ select MTD_CFI -+ select MTD_CFI_AMDSTD -+ select MTD_JEDECPROBE if ETRAX_ARCH_V32 -+ select MTD_CHAR -+ select MTD_BLOCK -+ select MTD_PARTITIONS -+ select MTD_COMPLEX_MAPPINGS -+ help -+ This option enables MTD mapping of flash devices. Needed to use -+ flash memories. If unsure, say Y. -+ -+config ETRAX_RTC -+ bool "Real Time Clock support" -+ depends on ETRAX_I2C -+ help -+ Enables drivers for the Real-Time Clock battery-backed chips on -+ some products. The kernel reads the time when booting, and -+ the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a -+ rtc_time struct (see <file:include/asm-cris/rtc.h>) on the /dev/rtc -+ device. You can check the time with cat /proc/rtc, but -+ normal time reading should be done using libc function time and -+ friends. -+ -+choice -+ prompt "RTC chip" -+ depends on ETRAX_RTC -+ default ETRAX_DS1302 -+ -+config ETRAX_DS1302 -+ depends on ETRAX_ARCH_V10 -+ bool "DS1302" -+ help -+ Enables the driver for the DS1302 Real-Time Clock battery-backed -+ chip on some products. -+ -+config ETRAX_PCF8563 -+ bool "PCF8563" -+ help -+ Enables the driver for the PCF8563 Real-Time Clock battery-backed -+ chip on some products. -+ -+endchoice -+ -+config ETRAX_SYNCHRONOUS_SERIAL -+ bool "Synchronous serial-port support" -+ help -+ Select this to enable the synchronous serial port driver. -+ -+config ETRAX_SYNCHRONOUS_SERIAL_PORT0 -+ bool "Synchronous serial port 0 enabled" -+ depends on ETRAX_SYNCHRONOUS_SERIAL -+ help -+ Enabled synchronous serial port 0. -+ -+config ETRAX_SYNCHRONOUS_SERIAL0_DMA -+ bool "Enable DMA on synchronous serial port 0." -+ depends on ETRAX_SYNCHRONOUS_SERIAL_PORT0 -+ help -+ A synchronous serial port can run in manual or DMA mode. -+ Selecting this option will make it run in DMA mode. -+ -+config ETRAX_SYNCHRONOUS_SERIAL_PORT1 -+ bool "Synchronous serial port 1 enabled" -+ depends on ETRAX_SYNCHRONOUS_SERIAL && (ETRAXFS || ETRAX_ARCH_V10) -+ help -+ Enabled synchronous serial port 1. -+ -+config ETRAX_SYNCHRONOUS_SERIAL1_DMA -+ bool "Enable DMA on synchronous serial port 1." -+ depends on ETRAX_SYNCHRONOUS_SERIAL_PORT1 -+ help -+ A synchronous serial port can run in manual or DMA mode. -+ Selecting this option will make it run in DMA mode. -+ -+choice -+ prompt "Network LED behavior" -+ depends on ETRAX_ETHERNET -+ default ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY -+ -+config ETRAX_NETWORK_LED_ON_WHEN_LINK -+ bool "LED_on_when_link" -+ help -+ Selecting LED_on_when_link will light the LED when there is a -+ connection and will flash off when there is activity. -+ -+ Selecting LED_on_when_activity will light the LED only when -+ there is activity. -+ -+ This setting will also affect the behaviour of other activity LEDs -+ e.g. Bluetooth. -+ -+config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY -+ bool "LED_on_when_activity" -+ help -+ Selecting LED_on_when_link will light the LED when there is a -+ connection and will flash off when there is activity. -+ -+ Selecting LED_on_when_activity will light the LED only when -+ there is activity. -+ -+ This setting will also affect the behaviour of other activity LEDs -+ e.g. Bluetooth. -+ -+endchoice -+ -+choice -+ prompt "Ser0 DMA out channel" -+ depends on ETRAX_SERIAL_PORT0 -+ default ETRAX_SERIAL_PORT0_DMA6_OUT if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT0_NO_DMA_OUT if ETRAX_ARCH_V10 -+ -+config ETRAX_SERIAL_PORT0_NO_DMA_OUT -+ bool "Ser0 uses no DMA for output" -+ help -+ Do not use DMA for ser0 output. -+ -+config ETRAX_SERIAL_PORT0_DMA6_OUT -+ bool "Ser0 uses DMA6 for output" -+ depends on ETRAXFS -+ help -+ Enables the DMA6 output channel for ser0 (ttyS0). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT0_DMA0_OUT -+ bool "Ser0 uses DMA0 for output" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA0 output channel for ser0 (ttyS0). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser0 DMA in channel " -+ depends on ETRAX_SERIAL_PORT0 -+ default ETRAX_SERIAL_PORT0_NO_DMA_IN if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT0_DMA7_IN if ETRAX_ARCH_V10 -+ help -+ What DMA channel to use for ser0. -+ -+config ETRAX_SERIAL_PORT0_NO_DMA_IN -+ bool "Ser0 uses no DMA for input" -+ help -+ Do not use DMA for ser0 input. -+ -+config ETRAX_SERIAL_PORT0_DMA7_IN -+ bool "Ser0 uses DMA7 for input" -+ depends on ETRAXFS -+ help -+ Enables the DMA7 input channel for ser0 (ttyS0). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT0_DMA1_IN -+ bool "Ser0 uses DMA1 for input" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA1 input channel for ser0 (ttyS0). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser1 DMA in channel " -+ depends on ETRAX_SERIAL_PORT1 -+ default ETRAX_SERIAL_PORT1_NO_DMA_IN if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT1_DMA9_IN if ETRAX_ARCH_V10 -+ help -+ What DMA channel to use for ser1. -+ -+config ETRAX_SERIAL_PORT1_NO_DMA_IN -+ bool "Ser1 uses no DMA for input" -+ help -+ Do not use DMA for ser1 input. -+ -+config ETRAX_SERIAL_PORT1_DMA5_IN -+ bool "Ser1 uses DMA5 for input" -+ depends on ETRAX_ARCH_V32 -+ help -+ Enables the DMA5 input channel for ser1 (ttyS1). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want this on, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT1_DMA9_IN -+ depends on ETRAX_ARCH_V10 -+ bool "Ser1 uses DMA9 for input" -+ -+endchoice -+ -+ -+choice -+ prompt "Ser1 DMA out channel" -+ depends on ETRAX_SERIAL_PORT1 -+ default ETRAX_SERIAL_PORT1_NO_DMA_OUT if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT1_DMA8_OUT if ETRAX_ARCH_V10 -+ help -+ What DMA channel to use for ser1. -+ -+config ETRAX_SERIAL_PORT1_NO_DMA_OUT -+ bool "Ser1 uses no DMA for output" -+ help -+ Do not use DMA for ser1 output. -+ -+config ETRAX_SERIAL_PORT1_DMA8_OUT -+ depends on ETRAX_ARCH_V10 -+ bool "Ser1 uses DMA8 for output" -+ -+config ETRAX_SERIAL_PORT1_DMA4_OUT -+ depends on ETRAX_ARCH_V32 -+ bool "Ser1 uses DMA4 for output" -+ help -+ Enables the DMA4 output channel for ser1 (ttyS1). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want this on, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser2 DMA out channel" -+ depends on ETRAX_SERIAL_PORT2 -+ default ETRAX_SERIAL_PORT2_NO_DMA_OUT if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT2_DMA2_OUT if ETRAX_ARCH_V10 -+ -+config ETRAX_SERIAL_PORT2_NO_DMA_OUT -+ bool "Ser2 uses no DMA for output" -+ help -+ Do not use DMA for ser2 output. -+ -+config ETRAX_SERIAL_PORT2_DMA2_OUT -+ bool "Ser2 uses DMA2 for output" -+ depends on ETRAXFS || ETRAX_ARCH_V10 -+ help -+ Enables the DMA2 output channel for ser2 (ttyS2). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT2_DMA6_OUT -+ bool "Ser2 uses DMA6 for output" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA6 output channel for ser2 (ttyS2). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser2 DMA in channel" -+ depends on ETRAX_SERIAL_PORT2 -+ default ETRAX_SERIAL_PORT2_NO_DMA_IN if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT2_DMA3_IN if ETRAX_ARCH_V10 -+ help -+ What DMA channel to use for ser2. -+ -+config ETRAX_SERIAL_PORT2_NO_DMA_IN -+ bool "Ser2 uses no DMA for input" -+ help -+ Do not use DMA for ser2 input. -+ -+config ETRAX_SERIAL_PORT2_DMA3_IN -+ bool "Ser2 uses DMA3 for input" -+ depends on ETRAXFS || ETRAX_ARCH_V10 -+ help -+ Enables the DMA3 input channel for ser2 (ttyS2). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT2_DMA7_IN -+ bool "Ser2 uses DMA7 for input" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA7 input channel for ser2 (ttyS2). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser3 DMA in channel" -+ depends on ETRAX_SERIAL_PORT3 -+ default ETRAX_SERIAL_PORT3_NO_DMA_IN if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT3_DMA5_IN if ETRAX_ARCH_V10 -+ help -+ What DMA channel to use for ser3. -+ -+config ETRAX_SERIAL_PORT3_NO_DMA_IN -+ bool "Ser3 uses no DMA for input" -+ help -+ Do not use DMA for ser3 input. -+ -+config ETRAX_SERIAL_PORT3_DMA5_IN -+ depends on ETRAX_ARCH_V10 -+ bool "DMA 5" -+ -+config ETRAX_SERIAL_PORT3_DMA9_IN -+ bool "Ser3 uses DMA9 for input" -+ depends on ETRAXFS -+ help -+ Enables the DMA9 input channel for ser3 (ttyS3). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT3_DMA3_IN -+ bool "Ser3 uses DMA3 for input" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA3 input channel for ser3 (ttyS3). -+ If you do not enable DMA, an interrupt for each character will be -+ used when receiving data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+choice -+ prompt "Ser3 DMA out channel" -+ depends on ETRAX_SERIAL_PORT3 -+ default ETRAX_SERIAL_PORT3_NO_DMA_OUT if ETRAX_ARCH_V32 -+ default ETRAX_SERIAL_PORT3_DMA4_OUT if ETRAX_ARCH_V10 -+ -+config ETRAX_SERIAL_PORT3_NO_DMA_OUT -+ bool "Ser3 uses no DMA for output" -+ help -+ Do not use DMA for ser3 output. -+ -+config ETRAX_SERIAL_PORT3_DMA4_OUT -+ depends on ETRAX_ARCH_V10 -+ bool "DMA 4" -+ -+config ETRAX_SERIAL_PORT3_DMA8_OUT -+ bool "Ser3 uses DMA8 for output" -+ depends on ETRAXFS -+ help -+ Enables the DMA8 output channel for ser3 (ttyS3). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+config ETRAX_SERIAL_PORT3_DMA2_OUT -+ bool "Ser3 uses DMA2 for output" -+ depends on CRIS_MACH_ARTPEC3 -+ help -+ Enables the DMA2 output channel for ser3 (ttyS3). -+ If you do not enable DMA, an interrupt for each character will be -+ used when transmitting data. -+ Normally you want to use DMA, unless you use the DMA channel for -+ something else. -+ -+endchoice -+ -+endmenu -+ -+source "drivers/base/Kconfig" -+ -+# standard linux drivers -+source "drivers/mtd/Kconfig" -+ -+source "drivers/parport/Kconfig" -+ -+source "drivers/pnp/Kconfig" -+ -+source "drivers/block/Kconfig" -+ -+source "drivers/ide/Kconfig" -+ -+source "drivers/net/Kconfig" -+ -+source "drivers/i2c/Kconfig" -+ -+source "drivers/rtc/Kconfig" -+ -+# -+# input before char - char/joystick depends on it. As does USB. -+# -+source "drivers/input/Kconfig" -+ -+source "drivers/char/Kconfig" -+ -+source "fs/Kconfig" -+ -+source "drivers/usb/Kconfig" -+ -+source "drivers/uwb/Kconfig" -+ -+source "drivers/staging/Kconfig" -+ -+source "arch/cris/Kconfig.debug" -+ -+source "security/Kconfig" -+ -+source "crypto/Kconfig" -+ -+source "lib/Kconfig" diff -Nur linux-2.6.39.orig/arch/cris/Makefile linux-2.6.39/arch/cris/Makefile --- linux-2.6.39.orig/arch/cris/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/Makefile 2011-07-28 16:16:36.883415879 +0200 ++++ linux-2.6.39/arch/cris/Makefile 2011-08-22 08:58:55.837980069 +0200 @@ -40,10 +40,10 @@ LD = $(CROSS_COMPILE)ld -mcrislinux @@ -1463,7 +335,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/Makefile linux-2.6.39/arch/cris/Makefile ifdef CONFIG_FRAME_POINTER diff -Nur linux-2.6.39.orig/arch/cris/mm/init.c linux-2.6.39/arch/cris/mm/init.c --- linux-2.6.39.orig/arch/cris/mm/init.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/arch/cris/mm/init.c 2011-07-28 16:16:37.013424379 +0200 ++++ linux-2.6.39/arch/cris/mm/init.c 2011-08-22 08:58:55.897980391 +0200 @@ -16,6 +16,7 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); @@ -1485,7 +357,7 @@ diff -Nur linux-2.6.39.orig/arch/cris/mm/init.c linux-2.6.39/arch/cris/mm/init.c +#endif diff -Nur linux-2.6.39.orig/drivers/net/cris/eth_v10.c linux-2.6.39/drivers/net/cris/eth_v10.c --- linux-2.6.39.orig/drivers/net/cris/eth_v10.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/net/cris/eth_v10.c 2011-07-28 16:16:37.184155914 +0200 ++++ linux-2.6.39/drivers/net/cris/eth_v10.c 2011-08-22 08:58:55.987980420 +0200 @@ -1714,7 +1714,7 @@ static void e100_netpoll(struct net_device* netdev) @@ -1495,1762 +367,9 @@ diff -Nur linux-2.6.39.orig/drivers/net/cris/eth_v10.c linux-2.6.39/drivers/net/ } #endif -diff -Nur linux-2.6.39.orig/drivers/net/cris/eth_v10.c.orig linux-2.6.39/drivers/net/cris/eth_v10.c.orig ---- linux-2.6.39.orig/drivers/net/cris/eth_v10.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/net/cris/eth_v10.c.orig 2011-05-19 06:06:34.000000000 +0200 -@@ -0,0 +1,1749 @@ -+/* -+ * e100net.c: A network driver for the ETRAX 100LX network controller. -+ * -+ * Copyright (c) 1998-2002 Axis Communications AB. -+ * -+ * The outline of this driver comes from skeleton.c. -+ * -+ */ -+ -+ -+#include <linux/module.h> -+ -+#include <linux/kernel.h> -+#include <linux/delay.h> -+#include <linux/types.h> -+#include <linux/fcntl.h> -+#include <linux/interrupt.h> -+#include <linux/ptrace.h> -+#include <linux/ioport.h> -+#include <linux/in.h> -+#include <linux/string.h> -+#include <linux/spinlock.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/bitops.h> -+ -+#include <linux/if.h> -+#include <linux/mii.h> -+#include <linux/netdevice.h> -+#include <linux/etherdevice.h> -+#include <linux/skbuff.h> -+#include <linux/ethtool.h> -+ -+#include <arch/svinto.h>/* DMA and register descriptions */ -+#include <asm/io.h> /* CRIS_LED_* I/O functions */ -+#include <asm/irq.h> -+#include <asm/dma.h> -+#include <asm/system.h> -+#include <asm/ethernet.h> -+#include <asm/cache.h> -+#include <arch/io_interface_mux.h> -+ -+//#define ETHDEBUG -+#define D(x) -+ -+/* -+ * The name of the card. Is used for messages and in the requests for -+ * io regions, irqs and dma channels -+ */ -+ -+static const char* cardname = "ETRAX 100LX built-in ethernet controller"; -+ -+/* A default ethernet address. Highlevel SW will set the real one later */ -+ -+static struct sockaddr default_mac = { -+ 0, -+ { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 } -+}; -+ -+/* Information that need to be kept for each board. */ -+struct net_local { -+ struct mii_if_info mii_if; -+ -+ /* Tx control lock. This protects the transmit buffer ring -+ * state along with the "tx full" state of the driver. This -+ * means all netif_queue flow control actions are protected -+ * by this lock as well. -+ */ -+ spinlock_t lock; -+ -+ spinlock_t led_lock; /* Protect LED state */ -+ spinlock_t transceiver_lock; /* Protect transceiver state. */ -+}; -+ -+typedef struct etrax_eth_descr -+{ -+ etrax_dma_descr descr; -+ struct sk_buff* skb; -+} etrax_eth_descr; -+ -+/* Some transceivers requires special handling */ -+struct transceiver_ops -+{ -+ unsigned int oui; -+ void (*check_speed)(struct net_device* dev); -+ void (*check_duplex)(struct net_device* dev); -+}; -+ -+/* Duplex settings */ -+enum duplex -+{ -+ half, -+ full, -+ autoneg -+}; -+ -+/* Dma descriptors etc. */ -+ -+#define MAX_MEDIA_DATA_SIZE 1522 -+ -+#define MIN_PACKET_LEN 46 -+#define ETHER_HEAD_LEN 14 -+ -+/* -+** MDIO constants. -+*/ -+#define MDIO_START 0x1 -+#define MDIO_READ 0x2 -+#define MDIO_WRITE 0x1 -+#define MDIO_PREAMBLE 0xfffffffful -+ -+/* Broadcom specific */ -+#define MDIO_AUX_CTRL_STATUS_REG 0x18 -+#define MDIO_BC_FULL_DUPLEX_IND 0x1 -+#define MDIO_BC_SPEED 0x2 -+ -+/* TDK specific */ -+#define MDIO_TDK_DIAGNOSTIC_REG 18 -+#define MDIO_TDK_DIAGNOSTIC_RATE 0x400 -+#define MDIO_TDK_DIAGNOSTIC_DPLX 0x800 -+ -+/*Intel LXT972A specific*/ -+#define MDIO_INT_STATUS_REG_2 0x0011 -+#define MDIO_INT_FULL_DUPLEX_IND (1 << 9) -+#define MDIO_INT_SPEED (1 << 14) -+ -+/* Network flash constants */ -+#define NET_FLASH_TIME (HZ/50) /* 20 ms */ -+#define NET_FLASH_PAUSE (HZ/100) /* 10 ms */ -+#define NET_LINK_UP_CHECK_INTERVAL (2*HZ) /* 2 s */ -+#define NET_DUPLEX_CHECK_INTERVAL (2*HZ) /* 2 s */ -+ -+#define NO_NETWORK_ACTIVITY 0 -+#define NETWORK_ACTIVITY 1 -+ -+#define NBR_OF_RX_DESC 32 -+#define NBR_OF_TX_DESC 16 -+ -+/* Large packets are sent directly to upper layers while small packets are */ -+/* copied (to reduce memory waste). The following constant decides the breakpoint */ -+#define RX_COPYBREAK 256 -+ -+/* Due to a chip bug we need to flush the cache when descriptors are returned */ -+/* to the DMA. To decrease performance impact we return descriptors in chunks. */ -+/* The following constant determines the number of descriptors to return. */ -+#define RX_QUEUE_THRESHOLD NBR_OF_RX_DESC/2 -+ -+#define GET_BIT(bit,val) (((val) >> (bit)) & 0x01) -+ -+/* Define some macros to access ETRAX 100 registers */ -+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ -+ IO_FIELD_(reg##_, field##_, val) -+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ -+ IO_STATE_(reg##_, field##_, _##val) -+ -+static etrax_eth_descr *myNextRxDesc; /* Points to the next descriptor to -+ to be processed */ -+static etrax_eth_descr *myLastRxDesc; /* The last processed descriptor */ -+ -+static etrax_eth_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(32))); -+ -+static etrax_eth_descr* myFirstTxDesc; /* First packet not yet sent */ -+static etrax_eth_descr* myLastTxDesc; /* End of send queue */ -+static etrax_eth_descr* myNextTxDesc; /* Next descriptor to use */ -+static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32))); -+ -+static unsigned int network_rec_config_shadow = 0; -+ -+static unsigned int network_tr_ctrl_shadow = 0; -+ -+/* Network speed indication. */ -+static DEFINE_TIMER(speed_timer, NULL, 0, 0); -+static DEFINE_TIMER(clear_led_timer, NULL, 0, 0); -+static int current_speed; /* Speed read from transceiver */ -+static int current_speed_selection; /* Speed selected by user */ -+static unsigned long led_next_time; -+static int led_active; -+static int rx_queue_len; -+ -+/* Duplex */ -+static DEFINE_TIMER(duplex_timer, NULL, 0, 0); -+static int full_duplex; -+static enum duplex current_duplex; -+ -+/* Index to functions, as function prototypes. */ -+ -+static int etrax_ethernet_init(void); -+ -+static int e100_open(struct net_device *dev); -+static int e100_set_mac_address(struct net_device *dev, void *addr); -+static int e100_send_packet(struct sk_buff *skb, struct net_device *dev); -+static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id); -+static irqreturn_t e100nw_interrupt(int irq, void *dev_id); -+static void e100_rx(struct net_device *dev); -+static int e100_close(struct net_device *dev); -+static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -+static int e100_set_config(struct net_device* dev, struct ifmap* map); -+static void e100_tx_timeout(struct net_device *dev); -+static struct net_device_stats *e100_get_stats(struct net_device *dev); -+static void set_multicast_list(struct net_device *dev); -+static void e100_hardware_send_packet(struct net_local* np, char *buf, int length); -+static void update_rx_stats(struct net_device_stats *); -+static void update_tx_stats(struct net_device_stats *); -+static int e100_probe_transceiver(struct net_device* dev); -+ -+static void e100_check_speed(unsigned long priv); -+static void e100_set_speed(struct net_device* dev, unsigned long speed); -+static void e100_check_duplex(unsigned long priv); -+static void e100_set_duplex(struct net_device* dev, enum duplex); -+static void e100_negotiate(struct net_device* dev); -+ -+static int e100_get_mdio_reg(struct net_device *dev, int phy_id, int location); -+static void e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value); -+ -+static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd); -+static void e100_send_mdio_bit(unsigned char bit); -+static unsigned char e100_receive_mdio_bit(void); -+static void e100_reset_transceiver(struct net_device* net); -+ -+static void e100_clear_network_leds(unsigned long dummy); -+static void e100_set_network_leds(int active); -+ -+static const struct ethtool_ops e100_ethtool_ops; -+#if defined(CONFIG_ETRAX_NO_PHY) -+static void dummy_check_speed(struct net_device* dev); -+static void dummy_check_duplex(struct net_device* dev); -+#else -+static void broadcom_check_speed(struct net_device* dev); -+static void broadcom_check_duplex(struct net_device* dev); -+static void tdk_check_speed(struct net_device* dev); -+static void tdk_check_duplex(struct net_device* dev); -+static void intel_check_speed(struct net_device* dev); -+static void intel_check_duplex(struct net_device* dev); -+static void generic_check_speed(struct net_device* dev); -+static void generic_check_duplex(struct net_device* dev); -+#endif -+#ifdef CONFIG_NET_POLL_CONTROLLER -+static void e100_netpoll(struct net_device* dev); -+#endif -+ -+static int autoneg_normal = 1; -+ -+struct transceiver_ops transceivers[] = -+{ -+#if defined(CONFIG_ETRAX_NO_PHY) -+ {0x0000, dummy_check_speed, dummy_check_duplex} /* Dummy */ -+#else -+ {0x1018, broadcom_check_speed, broadcom_check_duplex}, /* Broadcom */ -+ {0xC039, tdk_check_speed, tdk_check_duplex}, /* TDK 2120 */ -+ {0x039C, tdk_check_speed, tdk_check_duplex}, /* TDK 2120C */ -+ {0x04de, intel_check_speed, intel_check_duplex}, /* Intel LXT972A*/ -+ {0x0000, generic_check_speed, generic_check_duplex} /* Generic, must be last */ -+#endif -+}; -+ -+struct transceiver_ops* transceiver = &transceivers[0]; -+ -+static const struct net_device_ops e100_netdev_ops = { -+ .ndo_open = e100_open, -+ .ndo_stop = e100_close, -+ .ndo_start_xmit = e100_send_packet, -+ .ndo_tx_timeout = e100_tx_timeout, -+ .ndo_get_stats = e100_get_stats, -+ .ndo_set_multicast_list = set_multicast_list, -+ .ndo_do_ioctl = e100_ioctl, -+ .ndo_set_mac_address = e100_set_mac_address, -+ .ndo_validate_addr = eth_validate_addr, -+ .ndo_change_mtu = eth_change_mtu, -+ .ndo_set_config = e100_set_config, -+#ifdef CONFIG_NET_POLL_CONTROLLER -+ .ndo_poll_controller = e100_netpoll, -+#endif -+}; -+ -+#define tx_done(dev) (*R_DMA_CH0_CMD == 0) -+ -+/* -+ * Check for a network adaptor of this type, and return '0' if one exists. -+ * If dev->base_addr == 0, probe all likely locations. -+ * If dev->base_addr == 1, always return failure. -+ * If dev->base_addr == 2, allocate space for the device and return success -+ * (detachable devices only). -+ */ -+ -+static int __init -+etrax_ethernet_init(void) -+{ -+ struct net_device *dev; -+ struct net_local* np; -+ int i, err; -+ -+ printk(KERN_INFO -+ "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 1998-2007 Axis Communications AB\n"); -+ -+ if (cris_request_io_interface(if_eth, cardname)) { -+ printk(KERN_CRIT "etrax_ethernet_init failed to get IO interface\n"); -+ return -EBUSY; -+ } -+ -+ dev = alloc_etherdev(sizeof(struct net_local)); -+ if (!dev) -+ return -ENOMEM; -+ -+ np = netdev_priv(dev); -+ -+ /* we do our own locking */ -+ dev->features |= NETIF_F_LLTX; -+ -+ dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ -+ -+ /* now setup our etrax specific stuff */ -+ -+ dev->irq = NETWORK_DMA_RX_IRQ_NBR; /* we really use DMATX as well... */ -+ dev->dma = NETWORK_RX_DMA_NBR; -+ -+ /* fill in our handlers so the network layer can talk to us in the future */ -+ -+ dev->ethtool_ops = &e100_ethtool_ops; -+ dev->netdev_ops = &e100_netdev_ops; -+ -+ spin_lock_init(&np->lock); -+ spin_lock_init(&np->led_lock); -+ spin_lock_init(&np->transceiver_lock); -+ -+ /* Initialise the list of Etrax DMA-descriptors */ -+ -+ /* Initialise receive descriptors */ -+ -+ for (i = 0; i < NBR_OF_RX_DESC; i++) { -+ /* Allocate two extra cachelines to make sure that buffer used -+ * by DMA does not share cacheline with any other data (to -+ * avoid cache bug) -+ */ -+ RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES); -+ if (!RxDescList[i].skb) -+ return -ENOMEM; -+ RxDescList[i].descr.ctrl = 0; -+ RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE; -+ RxDescList[i].descr.next = virt_to_phys(&RxDescList[i + 1]); -+ RxDescList[i].descr.buf = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data)); -+ RxDescList[i].descr.status = 0; -+ RxDescList[i].descr.hw_len = 0; -+ prepare_rx_descriptor(&RxDescList[i].descr); -+ } -+ -+ RxDescList[NBR_OF_RX_DESC - 1].descr.ctrl = d_eol; -+ RxDescList[NBR_OF_RX_DESC - 1].descr.next = virt_to_phys(&RxDescList[0]); -+ rx_queue_len = 0; -+ -+ /* Initialize transmit descriptors */ -+ for (i = 0; i < NBR_OF_TX_DESC; i++) { -+ TxDescList[i].descr.ctrl = 0; -+ TxDescList[i].descr.sw_len = 0; -+ TxDescList[i].descr.next = virt_to_phys(&TxDescList[i + 1].descr); -+ TxDescList[i].descr.buf = 0; -+ TxDescList[i].descr.status = 0; -+ TxDescList[i].descr.hw_len = 0; -+ TxDescList[i].skb = 0; -+ } -+ -+ TxDescList[NBR_OF_TX_DESC - 1].descr.ctrl = d_eol; -+ TxDescList[NBR_OF_TX_DESC - 1].descr.next = virt_to_phys(&TxDescList[0].descr); -+ -+ /* Initialise initial pointers */ -+ -+ myNextRxDesc = &RxDescList[0]; -+ myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; -+ myFirstTxDesc = &TxDescList[0]; -+ myNextTxDesc = &TxDescList[0]; -+ myLastTxDesc = &TxDescList[NBR_OF_TX_DESC - 1]; -+ -+ /* Register device */ -+ err = register_netdev(dev); -+ if (err) { -+ free_netdev(dev); -+ return err; -+ } -+ -+ /* set the default MAC address */ -+ -+ e100_set_mac_address(dev, &default_mac); -+ -+ /* Initialize speed indicator stuff. */ -+ -+ current_speed = 10; -+ current_speed_selection = 0; /* Auto */ -+ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; -+ speed_timer.data = (unsigned long)dev; -+ speed_timer.function = e100_check_speed; -+ -+ clear_led_timer.function = e100_clear_network_leds; -+ clear_led_timer.data = (unsigned long)dev; -+ -+ full_duplex = 0; -+ current_duplex = autoneg; -+ duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL; -+ duplex_timer.data = (unsigned long)dev; -+ duplex_timer.function = e100_check_duplex; -+ -+ /* Initialize mii interface */ -+ np->mii_if.phy_id_mask = 0x1f; -+ np->mii_if.reg_num_mask = 0x1f; -+ np->mii_if.dev = dev; -+ np->mii_if.mdio_read = e100_get_mdio_reg; -+ np->mii_if.mdio_write = e100_set_mdio_reg; -+ -+ /* Initialize group address registers to make sure that no */ -+ /* unwanted addresses are matched */ -+ *R_NETWORK_GA_0 = 0x00000000; -+ *R_NETWORK_GA_1 = 0x00000000; -+ -+ /* Initialize next time the led can flash */ -+ led_next_time = jiffies; -+ return 0; -+} -+ -+/* set MAC address of the interface. called from the core after a -+ * SIOCSIFADDR ioctl, and from the bootup above. -+ */ -+ -+static int -+e100_set_mac_address(struct net_device *dev, void *p) -+{ -+ struct net_local *np = netdev_priv(dev); -+ struct sockaddr *addr = p; -+ -+ spin_lock(&np->lock); /* preemption protection */ -+ -+ /* remember it */ -+ -+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); -+ -+ /* Write it to the hardware. -+ * Note the way the address is wrapped: -+ * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24); -+ * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8); -+ */ -+ -+ *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) | -+ (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24); -+ *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8); -+ *R_NETWORK_SA_2 = 0; -+ -+ /* show it in the log as well */ -+ -+ printk(KERN_INFO "%s: changed MAC to %pM\n", dev->name, dev->dev_addr); -+ -+ spin_unlock(&np->lock); -+ -+ return 0; -+} -+ -+/* -+ * Open/initialize the board. This is called (in the current kernel) -+ * sometime after booting when the 'ifconfig' program is run. -+ * -+ * This routine should set everything up anew at each open, even -+ * registers that "should" only need to be set once at boot, so that -+ * there is non-reboot way to recover if something goes wrong. -+ */ -+ -+static int -+e100_open(struct net_device *dev) -+{ -+ unsigned long flags; -+ -+ /* enable the MDIO output pin */ -+ -+ *R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable); -+ -+ *R_IRQ_MASK0_CLR = -+ IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | -+ IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | -+ IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); -+ -+ /* clear dma0 and 1 eop and descr irq masks */ -+ *R_IRQ_MASK2_CLR = -+ IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); -+ -+ /* Reset and wait for the DMA channels */ -+ -+ RESET_DMA(NETWORK_TX_DMA_NBR); -+ RESET_DMA(NETWORK_RX_DMA_NBR); -+ WAIT_DMA(NETWORK_TX_DMA_NBR); -+ WAIT_DMA(NETWORK_RX_DMA_NBR); -+ -+ /* Initialise the etrax network controller */ -+ -+ /* allocate the irq corresponding to the receiving DMA */ -+ -+ if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, -+ IRQF_SAMPLE_RANDOM, cardname, (void *)dev)) { -+ goto grace_exit0; -+ } -+ -+ /* allocate the irq corresponding to the transmitting DMA */ -+ -+ if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0, -+ cardname, (void *)dev)) { -+ goto grace_exit1; -+ } -+ -+ /* allocate the irq corresponding to the network errors etc */ -+ -+ if (request_irq(NETWORK_STATUS_IRQ_NBR, e100nw_interrupt, 0, -+ cardname, (void *)dev)) { -+ goto grace_exit2; -+ } -+ -+ /* -+ * Always allocate the DMA channels after the IRQ, -+ * and clean up on failure. -+ */ -+ -+ if (cris_request_dma(NETWORK_TX_DMA_NBR, -+ cardname, -+ DMA_VERBOSE_ON_ERROR, -+ dma_eth)) { -+ goto grace_exit3; -+ } -+ -+ if (cris_request_dma(NETWORK_RX_DMA_NBR, -+ cardname, -+ DMA_VERBOSE_ON_ERROR, -+ dma_eth)) { -+ goto grace_exit4; -+ } -+ -+ /* give the HW an idea of what MAC address we want */ -+ -+ *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) | -+ (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24); -+ *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8); -+ *R_NETWORK_SA_2 = 0; -+ -+#if 0 -+ /* use promiscuous mode for testing */ -+ *R_NETWORK_GA_0 = 0xffffffff; -+ *R_NETWORK_GA_1 = 0xffffffff; -+ -+ *R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */ -+#else -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, max_size, size1522); -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, broadcast, receive); -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, ma0, enable); -+ SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+#endif -+ -+ *R_NETWORK_GEN_CONFIG = -+ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | -+ IO_STATE(R_NETWORK_GEN_CONFIG, enable, on); -+ -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, delay, none); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cancel, dont); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cd, enable); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, retry, enable); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, pad, enable); -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, crc, enable); -+ *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow; -+ -+ local_irq_save(flags); -+ -+ /* enable the irq's for ethernet DMA */ -+ -+ *R_IRQ_MASK2_SET = -+ IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) | -+ IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); -+ -+ *R_IRQ_MASK0_SET = -+ IO_STATE(R_IRQ_MASK0_SET, overrun, set) | -+ IO_STATE(R_IRQ_MASK0_SET, underrun, set) | -+ IO_STATE(R_IRQ_MASK0_SET, excessive_col, set); -+ -+ /* make sure the irqs are cleared */ -+ -+ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); -+ *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do); -+ -+ /* make sure the rec and transmit error counters are cleared */ -+ -+ (void)*R_REC_COUNTERS; /* dummy read */ -+ (void)*R_TR_COUNTERS; /* dummy read */ -+ -+ /* start the receiving DMA channel so we can receive packets from now on */ -+ -+ *R_DMA_CH1_FIRST = virt_to_phys(myNextRxDesc); -+ *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start); -+ -+ /* Set up transmit DMA channel so it can be restarted later */ -+ -+ *R_DMA_CH0_FIRST = 0; -+ *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc); -+ netif_start_queue(dev); -+ -+ local_irq_restore(flags); -+ -+ /* Probe for transceiver */ -+ if (e100_probe_transceiver(dev)) -+ goto grace_exit5; -+ -+ /* Start duplex/speed timers */ -+ add_timer(&speed_timer); -+ add_timer(&duplex_timer); -+ -+ /* We are now ready to accept transmit requeusts from -+ * the queueing layer of the networking. -+ */ -+ netif_carrier_on(dev); -+ -+ return 0; -+ -+grace_exit5: -+ cris_free_dma(NETWORK_RX_DMA_NBR, cardname); -+grace_exit4: -+ cris_free_dma(NETWORK_TX_DMA_NBR, cardname); -+grace_exit3: -+ free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); -+grace_exit2: -+ free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); -+grace_exit1: -+ free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev); -+grace_exit0: -+ return -EAGAIN; -+} -+ -+#if defined(CONFIG_ETRAX_NO_PHY) -+static void -+dummy_check_speed(struct net_device* dev) -+{ -+ current_speed = 100; -+} -+#else -+static void -+generic_check_speed(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE); -+ if ((data & ADVERTISE_100FULL) || -+ (data & ADVERTISE_100HALF)) -+ current_speed = 100; -+ else -+ current_speed = 10; -+} -+ -+static void -+tdk_check_speed(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_TDK_DIAGNOSTIC_REG); -+ current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10); -+} -+ -+static void -+broadcom_check_speed(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_AUX_CTRL_STATUS_REG); -+ current_speed = (data & MDIO_BC_SPEED ? 100 : 10); -+} -+ -+static void -+intel_check_speed(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_INT_STATUS_REG_2); -+ current_speed = (data & MDIO_INT_SPEED ? 100 : 10); -+} -+#endif -+static void -+e100_check_speed(unsigned long priv) -+{ -+ struct net_device* dev = (struct net_device*)priv; -+ struct net_local *np = netdev_priv(dev); -+ static int led_initiated = 0; -+ unsigned long data; -+ int old_speed = current_speed; -+ -+ spin_lock(&np->transceiver_lock); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMSR); -+ if (!(data & BMSR_LSTATUS)) { -+ current_speed = 0; -+ } else { -+ transceiver->check_speed(dev); -+ } -+ -+ spin_lock(&np->led_lock); -+ if ((old_speed != current_speed) || !led_initiated) { -+ led_initiated = 1; -+ e100_set_network_leds(NO_NETWORK_ACTIVITY); -+ if (current_speed) -+ netif_carrier_on(dev); -+ else -+ netif_carrier_off(dev); -+ } -+ spin_unlock(&np->led_lock); -+ -+ /* Reinitialize the timer. */ -+ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; -+ add_timer(&speed_timer); -+ -+ spin_unlock(&np->transceiver_lock); -+} -+ -+static void -+e100_negotiate(struct net_device* dev) -+{ -+ struct net_local *np = netdev_priv(dev); -+ unsigned short data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MII_ADVERTISE); -+ -+ /* Discard old speed and duplex settings */ -+ data &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL | -+ ADVERTISE_10HALF | ADVERTISE_10FULL); -+ -+ switch (current_speed_selection) { -+ case 10: -+ if (current_duplex == full) -+ data |= ADVERTISE_10FULL; -+ else if (current_duplex == half) -+ data |= ADVERTISE_10HALF; -+ else -+ data |= ADVERTISE_10HALF | ADVERTISE_10FULL; -+ break; -+ -+ case 100: -+ if (current_duplex == full) -+ data |= ADVERTISE_100FULL; -+ else if (current_duplex == half) -+ data |= ADVERTISE_100HALF; -+ else -+ data |= ADVERTISE_100HALF | ADVERTISE_100FULL; -+ break; -+ -+ case 0: /* Auto */ -+ if (current_duplex == full) -+ data |= ADVERTISE_100FULL | ADVERTISE_10FULL; -+ else if (current_duplex == half) -+ data |= ADVERTISE_100HALF | ADVERTISE_10HALF; -+ else -+ data |= ADVERTISE_10HALF | ADVERTISE_10FULL | -+ ADVERTISE_100HALF | ADVERTISE_100FULL; -+ break; -+ -+ default: /* assume autoneg speed and duplex */ -+ data |= ADVERTISE_10HALF | ADVERTISE_10FULL | -+ ADVERTISE_100HALF | ADVERTISE_100FULL; -+ break; -+ } -+ -+ e100_set_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE, data); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR); -+ if (autoneg_normal) { -+ /* Renegotiate with link partner */ -+ data |= BMCR_ANENABLE | BMCR_ANRESTART; -+ } else { -+ /* Don't negotiate speed or duplex */ -+ data &= ~(BMCR_ANENABLE | BMCR_ANRESTART); -+ -+ /* Set speed and duplex static */ -+ if (current_speed_selection == 10) -+ data &= ~BMCR_SPEED100; -+ else -+ data |= BMCR_SPEED100; -+ -+ if (current_duplex != full) -+ data &= ~BMCR_FULLDPLX; -+ else -+ data |= BMCR_FULLDPLX; -+ } -+ e100_set_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR, data); -+} -+ -+static void -+e100_set_speed(struct net_device* dev, unsigned long speed) -+{ -+ struct net_local *np = netdev_priv(dev); -+ -+ spin_lock(&np->transceiver_lock); -+ if (speed != current_speed_selection) { -+ current_speed_selection = speed; -+ e100_negotiate(dev); -+ } -+ spin_unlock(&np->transceiver_lock); -+} -+ -+static void -+e100_check_duplex(unsigned long priv) -+{ -+ struct net_device *dev = (struct net_device *)priv; -+ struct net_local *np = netdev_priv(dev); -+ int old_duplex; -+ -+ spin_lock(&np->transceiver_lock); -+ old_duplex = full_duplex; -+ transceiver->check_duplex(dev); -+ if (old_duplex != full_duplex) { -+ /* Duplex changed */ -+ SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+ } -+ -+ /* Reinitialize the timer. */ -+ duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL; -+ add_timer(&duplex_timer); -+ np->mii_if.full_duplex = full_duplex; -+ spin_unlock(&np->transceiver_lock); -+} -+#if defined(CONFIG_ETRAX_NO_PHY) -+static void -+dummy_check_duplex(struct net_device* dev) -+{ -+ full_duplex = 1; -+} -+#else -+static void -+generic_check_duplex(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE); -+ if ((data & ADVERTISE_10FULL) || -+ (data & ADVERTISE_100FULL)) -+ full_duplex = 1; -+ else -+ full_duplex = 0; -+} -+ -+static void -+tdk_check_duplex(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_TDK_DIAGNOSTIC_REG); -+ full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0; -+} -+ -+static void -+broadcom_check_duplex(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_AUX_CTRL_STATUS_REG); -+ full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0; -+} -+ -+static void -+intel_check_duplex(struct net_device* dev) -+{ -+ unsigned long data; -+ struct net_local *np = netdev_priv(dev); -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, -+ MDIO_INT_STATUS_REG_2); -+ full_duplex = (data & MDIO_INT_FULL_DUPLEX_IND) ? 1 : 0; -+} -+#endif -+static void -+e100_set_duplex(struct net_device* dev, enum duplex new_duplex) -+{ -+ struct net_local *np = netdev_priv(dev); -+ -+ spin_lock(&np->transceiver_lock); -+ if (new_duplex != current_duplex) { -+ current_duplex = new_duplex; -+ e100_negotiate(dev); -+ } -+ spin_unlock(&np->transceiver_lock); -+} -+ -+static int -+e100_probe_transceiver(struct net_device* dev) -+{ -+ int ret = 0; -+ -+#if !defined(CONFIG_ETRAX_NO_PHY) -+ unsigned int phyid_high; -+ unsigned int phyid_low; -+ unsigned int oui; -+ struct transceiver_ops* ops = NULL; -+ struct net_local *np = netdev_priv(dev); -+ -+ spin_lock(&np->transceiver_lock); -+ -+ /* Probe MDIO physical address */ -+ for (np->mii_if.phy_id = 0; np->mii_if.phy_id <= 31; -+ np->mii_if.phy_id++) { -+ if (e100_get_mdio_reg(dev, -+ np->mii_if.phy_id, MII_BMSR) != 0xffff) -+ break; -+ } -+ if (np->mii_if.phy_id == 32) { -+ ret = -ENODEV; -+ goto out; -+ } -+ -+ /* Get manufacturer */ -+ phyid_high = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_PHYSID1); -+ phyid_low = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_PHYSID2); -+ oui = (phyid_high << 6) | (phyid_low >> 10); -+ -+ for (ops = &transceivers[0]; ops->oui; ops++) { -+ if (ops->oui == oui) -+ break; -+ } -+ transceiver = ops; -+out: -+ spin_unlock(&np->transceiver_lock); -+#endif -+ return ret; -+} -+ -+static int -+e100_get_mdio_reg(struct net_device *dev, int phy_id, int location) -+{ -+ unsigned short cmd; /* Data to be sent on MDIO port */ -+ int data; /* Data read from MDIO */ -+ int bitCounter; -+ -+ /* Start of frame, OP Code, Physical Address, Register Address */ -+ cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (phy_id << 7) | -+ (location << 2); -+ -+ e100_send_mdio_cmd(cmd, 0); -+ -+ data = 0; -+ -+ /* Data... */ -+ for (bitCounter=15; bitCounter>=0 ; bitCounter--) { -+ data |= (e100_receive_mdio_bit() << bitCounter); -+ } -+ -+ return data; -+} -+ -+static void -+e100_set_mdio_reg(struct net_device *dev, int phy_id, int location, int value) -+{ -+ int bitCounter; -+ unsigned short cmd; -+ -+ cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (phy_id << 7) | -+ (location << 2); -+ -+ e100_send_mdio_cmd(cmd, 1); -+ -+ /* Data... */ -+ for (bitCounter=15; bitCounter>=0 ; bitCounter--) { -+ e100_send_mdio_bit(GET_BIT(bitCounter, value)); -+ } -+ -+} -+ -+static void -+e100_send_mdio_cmd(unsigned short cmd, int write_cmd) -+{ -+ int bitCounter; -+ unsigned char data = 0x2; -+ -+ /* Preamble */ -+ for (bitCounter = 31; bitCounter>= 0; bitCounter--) -+ e100_send_mdio_bit(GET_BIT(bitCounter, MDIO_PREAMBLE)); -+ -+ for (bitCounter = 15; bitCounter >= 2; bitCounter--) -+ e100_send_mdio_bit(GET_BIT(bitCounter, cmd)); -+ -+ /* Turnaround */ -+ for (bitCounter = 1; bitCounter >= 0 ; bitCounter--) -+ if (write_cmd) -+ e100_send_mdio_bit(GET_BIT(bitCounter, data)); -+ else -+ e100_receive_mdio_bit(); -+} -+ -+static void -+e100_send_mdio_bit(unsigned char bit) -+{ -+ *R_NETWORK_MGM_CTRL = -+ IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) | -+ IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit); -+ udelay(1); -+ *R_NETWORK_MGM_CTRL = -+ IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) | -+ IO_MASK(R_NETWORK_MGM_CTRL, mdck) | -+ IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit); -+ udelay(1); -+} -+ -+static unsigned char -+e100_receive_mdio_bit() -+{ -+ unsigned char bit; -+ *R_NETWORK_MGM_CTRL = 0; -+ bit = IO_EXTRACT(R_NETWORK_STAT, mdio, *R_NETWORK_STAT); -+ udelay(1); -+ *R_NETWORK_MGM_CTRL = IO_MASK(R_NETWORK_MGM_CTRL, mdck); -+ udelay(1); -+ return bit; -+} -+ -+static void -+e100_reset_transceiver(struct net_device* dev) -+{ -+ struct net_local *np = netdev_priv(dev); -+ unsigned short cmd; -+ unsigned short data; -+ int bitCounter; -+ -+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR); -+ -+ cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (np->mii_if.phy_id << 7) | (MII_BMCR << 2); -+ -+ e100_send_mdio_cmd(cmd, 1); -+ -+ data |= 0x8000; -+ -+ for (bitCounter = 15; bitCounter >= 0 ; bitCounter--) { -+ e100_send_mdio_bit(GET_BIT(bitCounter, data)); -+ } -+} -+ -+/* Called by upper layers if they decide it took too long to complete -+ * sending a packet - we need to reset and stuff. -+ */ -+ -+static void -+e100_tx_timeout(struct net_device *dev) -+{ -+ struct net_local *np = netdev_priv(dev); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&np->lock, flags); -+ -+ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, -+ tx_done(dev) ? "IRQ problem" : "network cable problem"); -+ -+ /* remember we got an error */ -+ -+ dev->stats.tx_errors++; -+ -+ /* reset the TX DMA in case it has hung on something */ -+ -+ RESET_DMA(NETWORK_TX_DMA_NBR); -+ WAIT_DMA(NETWORK_TX_DMA_NBR); -+ -+ /* Reset the transceiver. */ -+ -+ e100_reset_transceiver(dev); -+ -+ /* and get rid of the packets that never got an interrupt */ -+ while (myFirstTxDesc != myNextTxDesc) { -+ dev_kfree_skb(myFirstTxDesc->skb); -+ myFirstTxDesc->skb = 0; -+ myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next); -+ } -+ -+ /* Set up transmit DMA channel so it can be restarted later */ -+ *R_DMA_CH0_FIRST = 0; -+ *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc); -+ -+ /* tell the upper layers we're ok again */ -+ -+ netif_wake_queue(dev); -+ spin_unlock_irqrestore(&np->lock, flags); -+} -+ -+ -+/* This will only be invoked if the driver is _not_ in XOFF state. -+ * What this means is that we need not check it, and that this -+ * invariant will hold if we make sure that the netif_*_queue() -+ * calls are done at the proper times. -+ */ -+ -+static int -+e100_send_packet(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct net_local *np = netdev_priv(dev); -+ unsigned char *buf = skb->data; -+ unsigned long flags; -+ -+#ifdef ETHDEBUG -+ printk("send packet len %d\n", length); -+#endif -+ spin_lock_irqsave(&np->lock, flags); /* protect from tx_interrupt and ourself */ -+ -+ myNextTxDesc->skb = skb; -+ -+ dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ -+ -+ e100_hardware_send_packet(np, buf, skb->len); -+ -+ myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next); -+ -+ /* Stop queue if full */ -+ if (myNextTxDesc == myFirstTxDesc) { -+ netif_stop_queue(dev); -+ } -+ -+ spin_unlock_irqrestore(&np->lock, flags); -+ -+ return NETDEV_TX_OK; -+} -+ -+/* -+ * The typical workload of the driver: -+ * Handle the network interface interrupts. -+ */ -+ -+static irqreturn_t -+e100rxtx_interrupt(int irq, void *dev_id) -+{ -+ struct net_device *dev = (struct net_device *)dev_id; -+ struct net_local *np = netdev_priv(dev); -+ unsigned long irqbits; -+ -+ /* -+ * Note that both rx and tx interrupts are blocked at this point, -+ * regardless of which got us here. -+ */ -+ -+ irqbits = *R_IRQ_MASK2_RD; -+ -+ /* Handle received packets */ -+ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { -+ /* acknowledge the eop interrupt */ -+ -+ *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do); -+ -+ /* check if one or more complete packets were indeed received */ -+ -+ while ((*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) && -+ (myNextRxDesc != myLastRxDesc)) { -+ /* Take out the buffer and give it to the OS, then -+ * allocate a new buffer to put a packet in. -+ */ -+ e100_rx(dev); -+ dev->stats.rx_packets++; -+ /* restart/continue on the channel, for safety */ -+ *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart); -+ /* clear dma channel 1 eop/descr irq bits */ -+ *R_DMA_CH1_CLR_INTR = -+ IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) | -+ IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do); -+ -+ /* now, we might have gotten another packet -+ so we have to loop back and check if so */ -+ } -+ } -+ -+ /* Report any packets that have been sent */ -+ while (virt_to_phys(myFirstTxDesc) != *R_DMA_CH0_FIRST && -+ (netif_queue_stopped(dev) || myFirstTxDesc != myNextTxDesc)) { -+ dev->stats.tx_bytes += myFirstTxDesc->skb->len; -+ dev->stats.tx_packets++; -+ -+ /* dma is ready with the transmission of the data in tx_skb, so now -+ we can release the skb memory */ -+ dev_kfree_skb_irq(myFirstTxDesc->skb); -+ myFirstTxDesc->skb = 0; -+ myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next); -+ /* Wake up queue. */ -+ netif_wake_queue(dev); -+ } -+ -+ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { -+ /* acknowledge the eop interrupt. */ -+ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t -+e100nw_interrupt(int irq, void *dev_id) -+{ -+ struct net_device *dev = (struct net_device *)dev_id; -+ unsigned long irqbits = *R_IRQ_MASK0_RD; -+ -+ /* check for underrun irq */ -+ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr); -+ *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow; -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop); -+ dev->stats.tx_errors++; -+ D(printk("ethernet receiver underrun!\n")); -+ } -+ -+ /* check for overrun irq */ -+ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { -+ update_rx_stats(&dev->stats); /* this will ack the irq */ -+ D(printk("ethernet receiver overrun!\n")); -+ } -+ /* check for excessive collision irq */ -+ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr); -+ *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow; -+ SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop); -+ dev->stats.tx_errors++; -+ D(printk("ethernet excessive collisions!\n")); -+ } -+ return IRQ_HANDLED; -+} -+ -+/* We have a good packet(s), get it/them out of the buffers. */ -+static void -+e100_rx(struct net_device *dev) -+{ -+ struct sk_buff *skb; -+ int length = 0; -+ struct net_local *np = netdev_priv(dev); -+ unsigned char *skb_data_ptr; -+#ifdef ETHDEBUG -+ int i; -+#endif -+ etrax_eth_descr *prevRxDesc; /* The descriptor right before myNextRxDesc */ -+ spin_lock(&np->led_lock); -+ if (!led_active && time_after(jiffies, led_next_time)) { -+ /* light the network leds depending on the current speed. */ -+ e100_set_network_leds(NETWORK_ACTIVITY); -+ -+ /* Set the earliest time we may clear the LED */ -+ led_next_time = jiffies + NET_FLASH_TIME; -+ led_active = 1; -+ mod_timer(&clear_led_timer, jiffies + HZ/10); -+ } -+ spin_unlock(&np->led_lock); -+ -+ length = myNextRxDesc->descr.hw_len - 4; -+ dev->stats.rx_bytes += length; -+ -+#ifdef ETHDEBUG -+ printk("Got a packet of length %d:\n", length); -+ /* dump the first bytes in the packet */ -+ skb_data_ptr = (unsigned char *)phys_to_virt(myNextRxDesc->descr.buf); -+ for (i = 0; i < 8; i++) { -+ printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, -+ skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3], -+ skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]); -+ skb_data_ptr += 8; -+ } -+#endif -+ -+ if (length < RX_COPYBREAK) { -+ /* Small packet, copy data */ -+ skb = dev_alloc_skb(length - ETHER_HEAD_LEN); -+ if (!skb) { -+ dev->stats.rx_errors++; -+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); -+ goto update_nextrxdesc; -+ } -+ -+ skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ -+ skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ -+ -+#ifdef ETHDEBUG -+ printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", -+ skb->head, skb->data, skb_tail_pointer(skb), -+ skb_end_pointer(skb)); -+ printk("copying packet to 0x%x.\n", skb_data_ptr); -+#endif -+ -+ memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length); -+ } -+ else { -+ /* Large packet, send directly to upper layers and allocate new -+ * memory (aligned to cache line boundary to avoid bug). -+ * Before sending the skb to upper layers we must make sure -+ * that skb->data points to the aligned start of the packet. -+ */ -+ int align; -+ struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES); -+ if (!new_skb) { -+ dev->stats.rx_errors++; -+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); -+ goto update_nextrxdesc; -+ } -+ skb = myNextRxDesc->skb; -+ align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data; -+ skb_put(skb, length + align); -+ skb_pull(skb, align); /* Remove alignment bytes */ -+ myNextRxDesc->skb = new_skb; -+ myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data)); -+ } -+ -+ skb->protocol = eth_type_trans(skb, dev); -+ -+ /* Send the packet to the upper layers */ -+ netif_rx(skb); -+ -+ update_nextrxdesc: -+ /* Prepare for next packet */ -+ myNextRxDesc->descr.status = 0; -+ prevRxDesc = myNextRxDesc; -+ myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next); -+ -+ rx_queue_len++; -+ -+ /* Check if descriptors should be returned */ -+ if (rx_queue_len == RX_QUEUE_THRESHOLD) { -+ flush_etrax_cache(); -+ prevRxDesc->descr.ctrl |= d_eol; -+ myLastRxDesc->descr.ctrl &= ~d_eol; -+ myLastRxDesc = prevRxDesc; -+ rx_queue_len = 0; -+ } -+} -+ -+/* The inverse routine to net_open(). */ -+static int -+e100_close(struct net_device *dev) -+{ -+ printk(KERN_INFO "Closing %s.\n", dev->name); -+ -+ netif_stop_queue(dev); -+ -+ *R_IRQ_MASK0_CLR = -+ IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | -+ IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | -+ IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); -+ -+ *R_IRQ_MASK2_CLR = -+ IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | -+ IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); -+ -+ /* Stop the receiver and the transmitter */ -+ -+ RESET_DMA(NETWORK_TX_DMA_NBR); -+ RESET_DMA(NETWORK_RX_DMA_NBR); -+ -+ /* Flush the Tx and disable Rx here. */ -+ -+ free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev); -+ free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); -+ free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); -+ -+ cris_free_dma(NETWORK_TX_DMA_NBR, cardname); -+ cris_free_dma(NETWORK_RX_DMA_NBR, cardname); -+ -+ /* Update the statistics here. */ -+ -+ update_rx_stats(&dev->stats); -+ update_tx_stats(&dev->stats); -+ -+ /* Stop speed/duplex timers */ -+ del_timer(&speed_timer); -+ del_timer(&duplex_timer); -+ -+ return 0; -+} -+ -+static int -+e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -+{ -+ struct mii_ioctl_data *data = if_mii(ifr); -+ struct net_local *np = netdev_priv(dev); -+ int rc = 0; -+ int old_autoneg; -+ -+ spin_lock(&np->lock); /* Preempt protection */ -+ switch (cmd) { -+ /* The ioctls below should be considered obsolete but are */ -+ /* still present for compatibility with old scripts/apps */ -+ case SET_ETH_SPEED_10: /* 10 Mbps */ -+ e100_set_speed(dev, 10); -+ break; -+ case SET_ETH_SPEED_100: /* 100 Mbps */ -+ e100_set_speed(dev, 100); -+ break; -+ case SET_ETH_SPEED_AUTO: /* Auto-negotiate speed */ -+ e100_set_speed(dev, 0); -+ break; -+ case SET_ETH_DUPLEX_HALF: /* Half duplex */ -+ e100_set_duplex(dev, half); -+ break; -+ case SET_ETH_DUPLEX_FULL: /* Full duplex */ -+ e100_set_duplex(dev, full); -+ break; -+ case SET_ETH_DUPLEX_AUTO: /* Auto-negotiate duplex */ -+ e100_set_duplex(dev, autoneg); -+ break; -+ case SET_ETH_AUTONEG: -+ old_autoneg = autoneg_normal; -+ autoneg_normal = *(int*)data; -+ if (autoneg_normal != old_autoneg) -+ e100_negotiate(dev); -+ break; -+ default: -+ rc = generic_mii_ioctl(&np->mii_if, if_mii(ifr), -+ cmd, NULL); -+ break; -+ } -+ spin_unlock(&np->lock); -+ return rc; -+} -+ -+static int e100_get_settings(struct net_device *dev, -+ struct ethtool_cmd *cmd) -+{ -+ struct net_local *np = netdev_priv(dev); -+ int err; -+ -+ spin_lock_irq(&np->lock); -+ err = mii_ethtool_gset(&np->mii_if, cmd); -+ spin_unlock_irq(&np->lock); -+ -+ /* The PHY may support 1000baseT, but the Etrax100 does not. */ -+ cmd->supported &= ~(SUPPORTED_1000baseT_Half -+ | SUPPORTED_1000baseT_Full); -+ return err; -+} -+ -+static int e100_set_settings(struct net_device *dev, -+ struct ethtool_cmd *ecmd) -+{ -+ if (ecmd->autoneg == AUTONEG_ENABLE) { -+ e100_set_duplex(dev, autoneg); -+ e100_set_speed(dev, 0); -+ } else { -+ e100_set_duplex(dev, ecmd->duplex == DUPLEX_HALF ? half : full); -+ e100_set_speed(dev, ecmd->speed == SPEED_10 ? 10: 100); -+ } -+ -+ return 0; -+} -+ -+static void e100_get_drvinfo(struct net_device *dev, -+ struct ethtool_drvinfo *info) -+{ -+ strncpy(info->driver, "ETRAX 100LX", sizeof(info->driver) - 1); -+ strncpy(info->version, "$Revision: 1.31 $", sizeof(info->version) - 1); -+ strncpy(info->fw_version, "N/A", sizeof(info->fw_version) - 1); -+ strncpy(info->bus_info, "N/A", sizeof(info->bus_info) - 1); -+} -+ -+static int e100_nway_reset(struct net_device *dev) -+{ -+ if (current_duplex == autoneg && current_speed_selection == 0) -+ e100_negotiate(dev); -+ return 0; -+} -+ -+static const struct ethtool_ops e100_ethtool_ops = { -+ .get_settings = e100_get_settings, -+ .set_settings = e100_set_settings, -+ .get_drvinfo = e100_get_drvinfo, -+ .nway_reset = e100_nway_reset, -+ .get_link = ethtool_op_get_link, -+}; -+ -+static int -+e100_set_config(struct net_device *dev, struct ifmap *map) -+{ -+ struct net_local *np = netdev_priv(dev); -+ -+ spin_lock(&np->lock); /* Preempt protection */ -+ -+ switch(map->port) { -+ case IF_PORT_UNKNOWN: -+ /* Use autoneg */ -+ e100_set_speed(dev, 0); -+ e100_set_duplex(dev, autoneg); -+ break; -+ case IF_PORT_10BASET: -+ e100_set_speed(dev, 10); -+ e100_set_duplex(dev, autoneg); -+ break; -+ case IF_PORT_100BASET: -+ case IF_PORT_100BASETX: -+ e100_set_speed(dev, 100); -+ e100_set_duplex(dev, autoneg); -+ break; -+ case IF_PORT_100BASEFX: -+ case IF_PORT_10BASE2: -+ case IF_PORT_AUI: -+ spin_unlock(&np->lock); -+ return -EOPNOTSUPP; -+ break; -+ default: -+ printk(KERN_ERR "%s: Invalid media selected", dev->name); -+ spin_unlock(&np->lock); -+ return -EINVAL; -+ } -+ spin_unlock(&np->lock); -+ return 0; -+} -+ -+static void -+update_rx_stats(struct net_device_stats *es) -+{ -+ unsigned long r = *R_REC_COUNTERS; -+ /* update stats relevant to reception errors */ -+ es->rx_fifo_errors += IO_EXTRACT(R_REC_COUNTERS, congestion, r); -+ es->rx_crc_errors += IO_EXTRACT(R_REC_COUNTERS, crc_error, r); -+ es->rx_frame_errors += IO_EXTRACT(R_REC_COUNTERS, alignment_error, r); -+ es->rx_length_errors += IO_EXTRACT(R_REC_COUNTERS, oversize, r); -+} -+ -+static void -+update_tx_stats(struct net_device_stats *es) -+{ -+ unsigned long r = *R_TR_COUNTERS; -+ /* update stats relevant to transmission errors */ -+ es->collisions += -+ IO_EXTRACT(R_TR_COUNTERS, single_col, r) + -+ IO_EXTRACT(R_TR_COUNTERS, multiple_col, r); -+} -+ -+/* -+ * Get the current statistics. -+ * This may be called with the card open or closed. -+ */ -+static struct net_device_stats * -+e100_get_stats(struct net_device *dev) -+{ -+ struct net_local *lp = netdev_priv(dev); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&lp->lock, flags); -+ -+ update_rx_stats(&dev->stats); -+ update_tx_stats(&dev->stats); -+ -+ spin_unlock_irqrestore(&lp->lock, flags); -+ return &dev->stats; -+} -+ -+/* -+ * Set or clear the multicast filter for this adaptor. -+ * num_addrs == -1 Promiscuous mode, receive all packets -+ * num_addrs == 0 Normal mode, clear multicast list -+ * num_addrs > 0 Multicast mode, receive normal and MC packets, -+ * and do best-effort filtering. -+ */ -+static void -+set_multicast_list(struct net_device *dev) -+{ -+ struct net_local *lp = netdev_priv(dev); -+ int num_addr = netdev_mc_count(dev); -+ unsigned long int lo_bits; -+ unsigned long int hi_bits; -+ -+ spin_lock(&lp->lock); -+ if (dev->flags & IFF_PROMISC) { -+ /* promiscuous mode */ -+ lo_bits = 0xfffffffful; -+ hi_bits = 0xfffffffful; -+ -+ /* Enable individual receive */ -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, receive); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+ } else if (dev->flags & IFF_ALLMULTI) { -+ /* enable all multicasts */ -+ lo_bits = 0xfffffffful; -+ hi_bits = 0xfffffffful; -+ -+ /* Disable individual receive */ -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+ } else if (num_addr == 0) { -+ /* Normal, clear the mc list */ -+ lo_bits = 0x00000000ul; -+ hi_bits = 0x00000000ul; -+ -+ /* Disable individual receive */ -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+ } else { -+ /* MC mode, receive normal and MC packets */ -+ char hash_ix; -+ struct netdev_hw_addr *ha; -+ char *baddr; -+ -+ lo_bits = 0x00000000ul; -+ hi_bits = 0x00000000ul; -+ netdev_for_each_mc_addr(ha, dev) { -+ /* Calculate the hash index for the GA registers */ -+ -+ hash_ix = 0; -+ baddr = ha->addr; -+ hash_ix ^= (*baddr) & 0x3f; -+ hash_ix ^= ((*baddr) >> 6) & 0x03; -+ ++baddr; -+ hash_ix ^= ((*baddr) << 2) & 0x03c; -+ hash_ix ^= ((*baddr) >> 4) & 0xf; -+ ++baddr; -+ hash_ix ^= ((*baddr) << 4) & 0x30; -+ hash_ix ^= ((*baddr) >> 2) & 0x3f; -+ ++baddr; -+ hash_ix ^= (*baddr) & 0x3f; -+ hash_ix ^= ((*baddr) >> 6) & 0x03; -+ ++baddr; -+ hash_ix ^= ((*baddr) << 2) & 0x03c; -+ hash_ix ^= ((*baddr) >> 4) & 0xf; -+ ++baddr; -+ hash_ix ^= ((*baddr) << 4) & 0x30; -+ hash_ix ^= ((*baddr) >> 2) & 0x3f; -+ -+ hash_ix &= 0x3f; -+ -+ if (hash_ix >= 32) { -+ hi_bits |= (1 << (hash_ix-32)); -+ } else { -+ lo_bits |= (1 << hash_ix); -+ } -+ } -+ /* Disable individual receive */ -+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); -+ *R_NETWORK_REC_CONFIG = network_rec_config_shadow; -+ } -+ *R_NETWORK_GA_0 = lo_bits; -+ *R_NETWORK_GA_1 = hi_bits; -+ spin_unlock(&lp->lock); -+} -+ -+void -+e100_hardware_send_packet(struct net_local *np, char *buf, int length) -+{ -+ D(printk("e100 send pack, buf 0x%x len %d\n", buf, length)); -+ -+ spin_lock(&np->led_lock); -+ if (!led_active && time_after(jiffies, led_next_time)) { -+ /* light the network leds depending on the current speed. */ -+ e100_set_network_leds(NETWORK_ACTIVITY); -+ -+ /* Set the earliest time we may clear the LED */ -+ led_next_time = jiffies + NET_FLASH_TIME; -+ led_active = 1; -+ mod_timer(&clear_led_timer, jiffies + HZ/10); -+ } -+ spin_unlock(&np->led_lock); -+ -+ /* configure the tx dma descriptor */ -+ myNextTxDesc->descr.sw_len = length; -+ myNextTxDesc->descr.ctrl = d_eop | d_eol | d_wait; -+ myNextTxDesc->descr.buf = virt_to_phys(buf); -+ -+ /* Move end of list */ -+ myLastTxDesc->descr.ctrl &= ~d_eol; -+ myLastTxDesc = myNextTxDesc; -+ -+ /* Restart DMA channel */ -+ *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, restart); -+} -+ -+static void -+e100_clear_network_leds(unsigned long dummy) -+{ -+ struct net_device *dev = (struct net_device *)dummy; -+ struct net_local *np = netdev_priv(dev); -+ -+ spin_lock(&np->led_lock); -+ -+ if (led_active && time_after(jiffies, led_next_time)) { -+ e100_set_network_leds(NO_NETWORK_ACTIVITY); -+ -+ /* Set the earliest time we may set the LED */ -+ led_next_time = jiffies + NET_FLASH_PAUSE; -+ led_active = 0; -+ } -+ -+ spin_unlock(&np->led_lock); -+} -+ -+static void -+e100_set_network_leds(int active) -+{ -+#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK) -+ int light_leds = (active == NO_NETWORK_ACTIVITY); -+#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY) -+ int light_leds = (active == NETWORK_ACTIVITY); -+#else -+#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY" -+#endif -+ -+ if (!current_speed) { -+ /* Make LED red, link is down */ -+ CRIS_LED_NETWORK_SET(CRIS_LED_OFF); -+ } else if (light_leds) { -+ if (current_speed == 10) { -+ CRIS_LED_NETWORK_SET(CRIS_LED_ORANGE); -+ } else { -+ CRIS_LED_NETWORK_SET(CRIS_LED_GREEN); -+ } -+ } else { -+ CRIS_LED_NETWORK_SET(CRIS_LED_OFF); -+ } -+} -+ -+#ifdef CONFIG_NET_POLL_CONTROLLER -+static void -+e100_netpoll(struct net_device* netdev) -+{ -+ e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev, NULL); -+} -+#endif -+ -+static int -+etrax_init_module(void) -+{ -+ return etrax_ethernet_init(); -+} -+ -+static int __init -+e100_boot_setup(char* str) -+{ -+ struct sockaddr sa = {0}; -+ int i; -+ -+ /* Parse the colon separated Ethernet station address */ -+ for (i = 0; i < ETH_ALEN; i++) { -+ unsigned int tmp; -+ if (sscanf(str + 3*i, "%2x", &tmp) != 1) { -+ printk(KERN_WARNING "Malformed station address"); -+ return 0; -+ } -+ sa.sa_data[i] = (char)tmp; -+ } -+ -+ default_mac = sa; -+ return 1; -+} -+ -+__setup("etrax100_eth=", e100_boot_setup); -+ -+module_init(etrax_init_module); diff -Nur linux-2.6.39.orig/drivers/tty/serial/crisv10.c linux-2.6.39/drivers/tty/serial/crisv10.c --- linux-2.6.39.orig/drivers/tty/serial/crisv10.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/tty/serial/crisv10.c 2011-07-28 16:27:57.623883501 +0200 ++++ linux-2.6.39/drivers/tty/serial/crisv10.c 2011-08-22 08:58:56.137981508 +0200 @@ -26,6 +26,7 @@ #include <linux/kernel.h> #include <linux/mutex.h> @@ -3292,4585 +411,9 @@ diff -Nur linux-2.6.39.orig/drivers/tty/serial/crisv10.c linux-2.6.39/drivers/tt return 0; } -diff -Nur linux-2.6.39.orig/drivers/tty/serial/crisv10.c.orig linux-2.6.39/drivers/tty/serial/crisv10.c.orig ---- linux-2.6.39.orig/drivers/tty/serial/crisv10.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/tty/serial/crisv10.c.orig 2011-05-19 06:06:34.000000000 +0200 -@@ -0,0 +1,4572 @@ -+/* -+ * Serial port driver for the ETRAX 100LX chip -+ * -+ * Copyright (C) 1998-2007 Axis Communications AB -+ * -+ * Many, many authors. Based once upon a time on serial.c for 16x50. -+ * -+ */ -+ -+static char *serial_version = "$Revision: 1.25 $"; -+ -+#include <linux/types.h> -+#include <linux/errno.h> -+#include <linux/signal.h> -+#include <linux/sched.h> -+#include <linux/timer.h> -+#include <linux/interrupt.h> -+#include <linux/tty.h> -+#include <linux/tty_flip.h> -+#include <linux/major.h> -+#include <linux/string.h> -+#include <linux/fcntl.h> -+#include <linux/mm.h> -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/mutex.h> -+#include <linux/bitops.h> -+#include <linux/seq_file.h> -+#include <linux/delay.h> -+#include <linux/module.h> -+#include <linux/uaccess.h> -+#include <linux/io.h> -+ -+#include <asm/irq.h> -+#include <asm/dma.h> -+#include <asm/system.h> -+ -+#include <arch/svinto.h> -+ -+/* non-arch dependent serial structures are in linux/serial.h */ -+#include <linux/serial.h> -+/* while we keep our own stuff (struct e100_serial) in a local .h file */ -+#include "crisv10.h" -+#include <asm/fasttimer.h> -+#include <arch/io_interface_mux.h> -+ -+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -+#ifndef CONFIG_ETRAX_FAST_TIMER -+#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER" -+#endif -+#endif -+ -+#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \ -+ (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0) -+#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1" -+#endif -+ -+#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G) -+#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G" -+#endif -+ -+/* -+ * All of the compatibilty code so we can compile serial.c against -+ * older kernels is hidden in serial_compat.h -+ */ -+#if defined(LOCAL_HEADERS) -+#include "serial_compat.h" -+#endif -+ -+struct tty_driver *serial_driver; -+ -+/* number of characters left in xmit buffer before we ask for more */ -+#define WAKEUP_CHARS 256 -+ -+//#define SERIAL_DEBUG_INTR -+//#define SERIAL_DEBUG_OPEN -+//#define SERIAL_DEBUG_FLOW -+//#define SERIAL_DEBUG_DATA -+//#define SERIAL_DEBUG_THROTTLE -+//#define SERIAL_DEBUG_IO /* Debug for Extra control and status pins */ -+//#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */ -+ -+/* Enable this to use serial interrupts to handle when you -+ expect the first received event on the serial port to -+ be an error, break or similar. Used to be able to flash IRMA -+ from eLinux */ -+#define SERIAL_HANDLE_EARLY_ERRORS -+ -+/* Currently 16 descriptors x 128 bytes = 2048 bytes */ -+#define SERIAL_DESCR_BUF_SIZE 256 -+ -+#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */ -+#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE -+ -+/* We don't want to load the system with massive fast timer interrupt -+ * on high baudrates so limit it to 250 us (4kHz) */ -+#define MIN_FLUSH_TIME_USEC 250 -+ -+/* Add an x here to log a lot of timer stuff */ -+#define TIMERD(x) -+/* Debug details of interrupt handling */ -+#define DINTR1(x) /* irq on/off, errors */ -+#define DINTR2(x) /* tx and rx */ -+/* Debug flip buffer stuff */ -+#define DFLIP(x) -+/* Debug flow control and overview of data flow */ -+#define DFLOW(x) -+#define DBAUD(x) -+#define DLOG_INT_TRIG(x) -+ -+//#define DEBUG_LOG_INCLUDED -+#ifndef DEBUG_LOG_INCLUDED -+#define DEBUG_LOG(line, string, value) -+#else -+struct debug_log_info -+{ -+ unsigned long time; -+ unsigned long timer_data; -+// int line; -+ const char *string; -+ int value; -+}; -+#define DEBUG_LOG_SIZE 4096 -+ -+struct debug_log_info debug_log[DEBUG_LOG_SIZE]; -+int debug_log_pos = 0; -+ -+#define DEBUG_LOG(_line, _string, _value) do { \ -+ if ((_line) == SERIAL_DEBUG_LINE) {\ -+ debug_log_func(_line, _string, _value); \ -+ }\ -+}while(0) -+ -+void debug_log_func(int line, const char *string, int value) -+{ -+ if (debug_log_pos < DEBUG_LOG_SIZE) { -+ debug_log[debug_log_pos].time = jiffies; -+ debug_log[debug_log_pos].timer_data = *R_TIMER_DATA; -+// debug_log[debug_log_pos].line = line; -+ debug_log[debug_log_pos].string = string; -+ debug_log[debug_log_pos].value = value; -+ debug_log_pos++; -+ } -+ /*printk(string, value);*/ -+} -+#endif -+ -+#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS -+/* Default number of timer ticks before flushing rx fifo -+ * When using "little data, low latency applications: use 0 -+ * When using "much data applications (PPP)" use ~5 -+ */ -+#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 -+#endif -+ -+unsigned long timer_data_to_ns(unsigned long timer_data); -+ -+static void change_speed(struct e100_serial *info); -+static void rs_throttle(struct tty_struct * tty); -+static void rs_wait_until_sent(struct tty_struct *tty, int timeout); -+static int rs_write(struct tty_struct *tty, -+ const unsigned char *buf, int count); -+#ifdef CONFIG_ETRAX_RS485 -+static int e100_write_rs485(struct tty_struct *tty, -+ const unsigned char *buf, int count); -+#endif -+static int get_lsr_info(struct e100_serial *info, unsigned int *value); -+ -+ -+#define DEF_BAUD 115200 /* 115.2 kbit/s */ -+#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) -+#define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */ -+/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */ -+#define DEF_TX 0x80 /* or SERIAL_CTRL_B */ -+ -+/* offsets from R_SERIALx_CTRL */ -+ -+#define REG_DATA 0 -+#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */ -+#define REG_TR_DATA 0 -+#define REG_STATUS 1 -+#define REG_TR_CTRL 1 -+#define REG_REC_CTRL 2 -+#define REG_BAUD 3 -+#define REG_XOFF 4 /* this is a 32 bit register */ -+ -+/* The bitfields are the same for all serial ports */ -+#define SER_RXD_MASK IO_MASK(R_SERIAL0_STATUS, rxd) -+#define SER_DATA_AVAIL_MASK IO_MASK(R_SERIAL0_STATUS, data_avail) -+#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err) -+#define SER_PAR_ERR_MASK IO_MASK(R_SERIAL0_STATUS, par_err) -+#define SER_OVERRUN_MASK IO_MASK(R_SERIAL0_STATUS, overrun) -+ -+#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK) -+ -+/* Values for info->errorcode */ -+#define ERRCODE_SET_BREAK (TTY_BREAK) -+#define ERRCODE_INSERT 0x100 -+#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK) -+ -+#define FORCE_EOP(info) *R_SET_EOP = 1U << info->iseteop; -+ -+/* -+ * General note regarding the use of IO_* macros in this file: -+ * -+ * We will use the bits defined for DMA channel 6 when using various -+ * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are -+ * the same for all channels (which of course they are). -+ * -+ * We will also use the bits defined for serial port 0 when writing commands -+ * to the different ports, as these bits too are the same for all ports. -+ */ -+ -+ -+/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */ -+static const unsigned long e100_ser_int_mask = 0 -+#ifdef CONFIG_ETRAX_SERIAL_PORT0 -+| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready) -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT1 -+| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready) -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT2 -+| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready) -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT3 -+| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready) -+#endif -+; -+unsigned long r_alt_ser_baudrate_shadow = 0; -+ -+/* this is the data for the four serial ports in the etrax100 */ -+/* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */ -+/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */ -+ -+static struct e100_serial rs_table[] = { -+ { .baud = DEF_BAUD, -+ .ioport = (unsigned char *)R_SERIAL0_CTRL, -+ .irq = 1U << 12, /* uses DMA 6 and 7 */ -+ .oclrintradr = R_DMA_CH6_CLR_INTR, -+ .ofirstadr = R_DMA_CH6_FIRST, -+ .ocmdadr = R_DMA_CH6_CMD, -+ .ostatusadr = R_DMA_CH6_STATUS, -+ .iclrintradr = R_DMA_CH7_CLR_INTR, -+ .ifirstadr = R_DMA_CH7_FIRST, -+ .icmdadr = R_DMA_CH7_CMD, -+ .idescradr = R_DMA_CH7_DESCR, -+ .flags = STD_FLAGS, -+ .rx_ctrl = DEF_RX, -+ .tx_ctrl = DEF_TX, -+ .iseteop = 2, -+ .dma_owner = dma_ser0, -+ .io_if = if_serial_0, -+#ifdef CONFIG_ETRAX_SERIAL_PORT0 -+ .enabled = 1, -+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT -+ .dma_out_enabled = 1, -+ .dma_out_nbr = SER0_TX_DMA_NBR, -+ .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR, -+ .dma_out_irq_flags = IRQF_DISABLED, -+ .dma_out_irq_description = "serial 0 dma tr", -+#else -+ .dma_out_enabled = 0, -+ .dma_out_nbr = UINT_MAX, -+ .dma_out_irq_nbr = 0, -+ .dma_out_irq_flags = 0, -+ .dma_out_irq_description = NULL, -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN -+ .dma_in_enabled = 1, -+ .dma_in_nbr = SER0_RX_DMA_NBR, -+ .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR, -+ .dma_in_irq_flags = IRQF_DISABLED, -+ .dma_in_irq_description = "serial 0 dma rec", -+#else -+ .dma_in_enabled = 0, -+ .dma_in_nbr = UINT_MAX, -+ .dma_in_irq_nbr = 0, -+ .dma_in_irq_flags = 0, -+ .dma_in_irq_description = NULL, -+#endif -+#else -+ .enabled = 0, -+ .io_if_description = NULL, -+ .dma_out_enabled = 0, -+ .dma_in_enabled = 0 -+#endif -+ -+}, /* ttyS0 */ -+#ifndef CONFIG_SVINTO_SIM -+ { .baud = DEF_BAUD, -+ .ioport = (unsigned char *)R_SERIAL1_CTRL, -+ .irq = 1U << 16, /* uses DMA 8 and 9 */ -+ .oclrintradr = R_DMA_CH8_CLR_INTR, -+ .ofirstadr = R_DMA_CH8_FIRST, -+ .ocmdadr = R_DMA_CH8_CMD, -+ .ostatusadr = R_DMA_CH8_STATUS, -+ .iclrintradr = R_DMA_CH9_CLR_INTR, -+ .ifirstadr = R_DMA_CH9_FIRST, -+ .icmdadr = R_DMA_CH9_CMD, -+ .idescradr = R_DMA_CH9_DESCR, -+ .flags = STD_FLAGS, -+ .rx_ctrl = DEF_RX, -+ .tx_ctrl = DEF_TX, -+ .iseteop = 3, -+ .dma_owner = dma_ser1, -+ .io_if = if_serial_1, -+#ifdef CONFIG_ETRAX_SERIAL_PORT1 -+ .enabled = 1, -+ .io_if_description = "ser1", -+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT -+ .dma_out_enabled = 1, -+ .dma_out_nbr = SER1_TX_DMA_NBR, -+ .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR, -+ .dma_out_irq_flags = IRQF_DISABLED, -+ .dma_out_irq_description = "serial 1 dma tr", -+#else -+ .dma_out_enabled = 0, -+ .dma_out_nbr = UINT_MAX, -+ .dma_out_irq_nbr = 0, -+ .dma_out_irq_flags = 0, -+ .dma_out_irq_description = NULL, -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN -+ .dma_in_enabled = 1, -+ .dma_in_nbr = SER1_RX_DMA_NBR, -+ .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR, -+ .dma_in_irq_flags = IRQF_DISABLED, -+ .dma_in_irq_description = "serial 1 dma rec", -+#else -+ .dma_in_enabled = 0, -+ .dma_in_enabled = 0, -+ .dma_in_nbr = UINT_MAX, -+ .dma_in_irq_nbr = 0, -+ .dma_in_irq_flags = 0, -+ .dma_in_irq_description = NULL, -+#endif -+#else -+ .enabled = 0, -+ .io_if_description = NULL, -+ .dma_in_irq_nbr = 0, -+ .dma_out_enabled = 0, -+ .dma_in_enabled = 0 -+#endif -+}, /* ttyS1 */ -+ -+ { .baud = DEF_BAUD, -+ .ioport = (unsigned char *)R_SERIAL2_CTRL, -+ .irq = 1U << 4, /* uses DMA 2 and 3 */ -+ .oclrintradr = R_DMA_CH2_CLR_INTR, -+ .ofirstadr = R_DMA_CH2_FIRST, -+ .ocmdadr = R_DMA_CH2_CMD, -+ .ostatusadr = R_DMA_CH2_STATUS, -+ .iclrintradr = R_DMA_CH3_CLR_INTR, -+ .ifirstadr = R_DMA_CH3_FIRST, -+ .icmdadr = R_DMA_CH3_CMD, -+ .idescradr = R_DMA_CH3_DESCR, -+ .flags = STD_FLAGS, -+ .rx_ctrl = DEF_RX, -+ .tx_ctrl = DEF_TX, -+ .iseteop = 0, -+ .dma_owner = dma_ser2, -+ .io_if = if_serial_2, -+#ifdef CONFIG_ETRAX_SERIAL_PORT2 -+ .enabled = 1, -+ .io_if_description = "ser2", -+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT -+ .dma_out_enabled = 1, -+ .dma_out_nbr = SER2_TX_DMA_NBR, -+ .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR, -+ .dma_out_irq_flags = IRQF_DISABLED, -+ .dma_out_irq_description = "serial 2 dma tr", -+#else -+ .dma_out_enabled = 0, -+ .dma_out_nbr = UINT_MAX, -+ .dma_out_irq_nbr = 0, -+ .dma_out_irq_flags = 0, -+ .dma_out_irq_description = NULL, -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN -+ .dma_in_enabled = 1, -+ .dma_in_nbr = SER2_RX_DMA_NBR, -+ .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR, -+ .dma_in_irq_flags = IRQF_DISABLED, -+ .dma_in_irq_description = "serial 2 dma rec", -+#else -+ .dma_in_enabled = 0, -+ .dma_in_nbr = UINT_MAX, -+ .dma_in_irq_nbr = 0, -+ .dma_in_irq_flags = 0, -+ .dma_in_irq_description = NULL, -+#endif -+#else -+ .enabled = 0, -+ .io_if_description = NULL, -+ .dma_out_enabled = 0, -+ .dma_in_enabled = 0 -+#endif -+ }, /* ttyS2 */ -+ -+ { .baud = DEF_BAUD, -+ .ioport = (unsigned char *)R_SERIAL3_CTRL, -+ .irq = 1U << 8, /* uses DMA 4 and 5 */ -+ .oclrintradr = R_DMA_CH4_CLR_INTR, -+ .ofirstadr = R_DMA_CH4_FIRST, -+ .ocmdadr = R_DMA_CH4_CMD, -+ .ostatusadr = R_DMA_CH4_STATUS, -+ .iclrintradr = R_DMA_CH5_CLR_INTR, -+ .ifirstadr = R_DMA_CH5_FIRST, -+ .icmdadr = R_DMA_CH5_CMD, -+ .idescradr = R_DMA_CH5_DESCR, -+ .flags = STD_FLAGS, -+ .rx_ctrl = DEF_RX, -+ .tx_ctrl = DEF_TX, -+ .iseteop = 1, -+ .dma_owner = dma_ser3, -+ .io_if = if_serial_3, -+#ifdef CONFIG_ETRAX_SERIAL_PORT3 -+ .enabled = 1, -+ .io_if_description = "ser3", -+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT -+ .dma_out_enabled = 1, -+ .dma_out_nbr = SER3_TX_DMA_NBR, -+ .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR, -+ .dma_out_irq_flags = IRQF_DISABLED, -+ .dma_out_irq_description = "serial 3 dma tr", -+#else -+ .dma_out_enabled = 0, -+ .dma_out_nbr = UINT_MAX, -+ .dma_out_irq_nbr = 0, -+ .dma_out_irq_flags = 0, -+ .dma_out_irq_description = NULL, -+#endif -+#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN -+ .dma_in_enabled = 1, -+ .dma_in_nbr = SER3_RX_DMA_NBR, -+ .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR, -+ .dma_in_irq_flags = IRQF_DISABLED, -+ .dma_in_irq_description = "serial 3 dma rec", -+#else -+ .dma_in_enabled = 0, -+ .dma_in_nbr = UINT_MAX, -+ .dma_in_irq_nbr = 0, -+ .dma_in_irq_flags = 0, -+ .dma_in_irq_description = NULL -+#endif -+#else -+ .enabled = 0, -+ .io_if_description = NULL, -+ .dma_out_enabled = 0, -+ .dma_in_enabled = 0 -+#endif -+ } /* ttyS3 */ -+#endif -+}; -+ -+ -+#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) -+ -+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -+static struct fast_timer fast_timers[NR_PORTS]; -+#endif -+ -+#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY -+#define PROCSTAT(x) x -+struct ser_statistics_type { -+ int overrun_cnt; -+ int early_errors_cnt; -+ int ser_ints_ok_cnt; -+ int errors_cnt; -+ unsigned long int processing_flip; -+ unsigned long processing_flip_still_room; -+ unsigned long int timeout_flush_cnt; -+ int rx_dma_ints; -+ int tx_dma_ints; -+ int rx_tot; -+ int tx_tot; -+}; -+ -+static struct ser_statistics_type ser_stat[NR_PORTS]; -+ -+#else -+ -+#define PROCSTAT(x) -+ -+#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */ -+ -+/* RS-485 */ -+#if defined(CONFIG_ETRAX_RS485) -+#ifdef CONFIG_ETRAX_FAST_TIMER -+static struct fast_timer fast_timers_rs485[NR_PORTS]; -+#endif -+#if defined(CONFIG_ETRAX_RS485_ON_PA) -+static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; -+#endif -+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -+static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT; -+#endif -+#endif -+ -+/* Info and macros needed for each ports extra control/status signals. */ -+#define E100_STRUCT_PORT(line, pinname) \ -+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ -+ (R_PORT_PA_DATA): ( \ -+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ -+ (R_PORT_PB_DATA):&dummy_ser[line])) -+ -+#define E100_STRUCT_SHADOW(line, pinname) \ -+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ -+ (&port_pa_data_shadow): ( \ -+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ -+ (&port_pb_data_shadow):&dummy_ser[line])) -+#define E100_STRUCT_MASK(line, pinname) \ -+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ -+ (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \ -+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ -+ (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK)) -+ -+#define DUMMY_DTR_MASK 1 -+#define DUMMY_RI_MASK 2 -+#define DUMMY_DSR_MASK 4 -+#define DUMMY_CD_MASK 8 -+static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF}; -+ -+/* If not all status pins are used or disabled, use mixed mode */ -+#ifdef CONFIG_ETRAX_SERIAL_PORT0 -+ -+#define SER0_PA_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PA_BIT+CONFIG_ETRAX_SER0_RI_ON_PA_BIT+CONFIG_ETRAX_SER0_DSR_ON_PA_BIT+CONFIG_ETRAX_SER0_CD_ON_PA_BIT) -+ -+#if SER0_PA_BITSUM != -4 -+# if CONFIG_ETRAX_SER0_DTR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_RI_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_DSR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_CD_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#define SER0_PB_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PB_BIT+CONFIG_ETRAX_SER0_RI_ON_PB_BIT+CONFIG_ETRAX_SER0_DSR_ON_PB_BIT+CONFIG_ETRAX_SER0_CD_ON_PB_BIT) -+ -+#if SER0_PB_BITSUM != -4 -+# if CONFIG_ETRAX_SER0_DTR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_RI_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_DSR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER0_CD_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#endif /* PORT0 */ -+ -+ -+#ifdef CONFIG_ETRAX_SERIAL_PORT1 -+ -+#define SER1_PA_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PA_BIT+CONFIG_ETRAX_SER1_RI_ON_PA_BIT+CONFIG_ETRAX_SER1_DSR_ON_PA_BIT+CONFIG_ETRAX_SER1_CD_ON_PA_BIT) -+ -+#if SER1_PA_BITSUM != -4 -+# if CONFIG_ETRAX_SER1_DTR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_RI_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_DSR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_CD_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#define SER1_PB_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PB_BIT+CONFIG_ETRAX_SER1_RI_ON_PB_BIT+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT+CONFIG_ETRAX_SER1_CD_ON_PB_BIT) -+ -+#if SER1_PB_BITSUM != -4 -+# if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_RI_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_DSR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER1_CD_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#endif /* PORT1 */ -+ -+#ifdef CONFIG_ETRAX_SERIAL_PORT2 -+ -+#define SER2_PA_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PA_BIT+CONFIG_ETRAX_SER2_RI_ON_PA_BIT+CONFIG_ETRAX_SER2_DSR_ON_PA_BIT+CONFIG_ETRAX_SER2_CD_ON_PA_BIT) -+ -+#if SER2_PA_BITSUM != -4 -+# if CONFIG_ETRAX_SER2_DTR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_RI_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_DSR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_CD_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#define SER2_PB_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PB_BIT+CONFIG_ETRAX_SER2_RI_ON_PB_BIT+CONFIG_ETRAX_SER2_DSR_ON_PB_BIT+CONFIG_ETRAX_SER2_CD_ON_PB_BIT) -+ -+#if SER2_PB_BITSUM != -4 -+# if CONFIG_ETRAX_SER2_DTR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_RI_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_DSR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER2_CD_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#endif /* PORT2 */ -+ -+#ifdef CONFIG_ETRAX_SERIAL_PORT3 -+ -+#define SER3_PA_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PA_BIT+CONFIG_ETRAX_SER3_RI_ON_PA_BIT+CONFIG_ETRAX_SER3_DSR_ON_PA_BIT+CONFIG_ETRAX_SER3_CD_ON_PA_BIT) -+ -+#if SER3_PA_BITSUM != -4 -+# if CONFIG_ETRAX_SER3_DTR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_RI_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_DSR_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_CD_ON_PA_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#define SER3_PB_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PB_BIT+CONFIG_ETRAX_SER3_RI_ON_PB_BIT+CONFIG_ETRAX_SER3_DSR_ON_PB_BIT+CONFIG_ETRAX_SER3_CD_ON_PB_BIT) -+ -+#if SER3_PB_BITSUM != -4 -+# if CONFIG_ETRAX_SER3_DTR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_RI_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_DSR_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+# if CONFIG_ETRAX_SER3_CD_ON_PB_BIT == -1 -+# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED -+# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 -+# endif -+# endif -+#endif -+ -+#endif /* PORT3 */ -+ -+ -+#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \ -+ defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \ -+ defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \ -+ defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED) -+#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED -+#endif -+ -+#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED -+/* The pins can be mixed on PA and PB */ -+#define CONTROL_PINS_PORT_NOT_USED(line) \ -+ &dummy_ser[line], &dummy_ser[line], \ -+ &dummy_ser[line], &dummy_ser[line], \ -+ &dummy_ser[line], &dummy_ser[line], \ -+ &dummy_ser[line], &dummy_ser[line], \ -+ DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK -+ -+ -+struct control_pins -+{ -+ volatile unsigned char *dtr_port; -+ unsigned char *dtr_shadow; -+ volatile unsigned char *ri_port; -+ unsigned char *ri_shadow; -+ volatile unsigned char *dsr_port; -+ unsigned char *dsr_shadow; -+ volatile unsigned char *cd_port; -+ unsigned char *cd_shadow; -+ -+ unsigned char dtr_mask; -+ unsigned char ri_mask; -+ unsigned char dsr_mask; -+ unsigned char cd_mask; -+}; -+ -+static const struct control_pins e100_modem_pins[NR_PORTS] = -+{ -+ /* Ser 0 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT0 -+ E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR), -+ E100_STRUCT_PORT(0,RI), E100_STRUCT_SHADOW(0,RI), -+ E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR), -+ E100_STRUCT_PORT(0,CD), E100_STRUCT_SHADOW(0,CD), -+ E100_STRUCT_MASK(0,DTR), -+ E100_STRUCT_MASK(0,RI), -+ E100_STRUCT_MASK(0,DSR), -+ E100_STRUCT_MASK(0,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(0) -+#endif -+ }, -+ -+ /* Ser 1 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT1 -+ E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR), -+ E100_STRUCT_PORT(1,RI), E100_STRUCT_SHADOW(1,RI), -+ E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR), -+ E100_STRUCT_PORT(1,CD), E100_STRUCT_SHADOW(1,CD), -+ E100_STRUCT_MASK(1,DTR), -+ E100_STRUCT_MASK(1,RI), -+ E100_STRUCT_MASK(1,DSR), -+ E100_STRUCT_MASK(1,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(1) -+#endif -+ }, -+ -+ /* Ser 2 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT2 -+ E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR), -+ E100_STRUCT_PORT(2,RI), E100_STRUCT_SHADOW(2,RI), -+ E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR), -+ E100_STRUCT_PORT(2,CD), E100_STRUCT_SHADOW(2,CD), -+ E100_STRUCT_MASK(2,DTR), -+ E100_STRUCT_MASK(2,RI), -+ E100_STRUCT_MASK(2,DSR), -+ E100_STRUCT_MASK(2,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(2) -+#endif -+ }, -+ -+ /* Ser 3 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT3 -+ E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR), -+ E100_STRUCT_PORT(3,RI), E100_STRUCT_SHADOW(3,RI), -+ E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR), -+ E100_STRUCT_PORT(3,CD), E100_STRUCT_SHADOW(3,CD), -+ E100_STRUCT_MASK(3,DTR), -+ E100_STRUCT_MASK(3,RI), -+ E100_STRUCT_MASK(3,DSR), -+ E100_STRUCT_MASK(3,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(3) -+#endif -+ } -+}; -+#else /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ -+ -+/* All pins are on either PA or PB for each serial port */ -+#define CONTROL_PINS_PORT_NOT_USED(line) \ -+ &dummy_ser[line], &dummy_ser[line], \ -+ DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK -+ -+ -+struct control_pins -+{ -+ volatile unsigned char *port; -+ unsigned char *shadow; -+ -+ unsigned char dtr_mask; -+ unsigned char ri_mask; -+ unsigned char dsr_mask; -+ unsigned char cd_mask; -+}; -+ -+#define dtr_port port -+#define dtr_shadow shadow -+#define ri_port port -+#define ri_shadow shadow -+#define dsr_port port -+#define dsr_shadow shadow -+#define cd_port port -+#define cd_shadow shadow -+ -+static const struct control_pins e100_modem_pins[NR_PORTS] = -+{ -+ /* Ser 0 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT0 -+ E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR), -+ E100_STRUCT_MASK(0,DTR), -+ E100_STRUCT_MASK(0,RI), -+ E100_STRUCT_MASK(0,DSR), -+ E100_STRUCT_MASK(0,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(0) -+#endif -+ }, -+ -+ /* Ser 1 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT1 -+ E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR), -+ E100_STRUCT_MASK(1,DTR), -+ E100_STRUCT_MASK(1,RI), -+ E100_STRUCT_MASK(1,DSR), -+ E100_STRUCT_MASK(1,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(1) -+#endif -+ }, -+ -+ /* Ser 2 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT2 -+ E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR), -+ E100_STRUCT_MASK(2,DTR), -+ E100_STRUCT_MASK(2,RI), -+ E100_STRUCT_MASK(2,DSR), -+ E100_STRUCT_MASK(2,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(2) -+#endif -+ }, -+ -+ /* Ser 3 */ -+ { -+#ifdef CONFIG_ETRAX_SERIAL_PORT3 -+ E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR), -+ E100_STRUCT_MASK(3,DTR), -+ E100_STRUCT_MASK(3,RI), -+ E100_STRUCT_MASK(3,DSR), -+ E100_STRUCT_MASK(3,CD) -+#else -+ CONTROL_PINS_PORT_NOT_USED(3) -+#endif -+ } -+}; -+#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ -+ -+#define E100_RTS_MASK 0x20 -+#define E100_CTS_MASK 0x40 -+ -+/* All serial port signals are active low: -+ * active = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level -+ * inactive = 1 -> 0V to RS-232 driver -> +12V on RS-232 level -+ * -+ * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip -+ */ -+ -+/* Output */ -+#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK) -+/* Input */ -+#define E100_CTS_GET(info) ((info)->ioport[REG_STATUS] & E100_CTS_MASK) -+ -+/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */ -+/* Is an output */ -+#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask) -+ -+/* Normally inputs */ -+#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask) -+#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask) -+ -+/* Input */ -+#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask) -+ -+ -+/* -+ * tmp_buf is used as a temporary buffer by serial_write. We need to -+ * lock it in case the memcpy_fromfs blocks while swapping in a page, -+ * and some other program tries to do a serial write at the same time. -+ * Since the lock will only come under contention when the system is -+ * swapping and available memory is low, it makes sense to share one -+ * buffer across all the serial ports, since it significantly saves -+ * memory if large numbers of serial ports are open. -+ */ -+static unsigned char *tmp_buf; -+static DEFINE_MUTEX(tmp_buf_mutex); -+ -+/* Calculate the chartime depending on baudrate, numbor of bits etc. */ -+static void update_char_time(struct e100_serial * info) -+{ -+ tcflag_t cflags = info->port.tty->termios->c_cflag; -+ int bits; -+ -+ /* calc. number of bits / data byte */ -+ /* databits + startbit and 1 stopbit */ -+ if ((cflags & CSIZE) == CS7) -+ bits = 9; -+ else -+ bits = 10; -+ -+ if (cflags & CSTOPB) /* 2 stopbits ? */ -+ bits++; -+ -+ if (cflags & PARENB) /* parity bit ? */ -+ bits++; -+ -+ /* calc timeout */ -+ info->char_time_usec = ((bits * 1000000) / info->baud) + 1; -+ info->flush_time_usec = 4*info->char_time_usec; -+ if (info->flush_time_usec < MIN_FLUSH_TIME_USEC) -+ info->flush_time_usec = MIN_FLUSH_TIME_USEC; -+ -+} -+ -+/* -+ * This function maps from the Bxxxx defines in asm/termbits.h into real -+ * baud rates. -+ */ -+ -+static int -+cflag_to_baud(unsigned int cflag) -+{ -+ static int baud_table[] = { -+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, -+ 4800, 9600, 19200, 38400 }; -+ -+ static int ext_baud_table[] = { -+ 0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000, -+ 0, 0, 0, 0, 0, 0, 0, 0 }; -+ -+ if (cflag & CBAUDEX) -+ return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; -+ else -+ return baud_table[cflag & CBAUD]; -+} -+ -+/* and this maps to an etrax100 hardware baud constant */ -+ -+static unsigned char -+cflag_to_etrax_baud(unsigned int cflag) -+{ -+ char retval; -+ -+ static char baud_table[] = { -+ -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 }; -+ -+ static char ext_baud_table[] = { -+ -1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 }; -+ -+ if (cflag & CBAUDEX) -+ retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; -+ else -+ retval = baud_table[cflag & CBAUD]; -+ -+ if (retval < 0) { -+ printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag); -+ retval = 5; /* choose default 9600 instead */ -+ } -+ -+ return retval | (retval << 4); /* choose same for both TX and RX */ -+} -+ -+ -+/* Various static support functions */ -+ -+/* Functions to set or clear DTR/RTS on the requested line */ -+/* It is complicated by the fact that RTS is a serial port register, while -+ * DTR might not be implemented in the HW at all, and if it is, it can be on -+ * any general port. -+ */ -+ -+ -+static inline void -+e100_dtr(struct e100_serial *info, int set) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ unsigned char mask = e100_modem_pins[info->line].dtr_mask; -+ -+#ifdef SERIAL_DEBUG_IO -+ printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask); -+ printk("ser%i shadow before 0x%02X get: %i\n", -+ info->line, *e100_modem_pins[info->line].dtr_shadow, -+ E100_DTR_GET(info)); -+#endif -+ /* DTR is active low */ -+ { -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ *e100_modem_pins[info->line].dtr_shadow &= ~mask; -+ *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); -+ *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow; -+ local_irq_restore(flags); -+ } -+ -+#ifdef SERIAL_DEBUG_IO -+ printk("ser%i shadow after 0x%02X get: %i\n", -+ info->line, *e100_modem_pins[info->line].dtr_shadow, -+ E100_DTR_GET(info)); -+#endif -+#endif -+} -+ -+/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive -+ * 0=0V , 1=3.3V -+ */ -+static inline void -+e100_rts(struct e100_serial *info, int set) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ unsigned long flags; -+ local_irq_save(flags); -+ info->rx_ctrl &= ~E100_RTS_MASK; -+ info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ -+ info->ioport[REG_REC_CTRL] = info->rx_ctrl; -+ local_irq_restore(flags); -+#ifdef SERIAL_DEBUG_IO -+ printk("ser%i rts %i\n", info->line, set); -+#endif -+#endif -+} -+ -+ -+/* If this behaves as a modem, RI and CD is an output */ -+static inline void -+e100_ri_out(struct e100_serial *info, int set) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ /* RI is active low */ -+ { -+ unsigned char mask = e100_modem_pins[info->line].ri_mask; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ *e100_modem_pins[info->line].ri_shadow &= ~mask; -+ *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); -+ *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow; -+ local_irq_restore(flags); -+ } -+#endif -+} -+static inline void -+e100_cd_out(struct e100_serial *info, int set) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ /* CD is active low */ -+ { -+ unsigned char mask = e100_modem_pins[info->line].cd_mask; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ *e100_modem_pins[info->line].cd_shadow &= ~mask; -+ *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); -+ *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow; -+ local_irq_restore(flags); -+ } -+#endif -+} -+ -+static inline void -+e100_disable_rx(struct e100_serial *info) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ /* disable the receiver */ -+ info->ioport[REG_REC_CTRL] = -+ (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -+#endif -+} -+ -+static inline void -+e100_enable_rx(struct e100_serial *info) -+{ -+#ifndef CONFIG_SVINTO_SIM -+ /* enable the receiver */ -+ info->ioport[REG_REC_CTRL] = -+ (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -+#endif -+} -+ -+/* the rx DMA uses both the dma_descr and the dma_eop interrupts */ -+ -+static inline void -+e100_disable_rxdma_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("rxdma_irq(%d): 0\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line)); -+ *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3); -+} -+ -+static inline void -+e100_enable_rxdma_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("rxdma_irq(%d): 1\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line)); -+ *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3); -+} -+ -+/* the tx DMA uses only dma_descr interrupt */ -+ -+static void e100_disable_txdma_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("txdma_irq(%d): 0\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line)); -+ *R_IRQ_MASK2_CLR = info->irq; -+} -+ -+static void e100_enable_txdma_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("txdma_irq(%d): 1\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line)); -+ *R_IRQ_MASK2_SET = info->irq; -+} -+ -+static void e100_disable_txdma_channel(struct e100_serial *info) -+{ -+ unsigned long flags; -+ -+ /* Disable output DMA channel for the serial port in question -+ * ( set to something other than serialX) -+ */ -+ local_irq_save(flags); -+ DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line)); -+ if (info->line == 0) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) == -+ IO_STATE(R_GEN_CONFIG, dma6, serial0)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); -+ } -+ } else if (info->line == 1) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) == -+ IO_STATE(R_GEN_CONFIG, dma8, serial1)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); -+ } -+ } else if (info->line == 2) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) == -+ IO_STATE(R_GEN_CONFIG, dma2, serial2)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); -+ } -+ } else if (info->line == 3) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) == -+ IO_STATE(R_GEN_CONFIG, dma4, serial3)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1); -+ } -+ } -+ *R_GEN_CONFIG = genconfig_shadow; -+ local_irq_restore(flags); -+} -+ -+ -+static void e100_enable_txdma_channel(struct e100_serial *info) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line)); -+ /* Enable output DMA channel for the serial port in question */ -+ if (info->line == 0) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0); -+ } else if (info->line == 1) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1); -+ } else if (info->line == 2) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2); -+ } else if (info->line == 3) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3); -+ } -+ *R_GEN_CONFIG = genconfig_shadow; -+ local_irq_restore(flags); -+} -+ -+static void e100_disable_rxdma_channel(struct e100_serial *info) -+{ -+ unsigned long flags; -+ -+ /* Disable input DMA channel for the serial port in question -+ * ( set to something other than serialX) -+ */ -+ local_irq_save(flags); -+ if (info->line == 0) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) == -+ IO_STATE(R_GEN_CONFIG, dma7, serial0)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused); -+ } -+ } else if (info->line == 1) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) == -+ IO_STATE(R_GEN_CONFIG, dma9, serial1)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma9); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb); -+ } -+ } else if (info->line == 2) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) == -+ IO_STATE(R_GEN_CONFIG, dma3, serial2)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0); -+ } -+ } else if (info->line == 3) { -+ if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) == -+ IO_STATE(R_GEN_CONFIG, dma5, serial3)) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1); -+ } -+ } -+ *R_GEN_CONFIG = genconfig_shadow; -+ local_irq_restore(flags); -+} -+ -+ -+static void e100_enable_rxdma_channel(struct e100_serial *info) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ /* Enable input DMA channel for the serial port in question */ -+ if (info->line == 0) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0); -+ } else if (info->line == 1) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma9); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1); -+ } else if (info->line == 2) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2); -+ } else if (info->line == 3) { -+ genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5); -+ genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3); -+ } -+ *R_GEN_CONFIG = genconfig_shadow; -+ local_irq_restore(flags); -+} -+ -+#ifdef SERIAL_HANDLE_EARLY_ERRORS -+/* in order to detect and fix errors on the first byte -+ we have to use the serial interrupts as well. */ -+ -+static inline void -+e100_disable_serial_data_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("ser_irq(%d): 0\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line)); -+ *R_IRQ_MASK1_CLR = (1U << (8+2*info->line)); -+} -+ -+static inline void -+e100_enable_serial_data_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("ser_irq(%d): 1\n",info->line); -+ printk("**** %d = %d\n", -+ (8+2*info->line), -+ (1U << (8+2*info->line))); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line)); -+ *R_IRQ_MASK1_SET = (1U << (8+2*info->line)); -+} -+#endif -+ -+static inline void -+e100_disable_serial_tx_ready_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("ser_tx_irq(%d): 0\n",info->line); -+#endif -+ DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line)); -+ *R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line)); -+} -+ -+static inline void -+e100_enable_serial_tx_ready_irq(struct e100_serial *info) -+{ -+#ifdef SERIAL_DEBUG_INTR -+ printk("ser_tx_irq(%d): 1\n",info->line); -+ printk("**** %d = %d\n", -+ (8+1+2*info->line), -+ (1U << (8+1+2*info->line))); -+#endif -+ DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line)); -+ *R_IRQ_MASK1_SET = (1U << (8+1+2*info->line)); -+} -+ -+static inline void e100_enable_rx_irq(struct e100_serial *info) -+{ -+ if (info->uses_dma_in) -+ e100_enable_rxdma_irq(info); -+ else -+ e100_enable_serial_data_irq(info); -+} -+static inline void e100_disable_rx_irq(struct e100_serial *info) -+{ -+ if (info->uses_dma_in) -+ e100_disable_rxdma_irq(info); -+ else -+ e100_disable_serial_data_irq(info); -+} -+ -+#if defined(CONFIG_ETRAX_RS485) -+/* Enable RS-485 mode on selected port. This is UGLY. */ -+static int -+e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r) -+{ -+ struct e100_serial * info = (struct e100_serial *)tty->driver_data; -+ -+#if defined(CONFIG_ETRAX_RS485_ON_PA) -+ *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); -+#endif -+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ rs485_port_g_bit, 1); -+#endif -+#if defined(CONFIG_ETRAX_RS485_LTC1387) -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1); -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1); -+#endif -+ -+ info->rs485 = *r; -+ -+ /* Maximum delay before RTS equal to 1000 */ -+ if (info->rs485.delay_rts_before_send >= 1000) -+ info->rs485.delay_rts_before_send = 1000; -+ -+/* printk("rts: on send = %i, after = %i, enabled = %i", -+ info->rs485.rts_on_send, -+ info->rs485.rts_after_sent, -+ info->rs485.enabled -+ ); -+*/ -+ return 0; -+} -+ -+static int -+e100_write_rs485(struct tty_struct *tty, -+ const unsigned char *buf, int count) -+{ -+ struct e100_serial * info = (struct e100_serial *)tty->driver_data; -+ int old_value = (info->rs485.flags) & SER_RS485_ENABLED; -+ -+ /* rs485 is always implicitly enabled if we're using the ioctl() -+ * but it doesn't have to be set in the serial_rs485 -+ * (to be backward compatible with old apps) -+ * So we store, set and restore it. -+ */ -+ info->rs485.flags |= SER_RS485_ENABLED; -+ /* rs_write now deals with RS485 if enabled */ -+ count = rs_write(tty, buf, count); -+ if (!old_value) -+ info->rs485.flags &= ~(SER_RS485_ENABLED); -+ return count; -+} -+ -+#ifdef CONFIG_ETRAX_FAST_TIMER -+/* Timer function to toggle RTS when using FAST_TIMER */ -+static void rs485_toggle_rts_timer_function(unsigned long data) -+{ -+ struct e100_serial *info = (struct e100_serial *)data; -+ -+ fast_timers_rs485[info->line].function = NULL; -+ e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND)); -+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) -+ e100_enable_rx(info); -+ e100_enable_rx_irq(info); -+#endif -+} -+#endif -+#endif /* CONFIG_ETRAX_RS485 */ -+ -+/* -+ * ------------------------------------------------------------ -+ * rs_stop() and rs_start() -+ * -+ * This routines are called before setting or resetting tty->stopped. -+ * They enable or disable transmitter using the XOFF registers, as necessary. -+ * ------------------------------------------------------------ -+ */ -+ -+static void -+rs_stop(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ if (info) { -+ unsigned long flags; -+ unsigned long xoff; -+ -+ local_irq_save(flags); -+ DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n", -+ CIRC_CNT(info->xmit.head, -+ info->xmit.tail,SERIAL_XMIT_SIZE))); -+ -+ xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, -+ STOP_CHAR(info->port.tty)); -+ xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop); -+ if (tty->termios->c_iflag & IXON ) { -+ xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); -+ } -+ -+ *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; -+ local_irq_restore(flags); -+ } -+} -+ -+static void -+rs_start(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ if (info) { -+ unsigned long flags; -+ unsigned long xoff; -+ -+ local_irq_save(flags); -+ DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n", -+ CIRC_CNT(info->xmit.head, -+ info->xmit.tail,SERIAL_XMIT_SIZE))); -+ xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty)); -+ xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); -+ if (tty->termios->c_iflag & IXON ) { -+ xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); -+ } -+ -+ *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; -+ if (!info->uses_dma_out && -+ info->xmit.head != info->xmit.tail && info->xmit.buf) -+ e100_enable_serial_tx_ready_irq(info); -+ -+ local_irq_restore(flags); -+ } -+} -+ -+/* -+ * ---------------------------------------------------------------------- -+ * -+ * Here starts the interrupt handling routines. All of the following -+ * subroutines are declared as inline and are folded into -+ * rs_interrupt(). They were separated out for readability's sake. -+ * -+ * Note: rs_interrupt() is a "fast" interrupt, which means that it -+ * runs with interrupts turned off. People who may want to modify -+ * rs_interrupt() should try to keep the interrupt handler as fast as -+ * possible. After you are done making modifications, it is not a bad -+ * idea to do: -+ * -+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c -+ * -+ * and look at the resulting assemble code in serial.s. -+ * -+ * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 -+ * ----------------------------------------------------------------------- -+ */ -+ -+/* -+ * This routine is used by the interrupt handler to schedule -+ * processing in the software interrupt portion of the driver. -+ */ -+static void rs_sched_event(struct e100_serial *info, int event) -+{ -+ if (info->event & (1 << event)) -+ return; -+ info->event |= 1 << event; -+ schedule_work(&info->work); -+} -+ -+/* The output DMA channel is free - use it to send as many chars as possible -+ * NOTES: -+ * We don't pay attention to info->x_char, which means if the TTY wants to -+ * use XON/XOFF it will set info->x_char but we won't send any X char! -+ * -+ * To implement this, we'd just start a DMA send of 1 byte pointing at a -+ * buffer containing the X char, and skip updating xmit. We'd also have to -+ * check if the last sent char was the X char when we enter this function -+ * the next time, to avoid updating xmit with the sent X value. -+ */ -+ -+static void -+transmit_chars_dma(struct e100_serial *info) -+{ -+ unsigned int c, sentl; -+ struct etrax_dma_descr *descr; -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* This will output too little if tail is not 0 always since -+ * we don't reloop to send the other part. Anyway this SHOULD be a -+ * no-op - transmit_chars_dma would never really be called during sim -+ * since rs_write does not write into the xmit buffer then. -+ */ -+ if (info->xmit.tail) -+ printk("Error in serial.c:transmit_chars-dma(), tail!=0\n"); -+ if (info->xmit.head != info->xmit.tail) { -+ SIMCOUT(info->xmit.buf + info->xmit.tail, -+ CIRC_CNT(info->xmit.head, -+ info->xmit.tail, -+ SERIAL_XMIT_SIZE)); -+ info->xmit.head = info->xmit.tail; /* move back head */ -+ info->tr_running = 0; -+ } -+ return; -+#endif -+ /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ -+ *info->oclrintradr = -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); -+ -+#ifdef SERIAL_DEBUG_INTR -+ if (info->line == SERIAL_DEBUG_LINE) -+ printk("tc\n"); -+#endif -+ if (!info->tr_running) { -+ /* weirdo... we shouldn't get here! */ -+ printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n"); -+ return; -+ } -+ -+ descr = &info->tr_descr; -+ -+ /* first get the amount of bytes sent during the last DMA transfer, -+ and update xmit accordingly */ -+ -+ /* if the stop bit was not set, all data has been sent */ -+ if (!(descr->status & d_stop)) { -+ sentl = descr->sw_len; -+ } else -+ /* otherwise we find the amount of data sent here */ -+ sentl = descr->hw_len; -+ -+ DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl)); -+ -+ /* update stats */ -+ info->icount.tx += sentl; -+ -+ /* update xmit buffer */ -+ info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1); -+ -+ /* if there is only a few chars left in the buf, wake up the blocked -+ write if any */ -+ if (CIRC_CNT(info->xmit.head, -+ info->xmit.tail, -+ SERIAL_XMIT_SIZE) < WAKEUP_CHARS) -+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); -+ -+ /* find out the largest amount of consecutive bytes we want to send now */ -+ -+ c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -+ -+ /* Don't send all in one DMA transfer - divide it so we wake up -+ * application before all is sent -+ */ -+ -+ if (c >= 4*WAKEUP_CHARS) -+ c = c/2; -+ -+ if (c <= 0) { -+ /* our job here is done, don't schedule any new DMA transfer */ -+ info->tr_running = 0; -+ -+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) -+ if (info->rs485.flags & SER_RS485_ENABLED) { -+ /* Set a short timer to toggle RTS */ -+ start_one_shot_timer(&fast_timers_rs485[info->line], -+ rs485_toggle_rts_timer_function, -+ (unsigned long)info, -+ info->char_time_usec*2, -+ "RS-485"); -+ } -+#endif /* RS485 */ -+ return; -+ } -+ -+ /* ok we can schedule a dma send of c chars starting at info->xmit.tail */ -+ /* set up the descriptor correctly for output */ -+ DFLOW(DEBUG_LOG(info->line, "TX %i\n", c)); -+ descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */ -+ descr->sw_len = c; -+ descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail); -+ descr->status = 0; -+ -+ *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */ -+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); -+ -+ /* DMA is now running (hopefully) */ -+} /* transmit_chars_dma */ -+ -+static void -+start_transmit(struct e100_serial *info) -+{ -+#if 0 -+ if (info->line == SERIAL_DEBUG_LINE) -+ printk("x\n"); -+#endif -+ -+ info->tr_descr.sw_len = 0; -+ info->tr_descr.hw_len = 0; -+ info->tr_descr.status = 0; -+ info->tr_running = 1; -+ if (info->uses_dma_out) -+ transmit_chars_dma(info); -+ else -+ e100_enable_serial_tx_ready_irq(info); -+} /* start_transmit */ -+ -+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -+static int serial_fast_timer_started = 0; -+static int serial_fast_timer_expired = 0; -+static void flush_timeout_function(unsigned long data); -+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\ -+ unsigned long timer_flags; \ -+ local_irq_save(timer_flags); \ -+ if (fast_timers[info->line].function == NULL) { \ -+ serial_fast_timer_started++; \ -+ TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \ -+ TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \ -+ start_one_shot_timer(&fast_timers[info->line], \ -+ flush_timeout_function, \ -+ (unsigned long)info, \ -+ (usec), \ -+ string); \ -+ } \ -+ else { \ -+ TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \ -+ } \ -+ local_irq_restore(timer_flags); \ -+} -+#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec) -+ -+#else -+#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) -+#define START_FLUSH_FAST_TIMER(info, string) -+#endif -+ -+static struct etrax_recv_buffer * -+alloc_recv_buffer(unsigned int size) -+{ -+ struct etrax_recv_buffer *buffer; -+ -+ if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC))) -+ return NULL; -+ -+ buffer->next = NULL; -+ buffer->length = 0; -+ buffer->error = TTY_NORMAL; -+ -+ return buffer; -+} -+ -+static void -+append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ if (!info->first_recv_buffer) -+ info->first_recv_buffer = buffer; -+ else -+ info->last_recv_buffer->next = buffer; -+ -+ info->last_recv_buffer = buffer; -+ -+ info->recv_cnt += buffer->length; -+ if (info->recv_cnt > info->max_recv_cnt) -+ info->max_recv_cnt = info->recv_cnt; -+ -+ local_irq_restore(flags); -+} -+ -+static int -+add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag) -+{ -+ struct etrax_recv_buffer *buffer; -+ if (info->uses_dma_in) { -+ if (!(buffer = alloc_recv_buffer(4))) -+ return 0; -+ -+ buffer->length = 1; -+ buffer->error = flag; -+ buffer->buffer[0] = data; -+ -+ append_recv_buffer(info, buffer); -+ -+ info->icount.rx++; -+ } else { -+ struct tty_struct *tty = info->port.tty; -+ tty_insert_flip_char(tty, data, flag); -+ info->icount.rx++; -+ } -+ -+ return 1; -+} -+ -+static unsigned int handle_descr_data(struct e100_serial *info, -+ struct etrax_dma_descr *descr, -+ unsigned int recvl) -+{ -+ struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer; -+ -+ if (info->recv_cnt + recvl > 65536) { -+ printk(KERN_CRIT -+ "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl); -+ return 0; -+ } -+ -+ buffer->length = recvl; -+ -+ if (info->errorcode == ERRCODE_SET_BREAK) -+ buffer->error = TTY_BREAK; -+ info->errorcode = 0; -+ -+ append_recv_buffer(info, buffer); -+ -+ if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) -+ panic("%s: Failed to allocate memory for receive buffer!\n", __func__); -+ -+ descr->buf = virt_to_phys(buffer->buffer); -+ -+ return recvl; -+} -+ -+static unsigned int handle_all_descr_data(struct e100_serial *info) -+{ -+ struct etrax_dma_descr *descr; -+ unsigned int recvl; -+ unsigned int ret = 0; -+ -+ while (1) -+ { -+ descr = &info->rec_descr[info->cur_rec_descr]; -+ -+ if (descr == phys_to_virt(*info->idescradr)) -+ break; -+ -+ if (++info->cur_rec_descr == SERIAL_RECV_DESCRIPTORS) -+ info->cur_rec_descr = 0; -+ -+ /* find out how many bytes were read */ -+ -+ /* if the eop bit was not set, all data has been received */ -+ if (!(descr->status & d_eop)) { -+ recvl = descr->sw_len; -+ } else { -+ /* otherwise we find the amount of data received here */ -+ recvl = descr->hw_len; -+ } -+ -+ /* Reset the status information */ -+ descr->status = 0; -+ -+ DFLOW( DEBUG_LOG(info->line, "RX %lu\n", recvl); -+ if (info->port.tty->stopped) { -+ unsigned char *buf = phys_to_virt(descr->buf); -+ DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]); -+ DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]); -+ DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]); -+ } -+ ); -+ -+ /* update stats */ -+ info->icount.rx += recvl; -+ -+ ret += handle_descr_data(info, descr, recvl); -+ } -+ -+ return ret; -+} -+ -+static void receive_chars_dma(struct e100_serial *info) -+{ -+ struct tty_struct *tty; -+ unsigned char rstat; -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* No receive in the simulator. Will probably be when the rest of -+ * the serial interface works, and this piece will just be removed. -+ */ -+ return; -+#endif -+ -+ /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ -+ *info->iclrintradr = -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); -+ -+ tty = info->port.tty; -+ if (!tty) /* Something wrong... */ -+ return; -+ -+#ifdef SERIAL_HANDLE_EARLY_ERRORS -+ if (info->uses_dma_in) -+ e100_enable_serial_data_irq(info); -+#endif -+ -+ if (info->errorcode == ERRCODE_INSERT_BREAK) -+ add_char_and_flag(info, '\0', TTY_BREAK); -+ -+ handle_all_descr_data(info); -+ -+ /* Read the status register to detect errors */ -+ rstat = info->ioport[REG_STATUS]; -+ if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { -+ DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat)); -+ } -+ -+ if (rstat & SER_ERROR_MASK) { -+ /* If we got an error, we must reset it by reading the -+ * data_in field -+ */ -+ unsigned char data = info->ioport[REG_DATA]; -+ -+ PROCSTAT(ser_stat[info->line].errors_cnt++); -+ DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n", -+ ((rstat & SER_ERROR_MASK) << 8) | data); -+ -+ if (rstat & SER_PAR_ERR_MASK) -+ add_char_and_flag(info, data, TTY_PARITY); -+ else if (rstat & SER_OVERRUN_MASK) -+ add_char_and_flag(info, data, TTY_OVERRUN); -+ else if (rstat & SER_FRAMING_ERR_MASK) -+ add_char_and_flag(info, data, TTY_FRAME); -+ } -+ -+ START_FLUSH_FAST_TIMER(info, "receive_chars"); -+ -+ /* Restart the receiving DMA */ -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); -+} -+ -+static int start_recv_dma(struct e100_serial *info) -+{ -+ struct etrax_dma_descr *descr = info->rec_descr; -+ struct etrax_recv_buffer *buffer; -+ int i; -+ -+ /* Set up the receiving descriptors */ -+ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { -+ if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) -+ panic("%s: Failed to allocate memory for receive buffer!\n", __func__); -+ -+ descr[i].ctrl = d_int; -+ descr[i].buf = virt_to_phys(buffer->buffer); -+ descr[i].sw_len = SERIAL_DESCR_BUF_SIZE; -+ descr[i].hw_len = 0; -+ descr[i].status = 0; -+ descr[i].next = virt_to_phys(&descr[i+1]); -+ } -+ -+ /* Link the last descriptor to the first */ -+ descr[i-1].next = virt_to_phys(&descr[0]); -+ -+ /* Start with the first descriptor in the list */ -+ info->cur_rec_descr = 0; -+ -+ /* Start the DMA */ -+ *info->ifirstadr = virt_to_phys(&descr[info->cur_rec_descr]); -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); -+ -+ /* Input DMA should be running now */ -+ return 1; -+} -+ -+static void -+start_receive(struct e100_serial *info) -+{ -+#ifdef CONFIG_SVINTO_SIM -+ /* No receive in the simulator. Will probably be when the rest of -+ * the serial interface works, and this piece will just be removed. -+ */ -+ return; -+#endif -+ if (info->uses_dma_in) { -+ /* reset the input dma channel to be sure it works */ -+ -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); -+ while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == -+ IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); -+ -+ start_recv_dma(info); -+ } -+} -+ -+ -+/* the bits in the MASK2 register are laid out like this: -+ DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR -+ where I is the input channel and O is the output channel for the port. -+ info->irq is the bit number for the DMAO_DESCR so to check the others we -+ shift info->irq to the left. -+*/ -+ -+/* dma output channel interrupt handler -+ this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or -+ DMA8(ser1) when they have finished a descriptor with the intr flag set. -+*/ -+ -+static irqreturn_t -+tr_interrupt(int irq, void *dev_id) -+{ -+ struct e100_serial *info; -+ unsigned long ireg; -+ int i; -+ int handled = 0; -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* No receive in the simulator. Will probably be when the rest of -+ * the serial interface works, and this piece will just be removed. -+ */ -+ { -+ const char *s = "What? tr_interrupt in simulator??\n"; -+ SIMCOUT(s,strlen(s)); -+ } -+ return IRQ_HANDLED; -+#endif -+ -+ /* find out the line that caused this irq and get it from rs_table */ -+ -+ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ info = rs_table + i; -+ if (!info->enabled || !info->uses_dma_out) -+ continue; -+ /* check for dma_descr (don't need to check for dma_eop in output dma for serial */ -+ if (ireg & info->irq) { -+ handled = 1; -+ /* we can send a new dma bunch. make it so. */ -+ DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i)); -+ /* Read jiffies_usec first, -+ * we want this time to be as late as possible -+ */ -+ PROCSTAT(ser_stat[info->line].tx_dma_ints++); -+ info->last_tx_active_usec = GET_JIFFIES_USEC(); -+ info->last_tx_active = jiffies; -+ transmit_chars_dma(info); -+ } -+ -+ /* FIXME: here we should really check for a change in the -+ status lines and if so call status_handle(info) */ -+ } -+ return IRQ_RETVAL(handled); -+} /* tr_interrupt */ -+ -+/* dma input channel interrupt handler */ -+ -+static irqreturn_t -+rec_interrupt(int irq, void *dev_id) -+{ -+ struct e100_serial *info; -+ unsigned long ireg; -+ int i; -+ int handled = 0; -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* No receive in the simulator. Will probably be when the rest of -+ * the serial interface works, and this piece will just be removed. -+ */ -+ { -+ const char *s = "What? rec_interrupt in simulator??\n"; -+ SIMCOUT(s,strlen(s)); -+ } -+ return IRQ_HANDLED; -+#endif -+ -+ /* find out the line that caused this irq and get it from rs_table */ -+ -+ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ info = rs_table + i; -+ if (!info->enabled || !info->uses_dma_in) -+ continue; -+ /* check for both dma_eop and dma_descr for the input dma channel */ -+ if (ireg & ((info->irq << 2) | (info->irq << 3))) { -+ handled = 1; -+ /* we have received something */ -+ receive_chars_dma(info); -+ } -+ -+ /* FIXME: here we should really check for a change in the -+ status lines and if so call status_handle(info) */ -+ } -+ return IRQ_RETVAL(handled); -+} /* rec_interrupt */ -+ -+static int force_eop_if_needed(struct e100_serial *info) -+{ -+ /* We check data_avail bit to determine if data has -+ * arrived since last time -+ */ -+ unsigned char rstat = info->ioport[REG_STATUS]; -+ -+ /* error or datavail? */ -+ if (rstat & SER_ERROR_MASK) { -+ /* Some error has occurred. If there has been valid data, an -+ * EOP interrupt will be made automatically. If no data, the -+ * normal ser_interrupt should be enabled and handle it. -+ * So do nothing! -+ */ -+ DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n", -+ rstat | (info->line << 8)); -+ return 0; -+ } -+ -+ if (rstat & SER_DATA_AVAIL_MASK) { -+ /* Ok data, no error, count it */ -+ TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n", -+ rstat | (info->line << 8))); -+ /* Read data to clear status flags */ -+ (void)info->ioport[REG_DATA]; -+ -+ info->forced_eop = 0; -+ START_FLUSH_FAST_TIMER(info, "magic"); -+ return 0; -+ } -+ -+ /* hit the timeout, force an EOP for the input -+ * dma channel if we haven't already -+ */ -+ if (!info->forced_eop) { -+ info->forced_eop = 1; -+ PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); -+ TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line)); -+ FORCE_EOP(info); -+ } -+ -+ return 1; -+} -+ -+static void flush_to_flip_buffer(struct e100_serial *info) -+{ -+ struct tty_struct *tty; -+ struct etrax_recv_buffer *buffer; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ tty = info->port.tty; -+ -+ if (!tty) { -+ local_irq_restore(flags); -+ return; -+ } -+ -+ while ((buffer = info->first_recv_buffer) != NULL) { -+ unsigned int count = buffer->length; -+ -+ tty_insert_flip_string(tty, buffer->buffer, count); -+ info->recv_cnt -= count; -+ -+ if (count == buffer->length) { -+ info->first_recv_buffer = buffer->next; -+ kfree(buffer); -+ } else { -+ buffer->length -= count; -+ memmove(buffer->buffer, buffer->buffer + count, buffer->length); -+ buffer->error = TTY_NORMAL; -+ } -+ } -+ -+ if (!info->first_recv_buffer) -+ info->last_recv_buffer = NULL; -+ -+ local_irq_restore(flags); -+ -+ /* This includes a check for low-latency */ -+ tty_flip_buffer_push(tty); -+} -+ -+static void check_flush_timeout(struct e100_serial *info) -+{ -+ /* Flip what we've got (if we can) */ -+ flush_to_flip_buffer(info); -+ -+ /* We might need to flip later, but not to fast -+ * since the system is busy processing input... */ -+ if (info->first_recv_buffer) -+ START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000); -+ -+ /* Force eop last, since data might have come while we're processing -+ * and if we started the slow timer above, we won't start a fast -+ * below. -+ */ -+ force_eop_if_needed(info); -+} -+ -+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -+static void flush_timeout_function(unsigned long data) -+{ -+ struct e100_serial *info = (struct e100_serial *)data; -+ -+ fast_timers[info->line].function = NULL; -+ serial_fast_timer_expired++; -+ TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line)); -+ TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired)); -+ check_flush_timeout(info); -+} -+ -+#else -+ -+/* dma fifo/buffer timeout handler -+ forces an end-of-packet for the dma input channel if no chars -+ have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s. -+*/ -+ -+static struct timer_list flush_timer; -+ -+static void -+timed_flush_handler(unsigned long ptr) -+{ -+ struct e100_serial *info; -+ int i; -+ -+#ifdef CONFIG_SVINTO_SIM -+ return; -+#endif -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ info = rs_table + i; -+ if (info->uses_dma_in) -+ check_flush_timeout(info); -+ } -+ -+ /* restart flush timer */ -+ mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS); -+} -+#endif -+ -+#ifdef SERIAL_HANDLE_EARLY_ERRORS -+ -+/* If there is an error (ie break) when the DMA is running and -+ * there are no bytes in the fifo the DMA is stopped and we get no -+ * eop interrupt. Thus we have to monitor the first bytes on a DMA -+ * transfer, and if it is without error we can turn the serial -+ * interrupts off. -+ */ -+ -+/* -+BREAK handling on ETRAX 100: -+ETRAX will generate interrupt although there is no stop bit between the -+characters. -+ -+Depending on how long the break sequence is, the end of the breaksequence -+will look differently: -+| indicates start/end of a character. -+ -+B= Break character (0x00) with framing error. -+E= Error byte with parity error received after B characters. -+F= "Faked" valid byte received immediately after B characters. -+V= Valid byte -+ -+1. -+ B BL ___________________________ V -+.._|__________|__________| |valid data | -+ -+Multiple frame errors with data == 0x00 (B), -+the timing matches up "perfectly" so no extra ending char is detected. -+The RXD pin is 1 in the last interrupt, in that case -+we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really -+know if another byte will come and this really is case 2. below -+(e.g F=0xFF or 0xFE) -+If RXD pin is 0 we can expect another character (see 2. below). -+ -+ -+2. -+ -+ B B E or F__________________..__ V -+.._|__________|__________|______ | |valid data -+ "valid" or -+ parity error -+ -+Multiple frame errors with data == 0x00 (B), -+but the part of the break trigs is interpreted as a start bit (and possibly -+some 0 bits followed by a number of 1 bits and a stop bit). -+Depending on parity settings etc. this last character can be either -+a fake "valid" char (F) or have a parity error (E). -+ -+If the character is valid it will be put in the buffer, -+we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt -+will set the flags so the tty will handle it, -+if it's an error byte it will not be put in the buffer -+and we set info->errorcode = ERRCODE_INSERT_BREAK. -+ -+To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp -+of the last faulty char (B) and compares it with the current time: -+If the time elapsed time is less then 2*char_time_usec we will assume -+it's a faked F char and not a Valid char and set -+info->errorcode = ERRCODE_SET_BREAK. -+ -+Flaws in the above solution: -+~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+We use the timer to distinguish a F character from a V character, -+if a V character is to close after the break we might make the wrong decision. -+ -+TODO: The break will be delayed until an F or V character is received. -+ -+*/ -+ -+static -+struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info) -+{ -+ unsigned long data_read; -+ struct tty_struct *tty = info->port.tty; -+ -+ if (!tty) { -+ printk("!NO TTY!\n"); -+ return info; -+ } -+ -+ /* Read data and status at the same time */ -+ data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); -+more_data: -+ if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) { -+ DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); -+ } -+ DINTR2(DEBUG_LOG(info->line, "ser_rx %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read))); -+ -+ if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) | -+ IO_MASK(R_SERIAL0_READ, par_err) | -+ IO_MASK(R_SERIAL0_READ, overrun) )) { -+ /* An error */ -+ info->last_rx_active_usec = GET_JIFFIES_USEC(); -+ info->last_rx_active = jiffies; -+ DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read)); -+ DLOG_INT_TRIG( -+ if (!log_int_trig1_pos) { -+ log_int_trig1_pos = log_int_pos; -+ log_int(rdpc(), 0, 0); -+ } -+ ); -+ -+ -+ if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) && -+ (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) { -+ /* Most likely a break, but we get interrupts over and -+ * over again. -+ */ -+ -+ if (!info->break_detected_cnt) { -+ DEBUG_LOG(info->line, "#BRK start\n", 0); -+ } -+ if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) { -+ /* The RX pin is high now, so the break -+ * must be over, but.... -+ * we can't really know if we will get another -+ * last byte ending the break or not. -+ * And we don't know if the byte (if any) will -+ * have an error or look valid. -+ */ -+ DEBUG_LOG(info->line, "# BL BRK\n", 0); -+ info->errorcode = ERRCODE_INSERT_BREAK; -+ } -+ info->break_detected_cnt++; -+ } else { -+ /* The error does not look like a break, but could be -+ * the end of one -+ */ -+ if (info->break_detected_cnt) { -+ DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); -+ info->errorcode = ERRCODE_INSERT_BREAK; -+ } else { -+ unsigned char data = IO_EXTRACT(R_SERIAL0_READ, -+ data_in, data_read); -+ char flag = TTY_NORMAL; -+ if (info->errorcode == ERRCODE_INSERT_BREAK) { -+ struct tty_struct *tty = info->port.tty; -+ tty_insert_flip_char(tty, 0, flag); -+ info->icount.rx++; -+ } -+ -+ if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) { -+ info->icount.parity++; -+ flag = TTY_PARITY; -+ } else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) { -+ info->icount.overrun++; -+ flag = TTY_OVERRUN; -+ } else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) { -+ info->icount.frame++; -+ flag = TTY_FRAME; -+ } -+ tty_insert_flip_char(tty, data, flag); -+ info->errorcode = 0; -+ } -+ info->break_detected_cnt = 0; -+ } -+ } else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) { -+ /* No error */ -+ DLOG_INT_TRIG( -+ if (!log_int_trig1_pos) { -+ if (log_int_pos >= log_int_size) { -+ log_int_pos = 0; -+ } -+ log_int_trig0_pos = log_int_pos; -+ log_int(rdpc(), 0, 0); -+ } -+ ); -+ tty_insert_flip_char(tty, -+ IO_EXTRACT(R_SERIAL0_READ, data_in, data_read), -+ TTY_NORMAL); -+ } else { -+ DEBUG_LOG(info->line, "ser_rx int but no data_avail %08lX\n", data_read); -+ } -+ -+ -+ info->icount.rx++; -+ data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]); -+ if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) { -+ DEBUG_LOG(info->line, "ser_rx %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)); -+ goto more_data; -+ } -+ -+ tty_flip_buffer_push(info->port.tty); -+ return info; -+} -+ -+static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info) -+{ -+ unsigned char rstat; -+ -+#ifdef SERIAL_DEBUG_INTR -+ printk("Interrupt from serport %d\n", i); -+#endif -+/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */ -+ if (!info->uses_dma_in) { -+ return handle_ser_rx_interrupt_no_dma(info); -+ } -+ /* DMA is used */ -+ rstat = info->ioport[REG_STATUS]; -+ if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) { -+ DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0)); -+ } -+ -+ if (rstat & SER_ERROR_MASK) { -+ unsigned char data; -+ -+ info->last_rx_active_usec = GET_JIFFIES_USEC(); -+ info->last_rx_active = jiffies; -+ /* If we got an error, we must reset it by reading the -+ * data_in field -+ */ -+ data = info->ioport[REG_DATA]; -+ DINTR1(DEBUG_LOG(info->line, "ser_rx! %c\n", data)); -+ DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat)); -+ if (!data && (rstat & SER_FRAMING_ERR_MASK)) { -+ /* Most likely a break, but we get interrupts over and -+ * over again. -+ */ -+ -+ if (!info->break_detected_cnt) { -+ DEBUG_LOG(info->line, "#BRK start\n", 0); -+ } -+ if (rstat & SER_RXD_MASK) { -+ /* The RX pin is high now, so the break -+ * must be over, but.... -+ * we can't really know if we will get another -+ * last byte ending the break or not. -+ * And we don't know if the byte (if any) will -+ * have an error or look valid. -+ */ -+ DEBUG_LOG(info->line, "# BL BRK\n", 0); -+ info->errorcode = ERRCODE_INSERT_BREAK; -+ } -+ info->break_detected_cnt++; -+ } else { -+ /* The error does not look like a break, but could be -+ * the end of one -+ */ -+ if (info->break_detected_cnt) { -+ DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); -+ info->errorcode = ERRCODE_INSERT_BREAK; -+ } else { -+ if (info->errorcode == ERRCODE_INSERT_BREAK) { -+ info->icount.brk++; -+ add_char_and_flag(info, '\0', TTY_BREAK); -+ } -+ -+ if (rstat & SER_PAR_ERR_MASK) { -+ info->icount.parity++; -+ add_char_and_flag(info, data, TTY_PARITY); -+ } else if (rstat & SER_OVERRUN_MASK) { -+ info->icount.overrun++; -+ add_char_and_flag(info, data, TTY_OVERRUN); -+ } else if (rstat & SER_FRAMING_ERR_MASK) { -+ info->icount.frame++; -+ add_char_and_flag(info, data, TTY_FRAME); -+ } -+ -+ info->errorcode = 0; -+ } -+ info->break_detected_cnt = 0; -+ DEBUG_LOG(info->line, "#iERR s d %04X\n", -+ ((rstat & SER_ERROR_MASK) << 8) | data); -+ } -+ PROCSTAT(ser_stat[info->line].early_errors_cnt++); -+ } else { /* It was a valid byte, now let the DMA do the rest */ -+ unsigned long curr_time_u = GET_JIFFIES_USEC(); -+ unsigned long curr_time = jiffies; -+ -+ if (info->break_detected_cnt) { -+ /* Detect if this character is a new valid char or the -+ * last char in a break sequence: If LSBits are 0 and -+ * MSBits are high AND the time is close to the -+ * previous interrupt we should discard it. -+ */ -+ long elapsed_usec = -+ (curr_time - info->last_rx_active) * (1000000/HZ) + -+ curr_time_u - info->last_rx_active_usec; -+ if (elapsed_usec < 2*info->char_time_usec) { -+ DEBUG_LOG(info->line, "FBRK %i\n", info->line); -+ /* Report as BREAK (error) and let -+ * receive_chars_dma() handle it -+ */ -+ info->errorcode = ERRCODE_SET_BREAK; -+ } else { -+ DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line); -+ } -+ DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt); -+ } -+ -+#ifdef SERIAL_DEBUG_INTR -+ printk("** OK, disabling ser_interrupts\n"); -+#endif -+ e100_disable_serial_data_irq(info); -+ DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line)); -+ info->break_detected_cnt = 0; -+ -+ PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); -+ } -+ /* Restarting the DMA never hurts */ -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); -+ START_FLUSH_FAST_TIMER(info, "ser_int"); -+ return info; -+} /* handle_ser_rx_interrupt */ -+ -+static void handle_ser_tx_interrupt(struct e100_serial *info) -+{ -+ unsigned long flags; -+ -+ if (info->x_char) { -+ unsigned char rstat; -+ DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char)); -+ local_irq_save(flags); -+ rstat = info->ioport[REG_STATUS]; -+ DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); -+ -+ info->ioport[REG_TR_DATA] = info->x_char; -+ info->icount.tx++; -+ info->x_char = 0; -+ /* We must enable since it is disabled in ser_interrupt */ -+ e100_enable_serial_tx_ready_irq(info); -+ local_irq_restore(flags); -+ return; -+ } -+ if (info->uses_dma_out) { -+ unsigned char rstat; -+ int i; -+ /* We only use normal tx interrupt when sending x_char */ -+ DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0)); -+ local_irq_save(flags); -+ rstat = info->ioport[REG_STATUS]; -+ DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat)); -+ e100_disable_serial_tx_ready_irq(info); -+ if (info->port.tty->stopped) -+ rs_stop(info->port.tty); -+ /* Enable the DMA channel and tell it to continue */ -+ e100_enable_txdma_channel(info); -+ /* Wait 12 cycles before doing the DMA command */ -+ for(i = 6; i > 0; i--) -+ nop(); -+ -+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue); -+ local_irq_restore(flags); -+ return; -+ } -+ /* Normal char-by-char interrupt */ -+ if (info->xmit.head == info->xmit.tail -+ || info->port.tty->stopped -+ || info->port.tty->hw_stopped) { -+ DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", -+ info->port.tty->stopped)); -+ e100_disable_serial_tx_ready_irq(info); -+ info->tr_running = 0; -+ return; -+ } -+ DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail])); -+ /* Send a byte, rs485 timing is critical so turn of ints */ -+ local_irq_save(flags); -+ info->ioport[REG_TR_DATA] = info->xmit.buf[info->xmit.tail]; -+ info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1); -+ info->icount.tx++; -+ if (info->xmit.head == info->xmit.tail) { -+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) -+ if (info->rs485.flags & SER_RS485_ENABLED) { -+ /* Set a short timer to toggle RTS */ -+ start_one_shot_timer(&fast_timers_rs485[info->line], -+ rs485_toggle_rts_timer_function, -+ (unsigned long)info, -+ info->char_time_usec*2, -+ "RS-485"); -+ } -+#endif /* RS485 */ -+ info->last_tx_active_usec = GET_JIFFIES_USEC(); -+ info->last_tx_active = jiffies; -+ e100_disable_serial_tx_ready_irq(info); -+ info->tr_running = 0; -+ DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0)); -+ } else { -+ /* We must enable since it is disabled in ser_interrupt */ -+ e100_enable_serial_tx_ready_irq(info); -+ } -+ local_irq_restore(flags); -+ -+ if (CIRC_CNT(info->xmit.head, -+ info->xmit.tail, -+ SERIAL_XMIT_SIZE) < WAKEUP_CHARS) -+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); -+ -+} /* handle_ser_tx_interrupt */ -+ -+/* result of time measurements: -+ * RX duration 54-60 us when doing something, otherwise 6-9 us -+ * ser_int duration: just sending: 8-15 us normally, up to 73 us -+ */ -+static irqreturn_t -+ser_interrupt(int irq, void *dev_id) -+{ -+ static volatile int tx_started = 0; -+ struct e100_serial *info; -+ int i; -+ unsigned long flags; -+ unsigned long irq_mask1_rd; -+ unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */ -+ int handled = 0; -+ static volatile unsigned long reentered_ready_mask = 0; -+ -+ local_irq_save(flags); -+ irq_mask1_rd = *R_IRQ_MASK1_RD; -+ /* First handle all rx interrupts with ints disabled */ -+ info = rs_table; -+ irq_mask1_rd &= e100_ser_int_mask; -+ for (i = 0; i < NR_PORTS; i++) { -+ /* Which line caused the data irq? */ -+ if (irq_mask1_rd & data_mask) { -+ handled = 1; -+ handle_ser_rx_interrupt(info); -+ } -+ info += 1; -+ data_mask <<= 2; -+ } -+ /* Handle tx interrupts with interrupts enabled so we -+ * can take care of new data interrupts while transmitting -+ * We protect the tx part with the tx_started flag. -+ * We disable the tr_ready interrupts we are about to handle and -+ * unblock the serial interrupt so new serial interrupts may come. -+ * -+ * If we get a new interrupt: -+ * - it migth be due to synchronous serial ports. -+ * - serial irq will be blocked by general irq handler. -+ * - async data will be handled above (sync will be ignored). -+ * - tx_started flag will prevent us from trying to send again and -+ * we will exit fast - no need to unblock serial irq. -+ * - Next (sync) serial interrupt handler will be runned with -+ * disabled interrupt due to restore_flags() at end of function, -+ * so sync handler will not be preempted or reentered. -+ */ -+ if (!tx_started) { -+ unsigned long ready_mask; -+ unsigned long -+ tx_started = 1; -+ /* Only the tr_ready interrupts left */ -+ irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser1_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser2_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser3_ready)); -+ while (irq_mask1_rd) { -+ /* Disable those we are about to handle */ -+ *R_IRQ_MASK1_CLR = irq_mask1_rd; -+ /* Unblock the serial interrupt */ -+ *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set); -+ -+ local_irq_enable(); -+ ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */ -+ info = rs_table; -+ for (i = 0; i < NR_PORTS; i++) { -+ /* Which line caused the ready irq? */ -+ if (irq_mask1_rd & ready_mask) { -+ handled = 1; -+ handle_ser_tx_interrupt(info); -+ } -+ info += 1; -+ ready_mask <<= 2; -+ } -+ /* handle_ser_tx_interrupt enables tr_ready interrupts */ -+ local_irq_disable(); -+ /* Handle reentered TX interrupt */ -+ irq_mask1_rd = reentered_ready_mask; -+ } -+ local_irq_disable(); -+ tx_started = 0; -+ } else { -+ unsigned long ready_mask; -+ ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser1_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser2_ready) | -+ IO_MASK(R_IRQ_MASK1_RD, ser3_ready)); -+ if (ready_mask) { -+ reentered_ready_mask |= ready_mask; -+ /* Disable those we are about to handle */ -+ *R_IRQ_MASK1_CLR = ready_mask; -+ DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask)); -+ } -+ } -+ -+ local_irq_restore(flags); -+ return IRQ_RETVAL(handled); -+} /* ser_interrupt */ -+#endif -+ -+/* -+ * ------------------------------------------------------------------- -+ * Here ends the serial interrupt routines. -+ * ------------------------------------------------------------------- -+ */ -+ -+/* -+ * This routine is used to handle the "bottom half" processing for the -+ * serial driver, known also the "software interrupt" processing. -+ * This processing is done at the kernel interrupt level, after the -+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This -+ * is where time-consuming activities which can not be done in the -+ * interrupt driver proper are done; the interrupt driver schedules -+ * them using rs_sched_event(), and they get done here. -+ */ -+static void -+do_softint(struct work_struct *work) -+{ -+ struct e100_serial *info; -+ struct tty_struct *tty; -+ -+ info = container_of(work, struct e100_serial, work); -+ -+ tty = info->port.tty; -+ if (!tty) -+ return; -+ -+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) -+ tty_wakeup(tty); -+} -+ -+static int -+startup(struct e100_serial * info) -+{ -+ unsigned long flags; -+ unsigned long xmit_page; -+ int i; -+ -+ xmit_page = get_zeroed_page(GFP_KERNEL); -+ if (!xmit_page) -+ return -ENOMEM; -+ -+ local_irq_save(flags); -+ -+ /* if it was already initialized, skip this */ -+ -+ if (info->flags & ASYNC_INITIALIZED) { -+ local_irq_restore(flags); -+ free_page(xmit_page); -+ return 0; -+ } -+ -+ if (info->xmit.buf) -+ free_page(xmit_page); -+ else -+ info->xmit.buf = (unsigned char *) xmit_page; -+ -+#ifdef SERIAL_DEBUG_OPEN -+ printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf); -+#endif -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* Bits and pieces collected from below. Better to have them -+ in one ifdef:ed clause than to mix in a lot of ifdefs, -+ right? */ -+ if (info->port.tty) -+ clear_bit(TTY_IO_ERROR, &info->port.tty->flags); -+ -+ info->xmit.head = info->xmit.tail = 0; -+ info->first_recv_buffer = info->last_recv_buffer = NULL; -+ info->recv_cnt = info->max_recv_cnt = 0; -+ -+ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) -+ info->rec_descr[i].buf = NULL; -+ -+ /* No real action in the simulator, but may set info important -+ to ioctl. */ -+ change_speed(info); -+#else -+ -+ /* -+ * Clear the FIFO buffers and disable them -+ * (they will be reenabled in change_speed()) -+ */ -+ -+ /* -+ * Reset the DMA channels and make sure their interrupts are cleared -+ */ -+ -+ if (info->dma_in_enabled) { -+ info->uses_dma_in = 1; -+ e100_enable_rxdma_channel(info); -+ -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); -+ -+ /* Wait until reset cycle is complete */ -+ while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == -+ IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); -+ -+ /* Make sure the irqs are cleared */ -+ *info->iclrintradr = -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); -+ } else { -+ e100_disable_rxdma_channel(info); -+ } -+ -+ if (info->dma_out_enabled) { -+ info->uses_dma_out = 1; -+ e100_enable_txdma_channel(info); -+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); -+ -+ while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == -+ IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); -+ -+ /* Make sure the irqs are cleared */ -+ *info->oclrintradr = -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | -+ IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); -+ } else { -+ e100_disable_txdma_channel(info); -+ } -+ -+ if (info->port.tty) -+ clear_bit(TTY_IO_ERROR, &info->port.tty->flags); -+ -+ info->xmit.head = info->xmit.tail = 0; -+ info->first_recv_buffer = info->last_recv_buffer = NULL; -+ info->recv_cnt = info->max_recv_cnt = 0; -+ -+ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) -+ info->rec_descr[i].buf = 0; -+ -+ /* -+ * and set the speed and other flags of the serial port -+ * this will start the rx/tx as well -+ */ -+#ifdef SERIAL_HANDLE_EARLY_ERRORS -+ e100_enable_serial_data_irq(info); -+#endif -+ change_speed(info); -+ -+ /* dummy read to reset any serial errors */ -+ -+ (void)info->ioport[REG_DATA]; -+ -+ /* enable the interrupts */ -+ if (info->uses_dma_out) -+ e100_enable_txdma_irq(info); -+ -+ e100_enable_rx_irq(info); -+ -+ info->tr_running = 0; /* to be sure we don't lock up the transmitter */ -+ -+ /* setup the dma input descriptor and start dma */ -+ -+ start_receive(info); -+ -+ /* for safety, make sure the descriptors last result is 0 bytes written */ -+ -+ info->tr_descr.sw_len = 0; -+ info->tr_descr.hw_len = 0; -+ info->tr_descr.status = 0; -+ -+ /* enable RTS/DTR last */ -+ -+ e100_rts(info, 1); -+ e100_dtr(info, 1); -+ -+#endif /* CONFIG_SVINTO_SIM */ -+ -+ info->flags |= ASYNC_INITIALIZED; -+ -+ local_irq_restore(flags); -+ return 0; -+} -+ -+/* -+ * This routine will shutdown a serial port; interrupts are disabled, and -+ * DTR is dropped if the hangup on close termio flag is on. -+ */ -+static void -+shutdown(struct e100_serial * info) -+{ -+ unsigned long flags; -+ struct etrax_dma_descr *descr = info->rec_descr; -+ struct etrax_recv_buffer *buffer; -+ int i; -+ -+#ifndef CONFIG_SVINTO_SIM -+ /* shut down the transmitter and receiver */ -+ DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line)); -+ e100_disable_rx(info); -+ info->ioport[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40); -+ -+ /* disable interrupts, reset dma channels */ -+ if (info->uses_dma_in) { -+ e100_disable_rxdma_irq(info); -+ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); -+ info->uses_dma_in = 0; -+ } else { -+ e100_disable_serial_data_irq(info); -+ } -+ -+ if (info->uses_dma_out) { -+ e100_disable_txdma_irq(info); -+ info->tr_running = 0; -+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); -+ info->uses_dma_out = 0; -+ } else { -+ e100_disable_serial_tx_ready_irq(info); -+ info->tr_running = 0; -+ } -+ -+#endif /* CONFIG_SVINTO_SIM */ -+ -+ if (!(info->flags & ASYNC_INITIALIZED)) -+ return; -+ -+#ifdef SERIAL_DEBUG_OPEN -+ printk("Shutting down serial port %d (irq %d)....\n", info->line, -+ info->irq); -+#endif -+ -+ local_irq_save(flags); -+ -+ if (info->xmit.buf) { -+ free_page((unsigned long)info->xmit.buf); -+ info->xmit.buf = NULL; -+ } -+ -+ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) -+ if (descr[i].buf) { -+ buffer = phys_to_virt(descr[i].buf) - sizeof *buffer; -+ kfree(buffer); -+ descr[i].buf = 0; -+ } -+ -+ if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { -+ /* hang up DTR and RTS if HUPCL is enabled */ -+ e100_dtr(info, 0); -+ e100_rts(info, 0); /* could check CRTSCTS before doing this */ -+ } -+ -+ if (info->port.tty) -+ set_bit(TTY_IO_ERROR, &info->port.tty->flags); -+ -+ info->flags &= ~ASYNC_INITIALIZED; -+ local_irq_restore(flags); -+} -+ -+ -+/* change baud rate and other assorted parameters */ -+ -+static void -+change_speed(struct e100_serial *info) -+{ -+ unsigned int cflag; -+ unsigned long xoff; -+ unsigned long flags; -+ /* first some safety checks */ -+ -+ if (!info->port.tty || !info->port.tty->termios) -+ return; -+ if (!info->ioport) -+ return; -+ -+ cflag = info->port.tty->termios->c_cflag; -+ -+ /* possibly, the tx/rx should be disabled first to do this safely */ -+ -+ /* change baud-rate and write it to the hardware */ -+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { -+ /* Special baudrate */ -+ u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */ -+ unsigned long alt_source = -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) | -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal); -+ /* R_ALT_SER_BAUDRATE selects the source */ -+ DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n", -+ (unsigned long)info->baud_base, info->custom_divisor)); -+ if (info->baud_base == SERIAL_PRESCALE_BASE) { -+ /* 0, 2-65535 (0=65536) */ -+ u16 divisor = info->custom_divisor; -+ /* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */ -+ /* baudrate is 3.125MHz/custom_divisor */ -+ alt_source = -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) | -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale); -+ alt_source = 0x11; -+ DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor)); -+ *R_SERIAL_PRESCALE = divisor; -+ info->baud = SERIAL_PRESCALE_BASE/divisor; -+ } -+#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED -+ else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 && -+ info->custom_divisor == 1) || -+ (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ && -+ info->custom_divisor == 8)) { -+ /* ext_clk selected */ -+ alt_source = -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) | -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern); -+ DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8)); -+ info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8; -+ } -+#endif -+ else -+ { -+ /* Bad baudbase, we don't support using timer0 -+ * for baudrate. -+ */ -+ printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n", -+ (unsigned long)info->baud_base, info->custom_divisor); -+ } -+ r_alt_ser_baudrate_shadow &= ~mask; -+ r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8)); -+ *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow; -+ } else { -+ /* Normal baudrate */ -+ /* Make sure we use normal baudrate */ -+ u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */ -+ unsigned long alt_source = -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) | -+ IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal); -+ r_alt_ser_baudrate_shadow &= ~mask; -+ r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8)); -+#ifndef CONFIG_SVINTO_SIM -+ *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow; -+#endif /* CONFIG_SVINTO_SIM */ -+ -+ info->baud = cflag_to_baud(cflag); -+#ifndef CONFIG_SVINTO_SIM -+ info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag); -+#endif /* CONFIG_SVINTO_SIM */ -+ } -+ -+#ifndef CONFIG_SVINTO_SIM -+ /* start with default settings and then fill in changes */ -+ local_irq_save(flags); -+ /* 8 bit, no/even parity */ -+ info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) | -+ IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) | -+ IO_MASK(R_SERIAL0_REC_CTRL, rec_par)); -+ -+ /* 8 bit, no/even parity, 1 stop bit, no cts */ -+ info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) | -+ IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) | -+ IO_MASK(R_SERIAL0_TR_CTRL, tr_par) | -+ IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) | -+ IO_MASK(R_SERIAL0_TR_CTRL, auto_cts)); -+ -+ if ((cflag & CSIZE) == CS7) { -+ /* set 7 bit mode */ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit); -+ info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit); -+ } -+ -+ if (cflag & CSTOPB) { -+ /* set 2 stop bit mode */ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits); -+ } -+ -+ if (cflag & PARENB) { -+ /* enable parity */ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); -+ info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); -+ } -+ -+ if (cflag & CMSPAR) { -+ /* enable stick parity, PARODD mean Mark which matches ETRAX */ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick); -+ info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick); -+ } -+ if (cflag & PARODD) { -+ /* set odd parity (or Mark if CMSPAR) */ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd); -+ info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd); -+ } -+ -+ if (cflag & CRTSCTS) { -+ /* enable automatic CTS handling */ -+ DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0)); -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active); -+ } -+ -+ /* make sure the tx and rx are enabled */ -+ -+ info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable); -+ info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); -+ -+ /* actually write the control regs to the hardware */ -+ -+ info->ioport[REG_TR_CTRL] = info->tx_ctrl; -+ info->ioport[REG_REC_CTRL] = info->rx_ctrl; -+ xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty)); -+ xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); -+ if (info->port.tty->termios->c_iflag & IXON ) { -+ DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n", -+ STOP_CHAR(info->port.tty))); -+ xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); -+ } -+ -+ *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; -+ local_irq_restore(flags); -+#endif /* !CONFIG_SVINTO_SIM */ -+ -+ update_char_time(info); -+ -+} /* change_speed */ -+ -+/* start transmitting chars NOW */ -+ -+static void -+rs_flush_chars(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ if (info->tr_running || -+ info->xmit.head == info->xmit.tail || -+ tty->stopped || -+ tty->hw_stopped || -+ !info->xmit.buf) -+ return; -+ -+#ifdef SERIAL_DEBUG_FLOW -+ printk("rs_flush_chars\n"); -+#endif -+ -+ /* this protection might not exactly be necessary here */ -+ -+ local_irq_save(flags); -+ start_transmit(info); -+ local_irq_restore(flags); -+} -+ -+static int rs_raw_write(struct tty_struct *tty, -+ const unsigned char *buf, int count) -+{ -+ int c, ret = 0; -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ /* first some sanity checks */ -+ -+ if (!tty || !info->xmit.buf || !tmp_buf) -+ return 0; -+ -+#ifdef SERIAL_DEBUG_DATA -+ if (info->line == SERIAL_DEBUG_LINE) -+ printk("rs_raw_write (%d), status %d\n", -+ count, info->ioport[REG_STATUS]); -+#endif -+ -+#ifdef CONFIG_SVINTO_SIM -+ /* Really simple. The output is here and now. */ -+ SIMCOUT(buf, count); -+ return count; -+#endif -+ local_save_flags(flags); -+ DFLOW(DEBUG_LOG(info->line, "write count %i ", count)); -+ DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty))); -+ -+ -+ /* The local_irq_disable/restore_flags pairs below are needed -+ * because the DMA interrupt handler moves the info->xmit values. -+ * the memcpy needs to be in the critical region unfortunately, -+ * because we need to read xmit values, memcpy, write xmit values -+ * in one atomic operation... this could perhaps be avoided by -+ * more clever design. -+ */ -+ local_irq_disable(); -+ while (count) { -+ c = CIRC_SPACE_TO_END(info->xmit.head, -+ info->xmit.tail, -+ SERIAL_XMIT_SIZE); -+ -+ if (count < c) -+ c = count; -+ if (c <= 0) -+ break; -+ -+ memcpy(info->xmit.buf + info->xmit.head, buf, c); -+ info->xmit.head = (info->xmit.head + c) & -+ (SERIAL_XMIT_SIZE-1); -+ buf += c; -+ count -= c; -+ ret += c; -+ } -+ local_irq_restore(flags); -+ -+ /* enable transmitter if not running, unless the tty is stopped -+ * this does not need IRQ protection since if tr_running == 0 -+ * the IRQ's are not running anyway for this port. -+ */ -+ DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret)); -+ -+ if (info->xmit.head != info->xmit.tail && -+ !tty->stopped && -+ !tty->hw_stopped && -+ !info->tr_running) { -+ start_transmit(info); -+ } -+ -+ return ret; -+} /* raw_raw_write() */ -+ -+static int -+rs_write(struct tty_struct *tty, -+ const unsigned char *buf, int count) -+{ -+#if defined(CONFIG_ETRAX_RS485) -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ -+ if (info->rs485.flags & SER_RS485_ENABLED) -+ { -+ /* If we are in RS-485 mode, we need to toggle RTS and disable -+ * the receiver before initiating a DMA transfer -+ */ -+#ifdef CONFIG_ETRAX_FAST_TIMER -+ /* Abort any started timer */ -+ fast_timers_rs485[info->line].function = NULL; -+ del_fast_timer(&fast_timers_rs485[info->line]); -+#endif -+ e100_rts(info, (info->rs485.flags & SER_RS485_RTS_ON_SEND)); -+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) -+ e100_disable_rx(info); -+ e100_enable_rx_irq(info); -+#endif -+ if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) && -+ (info->rs485.delay_rts_before_send > 0)) -+ msleep(info->rs485.delay_rts_before_send); -+ } -+#endif /* CONFIG_ETRAX_RS485 */ -+ -+ count = rs_raw_write(tty, buf, count); -+ -+#if defined(CONFIG_ETRAX_RS485) -+ if (info->rs485.flags & SER_RS485_ENABLED) -+ { -+ unsigned int val; -+ /* If we are in RS-485 mode the following has to be done: -+ * wait until DMA is ready -+ * wait on transmit shift register -+ * toggle RTS -+ * enable the receiver -+ */ -+ -+ /* Sleep until all sent */ -+ tty_wait_until_sent(tty, 0); -+#ifdef CONFIG_ETRAX_FAST_TIMER -+ /* Now sleep a little more so that shift register is empty */ -+ schedule_usleep(info->char_time_usec * 2); -+#endif -+ /* wait on transmit shift register */ -+ do{ -+ get_lsr_info(info, &val); -+ }while (!(val & TIOCSER_TEMT)); -+ -+ e100_rts(info, (info->rs485.flags & SER_RS485_RTS_AFTER_SEND)); -+ -+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) -+ e100_enable_rx(info); -+ e100_enable_rxdma_irq(info); -+#endif -+ } -+#endif /* CONFIG_ETRAX_RS485 */ -+ -+ return count; -+} /* rs_write */ -+ -+ -+/* how much space is available in the xmit buffer? */ -+ -+static int -+rs_write_room(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ -+ return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -+} -+ -+/* How many chars are in the xmit buffer? -+ * This does not include any chars in the transmitter FIFO. -+ * Use wait_until_sent for waiting for FIFO drain. -+ */ -+ -+static int -+rs_chars_in_buffer(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ -+ return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -+} -+ -+/* discard everything in the xmit buffer */ -+ -+static void -+rs_flush_buffer(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ info->xmit.head = info->xmit.tail = 0; -+ local_irq_restore(flags); -+ -+ tty_wakeup(tty); -+} -+ -+/* -+ * This function is used to send a high-priority XON/XOFF character to -+ * the device -+ * -+ * Since we use DMA we don't check for info->x_char in transmit_chars_dma(), -+ * but we do it in handle_ser_tx_interrupt(). -+ * We disable DMA channel and enable tx ready interrupt and write the -+ * character when possible. -+ */ -+static void rs_send_xchar(struct tty_struct *tty, char ch) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ local_irq_save(flags); -+ if (info->uses_dma_out) { -+ /* Put the DMA on hold and disable the channel */ -+ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold); -+ while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) != -+ IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold)); -+ e100_disable_txdma_channel(info); -+ } -+ -+ /* Must make sure transmitter is not stopped before we can transmit */ -+ if (tty->stopped) -+ rs_start(tty); -+ -+ /* Enable manual transmit interrupt and send from there */ -+ DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch)); -+ info->x_char = ch; -+ e100_enable_serial_tx_ready_irq(info); -+ local_irq_restore(flags); -+} -+ -+/* -+ * ------------------------------------------------------------ -+ * rs_throttle() -+ * -+ * This routine is called by the upper-layer tty layer to signal that -+ * incoming characters should be throttled. -+ * ------------------------------------------------------------ -+ */ -+static void -+rs_throttle(struct tty_struct * tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+#ifdef SERIAL_DEBUG_THROTTLE -+ char buf[64]; -+ -+ printk("throttle %s: %lu....\n", tty_name(tty, buf), -+ (unsigned long)tty->ldisc.chars_in_buffer(tty)); -+#endif -+ DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty))); -+ -+ /* Do RTS before XOFF since XOFF might take some time */ -+ if (tty->termios->c_cflag & CRTSCTS) { -+ /* Turn off RTS line */ -+ e100_rts(info, 0); -+ } -+ if (I_IXOFF(tty)) -+ rs_send_xchar(tty, STOP_CHAR(tty)); -+ -+} -+ -+static void -+rs_unthrottle(struct tty_struct * tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+#ifdef SERIAL_DEBUG_THROTTLE -+ char buf[64]; -+ -+ printk("unthrottle %s: %lu....\n", tty_name(tty, buf), -+ (unsigned long)tty->ldisc.chars_in_buffer(tty)); -+#endif -+ DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty))); -+ DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count)); -+ /* Do RTS before XOFF since XOFF might take some time */ -+ if (tty->termios->c_cflag & CRTSCTS) { -+ /* Assert RTS line */ -+ e100_rts(info, 1); -+ } -+ -+ if (I_IXOFF(tty)) { -+ if (info->x_char) -+ info->x_char = 0; -+ else -+ rs_send_xchar(tty, START_CHAR(tty)); -+ } -+ -+} -+ -+/* -+ * ------------------------------------------------------------ -+ * rs_ioctl() and friends -+ * ------------------------------------------------------------ -+ */ -+ -+static int -+get_serial_info(struct e100_serial * info, -+ struct serial_struct * retinfo) -+{ -+ struct serial_struct tmp; -+ -+ /* this is all probably wrong, there are a lot of fields -+ * here that we don't have in e100_serial and maybe we -+ * should set them to something else than 0. -+ */ -+ -+ if (!retinfo) -+ return -EFAULT; -+ memset(&tmp, 0, sizeof(tmp)); -+ tmp.type = info->type; -+ tmp.line = info->line; -+ tmp.port = (int)info->ioport; -+ tmp.irq = info->irq; -+ tmp.flags = info->flags; -+ tmp.baud_base = info->baud_base; -+ tmp.close_delay = info->close_delay; -+ tmp.closing_wait = info->closing_wait; -+ tmp.custom_divisor = info->custom_divisor; -+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) -+ return -EFAULT; -+ return 0; -+} -+ -+static int -+set_serial_info(struct e100_serial *info, -+ struct serial_struct *new_info) -+{ -+ struct serial_struct new_serial; -+ struct e100_serial old_info; -+ int retval = 0; -+ -+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) -+ return -EFAULT; -+ -+ old_info = *info; -+ -+ if (!capable(CAP_SYS_ADMIN)) { -+ if ((new_serial.type != info->type) || -+ (new_serial.close_delay != info->close_delay) || -+ ((new_serial.flags & ~ASYNC_USR_MASK) != -+ (info->flags & ~ASYNC_USR_MASK))) -+ return -EPERM; -+ info->flags = ((info->flags & ~ASYNC_USR_MASK) | -+ (new_serial.flags & ASYNC_USR_MASK)); -+ goto check_and_exit; -+ } -+ -+ if (info->count > 1) -+ return -EBUSY; -+ -+ /* -+ * OK, past this point, all the error checking has been done. -+ * At this point, we start making changes..... -+ */ -+ -+ info->baud_base = new_serial.baud_base; -+ info->flags = ((info->flags & ~ASYNC_FLAGS) | -+ (new_serial.flags & ASYNC_FLAGS)); -+ info->custom_divisor = new_serial.custom_divisor; -+ info->type = new_serial.type; -+ info->close_delay = new_serial.close_delay; -+ info->closing_wait = new_serial.closing_wait; -+ info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -+ -+ check_and_exit: -+ if (info->flags & ASYNC_INITIALIZED) { -+ change_speed(info); -+ } else -+ retval = startup(info); -+ return retval; -+} -+ -+/* -+ * get_lsr_info - get line status register info -+ * -+ * Purpose: Let user call ioctl() to get info when the UART physically -+ * is emptied. On bus types like RS485, the transmitter must -+ * release the bus after transmitting. This must be done when -+ * the transmit shift register is empty, not be done when the -+ * transmit holding register is empty. This functionality -+ * allows an RS485 driver to be written in user space. -+ */ -+static int -+get_lsr_info(struct e100_serial * info, unsigned int *value) -+{ -+ unsigned int result = TIOCSER_TEMT; -+#ifndef CONFIG_SVINTO_SIM -+ unsigned long curr_time = jiffies; -+ unsigned long curr_time_usec = GET_JIFFIES_USEC(); -+ unsigned long elapsed_usec = -+ (curr_time - info->last_tx_active) * 1000000/HZ + -+ curr_time_usec - info->last_tx_active_usec; -+ -+ if (info->xmit.head != info->xmit.tail || -+ elapsed_usec < 2*info->char_time_usec) { -+ result = 0; -+ } -+#endif -+ -+ if (copy_to_user(value, &result, sizeof(int))) -+ return -EFAULT; -+ return 0; -+} -+ -+#ifdef SERIAL_DEBUG_IO -+struct state_str -+{ -+ int state; -+ const char *str; -+}; -+ -+const struct state_str control_state_str[] = { -+ {TIOCM_DTR, "DTR" }, -+ {TIOCM_RTS, "RTS"}, -+ {TIOCM_ST, "ST?" }, -+ {TIOCM_SR, "SR?" }, -+ {TIOCM_CTS, "CTS" }, -+ {TIOCM_CD, "CD" }, -+ {TIOCM_RI, "RI" }, -+ {TIOCM_DSR, "DSR" }, -+ {0, NULL } -+}; -+ -+char *get_control_state_str(int MLines, char *s) -+{ -+ int i = 0; -+ -+ s[0]='\0'; -+ while (control_state_str[i].str != NULL) { -+ if (MLines & control_state_str[i].state) { -+ if (s[0] != '\0') { -+ strcat(s, ", "); -+ } -+ strcat(s, control_state_str[i].str); -+ } -+ i++; -+ } -+ return s; -+} -+#endif -+ -+static int -+rs_break(struct tty_struct *tty, int break_state) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ if (!info->ioport) -+ return -EIO; -+ -+ local_irq_save(flags); -+ if (break_state == -1) { -+ /* Go to manual mode and set the txd pin to 0 */ -+ /* Clear bit 7 (txd) and 6 (tr_enable) */ -+ info->tx_ctrl &= 0x3F; -+ } else { -+ /* Set bit 7 (txd) and 6 (tr_enable) */ -+ info->tx_ctrl |= (0x80 | 0x40); -+ } -+ info->ioport[REG_TR_CTRL] = info->tx_ctrl; -+ local_irq_restore(flags); -+ return 0; -+} -+ -+static int -+rs_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ if (clear & TIOCM_RTS) -+ e100_rts(info, 0); -+ if (clear & TIOCM_DTR) -+ e100_dtr(info, 0); -+ /* Handle FEMALE behaviour */ -+ if (clear & TIOCM_RI) -+ e100_ri_out(info, 0); -+ if (clear & TIOCM_CD) -+ e100_cd_out(info, 0); -+ -+ if (set & TIOCM_RTS) -+ e100_rts(info, 1); -+ if (set & TIOCM_DTR) -+ e100_dtr(info, 1); -+ /* Handle FEMALE behaviour */ -+ if (set & TIOCM_RI) -+ e100_ri_out(info, 1); -+ if (set & TIOCM_CD) -+ e100_cd_out(info, 1); -+ -+ local_irq_restore(flags); -+ return 0; -+} -+ -+static int -+rs_tiocmget(struct tty_struct *tty) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned int result; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ result = -+ (!E100_RTS_GET(info) ? TIOCM_RTS : 0) -+ | (!E100_DTR_GET(info) ? TIOCM_DTR : 0) -+ | (!E100_RI_GET(info) ? TIOCM_RNG : 0) -+ | (!E100_DSR_GET(info) ? TIOCM_DSR : 0) -+ | (!E100_CD_GET(info) ? TIOCM_CAR : 0) -+ | (!E100_CTS_GET(info) ? TIOCM_CTS : 0); -+ -+ local_irq_restore(flags); -+ -+#ifdef SERIAL_DEBUG_IO -+ printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n", -+ info->line, result, result); -+ { -+ char s[100]; -+ -+ get_control_state_str(result, s); -+ printk(KERN_DEBUG "state: %s\n", s); -+ } -+#endif -+ return result; -+ -+} -+ -+ -+static int -+rs_ioctl(struct tty_struct *tty, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct e100_serial * info = (struct e100_serial *)tty->driver_data; -+ -+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && -+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && -+ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { -+ if (tty->flags & (1 << TTY_IO_ERROR)) -+ return -EIO; -+ } -+ -+ switch (cmd) { -+ case TIOCGSERIAL: -+ return get_serial_info(info, -+ (struct serial_struct *) arg); -+ case TIOCSSERIAL: -+ return set_serial_info(info, -+ (struct serial_struct *) arg); -+ case TIOCSERGETLSR: /* Get line status register */ -+ return get_lsr_info(info, (unsigned int *) arg); -+ -+ case TIOCSERGSTRUCT: -+ if (copy_to_user((struct e100_serial *) arg, -+ info, sizeof(struct e100_serial))) -+ return -EFAULT; -+ return 0; -+ -+#if defined(CONFIG_ETRAX_RS485) -+ case TIOCSERSETRS485: -+ { -+ /* In this ioctl we still use the old structure -+ * rs485_control for backward compatibility -+ * (if we use serial_rs485, then old user-level code -+ * wouldn't work anymore...). -+ * The use of this ioctl is deprecated: use TIOCSRS485 -+ * instead.*/ -+ struct rs485_control rs485ctrl; -+ struct serial_rs485 rs485data; -+ printk(KERN_DEBUG "The use of this ioctl is deprecated. Use TIOCSRS485 instead\n"); -+ if (copy_from_user(&rs485ctrl, (struct rs485_control *)arg, -+ sizeof(rs485ctrl))) -+ return -EFAULT; -+ -+ rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send; -+ rs485data.flags = 0; -+ if (rs485data.delay_rts_before_send != 0) -+ rs485data.flags |= SER_RS485_RTS_BEFORE_SEND; -+ else -+ rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND); -+ -+ if (rs485ctrl.enabled) -+ rs485data.flags |= SER_RS485_ENABLED; -+ else -+ rs485data.flags &= ~(SER_RS485_ENABLED); -+ -+ if (rs485ctrl.rts_on_send) -+ rs485data.flags |= SER_RS485_RTS_ON_SEND; -+ else -+ rs485data.flags &= ~(SER_RS485_RTS_ON_SEND); -+ -+ if (rs485ctrl.rts_after_sent) -+ rs485data.flags |= SER_RS485_RTS_AFTER_SEND; -+ else -+ rs485data.flags &= ~(SER_RS485_RTS_AFTER_SEND); -+ -+ return e100_enable_rs485(tty, &rs485data); -+ } -+ -+ case TIOCSRS485: -+ { -+ /* This is the new version of TIOCSRS485, with new -+ * data structure serial_rs485 */ -+ struct serial_rs485 rs485data; -+ if (copy_from_user(&rs485data, (struct rs485_control *)arg, -+ sizeof(rs485data))) -+ return -EFAULT; -+ -+ return e100_enable_rs485(tty, &rs485data); -+ } -+ -+ case TIOCGRS485: -+ { -+ struct serial_rs485 *rs485data = -+ &(((struct e100_serial *)tty->driver_data)->rs485); -+ /* This is the ioctl to get RS485 data from user-space */ -+ if (copy_to_user((struct serial_rs485 *) arg, -+ rs485data, -+ sizeof(struct serial_rs485))) -+ return -EFAULT; -+ break; -+ } -+ -+ case TIOCSERWRRS485: -+ { -+ struct rs485_write rs485wr; -+ if (copy_from_user(&rs485wr, (struct rs485_write *)arg, -+ sizeof(rs485wr))) -+ return -EFAULT; -+ -+ return e100_write_rs485(tty, rs485wr.outc, rs485wr.outc_size); -+ } -+#endif -+ -+ default: -+ return -ENOIOCTLCMD; -+ } -+ return 0; -+} -+ -+static void -+rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -+{ -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ -+ change_speed(info); -+ -+ /* Handle turning off CRTSCTS */ -+ if ((old_termios->c_cflag & CRTSCTS) && -+ !(tty->termios->c_cflag & CRTSCTS)) { -+ tty->hw_stopped = 0; -+ rs_start(tty); -+ } -+ -+} -+ -+/* -+ * ------------------------------------------------------------ -+ * rs_close() -+ * -+ * This routine is called when the serial port gets closed. First, we -+ * wait for the last remaining data to be sent. Then, we unlink its -+ * S structure from the interrupt chain if necessary, and we free -+ * that IRQ if nothing is left in the chain. -+ * ------------------------------------------------------------ -+ */ -+static void -+rs_close(struct tty_struct *tty, struct file * filp) -+{ -+ struct e100_serial * info = (struct e100_serial *)tty->driver_data; -+ unsigned long flags; -+ -+ if (!info) -+ return; -+ -+ /* interrupts are disabled for this entire function */ -+ -+ local_irq_save(flags); -+ -+ if (tty_hung_up_p(filp)) { -+ local_irq_restore(flags); -+ return; -+ } -+ -+#ifdef SERIAL_DEBUG_OPEN -+ printk("[%d] rs_close ttyS%d, count = %d\n", current->pid, -+ info->line, info->count); -+#endif -+ if ((tty->count == 1) && (info->count != 1)) { -+ /* -+ * Uh, oh. tty->count is 1, which means that the tty -+ * structure will be freed. Info->count should always -+ * be one in these conditions. If it's greater than -+ * one, we've got real problems, since it means the -+ * serial port won't be shutdown. -+ */ -+ printk(KERN_CRIT -+ "rs_close: bad serial port count; tty->count is 1, " -+ "info->count is %d\n", info->count); -+ info->count = 1; -+ } -+ if (--info->count < 0) { -+ printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n", -+ info->line, info->count); -+ info->count = 0; -+ } -+ if (info->count) { -+ local_irq_restore(flags); -+ return; -+ } -+ info->flags |= ASYNC_CLOSING; -+ /* -+ * Save the termios structure, since this port may have -+ * separate termios for callout and dialin. -+ */ -+ if (info->flags & ASYNC_NORMAL_ACTIVE) -+ info->normal_termios = *tty->termios; -+ /* -+ * Now we wait for the transmit buffer to clear; and we notify -+ * the line discipline to only process XON/XOFF characters. -+ */ -+ tty->closing = 1; -+ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) -+ tty_wait_until_sent(tty, info->closing_wait); -+ /* -+ * At this point we stop accepting input. To do this, we -+ * disable the serial receiver and the DMA receive interrupt. -+ */ -+#ifdef SERIAL_HANDLE_EARLY_ERRORS -+ e100_disable_serial_data_irq(info); -+#endif -+ -+#ifndef CONFIG_SVINTO_SIM -+ e100_disable_rx(info); -+ e100_disable_rx_irq(info); -+ -+ if (info->flags & ASYNC_INITIALIZED) { -+ /* -+ * Before we drop DTR, make sure the UART transmitter -+ * has completely drained; this is especially -+ * important as we have a transmit FIFO! -+ */ -+ rs_wait_until_sent(tty, HZ); -+ } -+#endif -+ -+ shutdown(info); -+ rs_flush_buffer(tty); -+ tty_ldisc_flush(tty); -+ tty->closing = 0; -+ info->event = 0; -+ info->port.tty = NULL; -+ if (info->blocked_open) { -+ if (info->close_delay) -+ schedule_timeout_interruptible(info->close_delay); -+ wake_up_interruptible(&info->open_wait); -+ } -+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); -+ wake_up_interruptible(&info->close_wait); -+ local_irq_restore(flags); -+ -+ /* port closed */ -+ -+#if defined(CONFIG_ETRAX_RS485) -+ if (info->rs485.flags & SER_RS485_ENABLED) { -+ info->rs485.flags &= ~(SER_RS485_ENABLED); -+#if defined(CONFIG_ETRAX_RS485_ON_PA) -+ *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); -+#endif -+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ rs485_port_g_bit, 0); -+#endif -+#if defined(CONFIG_ETRAX_RS485_LTC1387) -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0); -+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, -+ CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0); -+#endif -+ } -+#endif -+ -+ /* -+ * Release any allocated DMA irq's. -+ */ -+ if (info->dma_in_enabled) { -+ free_irq(info->dma_in_irq_nbr, info); -+ cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description); -+ info->uses_dma_in = 0; -+#ifdef SERIAL_DEBUG_OPEN -+ printk(KERN_DEBUG "DMA irq '%s' freed\n", -+ info->dma_in_irq_description); -+#endif -+ } -+ if (info->dma_out_enabled) { -+ free_irq(info->dma_out_irq_nbr, info); -+ cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description); -+ info->uses_dma_out = 0; -+#ifdef SERIAL_DEBUG_OPEN -+ printk(KERN_DEBUG "DMA irq '%s' freed\n", -+ info->dma_out_irq_description); -+#endif -+ } -+} -+ -+/* -+ * rs_wait_until_sent() --- wait until the transmitter is empty -+ */ -+static void rs_wait_until_sent(struct tty_struct *tty, int timeout) -+{ -+ unsigned long orig_jiffies; -+ struct e100_serial *info = (struct e100_serial *)tty->driver_data; -+ unsigned long curr_time = jiffies; -+ unsigned long curr_time_usec = GET_JIFFIES_USEC(); -+ long elapsed_usec = -+ (curr_time - info->last_tx_active) * (1000000/HZ) + -+ curr_time_usec - info->last_tx_active_usec; -+ -+ /* -+ * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO -+ * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k) -+ */ -+ orig_jiffies = jiffies; -+ while (info->xmit.head != info->xmit.tail || /* More in send queue */ -+ (*info->ostatusadr & 0x007f) || /* more in FIFO */ -+ (elapsed_usec < 2*info->char_time_usec)) { -+ schedule_timeout_interruptible(1); -+ if (signal_pending(current)) -+ break; -+ if (timeout && time_after(jiffies, orig_jiffies + timeout)) -+ break; -+ curr_time = jiffies; -+ curr_time_usec = GET_JIFFIES_USEC(); -+ elapsed_usec = -+ (curr_time - info->last_tx_active) * (1000000/HZ) + -+ curr_time_usec - info->last_tx_active_usec; -+ } -+ set_current_state(TASK_RUNNING); -+} -+ -+/* -+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled. -+ */ -+void -+rs_hangup(struct tty_struct *tty) -+{ -+ struct e100_serial * info = (struct e100_serial *)tty->driver_data; -+ -+ rs_flush_buffer(tty); -+ shutdown(info); -+ info->event = 0; -+ info->count = 0; -+ info->flags &= ~ASYNC_NORMAL_ACTIVE; -+ info->port.tty = NULL; -+ wake_up_interruptible(&info->open_wait); -+} -+ -+/* -+ * ------------------------------------------------------------ -+ * rs_open() and friends -+ * ------------------------------------------------------------ -+ */ -+static int -+block_til_ready(struct tty_struct *tty, struct file * filp, -+ struct e100_serial *info) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int retval; -+ int do_clocal = 0, extra_count = 0; -+ -+ /* -+ * If the device is in the middle of being closed, then block -+ * until it's done, and then try again. -+ */ -+ if (tty_hung_up_p(filp) || -+ (info->flags & ASYNC_CLOSING)) { -+ wait_event_interruptible_tty(info->close_wait, -+ !(info->flags & ASYNC_CLOSING)); -+#ifdef SERIAL_DO_RESTART -+ if (info->flags & ASYNC_HUP_NOTIFY) -+ return -EAGAIN; -+ else -+ return -ERESTARTSYS; -+#else -+ return -EAGAIN; -+#endif -+ } -+ -+ /* -+ * If non-blocking mode is set, or the port is not enabled, -+ * then make the check up front and then exit. -+ */ -+ if ((filp->f_flags & O_NONBLOCK) || -+ (tty->flags & (1 << TTY_IO_ERROR))) { -+ info->flags |= ASYNC_NORMAL_ACTIVE; -+ return 0; -+ } -+ -+ if (tty->termios->c_cflag & CLOCAL) { -+ do_clocal = 1; -+ } -+ -+ /* -+ * Block waiting for the carrier detect and the line to become -+ * free (i.e., not in use by the callout). While we are in -+ * this loop, info->count is dropped by one, so that -+ * rs_close() knows when to free things. We restore it upon -+ * exit, either normal or abnormal. -+ */ -+ retval = 0; -+ add_wait_queue(&info->open_wait, &wait); -+#ifdef SERIAL_DEBUG_OPEN -+ printk("block_til_ready before block: ttyS%d, count = %d\n", -+ info->line, info->count); -+#endif -+ local_irq_save(flags); -+ if (!tty_hung_up_p(filp)) { -+ extra_count++; -+ info->count--; -+ } -+ local_irq_restore(flags); -+ info->blocked_open++; -+ while (1) { -+ local_irq_save(flags); -+ /* assert RTS and DTR */ -+ e100_rts(info, 1); -+ e100_dtr(info, 1); -+ local_irq_restore(flags); -+ set_current_state(TASK_INTERRUPTIBLE); -+ if (tty_hung_up_p(filp) || -+ !(info->flags & ASYNC_INITIALIZED)) { -+#ifdef SERIAL_DO_RESTART -+ if (info->flags & ASYNC_HUP_NOTIFY) -+ retval = -EAGAIN; -+ else -+ retval = -ERESTARTSYS; -+#else -+ retval = -EAGAIN; -+#endif -+ break; -+ } -+ if (!(info->flags & ASYNC_CLOSING) && do_clocal) -+ /* && (do_clocal || DCD_IS_ASSERTED) */ -+ break; -+ if (signal_pending(current)) { -+ retval = -ERESTARTSYS; -+ break; -+ } -+#ifdef SERIAL_DEBUG_OPEN -+ printk("block_til_ready blocking: ttyS%d, count = %d\n", -+ info->line, info->count); -+#endif -+ tty_unlock(); -+ schedule(); -+ tty_lock(); -+ } -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&info->open_wait, &wait); -+ if (extra_count) -+ info->count++; -+ info->blocked_open--; -+#ifdef SERIAL_DEBUG_OPEN -+ printk("block_til_ready after blocking: ttyS%d, count = %d\n", -+ info->line, info->count); -+#endif -+ if (retval) -+ return retval; -+ info->flags |= ASYNC_NORMAL_ACTIVE; -+ return 0; -+} -+ -+static void -+deinit_port(struct e100_serial *info) -+{ -+ if (info->dma_out_enabled) { -+ cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description); -+ free_irq(info->dma_out_irq_nbr, info); -+ } -+ if (info->dma_in_enabled) { -+ cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description); -+ free_irq(info->dma_in_irq_nbr, info); -+ } -+} -+ -+/* -+ * This routine is called whenever a serial port is opened. -+ * It performs the serial-specific initialization for the tty structure. -+ */ -+static int -+rs_open(struct tty_struct *tty, struct file * filp) -+{ -+ struct e100_serial *info; -+ int retval, line; -+ unsigned long page; -+ int allocated_resources = 0; -+ -+ /* find which port we want to open */ -+ line = tty->index; -+ -+ if (line < 0 || line >= NR_PORTS) -+ return -ENODEV; -+ -+ /* find the corresponding e100_serial struct in the table */ -+ info = rs_table + line; -+ -+ /* don't allow the opening of ports that are not enabled in the HW config */ -+ if (!info->enabled) -+ return -ENODEV; -+ -+#ifdef SERIAL_DEBUG_OPEN -+ printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name, -+ info->count); -+#endif -+ -+ info->count++; -+ tty->driver_data = info; -+ info->port.tty = tty; -+ -+ info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -+ -+ if (!tmp_buf) { -+ page = get_zeroed_page(GFP_KERNEL); -+ if (!page) { -+ return -ENOMEM; -+ } -+ if (tmp_buf) -+ free_page(page); -+ else -+ tmp_buf = (unsigned char *) page; -+ } -+ -+ /* -+ * If the port is in the middle of closing, bail out now -+ */ -+ if (tty_hung_up_p(filp) || -+ (info->flags & ASYNC_CLOSING)) { -+ wait_event_interruptible_tty(info->close_wait, -+ !(info->flags & ASYNC_CLOSING)); -+#ifdef SERIAL_DO_RESTART -+ return ((info->flags & ASYNC_HUP_NOTIFY) ? -+ -EAGAIN : -ERESTARTSYS); -+#else -+ return -EAGAIN; -+#endif -+ } -+ -+ /* -+ * If DMA is enabled try to allocate the irq's. -+ */ -+ if (info->count == 1) { -+ allocated_resources = 1; -+ if (info->dma_in_enabled) { -+ if (request_irq(info->dma_in_irq_nbr, -+ rec_interrupt, -+ info->dma_in_irq_flags, -+ info->dma_in_irq_description, -+ info)) { -+ printk(KERN_WARNING "DMA irq '%s' busy; " -+ "falling back to non-DMA mode\n", -+ info->dma_in_irq_description); -+ /* Make sure we never try to use DMA in */ -+ /* for the port again. */ -+ info->dma_in_enabled = 0; -+ } else if (cris_request_dma(info->dma_in_nbr, -+ info->dma_in_irq_description, -+ DMA_VERBOSE_ON_ERROR, -+ info->dma_owner)) { -+ free_irq(info->dma_in_irq_nbr, info); -+ printk(KERN_WARNING "DMA '%s' busy; " -+ "falling back to non-DMA mode\n", -+ info->dma_in_irq_description); -+ /* Make sure we never try to use DMA in */ -+ /* for the port again. */ -+ info->dma_in_enabled = 0; -+ } -+#ifdef SERIAL_DEBUG_OPEN -+ else -+ printk(KERN_DEBUG "DMA irq '%s' allocated\n", -+ info->dma_in_irq_description); -+#endif -+ } -+ if (info->dma_out_enabled) { -+ if (request_irq(info->dma_out_irq_nbr, -+ tr_interrupt, -+ info->dma_out_irq_flags, -+ info->dma_out_irq_description, -+ info)) { -+ printk(KERN_WARNING "DMA irq '%s' busy; " -+ "falling back to non-DMA mode\n", -+ info->dma_out_irq_description); -+ /* Make sure we never try to use DMA out */ -+ /* for the port again. */ -+ info->dma_out_enabled = 0; -+ } else if (cris_request_dma(info->dma_out_nbr, -+ info->dma_out_irq_description, -+ DMA_VERBOSE_ON_ERROR, -+ info->dma_owner)) { -+ free_irq(info->dma_out_irq_nbr, info); -+ printk(KERN_WARNING "DMA '%s' busy; " -+ "falling back to non-DMA mode\n", -+ info->dma_out_irq_description); -+ /* Make sure we never try to use DMA out */ -+ /* for the port again. */ -+ info->dma_out_enabled = 0; -+ } -+#ifdef SERIAL_DEBUG_OPEN -+ else -+ printk(KERN_DEBUG "DMA irq '%s' allocated\n", -+ info->dma_out_irq_description); -+#endif -+ } -+ } -+ -+ /* -+ * Start up the serial port -+ */ -+ -+ retval = startup(info); -+ if (retval) { -+ if (allocated_resources) -+ deinit_port(info); -+ -+ /* FIXME Decrease count info->count here too? */ -+ return retval; -+ } -+ -+ -+ retval = block_til_ready(tty, filp, info); -+ if (retval) { -+#ifdef SERIAL_DEBUG_OPEN -+ printk("rs_open returning after block_til_ready with %d\n", -+ retval); -+#endif -+ if (allocated_resources) -+ deinit_port(info); -+ -+ return retval; -+ } -+ -+ if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { -+ *tty->termios = info->normal_termios; -+ change_speed(info); -+ } -+ -+#ifdef SERIAL_DEBUG_OPEN -+ printk("rs_open ttyS%d successful...\n", info->line); -+#endif -+ DLOG_INT_TRIG( log_int_pos = 0); -+ -+ DFLIP( if (info->line == SERIAL_DEBUG_LINE) { -+ info->icount.rx = 0; -+ } ); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PROC_FS -+/* -+ * /proc fs routines.... -+ */ -+ -+static void seq_line_info(struct seq_file *m, struct e100_serial *info) -+{ -+ unsigned long tmp; -+ -+ seq_printf(m, "%d: uart:E100 port:%lX irq:%d", -+ info->line, (unsigned long)info->ioport, info->irq); -+ -+ if (!info->ioport || (info->type == PORT_UNKNOWN)) { -+ seq_printf(m, "\n"); -+ return; -+ } -+ -+ seq_printf(m, " baud:%d", info->baud); -+ seq_printf(m, " tx:%lu rx:%lu", -+ (unsigned long)info->icount.tx, -+ (unsigned long)info->icount.rx); -+ tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -+ if (tmp) -+ seq_printf(m, " tx_pend:%lu/%lu", -+ (unsigned long)tmp, -+ (unsigned long)SERIAL_XMIT_SIZE); -+ -+ seq_printf(m, " rx_pend:%lu/%lu", -+ (unsigned long)info->recv_cnt, -+ (unsigned long)info->max_recv_cnt); -+ -+#if 1 -+ if (info->port.tty) { -+ if (info->port.tty->stopped) -+ seq_printf(m, " stopped:%i", -+ (int)info->port.tty->stopped); -+ if (info->port.tty->hw_stopped) -+ seq_printf(m, " hw_stopped:%i", -+ (int)info->port.tty->hw_stopped); -+ } -+ -+ { -+ unsigned char rstat = info->ioport[REG_STATUS]; -+ if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect)) -+ seq_printf(m, " xoff_detect:1"); -+ } -+ -+#endif -+ -+ if (info->icount.frame) -+ seq_printf(m, " fe:%lu", (unsigned long)info->icount.frame); -+ -+ if (info->icount.parity) -+ seq_printf(m, " pe:%lu", (unsigned long)info->icount.parity); -+ -+ if (info->icount.brk) -+ seq_printf(m, " brk:%lu", (unsigned long)info->icount.brk); -+ -+ if (info->icount.overrun) -+ seq_printf(m, " oe:%lu", (unsigned long)info->icount.overrun); -+ -+ /* -+ * Last thing is the RS-232 status lines -+ */ -+ if (!E100_RTS_GET(info)) -+ seq_puts(m, "|RTS"); -+ if (!E100_CTS_GET(info)) -+ seq_puts(m, "|CTS"); -+ if (!E100_DTR_GET(info)) -+ seq_puts(m, "|DTR"); -+ if (!E100_DSR_GET(info)) -+ seq_puts(m, "|DSR"); -+ if (!E100_CD_GET(info)) -+ seq_puts(m, "|CD"); -+ if (!E100_RI_GET(info)) -+ seq_puts(m, "|RI"); -+ seq_puts(m, "\n"); -+} -+ -+ -+static int crisv10_proc_show(struct seq_file *m, void *v) -+{ -+ int i; -+ -+ seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ if (!rs_table[i].enabled) -+ continue; -+ seq_line_info(m, &rs_table[i]); -+ } -+#ifdef DEBUG_LOG_INCLUDED -+ for (i = 0; i < debug_log_pos; i++) { -+ seq_printf(m, "%-4i %lu.%lu ", -+ i, debug_log[i].time, -+ timer_data_to_ns(debug_log[i].timer_data)); -+ seq_printf(m, debug_log[i].string, debug_log[i].value); -+ } -+ seq_printf(m, "debug_log %i/%i\n", i, DEBUG_LOG_SIZE); -+ debug_log_pos = 0; -+#endif -+ return 0; -+} -+ -+static int crisv10_proc_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, crisv10_proc_show, NULL); -+} -+ -+static const struct file_operations crisv10_proc_fops = { -+ .owner = THIS_MODULE, -+ .open = crisv10_proc_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+#endif -+ -+ -+/* Finally, routines used to initialize the serial driver. */ -+ -+static void show_serial_version(void) -+{ -+ printk(KERN_INFO -+ "ETRAX 100LX serial-driver %s, " -+ "(c) 2000-2004 Axis Communications AB\r\n", -+ &serial_version[11]); /* "$Revision: x.yy" */ -+} -+ -+/* rs_init inits the driver at boot (using the module_init chain) */ -+ -+static const struct tty_operations rs_ops = { -+ .open = rs_open, -+ .close = rs_close, -+ .write = rs_write, -+ .flush_chars = rs_flush_chars, -+ .write_room = rs_write_room, -+ .chars_in_buffer = rs_chars_in_buffer, -+ .flush_buffer = rs_flush_buffer, -+ .ioctl = rs_ioctl, -+ .throttle = rs_throttle, -+ .unthrottle = rs_unthrottle, -+ .set_termios = rs_set_termios, -+ .stop = rs_stop, -+ .start = rs_start, -+ .hangup = rs_hangup, -+ .break_ctl = rs_break, -+ .send_xchar = rs_send_xchar, -+ .wait_until_sent = rs_wait_until_sent, -+ .tiocmget = rs_tiocmget, -+ .tiocmset = rs_tiocmset, -+#ifdef CONFIG_PROC_FS -+ .proc_fops = &crisv10_proc_fops, -+#endif -+}; -+ -+static int __init rs_init(void) -+{ -+ int i; -+ struct e100_serial *info; -+ struct tty_driver *driver = alloc_tty_driver(NR_PORTS); -+ -+ if (!driver) -+ return -ENOMEM; -+ -+ show_serial_version(); -+ -+ /* Setup the timed flush handler system */ -+ -+#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER) -+ setup_timer(&flush_timer, timed_flush_handler, 0); -+ mod_timer(&flush_timer, jiffies + 5); -+#endif -+ -+#if defined(CONFIG_ETRAX_RS485) -+#if defined(CONFIG_ETRAX_RS485_ON_PA) -+ if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit, -+ rs485_pa_bit)) { -+ printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " -+ "RS485 pin\n"); -+ put_tty_driver(driver); -+ return -EBUSY; -+ } -+#endif -+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -+ if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit, -+ rs485_port_g_bit)) { -+ printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " -+ "RS485 pin\n"); -+ put_tty_driver(driver); -+ return -EBUSY; -+ } -+#endif -+#endif -+ -+ /* Initialize the tty_driver structure */ -+ -+ driver->driver_name = "serial"; -+ driver->name = "ttyS"; -+ driver->major = TTY_MAJOR; -+ driver->minor_start = 64; -+ driver->type = TTY_DRIVER_TYPE_SERIAL; -+ driver->subtype = SERIAL_TYPE_NORMAL; -+ driver->init_termios = tty_std_termios; -+ driver->init_termios.c_cflag = -+ B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ -+ driver->init_termios.c_ispeed = 115200; -+ driver->init_termios.c_ospeed = 115200; -+ driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; -+ -+ tty_set_operations(driver, &rs_ops); -+ serial_driver = driver; -+ if (tty_register_driver(driver)) -+ panic("Couldn't register serial driver\n"); -+ /* do some initializing for the separate ports */ -+ -+ for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { -+ if (info->enabled) { -+ if (cris_request_io_interface(info->io_if, -+ info->io_if_description)) { -+ printk(KERN_CRIT "ETRAX100LX async serial: " -+ "Could not allocate IO pins for " -+ "%s, port %d\n", -+ info->io_if_description, i); -+ info->enabled = 0; -+ } -+ } -+ info->uses_dma_in = 0; -+ info->uses_dma_out = 0; -+ info->line = i; -+ info->port.tty = NULL; -+ info->type = PORT_ETRAX; -+ info->tr_running = 0; -+ info->forced_eop = 0; -+ info->baud_base = DEF_BAUD_BASE; -+ info->custom_divisor = 0; -+ info->flags = 0; -+ info->close_delay = 5*HZ/10; -+ info->closing_wait = 30*HZ; -+ info->x_char = 0; -+ info->event = 0; -+ info->count = 0; -+ info->blocked_open = 0; -+ info->normal_termios = driver->init_termios; -+ init_waitqueue_head(&info->open_wait); -+ init_waitqueue_head(&info->close_wait); -+ info->xmit.buf = NULL; -+ info->xmit.tail = info->xmit.head = 0; -+ info->first_recv_buffer = info->last_recv_buffer = NULL; -+ info->recv_cnt = info->max_recv_cnt = 0; -+ info->last_tx_active_usec = 0; -+ info->last_tx_active = 0; -+ -+#if defined(CONFIG_ETRAX_RS485) -+ /* Set sane defaults */ -+ info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND); -+ info->rs485.flags |= SER_RS485_RTS_AFTER_SEND; -+ info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND); -+ info->rs485.delay_rts_before_send = 0; -+ info->rs485.flags &= ~(SER_RS485_ENABLED); -+#endif -+ INIT_WORK(&info->work, do_softint); -+ -+ if (info->enabled) { -+ printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n", -+ serial_driver->name, info->line, info->ioport); -+ } -+ } -+#ifdef CONFIG_ETRAX_FAST_TIMER -+#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER -+ memset(fast_timers, 0, sizeof(fast_timers)); -+#endif -+#ifdef CONFIG_ETRAX_RS485 -+ memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485)); -+#endif -+ fast_timer_init(); -+#endif -+ -+#ifndef CONFIG_SVINTO_SIM -+#ifndef CONFIG_ETRAX_KGDB -+ /* Not needed in simulator. May only complicate stuff. */ -+ /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ -+ -+ if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, -+ IRQF_SHARED | IRQF_DISABLED, "serial ", driver)) -+ panic("%s: Failed to request irq8", __func__); -+ -+#endif -+#endif /* CONFIG_SVINTO_SIM */ -+ -+ return 0; -+} -+ -+/* this makes sure that rs_init is called during kernel boot */ -+ -+module_init(rs_init); diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-cris-dbg.h linux-2.6.39/drivers/usb/host/hc-cris-dbg.h --- linux-2.6.39.orig/drivers/usb/host/hc-cris-dbg.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/usb/host/hc-cris-dbg.h 2011-07-28 16:16:37.503543830 +0200 ++++ linux-2.6.39/drivers/usb/host/hc-cris-dbg.h 2011-08-22 08:58:56.307980767 +0200 @@ -0,0 +1,146 @@ + +/* macros for debug output */ @@ -8020,7 +563,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-cris-dbg.h linux-2.6.39/drivers/ + }) diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-crisv10.c linux-2.6.39/drivers/usb/host/hc-crisv10.c --- linux-2.6.39.orig/drivers/usb/host/hc-crisv10.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/usb/host/hc-crisv10.c 2011-07-28 16:16:37.633441816 +0200 ++++ linux-2.6.39/drivers/usb/host/hc-crisv10.c 2011-08-22 08:58:56.397980354 +0200 @@ -0,0 +1,4801 @@ +/* + * @@ -12825,7 +5368,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-crisv10.c linux-2.6.39/drivers/u +module_exit(module_hcd_exit); diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-crisv10.h linux-2.6.39/drivers/usb/host/hc-crisv10.h --- linux-2.6.39.orig/drivers/usb/host/hc-crisv10.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.39/drivers/usb/host/hc-crisv10.h 2011-07-28 16:16:37.757174124 +0200 ++++ linux-2.6.39/drivers/usb/host/hc-crisv10.h 2011-08-22 08:58:56.467980502 +0200 @@ -0,0 +1,331 @@ +#ifndef __LINUX_ETRAX_USB_H +#define __LINUX_ETRAX_USB_H @@ -13160,7 +5703,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/hc-crisv10.h linux-2.6.39/drivers/u +#endif diff -Nur linux-2.6.39.orig/drivers/usb/host/Makefile linux-2.6.39/drivers/usb/host/Makefile --- linux-2.6.39.orig/drivers/usb/host/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/usb/host/Makefile 2011-07-28 16:16:37.863421513 +0200 ++++ linux-2.6.39/drivers/usb/host/Makefile 2011-08-22 08:58:56.527980204 +0200 @@ -32,6 +32,7 @@ obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o @@ -13171,7 +5714,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/host/Makefile linux-2.6.39/drivers/usb/h obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o diff -Nur linux-2.6.39.orig/drivers/usb/Makefile linux-2.6.39/drivers/usb/Makefile --- linux-2.6.39.orig/drivers/usb/Makefile 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/drivers/usb/Makefile 2011-07-28 16:16:37.993659487 +0200 ++++ linux-2.6.39/drivers/usb/Makefile 2011-08-22 08:58:56.607990534 +0200 @@ -21,6 +21,7 @@ obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_HWA_HCD) += host/ @@ -13182,7 +5725,7 @@ diff -Nur linux-2.6.39.orig/drivers/usb/Makefile linux-2.6.39/drivers/usb/Makefi obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ diff -Nur linux-2.6.39.orig/lib/klist.c linux-2.6.39/lib/klist.c --- linux-2.6.39.orig/lib/klist.c 2011-05-19 06:06:34.000000000 +0200 -+++ linux-2.6.39/lib/klist.c 2011-07-28 16:16:38.103425277 +0200 ++++ linux-2.6.39/lib/klist.c 2011-08-22 08:58:56.667990229 +0200 @@ -60,7 +60,7 @@ { knode->n_klist = klist; |