diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/Documentation/parisc/todo linux-2.5/Documentation/parisc/todo --- ../prev/linux-2.5/Documentation/parisc/todo Wed Dec 31 17:00:00 1969 +++ linux-2.5/Documentation/parisc/todo Tue Mar 18 15:21:01 2003 @@ -0,0 +1,67 @@ +Status: +------- + - Merged to 2.5.65, boots on 712, Cxxx, A500 + - SuckyIO serial problems still exist. + - Don't know what other patches need to be brought forward from 2.4 + - SMP compiles, but doesn't work yet + - No preemptible support + + +Todo: +----- + - review diff vs 2.4 for additional changes + - Serial code not working for c3000 + - the fix for do_fork needs checking + - our PDC early debug console hacks need to be cleaned up somehow + - ad1889 driver: only works with .wav; Convert to ALSA (ggg, tausq, tbone) + - ns87415 dma doesn't work reliably on suckyio-systems + - CPU hotplug support (useful to take flaky CPU "offline") + - flush_tlb_kernel_range is horribly inefficient + - flush_icache_user_range could flush just that range rather than the + entire page. + - (ab)use kmap/kunmap on 64-bit to eliminate flush_dcache calls. + - cp_new_stat32 for sys_parisc32.c is inefficient; maybe it's better + to fill in a tmp stat32 and just do copy_to_user in one go at the end? + - syscall signal return path needs work + - changes in arch/parisc/kernel/signal.c regarding HACK needs testing + - signal.c #if CACHE_FLUSHING_IS_NOT_BROKEN needs to be solved + - task_struct/thread_info split -- task_struct should not be visible in + entry.S, we need to move some items into thread_info -- this includes + pt_regs and maybe some of the flags (ptrace, etc) + - Use zone_highmem for the 256MB of RAM at 64GB on Astro-based machines. + (NB, what does Stretch do?) + - investigate not putting in extable entries for put_kernel_asm; will + probably reduce kernel size + - call to pdc_suspend_usb() in inventory.c crashes c3k with kernel 2.5 + - fix HIL problem: ksoftirqd/0 eats 56% cpu (kernel 2.4 & kernel 2.5) + - write floppy driver for lasi + - write floppy driver for suckyio + - XFS goes into an infinite loop when mounting volume. + - spifi driver (rbrad) + - write optimized versions of lcopy_{to,from}_user. Can we port the + hpux versions? + - kernel module loader support + - IRQ cpu-affinity support + - NPTL kernel support (CLONE_*TID flags need to be correctly handled by + sys_clone() and friends) + - port sym53c8xx hppa changes forward (still needed?) + + + Started and in progress: + ------------------------ + - Some options still need Kconfig help entries (see below!) + - Look at Config.help too. (tbone, HIL -> helge?) + - commit beta ALSA harmony driver (laurent) + - port hil_kbd.c to new input layer + - port hil_ptr.c to new input layer + - oprofile support (tausq) + - 64-bit userspace (Leandro) + + + CONFIG options without help: + ----------------------------- + _USB_OHCI_HCD (add parisc info?) + _HP_SDC_RTC + _HIL_MLC + _HIL_KBD (to improve) + _HIL_PTR (to improve) diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/Makefile linux-2.5/Makefile --- ../prev/linux-2.5/Makefile Fri May 2 03:58:54 2003 +++ linux-2.5/Makefile Fri May 2 00:30:17 2003 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 68 -EXTRAVERSION = +EXTRAVERSION = -pa2 # *DOCUMENTATION* # To see a list of typical targets execute "make help" @@ -40,6 +40,8 @@ # Remove hyphens since they have special meaning in RPM filenames KERNELPATH=kernel-$(subst -,,$(KERNELRELEASE)) + +ARCH := parisc UTS_MACHINE := $(ARCH) diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/alpha/kernel/core_marvel.c linux-2.5/arch/alpha/kernel/core_marvel.c --- ../prev/linux-2.5/arch/alpha/kernel/core_marvel.c Fri May 2 03:59:08 2003 +++ linux-2.5/arch/alpha/kernel/core_marvel.c Thu Apr 24 07:12:42 2003 @@ -452,7 +452,6 @@ /* With multiple PCI busses, we play with I/O as physical addrs. */ ioport_resource.end = ~0UL; - iomem_resource.end = ~0UL; /* PCI DMA Direct Mapping is 1GB at 2GB. */ __direct_map_base = 0x80000000; diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/alpha/kernel/core_mcpcia.c linux-2.5/arch/alpha/kernel/core_mcpcia.c --- ../prev/linux-2.5/arch/alpha/kernel/core_mcpcia.c Fri May 2 03:59:08 2003 +++ linux-2.5/arch/alpha/kernel/core_mcpcia.c Thu Apr 24 07:12:43 2003 @@ -407,7 +407,6 @@ { /* With multiple PCI busses, we play with I/O as physical addrs. */ ioport_resource.end = ~0UL; - iomem_resource.end = ~0UL; /* Allocate hose 0. That's the one that all the ISA junk hangs off of, from which we'll be registering stuff here in a bit. diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/alpha/kernel/core_titan.c linux-2.5/arch/alpha/kernel/core_titan.c --- ../prev/linux-2.5/arch/alpha/kernel/core_titan.c Fri May 2 03:59:08 2003 +++ linux-2.5/arch/alpha/kernel/core_titan.c Thu Apr 24 07:12:43 2003 @@ -412,7 +412,6 @@ /* With multiple PCI busses, we play with I/O as physical addrs. */ ioport_resource.end = ~0UL; - iomem_resource.end = ~0UL; /* PCI DMA Direct Mapping is 1GB at 2GB. */ __direct_map_base = 0x80000000; diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/alpha/kernel/core_tsunami.c linux-2.5/arch/alpha/kernel/core_tsunami.c --- ../prev/linux-2.5/arch/alpha/kernel/core_tsunami.c Fri May 2 03:59:08 2003 +++ linux-2.5/arch/alpha/kernel/core_tsunami.c Thu Apr 24 07:12:43 2003 @@ -390,7 +390,6 @@ #endif /* With multiple PCI busses, we play with I/O as physical addrs. */ ioport_resource.end = ~0UL; - iomem_resource.end = ~0UL; /* Find how many hoses we have, and initialize them. TSUNAMI and TYPHOON can have 2, but might only have 1 (DS10). */ diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/alpha/kernel/core_wildfire.c linux-2.5/arch/alpha/kernel/core_wildfire.c --- ../prev/linux-2.5/arch/alpha/kernel/core_wildfire.c Fri May 2 03:59:08 2003 +++ linux-2.5/arch/alpha/kernel/core_wildfire.c Thu Apr 24 07:12:43 2003 @@ -309,7 +309,6 @@ /* With multiple PCI buses, we play with I/O as physical addrs. */ ioport_resource.end = ~0UL; - iomem_resource.end = ~0UL; /* Probe the hardware for info about configuration. */ diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/ia64/sn/io/pci_bus_cvlink.c linux-2.5/arch/ia64/sn/io/pci_bus_cvlink.c --- ../prev/linux-2.5/arch/ia64/sn/io/pci_bus_cvlink.c Fri May 2 03:59:39 2003 +++ linux-2.5/arch/ia64/sn/io/pci_bus_cvlink.c Thu Apr 24 07:12:43 2003 @@ -373,12 +373,6 @@ #endif /* - * Set the root start and end for Mem Resource. - */ - iomem_resource.start = 0; - iomem_resource.end = 0xffffffffffffffff; - - /* * Initialize the device vertex in the pci_dev struct. */ pci_for_each_dev(device_dev) { diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/ia64/sn/io/sn2/pci_bus_cvlink.c linux-2.5/arch/ia64/sn/io/sn2/pci_bus_cvlink.c --- ../prev/linux-2.5/arch/ia64/sn/io/sn2/pci_bus_cvlink.c Fri May 2 03:59:42 2003 +++ linux-2.5/arch/ia64/sn/io/sn2/pci_bus_cvlink.c Thu Apr 24 07:12:43 2003 @@ -323,12 +323,6 @@ ioport_resource.end = 0xcfffffffffffffff; /* - * Set the root start and end for Mem Resource. - */ - iomem_resource.start = 0; - iomem_resource.end = 0xffffffffffffffff; - - /* * Initialize the device vertex in the pci_dev struct. */ pci_for_each_dev(device_dev) { diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/mips64/sgi-ip27/ip27-pci.c linux-2.5/arch/mips64/sgi-ip27/ip27-pci.c --- ../prev/linux-2.5/arch/mips64/sgi-ip27/ip27-pci.c Fri May 2 04:00:11 2003 +++ linux-2.5/arch/mips64/sgi-ip27/ip27-pci.c Thu Apr 24 07:12:43 2003 @@ -149,7 +149,6 @@ int i; ioport_resource.end = ~0UL; - iomem_resource.end = ~0UL; for (i=0; i EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(boot_cpu_data); +#ifdef CONFIG_BINFMT_SOM EXPORT_SYMBOL(map_hpux_gateway_page); +#endif #ifdef CONFIG_EISA EXPORT_SYMBOL(EISA_bus); #endif diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/parisc/kernel/process.c linux-2.5/arch/parisc/kernel/process.c --- ../prev/linux-2.5/arch/parisc/kernel/process.c Fri May 2 04:00:18 2003 +++ linux-2.5/arch/parisc/kernel/process.c Wed Apr 9 22:45:31 2003 @@ -251,7 +251,9 @@ * Make them const so the compiler knows they live in .text */ extern void * const ret_from_kernel_thread; extern void * const child_return; +#ifdef CONFIG_BINFMT_SOM extern void * const hpux_child_return; +#endif *cregs = *pregs; @@ -295,7 +297,11 @@ + (pregs->gr[21] & (INIT_THREAD_SIZE - 1)); cregs->gr[30] = usp; if (p->personality == PER_HPUX) { +#ifdef CONFIG_BINFMT_SOM cregs->kpc = (unsigned long) &hpux_child_return; +#else + BUG(); +#endif } else { cregs->kpc = (unsigned long) &child_return; } diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/parisc/kernel/processor.c linux-2.5/arch/parisc/kernel/processor.c --- ../prev/linux-2.5/arch/parisc/kernel/processor.c Fri May 2 04:00:18 2003 +++ linux-2.5/arch/parisc/kernel/processor.c Sun Mar 23 13:14:52 2003 @@ -145,6 +145,7 @@ /* initialize counters */ memset(p, 0, sizeof(struct cpuinfo_parisc)); + p->loops_per_jiffy = loops_per_jiffy; p->dev = dev; /* Save IODC data in case we need it */ p->hpa = dev->hpa; /* save CPU hpa */ p->cpuid = cpuid; /* save CPU id */ @@ -356,8 +357,8 @@ show_cache_info(m); seq_printf(m, "bogomips\t: %lu.%02lu\n", - loops_per_jiffy / (500000 / HZ), - (loops_per_jiffy / (5000 / HZ)) % 100); + cpu_data[n].loops_per_jiffy / (500000 / HZ), + (cpu_data[n].loops_per_jiffy / (5000 / HZ)) % 100); seq_printf(m, "software id\t: %ld\n\n", boot_cpu_data.pdc.model.sw_id); diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/parisc/kernel/signal.c linux-2.5/arch/parisc/kernel/signal.c --- ../prev/linux-2.5/arch/parisc/kernel/signal.c Fri May 2 04:00:19 2003 +++ linux-2.5/arch/parisc/kernel/signal.c Sun Mar 23 13:14:52 2003 @@ -309,7 +309,8 @@ } #endif -#if CACHE_FLUSHING_IS_NOT_BROKEN +#undef CACHE_FLUSHING_IS_NOT_BROKEN +#ifdef CACHE_FLUSHING_IS_NOT_BROKEN flush_user_icache_range((unsigned long) &frame->tramp[0], (unsigned long) &frame->tramp[4]); #else diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/parisc/kernel/smp.c linux-2.5/arch/parisc/kernel/smp.c --- ../prev/linux-2.5/arch/parisc/kernel/smp.c Fri May 2 04:00:19 2003 +++ linux-2.5/arch/parisc/kernel/smp.c Sun Mar 23 13:14:52 2003 @@ -522,7 +522,7 @@ /* * Bring one cpu online. */ -static int smp_boot_one_cpu(int cpuid, int cpunum) +static int __init smp_boot_one_cpu(int cpuid, int cpunum) { struct task_struct *idle; long timeout; @@ -613,7 +613,7 @@ void __init smp_boot_cpus(void) { int i, cpu_count = 1; - unsigned long bogosum = loops_per_jiffy; /* Count Monarch */ + unsigned long bogosum = cpu_data[0].loops_per_jiffy; /* Count Monarch */ /* REVISIT - assumes first CPU reported by PAT PDC is BSP */ int bootstrap_processor=cpu_data[0].cpuid; /* CPU ID of BSP */ @@ -650,7 +650,7 @@ if (smp_boot_one_cpu(cpu_data[i].cpuid, cpu_count) < 0) continue; - bogosum += loops_per_jiffy; + bogosum += cpu_data[i].loops_per_jiffy; cpu_count++; /* Count good CPUs only... */ cpu_present_mask |= 1UL << i; diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/parisc/kernel/sys_parisc32.c linux-2.5/arch/parisc/kernel/sys_parisc32.c --- ../prev/linux-2.5/arch/parisc/kernel/sys_parisc32.c Fri May 2 04:00:19 2003 +++ linux-2.5/arch/parisc/kernel/sys_parisc32.c Fri May 2 00:30:17 2003 @@ -30,10 +30,7 @@ #include #include #include -#include -#include #include -#include #include #include #include @@ -42,11 +39,6 @@ #include #include #include -#include /* for setsockopt() */ -#include /* for setsockopt() */ -#include /* for setsockopt() */ -#include /* for setsockopt() */ -#include /* for setsockopt() */ #include #include #include @@ -62,9 +54,6 @@ #include "sys32.h" -#define A(__x) ((unsigned long)(__x)) - - #undef DEBUG #ifdef DEBUG @@ -73,34 +62,6 @@ #define DBG(x) #endif -/* For this source file, we want overflow handling. */ - -#undef high2lowuid -#undef high2lowgid -#undef low2highuid -#undef low2highgid -#undef SET_UID16 -#undef SET_GID16 -#undef NEW_TO_OLD_UID -#undef NEW_TO_OLD_GID -#undef SET_OLDSTAT_UID -#undef SET_OLDSTAT_GID -#undef SET_STAT_UID -#undef SET_STAT_GID - -#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid) -#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid) -#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid) -#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid) -#define SET_UID16(var, uid) var = high2lowuid(uid) -#define SET_GID16(var, gid) var = high2lowgid(gid) -#define NEW_TO_OLD_UID(uid) high2lowuid(uid) -#define NEW_TO_OLD_GID(gid) high2lowgid(gid) -#define SET_OLDSTAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid) -#define SET_OLDSTAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid) -#define SET_STAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid) -#define SET_STAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid) - /* * count32() counts the number of arguments/envelopes. It is basically * a copy of count() from fs/exec.c, except that it works @@ -145,7 +106,7 @@ if (get_user(str, argv + argc) || !str || - !(len = strnlen_user((char *)A(str), bprm->p))) + !(len = strnlen_user((char *)compat_ptr(str), bprm->p))) return -EFAULT; if (bprm->p < len) @@ -181,7 +142,7 @@ if (new) memset(kaddr+offset+len, 0, PAGE_SIZE-offset-len); } - err = copy_from_user(kaddr + offset, (char *)A(str), bytes_to_copy); + err = copy_from_user(kaddr + offset, (char *)compat_ptr(str), bytes_to_copy); flush_dcache_page(page); kunmap(page); @@ -784,7 +745,7 @@ __get_user(len, &vector->iov_len); __get_user(buf, &vector->iov_base); tot_len += len; - ivp->iov_base = (void *)A(buf); + ivp->iov_base = compat_ptr(buf); ivp->iov_len = (compat_size_t) len; vector++; ivp++; @@ -1214,67 +1175,6 @@ return ret; } - -#include - -struct dqblk32 { - __u32 dqb_bhardlimit; - __u32 dqb_bsoftlimit; - __u32 dqb_curblocks; - __u32 dqb_ihardlimit; - __u32 dqb_isoftlimit; - __u32 dqb_curinodes; - compat_time_t dqb_btime; - compat_time_t dqb_itime; -}; - - -asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr) -{ -#if 0 - extern int sys_quotactl(int cmd, const char *special, int id, caddr_t addr); - int cmds = cmd >> SUBCMDSHIFT; - int err; - struct dqblk d; - char *spec; - - switch (cmds) { - case Q_GETQUOTA: - break; - case Q_SETQUOTA: - case Q_SETUSE: - case Q_SETQLIM: - if (copy_from_user (&d, (struct dqblk32 *)addr, - sizeof (struct dqblk32))) - return -EFAULT; - d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; - d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; - break; - default: - return sys_quotactl(cmd, special, - id, (caddr_t)addr); - } - spec = getname (special); - err = PTR_ERR(spec); - if (IS_ERR(spec)) return err; - KERNEL_SYSCALL(err, sys_quotactl, cmd, (const char *)spec, id, (caddr_t)&d); - putname (spec); - if (cmds == Q_GETQUOTA) { - __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; - ((struct dqblk32 *)&d)->dqb_itime = i; - ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user ((struct dqblk32 *)addr, &d, - sizeof (struct dqblk32))) - return -EFAULT; - } - return err; -#endif - /* TODO */ - BUG(); - return -EINVAL; -} - - extern asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count); typedef long __kernel_loff_t32; /* move this to asm/posix_types.h? */ diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/parisc/kernel/syscall.S linux-2.5/arch/parisc/kernel/syscall.S --- ../prev/linux-2.5/arch/parisc/kernel/syscall.S Fri May 2 04:00:19 2003 +++ linux-2.5/arch/parisc/kernel/syscall.S Fri May 2 00:30:17 2003 @@ -497,7 +497,7 @@ ENTRY_SAME(delete_module) ENTRY_SAME(ni_syscall) /* 130: get_kernel_syms */ /* time_t inside struct dqblk */ - ENTRY_DIFF(quotactl) /* -- FIXME, doesn't work */ + ENTRY_SAME(quotactl) ENTRY_SAME(getpgid) ENTRY_SAME(fchdir) ENTRY_SAME(bdflush) diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/parisc/mm/init.c linux-2.5/arch/parisc/mm/init.c --- ../prev/linux-2.5/arch/parisc/mm/init.c Fri May 2 04:00:22 2003 +++ linux-2.5/arch/parisc/mm/init.c Thu Apr 24 07:12:43 2003 @@ -195,11 +195,6 @@ #endif /* __LP64__ */ -#if 1 - /* KLUGE! this really belongs in kernel/resource.c! */ - iomem_resource.end = ~0UL; -#endif - sysram_resource_count = npmem_ranges; for (i = 0; i < sysram_resource_count; i++) { struct resource *res = &sysram_resources[i]; @@ -671,6 +666,7 @@ PAGE_SIZE, PAGE_GATEWAY); } +#ifdef CONFIG_BINFMT_SOM void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm) { @@ -739,6 +735,7 @@ pg_table = (pte_t *) __va(pg_table) + start_pte; set_pte(pg_table, __mk_pte(address, PAGE_GATEWAY)); } +#endif extern void flush_tlb_all_local(void); diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/arch/sparc64/kernel/devices.c linux-2.5/arch/sparc64/kernel/devices.c --- ../prev/linux-2.5/arch/sparc64/kernel/devices.c Fri May 2 04:01:25 2003 +++ linux-2.5/arch/sparc64/kernel/devices.c Thu Apr 24 07:12:43 2003 @@ -40,7 +40,6 @@ /* FIX ME FAST... -DaveM */ ioport_resource.end = 0xffffffffffffffffUL; - iomem_resource.end = 0xffffffffffffffffUL; prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/ide/ide.c linux-2.5/drivers/ide/ide.c --- ../prev/linux-2.5/drivers/ide/ide.c Fri May 2 04:03:02 2003 +++ linux-2.5/drivers/ide/ide.c Wed Apr 23 19:35:47 2003 @@ -189,6 +189,7 @@ #endif EXPORT_SYMBOL(noautodma); +EXPORT_SYMBOL(ide_bus_type); /* * ide_modules keeps track of the available IDE chipset/probe/driver modules. diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/ide/pci/ns87415.c linux-2.5/drivers/ide/pci/ns87415.c --- ../prev/linux-2.5/drivers/ide/pci/ns87415.c Fri May 2 04:03:06 2003 +++ linux-2.5/drivers/ide/pci/ns87415.c Tue Feb 25 05:40:04 2003 @@ -25,6 +25,10 @@ #include +#if defined(__hppa__) && defined(CONFIG_SUPERIO) +#include +#endif + #include "ns87415.h" static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 }; @@ -200,7 +204,11 @@ } if (!using_inta) +#if defined(__hppa__) && defined(CONFIG_SUPERIO) + hwif->irq = superio_get_ide_irq(); /* legacy mode */ +#else hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */ +#endif else if (!hwif->irq && hwif->mate && hwif->mate->irq) hwif->irq = hwif->mate->irq; /* share IRQ with mate */ diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/keyboard/Kconfig linux-2.5/drivers/input/keyboard/Kconfig --- ../prev/linux-2.5/drivers/input/keyboard/Kconfig Fri May 2 04:03:11 2003 +++ linux-2.5/drivers/input/keyboard/Kconfig Mon Mar 24 20:18:17 2003 @@ -102,3 +102,30 @@ The module will be called xtkbd.o. If you want to compile it as a module, say M here and read . +config KEYBOARD_HIL_OLD + tristate "HP HIL keyboard support (simple driver)" + depends on PARISC && INPUT && INPUT_KEYBOARD && !HIL_MLC + default y + help + The "Human Interface Loop" is a older, 8-channel USB-like + controller used in several Hewlett Packard models. This driver + was adapted from the one written for m68k/hp300, and implements + support for a keyboard attached to the HIL port, but not for + any other types of HIL input devices like mice or tablets. + However, it has been thoroughly tested and is stable. + + If you want full HIL support including support for multiple + keyboards, mices and tablets, you have to enable the + "HP System Device Controller i8042 Support" in the input/serio + submenu. + +config KEYBOARD_HIL + tristate "HP HIL keyboard support" + depends on PARISC && INPUT && INPUT_KEYBOARD && HIL_MLC + default y + help + The "Human Interface Loop" is a older, 8-channel USB-like + controller used in several Hewlett Packard models. + This driver implements support for HIL-keyboards attached + to your machine, so normally you should say Y here. + diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/keyboard/Makefile linux-2.5/drivers/input/keyboard/Makefile --- ../prev/linux-2.5/drivers/input/keyboard/Makefile Fri May 2 04:03:11 2003 +++ linux-2.5/drivers/input/keyboard/Makefile Mon Mar 24 20:18:17 2003 @@ -2,8 +2,6 @@ # Makefile for the input core drivers. # -# Each configuration option enables a list of files. - obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o @@ -11,3 +9,5 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o +obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o +obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/keyboard/hil_kbd.c linux-2.5/drivers/input/keyboard/hil_kbd.c --- ../prev/linux-2.5/drivers/input/keyboard/hil_kbd.c Wed Dec 31 17:00:00 1969 +++ linux-2.5/drivers/input/keyboard/hil_kbd.c Sun Feb 2 15:46:21 2003 @@ -0,0 +1,456 @@ +/* + * Generic linux-input device driver for keyboard devices + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG /* DEBUG */ +#undef input_report_key +#define input_report_key(a,b,c) { printk("input_report_key(%p, %d, %d)\n", a, b, !!(c)); input_event(a, EV_KEY, b, !!(c)); } +#endif + +#define PREFIX "HIL KEYB: " +#define HIL_GENERIC_NAME "generic HIL keyboard device" + +MODULE_AUTHOR("Brian S. Julin "); +MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver"); +MODULE_LICENSE("Dual BSD/GPL"); + +#define HIL_KBD_MAX_LENGTH 16 + +#define HIL_KBD_SET1_UPBIT 0x01 +#define HIL_KBD_SET1_SHIFT 1 + +static uint8_t hil_kbd_set1[128] = { + KEY_5, KEY_RESERVED, KEY_RIGHTALT, KEY_LEFTALT, + KEY_RIGHTSHIFT, KEY_LEFTSHIFT, KEY_LEFTCTRL, KEY_SYSRQ, + KEY_KP4, KEY_KP8, KEY_KP5, KEY_KP9, + KEY_KP6, KEY_KP7, KEY_KPCOMMA, KEY_KPENTER, + KEY_KP1, KEY_KPSLASH, KEY_KP2, KEY_KPPLUS, + KEY_KP3, KEY_KPASTERISK, KEY_KP0, KEY_KPMINUS, + KEY_B, KEY_V, KEY_C, KEY_X, + KEY_Z, KEY_UNKNOWN, KEY_RESERVED, KEY_ESC, + KEY_6, KEY_F10, KEY_3, KEY_F11, + KEY_KPDOT, KEY_F9, KEY_TAB /*KP*/, KEY_F12, + KEY_H, KEY_G, KEY_F, KEY_D, + KEY_S, KEY_A, KEY_RESERVED, KEY_CAPSLOCK, + KEY_U, KEY_Y, KEY_T, KEY_R, + KEY_E, KEY_W, KEY_Q, KEY_TAB, + KEY_7, KEY_6, KEY_5, KEY_4, + KEY_3, KEY_2, KEY_1, KEY_GRAVE, + KEY_INTL1, KEY_INTL2, KEY_INTL3, KEY_INTL4, /*Buttons*/ + KEY_INTL5, KEY_INTL6, KEY_INTL7, KEY_INTL8, + KEY_MENU, KEY_F4, KEY_F3, KEY_F2, + KEY_F1, KEY_VOLUMEUP, KEY_STOP, KEY_SENDFILE/*Enter/Print*/, + KEY_SYSRQ, KEY_F5, KEY_F6, KEY_F7, + KEY_F8, KEY_VOLUMEDOWN, KEY_CUT /*CLEAR_LINE*/, KEY_REFRESH /*CLEAR_DISPLAY*/, + KEY_8, KEY_9, KEY_0, KEY_MINUS, + KEY_EQUAL, KEY_BACKSPACE, KEY_INSERT/*KPINSERT_LINE*/, KEY_DELETE /*KPDELETE_LINE*/, + KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, + KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_INSERT, KEY_DELETE, + KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, + KEY_APOSTROPHE, KEY_ENTER, KEY_HOME, KEY_SCROLLUP, + KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH, + KEY_RESERVED, KEY_OPEN/*Select*/,KEY_RESERVED,KEY_SCROLLDOWN/*KPNEXT*/, + KEY_N, KEY_SPACE, KEY_SCROLLDOWN/*Next*/, KEY_UNKNOWN, + KEY_LEFT, KEY_DOWN, KEY_UP, KEY_RIGHT +}; + +#define HIL_KBD_SET2_UPBIT 0x01 +#define HIL_KBD_SET2_SHIFT 1 + +/* Set2 is user defined */ + +#define HIL_KBD_SET3_UPBIT 0x80 +#define HIL_KBD_SET3_SHIFT 0 + +static uint8_t hil_kbd_set3[128] = { + KEY_RESERVED, KEY_ESC, KEY_1, KEY_2, + KEY_3, KEY_4, KEY_5, KEY_6, + KEY_7, KEY_8, KEY_9, KEY_0, + KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_TAB, + KEY_Q, KEY_W, KEY_E, KEY_R, + KEY_T, KEY_Y, KEY_U, KEY_I, + KEY_O, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, + KEY_ENTER, KEY_LEFTCTRL, KEY_A, KEY_S, + KEY_D, KEY_F, KEY_G, KEY_H, + KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, + KEY_APOSTROPHE,KEY_GRAVE, KEY_LEFTSHIFT, KEY_BACKSLASH, + KEY_Z, KEY_X, KEY_C, KEY_V, + KEY_B, KEY_N, KEY_M, KEY_COMMA, + KEY_DOT, KEY_SLASH, KEY_RIGHTSHIFT, KEY_KPASTERISK, + KEY_LEFTALT, KEY_SPACE, KEY_CAPSLOCK, KEY_F1, + KEY_F2, KEY_F3, KEY_F4, KEY_F5, + KEY_F6, KEY_F7, KEY_F8, KEY_F9, + KEY_F10, KEY_NUMLOCK, KEY_SCROLLLOCK, KEY_KP7, + KEY_KP8, KEY_KP9, KEY_KPMINUS, KEY_KP4, + KEY_KP5, KEY_KP6, KEY_KPPLUS, KEY_KP1, + KEY_KP2, KEY_KP3, KEY_KP0, KEY_KPDOT, + KEY_SYSRQ, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UP, KEY_LEFT, KEY_DOWN, KEY_RIGHT, + KEY_HOME, KEY_PAGEUP, KEY_END, KEY_PAGEDOWN, + KEY_INSERT, KEY_DELETE, KEY_102ND, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_F1, KEY_F2, KEY_F3, KEY_F4, + KEY_F5, KEY_F6, KEY_F7, KEY_F8, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, + KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED +}; + +static char hil_language[][16] = { HIL_LOCALE_MAP }; + +struct hil_kbd { + struct input_dev dev; + struct serio *serio; + + /* Input buffer and index for packets from HIL bus. */ + hil_packet data[HIL_KBD_MAX_LENGTH]; + int idx4; /* four counts per packet */ + + /* Raw device info records from HIL bus, see hil.h for fields. */ + char idd[HIL_KBD_MAX_LENGTH]; /* DID byte and IDD record */ + char rsc[HIL_KBD_MAX_LENGTH]; /* RSC record */ + char exd[HIL_KBD_MAX_LENGTH]; /* EXD record */ + char rnm[HIL_KBD_MAX_LENGTH + 1]; /* RNM record + NULL term. */ + + /* Something to sleep around with. */ + struct semaphore sem; +}; + +/* Process a complete packet after transfer from the HIL */ +static void hil_kbd_process_record(struct hil_kbd *kbd) +{ + struct input_dev *dev = &kbd->dev; + hil_packet *data = kbd->data; + hil_packet p; + int idx, i, cnt; + + idx = kbd->idx4/4; + p = data[idx - 1]; + + if ((p & ~HIL_CMDCT_POL) == + (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report; + if ((p & ~HIL_CMDCT_RPL) == + (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report; + + /* Not a poll response. See if we are loading config records. */ + switch (p & HIL_PKT_DATA_MASK) { + case HIL_CMD_IDD: + for (i = 0; i < idx; i++) + kbd->idd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_KBD_MAX_LENGTH; i++) + kbd->idd[i] = 0; + break; + case HIL_CMD_RSC: + for (i = 0; i < idx; i++) + kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_KBD_MAX_LENGTH; i++) + kbd->rsc[i] = 0; + break; + case HIL_CMD_EXD: + for (i = 0; i < idx; i++) + kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_KBD_MAX_LENGTH; i++) + kbd->exd[i] = 0; + break; + case HIL_CMD_RNM: + for (i = 0; i < idx; i++) + kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_KBD_MAX_LENGTH + 1; i++) + kbd->rnm[i] = '\0'; + break; + default: + /* These occur when device isn't present */ + if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; + /* Anything else we'd like to know about. */ + printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); + break; + } + goto out; + + report: + cnt = 1; + switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) { + case HIL_POL_CHARTYPE_NONE: + break; + case HIL_POL_CHARTYPE_ASCII: + while (cnt < idx - 1) + input_report_key(dev, kbd->data[cnt++] & 0x7f, 1); + break; + case HIL_POL_CHARTYPE_RSVD1: + case HIL_POL_CHARTYPE_RSVD2: + case HIL_POL_CHARTYPE_BINARY: + while (cnt < idx - 1) + input_report_key(dev, kbd->data[cnt++], 1); + break; + case HIL_POL_CHARTYPE_SET1: + while (cnt < idx - 1) { + unsigned int key; + int up; + key = kbd->data[cnt++]; + up = key & HIL_KBD_SET1_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); + key = key >> HIL_KBD_SET1_SHIFT; + if (key != KEY_RESERVED && key != KEY_UNKNOWN) + input_report_key(dev, hil_kbd_set1[key], !up); + } + break; + case HIL_POL_CHARTYPE_SET2: + while (cnt < idx - 1) { + unsigned int key; + int up; + key = kbd->data[cnt++]; + up = key & HIL_KBD_SET2_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); + key = key >> HIL_KBD_SET2_SHIFT; + if (key != KEY_RESERVED && key != KEY_UNKNOWN) + input_report_key(dev, key, !up); + } + break; + case HIL_POL_CHARTYPE_SET3: + while (cnt < idx - 1) { + unsigned int key; + int up; + key = kbd->data[cnt++]; + up = key & HIL_KBD_SET3_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); + key = key >> HIL_KBD_SET3_SHIFT; + if (key != KEY_RESERVED && key != KEY_UNKNOWN) + input_report_key(dev, hil_kbd_set3[key], !up); + } + break; + } + out: + kbd->idx4 = 0; + up(&kbd->sem); +} + +static void hil_kbd_process_err(struct hil_kbd *kbd) { + printk(KERN_WARNING PREFIX "errored HIL packet\n"); + kbd->idx4 = 0; + up(&kbd->sem); +} + +static void hil_kbd_interrupt(struct serio *serio, + unsigned char data, + unsigned int flags) +{ + struct hil_kbd *kbd; + hil_packet packet; + int idx; + + kbd = (struct hil_kbd *)serio->private; + if (kbd == NULL) { + BUG(); + return; + } + + if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) { + hil_kbd_process_err(kbd); + return; + } + idx = kbd->idx4/4; + if (!(kbd->idx4 % 4)) kbd->data[idx] = 0; + packet = kbd->data[idx]; + packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8); + kbd->data[idx] = packet; + + /* Records of N 4-byte hil_packets must terminate with a command. */ + if ((++(kbd->idx4)) % 4) return; + if ((packet & 0xffff0000) != HIL_ERR_INT) { + hil_kbd_process_err(kbd); + return; + } + if (packet & HIL_PKT_CMD) hil_kbd_process_record(kbd); +} + +static void hil_kbd_disconnect(struct serio *serio) +{ + struct hil_kbd *kbd; + + kbd = (struct hil_kbd *)serio->private; + if (kbd == NULL) { + BUG(); + return; + } + + input_unregister_device(&kbd->dev); + serio_close(serio); + kfree(kbd); +} + +static void hil_kbd_connect(struct serio *serio, struct serio_dev *dev) +{ + struct hil_kbd *kbd; + uint8_t did, *idd; + int i; + + if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return; + + if (!(kbd = kmalloc(sizeof(struct hil_kbd), GFP_KERNEL))) return; + memset(kbd, 0, sizeof(struct hil_kbd)); + + if (serio_open(serio, dev)) goto bail0; + + serio->private = kbd; + kbd->serio = serio; + kbd->dev.private = kbd; + + init_MUTEX_LOCKED(&(kbd->sem)); + + /* Get device info. MLC driver supplies devid/status/etc. */ + serio->write(serio, 0); + serio->write(serio, 0); + serio->write(serio, HIL_PKT_CMD >> 8); + serio->write(serio, HIL_CMD_IDD); + down(&(kbd->sem)); + + serio->write(serio, 0); + serio->write(serio, 0); + serio->write(serio, HIL_PKT_CMD >> 8); + serio->write(serio, HIL_CMD_RSC); + down(&(kbd->sem)); + + serio->write(serio, 0); + serio->write(serio, 0); + serio->write(serio, HIL_PKT_CMD >> 8); + serio->write(serio, HIL_CMD_RNM); + down(&(kbd->sem)); + + serio->write(serio, 0); + serio->write(serio, 0); + serio->write(serio, HIL_PKT_CMD >> 8); + serio->write(serio, HIL_CMD_EXD); + down(&(kbd->sem)); + + up(&(kbd->sem)); + + did = kbd->idd[0]; + idd = kbd->idd + 1; + switch (did & HIL_IDD_DID_TYPE_MASK) { + case HIL_IDD_DID_TYPE_KB_INTEGRAL: + case HIL_IDD_DID_TYPE_KB_ITF: + case HIL_IDD_DID_TYPE_KB_RSVD: + case HIL_IDD_DID_TYPE_CHAR: + printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n", + did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); + break; + default: + goto bail1; + } + + if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) { + printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n"); + goto bail1; + } + + kbd->dev.name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME; + + kbd->dev.id.bustype = BUS_HIL; + kbd->dev.id.vendor = SERIO_HIL; + kbd->dev.id.product = 0x0001; /* TODO: get from kbd->rsc */ + kbd->dev.id.version = 0x0100; /* TODO: get from kbd->rsc */ + + kbd->dev.evbit[0] |= BIT(EV_KEY); + + for (i = 0; i < 128; i++) { + set_bit(hil_kbd_set1[i], kbd->dev.keybit); + set_bit(hil_kbd_set3[i], kbd->dev.keybit); + } + clear_bit(0, kbd->dev.keybit); + +#if 0 + /* XXX: HACK !!! + * remove this call if hp_psaux.c/hp_keyb.c is converted + * to the input layer... */ + register_ps2_keybfuncs(); +#endif + + input_register_device(&kbd->dev); +#warning TODO Boottime printk needs update, as well as dev.name. + printk(KERN_INFO "input: %s, %s on hil%d\n", + kbd->dev.name, "HIL keyboard", 0); + + /* HIL keyboards don't have a numlock key, + * simulate a up-down sequence of numlock to + * make the keypad work at expected. */ + input_report_key(&kbd->dev, KEY_NUMLOCK, 1); +/* input_report_key(&kbd->dev, KEY_NUMLOCK, 0); */ + + serio->write(serio, 0); + serio->write(serio, 0); + serio->write(serio, HIL_PKT_CMD >> 8); + serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */ + down(&(kbd->sem)); + up(&(kbd->sem)); + + return; + bail1: + serio_close(serio); + bail0: + kfree(kbd); +} + + +struct serio_dev hil_kbd_serio_dev = { + .connect = hil_kbd_connect, + .disconnect = hil_kbd_disconnect, + .interrupt = hil_kbd_interrupt +}; + +static int __init hil_kbd_init(void) +{ + serio_register_device(&hil_kbd_serio_dev); + return 0; +} + +static void __exit hil_kbd_exit(void) +{ + serio_unregister_device(&hil_kbd_serio_dev); +#if 0 + /* XXX: HACK !!! + * remove this call if hp_psaux.c/hp_keyb.c is converted + * to the input layer... */ + unregister_kbd_ops(); +#endif +} + +module_init(hil_kbd_init); +module_exit(hil_kbd_exit); diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/keyboard/hilkbd.c linux-2.5/drivers/input/keyboard/hilkbd.c --- ../prev/linux-2.5/drivers/input/keyboard/hilkbd.c Wed Dec 31 17:00:00 1969 +++ linux-2.5/drivers/input/keyboard/hilkbd.c Wed Nov 6 21:04:36 2002 @@ -0,0 +1,390 @@ +/* + * linux/drivers/hil/hilkbd.c + * + * Copyright (C) 1998 Philip Blundell + * Copyright (C) 1999 Matthew Wilcox + * Copyright (C) 1999-2002 Helge Deller + * + * Very basic HP Human Interface Loop (HIL) driver. + * This driver handles the keyboard on HP300 (m68k) and on some + * HP700 (parisc) series machines. + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License version 2. See the file COPYING in the main directory of this + * archive for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +MODULE_AUTHOR("Philip Blundell, Matthew Wilcox, Helge Deller"); +MODULE_DESCRIPTION("HIL driver (basic functionality)"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; + + +#if defined(CONFIG_PARISC) + + #include + #include + static unsigned long hil_base; /* HPA for the HIL device */ + static unsigned int hil_irq; + #define HILBASE hil_base /* HPPA (parisc) port address */ + #define HIL_DATA 0x800 + #define HIL_CMD 0x801 + #define HIL_IRQ hil_irq + #define hil_readb(p) gsc_readb(p) + #define hil_writeb(v,p) gsc_writeb((v),(p)) + +#elif defined(CONFIG_HP300) + + #define HILBASE 0xf0428000 /* HP300 (m86k) port address */ + #define HIL_DATA 0x1 + #define HIL_CMD 0x3 + #define HIL_IRQ 2 + #define hil_readb(p) readb(p) + #define hil_writeb(v,p) writeb((v),(p)) + +#else +#error "HIL is not supported on this platform" +#endif + + + +/* HIL helper functions */ + +#define hil_busy() (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY) +#define hil_data_available() (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY) +#define hil_status() (hil_readb(HILBASE + HIL_CMD)) +#define hil_command(x) do { hil_writeb((x), HILBASE + HIL_CMD); } while (0) +#define hil_read_data() (hil_readb(HILBASE + HIL_DATA)) +#define hil_write_data(x) do { hil_writeb((x), HILBASE + HIL_DATA); } while (0) + +/* HIL constants */ + +#define HIL_BUSY 0x02 +#define HIL_DATA_RDY 0x01 + +#define HIL_SETARD 0xA0 /* set auto-repeat delay */ +#define HIL_SETARR 0xA2 /* set auto-repeat rate */ +#define HIL_SETTONE 0xA3 /* set tone generator */ +#define HIL_CNMT 0xB2 /* clear nmi */ +#define HIL_INTON 0x5C /* Turn on interrupts. */ +#define HIL_INTOFF 0x5D /* Turn off interrupts. */ +#define HIL_TRIGGER 0xC5 /* trigger command */ +#define HIL_STARTCMD 0xE0 /* start loop command */ +#define HIL_TIMEOUT 0xFE /* timeout */ +#define HIL_READTIME 0x13 /* Read real time register */ + +#define HIL_READBUSY 0x02 /* internal "busy" register */ +#define HIL_READKBDLANG 0x12 /* read keyboard language code */ +#define HIL_READKBDSADR 0xF9 +#define HIL_WRITEKBDSADR 0xE9 +#define HIL_READLPSTAT 0xFA +#define HIL_WRITELPSTAT 0xEA +#define HIL_READLPCTRL 0xFB +#define HIL_WRITELPCTRL 0xEB + + +static unsigned char hil_kbd_set1[128] = { + KEY_5, KEY_RESERVED, KEY_RIGHTALT, KEY_LEFTALT, + KEY_RIGHTSHIFT, KEY_LEFTSHIFT, KEY_LEFTCTRL, KEY_SYSRQ, + KEY_KP4, KEY_KP8, KEY_KP5, KEY_KP9, + KEY_KP6, KEY_KP7, KEY_KPCOMMA, KEY_KPENTER, + KEY_KP1, KEY_KPSLASH, KEY_KP2, KEY_KPPLUS, + KEY_KP3, KEY_KPASTERISK, KEY_KP0, KEY_KPMINUS, + KEY_B, KEY_V, KEY_C, KEY_X, + KEY_Z, KEY_UNKNOWN, KEY_RESERVED, KEY_ESC, + KEY_6, KEY_F10, KEY_3, KEY_F11, + KEY_KPDOT, KEY_F9, KEY_TAB /*KP*/, KEY_F12, + KEY_H, KEY_G, KEY_F, KEY_D, + KEY_S, KEY_A, KEY_RESERVED, KEY_CAPSLOCK, + KEY_U, KEY_Y, KEY_T, KEY_R, + KEY_E, KEY_W, KEY_Q, KEY_TAB, + KEY_7, KEY_6, KEY_5, KEY_4, + KEY_3, KEY_2, KEY_1, KEY_GRAVE, + KEY_INTL1, KEY_INTL2, KEY_INTL3, KEY_INTL4, /*Buttons*/ + KEY_INTL5, KEY_INTL6, KEY_INTL7, KEY_INTL8, + KEY_MENU, KEY_F4, KEY_F3, KEY_F2, + KEY_F1, KEY_VOLUMEUP, KEY_STOP, KEY_SENDFILE/*Enter/Print*/, + KEY_SYSRQ, KEY_F5, KEY_F6, KEY_F7, + KEY_F8, KEY_VOLUMEDOWN, KEY_CUT /*CLEAR_LINE*/, KEY_REFRESH /*CLEAR_DISPLAY*/, + KEY_8, KEY_9, KEY_0, KEY_MINUS, + KEY_EQUAL, KEY_BACKSPACE, KEY_INSERT/*KPINSERT_LINE*/, KEY_DELETE /*KPDELETE_LINE*/, + KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, + KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_INSERT, KEY_DELETE, + KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, + KEY_APOSTROPHE, KEY_ENTER, KEY_HOME, KEY_SCROLLUP, + KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH, + KEY_RESERVED, KEY_OPEN/*Select*/,KEY_RESERVED,KEY_SCROLLDOWN/*KPNEXT*/, + KEY_N, KEY_SPACE, KEY_SCROLLDOWN/*Next*/, KEY_UNKNOWN, + KEY_LEFT, KEY_DOWN, KEY_UP, KEY_RIGHT +}; + + +/* HIL structure */ +static struct { + struct input_dev dev; + + unsigned int curdev; + + unsigned char s; + unsigned char c; + int valid; + + unsigned char data[16]; + unsigned int ptr; + spinlock_t lock; + + void *dev_id; /* native bus device */ +} hil_dev; + + +static void poll_finished(void) +{ + int down; + int key; + unsigned char scode; + + switch (hil_dev.data[0]) { + case 0x40: + down = (hil_dev.data[1] & 1) == 0; + scode = hil_dev.data[1] >> 1; + key = hil_kbd_set1[scode & 0x7f]; + input_report_key(&hil_dev.dev, key, down); + break; + } + hil_dev.curdev = 0; +} + +static inline void handle_status(unsigned char s, unsigned char c) +{ + if (c & 0x8) { + /* End of block */ + if (c & 0x10) + poll_finished(); + } else { + if (c & 0x10) { + if (hil_dev.curdev) + poll_finished(); /* just in case */ + hil_dev.curdev = c & 7; + hil_dev.ptr = 0; + } + } +} + +static inline void handle_data(unsigned char s, unsigned char c) +{ + if (hil_dev.curdev) { + hil_dev.data[hil_dev.ptr++] = c; + hil_dev.ptr &= 15; + } +} + + +/* + * Handle HIL interrupts. + */ +static void hil_interrupt(int irq, void *handle, struct pt_regs *regs) +{ + unsigned char s, c; + + s = hil_status(); + c = hil_read_data(); + + switch (s >> 4) { + case 0x5: + handle_status(s, c); + break; + case 0x6: + handle_data(s, c); + break; + case 0x4: + hil_dev.s = s; + hil_dev.c = c; + mb(); + hil_dev.valid = 1; + break; + } +} + +/* + * Send a command to the HIL + */ + +static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len) +{ + unsigned long flags; + + spin_lock_irqsave(&hil_dev.lock, flags); + while (hil_busy()) + /* wait */; + hil_command(cmd); + while (len--) { + while (hil_busy()) + /* wait */; + hil_write_data(*(data++)); + } + spin_lock_irqrestore(&hil_dev.lock, flags); +} + + +/* + * Initialise HIL. + */ + +static int __init +hil_keyb_init(void) +{ + unsigned char c; + unsigned int i, kbid, n = 0; + + if (hil_dev.dev.idbus) { + printk("HIL: already initialized\n"); + return -ENODEV; + } + +#if defined(CONFIG_HP300) + if (!hwreg_present((void *)(HILBASE + HIL_DATA))) + return -ENODEV; + + request_region(HILBASE+HIL_DATA, 2, "hil"); +#endif + + request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id); + + /* Turn on interrupts */ + hil_do(HIL_INTON, NULL, 0); + + /* Look for keyboards */ + hil_dev.valid = 0; /* clear any pending data */ + hil_do(HIL_READKBDSADR, NULL, 0); + while (!hil_dev.valid) { + if (n++ > 100000) { + printk(KERN_DEBUG "HIL: timed out, assuming no keyboard present.\n"); + break; + } + mb(); + } + + c = hil_dev.c; + hil_dev.valid = 0; + if (c == 0) { + kbid = -1; + printk(KERN_WARNING "HIL: no keyboard present.\n"); + } else { + kbid = ffz(~c); + printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid); + } + + /* set it to raw mode */ + c = 0; + hil_do(HIL_WRITEKBDSADR, &c, 1); + + + /* register input interface */ + hil_dev.dev.name = "HIL keyboard"; + hil_dev.dev.idbus = BUS_HIL; + hil_dev.dev.idvendor = PCI_VENDOR_ID_HP; + hil_dev.dev.idproduct = 0x0001; + hil_dev.dev.idversion = 0x0100; + + hil_dev.dev.evbit[0] |= BIT(EV_KEY); + for (i = 0; i < 128; i++) + set_bit(hil_kbd_set1[i], hil_dev.dev.keybit); + clear_bit(0, hil_dev.dev.keybit); + +#if 1 + /* XXX: HACK !!! + * remove this call if hp_psaux.c/hp_keyb.c is converted + * to the input layer... */ + register_ps2_keybfuncs(); +#endif + + input_register_device(&hil_dev.dev); + printk(KERN_INFO "input%d: %s on hil%d (id %d)\n", + hil_dev.dev.number, hil_dev.dev.name, 0, kbid); + + /* HIL keyboards don't have a numlock key, + * simulate a up-down sequence of numlock to + * make the keypad work at expected. */ + input_report_key(&hil_dev.dev, KEY_NUMLOCK, 1); + + return 0; +} + +#if defined(CONFIG_PARISC) +static int __init +hil_init_chip(struct parisc_device *dev) +{ + if (!dev->irq) { + printk(KERN_WARNING "HIL: IRQ not found for HIL at 0x%lx\n", dev->hpa); + return -ENODEV; + } + + hil_base = dev->hpa; + hil_irq = dev->irq; + hil_dev.dev_id = dev; + + printk(KERN_INFO "Found HIL at 0x%lx, IRQ %d\n", hil_base, hil_irq); + + return hil_keyb_init(); +} + +static struct parisc_device_id hil_tbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00073 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(parisc, hil_tbl); + +static struct parisc_driver hil_driver = { + .name = "HIL", + .id_table = hil_tbl, + .probe = hil_init_chip, +}; +#endif /* CONFIG_PARISC */ + + + + + +static int __init hil_init(void) +{ +#if defined(CONFIG_PARISC) + return register_parisc_driver(&hil_driver); +#else + return hil_keyb_init(); +#endif +} + + +static void __exit hil_exit(void) +{ + if (HIL_IRQ) { + disable_irq(HIL_IRQ); + free_irq(HIL_IRQ, hil_dev.dev_id); + } + + input_unregister_device(&hil_dev.dev); + +#if defined(CONFIG_PARISC) + unregister_parisc_driver(&hil_driver); +#else + release_region(HILBASE+HIL_DATA, 2); +#endif +} + +module_init(hil_init); +module_exit(hil_exit); + diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/misc/Kconfig linux-2.5/drivers/input/misc/Kconfig --- ../prev/linux-2.5/drivers/input/misc/Kconfig Fri May 2 04:03:11 2003 +++ linux-2.5/drivers/input/misc/Kconfig Fri Feb 14 20:47:38 2003 @@ -69,3 +69,7 @@ XT mode like everyone else, so we need our own driver. Furthermore, the GSC PS/2 controller shares IRQ between mouse and keyboard. + +config HP_SDC_RTC + tristate "HP SDC Real Time Clock" + depends on HP_SDC diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/misc/Makefile linux-2.5/drivers/input/misc/Makefile --- ../prev/linux-2.5/drivers/input/misc/Makefile Fri May 2 04:03:11 2003 +++ linux-2.5/drivers/input/misc/Makefile Fri Feb 14 20:47:38 2003 @@ -9,4 +9,5 @@ obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_98SPKR) += 98spkr.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o +obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_GSC) += gsc_ps2.o diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/misc/gsc_ps2.c linux-2.5/drivers/input/misc/gsc_ps2.c --- ../prev/linux-2.5/drivers/input/misc/gsc_ps2.c Fri May 2 04:03:11 2003 +++ linux-2.5/drivers/input/misc/gsc_ps2.c Wed Mar 12 08:53:18 2003 @@ -56,12 +56,12 @@ #include /* for request_irq/free_irq */ #include #include -#include #include #include #include #include +#include /* Debugging stuff */ #undef KBD_DEBUG @@ -79,6 +79,7 @@ /* PS/2 keyboard and mouse constants */ #define AUX_RECONNECT 0xAA /* PS/2 Mouse end of test successful */ #define AUX_REPLY_ACK 0xFA +#define AUX_ENABLE_DEV 0xF4 /* Enables aux device */ /* Order of the mouse bytes coming to the host */ #define PACKET_X 1 @@ -131,6 +132,12 @@ #define MOUSE_XOVFLOW 0x40 #define MOUSE_YOVFLOW 0x80 +/* Remnant of pc_keyb.h */ +#define KBD_CMD_SET_LEDS 0xED /* Sets keyboard leds */ +#define KBD_CMD_SET_RATE 0xF3 /* Sets typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enables scanning */ +#define KBD_CMD_DISABLE 0xF5 +#define KBD_CMD_RESET 0xFF static unsigned char hpkeyb_keycode[KBD_TBLSIZE] = { @@ -341,7 +348,7 @@ default: hpkeyb.scancode = scancode; DPRINTK("sent=%d, rel=%d\n",hpkeyb.scancode, hpkeyb.released); - input_regs(regs); + /*input_regs(regs);*/ input_report_key(&hpkeyb.dev, hpkeyb_keycode[hpkeyb.scancode], !hpkeyb.released); input_sync(&hpkeyb.dev); if (hpkeyb.escaped) @@ -388,7 +395,7 @@ if ((hpmouse.bytes[PACKET_CTRL] & (MOUSE_XOVFLOW | MOUSE_YOVFLOW))) DPRINTK("Mouse: position overflow\n"); - input_regs(regs); + /*input_regs(regs);*/ input_report_key(&hpmouse.dev, BTN_LEFT, hpmouse.bytes[PACKET_CTRL] & MOUSE_LEFTBTN); input_report_key(&hpmouse.dev, BTN_MIDDLE, hpmouse.bytes[PACKET_CTRL] & MOUSE_MIDBTN); @@ -580,7 +587,7 @@ { u8 id; char *addr, *name; - int ret, device_found = 0; + int ret = 0, device_found = 0; unsigned long hpa = dev->hpa; if (!dev->irq) diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/misc/hp_sdc_rtc.c linux-2.5/drivers/input/misc/hp_sdc_rtc.c --- ../prev/linux-2.5/drivers/input/misc/hp_sdc_rtc.c Wed Dec 31 17:00:00 1969 +++ linux-2.5/drivers/input/misc/hp_sdc_rtc.c Wed Nov 6 21:04:36 2002 @@ -0,0 +1,720 @@ +/* + * HP i8042 SDC + MSM-58321 BBRTC driver. + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * System Device Controller Microprocessor Firmware Theory of Operation + * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 + * efirtc.c by Stephane Eranian/Hewlett Packard + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Brian S. Julin "); +MODULE_DESCRIPTION("HP i8042 SDC + MSM-58321 RTC Driver"); +MODULE_LICENSE("Dual BSD/GPL"); + +#define RTC_VERSION "1.10d" + +static unsigned long epoch = 2000; + +static struct semaphore i8042tregs; + +static hp_sdc_irqhook hp_sdc_rtc_isr; + +static struct fasync_struct *hp_sdc_rtc_async_queue; + +static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait); + +static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin); + +static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, + size_t count, loff_t *ppos); + +static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait); + +static int hp_sdc_rtc_open(struct inode *inode, struct file *file); +static int hp_sdc_rtc_release(struct inode *inode, struct file *file); +static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on); + +static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data); + +static void hp_sdc_rtc_isr (int irq, void *dev_id, + uint8_t status, uint8_t data) +{ + return; +} + +static int hp_sdc_rtc_do_read_bbrtc (struct rtc_time *rtctm) +{ + struct semaphore tsem; + hp_sdc_transaction t; + uint8_t tseq[91]; + int i; + + i = 0; + while (i < 91) { + tseq[i++] = HP_SDC_ACT_DATAREG | + HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN; + tseq[i++] = 0x01; /* write i8042[0x70] */ + tseq[i] = i / 7; /* BBRTC reg address */ + i++; + tseq[i++] = HP_SDC_CMD_DO_RTCR; /* Trigger command */ + tseq[i++] = 2; /* expect 1 stat/dat pair back. */ + i++; i++; /* buffer for stat/dat pair */ + } + tseq[84] |= HP_SDC_ACT_SEMAPHORE; + t.endidx = 91; + t.seq = tseq; + t.act.semaphore = &tsem; + init_MUTEX_LOCKED(&tsem); + + if (hp_sdc_enqueue_transaction(&t)) return -1; + + down_interruptible(&tsem); /* Put ourselves to sleep for results. */ + + /* Check for nonpresence of BBRTC */ + if (!((tseq[83] | tseq[90] | tseq[69] | tseq[76] | + tseq[55] | tseq[62] | tseq[34] | tseq[41] | + tseq[20] | tseq[27] | tseq[6] | tseq[13]) & 0x0f)) + return -1; + + memset(rtctm, 0, sizeof(struct rtc_time)); + rtctm->tm_year = (tseq[83] & 0x0f) + (tseq[90] & 0x0f) * 10; + rtctm->tm_mon = (tseq[69] & 0x0f) + (tseq[76] & 0x0f) * 10; + rtctm->tm_mday = (tseq[55] & 0x0f) + (tseq[62] & 0x0f) * 10; + rtctm->tm_wday = (tseq[48] & 0x0f); + rtctm->tm_hour = (tseq[34] & 0x0f) + (tseq[41] & 0x0f) * 10; + rtctm->tm_min = (tseq[20] & 0x0f) + (tseq[27] & 0x0f) * 10; + rtctm->tm_sec = (tseq[6] & 0x0f) + (tseq[13] & 0x0f) * 10; + + return 0; +} + +static int hp_sdc_rtc_read_bbrtc (struct rtc_time *rtctm) +{ + struct rtc_time tm, tm_last; + int i = 0; + + /* MSM-58321 has no read latch, so must read twice and compare. */ + + if (hp_sdc_rtc_do_read_bbrtc(&tm_last)) return -1; + if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1; + + while (memcmp(&tm, &tm_last, sizeof(struct rtc_time))) { + if (i++ > 4) return -1; + memcpy(&tm_last, &tm, sizeof(struct rtc_time)); + if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1; + } + + memcpy(rtctm, &tm, sizeof(struct rtc_time)); + + return 0; +} + + +static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg) +{ + hp_sdc_transaction t; + uint8_t tseq[26] = { + HP_SDC_ACT_PRECMD | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, + 0, + HP_SDC_CMD_READ_T1, 2, 0, 0, + HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, + HP_SDC_CMD_READ_T2, 2, 0, 0, + HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, + HP_SDC_CMD_READ_T3, 2, 0, 0, + HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, + HP_SDC_CMD_READ_T4, 2, 0, 0, + HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, + HP_SDC_CMD_READ_T5, 2, 0, 0 + }; + + t.endidx = numreg * 5; + + tseq[1] = loadcmd; + tseq[t.endidx - 4] |= HP_SDC_ACT_SEMAPHORE; /* numreg assumed > 1 */ + + t.seq = tseq; + t.act.semaphore = &i8042tregs; + + down_interruptible(&i8042tregs); /* Sleep if output regs in use. */ + + if (hp_sdc_enqueue_transaction(&t)) return -1; + + down_interruptible(&i8042tregs); /* Sleep until results come back. */ + up(&i8042tregs); + + return (tseq[5] | + ((uint64_t)(tseq[10]) << 8) | ((uint64_t)(tseq[15]) << 16) | + ((uint64_t)(tseq[20]) << 24) | ((uint64_t)(tseq[25]) << 32)); +} + + +/* Read the i8042 real-time clock */ +static inline int hp_sdc_rtc_read_rt(struct timeval *res) { + int64_t raw; + uint32_t tenms; + unsigned int days; + + raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_RT, 5); + if (raw < 0) return -1; + + tenms = (uint32_t)raw & 0xffffff; + days = (unsigned int)(raw >> 24) & 0xffff; + + res->tv_usec = (suseconds_t)(tenms % 100) * 10000; + res->tv_sec = (time_t)(tenms / 100) + days * 86400; + + return 0; +} + + +/* Read the i8042 fast handshake timer */ +static inline int hp_sdc_rtc_read_fhs(struct timeval *res) { + uint64_t raw; + unsigned int tenms; + + raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_FHS, 2); + if (raw < 0) return -1; + + tenms = (unsigned int)raw & 0xffff; + + res->tv_usec = (suseconds_t)(tenms % 100) * 10000; + res->tv_sec = (time_t)(tenms / 100); + + return 0; +} + + +/* Read the i8042 match timer (a.k.a. alarm) */ +static inline int hp_sdc_rtc_read_mt(struct timeval *res) { + int64_t raw; + uint32_t tenms; + + raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_MT, 3); + if (raw < 0) return -1; + + tenms = (uint32_t)raw & 0xffffff; + + res->tv_usec = (suseconds_t)(tenms % 100) * 10000; + res->tv_sec = (time_t)(tenms / 100); + + return 0; +} + + +/* Read the i8042 delay timer */ +static inline int hp_sdc_rtc_read_dt(struct timeval *res) { + int64_t raw; + uint32_t tenms; + + raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_DT, 3); + if (raw < 0) return -1; + + tenms = (uint32_t)raw & 0xffffff; + + res->tv_usec = (suseconds_t)(tenms % 100) * 10000; + res->tv_sec = (time_t)(tenms / 100); + + return 0; +} + + +/* Read the i8042 cycle timer (a.k.a. periodic) */ +static inline int hp_sdc_rtc_read_ct(struct timeval *res) { + int64_t raw; + uint32_t tenms; + + raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_CT, 3); + if (raw < 0) return -1; + + tenms = (uint32_t)raw & 0xffffff; + + res->tv_usec = (suseconds_t)(tenms % 100) * 10000; + res->tv_sec = (time_t)(tenms / 100); + + return 0; +} + + +/* Set the i8042 real-time clock */ +static int hp_sdc_rtc_set_rt (struct timeval *setto) +{ + uint32_t tenms; + unsigned int days; + hp_sdc_transaction t; + uint8_t tseq[11] = { + HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, + HP_SDC_CMD_SET_RTMS, 3, 0, 0, 0, + HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, + HP_SDC_CMD_SET_RTD, 2, 0, 0 + }; + + t.endidx = 10; + + if (0xffff < setto->tv_sec / 86400) return -1; + days = setto->tv_sec / 86400; + if (0xffff < setto->tv_usec / 1000000 / 86400) return -1; + days += ((setto->tv_sec % 86400) + setto->tv_usec / 1000000) / 86400; + if (days > 0xffff) return -1; + + if (0xffffff < setto->tv_sec) return -1; + tenms = setto->tv_sec * 100; + if (0xffffff < setto->tv_usec / 10000) return -1; + tenms += setto->tv_usec / 10000; + if (tenms > 0xffffff) return -1; + + tseq[3] = (uint8_t)(tenms & 0xff); + tseq[4] = (uint8_t)((tenms >> 8) & 0xff); + tseq[5] = (uint8_t)((tenms >> 16) & 0xff); + + tseq[9] = (uint8_t)(days & 0xff); + tseq[10] = (uint8_t)((days >> 8) & 0xff); + + t.seq = tseq; + + if (hp_sdc_enqueue_transaction(&t)) return -1; + return 0; +} + +/* Set the i8042 fast handshake timer */ +static int hp_sdc_rtc_set_fhs (struct timeval *setto) +{ + uint32_t tenms; + hp_sdc_transaction t; + uint8_t tseq[5] = { + HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, + HP_SDC_CMD_SET_FHS, 2, 0, 0 + }; + + t.endidx = 4; + + if (0xffff < setto->tv_sec) return -1; + tenms = setto->tv_sec * 100; + if (0xffff < setto->tv_usec / 10000) return -1; + tenms += setto->tv_usec / 10000; + if (tenms > 0xffff) return -1; + + tseq[3] = (uint8_t)(tenms & 0xff); + tseq[4] = (uint8_t)((tenms >> 8) & 0xff); + + t.seq = tseq; + + if (hp_sdc_enqueue_transaction(&t)) return -1; + return 0; +} + + +/* Set the i8042 match timer (a.k.a. alarm) */ +#define hp_sdc_rtc_set_mt (setto) \ + hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_MT) + +/* Set the i8042 delay timer */ +#define hp_sdc_rtc_set_dt (setto) \ + hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_DT) + +/* Set the i8042 cycle timer (a.k.a. periodic) */ +#define hp_sdc_rtc_set_ct (setto) \ + hp_sdc_rtc_set_i8042timer(setto, HP_SDC_CMD_SET_CT) + +/* Set one of the i8042 3-byte wide timers */ +static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd) +{ + uint32_t tenms; + hp_sdc_transaction t; + uint8_t tseq[6] = { + HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT, + 0, 3, 0, 0, 0 + }; + + t.endidx = 6; + + if (0xffffff < setto->tv_sec) return -1; + tenms = setto->tv_sec * 100; + if (0xffffff < setto->tv_usec / 10000) return -1; + tenms += setto->tv_usec / 10000; + if (tenms > 0xffffff) return -1; + + tseq[1] = setcmd; + tseq[3] = (uint8_t)(tenms & 0xff); + tseq[4] = (uint8_t)((tenms >> 8) & 0xff); + tseq[5] = (uint8_t)((tenms >> 16) & 0xff); + + t.seq = tseq; + + if (hp_sdc_enqueue_transaction(&t)) { + return -1; + } + return 0; +} + +static loff_t hp_sdc_rtc_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static ssize_t hp_sdc_rtc_read(struct file *file, char *buf, + size_t count, loff_t *ppos) { + ssize_t retval; + + if (count < sizeof(unsigned long)) + return -EINVAL; + + retval = put_user(68, (unsigned long *)buf); + return retval; +} + +static unsigned int hp_sdc_rtc_poll(struct file *file, poll_table *wait) +{ + unsigned long l; + + l = 0; + if (l != 0) + return POLLIN | POLLRDNORM; + return 0; +} + +static int hp_sdc_rtc_open(struct inode *inode, struct file *file) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int hp_sdc_rtc_release(struct inode *inode, struct file *file) +{ + /* Turn off interrupts? */ + + if (file->f_flags & FASYNC) { + hp_sdc_rtc_fasync (-1, file, 0); + } + + MOD_DEC_USE_COUNT; + return 0; +} + +static int hp_sdc_rtc_fasync (int fd, struct file *filp, int on) +{ + return fasync_helper (fd, filp, on, &hp_sdc_rtc_async_queue); +} + +static int hp_sdc_rtc_proc_output (char *buf) +{ +#define YN(bit) ("no") +#define NY(bit) ("yes") + char *p; + struct rtc_time tm; + struct timeval tv; + + memset(&tm, 0, sizeof(struct rtc_time)); + + p = buf; + + if (hp_sdc_rtc_read_bbrtc(&tm)) { + p += sprintf(p, "BBRTC\t\t: READ FAILED!\n"); + } else { + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, + tm.tm_mday, epoch); + } + + if (hp_sdc_rtc_read_rt(&tv)) { + p += sprintf(p, "i8042 rtc\t: READ FAILED!\n"); + } else { + p += sprintf(p, "i8042 rtc\t: %d.%02d seconds\n", + tv.tv_sec, tv.tv_usec/1000); + } + + if (hp_sdc_rtc_read_fhs(&tv)) { + p += sprintf(p, "handshake\t: READ FAILED!\n"); + } else { + p += sprintf(p, "handshake\t: %d.%02d seconds\n", + tv.tv_sec, tv.tv_usec/1000); + } + + if (hp_sdc_rtc_read_mt(&tv)) { + p += sprintf(p, "alarm\t\t: READ FAILED!\n"); + } else { + p += sprintf(p, "alarm\t\t: %d.%02d seconds\n", + tv.tv_sec, tv.tv_usec/1000); + } + + if (hp_sdc_rtc_read_dt(&tv)) { + p += sprintf(p, "delay\t\t: READ FAILED!\n"); + } else { + p += sprintf(p, "delay\t\t: %d.%02d seconds\n", + tv.tv_sec, tv.tv_usec/1000); + } + + if (hp_sdc_rtc_read_ct(&tv)) { + p += sprintf(p, "periodic\t: READ FAILED!\n"); + } else { + p += sprintf(p, "periodic\t: %d.%02d seconds\n", + tv.tv_sec, tv.tv_usec/1000); + } + + p += sprintf(p, + "DST_enable\t: %s\n" + "BCD\t\t: %s\n" + "24hr\t\t: %s\n" + "square_wave\t: %s\n" + "alarm_IRQ\t: %s\n" + "update_IRQ\t: %s\n" + "periodic_IRQ\t: %s\n" + "periodic_freq\t: %ld\n" + "batt_status\t: %s\n", + YN(RTC_DST_EN), + NY(RTC_DM_BINARY), + YN(RTC_24H), + YN(RTC_SQWE), + YN(RTC_AIE), + YN(RTC_UIE), + YN(RTC_PIE), + 1UL, + 1 ? "okay" : "dead"); + + return p - buf; +#undef YN +#undef NY +} + +static int hp_sdc_rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = hp_sdc_rtc_proc_output (page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ +#if 1 + return -EINVAL; +#else + + struct rtc_time wtime; + struct timeval ttime; + int use_wtime = 0; + + /* This needs major work. */ + + switch (cmd) { + + case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ + case RTC_AIE_ON: /* Allow alarm interrupts. */ + case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ + case RTC_PIE_ON: /* Allow periodic ints */ + case RTC_UIE_ON: /* Allow ints for RTC updates. */ + case RTC_UIE_OFF: /* Allow ints for RTC updates. */ + { + /* We cannot mask individual user timers and we + cannot tell them apart when they occur, so it + would be disingenuous to succeed these IOCTLs */ + return -EINVAL; + } + case RTC_ALM_READ: /* Read the present alarm time */ + { + if (hp_sdc_rtc_read_mt(&ttime)) return -EFAULT; + break; + } + case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ + { + return put_user(hp_sdc_rtc_freq, (unsigned long *)arg); + } + case RTC_IRQP_SET: /* Set periodic IRQ rate. */ + { + /* + * The max we can do is 100Hz. + */ + + if ((arg < 1) || (arg > 100)) return -EINVAL; + ttime.tv_sec = 0; + ttime.tv_usec = 1000000 / arg; + if (hp_sdc_rtc_set_ct(&ttime)) return -EFAULT; + hp_sdc_rtc_freq = arg; + return 0; + } + case RTC_ALM_SET: /* Store a time into the alarm */ + { + /* + * This expects a struct hp_sdc_rtc_time. Writing 0xff means + * "don't care" or "match all" for PC timers. The HP SDC + * does not support that perk, but it could be emulated fairly + * easily. Only the tm_hour, tm_min and tm_sec are used. + * We could do it with 10ms accuracy with the HP SDC, if the + * rtc interface left us a way to do that. + */ + struct hp_sdc_rtc_time alm_tm; + + if (copy_from_user(&alm_tm, (struct hp_sdc_rtc_time*)arg, + sizeof(struct hp_sdc_rtc_time))) + return -EFAULT; + + if (alm_tm.tm_hour > 23) return -EINVAL; + if (alm_tm.tm_min > 59) return -EINVAL; + if (alm_tm.tm_sec > 59) return -EINVAL; + + ttime.sec = alm_tm.tm_hour * 3600 + + alm_tm.tm_min * 60 + alm_tm.tm_sec; + ttime.usec = 0; + if (hp_sdc_rtc_set_mt(&ttime)) return -EFAULT; + return 0; + } + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + if (hp_sdc_rtc_read_bbrtc(&wtime)) return -EFAULT; + break; + } + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time hp_sdc_rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned int yrs; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + if (copy_from_user(&hp_sdc_rtc_tm, (struct rtc_time *)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = hp_sdc_rtc_tm.tm_year + 1900; + mon = hp_sdc_rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = hp_sdc_rtc_tm.tm_mday; + hrs = hp_sdc_rtc_tm.tm_hour; + min = hp_sdc_rtc_tm.tm_min; + sec = hp_sdc_rtc_tm.tm_sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= eH) > 255) /* They are unsigned */ + return -EINVAL; + + + return 0; + } + case RTC_epoch_READ: /* Read the epoch. */ + { + return put_user (epoch, (unsigned long *)arg); + } + case RTC_EPOCH_SET: /* Set the epoch. */ + { + /* + * There were no RTC clocks before 1900. + */ + if (arg < 1900) + return -EINVAL; + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + epoch = arg; + return 0; + } + default: + return -EINVAL; + } + return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; +#endif +} + +static struct file_operations hp_sdc_rtc_fops = { + .owner = THIS_MODULE, + .llseek = hp_sdc_rtc_llseek, + .read = hp_sdc_rtc_read, + .poll = hp_sdc_rtc_poll, + .ioctl = hp_sdc_rtc_ioctl, + .open = hp_sdc_rtc_open, + .release = hp_sdc_rtc_release, + .fasync = hp_sdc_rtc_fasync, +}; + +static struct miscdevice hp_sdc_rtc_dev = { + .minor = RTC_MINOR, + .name = "rtc", + .fops = &hp_sdc_rtc_fops +}; + +static int __init hp_sdc_rtc_init(void) +{ + int ret; + + init_MUTEX(&i8042tregs); + + if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr))) + return ret; + misc_register(&hp_sdc_rtc_dev); + create_proc_read_entry ("driver/rtc", 0, 0, + hp_sdc_rtc_read_proc, NULL); + + printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded " + "(RTC v " RTC_VERSION ")\n"); + + return 0; +} + +static void __exit hp_sdc_rtc_exit(void) +{ + remove_proc_entry ("driver/rtc", NULL); + misc_deregister(&hp_sdc_rtc_dev); + hp_sdc_release_timer_irq(hp_sdc_rtc_isr); + printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support unloaded\n"); +} + +module_init(hp_sdc_rtc_init); +module_exit(hp_sdc_rtc_exit); diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/mouse/Kconfig linux-2.5/drivers/input/mouse/Kconfig --- ../prev/linux-2.5/drivers/input/mouse/Kconfig Fri May 2 04:03:11 2003 +++ linux-2.5/drivers/input/mouse/Kconfig Mon Mar 24 20:18:17 2003 @@ -133,3 +133,8 @@ The module will be called logibm.o. If you want to compile it as a module, say M here and read . +config MOUSE_HIL + tristate "HIL pointers (mice etc)." + depends on PARISC && INPUT_MOUSE && HIL_MLC + help + Say Y here to support HIL pointers. diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/mouse/Makefile linux-2.5/drivers/input/mouse/Makefile --- ../prev/linux-2.5/drivers/input/mouse/Makefile Fri May 2 04:03:11 2003 +++ linux-2.5/drivers/input/mouse/Makefile Mon Mar 24 20:18:17 2003 @@ -13,3 +13,4 @@ obj-$(CONFIG_MOUSE_PC9800) += 98busmouse.o obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o +obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/mouse/hil_ptr.c linux-2.5/drivers/input/mouse/hil_ptr.c --- ../prev/linux-2.5/drivers/input/mouse/hil_ptr.c Wed Dec 31 17:00:00 1969 +++ linux-2.5/drivers/input/mouse/hil_ptr.c Thu Nov 7 09:24:48 2002 @@ -0,0 +1,407 @@ +/* + * Generic linux-input device driver for axis-bearing devices + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PREFIX "HIL PTR: " +#define HIL_GENERIC_NAME "generic HIL pointer device" + +MODULE_AUTHOR("Brian S. Julin "); +MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver"); +MODULE_LICENSE("Dual BSD/GPL"); + + +#define TABLET_SIMULATES_MOUSE /* allow tablet to be used as mouse */ +#undef TABLET_AUTOADJUST /* auto-adjust valid tablet ranges */ + + +#define HIL_PTR_MAX_LENGTH 16 + +struct hil_ptr { + struct input_dev dev; + struct serio *serio; + + /* Input buffer and index for packets from HIL bus. */ + hil_packet data[HIL_PTR_MAX_LENGTH]; + int idx4; /* four counts per packet */ + + /* Raw device info records from HIL bus, see hil.h for fields. */ + char idd[HIL_PTR_MAX_LENGTH]; /* DID byte and IDD record */ + char rsc[HIL_PTR_MAX_LENGTH]; /* RSC record */ + char exd[HIL_PTR_MAX_LENGTH]; /* EXD record */ + char rnm[HIL_PTR_MAX_LENGTH + 1]; /* RNM record + NULL term. */ + + /* Extra device details not contained in struct input_dev. */ + unsigned int nbtn, naxes; + unsigned int btnmap[7]; + + /* Something to sleep around with. */ + struct semaphore sem; +}; + +/* Process a complete packet after transfer from the HIL */ +static void hil_ptr_process_record(struct hil_ptr *ptr) +{ + struct input_dev *dev = &ptr->dev; + hil_packet *data = ptr->data; + hil_packet p; + int idx, i, cnt, laxis; + int ax16, absdev; + + idx = ptr->idx4/4; + p = data[idx - 1]; + + if ((p & ~HIL_CMDCT_POL) == + (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report; + if ((p & ~HIL_CMDCT_RPL) == + (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report; + + /* Not a poll response. See if we are loading config records. */ + switch (p & HIL_PKT_DATA_MASK) { + case HIL_CMD_IDD: + for (i = 0; i < idx; i++) + ptr->idd[i] = ptr->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_PTR_MAX_LENGTH; i++) + ptr->idd[i] = 0; + break; + case HIL_CMD_RSC: + for (i = 0; i < idx; i++) + ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_PTR_MAX_LENGTH; i++) + ptr->rsc[i] = 0; + break; + case HIL_CMD_EXD: + for (i = 0; i < idx; i++) + ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_PTR_MAX_LENGTH; i++) + ptr->exd[i] = 0; + break; + case HIL_CMD_RNM: + for (i = 0; i < idx; i++) + ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_PTR_MAX_LENGTH + 1; i++) + ptr->rnm[i] = '\0'; + break; + default: + /* These occur when device isn't present */ + if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; + /* Anything else we'd like to know about. */ + printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); + break; + } + goto out; + + report: + if ((p & HIL_CMDCT_POL) != idx - 1) { + printk(KERN_WARNING PREFIX "Malformed poll packet %x (idx = %i)\n", p, idx); + goto out; + } + + i = (ptr->data[0] & HIL_POL_AXIS_ALT) ? 3 : 0; + laxis = ptr->data[0] & HIL_POL_NUM_AXES_MASK; + laxis += i; + + ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */ + absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; + + for (cnt = 1; i < laxis; i++) { + unsigned int lo,hi,val; + lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK; + hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0; + if (absdev) { + val = lo + (hi<<8); +#ifdef TABLET_AUTOADJUST + if (val < ptr->dev.absmin[ABS_X + i]) + ptr->dev.absmin[ABS_X + i] = val; + if (val > ptr->dev.absmax[ABS_X + i]) + ptr->dev.absmax[ABS_X + i] = val; +#endif + if (i%3) val = ptr->dev.absmax[ABS_X + i] - val; + input_report_abs(dev, ABS_X + i, val); + } else { + val = (int) (((int8_t)lo) | ((int8_t)hi<<8)); + if (i%3) val *= -1; + input_report_rel(dev, REL_X + i, val); + } + } + + while (cnt < idx - 1) { + unsigned int btn; + int up; + btn = ptr->data[cnt++]; + up = btn & 1; + btn &= 0xfe; + if (btn == 0x8e) { + continue; /* TODO: proximity == touch? */ + } + else if ((btn > 0x8c) || (btn < 0x80)) continue; + btn = (btn - 0x80) >> 1; + btn = ptr->btnmap[btn]; + input_report_key(dev, btn, !up); + } + out: + ptr->idx4 = 0; + up(&ptr->sem); +} + +static void hil_ptr_process_err(struct hil_ptr *ptr) { + printk(KERN_WARNING PREFIX "errored HIL packet\n"); + ptr->idx4 = 0; + up(&ptr->sem); + return; +} + +static void hil_ptr_interrupt(struct serio *serio, + unsigned char data, + unsigned int flags) +{ + struct hil_ptr *ptr; + hil_packet packet; + int idx; + + ptr = (struct hil_ptr *)serio->private; + if (ptr == NULL) { + BUG(); + return; + } + + if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) { + hil_ptr_process_err(ptr); + return; + } + idx = ptr->idx4/4; + if (!(ptr->idx4 % 4)) ptr->data[idx] = 0; + packet = ptr->data[idx]; + packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8); + ptr->data[idx] = packet; + + /* Records of N 4-byte hil_packets must terminate with a command. */ + if ((++(ptr->idx4)) % 4) return; + if ((packet & 0xffff0000) != HIL_ERR_INT) { + hil_ptr_process_err(ptr); + return; + } + if (packet & HIL_PKT_CMD) + hil_ptr_process_record(ptr); +} + +static void hil_ptr_disconnect(struct serio *serio) +{ + struct hil_ptr *ptr; + + ptr = (struct hil_ptr *)serio->private; + if (ptr == NULL) { + BUG(); + return; + } + + input_unregister_device(&ptr->dev); + serio_close(serio); + kfree(ptr); +} + +static void hil_ptr_connect(struct serio *serio, struct serio_dev *dev) +{ + struct hil_ptr *ptr; + char *txt; + unsigned int i, naxsets, btntype; + uint8_t did, *idd; + + if (serio->type != (SERIO_HIL_MLC | SERIO_HIL)) return; + + if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return; + memset(ptr, 0, sizeof(struct hil_ptr)); + + if (serio_open(serio, dev)) goto bail0; + + serio->private = ptr; + ptr->serio = serio; + ptr->dev.private = ptr; + + init_MUTEX_LOCKED(&(ptr->sem)); + + /* Get device info. MLC driver supplies devid/status/etc. */ + serio->write(serio, 0); + serio->write(serio, 0); + serio->write(serio, HIL_PKT_CMD >> 8); + serio->write(serio, HIL_CMD_IDD); + down(&(ptr->sem)); + + serio->write(serio, 0); + serio->write(serio, 0); + serio->write(serio, HIL_PKT_CMD >> 8); + serio->write(serio, HIL_CMD_RSC); + down(&(ptr->sem)); + + serio->write(serio, 0); + serio->write(serio, 0); + serio->write(serio, HIL_PKT_CMD >> 8); + serio->write(serio, HIL_CMD_RNM); + down(&(ptr->sem)); + + serio->write(serio, 0); + serio->write(serio, 0); + serio->write(serio, HIL_PKT_CMD >> 8); + serio->write(serio, HIL_CMD_EXD); + down(&(ptr->sem)); + + up(&(ptr->sem)); + + did = ptr->idd[0]; + idd = ptr->idd + 1; + txt = "unknown"; + if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { + ptr->dev.evbit[0] = BIT(EV_REL); + txt = "relative"; + } + + if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) { + ptr->dev.evbit[0] = BIT(EV_ABS); + txt = "absolute"; + } + if (!ptr->dev.evbit[0]) { + goto bail1; + } + + ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); + if (ptr->nbtn) ptr->dev.evbit[0] |= BIT(EV_KEY); + + naxsets = HIL_IDD_NUM_AXSETS(*idd); + ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd); + + printk(KERN_INFO PREFIX "HIL pointer device found (did: 0x%02x, axis: %s)\n", + did, txt); + printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n", + ptr->nbtn, naxsets, ptr->naxes); + + btntype = BTN_MISC; + if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET) +#ifdef TABLET_SIMULATES_MOUSE + btntype = BTN_TOUCH; +#else + btntype = BTN_DIGI; +#endif + if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN) + btntype = BTN_TOUCH; + + if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE) + btntype = BTN_MOUSE; + + for (i = 0; i < ptr->nbtn; i++) { + set_bit(btntype | i, ptr->dev.keybit); + ptr->btnmap[i] = btntype | i; + } + + if (btntype == BTN_MOUSE) { + /* Swap buttons 2 and 3 */ + ptr->btnmap[1] = BTN_MIDDLE; + ptr->btnmap[2] = BTN_RIGHT; + } + + if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { + for (i = 0; i < ptr->naxes; i++) { + set_bit(REL_X + i, ptr->dev.relbit); + } + for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) { + set_bit(REL_X + i, ptr->dev.relbit); + } + } else { + for (i = 0; i < ptr->naxes; i++) { + set_bit(ABS_X + i, ptr->dev.absbit); + ptr->dev.absmin[ABS_X + i] = 0; + ptr->dev.absmax[ABS_X + i] = + HIL_IDD_AXIS_MAX((ptr->idd + 1), i); + } + for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) { + set_bit(ABS_X + i, ptr->dev.absbit); + ptr->dev.absmin[ABS_X + i] = 0; + ptr->dev.absmax[ABS_X + i] = + HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3)); + } +#ifdef TABLET_AUTOADJUST + for (i = 0; i < ABS_MAX; i++) { + int diff = ptr->dev.absmax[ABS_X + i] / 10; + ptr->dev.absmin[ABS_X + i] += diff; + ptr->dev.absmax[ABS_X + i] -= diff; + } +#endif + } + + ptr->dev.name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME; + + ptr->dev.id.bustype = BUS_HIL; + ptr->dev.id.vendor = SERIO_HIL; + ptr->dev.id.product = 0x0001; /* TODO: get from ptr->rsc */ + ptr->dev.id.version = 0x0100; /* TODO: get from ptr->rsc */ + + input_register_device(&ptr->dev); +#warning TODO Boottime printk needs update, as well as dev.name. + printk(KERN_INFO "input: %s, %s on hil%d\n", + ptr->dev.name, + (btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad", + 0); + + return; + bail1: + serio_close(serio); + bail0: + kfree(ptr); + return; +} + + +struct serio_dev hil_ptr_serio_dev = { + .connect = hil_ptr_connect, + .disconnect = hil_ptr_disconnect, + .interrupt = hil_ptr_interrupt +}; + +static int __init hil_ptr_init(void) +{ + serio_register_device(&hil_ptr_serio_dev); + return 0; +} + +static void __exit hil_ptr_exit(void) +{ + serio_unregister_device(&hil_ptr_serio_dev); +} + +module_init(hil_ptr_init); +module_exit(hil_ptr_exit); diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/serio/Kconfig linux-2.5/drivers/input/serio/Kconfig --- ../prev/linux-2.5/drivers/input/serio/Kconfig Fri May 2 04:03:11 2003 +++ linux-2.5/drivers/input/serio/Kconfig Mon Mar 24 20:18:18 2003 @@ -21,7 +21,7 @@ config SERIO_I8042 tristate "i8042 PC Keyboard controller" default y - depends on SERIO + depends on SERIO && !PARISC ---help--- i8042 is the chip over which the standard AT keyboard and PS/2 mouse are connected to the computer. If you use these devices, @@ -119,3 +119,28 @@ The module will be called rpckbd.o. If you want to compile it as a module, say M here and read . +config HP_SDC + tristate "HP System Device Controller i8042 Support" + depends on GSC && SERIO + default y + ---help--- + This option enables supports for the the "System Device + Controller", an i8042 carrying microcode to manage a + few miscellanous devices on some Hewlett Packard systems. + The SDC itself contains a 10ms resolution timer/clock capable + of delivering interrupts on a periodic and one-shot basis. + The SDC may also be connected to a battery-backed real-time + clock, a basic audio waveform generator, and an HP-HIL Master + Link Controller serving up to seven input devices. + + By itself this option is rather useless, but enabling it will + enable selection of drivers for the abovementioned devices. + It is, however, incompatible with the old, reliable HIL keyboard + driver, and the new HIL driver is experimental, so if you plan + to use a HIL keyboard as your primary keyboard, you may wish + to keep using that driver until the new HIL drivers have had + more testing. + +config HIL_MLC + tristate "HIL MLC Support (needed for HIL input devices)" + depends on HP_SDC diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/serio/Makefile linux-2.5/drivers/input/serio/Makefile --- ../prev/linux-2.5/drivers/input/serio/Makefile Fri May 2 04:03:11 2003 +++ linux-2.5/drivers/input/serio/Makefile Mon Mar 24 20:18:18 2003 @@ -2,8 +2,6 @@ # Makefile for the input core drivers. # -# Each configuration option enables a list of files. - obj-$(CONFIG_SERIO) += serio.o obj-$(CONFIG_SERIO_I8042) += i8042.o obj-$(CONFIG_SERIO_PARKBD) += parkbd.o @@ -14,3 +12,5 @@ obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o +obj-$(CONFIG_HP_SDC) += hp_sdc.o +obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/serio/hil_mlc.c linux-2.5/drivers/input/serio/hil_mlc.c --- ../prev/linux-2.5/drivers/input/serio/hil_mlc.c Wed Dec 31 17:00:00 1969 +++ linux-2.5/drivers/input/serio/hil_mlc.c Wed Mar 12 15:06:49 2003 @@ -0,0 +1,951 @@ +/* + * HIL MLC state machine and serio interface driver + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A + * + * + * Driver theory of operation: + * + * Some access methods and an ISR is defined by the sub-driver + * (e.g. hp_sdc_mlc.c). These methods are expected to provide a + * few bits of logic in addition to raw access to the HIL MLC, + * specifically, the ISR, which is entirely registered by the + * sub-driver and invoked directly, must check for record + * termination or packet match, at which point a semaphore must + * be cleared and then the hil_mlcs_tasklet must be scheduled. + * + * The hil_mlcs_tasklet processes the state machine for all MLCs + * each time it runs, checking each MLC's progress at the current + * node in the state machine, and moving the MLC to subsequent nodes + * in the state machine when appropriate. It will reschedule + * itself if output is pending. (This rescheduling should be replaced + * at some point with a sub-driver-specific mechanism.) + * + * A timer task prods the tasket once per second to prevent + * hangups when attached devices do not return expected data + * and to initiate probes of the loop for new devices. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Brian S. Julin "); +MODULE_DESCRIPTION("HIL MLC serio"); +MODULE_LICENSE("Dual BSD/GPL"); + +EXPORT_SYMBOL(hil_mlc_register); +EXPORT_SYMBOL(hil_mlc_unregister); + +#define PREFIX "HIL MLC: " + +static LIST_HEAD(hil_mlcs); +static rwlock_t hil_mlcs_lock = RW_LOCK_UNLOCKED; +static struct timer_list hil_mlcs_kicker; +static int hil_mlcs_probe; + +static void hil_mlcs_process(unsigned long unused); +DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0); + + +/* #define HIL_MLC_DEBUG */ + +/********************** Device info/instance management **********************/ + +static void hil_mlc_clear_di_map (hil_mlc *mlc, int val) { + int j; + for (j = val; j < 7 ; j++) { + mlc->di_map[j] = -1; + } +} + +static void hil_mlc_clear_di_scratch (hil_mlc *mlc) { + memset(&(mlc->di_scratch), 0, sizeof(mlc->di_scratch)); +} + +static void hil_mlc_copy_di_scratch (hil_mlc *mlc, int idx) { + memcpy(&(mlc->di[idx]), &(mlc->di_scratch), sizeof(mlc->di_scratch)); +} + +static int hil_mlc_match_di_scratch (hil_mlc *mlc) { + int idx; + + for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { + int j, found; + + /* In-use slots are not eligible. */ + found = 0; + for (j = 0; j < 7 ; j++) { + if (mlc->di_map[j] == idx) found++; + } + if (found) continue; + if (!memcmp(mlc->di + idx, + &(mlc->di_scratch), + sizeof(mlc->di_scratch))) break; + } + return((idx >= HIL_MLC_DEVMEM) ? -1 : idx); +} + +static int hil_mlc_find_free_di(hil_mlc *mlc) { + int idx; + /* TODO: Pick all-zero slots first, failing that, + * randomize the slot picked among those eligible. + */ + for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { + int j, found; + found = 0; + for (j = 0; j < 7 ; j++) { + if (mlc->di_map[j] == idx) found++; + } + if (!found) break; + } + return(idx); /* Note: It is guaranteed at least one above will match */ +} + +static inline void hil_mlc_clean_serio_map(hil_mlc *mlc) { + int idx; + for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) { + int j, found; + found = 0; + for (j = 0; j < 7 ; j++) { + if (mlc->di_map[j] == idx) found++; + } + if (!found) mlc->serio_map[idx].di_revmap = -1; + } +} + +static void hil_mlc_send_polls(hil_mlc *mlc) { + int did, i, cnt; + struct serio *serio; + struct serio_dev *dev; + + i = cnt = 0; + did = (mlc->ipacket[0] & HIL_PKT_ADDR_MASK) >> 8; + serio = did ? &(mlc->serio[mlc->di_map[did - 1]]) : NULL; + dev = (serio != NULL) ? serio->dev : NULL; + + while (mlc->icount < 15 - i) { + hil_packet p; + p = mlc->ipacket[i]; + if (did != (p & HIL_PKT_ADDR_MASK) >> 8) { + if (dev == NULL || dev->interrupt == NULL) goto skip; + + dev->interrupt(serio, 0, 0, NULL); + dev->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); + dev->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL); + dev->interrupt(serio, HIL_CMD_POL + cnt, 0, NULL); + skip: + did = (p & HIL_PKT_ADDR_MASK) >> 8; + serio = did ? &(mlc->serio[mlc->di_map[did-1]]) : NULL; + dev = (serio != NULL) ? serio->dev : NULL; + cnt = 0; + } + cnt++; i++; + if (dev == NULL || dev->interrupt == NULL) continue; + dev->interrupt(serio, (p >> 24), 0, NULL); + dev->interrupt(serio, (p >> 16) & 0xff, 0, NULL); + dev->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0, NULL); + dev->interrupt(serio, p & 0xff, 0, NULL); + } +} + +/*************************** State engine *********************************/ + +#define HILSEN_SCHED 0x000100 /* Schedule the tasklet */ +#define HILSEN_BREAK 0x000200 /* Wait until next pass */ +#define HILSEN_UP 0x000400 /* relative node#, decrement */ +#define HILSEN_DOWN 0x000800 /* relative node#, increment */ +#define HILSEN_FOLLOW 0x001000 /* use retval as next node# */ + +#define HILSEN_MASK 0x0000ff +#define HILSEN_START 0 +#define HILSEN_RESTART 1 +#define HILSEN_DHR 9 +#define HILSEN_DHR2 10 +#define HILSEN_IFC 14 +#define HILSEN_HEAL0 16 +#define HILSEN_HEAL 18 +#define HILSEN_ACF 21 +#define HILSEN_ACF2 22 +#define HILSEN_DISC0 25 +#define HILSEN_DISC 27 +#define HILSEN_MATCH 40 +#define HILSEN_OPERATE 41 +#define HILSEN_PROBE 44 +#define HILSEN_DSR 52 +#define HILSEN_REPOLL 55 +#define HILSEN_IFCACF 58 +#define HILSEN_END 60 + +#define HILSEN_NEXT (HILSEN_DOWN | 1) +#define HILSEN_SAME (HILSEN_DOWN | 0) +#define HILSEN_LAST (HILSEN_UP | 1) + +#define HILSEN_DOZE (HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK) +#define HILSEN_SLEEP (HILSEN_SAME | HILSEN_BREAK) + +static int hilse_match(hil_mlc *mlc, int unused) { + int rc; + rc = hil_mlc_match_di_scratch(mlc); + if (rc == -1) { + rc = hil_mlc_find_free_di(mlc); + if (rc == -1) goto err; +#ifdef HIL_MLC_DEBUG + printk(KERN_DEBUG PREFIX "new in slot %i\n", rc); +#endif + hil_mlc_copy_di_scratch(mlc, rc); + mlc->di_map[mlc->ddi] = rc; + mlc->serio_map[rc].di_revmap = mlc->ddi; + hil_mlc_clean_serio_map(mlc); + serio_rescan(mlc->serio + rc); + return -1; + } + mlc->di_map[mlc->ddi] = rc; +#ifdef HIL_MLC_DEBUG + printk(KERN_DEBUG PREFIX "same in slot %i\n", rc); +#endif + mlc->serio_map[rc].di_revmap = mlc->ddi; + hil_mlc_clean_serio_map(mlc); + return 0; + err: + printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n"); + return 1; +} + +/* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */ +static int hilse_init_lcv(hil_mlc *mlc, int unused) { + struct timeval tv; + + do_gettimeofday(&tv); + + if(mlc->lcv == 0) goto restart; /* First init, no need to dally */ + if(tv.tv_sec - mlc->lcv_tv.tv_sec < 5) return -1; + restart: + mlc->lcv_tv = tv; + mlc->lcv = 0; + return 0; +} + +static int hilse_inc_lcv(hil_mlc *mlc, int lim) { + if (mlc->lcv++ >= lim) return -1; + return 0; +} + +#if 0 +static int hilse_set_lcv(hil_mlc *mlc, int val) { + mlc->lcv = val; + return 0; +} +#endif + +/* Management of the discovered device index (zero based, -1 means no devs) */ +static int hilse_set_ddi(hil_mlc *mlc, int val) { + mlc->ddi = val; + hil_mlc_clear_di_map(mlc, val + 1); + return 0; +} + +static int hilse_dec_ddi(hil_mlc *mlc, int unused) { + mlc->ddi--; + if (mlc->ddi <= -1) { + mlc->ddi = -1; + hil_mlc_clear_di_map(mlc, 0); + return -1; + } + hil_mlc_clear_di_map(mlc, mlc->ddi + 1); + return 0; +} + +static int hilse_inc_ddi(hil_mlc *mlc, int unused) { + if (mlc->ddi >= 6) { + BUG(); + return -1; + } + mlc->ddi++; + return 0; +} + +static int hilse_take_idd(hil_mlc *mlc, int unused) { + int i; + + /* Help the state engine: + * Is this a real IDD response or just an echo? + * + * Real IDD response does not start with a command. + */ + if (mlc->ipacket[0] & HIL_PKT_CMD) goto bail; + /* Should have the command echoed further down. */ + for (i = 1; i < 16; i++) { + if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) == + (mlc->ipacket[0] & HIL_PKT_ADDR_MASK)) && + (mlc->ipacket[i] & HIL_PKT_CMD) && + ((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD)) + break; + } + if (i > 15) goto bail; + /* And the rest of the packets should still be clear. */ + while (++i < 16) { + if (mlc->ipacket[i]) break; + } + if (i < 16) goto bail; + for (i = 0; i < 16; i++) { + mlc->di_scratch.idd[i] = + mlc->ipacket[i] & HIL_PKT_DATA_MASK; + } + /* Next step is to see if RSC supported */ + if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC) + return HILSEN_NEXT; + if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) + return HILSEN_DOWN | 4; + return 0; + bail: + mlc->ddi--; + return -1; /* This should send us off to ACF */ +} + +static int hilse_take_rsc(hil_mlc *mlc, int unused) { + int i; + + for (i = 0; i < 16; i++) { + mlc->di_scratch.rsc[i] = + mlc->ipacket[i] & HIL_PKT_DATA_MASK; + } + /* Next step is to see if EXD supported (IDD has already been read) */ + if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) + return HILSEN_NEXT; + return 0; +} + +static int hilse_take_exd(hil_mlc *mlc, int unused) { + int i; + + for (i = 0; i < 16; i++) { + mlc->di_scratch.exd[i] = + mlc->ipacket[i] & HIL_PKT_DATA_MASK; + } + /* Next step is to see if RNM supported. */ + if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM) + return HILSEN_NEXT; + return 0; +} + +static int hilse_take_rnm(hil_mlc *mlc, int unused) { + int i; + + for (i = 0; i < 16; i++) { + mlc->di_scratch.rnm[i] = + mlc->ipacket[i] & HIL_PKT_DATA_MASK; + } + do { + char nam[17]; + snprintf(nam, 16, "%s", mlc->di_scratch.rnm); + nam[16] = '\0'; + printk(KERN_INFO PREFIX "Device name gotten: %s\n", nam); + } while (0); + return 0; +} + +static int hilse_operate(hil_mlc *mlc, int repoll) { + + if (mlc->opercnt == 0) hil_mlcs_probe = 0; + mlc->opercnt = 1; + + hil_mlc_send_polls(mlc); + + if (!hil_mlcs_probe) return 0; + hil_mlcs_probe = 0; + mlc->opercnt = 0; + return 1; +} + +#define FUNC(funct, funct_arg, zero_rc, neg_rc, pos_rc) \ +{ HILSE_FUNC, { func: &funct }, funct_arg, zero_rc, neg_rc, pos_rc }, +#define OUT(pack) \ +{ HILSE_OUT, { packet: pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 }, +#define CTS \ +{ HILSE_CTS, { packet: 0 }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 }, +#define EXPECT(comp, to, got, got_wrong, timed_out) \ +{ HILSE_EXPECT, { packet: comp }, to, got, got_wrong, timed_out }, +#define EXPECT_LAST(comp, to, got, got_wrong, timed_out) \ +{ HILSE_EXPECT_LAST, { packet: comp }, to, got, got_wrong, timed_out }, +#define EXPECT_DISC(comp, to, got, got_wrong, timed_out) \ +{ HILSE_EXPECT_DISC, { packet: comp }, to, got, got_wrong, timed_out }, +#define IN(to, got, got_error, timed_out) \ +{ HILSE_IN, { packet: 0 }, to, got, got_error, timed_out }, +#define OUT_DISC(pack) \ +{ HILSE_OUT_DISC, { packet: pack }, 0, 0, 0, 0 }, +#define OUT_LAST(pack) \ +{ HILSE_OUT_LAST, { packet: pack }, 0, 0, 0, 0 }, + +struct hilse_node hil_mlc_se[HILSEN_END] = { + + /* 0 HILSEN_START */ + FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0) + + /* 1 HILSEN_RESTART */ + FUNC(hilse_inc_lcv, 10, HILSEN_NEXT, HILSEN_START, 0) + OUT(HIL_CTRL_ONLY) /* Disable APE */ + CTS + +#define TEST_PACKET(x) \ +(HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT) | x << 4 | x) + + OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0x5)) + EXPECT(HIL_ERR_INT | TEST_PACKET(0x5), + 2000, HILSEN_NEXT, HILSEN_RESTART, HILSEN_RESTART) + OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0xa)) + EXPECT(HIL_ERR_INT | TEST_PACKET(0xa), + 2000, HILSEN_NEXT, HILSEN_RESTART, HILSEN_RESTART) + OUT(HIL_CTRL_ONLY | 0) /* Disable test mode */ + + /* 9 HILSEN_DHR */ + FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0) + + /* 10 HILSEN_DHR2 */ + FUNC(hilse_inc_lcv, 10, HILSEN_NEXT, HILSEN_START, 0) + FUNC(hilse_set_ddi, -1, HILSEN_NEXT, 0, 0) + OUT(HIL_PKT_CMD | HIL_CMD_DHR) + IN(300000, HILSEN_DHR2, HILSEN_DHR2, HILSEN_NEXT) + + /* 14 HILSEN_IFC */ + OUT(HIL_PKT_CMD | HIL_CMD_IFC) + EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT, + 20000, HILSEN_DISC, HILSEN_DHR2, HILSEN_NEXT ) + + /* If devices are there, they weren't in PUP or other loopback mode. + * We're more concerned at this point with restoring operation + * to devices than discovering new ones, so we try to salvage + * the loop configuration by closing off the loop. + */ + + /* 16 HILSEN_HEAL0 */ + FUNC(hilse_dec_ddi, 0, HILSEN_NEXT, HILSEN_ACF, 0) + FUNC(hilse_inc_ddi, 0, HILSEN_NEXT, 0, 0) + + /* 18 HILSEN_HEAL */ + OUT_LAST(HIL_CMD_ELB) + EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT, + 20000, HILSEN_REPOLL, HILSEN_DSR, HILSEN_NEXT) + FUNC(hilse_dec_ddi, 0, HILSEN_HEAL, HILSEN_NEXT, 0) + + /* 21 HILSEN_ACF */ + FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_DOZE, 0) + + /* 22 HILSEN_ACF2 */ + FUNC(hilse_inc_lcv, 10, HILSEN_NEXT, HILSEN_START, 0) + OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1) + IN(20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_NEXT) + + /* 25 HILSEN_DISC0 */ + OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB) + EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_ELB | HIL_ERR_INT, + 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) + + /* Only enter here if response just received */ + /* 27 HILSEN_DISC */ + OUT_DISC(HIL_PKT_CMD | HIL_CMD_IDD) + EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_IDD | HIL_ERR_INT, + 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_START) + FUNC(hilse_inc_ddi, 0, HILSEN_NEXT, HILSEN_START, 0) + FUNC(hilse_take_idd, 0, HILSEN_MATCH, HILSEN_IFCACF, HILSEN_FOLLOW) + OUT_LAST(HIL_PKT_CMD | HIL_CMD_RSC) + EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RSC | HIL_ERR_INT, + 30000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) + FUNC(hilse_take_rsc, 0, HILSEN_MATCH, 0, HILSEN_FOLLOW) + OUT_LAST(HIL_PKT_CMD | HIL_CMD_EXD) + EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_EXD | HIL_ERR_INT, + 30000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) + FUNC(hilse_take_exd, 0, HILSEN_MATCH, 0, HILSEN_FOLLOW) + OUT_LAST(HIL_PKT_CMD | HIL_CMD_RNM) + EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RNM | HIL_ERR_INT, + 30000, HILSEN_NEXT, HILSEN_DSR, HILSEN_DSR) + FUNC(hilse_take_rnm, 0, HILSEN_MATCH, 0, 0) + + /* 40 HILSEN_MATCH */ + FUNC(hilse_match, 0, HILSEN_NEXT, HILSEN_NEXT, /* TODO */ 0) + + /* 41 HILSEN_OPERATE */ + OUT(HIL_PKT_CMD | HIL_CMD_POL) + EXPECT(HIL_PKT_CMD | HIL_CMD_POL | HIL_ERR_INT, + 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_NEXT) + FUNC(hilse_operate, 0, HILSEN_OPERATE, HILSEN_IFC, HILSEN_NEXT) + + /* 44 HILSEN_PROBE */ + OUT_LAST(HIL_PKT_CMD | HIL_CMD_EPT) + IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT) + OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB) + IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT) + OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1) + IN(10000, HILSEN_DISC0, HILSEN_DSR, HILSEN_NEXT) + OUT_LAST(HIL_PKT_CMD | HIL_CMD_ELB) + IN(10000, HILSEN_OPERATE, HILSEN_DSR, HILSEN_DSR) + + /* 52 HILSEN_DSR */ + FUNC(hilse_set_ddi, -1, HILSEN_NEXT, 0, 0) + OUT(HIL_PKT_CMD | HIL_CMD_DSR) + IN(20000, HILSEN_DHR, HILSEN_DHR, HILSEN_IFC) + + /* 55 HILSEN_REPOLL */ + OUT(HIL_PKT_CMD | HIL_CMD_RPL) + EXPECT(HIL_PKT_CMD | HIL_CMD_RPL | HIL_ERR_INT, + 20000, HILSEN_NEXT, HILSEN_DSR, HILSEN_NEXT) + FUNC(hilse_operate, 1, HILSEN_OPERATE, HILSEN_IFC, HILSEN_PROBE) + + /* 58 HILSEN_IFCACF */ + OUT(HIL_PKT_CMD | HIL_CMD_IFC) + EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT, + 20000, HILSEN_ACF2, HILSEN_DHR2, HILSEN_HEAL) + + /* 60 HILSEN_END */ +}; + +static inline void hilse_setup_input(hil_mlc *mlc, struct hilse_node *node) { + + switch (node->act) { + case HILSE_EXPECT_DISC: + mlc->imatch = node->object.packet; + mlc->imatch |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT); + break; + case HILSE_EXPECT_LAST: + mlc->imatch = node->object.packet; + mlc->imatch |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT); + break; + case HILSE_EXPECT: + mlc->imatch = node->object.packet; + break; + case HILSE_IN: + mlc->imatch = 0; + break; + default: + BUG(); + } + mlc->istarted = 1; + mlc->intimeout = node->arg; + do_gettimeofday(&(mlc->instart)); + mlc->icount = 15; + memset(mlc->ipacket, 0, 16 * sizeof(hil_packet)); + if (down_trylock(&(mlc->isem))) BUG(); + + return; +} + +#ifdef HIL_MLC_DEBUG +static int doze = 0; +static int seidx; /* For debug */ +static int kick = 1; +#endif + +static int hilse_donode (hil_mlc *mlc) { + struct hilse_node *node; + int nextidx = 0; + int sched_long = 0; + unsigned long flags; + +#ifdef HIL_MLC_DEBUG + if (mlc->seidx && (mlc->seidx != seidx) && mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) { + printk(KERN_DEBUG PREFIX "z%i \n%s {%i}", doze, kick ? "K" : "", mlc->seidx); + doze = 0; + } + kick = 0; + + seidx = mlc->seidx; +#endif + node = hil_mlc_se + mlc->seidx; + + switch (node->act) { + int rc; + hil_packet pack; + + case HILSE_FUNC: + if (node->object.func == NULL) break; + rc = node->object.func(mlc, node->arg); + nextidx = (rc > 0) ? node->ugly : + ((rc < 0) ? node->bad : node->good); + if (nextidx == HILSEN_FOLLOW) nextidx = rc; + break; + case HILSE_EXPECT_LAST: + case HILSE_EXPECT_DISC: + case HILSE_EXPECT: + case HILSE_IN: + /* Already set up from previous HILSE_OUT_* */ + write_lock_irqsave(&(mlc->lock), flags); + rc = mlc->in(mlc, node->arg); + if (rc == 2) { + nextidx = HILSEN_DOZE; + sched_long = 1; + write_unlock_irqrestore(&(mlc->lock), flags); + break; + } + if (rc == 1) nextidx = node->ugly; + else if (rc == 0) nextidx = node->good; + else nextidx = node->bad; + mlc->istarted = 0; + write_unlock_irqrestore(&(mlc->lock), flags); + break; + case HILSE_OUT_LAST: + write_lock_irqsave(&(mlc->lock), flags); + pack = node->object.packet; + pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT); + goto out; + case HILSE_OUT_DISC: + write_lock_irqsave(&(mlc->lock), flags); + pack = node->object.packet; + pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT); + goto out; + case HILSE_OUT: + write_lock_irqsave(&(mlc->lock), flags); + pack = node->object.packet; + out: + if (mlc->istarted) goto out2; + /* Prepare to receive input */ + if ((node + 1)->act & HILSE_IN) + hilse_setup_input(mlc, node + 1); + + out2: + write_unlock_irqrestore(&(mlc->lock), flags); + + if (down_trylock(&mlc->osem)) { + nextidx = HILSEN_DOZE; + break; + } + up(&mlc->osem); + + write_lock_irqsave(&(mlc->lock), flags); + if (!(mlc->ostarted)) { + mlc->ostarted = 1; + mlc->opacket = pack; + mlc->out(mlc); + nextidx = HILSEN_DOZE; + write_unlock_irqrestore(&(mlc->lock), flags); + break; + } + mlc->ostarted = 0; + do_gettimeofday(&(mlc->instart)); + write_unlock_irqrestore(&(mlc->lock), flags); + nextidx = HILSEN_NEXT; + break; + case HILSE_CTS: + nextidx = mlc->cts(mlc) ? node->bad : node->good; + break; + default: + BUG(); + nextidx = 0; + break; + } + +#ifdef HIL_MLC_DEBUG + if (nextidx == HILSEN_DOZE) doze++; +#endif + + while (nextidx & HILSEN_SCHED) { + struct timeval tv; + + if (!sched_long) goto sched; + + do_gettimeofday(&tv); + tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec); + tv.tv_usec -= mlc->instart.tv_usec; + if (tv.tv_usec >= mlc->intimeout) goto sched; + tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / 1000000; + if (!tv.tv_usec) goto sched; + mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec); + break; + sched: + tasklet_schedule(&hil_mlcs_tasklet); + break; + } + if (nextidx & HILSEN_DOWN) mlc->seidx += nextidx & HILSEN_MASK; + else if (nextidx & HILSEN_UP) mlc->seidx -= nextidx & HILSEN_MASK; + else mlc->seidx = nextidx & HILSEN_MASK; + + if (nextidx & HILSEN_BREAK) return 1; + return 0; +} + +/******************** tasklet context functions **************************/ +static void hil_mlcs_process(unsigned long unused) { + struct list_head *tmp; + + read_lock(&hil_mlcs_lock); + list_for_each(tmp, &hil_mlcs) { + struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list); + while (hilse_donode(mlc) == 0) { +#ifdef HIL_MLC_DEBUG + if (mlc->seidx != 41 && + mlc->seidx != 42 && + mlc->seidx != 43) + printk(KERN_DEBUG PREFIX " + "); +#endif + }; + } + read_unlock(&hil_mlcs_lock); +} + +/************************* Keepalive timer task *********************/ + +void hil_mlcs_timer (unsigned long data) { + hil_mlcs_probe = 1; + tasklet_schedule(&hil_mlcs_tasklet); + /* Re-insert the periodic task. */ + if (!timer_pending(&hil_mlcs_kicker)) + mod_timer(&hil_mlcs_kicker, jiffies + HZ); +} + +/******************** user/kernel context functions **********************/ + +static int hil_mlc_serio_write(struct serio *serio, unsigned char c) { + struct hil_mlc_serio_map *map; + struct hil_mlc *mlc; + struct serio_dev *dev; + uint8_t *idx, *last; + + map = serio->driver; + if (map == NULL) { + BUG(); + return -EIO; + } + mlc = map->mlc; + if (mlc == NULL) { + BUG(); + return -EIO; + } + mlc->serio_opacket[map->didx] |= + ((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx])); + + if (mlc->serio_oidx[map->didx] >= 3) { + /* for now only commands */ + if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD)) + return -EIO; + switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) { + case HIL_CMD_IDD: + idx = mlc->di[map->didx].idd; + goto emu; + case HIL_CMD_RSC: + idx = mlc->di[map->didx].rsc; + goto emu; + case HIL_CMD_EXD: + idx = mlc->di[map->didx].exd; + goto emu; + case HIL_CMD_RNM: + idx = mlc->di[map->didx].rnm; + goto emu; + default: + break; + } + mlc->serio_oidx[map->didx] = 0; + mlc->serio_opacket[map->didx] = 0; + } + + mlc->serio_oidx[map->didx]++; + return -EIO; + emu: + dev = serio->dev; + if (dev == NULL) { + BUG(); + return -EIO; + } + last = idx + 15; + while ((last != idx) && (*last == 0)) last--; + + while (idx != last) { + dev->interrupt(serio, 0, 0, NULL); + dev->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); + dev->interrupt(serio, 0, 0, NULL); + dev->interrupt(serio, *idx, 0, NULL); + idx++; + } + dev->interrupt(serio, 0, 0, NULL); + dev->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL); + dev->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL); + dev->interrupt(serio, *idx, 0, NULL); + + mlc->serio_oidx[map->didx] = 0; + mlc->serio_opacket[map->didx] = 0; + + return 0; +} + +static int hil_mlc_serio_open(struct serio *serio) { + struct hil_mlc_serio_map *map; + struct hil_mlc *mlc; + + if (serio->private != NULL) return -EBUSY; + + map = serio->driver; + if (map == NULL) { + BUG(); + return -ENODEV; + } + mlc = map->mlc; + if (mlc == NULL) { + BUG(); + return -ENODEV; + } + + mlc->inc_use_count(); + + return 0; +} + +static void hil_mlc_serio_close(struct serio *serio) { + struct hil_mlc_serio_map *map; + struct hil_mlc *mlc; + + map = serio->driver; + if (map == NULL) { + BUG(); + return; + } + mlc = map->mlc; + if (mlc == NULL) { + BUG(); + return; + } + + mlc->dec_use_count(); + + serio->private = NULL; + serio->dev = NULL; + /* TODO wake up interruptable */ +} + +int hil_mlc_register(hil_mlc *mlc) { + int i; + unsigned long flags; + + MOD_INC_USE_COUNT; + if (mlc == NULL) { + MOD_DEC_USE_COUNT; + return -EINVAL; + } + + mlc->istarted = 0; + mlc->ostarted = 0; + + mlc->lock = RW_LOCK_UNLOCKED; + init_MUTEX(&(mlc->osem)); + + init_MUTEX(&(mlc->isem)); + mlc->icount = -1; + mlc->imatch = 0; + + mlc->opercnt = 0; + + init_MUTEX_LOCKED(&(mlc->csem)); + + hil_mlc_clear_di_scratch(mlc); + hil_mlc_clear_di_map(mlc, 0); + for (i = 0; i < HIL_MLC_DEVMEM; i++) { + hil_mlc_copy_di_scratch(mlc, i); + memset(&(mlc->serio[i]), 0, sizeof(mlc->serio[0])); + mlc->serio[i].type = SERIO_HIL | SERIO_HIL_MLC; + mlc->serio[i].write = hil_mlc_serio_write; + mlc->serio[i].open = hil_mlc_serio_open; + mlc->serio[i].close = hil_mlc_serio_close; + mlc->serio[i].driver = &(mlc->serio_map[i]); + mlc->serio_map[i].mlc = mlc; + mlc->serio_map[i].didx = i; + mlc->serio_map[i].di_revmap = -1; + mlc->serio_opacket[i] = 0; + mlc->serio_oidx[i] = 0; + serio_register_port(&(mlc->serio[i])); + } + + mlc->tasklet = &hil_mlcs_tasklet; + + write_lock_irqsave(&hil_mlcs_lock, flags); + list_add_tail(&mlc->list, &hil_mlcs); + mlc->seidx = HILSEN_START; + write_unlock_irqrestore(&hil_mlcs_lock, flags); + + tasklet_schedule(&hil_mlcs_tasklet); + return 0; +} + +int hil_mlc_unregister(hil_mlc *mlc) { + struct list_head *tmp; + unsigned long flags; + int i; + + if (mlc == NULL) + return -EINVAL; + + write_lock_irqsave(&hil_mlcs_lock, flags); + list_for_each(tmp, &hil_mlcs) { + if (list_entry(tmp, hil_mlc, list) == mlc) + goto found; + } + + /* not found in list */ + write_unlock_irqrestore(&hil_mlcs_lock, flags); + tasklet_schedule(&hil_mlcs_tasklet); + return -ENODEV; + + found: + list_del(tmp); + write_unlock_irqrestore(&hil_mlcs_lock, flags); + MOD_DEC_USE_COUNT; + + for (i = 0; i < HIL_MLC_DEVMEM; i++) + serio_unregister_port(&(mlc->serio[i])); + + tasklet_schedule(&hil_mlcs_tasklet); + return 0; +} + +/**************************** Module interface *************************/ + +static int __init hil_mlc_init(void) +{ + init_timer(&hil_mlcs_kicker); + hil_mlcs_kicker.expires = jiffies + HZ; + hil_mlcs_kicker.function = &hil_mlcs_timer; + add_timer(&hil_mlcs_kicker); + + tasklet_enable(&hil_mlcs_tasklet); + + return 0; +} + +static void __exit hil_mlc_exit(void) +{ + del_timer(&hil_mlcs_kicker); + + tasklet_disable(&hil_mlcs_tasklet); + tasklet_kill(&hil_mlcs_tasklet); +} + +module_init(hil_mlc_init); +module_exit(hil_mlc_exit); diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/serio/hp_sdc.c linux-2.5/drivers/input/serio/hp_sdc.c --- ../prev/linux-2.5/drivers/input/serio/hp_sdc.c Wed Dec 31 17:00:00 1969 +++ linux-2.5/drivers/input/serio/hp_sdc.c Tue Dec 24 17:39:09 2002 @@ -0,0 +1,1011 @@ +/* + * HP i8042-based System Device Controller driver. + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * System Device Controller Microprocessor Firmware Theory of Operation + * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 + * Helge Deller's original hilkbd.c port for PA-RISC. + * + * + * Driver theory of operation: + * + * hp_sdc_put does all writing to the SDC. ISR can run on a different + * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time + * (it cannot really benefit from SMP anyway.) A tasket fit this perfectly. + * + * All data coming back from the SDC is sent via interrupt and can be read + * fully in the ISR, so there are no latency/throughput problems there. + * The problem is with output, due to the slow clock speed of the SDC + * compared to the CPU. This should not be too horrible most of the time, + * but if used with HIL devices that support the multibyte transfer command, + * keeping outbound throughput flowing at the 6500KBps that the HIL is + * capable of is more than can be done at HZ=100. + * + * Busy polling for IBF clear wastes CPU cycles and bus cycles. hp_sdc.ibf + * is set to 0 when the IBF flag in the status register has cleared. ISR + * may do this, and may also access the parts of queued transactions related + * to reading data back from the SDC, but otherwise will not touch the + * hp_sdc state. Whenever a register is written hp_sdc.ibf is set to 1. + * + * The i8042 write index and the values in the 4-byte input buffer + * starting at 0x70 are kept track of in hp_sdc.wi, and .r7[], respectively, + * to minimize the amount of IO needed to the SDC. However these values + * do not need to be locked since they are only ever accessed by hp_sdc_put. + * + * A timer task schedules the tasklet once per second just to make + * sure it doesn't freeze up and to allow for bad reads to time out. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PREFIX "HP SDC: " + +MODULE_AUTHOR("Brian S. Julin "); +MODULE_DESCRIPTION("HP i8042-based SDC Driver"); +MODULE_LICENSE("Dual BSD/GPL"); + +EXPORT_SYMBOL(hp_sdc_request_timer_irq); +EXPORT_SYMBOL(hp_sdc_request_hil_irq); +EXPORT_SYMBOL(hp_sdc_request_cooked_irq); + +EXPORT_SYMBOL(hp_sdc_release_timer_irq); +EXPORT_SYMBOL(hp_sdc_release_hil_irq); +EXPORT_SYMBOL(hp_sdc_release_cooked_irq); + +EXPORT_SYMBOL(hp_sdc_enqueue_transaction); +EXPORT_SYMBOL(hp_sdc_dequeue_transaction); + +static hp_i8042_sdc hp_sdc; /* All driver state is kept in here. */ + +/*************** primitives for use in any context *********************/ +static inline uint8_t hp_sdc_status_in8 (void) { + uint8_t status; + unsigned long flags; + + write_lock_irqsave(&hp_sdc.ibf_lock, flags); + status = gsc_readb(hp_sdc.status_io); + if (!(status & HP_SDC_STATUS_IBF)) hp_sdc.ibf = 0; + write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); + + return status; +} + +static inline uint8_t hp_sdc_data_in8 (void) { + return gsc_readb(hp_sdc.data_io); +} + +static inline void hp_sdc_status_out8 (uint8_t val) { + unsigned long flags; + + write_lock_irqsave(&hp_sdc.ibf_lock, flags); + hp_sdc.ibf = 1; + if ((val & 0xf0) == 0xe0) hp_sdc.wi = 0xff; + gsc_writeb(val, hp_sdc.status_io); + write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); +} + +static inline void hp_sdc_data_out8 (uint8_t val) { + unsigned long flags; + + write_lock_irqsave(&hp_sdc.ibf_lock, flags); + hp_sdc.ibf = 1; + gsc_writeb(val, hp_sdc.data_io); + write_unlock_irqrestore(&hp_sdc.ibf_lock, flags); +} + +/* Care must be taken to only invoke hp_sdc_spin_ibf when + * absolutely needed, or in rarely invoked subroutines. + * Not only does it waste CPU cycles, it also wastes bus cycles. + */ +static inline void hp_sdc_spin_ibf(void) { + unsigned long flags; + rwlock_t *lock; + + lock = &hp_sdc.ibf_lock; + + read_lock_irqsave(lock, flags); + if (!hp_sdc.ibf) { + read_unlock_irqrestore(lock, flags); + return; + } + read_unlock(lock); + write_lock(lock); + while (gsc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF) {}; + hp_sdc.ibf = 0; + write_unlock_irqrestore(lock, flags); +} + + +/************************ Interrupt context functions ************************/ +static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) { + hp_sdc_transaction *curr; + + read_lock(&hp_sdc.rtq_lock); + if (hp_sdc.rcurr < 0) { + read_unlock(&hp_sdc.rtq_lock); + return; + } + curr = hp_sdc.tq[hp_sdc.rcurr]; + read_unlock(&hp_sdc.rtq_lock); + + curr->seq[curr->idx++] = status; + curr->seq[curr->idx++] = data; + hp_sdc.rqty -= 2; + do_gettimeofday(&hp_sdc.rtv); + + if (hp_sdc.rqty <= 0) { + /* All data has been gathered. */ + if(curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE) { + if (curr->act.semaphore) up(curr->act.semaphore); + } + if(curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK) { + if (curr->act.irqhook) + curr->act.irqhook(irq, dev_id, status, data); + } + curr->actidx = curr->idx; + curr->idx++; + /* Return control of this transaction */ + write_lock(&hp_sdc.rtq_lock); + hp_sdc.rcurr = -1; + hp_sdc.rqty = 0; + write_unlock(&hp_sdc.rtq_lock); + tasklet_schedule(&hp_sdc.task); + } +} + +static void hp_sdc_isr(int irq, void *dev_id, struct pt_regs * regs) { + uint8_t status, data; + + status = hp_sdc_status_in8(); + /* Read data unconditionally to advance i8042. */ + data = hp_sdc_data_in8(); + + /* For now we are ignoring these until we get the SDC to behave. */ + if (((status & 0xf1) == 0x51) && data == 0x82) { + return; + } + + switch(status & HP_SDC_STATUS_IRQMASK) { + case 0: /* This case is not documented. */ + break; + case HP_SDC_STATUS_USERTIMER: + case HP_SDC_STATUS_PERIODIC: + case HP_SDC_STATUS_TIMER: + read_lock(&hp_sdc.hook_lock); + if (hp_sdc.timer != NULL) + hp_sdc.timer(irq, dev_id, status, data); + read_unlock(&hp_sdc.hook_lock); + break; + case HP_SDC_STATUS_REG: + hp_sdc_take(irq, dev_id, status, data); + break; + case HP_SDC_STATUS_HILCMD: + case HP_SDC_STATUS_HILDATA: + read_lock(&hp_sdc.hook_lock); + if (hp_sdc.hil != NULL) + hp_sdc.hil(irq, dev_id, status, data); + read_unlock(&hp_sdc.hook_lock); + break; + case HP_SDC_STATUS_PUP: + read_lock(&hp_sdc.hook_lock); + if (hp_sdc.pup != NULL) + hp_sdc.pup(irq, dev_id, status, data); + else printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n"); + read_unlock(&hp_sdc.hook_lock); + break; + default: + read_lock(&hp_sdc.hook_lock); + if (hp_sdc.cooked != NULL) + hp_sdc.cooked(irq, dev_id, status, data); + read_unlock(&hp_sdc.hook_lock); + break; + } +} + + +static void hp_sdc_nmisr(int irq, void *dev_id, struct pt_regs * regs) { + int status; + + status = hp_sdc_status_in8(); + printk(KERN_WARNING PREFIX "NMI !\n"); + +#if 0 + if (status & HP_SDC_NMISTATUS_FHS) { + read_lock(&hp_sdc.hook_lock); + if (hp_sdc.timer != NULL) + hp_sdc.timer(irq, dev_id, status, 0); + read_unlock(&hp_sdc.hook_lock); + } + else { + /* TODO: pass this on to the HIL handler, or do SAK here? */ + printk(KERN_WARNING PREFIX "HIL NMI\n"); + } +#endif +} + + +/***************** Kernel (tasklet) context functions ****************/ + +unsigned long hp_sdc_put(void); + +static void hp_sdc_tasklet(unsigned long foo) { + + write_lock_irq(&hp_sdc.rtq_lock); + if (hp_sdc.rcurr >= 0) { + struct timeval tv; + do_gettimeofday(&tv); + if (tv.tv_sec > hp_sdc.rtv.tv_sec) tv.tv_usec += 1000000; + if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) { + hp_sdc_transaction *curr; + uint8_t tmp; + + curr = hp_sdc.tq[hp_sdc.rcurr]; + /* If this turns out to be a normal failure mode + * we'll need to figure out a way to communicate + * it back to the application. and be less verbose. + */ + printk(KERN_WARNING PREFIX "read timeout (%ius)!\n", + tv.tv_usec - hp_sdc.rtv.tv_usec); + curr->idx += hp_sdc.rqty; + hp_sdc.rqty = 0; + tmp = curr->seq[curr->actidx]; + curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD; + if(tmp & HP_SDC_ACT_SEMAPHORE) { + if (curr->act.semaphore) + up(curr->act.semaphore); + } + if(tmp & HP_SDC_ACT_CALLBACK) { + /* Note this means that irqhooks may be called + * in tasklet/bh context. + */ + if (curr->act.irqhook) + curr->act.irqhook(0, 0, 0, 0); + } + curr->actidx = curr->idx; + curr->idx++; + hp_sdc.rcurr = -1; + } + } + write_unlock_irq(&hp_sdc.rtq_lock); + hp_sdc_put(); +} + +unsigned long hp_sdc_put(void) { + hp_sdc_transaction *curr; + uint8_t act; + int idx, curridx; + + int limit = 0; + + write_lock(&hp_sdc.lock); + + /* If i8042 buffers are full, we cannot do anything that + requires output, so we skip to the administrativa. */ + if (hp_sdc.ibf) { + hp_sdc_status_in8(); + if (hp_sdc.ibf) goto finish; + } + + anew: + /* See if we are in the middle of a sequence. */ + if (hp_sdc.wcurr < 0) hp_sdc.wcurr = 0; + read_lock_irq(&hp_sdc.rtq_lock); + if (hp_sdc.rcurr == hp_sdc.wcurr) hp_sdc.wcurr++; + read_unlock_irq(&hp_sdc.rtq_lock); + if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; + curridx = hp_sdc.wcurr; + + if (hp_sdc.tq[curridx] != NULL) goto start; + + while (++curridx != hp_sdc.wcurr) { + if (curridx >= HP_SDC_QUEUE_LEN) { + curridx = -1; /* Wrap to top */ + continue; + } + read_lock_irq(&hp_sdc.rtq_lock); + if (hp_sdc.rcurr == curridx) { + read_unlock_irq(&hp_sdc.rtq_lock); + continue; + } + read_unlock_irq(&hp_sdc.rtq_lock); + if (hp_sdc.tq[curridx] != NULL) break; /* Found one. */ + } + if (curridx == hp_sdc.wcurr) { /* There's nothing queued to do. */ + curridx = -1; + } + hp_sdc.wcurr = curridx; + + start: + + /* Check to see if the interrupt mask needs to be set. */ + if (hp_sdc.set_im) { + hp_sdc_status_out8(hp_sdc.im | HP_SDC_CMD_SET_IM); + hp_sdc.set_im = 0; + goto finish; + } + + if (hp_sdc.wcurr == -1) goto done; + + curr = hp_sdc.tq[curridx]; + idx = curr->actidx; + + if (curr->actidx >= curr->endidx) { + hp_sdc.tq[curridx] = NULL; + /* Interleave outbound data between the transactions. */ + hp_sdc.wcurr++; + if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; + goto finish; + } + + act = curr->seq[idx]; + idx++; + + if (curr->idx >= curr->endidx) { + if (act & HP_SDC_ACT_DEALLOC) kfree(curr); + hp_sdc.tq[curridx] = NULL; + /* Interleave outbound data between the transactions. */ + hp_sdc.wcurr++; + if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; + goto finish; + } + + while (act & HP_SDC_ACT_PRECMD) { + if (curr->idx != idx) { + idx++; + act &= ~HP_SDC_ACT_PRECMD; + break; + } + hp_sdc_status_out8(curr->seq[idx]); + curr->idx++; + /* act finished? */ + if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD) + goto actdone; + /* skip quantity field if data-out sequence follows. */ + if (act & HP_SDC_ACT_DATAOUT) curr->idx++; + goto finish; + } + if (act & HP_SDC_ACT_DATAOUT) { + int qty; + + qty = curr->seq[idx]; + idx++; + if (curr->idx - idx < qty) { + hp_sdc_data_out8(curr->seq[curr->idx]); + curr->idx++; + /* act finished? */ + if ((curr->idx - idx >= qty) && + ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT)) + goto actdone; + goto finish; + } + idx += qty; + act &= ~HP_SDC_ACT_DATAOUT; + } + else while (act & HP_SDC_ACT_DATAREG) { + int mask; + uint8_t w7[4]; + + mask = curr->seq[idx]; + if (idx != curr->idx) { + idx++; + idx += !!(mask & 1); + idx += !!(mask & 2); + idx += !!(mask & 4); + idx += !!(mask & 8); + act &= ~HP_SDC_ACT_DATAREG; + break; + } + + w7[0] = (mask & 1) ? curr->seq[++idx] : hp_sdc.r7[0]; + w7[1] = (mask & 2) ? curr->seq[++idx] : hp_sdc.r7[1]; + w7[2] = (mask & 4) ? curr->seq[++idx] : hp_sdc.r7[2]; + w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3]; + + if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 || + w7[hp_sdc.wi-0x70] == hp_sdc.r7[hp_sdc.wi-0x70]) { + int i = 0; + + /* Need to point the write index register */ + while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++; + if (i < 4) { + hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i); + hp_sdc.wi = 0x70 + i; + goto finish; + } + idx++; + if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG) + goto actdone; + curr->idx = idx; + act &= ~HP_SDC_ACT_DATAREG; + break; + } + + hp_sdc_data_out8(w7[hp_sdc.wi - 0x70]); + hp_sdc.r7[hp_sdc.wi - 0x70] = w7[hp_sdc.wi - 0x70]; + hp_sdc.wi++; /* write index register autoincrements */ + { + int i = 0; + + while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++; + if (i >= 4) { + curr->idx = idx + 1; + if ((act & HP_SDC_ACT_DURING) == + HP_SDC_ACT_DATAREG) + goto actdone; + } + } + goto finish; + } + /* We don't go any further in the command if there is a pending read, + because we don't want interleaved results. */ + read_lock_irq(&hp_sdc.rtq_lock); + if (hp_sdc.rcurr >= 0) { + read_unlock_irq(&hp_sdc.rtq_lock); + goto finish; + } + read_unlock_irq(&hp_sdc.rtq_lock); + + + if (act & HP_SDC_ACT_POSTCMD) { + uint8_t postcmd; + + /* curr->idx should == idx at this point. */ + postcmd = curr->seq[idx]; + curr->idx++; + if (act & HP_SDC_ACT_DATAIN) { + + /* Start a new read */ + hp_sdc.rqty = curr->seq[curr->idx]; + do_gettimeofday(&hp_sdc.rtv); + curr->idx++; + /* Still need to lock here in case of spurious irq. */ + write_lock_irq(&hp_sdc.rtq_lock); + hp_sdc.rcurr = curridx; + write_unlock_irq(&hp_sdc.rtq_lock); + hp_sdc_status_out8(postcmd); + goto finish; + } + hp_sdc_status_out8(postcmd); + goto actdone; + } + +actdone: + if (act & HP_SDC_ACT_SEMAPHORE) { + up(curr->act.semaphore); + } + else if (act & HP_SDC_ACT_CALLBACK) { + curr->act.irqhook(0,0,0,0); + } + if (curr->idx >= curr->endidx) { /* This transaction is over. */ + if (act & HP_SDC_ACT_DEALLOC) kfree(curr); + hp_sdc.tq[curridx] = NULL; + } + else { + curr->actidx = idx + 1; + curr->idx = idx + 2; + } + /* Interleave outbound data between the transactions. */ + hp_sdc.wcurr++; + if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0; + + finish: + /* If by some quirk IBF has cleared and our ISR has run to + see that that has happened, do it all again. */ + if (!hp_sdc.ibf && limit++ < 20) goto anew; + + done: + if (hp_sdc.wcurr >= 0) tasklet_schedule(&hp_sdc.task); + write_unlock(&hp_sdc.lock); + return 0; +} + +/******* Functions called in either user or kernel context ****/ +int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) { + int i; + + if (this == NULL) { + tasklet_schedule(&hp_sdc.task); + return -EINVAL; + }; + + write_lock_bh(&hp_sdc.lock); + + /* Can't have same transaction on queue twice */ + for (i=0; i < HP_SDC_QUEUE_LEN; i++) + if (hp_sdc.tq[i] == this) goto fail; + + this->actidx = 0; + this->idx = 1; + + /* Search for empty slot */ + for (i=0; i < HP_SDC_QUEUE_LEN; i++) { + if (hp_sdc.tq[i] == NULL) { + hp_sdc.tq[i] = this; + tasklet_schedule(&hp_sdc.task); + write_unlock_bh(&hp_sdc.lock); + return 0; + } + } + write_unlock_bh(&hp_sdc.lock); + printk(KERN_WARNING PREFIX "No free slot to add transaction.\n"); + return -EBUSY; + + fail: + write_unlock_bh(&hp_sdc.lock); + printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n"); + return -EINVAL; +} + +int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) { + int i; + + write_lock_bh(&hp_sdc.lock); + + /* TODO: don't remove it if it's not done. */ + + for (i=0; i < HP_SDC_QUEUE_LEN; i++) + if (hp_sdc.tq[i] == this) hp_sdc.tq[i] = NULL; + + write_unlock_bh(&hp_sdc.lock); + return 0; +} + + + +/********************** User context functions **************************/ +int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) { + + MOD_INC_USE_COUNT; + if (callback == NULL || hp_sdc.dev == NULL) { + MOD_DEC_USE_COUNT; + return -EINVAL; + } + write_lock_irq(&hp_sdc.hook_lock); + if (hp_sdc.timer != NULL) { + write_unlock_irq(&hp_sdc.hook_lock); + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + hp_sdc.timer = callback; + /* Enable interrupts from the timers */ + hp_sdc.im &= ~HP_SDC_IM_FH; + hp_sdc.im &= ~HP_SDC_IM_PT; + hp_sdc.im &= ~HP_SDC_IM_TIMERS; + hp_sdc.set_im = 1; + write_unlock_irq(&hp_sdc.hook_lock); + + tasklet_schedule(&hp_sdc.task); + + return 0; +} + +int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) { + + MOD_INC_USE_COUNT; + if (callback == NULL || hp_sdc.dev == NULL) { + MOD_DEC_USE_COUNT; + return -EINVAL; + } + write_lock_irq(&hp_sdc.hook_lock); + if (hp_sdc.hil != NULL) { + write_unlock_irq(&hp_sdc.hook_lock); + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + hp_sdc.hil = callback; + hp_sdc.im &= ~HP_SDC_IM_HIL; + hp_sdc.set_im = 1; + write_unlock_irq(&hp_sdc.hook_lock); + + tasklet_schedule(&hp_sdc.task); + + return 0; +} + +int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) { + + MOD_INC_USE_COUNT; + if (callback == NULL || hp_sdc.dev == NULL) { + MOD_DEC_USE_COUNT; + return -EINVAL; + } + write_lock_irq(&hp_sdc.hook_lock); + if (hp_sdc.cooked != NULL) { + write_unlock_irq(&hp_sdc.hook_lock); + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + /* Enable interrupts from the HIL MLC */ + hp_sdc.cooked = callback; + hp_sdc.im &= ~HP_SDC_IM_HIL; + hp_sdc.set_im = 1; + write_unlock_irq(&hp_sdc.hook_lock); + + tasklet_schedule(&hp_sdc.task); + + return 0; +} + +int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) { + + + write_lock_irq(&hp_sdc.hook_lock); + if ((callback != hp_sdc.timer) || + (hp_sdc.timer == NULL)) { + write_unlock_irq(&hp_sdc.hook_lock); + return -EINVAL; + } + + /* Disable interrupts from the timers */ + hp_sdc.timer = NULL; + hp_sdc.im |= HP_SDC_IM_TIMERS; + hp_sdc.im |= HP_SDC_IM_FH; + hp_sdc.im |= HP_SDC_IM_PT; + hp_sdc.set_im = 1; + write_unlock_irq(&hp_sdc.hook_lock); + tasklet_schedule(&hp_sdc.task); + + MOD_DEC_USE_COUNT; + return 0; +} + +int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) { + + write_lock_irq(&hp_sdc.hook_lock); + if ((callback != hp_sdc.hil) || + (hp_sdc.hil == NULL)) { + write_unlock_irq(&hp_sdc.hook_lock); + return -EINVAL; + } + + hp_sdc.hil = NULL; + /* Disable interrupts from HIL only if there is no cooked driver. */ + if(hp_sdc.cooked == NULL) { + hp_sdc.im |= HP_SDC_IM_HIL; + hp_sdc.set_im = 1; + } + write_unlock_irq(&hp_sdc.hook_lock); + tasklet_schedule(&hp_sdc.task); + + MOD_DEC_USE_COUNT; + return 0; +} + +int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) { + + write_lock_irq(&hp_sdc.hook_lock); + if ((callback != hp_sdc.cooked) || + (hp_sdc.cooked == NULL)) { + write_unlock_irq(&hp_sdc.hook_lock); + return -EINVAL; + } + + hp_sdc.cooked = NULL; + /* Disable interrupts from HIL only if there is no raw HIL driver. */ + if(hp_sdc.hil == NULL) { + hp_sdc.im |= HP_SDC_IM_HIL; + hp_sdc.set_im = 1; + } + write_unlock_irq(&hp_sdc.hook_lock); + tasklet_schedule(&hp_sdc.task); + + MOD_DEC_USE_COUNT; + return 0; +} + +/************************* Keepalive timer task *********************/ + +void hp_sdc_kicker (unsigned long data) { + tasklet_schedule(&hp_sdc.task); + /* Re-insert the periodic task. */ + mod_timer(&hp_sdc.kicker, jiffies + HZ); +} + +/************************** Module Initialization ***************************/ + +static struct parisc_device_id hp_sdc_tbl[] = { + { + .hw_type = HPHW_FIO, + .hversion_rev = HVERSION_REV_ANY_ID, + .hversion = HVERSION_ANY_ID, + .sversion = 0x73, + }, + { 0, } +}; + +MODULE_DEVICE_TABLE(parisc, hp_sdc_tbl); + +static int __init hp_sdc_init(struct parisc_device *d); + +static struct parisc_driver hp_sdc_driver = { + .name = "HP SDC", + .id_table = hp_sdc_tbl, + .probe = hp_sdc_init, +}; + +static int __init hp_sdc_init(struct parisc_device *d) +{ + int i; + char *errstr = NULL; + hp_sdc_transaction t_sync; + uint8_t ts_sync[6]; + struct semaphore s_sync; + + + errstr = "foo\n"; + + if (!d) return 1; + if (hp_sdc.dev != NULL) return 1; /* We only expect one SDC */ + + hp_sdc.dev = d; + hp_sdc.irq = d->irq; + /* TODO: Is NMI == IRQ - 1 all cases, or is there a way to query? */ + hp_sdc.nmi = d->irq - 1; + hp_sdc.base_io = (unsigned long) d->hpa; + hp_sdc.data_io = (unsigned long) d->hpa + 0x800; + hp_sdc.status_io = (unsigned long) d->hpa + 0x801; + + hp_sdc.lock = RW_LOCK_UNLOCKED; + hp_sdc.ibf_lock = RW_LOCK_UNLOCKED; + hp_sdc.rtq_lock = RW_LOCK_UNLOCKED; + hp_sdc.hook_lock = RW_LOCK_UNLOCKED; + + hp_sdc.timer = NULL; + hp_sdc.hil = NULL; + hp_sdc.pup = NULL; + hp_sdc.cooked = NULL; + hp_sdc.im = HP_SDC_IM_MASK; /* Mask maskable irqs */ + hp_sdc.set_im = 1; + hp_sdc.wi = 0xff; + hp_sdc.r7[0] = 0xff; + hp_sdc.r7[1] = 0xff; + hp_sdc.r7[2] = 0xff; + hp_sdc.r7[3] = 0xff; + hp_sdc.ibf = 1; + + for (i = 0; i < HP_SDC_QUEUE_LEN; i++) hp_sdc.tq[i] = NULL; + hp_sdc.wcurr = -1; + hp_sdc.rcurr = -1; + hp_sdc.rqty = 0; + + hp_sdc.dev_err = -ENODEV; + + errstr = "IO not found for"; + if (!hp_sdc.base_io) goto err0; + + errstr = "IRQ not found for"; + if (!hp_sdc.irq) goto err0; + + hp_sdc.dev_err = -EBUSY; + + errstr = "IO not available for"; + if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0; + + errstr = "IRQ not available for"; + if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, hp_sdc_driver.name, + (void *) hp_sdc.base_io)) goto err1; + + errstr = "NMI not available for"; + if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, 0, "HP SDC NMI", + (void*)d->hpa)) goto err2; + + printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n", + (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi); + + hp_sdc_status_in8(); + hp_sdc_data_in8(); + + tasklet_init(&hp_sdc.task, hp_sdc_tasklet, 0); + + /* Sync the output buffer registers, thus scheduling hp_sdc_tasklet. */ + t_sync.actidx = 0; + t_sync.idx = 1; + t_sync.endidx = 6; + t_sync.seq = ts_sync; + ts_sync[0] = HP_SDC_ACT_DATAREG | HP_SDC_ACT_SEMAPHORE; + ts_sync[1] = 0x0f; + ts_sync[2] = ts_sync[3] = ts_sync[4] = ts_sync[5] = 0; + t_sync.act.semaphore = &s_sync; + init_MUTEX_LOCKED(&s_sync); + hp_sdc_enqueue_transaction(&t_sync); + down(&s_sync); /* Wait for t_sync to complete */ + + /* Create the keepalive task */ + init_timer(&hp_sdc.kicker); + hp_sdc.kicker.expires = jiffies + HZ; + hp_sdc.kicker.function = &hp_sdc_kicker; + add_timer(&hp_sdc.kicker); + + hp_sdc.dev_err = 0; + return 0; + err2: + free_irq(hp_sdc.irq, NULL); + err1: + release_region(hp_sdc.data_io, 2); + err0: + printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n", + errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi); + hp_sdc.dev = NULL; + return hp_sdc.dev_err; +} + +static void __exit hp_sdc_exit(void) +{ + write_lock_irq(&hp_sdc.lock); + + /* Turn off all maskable "sub-function" irq's. */ + hp_sdc_spin_ibf(); + gsc_writeb(HP_SDC_CMD_SET_IM | HP_SDC_IM_MASK, hp_sdc.status_io); + + /* Wait until we know this has been processed by the i8042 */ + hp_sdc_spin_ibf(); + + free_irq(hp_sdc.nmi, NULL); + free_irq(hp_sdc.irq, NULL); + write_unlock_irq(&hp_sdc.lock); + + del_timer(&hp_sdc.kicker); + + tasklet_kill(&hp_sdc.task); + +/* release_region(hp_sdc.data_io, 2); */ + + if (unregister_parisc_driver(&hp_sdc_driver)) + printk(KERN_WARNING PREFIX "Error unregistering HP SDC"); +} + +static int __init hp_sdc_register(void) +{ + hp_sdc.dev = NULL; + hp_sdc.dev_err = 0; + hp_sdc_transaction tq_init; + uint8_t tq_init_seq[5]; + struct semaphore tq_init_sem; + + if (register_parisc_driver(&hp_sdc_driver)) { + printk(KERN_WARNING PREFIX "Error registering SDC with system bus tree.\n"); + return -ENODEV; + } + if (hp_sdc.dev == NULL) { + printk(KERN_WARNING PREFIX "No SDC found.\n"); + return hp_sdc.dev_err; + } + + init_MUTEX_LOCKED(&tq_init_sem); + + tq_init.actidx = 0; + tq_init.idx = 1; + tq_init.endidx = 5; + tq_init.seq = tq_init_seq; + tq_init.act.semaphore = &tq_init_sem; + + tq_init_seq[0] = + HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE; + tq_init_seq[1] = HP_SDC_CMD_READ_KCC; + tq_init_seq[2] = 1; + tq_init_seq[3] = 0; + tq_init_seq[4] = 0; + + hp_sdc_enqueue_transaction(&tq_init); + + down(&tq_init_sem); + up(&tq_init_sem); + + if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) { + printk(KERN_WARNING PREFIX "Error reading config byte.\n"); + hp_sdc_exit(); + return -ENODEV; + } + hp_sdc.r11 = tq_init_seq[4]; + if (hp_sdc.r11 & HP_SDC_CFG_NEW) { + char *str; + printk(KERN_INFO PREFIX "New style SDC\n"); + tq_init_seq[1] = HP_SDC_CMD_READ_XTD; + tq_init.actidx = 0; + tq_init.idx = 1; + down(&tq_init_sem); + hp_sdc_enqueue_transaction(&tq_init); + down(&tq_init_sem); + up(&tq_init_sem); + if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) { + printk(KERN_WARNING PREFIX "Error reading extended config byte.\n"); + return -ENODEV; + } + hp_sdc.r7e = tq_init_seq[4]; + HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str) + printk(KERN_INFO PREFIX "Revision: %s\n", str); + if (hp_sdc.r7e & HP_SDC_XTD_BEEPER) { + printk(KERN_INFO PREFIX "TI SN76494 beeper present\n"); + } + if (hp_sdc.r7e & HP_SDC_XTD_BBRTC) { + printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n"); + } + printk(KERN_INFO PREFIX "Spunking the self test register to force PUP " + "on next firmware reset.\n"); + tq_init_seq[0] = HP_SDC_ACT_PRECMD | + HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE; + tq_init_seq[1] = HP_SDC_CMD_SET_STR; + tq_init_seq[2] = 1; + tq_init_seq[3] = 0; + tq_init.actidx = 0; + tq_init.idx = 1; + tq_init.endidx = 4; + down(&tq_init_sem); + hp_sdc_enqueue_transaction(&tq_init); + down(&tq_init_sem); + up(&tq_init_sem); + } + else { + printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n", + (hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087"); + } + + return 0; +} + +module_init(hp_sdc_register); +module_exit(hp_sdc_exit); + +/* Timing notes: These measurements taken on my 64MHz 7100-LC (715/64) + * cycles cycles-adj time + * between two consecutive mfctl(16)'s: 4 n/a 63ns + * hp_sdc_spin_ibf when idle: 119 115 1.7us + * gsc_writeb status register: 83 79 1.2us + * IBF to clear after sending SET_IM: 6204 6006 93us + * IBF to clear after sending LOAD_RT: 4467 4352 68us + * IBF to clear after sending two LOAD_RTs: 18974 18859 295us + * READ_T1, read status/data, IRQ, call handler: 35564 n/a 556us + * cmd to ~IBF READ_T1 2nd time right after: 5158403 n/a 81ms + * between IRQ received and ~IBF for above: 2578877 n/a 40ms + * + * Performance stats after a run of this module configuring HIL and + * receiving a few mouse events: + * + * status in8 282508 cycles 7128 calls + * status out8 8404 cycles 341 calls + * data out8 1734 cycles 78 calls + * isr 174324 cycles 617 calls (includes take) + * take 1241 cycles 2 calls + * put 1411504 cycles 6937 calls + * task 1655209 cycles 6937 calls (includes put) + * + */ diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/input/serio/hp_sdc_mlc.c linux-2.5/drivers/input/serio/hp_sdc_mlc.c --- ../prev/linux-2.5/drivers/input/serio/hp_sdc_mlc.c Wed Dec 31 17:00:00 1969 +++ linux-2.5/drivers/input/serio/hp_sdc_mlc.c Wed Nov 6 21:04:36 2002 @@ -0,0 +1,370 @@ +/* + * Access to HP-HIL MLC through HP System Device Controller. + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A + * System Device Controller Microprocessor Firmware Theory of Operation + * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PREFIX "HP SDC MLC: " + +static hil_mlc hp_sdc_mlc; + +MODULE_AUTHOR("Brian S. Julin "); +MODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines"); +MODULE_LICENSE("Dual BSD/GPL"); + +struct hp_sdc_mlc_priv_s { + int emtestmode; + hp_sdc_transaction trans; + u8 tseq[16]; + int got5x; +} hp_sdc_mlc_priv; + +/************************* Interrupt context ******************************/ +static void hp_sdc_mlc_isr (int irq, void *dev_id, + uint8_t status, uint8_t data) { + int idx; + hil_mlc *mlc = &hp_sdc_mlc; + + write_lock(&(mlc->lock)); + if (mlc->icount < 0) { + printk(KERN_WARNING PREFIX "HIL Overflow!\n"); + up(&mlc->isem); + goto out; + } + idx = 15 - mlc->icount; + if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) { + mlc->ipacket[idx] |= data | HIL_ERR_INT; + mlc->icount--; + if (hp_sdc_mlc_priv.got5x) goto check; + if (!idx) goto check; + if ((mlc->ipacket[idx-1] & HIL_PKT_ADDR_MASK) != + (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) { + mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK; + mlc->ipacket[idx] |= (mlc->ipacket[idx-1] + & HIL_PKT_ADDR_MASK); + } + goto check; + } + /* We know status is 5X */ + if (data & HP_SDC_HIL_ISERR) goto err; + mlc->ipacket[idx] = + (data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT; + hp_sdc_mlc_priv.got5x = 1; + goto out; + + check: + hp_sdc_mlc_priv.got5x = 0; + if (mlc->imatch == 0) goto done; + if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) + && (mlc->ipacket[idx] == (mlc->imatch | idx))) goto done; + if (mlc->ipacket[idx] == mlc->imatch) goto done; + goto out; + + err: + printk(KERN_DEBUG PREFIX "err code %x\n", data); + switch (data) { + case HP_SDC_HIL_RC_DONE: + printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n"); + break; + case HP_SDC_HIL_ERR: + mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR | + HIL_ERR_FERR | HIL_ERR_FOF; + break; + case HP_SDC_HIL_TO: + mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR; + break; + case HP_SDC_HIL_RC: + printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n"); + break; + default: + printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data); + break; + } + /* No more data will be coming due to an error. */ + done: + tasklet_schedule(mlc->tasklet); + up(&(mlc->isem)); + out: + write_unlock(&(mlc->lock)); +} + + +/******************** Tasklet or userspace context functions ****************/ + +static int hp_sdc_mlc_in (hil_mlc *mlc, suseconds_t timeout) { + unsigned long flags; + struct hp_sdc_mlc_priv_s *priv; + int rc = 2; + + priv = mlc->priv; + + write_lock_irqsave(&(mlc->lock), flags); + + /* Try to down the semaphore */ + if (down_trylock(&(mlc->isem))) { + struct timeval tv; + if (priv->emtestmode) { + mlc->ipacket[0] = + HIL_ERR_INT | (mlc->opacket & + (HIL_PKT_CMD | + HIL_PKT_ADDR_MASK | + HIL_PKT_DATA_MASK)); + mlc->icount = 14; + /* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */ + goto wasup; + } + do_gettimeofday(&tv); + tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec); + if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) { + /* printk("!%i %i", + tv.tv_usec - mlc->instart.tv_usec, + mlc->intimeout); + */ + rc = 1; + up(&(mlc->isem)); + } + goto done; + } + wasup: + up(&(mlc->isem)); + rc = 0; + goto done; + done: + write_unlock_irqrestore(&(mlc->lock), flags); + return rc; +} + +static int hp_sdc_mlc_cts (hil_mlc *mlc) { + struct hp_sdc_mlc_priv_s *priv; + unsigned long flags; + + priv = mlc->priv; + + write_lock_irqsave(&(mlc->lock), flags); + + /* Try to down the semaphores -- they should be up. */ + if (down_trylock(&(mlc->isem))) { + BUG(); + goto busy; + } + if (down_trylock(&(mlc->osem))) { + BUG(); + up(&(mlc->isem)); + goto busy; + } + up(&(mlc->isem)); + up(&(mlc->osem)); + + if (down_trylock(&(mlc->csem))) { + if (priv->trans.act.semaphore != &(mlc->csem)) goto poll; + goto busy; + } + if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) goto done; + + poll: + priv->trans.act.semaphore = &(mlc->csem); + priv->trans.actidx = 0; + priv->trans.idx = 1; + priv->trans.endidx = 5; + priv->tseq[0] = + HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE; + priv->tseq[1] = HP_SDC_CMD_READ_USE; + priv->tseq[2] = 1; + priv->tseq[3] = 0; + priv->tseq[4] = 0; + hp_sdc_enqueue_transaction(&(priv->trans)); + busy: + write_unlock_irqrestore(&(mlc->lock), flags); + return 1; + done: + priv->trans.act.semaphore = &(mlc->osem); + up(&(mlc->csem)); + write_unlock_irqrestore(&(mlc->lock), flags); + return 0; +} + +static void hp_sdc_mlc_out (hil_mlc *mlc) { + struct hp_sdc_mlc_priv_s *priv; + unsigned long flags; + + priv = mlc->priv; + + write_lock_irqsave(&(mlc->lock), flags); + + /* Try to down the semaphore -- it should be up. */ + if (down_trylock(&(mlc->osem))) { + BUG(); + goto done; + } + + if (mlc->opacket & HIL_DO_ALTER_CTRL) goto do_control; + + do_data: + if (priv->emtestmode) { + up(&(mlc->osem)); + goto done; + } + /* Shouldn't be sending commands when loop may be busy */ + if (down_trylock(&(mlc->csem))) { + BUG(); + goto done; + } + up(&(mlc->csem)); + + priv->trans.actidx = 0; + priv->trans.idx = 1; + priv->trans.act.semaphore = &(mlc->osem); + priv->trans.endidx = 6; + priv->tseq[0] = + HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE; + priv->tseq[1] = 0x7; + priv->tseq[2] = + (mlc->opacket & + (HIL_PKT_ADDR_MASK | HIL_PKT_CMD)) + >> HIL_PKT_ADDR_SHIFT; + priv->tseq[3] = + (mlc->opacket & HIL_PKT_DATA_MASK) + >> HIL_PKT_DATA_SHIFT; + priv->tseq[4] = 0; /* No timeout */ + if (priv->tseq[3] == HIL_CMD_DHR) priv->tseq[4] = 1; + priv->tseq[5] = HP_SDC_CMD_DO_HIL; + goto enqueue; + + do_control: + priv->emtestmode = mlc->opacket & HIL_CTRL_TEST; + if ((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE) { + BUG(); /* we cannot emulate this, it should not be used. */ + } + if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) goto control_only; + if (mlc->opacket & HIL_CTRL_APE) { + BUG(); /* Should not send command/data after engaging APE */ + goto done; + } + /* Disengaging APE this way would not be valid either since + * the loop must be allowed to idle. + * + * So, it works out that we really never actually send control + * and data when using SDC, we just send the data. + */ + goto do_data; + + control_only: + priv->trans.actidx = 0; + priv->trans.idx = 1; + priv->trans.act.semaphore = &(mlc->osem); + priv->trans.endidx = 4; + priv->tseq[0] = + HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE; + priv->tseq[1] = HP_SDC_CMD_SET_LPC; + priv->tseq[2] = 1; + // priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; + priv->tseq[3] = 0; + if (mlc->opacket & HIL_CTRL_APE) { + priv->tseq[3] |= HP_SDC_LPC_APE_IPF; + down_trylock(&(mlc->csem)); + } + enqueue: + hp_sdc_enqueue_transaction(&(priv->trans)); + done: + write_unlock_irqrestore(&(mlc->lock), flags); +} + + +static void hp_sdc_mlc_inc_use_count (void) { + MOD_INC_USE_COUNT; +} + +static void hp_sdc_mlc_dec_use_count (void) { + MOD_DEC_USE_COUNT; +} + +static int __init hp_sdc_mlc_init(void) +{ + hil_mlc *mlc = &hp_sdc_mlc; + + printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n"); + + hp_sdc_mlc_priv.emtestmode = 0; + hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq; + hp_sdc_mlc_priv.trans.act.semaphore = &(mlc->osem); + hp_sdc_mlc_priv.got5x = 0; + + mlc->cts = &hp_sdc_mlc_cts; + mlc->in = &hp_sdc_mlc_in; + mlc->out = &hp_sdc_mlc_out; + + mlc->inc_use_count = &hp_sdc_mlc_inc_use_count; + mlc->dec_use_count = &hp_sdc_mlc_dec_use_count; + + if (hil_mlc_register(mlc)) { + printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n"); + goto err0; + } + mlc->priv = &hp_sdc_mlc_priv; + + if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) { + printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n"); + goto err1; + } + return 0; + err1: + if (hil_mlc_unregister(mlc)) { + printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" + "This is bad. Could cause an oops.\n"); + } + err0: + return -EBUSY; +} + +static void __exit hp_sdc_mlc_exit(void) +{ + hil_mlc *mlc = &hp_sdc_mlc; + if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) { + printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n" + "This is bad. Could cause an oops.\n"); + } + if (hil_mlc_unregister(mlc)) { + printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n" + "This is bad. Could cause an oops.\n"); + } +} + +module_init(hp_sdc_mlc_init); +module_exit(hp_sdc_mlc_exit); diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/net/tulip/media.c linux-2.5/drivers/net/tulip/media.c --- ../prev/linux-2.5/drivers/net/tulip/media.c Fri May 2 04:04:08 2003 +++ linux-2.5/drivers/net/tulip/media.c Tue Dec 10 15:02:34 2002 @@ -271,13 +271,27 @@ int reset_length = p[2 + init_length]; misc_info = (u16*)(reset_sequence + reset_length); if (startup) { + int timeout = 20; /* 2 ms */ outl(mtable->csr12dir | 0x100, ioaddr + CSR12); for (i = 0; i < reset_length; i++) outl(reset_sequence[i], ioaddr + CSR12); + + /* flush posted writes */ + inl(ioaddr + CSR12); + /* Sect 3.10.3 in DP83840A.pdf (p39) */ + udelay(500); + + /* Section 4.2 in DP83840A.pdf (p43) */ + while (timeout-- && + (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET)) + udelay(100); } for (i = 0; i < init_length; i++) outl(init_sequence[i], ioaddr + CSR12); + + inl(ioaddr + CSR12); /* flush posted writes */ } + tmp_info = get_u16(&misc_info[1]); if (tmp_info) tp->advertising[phy_num] = tmp_info | 1; diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/parisc/Kconfig linux-2.5/drivers/parisc/Kconfig --- ../prev/linux-2.5/drivers/parisc/Kconfig Fri May 2 04:04:17 2003 +++ linux-2.5/drivers/parisc/Kconfig Wed Apr 9 10:19:44 2003 @@ -125,4 +125,29 @@ If unsure, say Y. +config HOTPLUG + bool "Support for hot-pluggable devices" + ---help--- + Say Y here if you want to plug devices into your computer while + the system is running, and be able to use them quickly. In many + cases, the devices can likewise be unplugged at any time too. + + One well known example of this is PCMCIA- or PC-cards, credit-card + size devices such as network cards, modems or hard drives which are + plugged into slots found on all modern laptop computers. Another + example, used on modern desktops as well as laptops, is USB. + + Enable HOTPLUG and KMOD, and build a modular kernel. Get agent + software (at ) and install it. + Then your kernel will automatically call out to a user mode "policy + agent" (/sbin/hotplug) to load modules and set up software needed + to use devices as you hotplug them. + +# jejb: keep this commented out for now. There is a known parisc laptop +# that might need this, but no-one's currently got it working +#source "drivers/pcmcia/Kconfig" + +source "drivers/hotplug/Kconfig" + + endmenu diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/scsi/sym53c8xx.c linux-2.5/drivers/scsi/sym53c8xx.c --- ../prev/linux-2.5/drivers/scsi/sym53c8xx.c Fri May 2 04:04:44 2003 +++ linux-2.5/drivers/scsi/sym53c8xx.c Wed Apr 23 20:57:12 2003 @@ -103,14 +103,7 @@ #include -#include -#include -#include -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17) #include -#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) -#include -#endif #include #include #include @@ -122,13 +115,13 @@ #include #include #include - #include #include - -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35) #include -#endif + +#include +#include +#include #ifndef __init #define __init @@ -137,10 +130,6 @@ #define __initdata #endif -#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92) -#include -#endif - #include "scsi.h" #include "hosts.h" @@ -439,8 +428,6 @@ ** code. */ -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) - typedef struct pci_dev *pcidev_t; #define PCIDEV_NULL (0) #define PciBusNumber(d) (d)->bus->number @@ -486,96 +473,6 @@ #undef PCI_BAR_OFFSET } -#else /* Incomplete emulation of current PCI code for pre-2.2 kernels */ - -typedef unsigned int pcidev_t; -#define PCIDEV_NULL (~0u) -#define PciBusNumber(d) ((d)>>8) -#define PciDeviceFn(d) ((d)&0xff) -#define __PciDev(busn, devfn) (((busn)<<8)+(devfn)) - -#define pci_present pcibios_present - -#define pci_read_config_byte(d, w, v) \ - pcibios_read_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v) -#define pci_read_config_word(d, w, v) \ - pcibios_read_config_word(PciBusNumber(d), PciDeviceFn(d), w, v) -#define pci_read_config_dword(d, w, v) \ - pcibios_read_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v) - -#define pci_write_config_byte(d, w, v) \ - pcibios_write_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v) -#define pci_write_config_word(d, w, v) \ - pcibios_write_config_word(PciBusNumber(d), PciDeviceFn(d), w, v) -#define pci_write_config_dword(d, w, v) \ - pcibios_write_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v) - -static pcidev_t __init -pci_find_device(unsigned int vendor, unsigned int device, pcidev_t prev) -{ - static unsigned short pci_index; - int retv; - unsigned char bus_number, device_fn; - - if (prev == PCIDEV_NULL) - pci_index = 0; - else - ++pci_index; - retv = pcibios_find_device (vendor, device, pci_index, - &bus_number, &device_fn); - return retv ? PCIDEV_NULL : __PciDev(bus_number, device_fn); -} - -static u_short __init PciVendorId(pcidev_t dev) -{ - u_short vendor_id; - pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); - return vendor_id; -} - -static u_short __init PciDeviceId(pcidev_t dev) -{ - u_short device_id; - pci_read_config_word(dev, PCI_DEVICE_ID, &device_id); - return device_id; -} - -static u_int __init PciIrqLine(pcidev_t dev) -{ - u_char irq; - pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); - return irq; -} - -static int __init -pci_get_base_address(pcidev_t dev, int offset, u_long *base) -{ - u_int32 tmp; - - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp); - *base = tmp; - offset += sizeof(u_int32); - if ((tmp & 0x7) == 0x4) { -#if BITS_PER_LONG > 32 - pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp); - *base |= (((u_long)tmp) << 32); -#endif - offset += sizeof(u_int32); - } - return offset; -} -static u_long __init -pci_get_base_cookie(struct pci_dev *pdev, int offset) -{ - u_long base; - - (void) pci_get_base_address(dev, offset, &base); - - return base; -} - -#endif /* LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) */ - /* Does not make sense in earlier kernels */ #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) #define pci_enable_device(pdev) (0) @@ -630,8 +527,6 @@ ** wished (e.g.: threaded by controller). */ -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) - spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED; #define NCR_LOCK_DRIVER(flags) spin_lock_irqsave(&sym53c8xx_lock, flags) #define NCR_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&sym53c8xx_lock,flags) @@ -645,20 +540,6 @@ #define NCR_UNLOCK_SCSI_DONE(host, flags) \ spin_unlock_irqrestore(((host)->host_lock), flags) -#else - -#define NCR_LOCK_DRIVER(flags) do { save_flags(flags); cli(); } while (0) -#define NCR_UNLOCK_DRIVER(flags) do { restore_flags(flags); } while (0) - -#define NCR_INIT_LOCK_NCB(np) do { } while (0) -#define NCR_LOCK_NCB(np, flags) do { save_flags(flags); cli(); } while (0) -#define NCR_UNLOCK_NCB(np, flags) do { restore_flags(flags); } while (0) - -#define NCR_LOCK_SCSI_DONE(host, flags) do {;} while (0) -#define NCR_UNLOCK_SCSI_DONE(host, flags) do {;} while (0) - -#endif - /* ** Memory mapped IO ** @@ -670,16 +551,9 @@ ** architecture. */ -#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0) -#define ioremap vremap -#define iounmap vfree -#endif - #ifdef __sparc__ # include # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) -#elif defined(__alpha__) -# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #else /* others */ # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #endif @@ -713,13 +587,8 @@ ** inaccurate on Pentium processors. */ -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,105) #define UDELAY udelay #define MDELAY mdelay -#else -static void UDELAY(long us) { udelay(us); } -static void MDELAY(long ms) { while (ms--) UDELAY(1000); } -#endif /* ** Simple power of two buddy-like allocator @@ -735,11 +604,7 @@ ** real bus astraction, btw). */ -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) #define __GetFreePages(flags, order) __get_free_pages(flags, order) -#else -#define __GetFreePages(flags, order) __get_free_pages(flags, order, 0) -#endif #define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ #if PAGE_SIZE >= 8192 @@ -1307,9 +1172,7 @@ driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP; # ifdef MODULE char *sym53c8xx = 0; /* command line passed by insmod */ -# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) MODULE_PARM(sym53c8xx, "s"); -# endif # endif #endif @@ -2026,9 +1889,7 @@ /* when lcb is not allocated. */ Scsi_Cmnd *done_list; /* Commands waiting for done() */ /* callback to be invoked. */ -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) spinlock_t smp_lock; /* Lock for SMP threading */ -#endif /*---------------------------------------------------------------- ** Chip and controller indentification. @@ -5843,12 +5704,8 @@ ((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT), #else ((driver_setup.irqm & 0x10) ? 0 : SA_SHIRQ) | -#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0) - ((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT), -#else 0, #endif -#endif NAME53C8XX, np)) { printk(KERN_ERR "%s: request irq %d failure\n", ncr_name(np), device->slot.irq); @@ -13244,38 +13101,11 @@ pci_write_config_word(pdev, PCI_COMMAND, command); } -#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0) - if ( is_prep ) { - if (io_port >= 0x10000000) { - printk(NAME53C8XX ": reallocating io_port (Wacky IBM)"); - io_port = (io_port & 0x00FFFFFF) | 0x01000000; - pci_write_config_dword(pdev, - PCI_BASE_ADDRESS_0, io_port); - } - if (base >= 0x10000000) { - printk(NAME53C8XX ": reallocating base (Wacky IBM)"); - base = (base & 0x00FFFFFF) | 0x01000000; - pci_write_config_dword(pdev, - PCI_BASE_ADDRESS_1, base); - } - if (base_2 >= 0x10000000) { - printk(NAME53C8XX ": reallocating base2 (Wacky IBM)"); - base_2 = (base_2 & 0x00FFFFFF) | 0x01000000; - pci_write_config_dword(pdev, - PCI_BASE_ADDRESS_2, base_2); - } - } -#endif #endif /* __powerpc__ */ #if defined(__i386__) && !defined(MODULE) if (!cache_line_size) { -#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75) - extern char x86; - switch(x86) { -#else switch(boot_cpu_data.x86) { -#endif case 4: suggested_cache_line_size = 4; break; case 6: case 5: suggested_cache_line_size = 8; break; diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/serial/8250.c linux-2.5/drivers/serial/8250.c --- ../prev/linux-2.5/drivers/serial/8250.c Fri May 2 04:04:51 2003 +++ linux-2.5/drivers/serial/8250.c Mon Mar 17 19:11:56 2003 @@ -1984,13 +1984,15 @@ .index = -1, }; -static int __init serial8250_console_init(void) +int __init serial8250_console_init(void) { serial8250_isa_init_ports(); register_console(&serial8250_console); return 0; } +#ifndef __hppa__ console_initcall(serial8250_console_init); +#endif #define SERIAL8250_CONSOLE &serial8250_console #else @@ -2119,9 +2121,12 @@ uart_resume_port(&serial8250_reg, &serial8250_ports[line].port, level); } -static int __init serial8250_init(void) +int __init serial8250_init(void) { int ret, i; +/* GROSS HACK for now -PB */ +static int beenhere = 0; +if (beenhere++) return 1; printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ " "IRQ sharing %sabled\n", share_irqs ? "en" : "dis"); diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/serial/8250_pci.c linux-2.5/drivers/serial/8250_pci.c --- ../prev/linux-2.5/drivers/serial/8250_pci.c Fri May 2 04:04:51 2003 +++ linux-2.5/drivers/serial/8250_pci.c Wed Apr 23 19:36:46 2003 @@ -2050,7 +2050,14 @@ static int __init serial8250_pci_init(void) { - return pci_module_init(&serial_pci_driver); + int ret; + ret = pci_module_init(&serial_pci_driver); + +#if defined(__hppa__) && defined(CONFIG_SERIAL_8250_CONSOLE) + serial8250_console_init(); +#endif + + return ret; } static void __exit serial8250_pci_exit(void) diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/serial/core.c linux-2.5/drivers/serial/core.c --- ../prev/linux-2.5/drivers/serial/core.c Fri May 2 04:04:52 2003 +++ linux-2.5/drivers/serial/core.c Wed Apr 23 19:36:46 2003 @@ -240,7 +240,8 @@ /* * Ensure that the IRQ handler isn't running on another CPU. */ - synchronize_irq(port->irq); + if(port->irq != SERIAL_IRQ_NONE) + synchronize_irq(port->irq); /* * Free the transmit buffer page. @@ -1970,7 +1971,12 @@ printk("MMIO 0x%lx", port->mapbase); break; } - printk(" (irq = %d) is a %s\n", port->irq, uart_type(port)); + + if(port->irq == SERIAL_IRQ_NONE) { + printk(" (polling) is a %s\n", uart_type(port)); + } else { + printk(" (irq = %d) is a %s\n", port->irq, uart_type(port)); + } } static void diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/drivers/video/stifb.c linux-2.5/drivers/video/stifb.c --- ../prev/linux-2.5/drivers/video/stifb.c Fri May 2 04:05:17 2003 +++ linux-2.5/drivers/video/stifb.c Tue Apr 8 11:17:28 2003 @@ -66,6 +66,7 @@ #include #include /* for HP-UX compatibility */ +#include #include "sticore.h" diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/fs/binfmt_elf.c linux-2.5/fs/binfmt_elf.c --- ../prev/linux-2.5/fs/binfmt_elf.c Fri May 2 04:05:26 2003 +++ linux-2.5/fs/binfmt_elf.c Wed Apr 23 19:37:03 2003 @@ -113,7 +113,7 @@ #define STACK_ADD(sp, items) ((elf_addr_t *)(sp) + (items)) #define STACK_ROUND(sp, items) \ ((15 + (unsigned long) ((sp) + (items))) &~ 15UL) -#define STACK_ALLOC(sp, len) ({ elf_addr_t *old_sp = sp; sp += len; old_sp; }) +#define STACK_ALLOC(sp, len) ({ elf_addr_t *old_sp = (elf_addr_t *)sp; sp += len; old_sp; }) #else #define STACK_ADD(sp, items) ((elf_addr_t *)(sp) - (items)) #define STACK_ROUND(sp, items) \ diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/fs/exec.c linux-2.5/fs/exec.c --- ../prev/linux-2.5/fs/exec.c Fri May 2 04:05:27 2003 +++ linux-2.5/fs/exec.c Wed Apr 23 19:37:03 2003 @@ -56,7 +56,7 @@ int core_uses_pid; char core_pattern[65] = "core"; -/* The maximal length of core_pattern is also specified in sysctl.c */ +/* The maximal length of core_pattern is also specified in sysctl.c */ static struct linux_binfmt *formats; static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED; @@ -189,7 +189,7 @@ * memory to free pages in kernel mem. These are in a format ready * to be put directly into the top of new user memory. */ -int copy_strings(int argc,char __user * __user * argv, struct linux_binprm *bprm) +int copy_strings(int argc,char __user * __user * argv, struct linux_binprm *bprm) { struct page *kmapped_page = NULL; char *kaddr = NULL; @@ -212,7 +212,7 @@ } bprm->p -= len; - /* XXX: add architecture specific overflow check here. */ + /* XXX: add architecture specific overflow check here. */ pos = bprm->p; while (len > 0) { @@ -274,10 +274,10 @@ { int r; mm_segment_t oldfs = get_fs(); - set_fs(KERNEL_DS); + set_fs(KERNEL_DS); r = copy_strings(argc, (char __user * __user *)argv, bprm); set_fs(oldfs); - return r; + return r; } #ifdef CONFIG_MMU @@ -338,6 +338,7 @@ struct vm_area_struct *mpnt; struct mm_struct *mm = current->mm; int i; + long arg_size; #ifdef CONFIG_STACK_GROWSUP /* Move the argument and environment strings to the bottom of the @@ -370,8 +371,15 @@ /* Adjust bprm->p to point to the end of the strings. */ bprm->p = PAGE_SIZE * i - offset; - stack_base = STACK_TOP - current->rlim[RLIMIT_STACK].rlim_max; + + /* Limit stack size to 1GB */ + stack_base = current->rlim[RLIMIT_STACK].rlim_max; + if (stack_base > (1 << 30)) + stack_base = 1 << 30; + stack_base = PAGE_ALIGN(STACK_TOP - stack_base); + mm->arg_start = stack_base; + arg_size = i << PAGE_SHIFT; /* zero pages that were copied above */ while (i < MAX_ARG_PAGES) @@ -379,6 +387,7 @@ #else stack_base = STACK_TOP - MAX_ARG_PAGES * PAGE_SIZE; mm->arg_start = bprm->p + stack_base; + arg_size = STACK_TOP - (PAGE_MASK & (unsigned long) mm->arg_start); #endif bprm->p += stack_base; @@ -390,7 +399,7 @@ if (!mpnt) return -ENOMEM; - if (!vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { + if (!vm_enough_memory(arg_size >> PAGE_SHIFT)) { kmem_cache_free(vm_area_cachep, mpnt); return -ENOMEM; } @@ -415,7 +424,7 @@ mpnt->vm_private_data = (void *) 0; insert_vm_struct(mm, mpnt); mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; - } + } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { struct page *page = bprm->page[i]; @@ -817,7 +826,7 @@ /* An exec changes our domain. We are no longer part of the thread group */ - + current->self_exec_id++; flush_signal_handlers(current, 0); @@ -901,7 +910,7 @@ * */ -void compute_creds(struct linux_binprm *bprm) +void compute_creds(struct linux_binprm *bprm) { task_lock(current); if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) { @@ -1069,7 +1078,7 @@ return retval; bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); - memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); + memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); bprm.file = file; bprm.filename = filename; @@ -1099,21 +1108,21 @@ goto out; retval = prepare_binprm(&bprm); - if (retval < 0) - goto out; + if (retval < 0) + goto out; retval = copy_strings_kernel(1, &bprm.filename, &bprm); - if (retval < 0) - goto out; + if (retval < 0) + goto out; bprm.exec = bprm.p; retval = copy_strings(bprm.envc, envp, &bprm); - if (retval < 0) - goto out; + if (retval < 0) + goto out; retval = copy_strings(bprm.argc, argv, &bprm); - if (retval < 0) - goto out; + if (retval < 0) + goto out; retval = search_binary_handler(&bprm,regs); if (retval >= 0) { diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/fs/intermezzo/dir.c linux-2.5/fs/intermezzo/dir.c --- ../prev/linux-2.5/fs/intermezzo/dir.c Fri May 2 04:05:37 2003 +++ linux-2.5/fs/intermezzo/dir.c Mon Mar 24 20:19:27 2003 @@ -1303,10 +1303,6 @@ return rc; } - case TCGETS: - EXIT; - return -EINVAL; - default: EXIT; return -EINVAL; diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/asm-parisc/elf.h linux-2.5/include/asm-parisc/elf.h --- ../prev/linux-2.5/include/asm-parisc/elf.h Fri May 2 04:06:41 2003 +++ linux-2.5/include/asm-parisc/elf.h Fri Mar 28 09:47:21 2003 @@ -10,10 +10,11 @@ #define EM_PARISC 15 /* - * The following definitions are those for 32-bit ELF binaries on a 32-bit kernel - * and for 64-bit binaries on a 64-bit kernel. To run 32-bit binaries on a 64-bit - * kernel, arch/parisc64/kernel/binfmt_elf32.c defines these macros appropriately - * and then #includes binfmt_elf.c, which then includes this file. + * The following definitions are those for 32-bit ELF binaries on a 32-bit + * kernel and for 64-bit binaries on a 64-bit kernel. To run 32-bit binaries + * on a 64-bit kernel, arch/parisc64/kernel/binfmt_elf32.c defines these + * macros appropriately and then #includes binfmt_elf.c, which then includes + * this file. */ #ifndef ELF_CLASS @@ -98,6 +99,8 @@ #define ELF_NFPREG 32 typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +struct task_struct; extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/asm-parisc/pgtable.h linux-2.5/include/asm-parisc/pgtable.h --- ../prev/linux-2.5/include/asm-parisc/pgtable.h Fri May 2 04:06:41 2003 +++ linux-2.5/include/asm-parisc/pgtable.h Thu Mar 27 22:47:02 2003 @@ -122,6 +122,7 @@ #define _PAGE_GATEWAY_BIT 28 /* (0x008) privilege promotion allowed */ #define _PAGE_DMB_BIT 27 /* (0x010) Data Memory Break enable (B bit) */ #define _PAGE_DIRTY_BIT 26 /* (0x020) Page Dirty (D bit) */ +#define _PAGE_FILE_BIT _PAGE_DIRTY_BIT /* overload this bit */ #define _PAGE_REFTRAP_BIT 25 /* (0x040) Page Ref. Trap enable (T bit) */ #define _PAGE_NO_CACHE_BIT 24 /* (0x080) Uncached Page (U bit) */ #define _PAGE_ACCESSED_BIT 23 /* (0x100) Software: Page Accessed */ @@ -135,6 +136,17 @@ #define xlate_pabit(x) (31 - x) +/* this defines the shift to the usable bits in the PTE it is set so + * that the valid bits _PAGE_PRESENT_BIT and _PAGE_USER_BIT are set + * to zero */ +#define PTE_SHIFT xlate_pabit(_PAGE_USER_BIT) + +/* this is how many bits may be used by the file functions */ +#define PTE_FILE_MAX_BITS (BITS_PER_LONG - PTE_SHIFT) + +#define pte_to_pgoff(pte) (pte_val(pte) >> PTE_SHIFT) +#define pgoff_to_pte(off) ((pte_t) { ((off) << PTE_SHIFT) | _PAGE_FILE }) + #define _PAGE_READ (1 << xlate_pabit(_PAGE_READ_BIT)) #define _PAGE_WRITE (1 << xlate_pabit(_PAGE_WRITE_BIT)) #define _PAGE_RW (_PAGE_READ | _PAGE_WRITE) @@ -148,6 +160,7 @@ #define _PAGE_PRESENT (1 << xlate_pabit(_PAGE_PRESENT_BIT)) #define _PAGE_FLUSH (1 << xlate_pabit(_PAGE_FLUSH_BIT)) #define _PAGE_USER (1 << xlate_pabit(_PAGE_USER_BIT)) +#define _PAGE_FILE (1 << xlate_pabit(_PAGE_FILE_BIT)) #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED) #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) @@ -256,6 +269,7 @@ extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } +extern inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_READ; return pte; } extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; } diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/asm-parisc/processor.h linux-2.5/include/asm-parisc/processor.h --- ../prev/linux-2.5/include/asm-parisc/processor.h Fri May 2 04:06:41 2003 +++ linux-2.5/include/asm-parisc/processor.h Sun Mar 23 13:14:52 2003 @@ -92,6 +92,7 @@ unsigned long fp_model; unsigned int state; struct parisc_device *dev; + unsigned long loops_per_jiffy; }; extern struct system_cpuinfo_parisc boot_cpu_data; diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/asm-parisc/rtc.h linux-2.5/include/asm-parisc/rtc.h --- ../prev/linux-2.5/include/asm-parisc/rtc.h Fri May 2 04:06:41 2003 +++ linux-2.5/include/asm-parisc/rtc.h Wed Apr 23 19:37:35 2003 @@ -27,6 +27,7 @@ #define RTC_BATT_BAD 0x100 /* battery bad */ /* some dummy definitions */ +#define RTC_BATT_BAD 0x100 /* battery bad */ #define RTC_SQWE 0x08 /* enable square-wave output */ #define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */ #define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/linux/console.h linux-2.5/include/linux/console.h --- ../prev/linux-2.5/include/linux/console.h Fri May 2 04:06:55 2003 +++ linux-2.5/include/linux/console.h Tue Dec 10 15:03:21 2002 @@ -91,6 +91,7 @@ #define CON_PRINTBUFFER (1) #define CON_CONSDEV (2) /* Last on the command line */ #define CON_ENABLED (4) +#define CON_BOOT (8) struct console { diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/linux/hil.h linux-2.5/include/linux/hil.h --- ../prev/linux-2.5/include/linux/hil.h Wed Dec 31 17:00:00 1969 +++ linux-2.5/include/linux/hil.h Wed Nov 6 21:04:36 2002 @@ -0,0 +1,405 @@ +/* + * Hewlett Packard Human Interface Loop (HP-HIL) Protocol -- header. + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A + * + * A note of thanks to HP for providing and shipping reference materials + * free of charge to help in the development of HIL support for Linux. + * + */ + +#include + +/* Physical constants relevant to raw loop/device timing. + */ + +#define HIL_CLOCK 8MHZ +#define HIL_EK1_CLOCK 30HZ +#define HIL_EK2_CLOCK 60HZ + +#define HIL_TIMEOUT_DEV 5 /* ms */ +#define HIL_TIMEOUT_DEVS 10 /* ms */ +#define HIL_TIMEOUT_NORESP 10 /* ms */ +#define HIL_TIMEOUT_DEVS_DATA 16 /* ms */ +#define HIL_TIMEOUT_SELFTEST 200 /* ms */ + + +/* Actual wire line coding. These will only be useful if someone is + * implementing a software MLC to run HIL devices on a non-parisc machine. + */ + +#define HIL_WIRE_PACKET_LEN 15 +enum hil_wire_bitpos { + HIL_WIRE_START = 0, + HIL_WIRE_ADDR2, + HIL_WIRE_ADDR1, + HIL_WIRE_ADDR0, + HIL_WIRE_COMMAND, + HIL_WIRE_DATA7, + HIL_WIRE_DATA6, + HIL_WIRE_DATA5, + HIL_WIRE_DATA4, + HIL_WIRE_DATA3, + HIL_WIRE_DATA2, + HIL_WIRE_DATA1, + HIL_WIRE_DATA0, + HIL_WIRE_PARITY, + HIL_WIRE_STOP +}; + +/* HP documentation uses these bit positions to refer to commands; + * we will call these "packets". + */ +enum hil_pkt_bitpos { + HIL_PKT_CMD = 0x00000800, + HIL_PKT_ADDR2 = 0x00000400, + HIL_PKT_ADDR1 = 0x00000200, + HIL_PKT_ADDR0 = 0x00000100, + HIL_PKT_ADDR_MASK = 0x00000700, + HIL_PKT_ADDR_SHIFT = 8, + HIL_PKT_DATA7 = 0x00000080, + HIL_PKT_DATA6 = 0x00000040, + HIL_PKT_DATA5 = 0x00000020, + HIL_PKT_DATA4 = 0x00000010, + HIL_PKT_DATA3 = 0x00000008, + HIL_PKT_DATA2 = 0x00000004, + HIL_PKT_DATA1 = 0x00000002, + HIL_PKT_DATA0 = 0x00000001, + HIL_PKT_DATA_MASK = 0x000000FF, + HIL_PKT_DATA_SHIFT = 0 +}; + +/* The HIL MLC also has several error/status/control bits. We extend the + * "packet" to include these when direct access to the MLC is available, + * or emulate them in cases where they are not available. + * + * This way the device driver knows that the underlying MLC driver + * has had to deal with loop errors. + */ +enum hil_error_bitpos { + HIL_ERR_OB = 0x00000800, /* MLC is busy sending an auto-poll, + or we have filled up the output + buffer and must wait. */ + HIL_ERR_INT = 0x00010000, /* A normal interrupt has occurred. */ + HIL_ERR_NMI = 0x00020000, /* An NMI has occurred. */ + HIL_ERR_LERR = 0x00040000, /* A poll didn't come back. */ + HIL_ERR_PERR = 0x01000000, /* There was a Parity Error. */ + HIL_ERR_FERR = 0x02000000, /* There was a Framing Error. */ + HIL_ERR_FOF = 0x04000000 /* Input FIFO Overflowed. */ +}; + +enum hil_control_bitpos { + HIL_CTRL_TEST = 0x00010000, + HIL_CTRL_IPF = 0x00040000, + HIL_CTRL_APE = 0x02000000 +}; + +/* Bits 30,31 are unused, we use them to control write behavior. */ +#define HIL_DO_ALTER_CTRL 0x40000000 /* Write MSW of packet to control + before writing LSW to loop */ +#define HIL_CTRL_ONLY 0xc0000000 /* *Only* alter the control registers */ + +/* This gives us a 32-bit "packet" + */ +typedef u32 hil_packet; + + +/* HIL Loop commands + */ +enum hil_command { + HIL_CMD_IFC = 0x00, /* Interface Clear */ + HIL_CMD_EPT = 0x01, /* Enter Pass-Thru Mode */ + HIL_CMD_ELB = 0x02, /* Enter Loop-Back Mode */ + HIL_CMD_IDD = 0x03, /* Identify and Describe */ + HIL_CMD_DSR = 0x04, /* Device Soft Reset */ + HIL_CMD_PST = 0x05, /* Perform Self Test */ + HIL_CMD_RRG = 0x06, /* Read Register */ + HIL_CMD_WRG = 0x07, /* Write Register */ + HIL_CMD_ACF = 0x08, /* Auto Configure */ + HIL_CMDID_ACF = 0x07, /* Auto Configure bits with incremented ID */ + HIL_CMD_POL = 0x10, /* Poll */ + HIL_CMDCT_POL = 0x0f, /* Poll command bits with item count */ + HIL_CMD_RPL = 0x20, /* RePoll */ + HIL_CMDCT_RPL = 0x0f, /* RePoll command bits with item count */ + HIL_CMD_RNM = 0x30, /* Report Name */ + HIL_CMD_RST = 0x31, /* Report Status */ + HIL_CMD_EXD = 0x32, /* Extended Describe */ + HIL_CMD_RSC = 0x33, /* Report Security Code */ + + /* 0x34 to 0x3c reserved for future use */ + + HIL_CMD_DKA = 0x3d, /* Disable Keyswitch Autorepeat */ + HIL_CMD_EK1 = 0x3e, /* Enable Keyswitch Autorepeat 1 */ + HIL_CMD_EK2 = 0x3f, /* Enable Keyswitch Autorepeat 2 */ + HIL_CMD_PR1 = 0x40, /* Prompt1 */ + HIL_CMD_PR2 = 0x41, /* Prompt2 */ + HIL_CMD_PR3 = 0x42, /* Prompt3 */ + HIL_CMD_PR4 = 0x43, /* Prompt4 */ + HIL_CMD_PR5 = 0x44, /* Prompt5 */ + HIL_CMD_PR6 = 0x45, /* Prompt6 */ + HIL_CMD_PR7 = 0x46, /* Prompt7 */ + HIL_CMD_PRM = 0x47, /* Prompt (General Purpose) */ + HIL_CMD_AK1 = 0x48, /* Acknowlege1 */ + HIL_CMD_AK2 = 0x49, /* Acknowlege2 */ + HIL_CMD_AK3 = 0x4a, /* Acknowlege3 */ + HIL_CMD_AK4 = 0x4b, /* Acknowlege4 */ + HIL_CMD_AK5 = 0x4c, /* Acknowlege5 */ + HIL_CMD_AK6 = 0x4d, /* Acknowlege6 */ + HIL_CMD_AK7 = 0x4e, /* Acknowlege7 */ + HIL_CMD_ACK = 0x4f, /* Acknowlege (General Purpose) */ + + /* 0x50 to 0x78 reserved for future use */ + /* 0x80 to 0xEF device-specific commands */ + /* 0xf0 to 0xf9 reserved for future use */ + + HIL_CMD_RIO = 0xfa, /* Register I/O Error */ + HIL_CMD_SHR = 0xfb, /* System Hard Reset */ + HIL_CMD_TER = 0xfc, /* Transmission Error */ + HIL_CMD_CAE = 0xfd, /* Configuration Address Error */ + HIL_CMD_DHR = 0xfe, /* Device Hard Reset */ + + /* 0xff is prohibited from use. */ +}; + + +/* + * Response "records" to HIL commands + */ + +/* Device ID byte + */ +#define HIL_IDD_DID_TYPE_MASK 0xe0 /* Primary type bits */ +#define HIL_IDD_DID_TYPE_KB_INTEGRAL 0xa0 /* Integral keyboard */ +#define HIL_IDD_DID_TYPE_KB_ITF 0xc0 /* ITD keyboard */ +#define HIL_IDD_DID_TYPE_KB_RSVD 0xe0 /* Reserved keyboard type */ +#define HIL_IDD_DID_TYPE_KB_LANG_MASK 0x1f /* Keyboard locale bits */ +#define HIL_IDD_DID_KBLANG_USE_ESD 0x00 /* Use ESD Locale instead */ +#define HIL_IDD_DID_TYPE_ABS 0x80 /* Absolute Positioners */ +#define HIL_IDD_DID_ABS_RSVD1_MASK 0xf8 /* Reserved */ +#define HIL_IDD_DID_ABS_RSVD1 0x98 +#define HIL_IDD_DID_ABS_TABLET_MASK 0xf8 /* Tablets and digitizers */ +#define HIL_IDD_DID_ABS_TABLET 0x90 +#define HIL_IDD_DID_ABS_TSCREEN_MASK 0xfc /* Touch screens */ +#define HIL_IDD_DID_ABS_TSCREEN 0x8c +#define HIL_IDD_DID_ABS_RSVD2_MASK 0xfc /* Reserved */ +#define HIL_IDD_DID_ABS_RSVD2 0x88 +#define HIL_IDD_DID_ABS_RSVD3_MASK 0xfc /* Reserved */ +#define HIL_IDD_DID_ABS_RSVD3 0x80 +#define HIL_IDD_DID_TYPE_REL 0x60 /* Relative Positioners */ +#define HIL_IDD_DID_REL_RSVD1_MASK 0xf0 /* Reserved */ +#define HIL_IDD_DID_REL_RSVD1 0x70 +#define HIL_IDD_DID_REL_RSVD2_MASK 0xfc /* Reserved */ +#define HIL_IDD_DID_REL_RSVD2 0x6c +#define HIL_IDD_DID_REL_MOUSE_MASK 0xfc /* Mouse */ +#define HIL_IDD_DID_REL_MOUSE 0x68 +#define HIL_IDD_DID_REL_QUAD_MASK 0xf8 /* Other Quadrature Devices */ +#define HIL_IDD_DID_REL_QUAD 0x60 +#define HIL_IDD_DID_TYPE_CHAR 0x40 /* Character Entry */ +#define HIL_IDD_DID_CHAR_BARCODE_MASK 0xfc /* Barcode Reader */ +#define HIL_IDD_DID_CHAR_BARCODE 0x5c +#define HIL_IDD_DID_CHAR_RSVD1_MASK 0xfc /* Reserved */ +#define HIL_IDD_DID_CHAR_RSVD1 0x58 +#define HIL_IDD_DID_CHAR_RSVD2_MASK 0xf8 /* Reserved */ +#define HIL_IDD_DID_CHAR_RSVD2 0x50 +#define HIL_IDD_DID_CHAR_RSVD3_MASK 0xf0 /* Reserved */ +#define HIL_IDD_DID_CHAR_RSVD3 0x40 +#define HIL_IDD_DID_TYPE_OTHER 0x20 /* Miscellaneous */ +#define HIL_IDD_DID_OTHER_RSVD1_MASK 0xf0 /* Reserved */ +#define HIL_IDD_DID_OTHER_RSVD1 0x30 +#define HIL_IDD_DID_OTHER_BARCODE_MASK 0xfc /* Tone Generator */ +#define HIL_IDD_DID_OTHER_BARCODE 0x2c +#define HIL_IDD_DID_OTHER_RSVD2_MASK 0xfc /* Reserved */ +#define HIL_IDD_DID_OTHER_RSVD2 0x28 +#define HIL_IDD_DID_OTHER_RSVD3_MASK 0xf8 /* Reserved */ +#define HIL_IDD_DID_OTHER_RSVD3 0x20 +#define HIL_IDD_DID_TYPE_KEYPAD 0x00 /* Vectra Keyboard */ + +/* IDD record header + */ +#define HIL_IDD_HEADER_AXSET_MASK 0x03 /* Number of axis in a set */ +#define HIL_IDD_HEADER_RSC 0x04 /* Supports RSC command */ +#define HIL_IDD_HEADER_EXD 0x08 /* Supports EXD command */ +#define HIL_IDD_HEADER_IOD 0x10 /* IOD byte to follow */ +#define HIL_IDD_HEADER_16BIT 0x20 /* 16 (vs. 8) bit resolution */ +#define HIL_IDD_HEADER_ABS 0x40 /* Reports Absolute Position */ +#define HIL_IDD_HEADER_2X_AXIS 0x80 /* Two sets of 1-3 axis */ + +/* I/O Descriptor + */ +#define HIL_IDD_IOD_NBUTTON_MASK 0x07 /* Number of buttons */ +#define HIL_IDD_IOD_PROXIMITY 0x08 /* Proximity in/out events */ +#define HIL_IDD_IOD_PROMPT_MASK 0x70 /* Number of prompts/acks */ +#define HIL_IDD_IOD_PROMPT_SHIFT 4 +#define HIL_IDD_IOD_PROMPT 0x80 /* Generic prompt/ack */ + +#define HIL_IDD_NUM_AXES_PER_SET(header_packet) \ +((header_packet) & HIL_IDD_HEADER_AXSET_MASK) + +#define HIL_IDD_NUM_AXSETS(header_packet) \ +(2 - !((header_packet) & HIL_IDD_HEADER_2X_AXIS)) + +#define HIL_IDD_LEN(header_packet) \ +((4 - !(header_packet & HIL_IDD_HEADER_IOD) - \ + 2 * !(HIL_IDD_NUM_AXES_PER_SET(header_packet))) + \ + 2 * HIL_IDD_NUM_AXES_PER_SET(header_packet) * \ + !!((header_packet) & HIL_IDD_HEADER_ABS)) + +/* The following HIL_IDD_* macros assume you have an array of + * packets and/or unpacked 8-bit data in the order that they + * were received. + */ + +#define HIL_IDD_AXIS_COUNTS_PER_M(header_ptr) \ +(!(HIL_IDD_NUM_AXSETS(*(header_ptr))) ? -1 : \ +(((*(header_ptr + 1) & HIL_PKT_DATA_MASK) + \ + ((*(header_ptr + 2) & HIL_PKT_DATA_MASK)) << 8) \ +* ((*(header_ptr) & HIL_IDD_HEADER_16BIT) ? 100 : 1))) + +#define HIL_IDD_AXIS_MAX(header_ptr, __axnum) \ +((!(*(header_ptr) & HIL_IDD_HEADER_ABS) || \ + (HIL_IDD_NUM_AXES_PER_SET(*(header_ptr)) <= __axnum)) ? 0 : \ + ((HIL_PKT_DATA_MASK & *((header_ptr) + 3 + 2 * __axnum)) + \ + ((HIL_PKT_DATA_MASK & *((header_ptr) + 4 + 2 * __axnum)) << 8))) + +#define HIL_IDD_IOD(header_ptr) \ +(*(header_ptr + HIL_IDD_LEN((*header_ptr)) - 1)) + +#define HIL_IDD_HAS_GEN_PROMPT(header_ptr) \ +((*header_ptr & HIL_IDD_HEADER_IOD) && \ + (HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_PROMPT)) + +#define HIL_IDD_HAS_GEN_PROXIMITY(header_ptr) \ +((*header_ptr & HIL_IDD_HEADER_IOD) && \ + (HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_PROXIMITY)) + +#define HIL_IDD_NUM_BUTTONS(header_ptr) \ +((*header_ptr & HIL_IDD_HEADER_IOD) ? \ + (HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_NBUTTON_MASK) : 0) + +#define HIL_IDD_NUM_PROMPTS(header_ptr) \ +((*header_ptr & HIL_IDD_HEADER_IOD) ? \ + ((HIL_IDD_IOD(header_ptr) & HIL_IDD_IOD_NPROMPT_MASK) \ + >> HIL_IDD_IOD_PROMPT_SHIFT) : 0) + +/* The response to HIL EXD commands -- the "extended describe record" */ +#define HIL_EXD_HEADER_WRG 0x03 /* Supports type2 WRG */ +#define HIL_EXD_HEADER_WRG_TYPE1 0x01 /* Supports type1 WRG */ +#define HIL_EXD_HEADER_WRG_TYPE2 0x02 /* Supports type2 WRG */ +#define HIL_EXD_HEADER_RRG 0x04 /* Supports RRG command */ +#define HIL_EXD_HEADER_RNM 0x10 /* Supports RNM command */ +#define HIL_EXD_HEADER_RST 0x20 /* Supports RST command */ +#define HIL_EXD_HEADER_LOCALE 0x40 /* Contains locale code */ + +#define HIL_EXD_NUM_RRG(header_ptr) \ +((*header_ptr & HIL_EXD_HEADER_RRG) ? \ + (*(header_ptr + 1) & HIL_PKT_DATA_MASK) : 0) + +#define HIL_EXD_NUM_WWG(header_ptr) \ +((*header_ptr & HIL_EXD_HEADER_WRG) ? \ + (*(header_ptr + 2 - !(*header_ptr & HIL_EXD_HEADER_RRG)) & \ + HIL_PKT_DATA_MASK) : 0) + +#define HIL_EXD_LEN(header_ptr) \ +(!!(*header_ptr & HIL_EXD_HEADER_RRG) + \ + !!(*header_ptr & HIL_EXD_HEADER_WRG) + \ + !!(*header_ptr & HIL_EXD_HEADER_LOCALE) + \ + 2 * !!(*header_ptr & HIL_EXD_HEADER_WRG_TYPE2) + 1) + +#define HIL_EXD_LOCALE(header_ptr) \ +(!(*header_ptr & HIL_EXD_HEADER_LOCALE) ? -1 : \ + (*(header_ptr + HIL_EXD_LEN(header_ptr) - 1) & HIL_PKT_DATA_MASK)) + +#define HIL_EXD_WRG_TYPE2_LEN(header_ptr) \ +(!(*header_ptr & HIL_EXD_HEADER_WRG_TYPE2) ? -1 : \ + (*(header_ptr + HIL_EXD_LEN(header_ptr) - 2 - \ + !!(*header_ptr & HIL_EXD_HEADER_LOCALE)) & HIL_PKT_DATA_MASK) + \ + ((*(header_ptr + HIL_EXD_LEN(header_ptr) - 1 - \ + !!(*header_ptr & HIL_EXD_HEADER_LOCALE)) & HIL_PKT_DATA_MASK) << 8)) + +/* Device locale codes. */ + +/* Last defined locale code. Everything above this is "Reserved", + and note that this same table applies to the Device ID Byte where + keyboards may have a nationality code which is only 5 bits. */ +#define HIL_LOCALE_MAX 0x1f + +/* Map to hopefully useful strings. I was trying to make these look + like locale.aliases strings do; maybe that isn't the right table to + emulate. In either case, I didn't have much to work on. */ +#define HIL_LOCALE_MAP \ +"", /* 0x00 Reserved */ \ +"", /* 0x01 Reserved */ \ +"", /* 0x02 Reserved */ \ +"swiss.french", /* 0x03 Swiss/French */ \ +"portuguese", /* 0x04 Portuguese */ \ +"arabic", /* 0x05 Arabic */ \ +"hebrew", /* 0x06 Hebrew */ \ +"english.canadian", /* 0x07 Canadian English */ \ +"turkish", /* 0x08 Turkish */ \ +"greek", /* 0x09 Greek */ \ +"thai", /* 0x0a Thai (Thailand) */ \ +"italian", /* 0x0b Italian */ \ +"korean", /* 0x0c Hangul (Korea) */ \ +"dutch", /* 0x0d Dutch */ \ +"swedish", /* 0x0e Swedish */ \ +"german", /* 0x0f German */ \ +"chinese", /* 0x10 Chinese-PRC */ \ +"chinese", /* 0x11 Chinese-ROC */ \ +"swiss.french", /* 0x12 Swiss/French II */ \ +"spanish", /* 0x13 Spanish */ \ +"swiss.german", /* 0x14 Swiss/German II */ \ +"flemish", /* 0x15 Belgian (Flemish) */ \ +"finnish", /* 0x16 Finnish */ \ +"english.uk", /* 0x17 United Kingdom */ \ +"french.canadian", /* 0x18 French/Canadian */ \ +"swiss.german", /* 0x19 Swiss/German */ \ +"norwegian", /* 0x1a Norwegian */ \ +"french", /* 0x1b French */ \ +"danish", /* 0x1c Danish */ \ +"japanese", /* 0x1d Katakana */ \ +"spanish", /* 0x1e Latin American/Spanish*/\ +"english.us" /* 0x1f United States */ \ + + +/* Response to POL command, the "poll record header" */ + +#define HIL_POL_NUM_AXES_MASK 0x03 /* Number of axis reported */ +#define HIL_POL_CTS 0x04 /* Device ready to receive data */ +#define HIL_POL_STATUS_PENDING 0x08 /* Device has status to report */ +#define HIL_POL_CHARTYPE_MASK 0x70 /* Type of character data to follow */ +#define HIL_POL_CHARTYPE_NONE 0x00 /* No character data to follow */ +#define HIL_POL_CHARTYPE_RSVD1 0x10 /* Reserved Set 1 */ +#define HIL_POL_CHARTYPE_ASCII 0x20 /* U.S. ASCII */ +#define HIL_POL_CHARTYPE_BINARY 0x30 /* Binary data */ +#define HIL_POL_CHARTYPE_SET1 0x40 /* Keycode Set 1 */ +#define HIL_POL_CHARTYPE_RSVD2 0x50 /* Reserved Set 2 */ +#define HIL_POL_CHARTYPE_SET2 0x60 /* Keycode Set 2 */ +#define HIL_POL_CHARTYPE_SET3 0x70 /* Keycode Set 3 */ +#define HIL_POL_AXIS_ALT 0x80 /* Data is from axis set 2 */ + diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/linux/hil_mlc.h linux-2.5/include/linux/hil_mlc.h --- ../prev/linux-2.5/include/linux/hil_mlc.h Wed Dec 31 17:00:00 1969 +++ linux-2.5/include/linux/hil_mlc.h Wed Nov 6 21:04:36 2002 @@ -0,0 +1,171 @@ +/* + * HP Human Interface Loop Master Link Controller driver. + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A + * + */ + +#include +#include +#include +#include +#include +#include + +typedef struct hil_mlc hil_mlc; + +/* The HIL has a complicated state engine. + * We define the structure of nodes in the state engine here. + */ +enum hilse_act { + /* HILSE_OUT prepares to receive input if the next node + * is an IN or EXPECT, and then sends the given packet. + */ + HILSE_OUT = 0, + + /* HILSE_CTS checks if the loop is busy. */ + HILSE_CTS, + + /* HILSE_OUT_LAST sends the given command packet to + * the last configured/running device on the loop. + */ + HILSE_OUT_LAST, + + /* HILSE_OUT_DISC sends the given command packet to + * the next device past the last configured/running one. + */ + HILSE_OUT_DISC, + + /* HILSE_FUNC runs a callback function with given arguments. + * a positive return value causes the "ugly" branch to be taken. + */ + HILSE_FUNC, + + /* HILSE_IN simply expects any non-errored packet to arrive + * within arg usecs. + */ + HILSE_IN = 0x100, + + /* HILSE_EXPECT expects a particular packet to arrive + * within arg usecs, any other packet is considered an error. + */ + HILSE_EXPECT, + + /* HILSE_EXPECT_LAST as above but dev field should be last + * discovered/operational device. + */ + HILSE_EXPECT_LAST, + + /* HILSE_EXPECT_LAST as above but dev field should be first + * undiscovered/inoperational device. + */ + HILSE_EXPECT_DISC +}; + +typedef int (hilse_func) (hil_mlc *mlc, int arg); +struct hilse_node { + enum hilse_act act; /* How to process this node */ + union { + hilse_func *func; /* Function to call if HILSE_FUNC */ + hil_packet packet; /* Packet to send or to compare */ + } object; + int arg; /* Timeout in usec or parm for func */ + int good; /* Node to jump to on success */ + int bad; /* Node to jump to on error */ + int ugly; /* Node to jump to on timeout */ +}; + +/* Methods for back-end drivers, e.g. hp_sdc_mlc */ +typedef int (hil_mlc_cts) (hil_mlc *mlc); +typedef void (hil_mlc_out) (hil_mlc *mlc); +typedef int (hil_mlc_in) (hil_mlc *mlc, suseconds_t timeout); + +struct hil_mlc_devinfo { + uint8_t idd[16]; /* Device ID Byte and Describe Record */ + uint8_t rsc[16]; /* Security Code Header and Record */ + uint8_t exd[16]; /* Extended Describe Record */ + uint8_t rnm[16]; /* Device name as returned by RNM command */ +}; + +struct hil_mlc_serio_map { + hil_mlc *mlc; + int di_revmap; + int didx; +}; + +/* How many (possibly old/detached) devices the we try to keep track of */ +#define HIL_MLC_DEVMEM 16 + +struct hil_mlc { + struct list_head list; /* hil_mlc is organized as linked list */ + + rwlock_t lock; + + void *priv; /* Data specific to a particular type of MLC */ + + int seidx; /* Current node in state engine */ + int istarted, ostarted; + + hil_mlc_cts *cts; + struct semaphore csem; /* Raised when loop idle */ + + hil_mlc_out *out; + struct semaphore osem; /* Raised when outpacket dispatched */ + hil_packet opacket; + + hil_mlc_in *in; + struct semaphore isem; /* Raised when a packet arrives */ + hil_packet ipacket[16]; + hil_packet imatch; + int icount; + struct timeval instart; + suseconds_t intimeout; + + int ddi; /* Last operational device id */ + int lcv; /* LCV to throttle loops */ + struct timeval lcv_tv; /* Time loop was started */ + + int di_map[7]; /* Maps below items to live devs */ + struct hil_mlc_devinfo di[HIL_MLC_DEVMEM]; + struct serio serio[HIL_MLC_DEVMEM]; + struct hil_mlc_serio_map serio_map[HIL_MLC_DEVMEM]; + hil_packet serio_opacket[HIL_MLC_DEVMEM]; + int serio_oidx[HIL_MLC_DEVMEM]; + struct hil_mlc_devinfo di_scratch; /* Temporary area */ + + void (*inc_use_count)(void); + void (*dec_use_count)(void); + + int opercnt; + + struct tasklet_struct *tasklet; +}; + +int hil_mlc_register(hil_mlc *mlc); +int hil_mlc_unregister(hil_mlc *mlc); diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/linux/hp_sdc.h linux-2.5/include/linux/hp_sdc.h --- ../prev/linux-2.5/include/linux/hp_sdc.h Wed Dec 31 17:00:00 1969 +++ linux-2.5/include/linux/hp_sdc.h Wed Nov 6 21:04:36 2002 @@ -0,0 +1,296 @@ +/* + * HP i8042 System Device Controller -- header + * + * Copyright (c) 2001 Brian S. Julin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * References: + * + * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A + * + * System Device Controller Microprocessor Firmware Theory of Operation + * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 + * + */ + +#ifndef _LINUX_HP_SDC_H +#define _LINUX_HP_SDC_H + +#include +#include +#include +#include +#include + + +/* No 4X status reads take longer than this (in usec). + */ +#define HP_SDC_MAX_REG_DELAY 20000 + +typedef void (hp_sdc_irqhook) (int irq, void *dev_id, + uint8_t status, uint8_t data); + +int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback); +int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback); +int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback); +int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback); +int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback); +int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback); + +typedef struct { + int actidx; /* Start of act. Acts are atomic WRT I/O to SDC */ + int idx; /* Index within the act */ + int endidx; /* transaction is over and done if idx == endidx */ + uint8_t *seq; /* commands/data for the transaction */ + union { + hp_sdc_irqhook *irqhook; /* Callback, isr or tasklet context */ + struct semaphore *semaphore; /* Semaphore to sleep on. */ + } act; +} hp_sdc_transaction; +int hp_sdc_enqueue_transaction(hp_sdc_transaction *this); +int hp_sdc_dequeue_transaction(hp_sdc_transaction *this); + +/* The HP_SDC_ACT* values are peculiar to this driver. + * Nuance: never HP_SDC_ACT_DATAIN | HP_SDC_ACT_DEALLOC, use another + * act to perform the dealloc. + */ +#define HP_SDC_ACT_PRECMD 0x01 /* Send a command first */ +#define HP_SDC_ACT_DATAREG 0x02 /* Set data registers */ +#define HP_SDC_ACT_DATAOUT 0x04 /* Send data bytes */ +#define HP_SDC_ACT_POSTCMD 0x08 /* Send command after */ +#define HP_SDC_ACT_DATAIN 0x10 /* Collect data after */ +#define HP_SDC_ACT_DURING 0x1f +#define HP_SDC_ACT_SEMAPHORE 0x20 /* Raise semaphore after */ +#define HP_SDC_ACT_CALLBACK 0x40 /* Pass data to IRQ handler */ +#define HP_SDC_ACT_DEALLOC 0x80 /* Destroy transaction after */ +#define HP_SDC_ACT_AFTER 0xe0 +#define HP_SDC_ACT_DEAD 0x60 /* Act timed out. */ + +/* Rest of the flags are straightforward representation of the SDC interface */ +#define HP_SDC_STATUS_IBF 0x02 /* Input buffer full */ + +#define HP_SDC_STATUS_IRQMASK 0xf0 /* Bits containing "level 1" irq */ +#define HP_SDC_STATUS_PERIODIC 0x10 /* Periodic 10ms timer */ +#define HP_SDC_STATUS_USERTIMER 0x20 /* "Special purpose" timer */ +#define HP_SDC_STATUS_TIMER 0x30 /* Both PERIODIC and USERTIMER */ +#define HP_SDC_STATUS_REG 0x40 /* Data from an i8042 register */ +#define HP_SDC_STATUS_HILCMD 0x50 /* Command from HIL MLC */ +#define HP_SDC_STATUS_HILDATA 0x60 /* Data from HIL MLC */ +#define HP_SDC_STATUS_PUP 0x70 /* Sucessful power-up self test */ +#define HP_SDC_STATUS_KCOOKED 0x80 /* Key from cooked kbd */ +#define HP_SDC_STATUS_KRPG 0xc0 /* Key from Repeat Gen */ +#define HP_SDC_STATUS_KMOD_SUP 0x10 /* Shift key is up */ +#define HP_SDC_STATUS_KMOD_CUP 0x20 /* Control key is up */ + +#define HP_SDC_NMISTATUS_FHS 0x40 /* NMI is a fast handshake irq */ + +/* Internal i8042 registers (there are more, but they are not too useful). */ + +#define HP_SDC_USE 0x02 /* Resource usage (including OB bit) */ +#define HP_SDC_IM 0x04 /* Interrupt mask */ +#define HP_SDC_CFG 0x11 /* Configuration register */ +#define HP_SDC_KBLANGUAGE 0x12 /* Keyboard language */ + +#define HP_SDC_D0 0x70 /* General purpose data buffer 0 */ +#define HP_SDC_D1 0x71 /* General purpose data buffer 1 */ +#define HP_SDC_D2 0x72 /* General purpose data buffer 2 */ +#define HP_SDC_D3 0x73 /* General purpose data buffer 3 */ +#define HP_SDC_VT1 0x74 /* Timer for voice 1 */ +#define HP_SDC_VT2 0x75 /* Timer for voice 2 */ +#define HP_SDC_VT3 0x76 /* Timer for voice 3 */ +#define HP_SDC_VT4 0x77 /* Timer for voice 4 */ +#define HP_SDC_KBN 0x78 /* Which HIL devs are Nimitz */ +#define HP_SDC_KBC 0x79 /* Which HIL devs are cooked kbds */ +#define HP_SDC_LPS 0x7a /* i8042's view of HIL status */ +#define HP_SDC_LPC 0x7b /* i8042's view of HIL "control" */ +#define HP_SDC_RSV 0x7c /* Reserved "for testing" */ +#define HP_SDC_LPR 0x7d /* i8042 count of HIL reconfigs */ +#define HP_SDC_XTD 0x7e /* "Extended Configuration" register */ +#define HP_SDC_STR 0x7f /* i8042 self-test result */ + +/* Bitfields for above registers */ +#define HP_SDC_USE_LOOP 0x04 /* Command is currently on the loop. */ + +#define HP_SDC_IM_MASK 0x1f /* these bits not part of cmd/status */ +#define HP_SDC_IM_FH 0x10 /* Mask the fast handshake irq */ +#define HP_SDC_IM_PT 0x08 /* Mask the periodic timer irq */ +#define HP_SDC_IM_TIMERS 0x04 /* Mask the MT/DT/CT irq */ +#define HP_SDC_IM_RESET 0x02 /* Mask the reset key irq */ +#define HP_SDC_IM_HIL 0x01 /* Mask the HIL MLC irq */ + +#define HP_SDC_CFG_ROLLOVER 0x08 /* WTF is "N-key rollover"? */ +#define HP_SDC_CFG_KBD 0x10 /* There is a keyboard */ +#define HP_SDC_CFG_NEW 0x20 /* Supports/uses HIL MLC */ +#define HP_SDC_CFG_KBD_OLD 0x03 /* keyboard code for non-HIL */ +#define HP_SDC_CFG_KBD_NEW 0x07 /* keyboard code from HIL autoconfig */ +#define HP_SDC_CFG_REV 0x40 /* Code revision bit */ +#define HP_SDC_CFG_IDPROM 0x80 /* IDPROM present in kbd (not HIL) */ + +#define HP_SDC_LPS_NDEV 0x07 /* # devices autoconfigured on HIL */ +#define HP_SDC_LPS_ACSUCC 0x08 /* loop autoconfigured successfully */ +#define HP_SDC_LPS_ACFAIL 0x80 /* last loop autoconfigure failed */ + +#define HP_SDC_LPC_APE_IPF 0x01 /* HIL MLC APE/IPF (autopoll) set */ +#define HP_SDC_LPC_ARCONERR 0x02 /* i8042 autoreconfigs loop on err */ +#define HP_SDC_LPC_ARCQUIET 0x03 /* i8042 doesn't report autoreconfigs*/ +#define HP_SDC_LPC_COOK 0x10 /* i8042 cooks devices in _KBN */ +#define HP_SDC_LPC_RC 0x80 /* causes autoreconfig */ + +#define HP_SDC_XTD_REV 0x07 /* contains revision code */ +#define HP_SDC_XTD_REV_STRINGS(val, str) \ +switch (val) { \ + case 0x1: str = "1820-3712"; break; \ + case 0x2: str = "1820-4379"; break; \ + case 0x3: str = "1820-4784"; break; \ + default: str = "unknown"; \ +}; +#define HP_SDC_XTD_BEEPER 0x08 /* TI SN76494 beeper available */ +#define HP_SDC_XTD_BBRTC 0x20 /* OKI MSM-58321 BBRTC present */ + +#define HP_SDC_CMD_LOAD_RT 0x31 /* Load real time (from 8042) */ +#define HP_SDC_CMD_LOAD_FHS 0x36 /* Load the fast handshake timer */ +#define HP_SDC_CMD_LOAD_MT 0x38 /* Load the match timer */ +#define HP_SDC_CMD_LOAD_DT 0x3B /* Load the delay timer */ +#define HP_SDC_CMD_LOAD_CT 0x3E /* Load the cycle timer */ + +#define HP_SDC_CMD_SET_IM 0x40 /* 010xxxxx == set irq mask */ + +/* The documents provided do not explicitly state that all registers betweem + * 0x01 and 0x1f inclusive can be read by sending their register index as a + * command, but this is implied and appears to be the case. + */ +#define HP_SDC_CMD_READ_RAM 0x00 /* Load from i8042 RAM (autoinc) */ +#define HP_SDC_CMD_READ_USE 0x02 /* Undocumented! Load from usage reg */ +#define HP_SDC_CMD_READ_IM 0x04 /* Load current interrupt mask */ +#define HP_SDC_CMD_READ_KCC 0x11 /* Load primary kbd config code */ +#define HP_SDC_CMD_READ_KLC 0x12 /* Load primary kbd language code */ +#define HP_SDC_CMD_READ_T1 0x13 /* Load timer output buffer byte 1 */ +#define HP_SDC_CMD_READ_T2 0x14 /* Load timer output buffer byte 1 */ +#define HP_SDC_CMD_READ_T3 0x15 /* Load timer output buffer byte 1 */ +#define HP_SDC_CMD_READ_T4 0x16 /* Load timer output buffer byte 1 */ +#define HP_SDC_CMD_READ_T5 0x17 /* Load timer output buffer byte 1 */ +#define HP_SDC_CMD_READ_D0 0xf0 /* Load from i8042 RAM location 0x70 */ +#define HP_SDC_CMD_READ_D1 0xf1 /* Load from i8042 RAM location 0x71 */ +#define HP_SDC_CMD_READ_D2 0xf2 /* Load from i8042 RAM location 0x72 */ +#define HP_SDC_CMD_READ_D3 0xf3 /* Load from i8042 RAM location 0x73 */ +#define HP_SDC_CMD_READ_VT1 0xf4 /* Load from i8042 RAM location 0x74 */ +#define HP_SDC_CMD_READ_VT2 0xf5 /* Load from i8042 RAM location 0x75 */ +#define HP_SDC_CMD_READ_VT3 0xf6 /* Load from i8042 RAM location 0x76 */ +#define HP_SDC_CMD_READ_VT4 0xf7 /* Load from i8042 RAM location 0x77 */ +#define HP_SDC_CMD_READ_KBN 0xf8 /* Load from i8042 RAM location 0x78 */ +#define HP_SDC_CMD_READ_KBC 0xf9 /* Load from i8042 RAM location 0x79 */ +#define HP_SDC_CMD_READ_LPS 0xfa /* Load from i8042 RAM location 0x7a */ +#define HP_SDC_CMD_READ_LPC 0xfb /* Load from i8042 RAM location 0x7b */ +#define HP_SDC_CMD_READ_RSV 0xfc /* Load from i8042 RAM location 0x7c */ +#define HP_SDC_CMD_READ_LPR 0xfd /* Load from i8042 RAM location 0x7d */ +#define HP_SDC_CMD_READ_XTD 0xfe /* Load from i8042 RAM location 0x7e */ +#define HP_SDC_CMD_READ_STR 0xff /* Load from i8042 RAM location 0x7f */ + +#define HP_SDC_CMD_SET_ARD 0xA0 /* Set emulated autorepeat delay */ +#define HP_SDC_CMD_SET_ARR 0xA2 /* Set emulated autorepeat rate */ +#define HP_SDC_CMD_SET_BELL 0xA3 /* Set voice 3 params for "beep" cmd */ +#define HP_SDC_CMD_SET_RPGR 0xA6 /* Set "RPG" irq rate (doesn't work) */ +#define HP_SDC_CMD_SET_RTMS 0xAD /* Set the RTC time (milliseconds) */ +#define HP_SDC_CMD_SET_RTD 0xAF /* Set the RTC time (days) */ +#define HP_SDC_CMD_SET_FHS 0xB2 /* Set fast handshake timer */ +#define HP_SDC_CMD_SET_MT 0xB4 /* Set match timer */ +#define HP_SDC_CMD_SET_DT 0xB7 /* Set delay timer */ +#define HP_SDC_CMD_SET_CT 0xBA /* Set cycle timer */ +#define HP_SDC_CMD_SET_RAMP 0xC1 /* Reset READ_RAM autoinc counter */ +#define HP_SDC_CMD_SET_D0 0xe0 /* Load to i8042 RAM location 0x70 */ +#define HP_SDC_CMD_SET_D1 0xe1 /* Load to i8042 RAM location 0x71 */ +#define HP_SDC_CMD_SET_D2 0xe2 /* Load to i8042 RAM location 0x72 */ +#define HP_SDC_CMD_SET_D3 0xe3 /* Load to i8042 RAM location 0x73 */ +#define HP_SDC_CMD_SET_VT1 0xe4 /* Load to i8042 RAM location 0x74 */ +#define HP_SDC_CMD_SET_VT2 0xe5 /* Load to i8042 RAM location 0x75 */ +#define HP_SDC_CMD_SET_VT3 0xe6 /* Load to i8042 RAM location 0x76 */ +#define HP_SDC_CMD_SET_VT4 0xe7 /* Load to i8042 RAM location 0x77 */ +#define HP_SDC_CMD_SET_KBN 0xe8 /* Load to i8042 RAM location 0x78 */ +#define HP_SDC_CMD_SET_KBC 0xe9 /* Load to i8042 RAM location 0x79 */ +#define HP_SDC_CMD_SET_LPS 0xea /* Load to i8042 RAM location 0x7a */ +#define HP_SDC_CMD_SET_LPC 0xeb /* Load to i8042 RAM location 0x7b */ +#define HP_SDC_CMD_SET_RSV 0xec /* Load to i8042 RAM location 0x7c */ +#define HP_SDC_CMD_SET_LPR 0xed /* Load to i8042 RAM location 0x7d */ +#define HP_SDC_CMD_SET_XTD 0xee /* Load to i8042 RAM location 0x7e */ +#define HP_SDC_CMD_SET_STR 0xef /* Load to i8042 RAM location 0x7f */ + +#define HP_SDC_CMD_DO_RTCW 0xc2 /* i8042 RAM 0x70 --> RTC */ +#define HP_SDC_CMD_DO_RTCR 0xc3 /* RTC[0x70 0:3] --> irq/status/data */ +#define HP_SDC_CMD_DO_BEEP 0xc4 /* i8042 RAM 0x70-74 --> beeper,VT3 */ +#define HP_SDC_CMD_DO_HIL 0xc5 /* i8042 RAM 0x70-73 --> + HIL MLC R0,R1 i8042 HIL watchdog */ + +/* Values used to (de)mangle input/output to/from the HIL MLC */ +#define HP_SDC_DATA 0x40 /* Data from an 8042 register */ +#define HP_SDC_HIL_CMD 0x50 /* Data from HIL MLC R1/8042 */ +#define HP_SDC_HIL_R1MASK 0x0f /* Contents of HIL MLC R1 0:3 */ +#define HP_SDC_HIL_AUTO 0x10 /* Set if POL results from i8042 */ +#define HP_SDC_HIL_ISERR 0x80 /* Has meaning as in next 4 values */ +#define HP_SDC_HIL_RC_DONE 0x80 /* i8042 auto-configured loop */ +#define HP_SDC_HIL_ERR 0x81 /* HIL MLC R2 had a bit set */ +#define HP_SDC_HIL_TO 0x82 /* i8042 HIL watchdog expired */ +#define HP_SDC_HIL_RC 0x84 /* i8042 is auto-configuring loop */ +#define HP_SDC_HIL_DAT 0x60 /* Data from HIL MLC R0 */ + + +typedef struct { + rwlock_t ibf_lock; + rwlock_t lock; /* user/tasklet lock */ + rwlock_t rtq_lock; /* isr/tasklet lock */ + rwlock_t hook_lock; /* isr/user lock for handler add/del */ + + unsigned int irq, nmi; /* Our IRQ lines */ + unsigned long base_io, status_io, data_io; /* Our IO ports */ + + uint8_t im; /* Interrupt mask */ + int set_im; /* Interrupt mask needs to be set. */ + + int ibf; /* Last known status of IBF flag */ + uint8_t wi; /* current i8042 write index */ + uint8_t r7[4]; /* current i8042[0x70 - 0x74] values */ + uint8_t r11, r7e; /* Values from version/revision regs */ + + hp_sdc_irqhook *timer, *reg, *hil, *pup, *cooked; + +#define HP_SDC_QUEUE_LEN 16 + hp_sdc_transaction *tq[HP_SDC_QUEUE_LEN]; /* All pending read/writes */ + + int rcurr, rqty; /* Current read transact in process */ + struct timeval rtv; /* Time when current read started */ + int wcurr; /* Current write transact in process */ + +#ifdef __hppa__ + struct parisc_device *dev; + int dev_err; /* carries status from registration */ +#else +#error No support for device registration on this arch yet. +#endif + + struct timer_list kicker; /* Keeps below task alive */ + struct tasklet_struct task; + +} hp_i8042_sdc; + +#endif /* _LINUX_HP_SDC_H */ diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/linux/input.h linux-2.5/include/linux/input.h --- ../prev/linux-2.5/include/linux/input.h Fri May 2 04:06:59 2003 +++ linux-2.5/include/linux/input.h Fri Feb 14 20:48:58 2003 @@ -581,6 +581,7 @@ #define BUS_ADB 0x17 #define BUS_I2C 0x18 #define BUS_HOST 0x19 +#define BUS_GSC 0x1A /* * Values describing the status of an effect diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/linux/interrupt.h linux-2.5/include/linux/interrupt.h --- ../prev/linux-2.5/include/linux/interrupt.h Fri May 2 04:06:59 2003 +++ linux-2.5/include/linux/interrupt.h Wed Apr 23 19:37:52 2003 @@ -3,6 +3,7 @@ #define _LINUX_INTERRUPT_H #include +#include #include #include #include diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/linux/serial_core.h linux-2.5/include/linux/serial_core.h --- ../prev/linux-2.5/include/linux/serial_core.h Fri May 2 04:07:06 2003 +++ linux-2.5/include/linux/serial_core.h Mon Mar 24 20:20:19 2003 @@ -67,6 +67,11 @@ #define PORT_PC9861 45 #define PORT_PC9801_101 46 +/* Parisc type numbers. */ +#define PORT_MUX 47 + + +#define SERIAL_IRQ_NONE -1 #ifdef __KERNEL__ diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/include/linux/sysctl.h linux-2.5/include/linux/sysctl.h --- ../prev/linux-2.5/include/linux/sysctl.h Fri May 2 04:07:07 2003 +++ linux-2.5/include/linux/sysctl.h Wed Apr 23 19:37:58 2003 @@ -130,6 +130,8 @@ KERN_PIDMAX=55, /* int: PID # limit */ KERN_CORE_PATTERN=56, /* string: pattern for core-file names */ KERN_PANIC_ON_OOPS=57, /* int: whether we will panic on an oops */ + KERN_HPPA_PWRSW=58, /* int: hppa soft-power enable */ + KERN_HPPA_UNALIGNED=59, /* int: hppa unaligned-trap enable */ }; diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/kernel/printk.c linux-2.5/kernel/printk.c --- ../prev/linux-2.5/kernel/printk.c Fri May 2 04:07:16 2003 +++ linux-2.5/kernel/printk.c Wed Apr 23 19:38:04 2003 @@ -76,8 +76,8 @@ * must be masked before subscripting */ static unsigned long log_start; /* Index into log_buf: next char to be read by syslog() */ -static unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */ -static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */ +unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */ +unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */ static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */ struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; @@ -606,6 +606,11 @@ if (!(console->flags & CON_ENABLED)) return; + + if (console_drivers && (console_drivers->flags & CON_BOOT)) { + unregister_console(console_drivers); + console->flags &= ~CON_PRINTBUFFER; + } /* * Put this console in the list - keep the diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/kernel/resource.c linux-2.5/kernel/resource.c --- ../prev/linux-2.5/kernel/resource.c Fri May 2 04:07:16 2003 +++ linux-2.5/kernel/resource.c Thu Apr 24 06:28:14 2003 @@ -21,7 +21,7 @@ struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO }; -struct resource iomem_resource = { "PCI mem", 0x00000000, 0xffffffff, IORESOURCE_MEM }; +struct resource iomem_resource = { "PCI mem", 0UL, ~0UL, IORESOURCE_MEM }; static rwlock_t resource_lock = RW_LOCK_UNLOCKED; diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/kernel/sysctl.c linux-2.5/kernel/sysctl.c --- ../prev/linux-2.5/kernel/sysctl.c Fri May 2 04:07:16 2003 +++ linux-2.5/kernel/sysctl.c Wed Apr 23 19:38:05 2003 @@ -86,6 +86,11 @@ extern int stop_a_enabled; #endif +#ifdef __hppa__ +extern int pwrsw_enabled; +extern int unaligned_enabled; +#endif + #ifdef CONFIG_ARCH_S390 #ifdef CONFIG_MATHEMU extern int sysctl_ieee_emulation_warnings; @@ -190,6 +195,12 @@ {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command, 256, 0644, NULL, &proc_dostring, &sysctl_string }, {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int), + 0644, NULL, &proc_dointvec}, +#endif +#ifdef __hppa__ + {KERN_HPPA_PWRSW, "soft-power", &pwrsw_enabled, sizeof (int), + 0644, NULL, &proc_dointvec}, + {KERN_HPPA_UNALIGNED, "unaligned-trap", &unaligned_enabled, sizeof (int), 0644, NULL, &proc_dointvec}, #endif #if defined(CONFIG_PPC32) && defined(CONFIG_6xx) diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/net/core/wireless.c linux-2.5/net/core/wireless.c --- ../prev/linux-2.5/net/core/wireless.c Fri May 2 04:07:23 2003 +++ linux-2.5/net/core/wireless.c Wed Apr 23 19:38:07 2003 @@ -48,6 +48,7 @@ /***************************** INCLUDES *****************************/ #include /* Not needed ??? */ +#include /* __init */ #include /* off_t */ #include /* struct ifreq, dev_get_by_name() */ #include diff -urN --exclude-from=/tmp/dont5872.17299 ../prev/linux-2.5/net/ipv4/Kconfig linux-2.5/net/ipv4/Kconfig --- ../prev/linux-2.5/net/ipv4/Kconfig Fri May 2 04:07:25 2003 +++ linux-2.5/net/ipv4/Kconfig Wed Apr 23 19:38:08 2003 @@ -357,6 +357,7 @@ config INET_ESP tristate "IP: ESP transformation" + depends on CRYPTO ---help--- Support for IPsec ESP.