diff -urN --exclude-from=/tmp/dont11398.6320 ../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 Sun Mar 2 23:58:28 2003 @@ -0,0 +1,66 @@ +Status: +------- + - Merged to 2.5.63, boots on C360, 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) + + + 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/dont11398.6320 ../prev/linux-2.5/Makefile linux-2.5/Makefile --- ../prev/linux-2.5/Makefile Thu Mar 13 09:11:25 2003 +++ linux-2.5/Makefile Wed Mar 12 08:53:18 2003 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 64 -EXTRAVERSION = +EXTRAVERSION = -pa5 # *DOCUMENTATION* # To see a list of typical targets execute "make help" @@ -38,6 +38,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/dont11398.6320 ../prev/linux-2.5/arch/parisc/Makefile linux-2.5/arch/parisc/Makefile --- ../prev/linux-2.5/arch/parisc/Makefile Thu Mar 13 09:12:35 2003 +++ linux-2.5/arch/parisc/Makefile Tue Feb 11 06:31:54 2003 @@ -95,8 +95,9 @@ @$(generate-asm-offsets.h) < $< > $@.tmp @$(update-if-changed) -CLEAN_FILES += palo.conf lifimage include/asm-parisc/offsets.h \ +CLEAN_FILES += lifimage include/asm-parisc/offsets.h \ include/asm-parisc/offsets.h.tmp +MRPROPER_FILES += palo.conf define archhelp @echo '* vmlinux - Uncompressed kernel image (./vmlinux)' diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/arch/parisc/kernel/binfmt_elf32.c linux-2.5/arch/parisc/kernel/binfmt_elf32.c --- ../prev/linux-2.5/arch/parisc/kernel/binfmt_elf32.c Thu Mar 13 09:12:36 2003 +++ linux-2.5/arch/parisc/kernel/binfmt_elf32.c Wed Mar 12 00:21:06 2003 @@ -12,6 +12,26 @@ #define ELF_CLASS ELFCLASS32 +#define ELF_CORE_COPY_REGS(dst, pt) \ + memset(dst, 0, sizeof(dst)); /* don't leak any "random" bits */ \ + { int i; \ + for (i = 0; i < 32; i++) dst[i] = (elf_greg_t) pt->gr[i]; \ + for (i = 0; i < 8; i++) dst[32 + i] = (elf_greg_t) pt->sr[i]; \ + } \ + dst[40] = (elf_greg_t) pt->iaoq[0]; dst[41] = (elf_greg_t) pt->iaoq[1]; \ + dst[42] = (elf_greg_t) pt->iasq[0]; dst[43] = (elf_greg_t) pt->iasq[1]; \ + dst[44] = (elf_greg_t) pt->sar; dst[45] = (elf_greg_t) pt->iir; \ + dst[46] = (elf_greg_t) pt->isr; dst[47] = (elf_greg_t) pt->ior; \ + dst[48] = (elf_greg_t) mfctl(22); dst[49] = (elf_greg_t) mfctl(0); \ + dst[50] = (elf_greg_t) mfctl(24); dst[51] = (elf_greg_t) mfctl(25); \ + dst[52] = (elf_greg_t) mfctl(26); dst[53] = (elf_greg_t) mfctl(27); \ + dst[54] = (elf_greg_t) mfctl(28); dst[55] = (elf_greg_t) mfctl(29); \ + dst[56] = (elf_greg_t) mfctl(30); dst[57] = (elf_greg_t) mfctl(31); \ + dst[58] = (elf_greg_t) mfctl( 8); dst[59] = (elf_greg_t) mfctl( 9); \ + dst[60] = (elf_greg_t) mfctl(12); dst[61] = (elf_greg_t) mfctl(13); \ + dst[62] = (elf_greg_t) mfctl(10); dst[63] = (elf_greg_t) mfctl(15); + + typedef unsigned int elf_greg_t; #include @@ -60,25 +80,6 @@ #define init_elf_binfmt init_elf32_binfmt #define ELF_PLATFORM ("PARISC32\0") - -#define ELF_CORE_COPY_REGS(dst, pt) \ - memset(dst, 0, sizeof(dst)); /* don't leak any "random" bits */ \ - { int i; \ - for (i = 0; i < 32; i++) dst[i] = (elf_greg_t) pt->gr[i]; \ - for (i = 0; i < 8; i++) dst[32 + i] = (elf_greg_t) pt->sr[i]; \ - } \ - dst[40] = (elf_greg_t) pt->iaoq[0]; dst[41] = (elf_greg_t) pt->iaoq[1]; \ - dst[42] = (elf_greg_t) pt->iasq[0]; dst[43] = (elf_greg_t) pt->iasq[1]; \ - dst[44] = (elf_greg_t) pt->sar; dst[45] = (elf_greg_t) pt->iir; \ - dst[46] = (elf_greg_t) pt->isr; dst[47] = (elf_greg_t) pt->ior; \ - dst[48] = (elf_greg_t) mfctl(22); dst[49] = (elf_greg_t) mfctl(0); \ - dst[50] = (elf_greg_t) mfctl(24); dst[51] = (elf_greg_t) mfctl(25); \ - dst[52] = (elf_greg_t) mfctl(26); dst[53] = (elf_greg_t) mfctl(27); \ - dst[54] = (elf_greg_t) mfctl(28); dst[55] = (elf_greg_t) mfctl(29); \ - dst[56] = (elf_greg_t) mfctl(30); dst[57] = (elf_greg_t) mfctl(31); \ - dst[58] = (elf_greg_t) mfctl( 8); dst[59] = (elf_greg_t) mfctl( 9); \ - dst[60] = (elf_greg_t) mfctl(12); dst[61] = (elf_greg_t) mfctl(13); \ - dst[62] = (elf_greg_t) mfctl(10); dst[63] = (elf_greg_t) mfctl(15); /* * We should probably use this macro to set a flag somewhere to indicate diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/arch/parisc/kernel/cache.c linux-2.5/arch/parisc/kernel/cache.c --- ../prev/linux-2.5/arch/parisc/kernel/cache.c Thu Mar 13 09:12:36 2003 +++ linux-2.5/arch/parisc/kernel/cache.c Sat Mar 8 20:01:30 2003 @@ -114,7 +114,7 @@ void __init parisc_cache_init(void) { - if(pdc_cache_info(&cache_info)<0) + if (pdc_cache_info(&cache_info) < 0) panic("parisc_cache_init: pdc_cache_info failed"); #if 0 @@ -167,25 +167,25 @@ split_tlb = 0; if (cache_info.dt_conf.tc_sh == 0 || cache_info.dt_conf.tc_sh == 2) { - - if (cache_info.dt_conf.tc_sh == 2) - printk(KERN_WARNING "Unexpected TLB configuration. " + if (cache_info.dt_conf.tc_sh == 2) + printk(KERN_WARNING "Unexpected TLB configuration. " "Will flush I/D separately (could be optimized).\n"); - split_tlb = 1; + split_tlb = 1; } - dcache_stride = ( (1<<(cache_info.dc_conf.cc_block+3)) * - cache_info.dc_conf.cc_line ); - icache_stride = ( (1<<(cache_info.ic_conf.cc_block+3)) * - cache_info.ic_conf.cc_line ); + dcache_stride = (1 << (cache_info.dc_conf.cc_block + 3)) * + cache_info.dc_conf.cc_line; + icache_stride = (1 << (cache_info.ic_conf.cc_block + 3)) * + cache_info.ic_conf.cc_line; #ifndef CONFIG_PA20 - if(pdc_btlb_info(&btlb_info)<0) { + if (pdc_btlb_info(&btlb_info) < 0) { memset(&btlb_info, 0, sizeof btlb_info); } #endif - if ((boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) == PDC_MODEL_NVA_UNSUPPORTED) { + if ((boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) == + PDC_MODEL_NVA_UNSUPPORTED) { printk(KERN_WARNING "Only equivalent aliasing supported\n"); #ifndef CONFIG_SMP panic("SMP kernel required to avoid non-equivalent aliasing"); @@ -195,31 +195,69 @@ void disable_sr_hashing(void) { - int srhash_type; + int srhash_type; + + switch (boot_cpu_data.cpu_type) { + case pcx: /* We shouldn't get this far. setup.c should prevent it. */ + BUG(); + return; + + case pcxs: + case pcxt: + case pcxt_: + srhash_type = SRHASH_PCXST; + break; + + case pcxl: + srhash_type = SRHASH_PCXL; + break; + + case pcxl2: /* pcxl2 doesn't support space register hashing */ + return; + + default: /* Currently all PA2.0 machines use the same ins. sequence */ + srhash_type = SRHASH_PA20; + break; + } - if (boot_cpu_data.cpu_type == pcxl2) - return; /* pcxl2 doesn't support space register hashing */ + disable_sr_hashing_asm(srhash_type); +} + +void __flush_dcache_page(struct page *page) +{ + struct mm_struct *mm = current->active_mm; + struct list_head *l; - switch (boot_cpu_data.cpu_type) { + flush_kernel_dcache_page(page_address(page)); - case pcx: - BUG(); /* We shouldn't get here. code in setup.c should prevent it */ - return; + if (!page->mapping) + return; - case pcxs: - case pcxt: - case pcxt_: - srhash_type = SRHASH_PCXST; - break; + list_for_each(l, &page->mapping->i_mmap_shared) { + struct vm_area_struct *mpnt; + unsigned long off; - case pcxl: - srhash_type = SRHASH_PCXL; - break; + mpnt = list_entry(l, struct vm_area_struct, shared); - default: /* Currently all PA2.0 machines use the same ins. sequence */ - srhash_type = SRHASH_PA20; - break; - } + /* + * If this VMA is not in our MM, we can ignore it. + */ + if (mpnt->vm_mm != mm) + continue; - disable_sr_hashing_asm(srhash_type); + if (page->index < mpnt->vm_pgoff) + continue; + + off = page->index - mpnt->vm_pgoff; + if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT) + continue; + + flush_cache_page(mpnt, mpnt->vm_start + (off << PAGE_SHIFT)); + + /* All user shared mappings should be equivalently mapped, + * so once we've flushed one we should be ok + */ + break; + } } + diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/arch/parisc/kernel/entry.S linux-2.5/arch/parisc/kernel/entry.S --- ../prev/linux-2.5/arch/parisc/kernel/entry.S Thu Mar 13 09:12:36 2003 +++ linux-2.5/arch/parisc/kernel/entry.S Wed Mar 5 21:21:51 2003 @@ -558,11 +558,9 @@ .export ret_from_kernel_thread ret_from_kernel_thread: -#if CONFIG_PREEMPT || CONFIG_SMP /* Call schedule_tail first though */ bl schedule_tail, %r2 nop -#endif LDREG TI_TASK-THREAD_SZ_ALGN(%r30), %r1 LDREG TASK_PT_GR25(%r1), %r26 @@ -2014,10 +2012,8 @@ /* Set the return value for the child */ child_return: -#if CONFIG_SMP || CONFIG_PREEMPT bl schedule_tail, %r2 nop -#endif LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1 LDREG TASK_PT_GR19(%r1),%r2 diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/arch/parisc/kernel/hardware.c linux-2.5/arch/parisc/kernel/hardware.c --- ../prev/linux-2.5/arch/parisc/kernel/hardware.c Thu Mar 13 09:12:36 2003 +++ linux-2.5/arch/parisc/kernel/hardware.c Fri Feb 7 13:29:04 2003 @@ -99,8 +99,8 @@ {HPHW_NPROC,0x481,0x4,0x81,"Wilbur (E25)"}, {HPHW_NPROC,0x482,0x4,0x81,"WB-80 (E35)"}, {HPHW_NPROC,0x483,0x4,0x81,"WB-96 (E45)"}, - {HPHW_NPROC,0x48,0x4,0x81,"UL Proc L-100 (811/D210,D310)"}, - {HPHW_NPROC,0x48,0x4,0x81,"UL Proc L-75 (801/D200)"}, + {HPHW_NPROC,0x484,0x4,0x81,"UL Proc L-100 (811/D210,D310)"}, + {HPHW_NPROC,0x485,0x4,0x81,"UL Proc L-75 (801/D200)"}, {HPHW_NPROC,0x501,0x4,0x81,"Merlin L2 132 (9000/778/B132L)"}, {HPHW_NPROC,0x502,0x4,0x81,"Merlin L2 160 (9000/778/B160L)"}, {HPHW_NPROC,0x503,0x4,0x81,"Merlin L2+ 132 (9000/778/B132L)"}, diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/arch/parisc/kernel/init_task.c linux-2.5/arch/parisc/kernel/init_task.c --- ../prev/linux-2.5/arch/parisc/kernel/init_task.c Thu Mar 13 09:12:36 2003 +++ linux-2.5/arch/parisc/kernel/init_task.c Mon Feb 10 17:49:16 2003 @@ -10,6 +10,7 @@ static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); /* diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/arch/parisc/kernel/ioctl32.c linux-2.5/arch/parisc/kernel/ioctl32.c --- ../prev/linux-2.5/arch/parisc/kernel/ioctl32.c Thu Mar 13 09:12:36 2003 +++ linux-2.5/arch/parisc/kernel/ioctl32.c Tue Mar 4 00:52:27 2003 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.6 2002/10/21 16:13:22 varenet Exp $ +/* $Id: ioctl32.c,v 1.5 2002/10/18 00:21:43 varenet Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -66,6 +66,9 @@ #define __KERNEL__ #include +#include +#include + #include #include #include @@ -2824,6 +2827,27 @@ return err; } +/* Fix sizeof(sizeof()) breakage */ +#define BLKBSZGET_32 _IOR(0x12,112,int) +#define BLKBSZSET_32 _IOW(0x12,113,int) +#define BLKGETSIZE64_32 _IOR(0x12,114,int) + +static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + return sys_ioctl(fd, BLKBSZGET, arg); +} + +static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + return sys_ioctl(fd, BLKBSZSET, arg); +} + +static int do_blkgetsize64(unsigned int fd, unsigned int cmd, + unsigned long arg) +{ + return sys_ioctl(fd, BLKGETSIZE64, arg); +} + static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) { return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); @@ -2997,14 +3021,13 @@ COMPATIBLE_IOCTL(BLKRRPART) COMPATIBLE_IOCTL(BLKFLSBUF) COMPATIBLE_IOCTL(BLKSECTSET) -COMPATIBLE_IOCTL(BLKSSZGET) -COMPATIBLE_IOCTL(BLKBSZGET) /* RAID */ COMPATIBLE_IOCTL(RAID_VERSION) COMPATIBLE_IOCTL(GET_ARRAY_INFO) COMPATIBLE_IOCTL(GET_DISK_INFO) COMPATIBLE_IOCTL(PRINT_RAID_DEBUG) +COMPATIBLE_IOCTL(RAID_AUTORUN) COMPATIBLE_IOCTL(CLEAR_ARRAY) COMPATIBLE_IOCTL(ADD_NEW_DISK) COMPATIBLE_IOCTL(HOT_REMOVE_DISK) @@ -3015,12 +3038,26 @@ COMPATIBLE_IOCTL(PROTECT_ARRAY) COMPATIBLE_IOCTL(HOT_ADD_DISK) COMPATIBLE_IOCTL(SET_DISK_FAULTY) +COMPATIBLE_IOCTL(HOT_GENERATE_ERROR) COMPATIBLE_IOCTL(RUN_ARRAY) COMPATIBLE_IOCTL(START_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY_RO) COMPATIBLE_IOCTL(RESTART_ARRAY_RW) +/* DM */ +COMPATIBLE_IOCTL(DM_VERSION) +COMPATIBLE_IOCTL(DM_REMOVE_ALL) +COMPATIBLE_IOCTL(DM_DEV_CREATE) +COMPATIBLE_IOCTL(DM_DEV_REMOVE) +COMPATIBLE_IOCTL(DM_DEV_RELOAD) +COMPATIBLE_IOCTL(DM_DEV_SUSPEND) +COMPATIBLE_IOCTL(DM_DEV_RENAME) +COMPATIBLE_IOCTL(DM_DEV_DEPS) +COMPATIBLE_IOCTL(DM_DEV_STATUS) +COMPATIBLE_IOCTL(DM_TARGET_STATUS) +COMPATIBLE_IOCTL(DM_TARGET_WAIT) + /* Big K */ COMPATIBLE_IOCTL(PIO_FONT) COMPATIBLE_IOCTL(GIO_FONT) @@ -3570,6 +3607,11 @@ HANDLE_IOCTL(0x1260, broken_blkgetsize) HANDLE_IOCTL(BLKSECTGET, w_long) HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) +/* take care of sizeof(sizeof()) breakage */ +/* block stuff */ +HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget) +HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset) +HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64) HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans) HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans) diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/arch/parisc/kernel/module.c linux-2.5/arch/parisc/kernel/module.c --- ../prev/linux-2.5/arch/parisc/kernel/module.c Thu Mar 13 09:12:36 2003 +++ linux-2.5/arch/parisc/kernel/module.c Sun Mar 2 23:58:28 2003 @@ -562,10 +562,8 @@ #ifdef __LP64__ me->init = (void *)get_fdesc(me, (Elf_Addr)me->init); #ifdef CONFIG_MODULE_UNLOAD - if (me->cleanup) - me->cleanup = (void *)get_fdesc(me, (Elf_Addr)me->cleanup); - if (me->destroy) - me->destroy = (void *)get_fdesc(me, (Elf_Addr)me->destroy); + if (me->exit) + me->exit = (void *)get_fdesc(me, (Elf_Addr)me->exit); #endif #endif return 0; diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/arch/parisc/kernel/pci.c linux-2.5/arch/parisc/kernel/pci.c --- ../prev/linux-2.5/arch/parisc/kernel/pci.c Thu Mar 13 09:12:37 2003 +++ linux-2.5/arch/parisc/kernel/pci.c Wed Mar 12 09:04:06 2003 @@ -83,16 +83,9 @@ u##size in##type (int addr) \ { \ int b = PCI_PORT_HBA(addr); \ - u##size d = (u##size) -1; \ EISA_IN(size); \ - ASSERT(pci_port); /* make sure services are defined */ \ - ASSERT(parisc_pci_hba[b]); /* make sure ioaddr are "fixed up" */ \ - if (parisc_pci_hba[b] == NULL) { \ - printk(KERN_WARNING "\nPCI or EISA Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \ - } else { \ - d = pci_port->in##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr)); \ - } \ - return d; \ + if (!parisc_pci_hba[b]) return (u##size) -1; \ + return pci_port->in##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr)); \ } PCI_PORT_IN(b, 8) @@ -105,7 +98,7 @@ { \ int b = PCI_PORT_HBA(addr); \ EISA_OUT(size); \ - ASSERT(pci_port); \ + if (!parisc_pci_hba[b]) return; \ pci_port->out##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr), d); \ } @@ -378,8 +371,6 @@ pcibios_link_hba_resources(&hba->lmmio_space, bus->resource[1]); } -#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2)) - /* ** pcibios align resources() is called everytime generic PCI code @@ -409,7 +400,7 @@ align = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; /* Align to largest of MIN or input size */ - mask = MAX(alignment, align) - 1; + mask = max(alignment, align) - 1; res->start += mask; res->start &= ~mask; diff -urN --exclude-from=/tmp/dont11398.6320 ../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 Thu Mar 13 09:12:37 2003 +++ linux-2.5/arch/parisc/kernel/process.c Wed Mar 12 00:21:06 2003 @@ -205,7 +205,16 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r) { + if (regs == NULL) + return 0; + memcpy(r, regs->fr, sizeof *r); + return 1; +} + +int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r) +{ + memcpy(r, tsk->thread.regs.fr, sizeof(*r)); return 1; } diff -urN --exclude-from=/tmp/dont11398.6320 ../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 Thu Mar 13 09:12:37 2003 +++ linux-2.5/arch/parisc/kernel/signal.c Sun Feb 16 11:10:20 2003 @@ -310,7 +310,7 @@ #endif #if CACHE_FLUSHING_IS_NOT_BROKEN - flush_icache_range((unsigned long) &frame->tramp[0], + flush_user_icache_range((unsigned long) &frame->tramp[0], (unsigned long) &frame->tramp[4]); #else /* It should *always* be cache line-aligned, but the compiler @@ -395,7 +395,7 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, int in_syscall) { - struct k_sigaction *ka = ¤t->sig->action[sig-1]; + struct k_sigaction *ka = ¤t->sighand->action[sig-1]; DBG(("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n", sig, ka, info, oldset, regs)); @@ -451,7 +451,7 @@ oldset->sig[0], oldset->sig[1])); - signr = get_signal_to_deliver(&info, regs); + signr = get_signal_to_deliver(&info, regs, NULL); if (signr > 0) { /* Restart a system call if necessary. */ if (in_syscall) { @@ -463,7 +463,7 @@ break; case -ERESTARTSYS: - ka = ¤t->sig->action[signr-1]; + ka = ¤t->sighand->action[signr-1]; if (!(ka->sa.sa_flags & SA_RESTART)) { DBG(("ERESTARTSYS: putting -EINTR\n")); regs->gr[28] = -EINTR; diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/arch/parisc/kernel/sys32.h linux-2.5/arch/parisc/kernel/sys32.h --- ../prev/linux-2.5/arch/parisc/kernel/sys32.h Thu Mar 13 09:12:37 2003 +++ linux-2.5/arch/parisc/kernel/sys32.h Sun Mar 2 23:58:28 2003 @@ -1,6 +1,8 @@ #ifndef _PARISC64_KERNEL_SYS32_H #define _PARISC64_KERNEL_SYS32_H +#include + /* Call a kernel syscall which will use kernel space instead of user * space for its copy_to/from_user. */ @@ -12,6 +14,8 @@ set_fs (old_fs); \ } +#ifdef CONFIG_COMPAT + typedef __u32 __sighandler_t32; struct sigaction32 { @@ -19,5 +23,7 @@ unsigned int sa_flags; compat_sigset_t sa_mask; /* mask last for extensibility */ }; + +#endif #endif diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/arch/parisc/kernel/traps.c linux-2.5/arch/parisc/kernel/traps.c --- ../prev/linux-2.5/arch/parisc/kernel/traps.c Thu Mar 13 09:12:37 2003 +++ linux-2.5/arch/parisc/kernel/traps.c Fri Feb 14 08:46:27 2003 @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -165,9 +166,11 @@ startstack = (unsigned long *)((unsigned long)stack & ~(THREAD_SIZE - 1)); i = 1; + stack = (long *)((long)(stack + 32) &~ (FRAME_SIZE-1)); /* Align */ printk("Kernel addresses on the stack:\n"); - while (stack >= startstack) { - addr = *stack--; + while (stack > startstack) { + stack -= 16; /* Stack frames are a multiple of 16 words */ + addr = stack[16 - RP_OFFSET / sizeof(long)]; /* * If the address is either in the text segment of the * kernel, or in the region which contains vmalloc'ed diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/drivers/ide/ide.c linux-2.5/drivers/ide/ide.c --- ../prev/linux-2.5/drivers/ide/ide.c Thu Mar 13 09:14:01 2003 +++ linux-2.5/drivers/ide/ide.c Tue Feb 25 05:40:03 2003 @@ -188,6 +188,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/dont11398.6320 ../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 Thu Mar 13 09:14:05 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/dont11398.6320 ../prev/linux-2.5/drivers/input/keyboard/Kconfig linux-2.5/drivers/input/keyboard/Kconfig --- ../prev/linux-2.5/drivers/input/keyboard/Kconfig Thu Mar 13 09:14:09 2003 +++ linux-2.5/drivers/input/keyboard/Kconfig Mon Feb 10 15:23:09 2003 @@ -90,3 +90,30 @@ The module will be called amikbd. 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/dont11398.6320 ../prev/linux-2.5/drivers/input/keyboard/Makefile linux-2.5/drivers/input/keyboard/Makefile --- ../prev/linux-2.5/drivers/input/keyboard/Makefile Thu Mar 13 09:14:09 2003 +++ linux-2.5/drivers/input/keyboard/Makefile Wed Nov 27 11:46:55 2002 @@ -2,11 +2,11 @@ # 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 obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o +obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o +obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o diff -urN --exclude-from=/tmp/dont11398.6320 ../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/dont11398.6320 ../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/dont11398.6320 ../prev/linux-2.5/drivers/input/misc/Kconfig linux-2.5/drivers/input/misc/Kconfig --- ../prev/linux-2.5/drivers/input/misc/Kconfig Thu Mar 13 09:14:09 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/dont11398.6320 ../prev/linux-2.5/drivers/input/misc/Makefile linux-2.5/drivers/input/misc/Makefile --- ../prev/linux-2.5/drivers/input/misc/Makefile Thu Mar 13 09:14:09 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/dont11398.6320 ../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 Thu Mar 13 09:14:09 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/dont11398.6320 ../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/dont11398.6320 ../prev/linux-2.5/drivers/input/mouse/Kconfig linux-2.5/drivers/input/mouse/Kconfig --- ../prev/linux-2.5/drivers/input/mouse/Kconfig Thu Mar 13 09:14:10 2003 +++ linux-2.5/drivers/input/mouse/Kconfig Mon Feb 10 15:23:09 2003 @@ -121,3 +121,8 @@ The module will be called rpcmouse. 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/dont11398.6320 ../prev/linux-2.5/drivers/input/mouse/Makefile linux-2.5/drivers/input/mouse/Makefile --- ../prev/linux-2.5/drivers/input/mouse/Makefile Thu Mar 13 09:14:10 2003 +++ linux-2.5/drivers/input/mouse/Makefile Mon Nov 11 11:04:01 2002 @@ -12,3 +12,4 @@ obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.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/dont11398.6320 ../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/dont11398.6320 ../prev/linux-2.5/drivers/input/serio/Kconfig linux-2.5/drivers/input/serio/Kconfig --- ../prev/linux-2.5/drivers/input/serio/Kconfig Thu Mar 13 09:14:11 2003 +++ linux-2.5/drivers/input/serio/Kconfig Mon Feb 10 15:23:09 2003 @@ -107,3 +107,28 @@ tristate "Intel SA1111 keyboard controller" depends on SA1111 && SERIO +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/dont11398.6320 ../prev/linux-2.5/drivers/input/serio/Makefile linux-2.5/drivers/input/serio/Makefile --- ../prev/linux-2.5/drivers/input/serio/Makefile Thu Mar 13 09:14:11 2003 +++ linux-2.5/drivers/input/serio/Makefile Mon Feb 10 15:23:09 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 @@ -13,3 +11,5 @@ obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o +obj-$(CONFIG_HP_SDC) += hp_sdc.o +obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o diff -urN --exclude-from=/tmp/dont11398.6320 ../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/dont11398.6320 ../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/dont11398.6320 ../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/dont11398.6320 ../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 Thu Mar 13 09:15:11 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/dont11398.6320 ../prev/linux-2.5/drivers/scsi/Kconfig linux-2.5/drivers/scsi/Kconfig --- ../prev/linux-2.5/drivers/scsi/Kconfig Thu Mar 13 09:15:32 2003 +++ linux-2.5/drivers/scsi/Kconfig Wed Mar 5 14:17:31 2003 @@ -946,16 +946,6 @@ Please read for more information. -config SCSI_ZALON - tristate "Zalon SCSI support" - depends on GSC && SCSI - help - The Zalon is a GSC/HSC bus interface chip that sits between the - PA-RISC processor and the NCR 53c720 SCSI controller on C100, - C110, J200, J210 and some D, K & R-class machines. It's also - used on the add-in Bluefish, Barracuda & Shrike SCSI cards. - Say Y here if you have one of these machines or cards. - config SCSI_SYM53C8XX_DMA_ADDRESSING_MODE int "DMA addressing mode" depends on SCSI_SYM53C8XX_2 @@ -1010,9 +1000,19 @@ If you say Y here, the driver will preferently use normal IO rather than memory mapped IO. +config SCSI_ZALON + tristate "Zalon SCSI support" + depends on GSC && SCSI + help + The Zalon is a GSC/HSC bus interface chip that sits between the + PA-RISC processor and the NCR 53c720 SCSI controller on C100, + C110, J200, J210 and some D, K & R-class machines. It's also + used on the add-in Bluefish, Barracuda & Shrike SCSI cards. + Say Y here if you have one of these machines or cards. + config SCSI_NCR53C8XX tristate "NCR53C8XX SCSI support" - depends on PCI && SCSI_SYM53C8XX_2!=y && SCSI + depends on PCI && SCSI_SYM53C8XX_2!=y && SCSI_ZALON!=y && SCSI ---help--- This is the BSD ncr driver adapted to Linux for the NCR53C8XX family of PCI-SCSI controllers. This driver supports parity checking, diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/drivers/scsi/ncr53c8xx.c linux-2.5/drivers/scsi/ncr53c8xx.c --- ../prev/linux-2.5/drivers/scsi/ncr53c8xx.c Thu Mar 13 09:15:41 2003 +++ linux-2.5/drivers/scsi/ncr53c8xx.c Wed Mar 5 14:17:41 2003 @@ -5024,7 +5024,6 @@ **========================================================== */ -#ifdef MODULE static int ncr_detach(ncb_p np) { ccb_p cp; @@ -5160,7 +5159,6 @@ return 1; } -#endif /*========================================================== ** @@ -8935,7 +8933,6 @@ } -#ifdef MODULE int ncr53c8xx_release(struct Scsi_Host *host) { #ifdef DEBUG_NCR53C8XX @@ -8945,7 +8942,6 @@ return 1; } -#endif /* diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/drivers/scsi/ncr53c8xx.h linux-2.5/drivers/scsi/ncr53c8xx.h --- ../prev/linux-2.5/drivers/scsi/ncr53c8xx.h Thu Mar 13 09:15:41 2003 +++ linux-2.5/drivers/scsi/ncr53c8xx.h Mon Feb 17 11:43:52 2003 @@ -60,17 +60,12 @@ int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int); int ncr53c8xx_slave_configure(Scsi_Device *); - -#ifdef MODULE int ncr53c8xx_release(struct Scsi_Host *); -#else -#define ncr53c8xx_release NULL -#endif #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,75) -#define NCR53C8XX { .name = "", \ +#define NCR53C8XX { .name = "ncr8xx", \ .detect = ncr53c8xx_detect, \ .release = ncr53c8xx_release, \ .info = ncr53c8xx_info, \ diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/drivers/scsi/sym53c8xx.c linux-2.5/drivers/scsi/sym53c8xx.c --- ../prev/linux-2.5/drivers/scsi/sym53c8xx.c Thu Mar 13 09:15:47 2003 +++ linux-2.5/drivers/scsi/sym53c8xx.c Wed Mar 5 14:17:53 2003 @@ -112,8 +112,8 @@ #include #endif #include +#include #include -#include #include #include #include @@ -4901,6 +4901,11 @@ u_long period; int i; +#ifdef CONFIG_PARISC + char scsi_mode = -1; + struct hardware_path hwpath; +#endif + /* ** Wide ? */ @@ -4972,6 +4977,31 @@ */ period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz; + +#if defined(CONFIG_PARISC) + /* Host firmware (PDC) keeps a table for crippling SCSI capabilities. + * Many newer machines export one channel of 53c896 chip + * as SE, 50-pin HD. Also used for Multi-initiator SCSI clusters + * to set the SCSI Initiator ID. + */ + get_pci_node_path(np->pdev, &hwpath); + if (pdc_get_initiator(&hwpath, &np->myaddr, &period, &np->maxwide, &scsi_mode)) + { + if (np->maxwide) + np->features |= FE_WIDE; + if (scsi_mode >= 0) { + /* C3000 PDC reports period/mode */ + driver_setup.diff_support = 0; + switch(scsi_mode) { + case 0: np->scsi_mode = SMODE_SE; break; + case 1: np->scsi_mode = SMODE_HVD; break; + case 2: np->scsi_mode = SMODE_LVD; break; + default: break; + } + } + } +#endif + if (period <= 250) np->minsync = 10; else if (period <= 303) np->minsync = 11; else if (period <= 500) np->minsync = 12; @@ -7214,7 +7244,6 @@ **========================================================== */ -#ifdef MODULE static int ncr_detach(ncb_p np) { int i; @@ -7260,7 +7289,6 @@ return 1; } -#endif /*========================================================== ** @@ -12958,6 +12986,7 @@ } if (i != count) /* Ignore this device if we already have it */ continue; + pci_set_master(pcidev); devp = &devtbl[count]; devp->host_id = driver_setup.host_id; devp->attach_done = 0; @@ -13201,9 +13230,9 @@ return -1; } -#ifdef __powerpc__ +#if defined(__powerpc__) || defined(__hppa__) /* - ** Fix-up for power/pc. + ** Fix-up for power/pc and hppa. ** Should not be performed by the driver. */ if ((command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) @@ -13798,7 +13827,6 @@ } -#ifdef MODULE int sym53c8xx_release(struct Scsi_Host *host) { #ifdef DEBUG_SYM53C8XX @@ -13808,7 +13836,6 @@ return 1; } -#endif /* diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/drivers/scsi/sym53c8xx.h linux-2.5/drivers/scsi/sym53c8xx.h --- ../prev/linux-2.5/drivers/scsi/sym53c8xx.h Thu Mar 13 09:15:47 2003 +++ linux-2.5/drivers/scsi/sym53c8xx.h Mon Feb 17 11:43:52 2003 @@ -75,17 +75,11 @@ int sym53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int sym53c8xx_reset(Scsi_Cmnd *, unsigned int); int sym53c8xx_slave_configure(Scsi_Device *); - -#ifdef MODULE int sym53c8xx_release(struct Scsi_Host *); -#else -#define sym53c8xx_release NULL -#endif - #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,75) -#define SYM53C8XX { .name = "", \ +#define SYM53C8XX { .name = "sym53c8xx", \ .detect = sym53c8xx_detect, \ .release = sym53c8xx_release, \ .info = sym53c8xx_info, \ diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/drivers/scsi/zalon.c linux-2.5/drivers/scsi/zalon.c --- ../prev/linux-2.5/drivers/scsi/zalon.c Thu Mar 13 09:15:48 2003 +++ linux-2.5/drivers/scsi/zalon.c Mon Feb 17 11:43:52 2003 @@ -151,7 +151,6 @@ return (hosts_used != 0); } -#ifdef MODULE extern int ncr53c8xx_release(struct Scsi_Host *host); int zalon7xx_release(struct Scsi_Host *host) @@ -160,4 +159,3 @@ unregister_parisc_driver(&zalon_driver); return 1; } -#endif diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/drivers/scsi/zalon.h linux-2.5/drivers/scsi/zalon.h --- ../prev/linux-2.5/drivers/scsi/zalon.h Thu Mar 13 09:15:48 2003 +++ linux-2.5/drivers/scsi/zalon.h Mon Feb 17 11:43:52 2003 @@ -15,12 +15,7 @@ int zalon7xx_detect(Scsi_Host_Template *tpnt); const char *ncr53c8xx_info(struct Scsi_Host *host); int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); - -#ifdef MODULE int zalon7xx_release(struct Scsi_Host *); -#else -#define zalon7xx_release NULL -#endif #define GSC_SCSI_ZALON_OFFSET 0x800 diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/drivers/serial/8250.c linux-2.5/drivers/serial/8250.c --- ../prev/linux-2.5/drivers/serial/8250.c Thu Mar 13 09:15:53 2003 +++ linux-2.5/drivers/serial/8250.c Wed Mar 5 14:18:01 2003 @@ -2093,9 +2093,12 @@ } } -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/dont11398.6320 ../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 Thu Mar 13 09:15:53 2003 +++ linux-2.5/drivers/serial/8250_pci.c Tue Feb 25 05:40:56 2003 @@ -1237,7 +1237,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/dont11398.6320 ../prev/linux-2.5/drivers/serial/core.c linux-2.5/drivers/serial/core.c --- ../prev/linux-2.5/drivers/serial/core.c Thu Mar 13 09:15:54 2003 +++ linux-2.5/drivers/serial/core.c Wed Mar 5 14:18:01 2003 @@ -239,7 +239,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. @@ -1920,8 +1921,13 @@ sa1100_rs_console_init(); #endif #ifdef CONFIG_SERIAL_8250_CONSOLE + /* HACK: this hack (together with stuff in 8250_pci.c + * are needed to get pci serial console working + */ +#ifndef __hppa__ serial8250_console_init(); #endif +#endif #ifdef CONFIG_SERIAL_UART00_CONSOLE uart00_console_init(); #endif @@ -2054,7 +2060,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/dont11398.6320 ../prev/linux-2.5/fs/binfmt_elf.c linux-2.5/fs/binfmt_elf.c --- ../prev/linux-2.5/fs/binfmt_elf.c Thu Mar 13 09:16:23 2003 +++ linux-2.5/fs/binfmt_elf.c Wed Mar 12 00:21:06 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/dont11398.6320 ../prev/linux-2.5/fs/exec.c linux-2.5/fs/exec.c --- ../prev/linux-2.5/fs/exec.c Thu Mar 13 09:16:23 2003 +++ linux-2.5/fs/exec.c Tue Feb 25 05:41:08 2003 @@ -57,7 +57,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; @@ -190,7 +190,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 ** argv, struct linux_binprm *bprm) +int copy_strings(int argc,char ** argv, struct linux_binprm *bprm) { struct page *kmapped_page = NULL; char *kaddr = NULL; @@ -213,7 +213,7 @@ } bprm->p -= len; - /* XXX: add architecture specific overflow check here. */ + /* XXX: add architecture specific overflow check here. */ pos = bprm->p; while (len > 0) { @@ -275,10 +275,10 @@ { int r; mm_segment_t oldfs = get_fs(); - set_fs(KERNEL_DS); + set_fs(KERNEL_DS); r = copy_strings(argc, argv, bprm); set_fs(oldfs); - return r; + return r; } #ifdef CONFIG_MMU @@ -340,6 +340,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 @@ -372,8 +373,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) @@ -381,6 +389,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; @@ -392,7 +401,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; } @@ -417,7 +426,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]; @@ -818,7 +827,7 @@ /* An exec changes our domain. We are no longer part of the thread group */ - + current->self_exec_id++; flush_signal_handlers(current, 0); @@ -902,7 +911,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) { @@ -1067,7 +1076,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; @@ -1097,21 +1106,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/dont11398.6320 ../prev/linux-2.5/fs/intermezzo/dir.c linux-2.5/fs/intermezzo/dir.c --- ../prev/linux-2.5/fs/intermezzo/dir.c Thu Mar 13 09:16:34 2003 +++ linux-2.5/fs/intermezzo/dir.c Tue Feb 11 13:05:30 2003 @@ -1306,10 +1306,6 @@ return rc; } - case TCGETS: - EXIT; - return -EINVAL; - default: EXIT; return -EINVAL; diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/include/asm-parisc/assembly.h linux-2.5/include/asm-parisc/assembly.h --- ../prev/linux-2.5/include/asm-parisc/assembly.h Thu Mar 13 09:17:40 2003 +++ linux-2.5/include/asm-parisc/assembly.h Wed Mar 5 14:19:10 2003 @@ -21,7 +21,25 @@ #ifndef _PARISC_ASSEMBLY_H #define _PARISC_ASSEMBLY_H -#if defined(__LP64__) && defined(__ASSEMBLY__) +#ifdef __LP64__ +#define LDREG ldd +#define STREG std +#define LDREGM ldd,mb +#define STREGM std,ma +#define RP_OFFSET 16 +#define FRAME_SIZE 128 +#else +#define LDREG ldw +#define STREG stw +#define LDREGM ldwm +#define STREGM stwm +#define RP_OFFSET 20 +#define FRAME_SIZE 64 +#endif + +#ifdef __ASSEMBLY__ + +#ifdef __LP64__ /* the 64-bit pa gnu assembler unfortunately defaults to .level 1.1 or 2.0 so * work around that for now... */ .level 2.0w @@ -101,22 +119,6 @@ ldo R%\value(\reg), \reg .endm -#ifdef __LP64__ -#define LDREG ldd -#define STREG std -#define LDREGM ldd,mb -#define STREGM std,ma -#define RP_OFFSET 16 -#define FRAME_SIZE 128 -#else -#define LDREG ldw -#define STREG stw -#define LDREGM ldwm -#define STREGM stwm -#define RP_OFFSET 20 -#define FRAME_SIZE 64 -#endif - .macro loadgp #ifdef __LP64__ ldil L%__gp, %r27 @@ -420,4 +422,5 @@ REST_CR (%cr22, PT_PSW (\regs)) .endm +#endif /* __ASSEMBLY__ */ #endif diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/include/asm-parisc/bug.h linux-2.5/include/asm-parisc/bug.h --- ../prev/linux-2.5/include/asm-parisc/bug.h Thu Mar 13 09:17:40 2003 +++ linux-2.5/include/asm-parisc/bug.h Sat Feb 15 08:10:20 2003 @@ -8,7 +8,9 @@ * We don't beep yet. prumpf */ #define BUG() do { \ + extern void dump_stack(void); \ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + dump_stack(); \ } while (0) #define PAGE_BUG(page) do { \ diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/include/asm-parisc/cacheflush.h linux-2.5/include/asm-parisc/cacheflush.h --- ../prev/linux-2.5/include/asm-parisc/cacheflush.h Thu Mar 13 09:17:40 2003 +++ linux-2.5/include/asm-parisc/cacheflush.h Sat Mar 8 20:01:30 2003 @@ -25,9 +25,14 @@ extern void flush_cache_all_local(void); +static inline void cacheflush_h_tmp_function(void *dummy) +{ + flush_cache_all_local(); +} + static inline void flush_cache_all(void) { - on_each_cpu((void (*)(void *))flush_cache_all_local, NULL, 1, 1); + on_each_cpu(cacheflush_h_tmp_function, NULL, 1, 1); } /* The following value needs to be tuned and probably scaled with the @@ -62,13 +67,15 @@ #endif } +extern void __flush_dcache_page(struct page *page); + static inline void flush_dcache_page(struct page *page) { if (page->mapping && list_empty(&page->mapping->i_mmap) && list_empty(&page->mapping->i_mmap_shared)) { set_bit(PG_dcache_dirty, &page->flags); } else { - flush_kernel_dcache_page(page_address(page)); + __flush_dcache_page(page); } } diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/include/asm-parisc/compat.h linux-2.5/include/asm-parisc/compat.h --- ../prev/linux-2.5/include/asm-parisc/compat.h Thu Mar 13 09:17:40 2003 +++ linux-2.5/include/asm-parisc/compat.h Sat Mar 8 00:05:52 2003 @@ -88,7 +88,7 @@ typedef u32 compat_old_sigset_t; /* at least 32 bits */ #define _COMPAT_NSIG 64 -#define _COMPAT_NSIG_BPW BITS_PER_LONG +#define _COMPAT_NSIG_BPW 32 typedef u32 compat_sigset_word; diff -urN --exclude-from=/tmp/dont11398.6320 ../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 Thu Mar 13 09:17:40 2003 +++ linux-2.5/include/asm-parisc/elf.h Wed Mar 12 00:21:06 2003 @@ -99,6 +99,9 @@ typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; +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) + struct pt_regs; /* forward declaration... */ diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/include/asm-parisc/ide.h linux-2.5/include/asm-parisc/ide.h --- ../prev/linux-2.5/include/asm-parisc/ide.h Thu Mar 13 09:17:40 2003 +++ linux-2.5/include/asm-parisc/ide.h Wed Feb 26 18:11:30 2003 @@ -83,6 +83,44 @@ #define ide_check_region(from,extent) check_region((from), (extent)) #define ide_request_region(from,extent,name) request_region((from), (extent), (name)) #define ide_release_region(from,extent) release_region((from), (extent)) +/* Generic I/O and MEMIO string operations. */ + +#define __ide_insw insw +#define __ide_insl insl +#define __ide_outsw outsw +#define __ide_outsl outsl + +static __inline__ void __ide_mm_insw(unsigned long port, void *addr, u32 count) +{ + while (count--) { + *(u16 *)addr = readw(port); + addr += 2; + } +} + +static __inline__ void __ide_mm_insl(unsigned long port, void *addr, u32 count) +{ + while (count--) { + *(u32 *)addr = readl(port); + addr += 4; + } +} + +static __inline__ void __ide_mm_outsw(unsigned long port, void *addr, u32 count) +{ + while (count--) { + writew(*(u16 *)addr, port); + addr += 2; + } +} + +static __inline__ void __ide_mm_outsl(unsigned long port, void *addr, u32 count) +{ + while (count--) { + writel(*(u32 *)addr, port); + addr += 4; + } +} #endif /* __KERNEL__ */ diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/include/asm-parisc/kmap_types.h linux-2.5/include/asm-parisc/kmap_types.h --- ../prev/linux-2.5/include/asm-parisc/kmap_types.h Thu Mar 13 09:17:40 2003 +++ linux-2.5/include/asm-parisc/kmap_types.h Sun Mar 2 23:58:28 2003 @@ -21,7 +21,9 @@ D(8) KM_PTE1, D(9) KM_IRQ0, D(10) KM_IRQ1, -D(11) KM_TYPE_NR +D(11) KM_SOFTIRQ0, +D(12) KM_SOFTIRQ1, +D(13) KM_TYPE_NR }; #undef D diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/include/asm-parisc/posix_types.h linux-2.5/include/asm-parisc/posix_types.h --- ../prev/linux-2.5/include/asm-parisc/posix_types.h Thu Mar 13 09:17:40 2003 +++ linux-2.5/include/asm-parisc/posix_types.h Wed Feb 26 18:12:37 2003 @@ -17,6 +17,8 @@ typedef unsigned int __kernel_gid_t; typedef int __kernel_suseconds_t; typedef int __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; typedef int __kernel_daddr_t; /* Note these change from narrow to wide kernels */ #ifdef __LP64__ diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/include/asm-parisc/ptrace.h linux-2.5/include/asm-parisc/ptrace.h --- ../prev/linux-2.5/include/asm-parisc/ptrace.h Thu Mar 13 09:17:40 2003 +++ linux-2.5/include/asm-parisc/ptrace.h Mon Feb 10 17:49:17 2003 @@ -43,9 +43,6 @@ * since we have taken branch traps too) */ #define PTRACE_SINGLEBLOCK 12 /* resume execution until next branch */ -#define PTRACE_GETSIGINFO 13 /* get child's siginfo structure */ -#define PTRACE_SETSIGINFO 14 /* set child's siginfo structure */ - #ifdef __KERNEL__ /* XXX should we use iaoq[1] or iaoq[0] ? */ diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/include/asm-parisc/signal.h linux-2.5/include/asm-parisc/signal.h --- ../prev/linux-2.5/include/asm-parisc/signal.h Thu Mar 13 09:17:40 2003 +++ linux-2.5/include/asm-parisc/signal.h Sun Feb 16 11:10:21 2003 @@ -156,6 +156,8 @@ struct sigaction sa; }; +#define ptrace_signal_deliver(regs, cookie) do { } while (0) + #include #endif /* __KERNEL__ */ diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/include/linux/console.h linux-2.5/include/linux/console.h --- ../prev/linux-2.5/include/linux/console.h Thu Mar 13 09:17:58 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/dont11398.6320 ../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/dont11398.6320 ../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/dont11398.6320 ../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/dont11398.6320 ../prev/linux-2.5/include/linux/input.h linux-2.5/include/linux/input.h --- ../prev/linux-2.5/include/linux/input.h Thu Mar 13 09:18:03 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/dont11398.6320 ../prev/linux-2.5/include/linux/interrupt.h linux-2.5/include/linux/interrupt.h --- ../prev/linux-2.5/include/linux/interrupt.h Thu Mar 13 09:18:03 2003 +++ linux-2.5/include/linux/interrupt.h Fri Nov 29 10:26:01 2002 @@ -3,6 +3,7 @@ #define _LINUX_INTERRUPT_H #include +#include #include #include #include diff -urN --exclude-from=/tmp/dont11398.6320 ../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 Thu Mar 13 09:18:10 2003 +++ linux-2.5/include/linux/serial_core.h Wed Mar 5 14:19:40 2003 @@ -59,6 +59,11 @@ /* NEC v850. */ #define PORT_NB85E_UART 40 +/* Parisc type numbers. */ +#define PORT_MUX 41 + + +#define SERIAL_IRQ_NONE -1 #ifdef __KERNEL__ diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/include/linux/sysctl.h linux-2.5/include/linux/sysctl.h --- ../prev/linux-2.5/include/linux/sysctl.h Thu Mar 13 09:18:11 2003 +++ linux-2.5/include/linux/sysctl.h Tue Feb 25 05:41:48 2003 @@ -129,6 +129,8 @@ KERN_CADPID=54, /* int: PID of the process to notify on CAD */ KERN_PIDMAX=55, /* int: PID # limit */ KERN_CORE_PATTERN=56, /* string: pattern for core-file names */ + KERN_HPPA_PWRSW=57, /* int: hppa soft-power enable */ + KERN_HPPA_UNALIGNED=58, /* int: hppa unaligned-trap enable */ }; diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/kernel/printk.c linux-2.5/kernel/printk.c --- ../prev/linux-2.5/kernel/printk.c Thu Mar 13 09:18:20 2003 +++ linux-2.5/kernel/printk.c Mon Feb 10 15:25:22 2003 @@ -75,8 +75,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]; @@ -603,6 +603,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/dont11398.6320 ../prev/linux-2.5/kernel/sysctl.c linux-2.5/kernel/sysctl.c --- ../prev/linux-2.5/kernel/sysctl.c Thu Mar 13 09:18:20 2003 +++ linux-2.5/kernel/sysctl.c Tue Dec 24 15:44:10 2002 @@ -84,6 +84,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; @@ -188,6 +193,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/dont11398.6320 ../prev/linux-2.5/net/core/wireless.c linux-2.5/net/core/wireless.c --- ../prev/linux-2.5/net/core/wireless.c Thu Mar 13 09:18:28 2003 +++ linux-2.5/net/core/wireless.c Wed Jan 8 10:46:27 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/dont11398.6320 ../prev/linux-2.5/net/ipv4/Kconfig linux-2.5/net/ipv4/Kconfig --- ../prev/linux-2.5/net/ipv4/Kconfig Thu Mar 13 09:18:28 2003 +++ linux-2.5/net/ipv4/Kconfig Fri Nov 29 08:02:28 2002 @@ -357,6 +357,7 @@ config INET_ESP tristate "IP: ESP transformation" + depends on CRYPTO ---help--- Support for IPsec ESP. diff -urN --exclude-from=/tmp/dont11398.6320 ../prev/linux-2.5/net/sunrpc/clnt.c linux-2.5/net/sunrpc/clnt.c --- ../prev/linux-2.5/net/sunrpc/clnt.c Thu Mar 13 09:18:37 2003 +++ linux-2.5/net/sunrpc/clnt.c Mon Feb 17 19:53:55 2003 @@ -208,7 +208,8 @@ rpcauth_destroy(clnt->cl_auth); clnt->cl_auth = NULL; } - rpc_rmdir(clnt->cl_pathname); + if (clnt->cl_pathname[0]) + rpc_rmdir(clnt->cl_pathname); if (clnt->cl_xprt) { xprt_destroy(clnt->cl_xprt); clnt->cl_xprt = NULL;