NETWORKS =net/network.a
DRIVERS =drivers/block/block.a \
drivers/char/char.a \
- drivers/misc/misc.a
+ drivers/parport/parport.a
LIBS =$(TOPDIR)/lib/lib.a
SUBDIRS =kernel drivers mm fs net ipc lib
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
-source drivers/misc/Config.in
+source drivers/parpor/Config.in
endmenu
source drivers/pnp/Config.in
setup_processor();
- init_task.mm->start_code = TASK_SIZE;
- init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext;
- init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata;
- init_task.mm->brk = TASK_SIZE + (unsigned long) &_end;
+ init_mm.start_code = TASK_SIZE;
+ init_mm.end_code = TASK_SIZE + (unsigned long) &_etext;
+ init_mm.end_data = TASK_SIZE + (unsigned long) &_edata;
+ init_mm.brk = TASK_SIZE + (unsigned long) &_end;
/*
* Add your machine dependencies here
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_interrupt() || mm == &init_mm)
+ if (in_interrupt() || !mm)
goto no_context;
down(&mm->mmap_sem);
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-source drivers/misc/Config.in
+source drivers/parport/Config.in
bool 'Advanced Power Management BIOS support' CONFIG_APM
if [ "$CONFIG_APM" = "y" ]; then
if (!MOUNT_ROOT_RDONLY)
root_mountflags &= ~MS_RDONLY;
memory_start = (unsigned long) &_end;
- init_task.mm->start_code = PAGE_OFFSET;
- init_task.mm->end_code = (unsigned long) &_etext;
- init_task.mm->end_data = (unsigned long) &_edata;
- init_task.mm->brk = (unsigned long) &_end;
+ init_mm.start_code = PAGE_OFFSET;
+ init_mm.end_code = (unsigned long) &_etext;
+ init_mm.end_data = (unsigned long) &_edata;
+ init_mm.brk = (unsigned long) &_end;
/* Save unparsed command line copy for /proc/cmdline */
memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
*to = '\0';
*cmdline_p = command_line;
-#define VMALLOC_RESERVE (64 << 20) /* 64MB for vmalloc */
+#define VMALLOC_RESERVE (128 << 20) /* 128MB for vmalloc and initrd */
#define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
if (memory_end > MAXMEM)
FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
RE_ENTRANT_CHECK_OFF;
- current->tss.trap_no = 16;
- current->tss.error_code = 0;
+ current->thread.trap_no = 16;
+ current->thread.error_code = 0;
send_sig(SIGFPE, current, 1);
return;
}
void math_abort(struct info * info, unsigned int signal)
{
FPU_EIP = FPU_ORIG_EIP;
- current->tss.trap_no = 16;
- current->tss.error_code = 0;
+ current->thread.trap_no = 16;
+ current->thread.error_code = 0;
send_sig(signal,current,1);
RE_ENTRANT_CHECK_OFF;
__asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
#define SEG_EXPAND_DOWN(s) (((s).b & ((1 << 11) | (1 << 10))) \
== (1 << 10))
-#define I387 (current->tss.i387)
+#define I387 (current->thread.i387)
#define FPU_info (I387.soft.info)
#define FPU_CS (*(unsigned short *) &(FPU_info->___cs))
/*
* Go through process' page directory.
*/
- if (!mm || mm == &init_mm)
+ if (!mm)
return;
for (vma = mm->mmap; vma; vma = vma->vm_next) {
pgd_t * pgd = pgd_offset(mm, vma->vm_start);
static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
-struct mm_struct init_mm = INIT_MM;
+struct mm_struct init_mm = INIT_MM(init_mm);
union task_union init_task_union
__attribute__((section("init_task"), aligned(2*PAGE_SIZE)))
asm __volatile__ ("frestore %0" : : "m" (zero));
}
- init_task.mm->start_code = PAGE_OFFSET;
- init_task.mm->end_code = (unsigned long) &_etext;
- init_task.mm->end_data = (unsigned long) &_edata;
- init_task.mm->brk = (unsigned long) &_end;
+ init_mm.start_code = PAGE_OFFSET;
+ init_mm.end_code = (unsigned long) &_etext;
+ init_mm.end_data = (unsigned long) &_edata;
+ init_mm.brk = (unsigned long) &_end;
*cmdline_p = m68k_command_line;
memcpy(saved_command_line, *cmdline_p, CL_SIZE);
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_interrupt() || mm == &init_mm)
+ if (in_interrupt() || !mm)
goto no_context;
down(&mm->mmap_sem);
bool 'Sysctl support' CONFIG_SYSCTL
if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
-source drivers/misc/Config.in
+source drivers/parport/Config.in
fi
endmenu
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_interrupt() || mm == &init_mm)
+ if (in_interrupt() || !mm)
goto no_context;
#if 0
printk("[%s:%d:%08lx:%ld:%08lx]\n", current->comm, current->pid,
define_bool CONFIG_KERNEL_ELF y
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-source drivers/misc/Config.in
+source drivers/parport/Config.in
bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
bool 'Support for frame buffer devices' CONFIG_FB
{
pte_t *pte;
- pte = my_find_pte(init_task.mm, address);
+ pte = my_find_pte(&init_mm, address);
if ( !pte )
{
printk("pte NULL in kernel_set_cachemode()\n");
pte_val (*pte) &= mask;
pte_val (*pte) |= flags;
- flush_tlb_page(find_vma(init_task.mm,address),address);
+ flush_tlb_page(find_vma(&init_mm,address),address);
address += PAGE_SIZE;
}
/*
* Make the page no cache so we don't blow our cache with 0's
*/
- pte = find_pte(init_task.mm, pageptr);
+ pte = find_pte(&init_mm, pageptr);
if ( !pte )
{
printk("pte NULL in zero_paged()\n");
}
pte_uncache(*pte);
- flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+ flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
/*
* Important here to not take time away from real processes.
*/
/* turn cache on for this page */
pte_cache(*pte);
- flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+ flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
/* atomically add this page to the list */
asm ( "101:lwarx %0,0,%1\n" /* reserve zero_cache */
" stw %0,0(%2)\n" /* update *pageptr */
/* reboot on panic */
panic_timeout = 180;
- init_task.mm->start_code = PAGE_OFFSET;
- init_task.mm->end_code = (unsigned long) _etext;
- init_task.mm->end_data = (unsigned long) _edata;
- init_task.mm->brk = (unsigned long) klimit;
+ init_mm.start_code = PAGE_OFFSET;
+ init_mm.end_code = (unsigned long) _etext;
+ init_mm.end_data = (unsigned long) _edata;
+ init_mm.brk = (unsigned long) klimit;
/* Save unparsed command line copy for /proc/cmdline */
strcpy(saved_command_line, cmd_line);
#if 0
current->mm->mmap->vm_page_prot = PAGE_SHARED;
current->mm->mmap->vm_start = PAGE_OFFSET;
- current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+ current->mm->mmap->vm_end = init_mm.mmap->vm_end;
#endif
cpu_callin_map[current->processor] = 1;
while(!smp_commenced)
return;
}
#endif
- if (in_interrupt()) {
+ if (in_interrupt() || !mm) {
static int complained;
if (complained < 20) {
++complained;
#endif /* CONFIG_APUS */
#endif /* CONFIG_8xx */
/* Do we have a page table? */
- if (init_task.mm->pgd == NULL)
+ if (init_mm.pgd == NULL)
return 0;
/* Use upper 10 bits of addr to index the first level map */
- pd = (pmd_t *) (init_task.mm->pgd + (addr >> PGDIR_SHIFT));
+ pd = (pmd_t *) (init_mm.pgd + (addr >> PGDIR_SHIFT));
if (pmd_none(*pd))
return 0;
static inline void apmmu_uncache_page(unsigned long addr)
{
- pgd_t *pgdp = apmmu_pgd_offset(init_task.mm, addr);
+ pgd_t *pgdp = apmmu_pgd_offset(&init_mm, addr);
pmd_t *pmdp;
pte_t *ptep;
static inline void apmmu_recache_page(unsigned long addr)
{
- pgd_t *pgdp = apmmu_pgd_offset(init_task.mm, addr);
+ pgd_t *pgdp = apmmu_pgd_offset(&init_mm, addr);
pmd_t *pmdp;
pte_t *ptep;
pte_t *ptep;
while(start < end) {
- pgdp = apmmu_pgd_offset(init_task.mm, start);
+ pgdp = apmmu_pgd_offset(&init_mm, start);
if(apmmu_pgd_none(*pgdp)) {
pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE);
apmmu_early_pgd_set(pgdp, pmdp);
pte_t *ptep;
unsigned start = virt_page<<12;
- pgdp = apmmu_pgd_offset(init_task.mm, start);
+ pgdp = apmmu_pgd_offset(&init_mm, start);
if(apmmu_pgd_none(*pgdp)) {
pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE);
apmmu_early_pgd_set(pgdp, pmdp);
pgd_t *pgdp;
unsigned start = virt_page<<12;
- pgdp = apmmu_pgd_offset(init_task.mm, start);
+ pgdp = apmmu_pgd_offset(&init_mm, start);
*pgdp = __pgd((phys_page<<8) | prot);
}
make_large_page((KERNBASE+phys)>>12,
(phys>>12),
APMMU_CACHE|APMMU_PRIV|APMMU_VALID);
- init_task.mm->mmap->vm_start = page_offset = KERNBASE;
+ init_mm.mmap->vm_start = page_offset = KERNBASE;
stack_top = page_offset - PAGE_SIZE;
}
/* Due to stack alignment restrictions and assumptions... */
- init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
- init_task.mm->mmap->vm_start = KERNBASE;
- init_task.mm->mmap->vm_end = *memory_end_p;
- init_task.mm->context = (unsigned long) NO_CONTEXT;
+ init_mm.mmap->vm_page_prot = PAGE_SHARED;
+ init_mm.mmap->vm_start = KERNBASE;
+ init_mm.mmap->vm_end = *memory_end_p;
+ init_mm.context = (unsigned long) NO_CONTEXT;
init_task.tss.kregs = &fake_swapper_regs;
if (serial_console)
current->mm->mmap->vm_page_prot = PAGE_SHARED;
current->mm->mmap->vm_start = PAGE_OFFSET;
- current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+ current->mm->mmap->vm_end = init_mm.mmap->vm_end;
local_flush_cache_all();
local_flush_tlb_all();
: "memory" /* paranoid */);
current->mm->mmap->vm_page_prot = PAGE_SHARED;
current->mm->mmap->vm_start = PAGE_OFFSET;
- current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+ current->mm->mmap->vm_end = init_mm.mmap->vm_end;
while(!smp_commenced)
barrier();
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_interrupt() || mm == &init_mm)
+ if (in_interrupt() || !mm)
goto do_kernel_fault;
down(&mm->mmap_sem);
unsigned long tmp;
physaddr &= PAGE_MASK;
- pgdp = srmmu_pgd_offset(init_task.mm, virt_addr);
+ pgdp = srmmu_pgd_offset(&init_mm, virt_addr);
pmdp = pmd_offset(pgdp, virt_addr);
ptep = pte_offset(pmdp, virt_addr);
tmp = (physaddr >> 4) | SRMMU_ET_PTE;
pmd_t *pmdp;
pte_t *ptep;
- pgdp = srmmu_pgd_offset(init_task.mm, virt_addr);
+ pgdp = srmmu_pgd_offset(&init_mm, virt_addr);
pmdp = pmd_offset(pgdp, virt_addr);
ptep = pte_offset(pmdp, virt_addr);
pte_t *ptep;
while(start < end) {
- pgdp = srmmu_pgd_offset(init_task.mm, start);
+ pgdp = srmmu_pgd_offset(&init_mm, start);
if(srmmu_pgd_none(*pgdp)) {
pmdp = sparc_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE);
srmmu_early_pgd_set(pgdp, pmdp);
what = 2;
}
- pgdp = srmmu_pgd_offset(init_task.mm, start);
+ pgdp = srmmu_pgd_offset(&init_mm, start);
if(what == 2) {
*pgdp = __pgd(prompte);
start += SRMMU_PGDIR_SIZE;
/* Create a third-level SRMMU 16MB page mapping. */
__initfunc(static void do_large_mapping(unsigned long vaddr, unsigned long phys_base))
{
- pgd_t *pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
+ pgd_t *pgdp = srmmu_pgd_offset(&init_mm, vaddr);
unsigned long big_pte;
MKTRACE(("dlm[v<%08lx>-->p<%08lx>]", vaddr, phys_base));
}
}
MKTRACE(("success\n"));
- init_task.mm->mmap->vm_start = page_offset = low_base;
+ init_mm.mmap->vm_start = page_offset = low_base;
stack_top = page_offset - PAGE_SIZE;
BTFIXUPSET_SETHI(page_offset, low_base);
BTFIXUPSET_SETHI(stack_top, page_offset - PAGE_SIZE);
memset((void *) start_mem, 0, bitmap_size);
start_mem += bitmap_size;
- sun4c_kstack_vma.vm_mm = init_task.mm;
+ sun4c_kstack_vma.vm_mm = &init_mm;
sun4c_kstack_vma.vm_start = sun4c_taskstack_start;
sun4c_kstack_vma.vm_end = sun4c_taskstack_end;
sun4c_kstack_vma.vm_page_prot = PAGE_SHARED;
fi
if [ "$CONFIG_PCI" = "y" ]; then
- source drivers/misc/Config.in
+ source drivers/parport/Config.in
dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
tristate 'SUNW,envctrl support' CONFIG_ENVCTRL
fi
#endif
/* Due to stack alignment restrictions and assumptions... */
- init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
- init_task.mm->mmap->vm_start = PAGE_OFFSET;
- init_task.mm->mmap->vm_end = *memory_end_p;
- init_task.mm->context = (unsigned long) NO_CONTEXT;
+ init_mm.mmap->vm_page_prot = PAGE_SHARED;
+ init_mm.mmap->vm_start = PAGE_OFFSET;
+ init_mm.mmap->vm_end = *memory_end_p;
+ init_mm.context = (unsigned long) NO_CONTEXT;
init_task.tss.kregs = &fake_swapper_regs;
#ifdef CONFIG_IP_PNP
* If we're in an interrupt or have no user
* context, we must not take the fault..
*/
- if (in_interrupt() || mm == &init_mm)
+ if (in_interrupt() || !mm)
goto do_kernel_fault;
down(&mm->mmap_sem);
#
# Note 2! The CFLAGS definitions are now in the main makefile.
-SUB_DIRS := block char net misc sound
+SUB_DIRS := block char net parport sound
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o \
macintosh video dio zorro fc4 usb \
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * A /dev/parportxy device node represents an arbitrary device ('y')
+ * A /dev/parportx device node represents an arbitrary device
* on port 'x'. The following operations are possible:
*
* open do nothing, set up default IEEE 1284 protocol to be COMPAT
+++ /dev/null
-Currently known (or at least suspected) bugs in parport:
-
-o lp doesn't allow you to read status while printing is in progress.
-
-See <URL:http://www.cyberelk.demon.co.uk/parport.html>.
+++ /dev/null
-#
-# For a description of the syntax of this configuration file,
-# see the Configure script.
-#
-# Parport configuration.
-#
-
-tristate 'Parallel port support' CONFIG_PARPORT
-if [ "$CONFIG_PARPORT" != "n" ]; then
- dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
- if [ "$CONFIG_PARPORT_PC" != "n" ]; then
- bool ' Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO
- fi
- if [ "$CONFIG_ARM" = "y" ]; then
- dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
- fi
- if [ "$CONFIG_AMIGA" = "y" ]; then
- dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
- if [ "$CONFIG_ZORRO" != "n" ]; then
- dep_tristate ' Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
- fi
- else
- define_bool CONFIG_PARPORT_AMIGA n
- define_bool CONFIG_PARPORT_MFC3 n
- fi
- if [ "$CONFIG_ATARI" = "y" ]; then
- dep_tristate ' Atari hardware' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
- else
- define_bool CONFIG_PARPORT_ATARI n
- fi
-
- # If exactly one hardware type is selected then parport will optimise away
- # support for loading any others. Defeat this if the user is keen.
- bool ' Support foreign hardware' CONFIG_PARPORT_OTHER
-
- bool ' IEEE 1284 transfer modes' CONFIG_PARPORT_1284
-fi
+++ /dev/null
-#
-# Makefile for the kernel miscellaneous drivers.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
-# Note 3! Parport is the Borg. We have assimilated some other
-# drivers in the `char', `net' and `scsi' directories, but left them
-# there to allay suspicion.
-
-SUB_DIRS :=
-MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS)
-
-L_TARGET := misc.a
-MX_OBJS :=
-LX_OBJS :=
-MI_OBJS :=
-MIX_OBJS :=
-
-ifeq ($(CONFIG_PARPORT),y)
- L_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o \
- parport_procfs.o
-
- ifeq ($(CONFIG_PARPORT_1284),y)
- L_OBJS += parport_daisy.o parport_probe.o
- endif
-
- ifeq ($(CONFIG_PARPORT_PC),y)
- LX_OBJS += parport_pc.o
- else
- ifeq ($(CONFIG_PARPORT_PC),m)
- M_OBJS += parport_pc.o
- endif
- endif
- ifeq ($(CONFIG_PARPORT_AX),y)
- LX_OBJS += parport_ax.o
- else
- ifeq ($(CONFIG_PARPORT_AX),m)
- M_OBJS += parport_ax.o
- endif
- endif
- ifeq ($(CONFIG_PARPORT_AMIGA),y)
- LX_OBJS += parport_amiga.o
- else
- ifeq ($(CONFIG_PARPORT_AMIGA),m)
- M_OBJS += parport_amiga.o
- endif
- endif
- ifeq ($(CONFIG_PARPORT_MFC3),y)
- LX_OBJS += parport_mfc3.o
- else
- ifeq ($(CONFIG_PARPORT_MFC3),m)
- M_OBJS += parport_mfc3.o
- endif
- endif
- ifeq ($(CONFIG_PARPORT_ATARI),y)
- LX_OBJS += parport_atari.o
- else
- ifeq ($(CONFIG_PARPORT_ATARI),m)
- M_OBJS += parport_atari.o
- endif
- endif
- LX_OBJS += parport_init.o
-else
- ifeq ($(CONFIG_PARPORT),m)
- MI_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o
- ifeq ($(CONFIG_PARPORT_1284),y)
- MI_OBJS += parport_daisy.o parport_probe.o
- endif
- ifneq ($(CONFIG_PROC_FS),n)
- MI_OBJS += parport_procfs.o
- endif
- MIX_OBJS += parport_init.o
- M_OBJS += parport.o
- endif
- ifeq ($(CONFIG_PARPORT_PC),m)
- M_OBJS += parport_pc.o
- endif
- ifeq ($(CONFIG_PARPORT_AX),m)
- M_OBJS += parport_ax.o
- endif
- ifeq ($(CONFIG_PARPORT_AMIGA),m)
- M_OBJS += parport_amiga.o
- endif
- ifeq ($(CONFIG_PARPORT_MFC3),m)
- M_OBJS += parport_mfc3.o
- endif
- ifeq ($(CONFIG_PARPORT_ATARI),m)
- M_OBJS += parport_atari.o
- endif
-endif
-
-include $(TOPDIR)/Rules.make
-
-# Special rule to build the composite parport.o module
-parport.o: $(MI_OBJS) $(MIX_OBJS)
- $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS)
+++ /dev/null
-Things to be done.
-
-0. Fix the bugs (see BUGS-parport).
-
-1. Proper documentation.
-
-2. A better lp.c:
-
- a) ECP support would be nice. This can only work if both the port and
- the printer support it.
-
- b) Handle status readback automatically. IEEE1284 printers can post status
- bits when they have something to say. We should read out and deal
- with (maybe just log) whatever the printer wants to tell the world.
-
-3. Support more hardware (eg m68k, Sun bpp).
-
-4. A better PLIP (make use of bidirectional/ECP/EPP ports).
-
-See <URL:http://www.cyberelk.demon.co.uk/parport.html>.
+++ /dev/null
-#ifndef _MULTIFACE_H_
-#define _MULTIFACE_H_
-
-/*
- * Defines for SerialMaster, Multiface Card II and Multiface Card III
- * The addresses given below are offsets to the board base address
- *
- * 6.11.95 Joerg Dorchain (dorchain@mpi-sb.mpg.de)
- *
- */
-
-#define PIA_REG_PADWIDTH 255
-
-#define DUARTBASE 0x0000
-#define PITBASE 0x0100
-#define ROMBASE 0x0200
-#define PIABASE 0x4000
-
-#endif
-
+++ /dev/null
-/* Low-level parallel port routines for the Amiga buildin port
- *
- * Author: Joerg Dorchain <dorchain@wirbel.com>
- *
- * This is a complete rewrite of the code, but based heaviy upon the old
- * lp_intern. code.
- *
- * The built-in Amiga parallel port provides one port at a fixed address
- * with 8 bisdirecttional data lines (D0 - D7) and 3 bidirectional status
- * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically in
- * hardware when the data register is accessed), and 1 input control line
- * /ACK, able to cause an interrupt, but both not directly settable by
- * software.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/parport.h>
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/irq.h>
-#include <asm/amigaints.h>
-
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTK printk
-#else
-static inline int DPRINTK() {return 0;}
-#endif
-
-static struct parport *this_port = NULL;
-
-static void amiga_write_data(struct parport *p, unsigned char data)
-{
-DPRINTK("write_data %c\n",data);
- /* Triggers also /STROBE. This behavior cannot be changed */
- ciaa.prb = data;
-}
-
-static unsigned char amiga_read_data(struct parport *p)
-{
- /* Triggers also /STROBE. This behavior cannot be changed */
- return ciaa.prb;
-}
-
-#if 0
-static unsigned char control_pc_to_amiga(unsigned char control)
-{
- unsigned char ret = 0;
-
- if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
- ;
- if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
- ;
- if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
- ;
- if (control & PARPORT_CONTROL_INIT) /* INITP */
- /* reset connected to cpu reset pin */;
- if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
- /* Not connected */;
- if (control & PARPORT_CONTROL_STROBE) /* Strobe */
- /* Handled only directly by hardware */;
- return ret;
-}
-#endif
-
-static unsigned char control_amiga_to_pc(unsigned char control)
-{
- return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT |
- PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
- /* fake value: interrupt enable, select in, no reset,
- no autolf, no strobe - seems to be closest the wiring diagram */
-}
-
-static void amiga_write_control(struct parport *p, unsigned char control)
-{
-DPRINTK("write_control %02x\n",control);
- /* No implementation possible */
-}
-
-static unsigned char amiga_read_control( struct parport *p)
-{
-DPRINTK("read_control \n");
- return control_amiga_to_pc(0);
-}
-
-static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val)
-{
- unsigned char old;
-
-DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
- old = amiga_read_control(p);
- amiga_write_control(p, (old & ~mask) ^ val);
- return old;
-}
-
-
-static unsigned char status_pc_to_amiga(unsigned char status)
-{
- unsigned char ret = 1;
-
- if (status & PARPORT_STATUS_BUSY) /* Busy */
- ret &= ~1;
- if (status & PARPORT_STATUS_ACK) /* Ack */
- /* handled in hardware */;
- if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
- ret |= 2;
- if (status & PARPORT_STATUS_SELECT) /* select */
- ret |= 4;
- if (status & PARPORT_STATUS_ERROR) /* error */
- /* not connected */;
- return ret;
-}
-
-static unsigned char status_amiga_to_pc(unsigned char status)
-{
- unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
-
- if (status & 1) /* Busy */
- ret &= ~PARPORT_STATUS_BUSY;
- if (status & 2) /* PaperOut */
- ret |= PARPORT_STATUS_PAPEROUT;
- if (status & 4) /* Selected */
- ret |= PARPORT_STATUS_SELECT;
- /* the rest is not connected or handled autonomously in hardware */
-
- return ret;
-}
-
-static void amiga_write_status( struct parport *p, unsigned char status)
-{
-DPRINTK("write_status %02x\n",status);
- ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status);
-}
-
-static unsigned char amiga_read_status(struct parport *p)
-{
- unsigned char status;
-
- status = status_amiga_to_pc(ciab.pra & 7);
-DPRINTK("read_status %02x\n", status);
- return status;
-}
-
-static void amiga_change_mode( struct parport *p, int m)
-{
- /* XXX: This port only has one mode, and I am
- not sure about the corresponding PC-style mode*/
-}
-
-/* as this ports irq handling is already done, we use a generic funktion */
-static void amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- parport_generic_irq(irq, (struct parport *) dev_id, regs);
-}
-
-
-static void amiga_init_state(struct parport_state *s)
-{
- s->u.amiga.data = 0;
- s->u.amiga.datadir = 255;
- s->u.amiga.status = 0;
- s->u.amiga.statusdir = 0;
-}
-
-static void amiga_save_state(struct parport *p, struct parport_state *s)
-{
- s->u.amiga.data = ciaa.prb;
- s->u.amiga.datadir = ciaa.ddrb;
- s->u.amiga.status = ciab.pra & 7;
- s->u.amiga.statusdir = ciab.ddra & 7;
-}
-
-static void amiga_restore_state(struct parport *p, struct parport_state *s)
-{
- ciaa.prb = s->u.amiga.data;
- ciaa.ddrb = s->u.amiga.datadir;
- ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status;
- ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir;
-}
-
-static void amiga_enable_irq(struct parport *p)
-{
- enable_irq(IRQ_AMIGA_CIAA_FLG);
-}
-
-static void amiga_disable_irq(struct parport *p)
-{
- disable_irq(IRQ_AMIGA_CIAA_FLG);
-}
-
-static void amiga_inc_use_count(void)
-{
- MOD_INC_USE_COUNT;
-}
-
-static void amiga_dec_use_count(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static void amiga_fill_inode(struct inode *inode, int fill)
-{
-#ifdef MODULE
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-#endif
-}
-
-static struct parport_operations pp_amiga_ops = {
- amiga_write_data,
- amiga_read_data,
-
- amiga_write_control,
- amiga_read_control,
- amiga_frob_control,
-
- NULL, /* write_econtrol */
- NULL, /* read_econtrol */
- NULL, /* frob_econtrol */
-
- amiga_write_status,
- amiga_read_status,
-
- NULL, /* write fifo */
- NULL, /* read fifo */
-
- amiga_change_mode,
-
-
- NULL, /* epp_write_data */
- NULL, /* epp_read_data */
- NULL, /* epp_write_addr */
- NULL, /* epp_read_addr */
- NULL, /* epp_check_timeout */
-
- NULL, /* epp_write_block */
- NULL, /* epp_read_block */
-
- NULL, /* ecp_write_block */
- NULL, /* ecp_read_block */
-
- amiga_init_state,
- amiga_save_state,
- amiga_restore_state,
-
- amiga_enable_irq,
- amiga_disable_irq,
- amiga_interrupt,
-
- amiga_inc_use_count,
- amiga_dec_use_count,
- amiga_fill_inode
-};
-
-/* ----------- Initialisation code --------------------------------- */
-
-__initfunc(int parport_amiga_init(void))
-{
- struct parport *p;
-
- if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) {
- ciaa.ddrb = 0xff;
- ciab.ddra &= 0xf8;
- if (!(p = parport_register_port((unsigned long)&ciaa.prb,
- IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
- &pp_amiga_ops)))
- return 0;
- this_port = p;
- printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
- /* XXX: set operating mode */
- parport_proc_register(p);
- if (request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0,
- p->name, p)) {
- parport_unregister_port (p);
- return 0;
- }
-
- if (parport_probe_hook)
- (*parport_probe_hook)(p);
-
- parport_announce_port (p);
-
- return 1;
-
- }
- return 0;
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Joerg Dorchain");
-MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
-MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port");
-
-int init_module(void)
-{
- return ! parport_amiga_init();
-}
-
-void cleanup_module(void)
-{
- if (p->irq != PARPORT_IRQ_NONE)
- free_irq(IRQ_AMIGA_CIAA_FLG, p);
- parport_proc_unregister(this_port);
- parport_unregister_port(this_port);
-}
-#endif
-
-
+++ /dev/null
-/* Low-level parallel port routines for Archimedes onboard hardware
- *
- * Author: Phil Blundell <Philip.Blundell@pobox.com>
- */
-
-/* This driver is for the parallel port hardware found on Acorn's old
- * range of Archimedes machines. The A5000 and newer systems have PC-style
- * I/O hardware and should use the parport_pc driver instead.
- *
- * The Acorn printer port hardware is very simple. There is a single 8-bit
- * write-only latch for the data port and control/status bits are handled
- * with various auxilliary input and output lines. The port is not
- * bidirectional, does not support any modes other than SPP, and has only
- * a subset of the standard printer control lines connected.
- */
-
-#include <linux/threads.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/parport.h>
-
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/arch/oldlatches.h>
-#include <asm/arch/irqs.h>
-
-#define DATA_ADDRESS 0x3350010
-
-/* This is equivalent to the above and only used for request_region. */
-#define PORT_BASE 0x80000000 | ((DATA_ADDRESS - IO_BASE) >> 2)
-
-/* The hardware can't read from the data latch, so we must use a soft
- copy. */
-static unsigned char data_copy;
-
-/* These are pretty simple. We know the irq is never shared and the
- kernel does all the magic that's required. */
-static void arc_enable_irq(struct parport *p)
-{
- enable_irq(p->irq);
-}
-
-static void arc_disable_irq(struct parport *p)
-{
- disable_irq(p->irq);
-}
-
-static void arc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- parport_generic_irq(irq, (struct parport *) dev_id, regs);
-}
-
-static void arc_write_data(struct parport *p, unsigned char data)
-{
- data_copy = data;
- outb_t(data, DATA_LATCH);
-}
-
-static unsigned char arc_read_data(struct parport *p)
-{
- return data_copy;
-}
-
-static void arc_inc_use_count(void)
-{
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
-}
-
-static void arc_dec_use_count(void)
-{
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
-}
-
-static void arc_fill_inode(struct inode *inode, int fill)
-{
-#ifdef MODULE
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-#endif
-}
-
-static struct parport_operations parport_arc_ops =
-{
- arc_write_data,
- arc_read_data,
-
- arc_write_control,
- arc_read_control,
- arc_frob_control,
-
- arc_read_status,
-
- arc_enable_irq,
- arc_disable_irq,
-
- arc_data_forward,
- arc_data_reverse,
-
- arc_interrupt,
-
- arc_init_state,
- arc_save_state,
- arc_restore_state,
-
- arc_inc_use_count,
- arc_dec_use_count,
- arc_fill_inode,
-
- parport_ieee1284_epp_write_data,
- parport_ieee1284_epp_read_data,
- parport_ieee1284_epp_write_addr,
- parport_ieee1284_epp_read_addr,
-
- parport_ieee1284_ecp_write_data,
- parport_ieee1284_ecp_read_data,
- parport_ieee1284_ecp_write_addr,
-
- parport_ieee1284_write_compat,
- parport_ieee1284_read_nibble,
- parport_ieee1284_read_byte,
-};
-
-/* --- Initialisation code -------------------------------- */
-
-int parport_arc_init(void)
-{
- /* Archimedes hardware provides only one port, at a fixed address */
- struct parport *p;
-
- if (check_region(PORT_BASE, 1))
- return 0;
-
- p = parport_register_port (PORT_BASE, IRQ_PRINTERACK,
- PARPORT_DMA_NONE, &parport_arc_ops);
-
- if (!p)
- return 0;
-
- p->modes = PARPORT_MODE_ARCSPP;
- p->size = 1;
-
- printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n",
- p->irq);
- parport_proc_register(p);
-
- /* Tell the high-level drivers about the port. */
- parport_announce_port (p);
-
- return 1;
-}
+++ /dev/null
-/* Low-level parallel port routines for the Atari builtin port
- *
- * Author: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- *
- * Based on parport_amiga.c.
- *
- * The built-in Atari parallel port provides one port at a fixed address
- * with 8 output data lines (D0 - D7), 1 output control line (STROBE)
- * and 1 input status line (BUSY) able to cause an interrupt.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/parport.h>
-#include <asm/setup.h>
-#include <asm/atarihw.h>
-#include <asm/irq.h>
-#include <asm/atariints.h>
-
-static struct parport *this_port = NULL;
-
-static unsigned char
-parport_atari_read_data(struct parport *p)
-{
- unsigned long flags;
- unsigned char data;
-
- save_flags(flags);
- cli();
- sound_ym.rd_data_reg_sel = 15;
- data = sound_ym.rd_data_reg_sel;
- restore_flags(flags);
- return data;
-}
-
-static void
-parport_atari_write_data(struct parport *p, unsigned char data)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- sound_ym.rd_data_reg_sel = 15;
- sound_ym.wd_data = data;
- restore_flags(flags);
-}
-
-static unsigned char
-parport_atari_read_control(struct parport *p)
-{
- unsigned long flags;
- unsigned char control = 0;
-
- save_flags(flags);
- cli();
- sound_ym.rd_data_reg_sel = 14;
- if (!(sound_ym.rd_data_reg_sel & (1 << 5)))
- control = PARPORT_CONTROL_STROBE;
- restore_flags(flags);
- return control;
-}
-
-static void
-parport_atari_write_control(struct parport *p, unsigned char control)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- sound_ym.rd_data_reg_sel = 14;
- if (control & PARPORT_CONTROL_STROBE)
- sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
- else
- sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
- restore_flags(flags);
-}
-
-static unsigned char
-parport_atari_frob_control(struct parport *p, unsigned char mask,
- unsigned char val)
-{
- unsigned char old = parport_atari_read_control(p);
- parport_atari_write_control(p, (old & ~mask) ^ val);
- return old;
-}
-
-static unsigned char
-parport_atari_read_status(struct parport *p)
-{
- return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
- PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
-}
-
-static void
-parport_atari_write_status(struct parport *p, unsigned char status)
-{
-}
-
-static void
-parport_atari_init_state(struct parport_state *s)
-{
-}
-
-static void
-parport_atari_save_state(struct parport *p, struct parport_state *s)
-{
-}
-
-static void
-parport_atari_restore_state(struct parport *p, struct parport_state *s)
-{
-}
-
-static void
-parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- parport_generic_irq(irq, (struct parport *) dev_id, regs);
-}
-
-static void
-parport_atari_inc_use_count(void)
-{
- MOD_INC_USE_COUNT;
-}
-
-static void
-parport_atari_dec_use_count(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static void
-parport_atari_fill_inode(struct inode *inode, int fill)
-{
-#ifdef MODULE
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-#endif
-}
-
-static struct parport_operations parport_atari_ops = {
- parport_atari_write_data,
- parport_atari_read_data,
-
- parport_atari_write_control,
- parport_atari_read_control,
- parport_atari_frob_control,
-
- NULL, /* write_econtrol */
- NULL, /* read_econtrol */
- NULL, /* frob_econtrol */
-
- parport_atari_write_status,
- parport_atari_read_status,
-
- NULL, /* write fifo */
- NULL, /* read fifo */
-
- NULL, /* change_mode */
-
- NULL, /* epp_write_data */
- NULL, /* epp_read_data */
- NULL, /* epp_write_addr */
- NULL, /* epp_read_addr */
- NULL, /* epp_check_timeout */
-
- NULL, /* epp_write_block */
- NULL, /* epp_read_block */
-
- NULL, /* ecp_write_block */
- NULL, /* ecp_read_block */
-
- parport_atari_init_state,
- parport_atari_save_state,
- parport_atari_restore_state,
-
- NULL, /* enable_irq */
- NULL, /* disable_irq */
- parport_atari_interrupt,
-
- parport_atari_inc_use_count,
- parport_atari_dec_use_count,
- parport_atari_fill_inode
-};
-
-
-int __init
-parport_atari_init(void)
-{
- struct parport *p;
- unsigned long flags;
-
- if (MACH_IS_ATARI) {
- save_flags(flags);
- cli();
- /* Soundchip port A/B as output. */
- sound_ym.rd_data_reg_sel = 7;
- sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
- /* STROBE high. */
- sound_ym.rd_data_reg_sel = 14;
- sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
- restore_flags(flags);
- /* MFP port I0 as input. */
- mfp.data_dir &= ~1;
- /* MFP port I0 interrupt on high->low edge. */
- mfp.active_edge &= ~1;
- p = parport_register_port((unsigned long)&sound_ym.wd_data,
- IRQ_MFP_BUSY, PARPORT_DMA_NONE,
- &parport_atari_ops);
- if (!p)
- return 0;
- if (request_irq(IRQ_MFP_BUSY, parport_atari_interrupt,
- IRQ_TYPE_SLOW, p->name, p)) {
- parport_unregister_port (p);
- return 0;
- }
-
- this_port = p;
- printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name);
- parport_proc_register(p);
-
- parport_announce_port (p);
-
- return 1;
- }
- return 0;
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Andreas Schwab");
-MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
-MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
-
-int
-init_module(void)
-{
- return parport_atari_init() ? 0 : -ENODEV;
-}
-
-void
-cleanup_module(void)
-{
- if (p->irq != PARPORT_IRQ_NONE)
- free_irq(IRQ_MFP_BUSY, p);
- parport_proc_unregister(this_port);
- parport_unregister_port(this_port);
-}
-#endif
+++ /dev/null
-/* $Id: parport_ax.c,v 1.20 1999/07/03 08:56:21 davem Exp $
- * Parallel-port routines for Sun Ultra/AX architecture
- *
- * Author: Eddie C. Dost <ecd@skynet.be>
- *
- * based on work by:
- * Phil Blundell <Philip.Blundell@pobox.com>
- * Tim Waugh <tim@cyberelk.demon.co.uk>
- * Jose Renau <renau@acm.org>
- * David Campbell <campbell@tirian.che.curtin.edu.au>
- * Grant Guenther <grant@torque.net>
- */
-
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/init.h>
-
-#include <linux/parport.h>
-
-#include <asm/ptrace.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/ebus.h>
-#include <asm/ns87303.h>
-#include <asm/irq.h>
-
-
-/*
- * Define this if you have Devices which don't support short
- * host read/write cycles.
- */
-#undef HAVE_SLOW_DEVICES
-
-
-#define DATA 0x00
-#define STATUS 0x01
-#define CONTROL 0x02
-#define EPPADDR 0x03
-#define EPPDATA 0x04
-
-#define CFIFO 0x400
-#define DFIFO 0x400
-#define TFIFO 0x400
-#define CONFIGA 0x400
-#define CONFIGB 0x401
-#define ECONTROL 0x402
-
-static void parport_ax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- parport_generic_irq(irq, (struct parport *) dev_id, regs);
-}
-
-void
-parport_ax_write_epp(struct parport *p, unsigned char d)
-{
- outb(d, p->base + EPPDATA);
-}
-
-unsigned char
-parport_ax_read_epp(struct parport *p)
-{
- return inb(p->base + EPPDATA);
-}
-
-void
-parport_ax_write_epp_addr(struct parport *p, unsigned char d)
-{
- outb(d, p->base + EPPADDR);
-}
-
-unsigned char
-parport_ax_read_epp_addr(struct parport *p)
-{
- return inb(p->base + EPPADDR);
-}
-
-int parport_ax_epp_clear_timeout(struct parport *pb);
-
-int
-parport_ax_check_epp_timeout(struct parport *p)
-{
- if (!(inb(p->base+STATUS) & 1))
- return 0;
- parport_ax_epp_clear_timeout(p);
- return 1;
-}
-
-unsigned char
-parport_ax_read_configb(struct parport *p)
-{
- return inb(p->base + CONFIGB);
-}
-
-void
-parport_ax_write_data(struct parport *p, unsigned char d)
-{
- outb(d, p->base + DATA);
-}
-
-unsigned char
-parport_ax_read_data(struct parport *p)
-{
- return inb(p->base + DATA);
-}
-
-void
-parport_ax_write_control(struct parport *p, unsigned char d)
-{
- outb(d, p->base + CONTROL);
-}
-
-unsigned char
-parport_ax_read_control(struct parport *p)
-{
- return inb(p->base + CONTROL);
-}
-
-unsigned char
-parport_ax_frob_control(struct parport *p, unsigned char mask, unsigned char val)
-{
- unsigned char old = inb(p->base + CONTROL);
- outb(((old & ~mask) ^ val), p->base + CONTROL);
- return old;
-}
-
-void
-parport_ax_write_status(struct parport *p, unsigned char d)
-{
- outb(d, p->base + STATUS);
-}
-
-unsigned char
-parport_ax_read_status(struct parport *p)
-{
- return inb(p->base + STATUS);
-}
-
-void
-parport_ax_write_econtrol(struct parport *p, unsigned char d)
-{
- outb(d, p->base + ECONTROL);
-}
-
-unsigned char
-parport_ax_read_econtrol(struct parport *p)
-{
- return inb(p->base + ECONTROL);
-}
-
-unsigned char
-parport_ax_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val)
-{
- unsigned char old = inb(p->base + ECONTROL);
- outb(((old & ~mask) ^ val), p->base + ECONTROL);
- return old;
-}
-
-void
-parport_ax_change_mode(struct parport *p, int m)
-{
- /* FIXME */
- parport_ax_frob_econtrol(p, 0xe0, m << 5);
-}
-
-void
-parport_ax_write_fifo(struct parport *p, unsigned char v)
-{
- outb(v, p->base + DFIFO);
-}
-
-unsigned char
-parport_ax_read_fifo(struct parport *p)
-{
- return inb(p->base + DFIFO);
-}
-
-void
-parport_ax_disable_irq(struct parport *p)
-{
- struct linux_ebus_dma *dma = p->private_data;
- unsigned int dcsr;
-
- dcsr = readl((unsigned long)&dma->dcsr);
- dcsr &= ~(EBUS_DCSR_INT_EN);
- writel(dcsr, (unsigned long)&dma->dcsr);
-}
-
-void
-parport_ax_enable_irq(struct parport *p)
-{
- struct linux_ebus_dma *dma = p->private_data;
- unsigned int dcsr;
-
- dcsr = readl((unsigned long)&dma->dcsr);
- dcsr |= EBUS_DCSR_INT_EN;
- writel(dcsr, (unsigned long)&dma->dcsr);
-}
-
-void
-parport_ax_init_state(struct pardevice *dev, struct parport_state *s)
-{
- struct linux_ebus_dma *dma = dev->port->private_data;
-
- s->u.ax.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
- s->u.ax.ecr = 0x0;
-
- if (dev->irq_func)
- s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
- | EBUS_DCSR_INT_EN);
- else
- s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
- & ~EBUS_DCSR_INT_EN);
-}
-
-void
-parport_ax_save_state(struct parport *p, struct parport_state *s)
-{
- struct linux_ebus_dma *dma = p->private_data;
-
- s->u.ax.ctr = parport_ax_read_control(p);
- s->u.ax.ecr = parport_ax_read_econtrol(p);
- s->u.ax.dcsr = readl((unsigned long)&dma->dcsr);
-}
-
-void
-parport_ax_restore_state(struct parport *p, struct parport_state *s)
-{
- struct linux_ebus_dma *dma = p->private_data;
-
- parport_ax_write_control(p, s->u.ax.ctr);
- parport_ax_write_econtrol(p, s->u.ax.ecr);
- writel(s->u.ax.dcsr, (unsigned long)&dma->dcsr);
-}
-
-void
-parport_ax_inc_use_count(void)
-{
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
-}
-
-void
-parport_ax_dec_use_count(void)
-{
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
-}
-
-static void parport_ax_fill_inode(struct inode *inode, int fill)
-{
-#ifdef MODULE
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-#endif
-}
-
-static struct parport_operations parport_ax_ops =
-{
- parport_ax_write_data,
- parport_ax_read_data,
-
- parport_ax_write_control,
- parport_ax_read_control,
- parport_ax_frob_control,
-
- parport_ax_read_status,
-
- parport_ax_enable_irq,
- parport_ax_disable_irq,
-
- parport_ax_data_forward,
- parport_ax_data_reverse,
-
- parport_ax_interrupt,
-
- parport_ax_init_state,
- parport_ax_save_state,
- parport_ax_restore_state,
-
- parport_ax_inc_use_count,
- parport_ax_dec_use_count,
- parport_ax_fill_inode,
-
- parport_ieee1284_epp_write_data,
- parport_ieee1284_epp_read_data,
- parport_ieee1284_epp_write_addr,
- parport_ieee1284_epp_read_addr,
-
- parport_ieee1284_ecp_write_data,
- parport_ieee1284_ecp_read_data,
- parport_ieee1284_ecp_write_addr,
-
- parport_ieee1284_write_compat,
- parport_ieee1284_read_nibble,
- parport_ieee1284_read_byte,
-};
-
-
-/******************************************************
- * MODE detection section:
- */
-
-/*
- * Clear TIMEOUT BIT in EPP MODE
- */
-int parport_ax_epp_clear_timeout(struct parport *pb)
-{
- unsigned char r;
-
- if (!(parport_ax_read_status(pb) & 0x01))
- return 1;
-
- /* To clear timeout some chips require double read */
- parport_ax_read_status(pb);
- r = parport_ax_read_status(pb);
- parport_ax_write_status(pb, r | 0x01); /* Some reset by writing 1 */
- parport_ax_write_status(pb, r & 0xfe); /* Others by writing 0 */
- r = parport_ax_read_status(pb);
-
- return !(r & 0x01);
-}
-
-/* Check for ECP
- *
- * Old style XT ports alias io ports every 0x400, hence accessing ECONTROL
- * on these cards actually accesses the CTR.
- *
- * Modern cards don't do this but reading from ECONTROL will return 0xff
- * regardless of what is written here if the card does NOT support
- * ECP.
- *
- * We will write 0x2c to ECONTROL and 0xcc to CTR since both of these
- * values are "safe" on the CTR since bits 6-7 of CTR are unused.
- */
-static int parport_ECR_present(struct parport *pb)
-{
- unsigned int r;
- unsigned char octr = pb->ops->read_control(pb),
- oecr = pb->ops->read_econtrol(pb);
-
- r = pb->ops->read_control(pb);
- if ((pb->ops->read_econtrol(pb) & 0x3) == (r & 0x3)) {
- pb->ops->write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */
-
- r = pb->ops->read_control(pb);
- if ((pb->ops->read_econtrol(pb) & 0x2) == (r & 0x2)) {
- pb->ops->write_control(pb, octr);
- return 0; /* Sure that no ECONTROL register exists */
- }
- }
-
- if ((pb->ops->read_econtrol(pb) & 0x3 ) != 0x1)
- return 0;
-
- pb->ops->write_econtrol(pb, 0x34);
- if (pb->ops->read_econtrol(pb) != 0x35)
- return 0;
-
- pb->ops->write_econtrol(pb, oecr);
- pb->ops->write_control(pb, octr);
-
- return PARPORT_MODE_PCECR;
-}
-
-static int parport_ECP_supported(struct parport *pb)
-{
- int i;
- unsigned char oecr = pb->ops->read_econtrol(pb);
-
- /* If there is no ECONTROL, we have no hope of supporting ECP. */
- if (!(pb->modes & PARPORT_MODE_PCECR))
- return 0;
-
- /*
- * Using LGS chipset it uses ECONTROL register, but
- * it doesn't support ECP or FIFO MODE
- */
-
- pb->ops->write_econtrol(pb, 0xc0); /* TEST FIFO */
- for (i=0; i < 1024 && (pb->ops->read_econtrol(pb) & 0x01); i++)
- pb->ops->write_fifo(pb, 0xaa);
-
- pb->ops->write_econtrol(pb, oecr);
- return (i == 1024) ? 0 : PARPORT_MODE_PCECP;
-}
-
-/* Detect PS/2 support.
- *
- * Bit 5 (0x20) sets the PS/2 data direction; setting this high
- * allows us to read data from the data lines. In theory we would get back
- * 0xff but any peripheral attached to the port may drag some or all of the
- * lines down to zero. So if we get back anything that isn't the contents
- * of the data register we deem PS/2 support to be present.
- *
- * Some SPP ports have "half PS/2" ability - you can't turn off the line
- * drivers, but an external peripheral with sufficiently beefy drivers of
- * its own can overpower them and assert its own levels onto the bus, from
- * where they can then be read back as normal. Ports with this property
- * and the right type of device attached are likely to fail the SPP test,
- * (as they will appear to have stuck bits) and so the fact that they might
- * be misdetected here is rather academic.
- */
-
-static int parport_PS2_supported(struct parport *pb)
-{
- int ok = 0;
- unsigned char octr = pb->ops->read_control(pb);
-
- pb->ops->write_control(pb, octr | 0x20); /* try to tri-state buffer */
-
- pb->ops->write_data(pb, 0x55);
- if (pb->ops->read_data(pb) != 0x55) ok++;
-
- pb->ops->write_data(pb, 0xaa);
- if (pb->ops->read_data(pb) != 0xaa) ok++;
-
- pb->ops->write_control(pb, octr); /* cancel input mode */
-
- return ok ? PARPORT_MODE_PCPS2 : 0;
-}
-
-static int parport_ECPPS2_supported(struct parport *pb)
-{
- int mode;
- unsigned char oecr = pb->ops->read_econtrol(pb);
-
- if (!(pb->modes & PARPORT_MODE_PCECR))
- return 0;
-
- pb->ops->write_econtrol(pb, 0x20);
-
- mode = parport_PS2_supported(pb);
-
- pb->ops->write_econtrol(pb, oecr);
- return mode ? PARPORT_MODE_PCECPPS2 : 0;
-}
-
-#define printmode(x) \
-{ \
- if (p->modes & PARPORT_MODE_PC##x) { \
- printk("%s%s", f ? "," : "", #x); \
- f++; \
- } \
-}
-
-int
-init_one_port(struct linux_ebus_device *dev)
-{
- struct parport tmpport, *p;
- unsigned long base;
- unsigned long config;
- unsigned char tmp;
- int irq, dma;
-
- /* Pointer to NS87303 Configuration Registers */
- config = dev->base_address[1];
-
- /* Setup temporary access to Device operations */
- tmpport.base = dev->base_address[0];
- tmpport.ops = &parport_ax_ops;
-
- /* Enable ECP mode, set bit 2 of the CTR first */
- tmpport.ops->write_control(&tmpport, 0x04);
- tmp = ns87303_readb(config, PCR);
- tmp |= (PCR_EPP_IEEE | PCR_ECP_ENABLE | PCR_ECP_CLK_ENA);
- ns87303_writeb(config, PCR, tmp);
-
- /* LPT CTR bit 5 controls direction of parallel port */
- tmp = ns87303_readb(config, PTR);
- tmp |= PTR_LPT_REG_DIR;
- ns87303_writeb(config, PTR, tmp);
-
- /* Configure IRQ to Push Pull, Level Low */
- tmp = ns87303_readb(config, PCR);
- tmp &= ~(PCR_IRQ_ODRAIN);
- tmp |= PCR_IRQ_POLAR;
- ns87303_writeb(config, PCR, tmp);
-
-#ifndef HAVE_SLOW_DEVICES
- /* Enable Zero Wait State for ECP */
- tmp = ns87303_readb(config, FCR);
- tmp |= FCR_ZWS_ENA;
- ns87303_writeb(config, FCR, tmp);
-#endif
-
- /*
- * Now continue initializing the port
- */
- base = dev->base_address[0];
- irq = dev->irqs[0];
- dma = PARPORT_DMA_AUTO;
-
- if (!(p = parport_register_port(base, irq, dma, &parport_ax_ops)))
- return 0;
-
- /* Save away pointer to our EBus DMA */
- p->private_data = (void *)dev->base_address[2];
-
- p->modes = PARPORT_MODE_PCSPP | parport_PS2_supported(p);
- if (!check_region(p->base + 0x400, 3)) {
- p->modes |= parport_ECR_present(p);
- p->modes |= parport_ECP_supported(p);
- p->modes |= parport_ECPPS2_supported(p);
- }
- p->size = 3;
-
- if (p->dma == PARPORT_DMA_AUTO)
- p->dma = (p->modes & PARPORT_MODE_PCECP) ? 0 : PARPORT_DMA_NONE;
-
- printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
- if (p->irq != PARPORT_IRQ_NONE)
- printk(", irq %s", __irq_itoa(p->irq));
- if (p->dma != PARPORT_DMA_NONE)
- printk(", dma %d", p->dma);
- printk(" [");
- {
- int f = 0;
- printmode(SPP);
- printmode(PS2);
- printmode(ECP);
- printmode(ECPPS2);
- }
- printk("]\n");
- parport_proc_register(p);
-
- if (p->irq != PARPORT_IRQ_NONE)
- if ((err = request_irq(p->irq, parport_ax_interrupt,
- 0, p->name, p)) != 0)
- return 0; /* @@@ FIXME */
-
- request_region(p->base, p->size, p->name);
- if (p->modes & PARPORT_MODE_PCECR)
- request_region(p->base+0x400, 3, p->name);
- request_region((unsigned long)p->private_data,
- sizeof(struct linux_ebus_dma), p->name);
-
- p->ops->write_control(p, 0x0c);
- p->ops->write_data(p, 0);
-
- /* Tell the high-level drivers about the port. */
- parport_announce_port (p);
-
- return 1;
-}
-
-EXPORT_NO_SYMBOLS;
-
-#ifdef MODULE
-int init_module(void)
-#else
-__initfunc(int parport_ax_init(void))
-#endif
-{
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev;
- int count = 0;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "ecpp"))
- count += init_one_port(edev);
- }
- }
- return count ? 0 : -ENODEV;
-}
-
-#ifdef MODULE
-void
-cleanup_module(void)
-{
- struct parport *p = parport_enumerate(), *tmp;
- while (p) {
- tmp = p->next;
- if (p->modes & PARPORT_MODE_PCSPP) {
- if (p->irq != PARPORT_IRQ_NONE) {
- parport_ax_disable_irq(p);
- free_irq(p->irq, p);
- }
- release_region(p->base, p->size);
- if (p->modes & PARPORT_MODE_PCECR)
- release_region(p->base+0x400, 3);
- release_region((unsigned long)p->private_data,
- sizeof(struct linux_ebus_dma));
- parport_proc_unregister(p);
- parport_unregister_port(p);
- }
- p = tmp;
- }
-}
-#endif
+++ /dev/null
-/*
- * IEEE 1284.3 Parallel port daisy chain and multiplexor code
- *
- * Copyright (C) 1999 Tim Waugh <tim@cyberelk.demon.co.uk>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * ??-12-1998: Initial implementation.
- * 31-01-1999: Make port-cloning transparent.
- * 13-02-1999: Move DeviceID technique from parport_probe.
- * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too.
- *
- */
-
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-
-#define DEBUG /* undef me for production */
-
-#ifdef DEBUG
-#define DPRINTK(stuff...) printk (stuff)
-#else
-#define DPRINTK(stuff...)
-#endif
-
-static struct daisydev {
- struct daisydev *next;
- struct parport *port;
- int daisy;
- int devnum;
-} *topology = NULL;
-
-static int numdevs = 0;
-
-/* Forward-declaration of lower-level functions. */
-static int mux_present (struct parport *port);
-static int num_mux_ports (struct parport *port);
-static int select_port (struct parport *port);
-static int assign_addrs (struct parport *port);
-
-/* Add a device to the discovered topology. */
-static void add_dev (int devnum, struct parport *port, int daisy)
-{
- struct daisydev *newdev;
- newdev = kmalloc (GFP_KERNEL, sizeof (struct daisydev));
- if (newdev) {
- newdev->port = port;
- newdev->daisy = daisy;
- newdev->devnum = devnum;
- newdev->next = topology;
- if (!topology || topology->devnum >= devnum)
- topology = newdev;
- else {
- struct daisydev *prev = topology;
- while (prev->next && prev->next->devnum < devnum)
- prev = prev->next;
- newdev->next = prev->next;
- prev->next = newdev;
- }
- }
-}
-
-/* Clone a parport (actually, make an alias). */
-static struct parport *clone_parport (struct parport *real, int muxport)
-{
- struct parport *extra = parport_register_port (real->base,
- real->irq,
- real->dma,
- real->ops);
- if (extra) {
- extra->portnum = real->portnum;
- extra->physport = real;
- extra->muxport = muxport;
- }
-
- return extra;
-}
-
-/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */
-int parport_daisy_init (struct parport *port)
-{
- char *deviceid;
- static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
- int num_ports;
- int i;
-
- /* Because this is called before any other devices exist,
- * we don't have to claim exclusive access. */
-
- /* If mux present on normal port, need to create new
- * parports for each extra port. */
- if (port->muxport < 0 && mux_present (port) &&
- /* don't be fooled: a mux must have 2 or 4 ports. */
- ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) {
- /* Leave original as port zero. */
- port->muxport = 0;
- printk (KERN_INFO
- "%s: 1st (default) port of %d-way multiplexor\n",
- port->name, num_ports);
- for (i = 1; i < num_ports; i++) {
- /* Clone the port. */
- struct parport *extra = clone_parport (port, i);
- if (!extra) {
- if (signal_pending (current))
- break;
-
- schedule ();
- continue;
- }
-
- printk (KERN_INFO
- "%s: %d%s port of %d-way multiplexor on %s\n",
- extra->name, i + 1, th[i + 1], num_ports,
- port->name);
-
- /* Analyse that port too. We won't recurse
- forever because of the 'port->muxport < 0'
- test above. */
- parport_announce_port (extra);
- }
- }
-
- if (port->muxport >= 0)
- select_port (port);
-
- parport_daisy_deselect_all (port);
- assign_addrs (port);
-
- /* Count the potential legacy device at the end. */
- add_dev (numdevs++, port, -1);
-
- /* Find out the legacy device's IEEE 1284 device ID. */
- deviceid = kmalloc (1000, GFP_KERNEL);
- if (deviceid) {
- parport_device_id (numdevs - 1, deviceid, 1000);
- kfree (deviceid);
- }
-
- return 0;
-}
-
-/* Forget about devices on a physical port. */
-void parport_daisy_fini (struct parport *port)
-{
- struct daisydev *dev, *prev = topology;
- while (prev && prev->port == port)
- prev = topology = topology->next;
-
- while (prev) {
- dev = prev->next;
- if (dev && dev->port == port)
- prev->next = dev->next;
-
- prev = prev->next;
- }
-
- /* Gaps in the numbering could be handled better. How should
- someone enumerate through all IEEE1284.3 devices in the
- topology?. */
- if (!topology) numdevs = 0;
- return; }
-
-/* Find a device by canonical device number. */
-struct pardevice *parport_open (int devnum, const char *name,
- int (*pf) (void *), void (*kf) (void *),
- void (*irqf) (int, void *, struct pt_regs *),
- int flags, void *handle)
-{
- struct parport *port = parport_enumerate ();
- struct pardevice *dev;
- int portnum;
- int muxnum;
- int daisynum;
-
- if (parport_device_coords (devnum, &portnum, &muxnum, &daisynum))
- return NULL;
-
- while (port && ((port->portnum != portnum) ||
- (port->muxport != muxnum)))
- port = port->next;
-
- if (!port)
- /* No corresponding parport. */
- return NULL;
-
- dev = parport_register_device (port, name, pf, kf,
- irqf, flags, handle);
- if (dev)
- dev->daisy = daisynum;
-
- /* Check that there really is a device to select. */
- if (daisynum >= 0) {
- int selected;
- parport_claim_or_block (dev);
- selected = port->daisy;
- parport_release (dev);
-
- if (selected != port->daisy) {
- /* No corresponding device. */
- parport_unregister_device (dev);
- return NULL;
- }
- }
-
- return dev;
-}
-
-/* The converse of parport_open. */
-void parport_close (struct pardevice *dev)
-{
- parport_unregister_device (dev);
-}
-
-/* Convert device coordinates into a canonical device number. */
-int parport_device_num (int parport, int mux, int daisy)
-{
- struct daisydev *dev = topology;
-
- while (dev && dev->port->portnum != parport &&
- dev->port->muxport != mux && dev->daisy != daisy)
- dev = dev->next;
-
- if (!dev)
- return -ENXIO;
-
- return dev->devnum;
-}
-
-/* Convert a canonical device number into device coordinates. */
-int parport_device_coords (int devnum, int *parport, int *mux, int *daisy)
-{
- struct daisydev *dev = topology;
-
- while (dev && dev->devnum != devnum)
- dev = dev->next;
-
- if (!dev)
- return -ENXIO;
-
- if (parport) *parport = dev->port->portnum;
- if (mux) *mux = dev->port->muxport;
- if (daisy) *daisy = dev->daisy;
- return 0;
-}
-
-/* Send a daisy-chain-style CPP command packet. */
-static int cpp_daisy (struct parport *port, int cmd)
-{
- unsigned char s;
-
- parport_write_data (port, 0xaa); udelay (2);
- parport_write_data (port, 0x55); udelay (2);
- parport_write_data (port, 0x00); udelay (2);
- parport_write_data (port, 0xff); udelay (2);
- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
- | PARPORT_STATUS_PAPEROUT
- | PARPORT_STATUS_SELECT
- | PARPORT_STATUS_ERROR);
- if (s != (PARPORT_STATUS_BUSY
- | PARPORT_STATUS_PAPEROUT
- | PARPORT_STATUS_SELECT
- | PARPORT_STATUS_ERROR)) {
- DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
- port->name, s);
- return -ENXIO;
- }
-
- parport_write_data (port, 0x87); udelay (2);
- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
- | PARPORT_STATUS_PAPEROUT
- | PARPORT_STATUS_SELECT
- | PARPORT_STATUS_ERROR);
- if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
- DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
- port->name, s);
- return -ENXIO;
- }
-
- parport_write_data (port, 0x78); udelay (2);
- parport_write_data (port, cmd); udelay (2);
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_STROBE);
- udelay (1);
- parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
- udelay (1);
- s = parport_read_status (port);
- parport_write_data (port, 0xff); udelay (2);
-
- return s;
-}
-
-/* Send a mux-style CPP command packet. */
-static int cpp_mux (struct parport *port, int cmd)
-{
- unsigned char s;
- int rc;
-
- parport_write_data (port, 0xaa); udelay (2);
- parport_write_data (port, 0x55); udelay (2);
- parport_write_data (port, 0xf0); udelay (2);
- parport_write_data (port, 0x0f); udelay (2);
- parport_write_data (port, 0x52); udelay (2);
- parport_write_data (port, 0xad); udelay (2);
- parport_write_data (port, cmd); udelay (2);
-
- s = parport_read_status (port);
- if (!(s & PARPORT_STATUS_ACK)) {
- DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
- port->name, cmd, s);
- return -EIO;
- }
-
- rc = (((s & PARPORT_STATUS_SELECT ? 1 : 0) << 0) |
- ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) |
- ((s & PARPORT_STATUS_BUSY ? 0 : 1) << 2) |
- ((s & PARPORT_STATUS_ERROR ? 0 : 1) << 3));
-
- return rc;
-}
-
-void parport_daisy_deselect_all (struct parport *port)
-{
- cpp_daisy (port, 0x30);
-}
-
-int parport_daisy_select (struct parport *port, int daisy, int mode)
-{
- /* mode is currently ignored. FIXME? */
- return cpp_daisy (port, 0xe0 + daisy) & PARPORT_STATUS_ERROR;
-}
-
-static int mux_present (struct parport *port)
-{
- return cpp_mux (port, 0x51) == 3;
-}
-
-static int num_mux_ports (struct parport *port)
-{
- return cpp_mux (port, 0x58);
-}
-
-static int select_port (struct parport *port)
-{
- int muxport = port->muxport;
- return cpp_mux (port, 0x60 + muxport) == muxport;
-}
-
-static int assign_addrs (struct parport *port)
-{
- unsigned char s, last_dev;
- unsigned char daisy;
- int thisdev = numdevs;
- char *deviceid;
-
- parport_write_data (port, 0xaa); udelay (2);
- parport_write_data (port, 0x55); udelay (2);
- parport_write_data (port, 0x00); udelay (2);
- parport_write_data (port, 0xff); udelay (2);
- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
- | PARPORT_STATUS_PAPEROUT
- | PARPORT_STATUS_SELECT
- | PARPORT_STATUS_ERROR);
- if (s != (PARPORT_STATUS_BUSY
- | PARPORT_STATUS_PAPEROUT
- | PARPORT_STATUS_SELECT
- | PARPORT_STATUS_ERROR)) {
- DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
- port->name, s);
- return -ENXIO;
- }
-
- parport_write_data (port, 0x87); udelay (2);
- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
- | PARPORT_STATUS_PAPEROUT
- | PARPORT_STATUS_SELECT
- | PARPORT_STATUS_ERROR);
- if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
- DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
- port->name, s);
- return -ENXIO;
- }
-
- parport_write_data (port, 0x78); udelay (2);
- last_dev = 0; /* We've just been speaking to a device, so we
- know there must be at least _one_ out there. */
-
- for (daisy = 0; daisy < 4; daisy++) {
- parport_write_data (port, daisy);
- udelay (2);
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_STROBE);
- udelay (1);
- parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
- udelay (1);
-
- if (last_dev)
- /* No more devices. */
- break;
-
- last_dev = !(parport_read_status (port)
- & PARPORT_STATUS_BUSY);
-
- add_dev (numdevs++, port, daisy);
- }
-
- parport_write_data (port, 0xff); udelay (2);
- DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
- numdevs - thisdev);
-
- /* Ask the new devices to introduce themselves. */
- deviceid = kmalloc (1000, GFP_KERNEL);
- if (!deviceid) return 0;
-
- for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
- parport_device_id (thisdev, deviceid, 1000);
-
- kfree (deviceid);
- return 0;
-}
-
-/* Find a device with a particular manufacturer and model string,
- starting from a given device number. Like the PCI equivalent,
- 'from' itself is skipped. */
-int parport_find_device (const char *mfg, const char *mdl, int from)
-{
- struct daisydev *d = topology; /* sorted by devnum */
-
- /* Find where to start. */
- while (d && d->devnum <= from)
- d = d->next;
-
- /* Search. */
- while (d) {
- struct parport_device_info *info;
- info = &d->port->probe_info[1 + d->daisy];
- if ((!mfg || !strcmp (mfg, info->mfr)) &&
- (!mdl || !strcmp (mdl, info->model)))
- break;
-
- d = d->next;
- }
-
- if (d)
- return d->devnum;
-
- return -1;
-}
-
-/* Find a device in a particular class. Like the PCI equivalent,
- 'from' itself is skipped. */
-int parport_find_class (parport_device_class cls, int from)
-{
- struct daisydev *d = topology; /* sorted by devnum */
-
- /* Find where to start. */
- while (d && d->devnum <= from)
- d = d->next;
-
- /* Search. */
- while (d && d->port->probe_info[1 + d->daisy].class != cls)
- d = d->next;
-
- if (d)
- return d->devnum;
-
- return -1;
-}
+++ /dev/null
-/* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $
- * IEEE-1284 implementation for parport.
- *
- * Authors: Phil Blundell <Philip.Blundell@pobox.com>
- * Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
- * Jose Renau <renau@acm.org>
- * Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten)
- *
- * This file is responsible for IEEE 1284 negotiation, and for handing
- * read/write requests to low-level drivers.
- */
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-
-#undef DEBUG /* undef me for production */
-
-#ifdef CONFIG_LP_CONSOLE
-#undef DEBUG /* Don't want a garbled console */
-#endif
-
-#ifdef DEBUG
-#define DPRINTK(stuff...) printk (stuff)
-#else
-#define DPRINTK(stuff...)
-#endif
-
-/* Make parport_wait_peripheral wake up.
- * It will be useful to call this from an interrupt handler. */
-void parport_ieee1284_wakeup (struct parport *port)
-{
- up (&port->physport->ieee1284.irq);
-}
-
-static struct parport *port_from_cookie[PARPORT_MAX];
-static void timeout_waiting_on_port (unsigned long cookie)
-{
- parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]);
-}
-
-/* Wait for a parport_ieee1284_wakeup.
- * 0: success
- * <0: error (exit as soon as possible)
- * >0: timed out
- */
-int parport_wait_event (struct parport *port, signed long timeout)
-{
- int ret;
- struct timer_list timer;
-
- if (!port->physport->cad->timeout)
- /* Zero timeout is special, and we can't down() the
- semaphore. */
- return 1;
-
- init_timer (&timer);
- timer.expires = jiffies + timeout;
- timer.function = timeout_waiting_on_port;
- port_from_cookie[port->number % PARPORT_MAX] = port;
- timer.data = port->number;
-
- add_timer (&timer);
- ret = down_interruptible (&port->physport->ieee1284.irq);
- if (!del_timer (&timer) && !ret)
- /* Timed out. */
- ret = 1;
-
- return ret;
-}
-
-/* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to
- * 25 for this. After this time we can create a timeout because the
- * peripheral doesn't conform to IEEE1284. We want to save CPU time: we are
- * waiting a maximum time of 500 us busy (this is for speed). If there is
- * not the right answer in this time, we call schedule and other processes
- * are able to eat the time up to 40ms.
- */
-
-int parport_wait_peripheral(struct parport *port,
- unsigned char mask,
- unsigned char result)
-{
- int counter;
- long deadline;
- unsigned char status;
-
- counter = port->physport->spintime; /* usecs of fast polling */
- if (!port->physport->cad->timeout)
- /* A zero timeout is "special": busy wait for the
- entire 35ms. */
- counter = 35000;
-
- /* Fast polling.
- *
- * This should be adjustable.
- * How about making a note (in the device structure) of how long
- * it takes, so we know for next time?
- */
- for (counter /= 5; counter > 0; counter--) {
- status = parport_read_status (port);
- if ((status & mask) == result)
- return 0;
- if (signal_pending (current))
- return -EINTR;
- if (current->need_resched)
- break;
- udelay(5);
- }
-
- if (!port->physport->cad->timeout)
- /* We may be in an interrupt handler, so we can't poll
- * slowly anyway. */
- return 1;
-
- /* 40ms of slow polling. */
- deadline = jiffies + (HZ + 24) / 25;
- while (time_before (jiffies, deadline)) {
- int ret;
-
- if (signal_pending (current))
- return -EINTR;
-
- /* Wait for 10ms (or until an interrupt occurs if
- * the handler is set) */
- if ((ret = parport_wait_event (port, (HZ + 99) / 100)) < 0)
- return ret;
-
- status = parport_read_status (port);
- if ((status & mask) == result)
- return 0;
-
- if (!ret) {
- /* parport_wait_event didn't time out, but the
- * peripheral wasn't actually ready either.
- * Wait for another 10ms. */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout ((HZ+ 99) / 100);
- }
- }
-
- return 1;
-}
-
-#ifdef CONFIG_PARPORT_1284
-/* Terminate a negotiated mode. */
-static void parport_ieee1284_terminate (struct parport *port)
-{
- port = port->physport;
-
- port->ieee1284.phase = IEEE1284_PH_TERMINATE;
-
- /* EPP terminates differently. */
- switch (port->ieee1284.mode) {
- case IEEE1284_MODE_EPP:
- case IEEE1284_MODE_EPPSL:
- case IEEE1284_MODE_EPPSWE:
- /* Terminate from EPP mode. */
-
- /* Event 68: Set nInit low */
- parport_frob_control (port,
- PARPORT_CONTROL_INIT,
- PARPORT_CONTROL_INIT);
- udelay (50);
-
- /* Event 69: Set nInit high, nSelectIn low */
- parport_frob_control (port,
- PARPORT_CONTROL_SELECT,
- PARPORT_CONTROL_SELECT);
- break;
-
- default:
- /* Terminate from all other modes. */
-
- /* Event 22: Set nSelectIn low, nAutoFd high */
- parport_frob_control (port,
- PARPORT_CONTROL_SELECT
- | PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_SELECT);
-
- /* Event 24: nAck goes low */
- parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0);
-
- /* Event 25: Set nAutoFd low */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- /* Event 27: nAck goes high */
- parport_wait_peripheral (port,
- PARPORT_STATUS_ACK,
- PARPORT_STATUS_ACK);
-
- /* Event 29: Set nAutoFd high */
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
- }
-
- port->ieee1284.mode = IEEE1284_MODE_COMPAT;
- port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
- DPRINTK (KERN_DEBUG "%s: In compatibility (forward idle) mode\n",
- port->name);
-}
-#endif /* IEEE1284 support */
-
-/* Negotiate an IEEE 1284 mode.
- * return values are:
- * 0 - handshake OK; IEEE1284 peripheral and mode available
- * -1 - handshake failed; peripheral is not compliant (or none present)
- * 1 - handshake OK; IEEE1284 peripheral present but mode not available
- */
-int parport_negotiate (struct parport *port, int mode)
-{
-#ifndef CONFIG_PARPORT_1284
- if (mode == IEEE1284_MODE_COMPAT)
- return 0;
- printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
- return -1;
-#else
- int m = mode & ~IEEE1284_ADDR;
- unsigned char xflag;
-
- port = port->physport;
-
- /* Is there anything to do? */
- if (port->ieee1284.mode == mode)
- return 0;
-
- /* Is the difference just an address-or-not bit? */
- if ((port->ieee1284.mode & ~IEEE1284_ADDR) == (mode & ~IEEE1284_ADDR)){
- port->ieee1284.mode = mode;
- return 0;
- }
-
- /* Go to compability forward idle mode */
- if (port->ieee1284.mode != IEEE1284_MODE_COMPAT)
- parport_ieee1284_terminate (port);
-
- if (mode == IEEE1284_MODE_COMPAT)
- /* Compatibility mode: no negotiation. */
- return 0;
-
- switch (mode) {
- case IEEE1284_MODE_ECPSWE:
- m = IEEE1284_MODE_ECP;
- break;
- case IEEE1284_MODE_EPPSL:
- case IEEE1284_MODE_EPPSWE:
- m = IEEE1284_MODE_EPP;
- break;
- case IEEE1284_MODE_BECP:
- return -ENOSYS; /* FIXME (implement BECP) */
- }
-
- port->ieee1284.phase = IEEE1284_PH_NEGOTIATION;
-
- /* Start off with nStrobe and nAutoFd high, and nSelectIn low */
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE
- | PARPORT_CONTROL_AUTOFD
- | PARPORT_CONTROL_SELECT,
- PARPORT_CONTROL_SELECT);
- udelay(1);
-
- /* Event 0: Set data */
- parport_write_data (port, m);
- udelay (400); /* Shouldn't need to wait this long. */
-
- /* Event 1: Set nSelectIn high, nAutoFd low */
- parport_frob_control (port,
- PARPORT_CONTROL_SELECT
- | PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- /* Event 2: PError, Select, nFault go high, nAck goes low */
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ERROR
- | PARPORT_STATUS_SELECT
- | PARPORT_STATUS_PAPEROUT
- | PARPORT_STATUS_ACK,
- PARPORT_STATUS_ERROR
- | PARPORT_STATUS_SELECT
- | PARPORT_STATUS_PAPEROUT)) {
- /* Timeout */
- parport_frob_control (port,
- PARPORT_CONTROL_SELECT
- | PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_SELECT);
- DPRINTK (KERN_DEBUG
- "%s: Peripheral not IEEE1284 compliant (0x%02X)\n",
- port->name, parport_read_status (port));
- port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
- return -1; /* Not IEEE1284 compliant */
- }
-
- /* Event 3: Set nStrobe low */
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_STROBE);
-
- /* Event 4: Set nStrobe and nAutoFd high */
- udelay (5);
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE
- | PARPORT_CONTROL_AUTOFD,
- 0);
-
- /* Event 6: nAck goes high */
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK
- | PARPORT_STATUS_PAPEROUT,
- PARPORT_STATUS_ACK)) {
- if (parport_read_status (port) & PARPORT_STATUS_ACK)
- printk (KERN_DEBUG
- "%s: working around buggy peripheral: tell "
- "Tim what make it is\n", port->name);
- DPRINTK (KERN_DEBUG
- "%s: Mode 0x%02x not supported? (0x%02x)\n",
- port->name, mode, port->ops->read_status (port));
- parport_ieee1284_terminate (port);
- return 1;
- }
-
- xflag = parport_read_status (port) & PARPORT_STATUS_SELECT;
-
- /* xflag should be high for all modes other than nibble (0). */
- if (mode && !xflag) {
- /* Mode not supported. */
- DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported\n",
- port->name, mode);
- parport_ieee1284_terminate (port);
- return 1;
- }
-
- /* Mode is supported */
- DPRINTK (KERN_DEBUG "%s: In mode 0x%02x\n", port->name, mode);
- port->ieee1284.mode = mode;
-
- /* But ECP is special */
- if (mode & IEEE1284_MODE_ECP) {
- port->ieee1284.phase = IEEE1284_PH_ECP_SETUP;
-
- /* Event 30: Set nAutoFd low */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- /* Event 31: PError goes high. */
- parport_wait_peripheral (port,
- PARPORT_STATUS_PAPEROUT,
- PARPORT_STATUS_PAPEROUT);
- /* (Should check that this works..) */
-
- port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
- DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
- port->name);
- } else switch (mode) {
- case IEEE1284_MODE_NIBBLE:
- case IEEE1284_MODE_BYTE:
- port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
- break;
- default:
- port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
- }
-
-
- return 0;
-#endif /* IEEE1284 support */
-}
-
-/* Acknowledge that the peripheral has data available.
- * Events 18-20, in order to get from Reverse Idle phase
- * to Host Busy Data Available.
- * This will most likely be called from an interrupt.
- * Returns zero if data was available.
- */
-#ifdef CONFIG_PARPORT_1284
-static int parport_ieee1284_ack_data_avail (struct parport *port)
-{
- if (parport_read_status (port) & PARPORT_STATUS_ERROR)
- /* Event 18 didn't happen. */
- return -1;
-
- /* Event 20: nAutoFd goes high. */
- port->ops->frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
- port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
- return 0;
-}
-#endif /* IEEE1284 support */
-
-/* Handle an interrupt. */
-void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs)
-{
- struct parport *port = handle;
- parport_ieee1284_wakeup (port);
-
-#ifdef CONFIG_PARPORT_1284
- if (port->ieee1284.phase == IEEE1284_PH_REV_IDLE) {
- /* An interrupt in this phase means that data
- * is now available. */
- DPRINTK (KERN_DEBUG "%s: Data available\n", port->name);
- parport_ieee1284_ack_data_avail (port);
- }
-#endif /* IEEE1284 support */
-}
-
-/* Write a block of data. */
-ssize_t parport_write (struct parport *port, const void *buffer, size_t len)
-{
-#ifndef CONFIG_PARPORT_1284
- return port->ops->compat_write_data (port, buffer, len, 0);
-#else
- ssize_t retval;
- int mode = port->ieee1284.mode;
- int addr = mode & IEEE1284_ADDR;
- size_t (*fn) (struct parport *, const void *, size_t, int);
-
- /* Ignore the device-ID-request bit and the address bit. */
- mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
-
- /* Use the mode we're in. */
- switch (mode) {
- case IEEE1284_MODE_NIBBLE:
- parport_negotiate (port, IEEE1284_MODE_COMPAT);
- case IEEE1284_MODE_COMPAT:
- DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n",
- port->name);
- fn = port->ops->compat_write_data;
- break;
-
- case IEEE1284_MODE_EPP:
- DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
- if (addr)
- fn = port->ops->epp_write_addr;
- else
- fn = port->ops->epp_write_data;
- break;
-
- case IEEE1284_MODE_ECP:
- case IEEE1284_MODE_ECPRLE:
- DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
- if (addr)
- fn = port->ops->ecp_write_addr;
- else
- fn = port->ops->ecp_write_data;
- break;
-
- case IEEE1284_MODE_ECPSWE:
- DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
- port->name);
- /* The caller has specified that it must be emulated,
- * even if we have ECP hardware! */
- if (addr)
- fn = parport_ieee1284_ecp_write_addr;
- else
- fn = parport_ieee1284_ecp_write_data;
- break;
-
- default:
- DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
- port->ieee1284.mode);
- return -ENOSYS;
- }
-
- retval = (*fn) (port, buffer, len, 0);
- DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval,
- len);
- return retval;
-#endif /* IEEE1284 support */
-}
-
-/* Read a block of data. */
-ssize_t parport_read (struct parport *port, void *buffer, size_t len)
-{
-#ifndef CONFIG_PARPORT_1284
- printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
- return -ENODEV;
-#else
- int mode = port->physport->ieee1284.mode;
- int addr = mode & IEEE1284_ADDR;
- size_t (*fn) (struct parport *, void *, size_t, int);
-
- /* Ignore the device-ID-request bit and the address bit. */
- mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
-
- /* Use the mode we're in. */
- switch (mode) {
- case IEEE1284_MODE_COMPAT:
- if (parport_negotiate (port, IEEE1284_MODE_NIBBLE))
- return -EIO;
- case IEEE1284_MODE_NIBBLE:
- DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name);
- fn = port->ops->nibble_read_data;
- break;
-
- case IEEE1284_MODE_BYTE:
- DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name);
- fn = port->ops->byte_read_data;
- break;
-
- case IEEE1284_MODE_EPP:
- DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
- if (addr)
- fn = port->ops->epp_read_addr;
- else
- fn = port->ops->epp_read_data;
- break;
-
- case IEEE1284_MODE_ECP:
- case IEEE1284_MODE_ECPRLE:
- DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
- fn = port->ops->ecp_read_data;
- break;
-
- case IEEE1284_MODE_ECPSWE:
- DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
- port->name);
- fn = parport_ieee1284_ecp_read_data;
- break;
-
- default:
- DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
- port->physport->ieee1284.mode);
- return -ENOSYS;
- }
-
- return (*fn) (port, buffer, len, 0);
-#endif /* IEEE1284 support */
-}
-
-/* Set the amount of time we wait while nothing's happening. */
-long parport_set_timeout (struct pardevice *dev, long inactivity)
-{
- long int old = dev->timeout;
-
- dev->timeout = inactivity;
-
- if (dev->port->physport->cad == dev)
- parport_ieee1284_wakeup (dev->port);
-
- return old;
-}
+++ /dev/null
-/* IEEE-1284 operations for parport.
- *
- * This file is for generic IEEE 1284 operations. The idea is that
- * they are used by the low-level drivers. If they have a special way
- * of doing something, they can provide their own routines (and put
- * the function pointers in port->ops); if not, they can just use these
- * as a fallback.
- *
- * Note: Make no assumptions about hardware or architecture in this file!
- *
- * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
- */
-
-#include <linux/config.h>
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-
-#define DEBUG /* undef me for production */
-
-#ifdef CONFIG_LP_CONSOLE
-#undef DEBUG /* Don't want a garbled console */
-#endif
-
-#ifdef DEBUG
-#define DPRINTK(stuff...) printk (stuff)
-#else
-#define DPRINTK(stuff...)
-#endif
-
-/*** *
- * One-way data transfer functions. *
- * ***/
-
-static inline
-int polling (struct pardevice *dev)
-{
- return dev->port->irq == PARPORT_IRQ_NONE;
-}
-
-/* Compatibility mode. */
-size_t parport_ieee1284_write_compat (struct parport *port,
- const void *buffer, size_t len,
- int flags)
-{
- ssize_t count = 0;
- const unsigned char *addr = buffer;
- unsigned char byte;
- struct pardevice *dev = port->physport->cad;
- unsigned char ctl = (PARPORT_CONTROL_SELECT
- | PARPORT_CONTROL_INIT);
-
- if (port->irq != PARPORT_IRQ_NONE)
- parport_enable_irq (port);
-
- port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
- while (count < len) {
- long expire = jiffies + dev->timeout;
- long wait = (HZ + 99) / 100;
- unsigned char mask = (PARPORT_STATUS_ERROR
- | PARPORT_STATUS_BUSY);
- unsigned char val = (PARPORT_STATUS_ERROR
- | PARPORT_STATUS_BUSY);
- int i;
-
- /* Write the character to the data lines. */
- byte = *addr++;
- parport_write_data (port, byte);
- udelay (1);
-
- /* Wait until the peripheral's ready */
- do {
- /* Is the peripheral ready yet? */
- if (!parport_wait_peripheral (port, mask, val))
- /* Skip the loop */
- goto ready;
-
- /* Is the peripheral upset? */
- if ((parport_read_status (port) &
- (PARPORT_STATUS_PAPEROUT |
- PARPORT_STATUS_SELECT |
- PARPORT_STATUS_ERROR))
- != (PARPORT_STATUS_SELECT |
- PARPORT_STATUS_ERROR))
- /* If nFault is asserted (i.e. no
- * error) and PAPEROUT and SELECT are
- * just red herrings, give the driver
- * a chance to check it's happy with
- * that before continuing. */
- goto stop;
-
- /* Have we run out of time? */
- if (!time_before (jiffies, expire))
- break;
-
- /* Yield the port for a while. If this is the
- first time around the loop, don't let go of
- the port. This way, we find out if we have
- our interrupt handler called. */
- if (count && polling (dev)) {
- parport_release (dev);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout (wait);
- parport_claim_or_block (dev);
- }
- else
- /* We must have the device claimed here */
- parport_wait_event (port, wait);
-
- /* Is there a signal pending? */
- if (signal_pending (current))
- goto stop;
-
- /* Wait longer next time. */
- wait *= 2;
- } while (time_before (jiffies, expire));
-
- DPRINTK (KERN_DEBUG "%s: Timed out\n", port->name);
- break;
-
- ready:
- /* Clear out previous irqs. */
- while (!down_trylock (&port->physport->ieee1284.irq));
-
- /* Pulse strobe. */
- parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
- udelay (1); /* strobe */
-
- parport_write_control (port, ctl);
- udelay (1); /* hold */
-
- /* Wait until it's received (up to 20us). */
- for (i = 0; i < 20; i++) {
- if (!down_trylock (&port->physport->ieee1284.irq) ||
- !(parport_read_status (port) & PARPORT_STATUS_ACK))
- break;
- udelay (1);
- }
-
- count++;
-
- /* Let another process run if it needs to. */
- if (time_before (jiffies, expire))
- if (!parport_yield_blocking (dev)
- && current->need_resched)
- schedule ();
- }
- stop:
- port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
- return count;
-}
-
-/* Nibble mode. */
-size_t parport_ieee1284_read_nibble (struct parport *port,
- void *buffer, size_t len,
- int flags)
-{
-#ifndef CONFIG_PARPORT_1284
- return 0;
-#else
- unsigned char *buf = buffer;
- int i;
- unsigned char byte = 0;
-
- len *= 2; /* in nibbles */
- for (i=0; i < len; i++) {
- unsigned char nibble;
-
- /* Does the error line indicate end of data? */
- if (((i & 1) == 0) &&
- (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
- port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
- DPRINTK (KERN_DEBUG
- "%s: No more nibble data (%d bytes)\n",
- port->name, i/2);
-
- /* Go to reverse idle phase. */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
- port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
- break;
- }
-
- /* Event 7: Set nAutoFd low. */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- /* Event 9: nAck goes low. */
- port->ieee1284.phase = IEEE1284_PH_REV_DATA;
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK, 0)) {
- /* Timeout -- no more data? */
- DPRINTK (KERN_DEBUG
- "%s: Nibble timeout at event 9 (%d bytes)\n",
- port->name, i/2);
- break;
- }
-
-
- /* Read a nibble. */
- nibble = parport_read_status (port) >> 3;
- nibble &= ~8;
- if ((nibble & 0x10) == 0)
- nibble |= 8;
- nibble &= 0xf;
-
- /* Event 10: Set nAutoFd high. */
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-
- /* Event 11: nAck goes high. */
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK,
- PARPORT_STATUS_ACK)) {
- /* Timeout -- no more data? */
- DPRINTK (KERN_DEBUG
- "%s: Nibble timeout at event 11\n",
- port->name);
- break;
- }
-
- if (i & 1) {
- /* Second nibble */
- byte |= nibble << 4;
- *buf++ = byte;
- } else
- byte = nibble;
- }
-
- i /= 2; /* i is now in bytes */
-
- if (i == len) {
- /* Read the last nibble without checking data avail. */
- port = port->physport;
- if (parport_read_status (port) & PARPORT_STATUS_ERROR)
- port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
- else
- port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
- }
-
- return i;
-#endif /* IEEE1284 support */
-}
-
-/* Byte mode. */
-size_t parport_ieee1284_read_byte (struct parport *port,
- void *buffer, size_t len,
- int flags)
-{
-#ifndef CONFIG_PARPORT_1284
- return 0;
-#else
- unsigned char *buf = buffer;
- ssize_t count = 0;
-
- for (count = 0; count < len; count++) {
- unsigned char byte;
-
- /* Data available? */
- if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
- port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
- DPRINTK (KERN_DEBUG
- "%s: No more byte data (%d bytes)\n",
- port->name, count);
-
- /* Go to reverse idle phase. */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
- port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
- break;
- }
-
- /* Event 7: Set nAutoFd low. */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- /* Event 9: nAck goes low. */
- port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA;
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK,
- 0)) {
- /* Timeout -- no more data? */
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
- 0);
- DPRINTK (KERN_DEBUG "%s: Byte timeout at event 9\n",
- port->name);
- break;
- }
-
- byte = parport_read_data (port);
- *buf++ = byte;
-
- /* Event 10: Set nAutoFd high */
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-
- /* Event 11: nAck goes high. */
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK,
- PARPORT_STATUS_ACK)) {
- /* Timeout -- no more data? */
- DPRINTK (KERN_DEBUG "%s: Byte timeout at event 11\n",
- port->name);
- break;
- }
-
- /* Event 16: Set nStrobe low. */
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_STROBE);
- udelay (5);
-
- /* Event 17: Set nStrobe high. */
- parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
- }
-
- if (count == len) {
- /* Read the last byte without checking data avail. */
- port = port->physport;
- if (parport_read_status (port) & PARPORT_STATUS_ERROR)
- port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
- else
- port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
- }
-
- return count;
-#endif /* IEEE1284 support */
-}
-
-/*** *
- * ECP Functions. *
- * ***/
-
-#ifdef CONFIG_PARPORT_1284
-
-static inline
-int ecp_forward_to_reverse (struct parport *port)
-{
- int retval;
-
- /* Event 38: Set nAutoFd low */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
- parport_data_reverse (port);
- udelay (5);
-
- /* Event 39: Set nInit low to initiate bus reversal */
- parport_frob_control (port,
- PARPORT_CONTROL_INIT,
- PARPORT_CONTROL_INIT);
-
- /* Event 40: PError goes low */
- retval = parport_wait_peripheral (port,
- PARPORT_STATUS_PAPEROUT, 0);
-
- if (!retval) {
- DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n",
- port->name);
- port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
- }
-
- return retval;
-}
-
-static inline
-int ecp_reverse_to_forward (struct parport *port)
-{
- int retval;
-
- /* Event 47: Set nInit high */
- parport_frob_control (port,
- PARPORT_CONTROL_INIT,
- PARPORT_CONTROL_INIT);
- parport_data_reverse (port);
-
- /* Event 49: PError goes high */
- retval = parport_wait_peripheral (port,
- PARPORT_STATUS_PAPEROUT,
- PARPORT_STATUS_PAPEROUT);
-
- if (!retval) {
- parport_data_forward (port);
- DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
- port->name);
- port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
- }
-
- return retval;
-}
-
-#endif /* IEEE1284 support */
-
-/* ECP mode, forward channel, data. */
-size_t parport_ieee1284_ecp_write_data (struct parport *port,
- const void *buffer, size_t len,
- int flags)
-{
-#ifndef CONFIG_PARPORT_1284
- return 0;
-#else
- const unsigned char *buf = buffer;
- size_t written;
- int ctl = parport_read_control (port) & ~PARPORT_CONTROL_AUTOFD;
- int retry;
-
- port = port->physport;
-
- if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
- if (ecp_reverse_to_forward (port))
- return 0;
-
- port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
-
- /* HostAck high (data, not command) */
- parport_write_control (port, ctl);
- for (written = 0; written < len; written++, buf++) {
- long expire = jiffies + port->cad->timeout;
- unsigned char byte;
-
- byte = *buf;
- try_again:
- parport_write_data (port, byte);
- parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
- udelay (5);
- for (retry = 0; retry < 100; retry++) {
- if (!parport_wait_peripheral (port,
- PARPORT_STATUS_BUSY, 0))
- goto success;
-
- if (signal_pending (current)) {
- parport_write_control (port, ctl);
- break;
- }
- }
-
- /* Time for Host Transfer Recovery (page 41 of IEEE1284) */
- DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
-
- parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
- udelay (50);
- if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
- /* It's buggered. */
- parport_write_control (port, ctl);
- break;
- }
-
- parport_write_control (port, ctl);
- udelay (50);
- if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
- break;
-
- DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
- port->name);
-
- if (time_after_eq (jiffies, expire)) break;
- goto try_again;
- success:
- parport_write_control (port, ctl);
- udelay (5);
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_BUSY,
- PARPORT_STATUS_BUSY))
- /* Peripheral hasn't accepted the data. */
- break;
- }
-
- port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
- return written;
-#endif /* IEEE1284 support */
-}
-
-/* ECP mode, reverse channel, data. */
-size_t parport_ieee1284_ecp_read_data (struct parport *port,
- void *buffer, size_t len, int flags)
-{
-#ifndef CONFIG_PARPORT_1284
- return 0;
-#else
- struct pardevice *dev = port->cad;
- unsigned char *buf = buffer;
- int rle_count = 0; /* shut gcc up */
- int rle = 0;
- ssize_t count = 0;
-
- port = port->physport;
-
- if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE)
- if (ecp_forward_to_reverse (port))
- return 0;
-
- port->ieee1284.phase = IEEE1284_PH_REV_DATA;
-
- /* Set HostAck low to start accepting data. */
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
- while (count < len) {
- long expire = jiffies + dev->timeout;
- unsigned char byte;
- int command;
-
- /* Event 43: Peripheral sets nAck low. It can take as
- long as it wants. */
- while (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK,
- PARPORT_STATUS_ACK)) {
- /* The peripheral hasn't given us data in
- 35ms. If we have data to give back to the
- caller, do it now. */
- if (count)
- goto out;
-
- /* If we've used up all the time we were allowed,
- give up altogether. */
- if (!time_before (jiffies, expire))
- goto out;
-
- /* Yield the port for a while. */
- if (count && polling (dev)) {
- parport_release (dev);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout ((HZ + 99) / 25);
- parport_claim_or_block (dev);
- }
- else
- /* We must have the device claimed here. */
- parport_wait_event (port, (HZ + 99) / 25);
-
- /* Is there a signal pending? */
- if (signal_pending (current))
- goto out;
- }
-
- /* Is this a command? */
- if (rle)
- /* The last byte was a run-length count, so
- this can't be as well. */
- command = 0;
- else
- command = (parport_read_status (port) &
- PARPORT_STATUS_BUSY) ? 1 : 0;
-
- /* Read the data. */
- byte = parport_read_data (port);
-
- /* If this is a channel command, rather than an RLE
- command or a normal data byte, don't accept it. */
- if (command) {
- if (byte & 0x80) {
- DPRINTK (KERN_DEBUG "%s: stopping short at "
- "channel command (%02x)\n",
- port->name, byte);
- goto out;
- }
- else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE)
- DPRINTK (KERN_DEBUG "%s: device illegally "
- "using RLE; accepting anyway\n",
- port->name);
-
- rle_count = byte + 1;
-
- /* Are we allowed to read that many bytes? */
- if (rle_count > (len - count)) {
- DPRINTK (KERN_DEBUG "%s: leaving %d RLE bytes "
- "for next time\n", port->name,
- rle_count);
- break;
- }
-
- rle = 1;
- }
-
- /* Event 44: Set HostAck high, acknowledging handshake. */
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-
- /* Event 45: The peripheral has 35ms to set nAck high. */
- if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
- /* It's gone wrong. Return what data we have
- to the caller. */
- DPRINTK (KERN_DEBUG "ECP read timed out at 45\n");
-
- if (command)
- printk (KERN_WARNING
- "%s: command ignored (%02x)\n",
- port->name, byte);
-
- break;
- }
-
- /* Event 46: Set HostAck low and accept the data. */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- /* If we just read a run-length count, fetch the data. */
- if (command)
- continue;
-
- /* If this is the byte after a run-length count, decompress. */
- if (rle) {
- rle = 0;
- memset (buf, byte, rle_count);
- buf += rle_count;
- count += rle_count;
- DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n",
- port->name, rle_count);
- }
- else
- /* Normal data byte. */
- *buf++ = byte, count++;
- }
-
- out:
- return count;
-#endif /* IEEE1284 support */
-}
-
-/* ECP mode, forward channel, commands. */
-size_t parport_ieee1284_ecp_write_addr (struct parport *port,
- const void *buffer, size_t len,
- int flags)
-{
-#ifndef CONFIG_PARPORT_1284
- return 0;
-#else
- const unsigned char *buf = buffer;
- size_t written;
- int ctl = parport_read_control (port) | PARPORT_CONTROL_AUTOFD;
- int retry;
-
- port = port->physport;
-
- if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
- if (ecp_reverse_to_forward (port))
- return 0;
-
- port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
-
- /* HostAck low (command, not data) */
- parport_write_control (port, ctl);
- for (written = 0; written < len; written++, buf++) {
- long expire = jiffies + port->cad->timeout;
- unsigned char byte;
-
- byte = *buf;
- try_again:
- parport_write_data (port, byte);
- parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
- udelay (5);
- for (retry = 0; retry < 100; retry++) {
- if (!parport_wait_peripheral (port,
- PARPORT_STATUS_BUSY, 0))
- goto success;
-
- if (signal_pending (current)) {
- parport_write_control (port, ctl);
- break;
- }
- }
-
- /* Time for Host Transfer Recovery (page 41 of IEEE1284) */
- DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
-
- parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
- udelay (50);
- if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
- /* It's buggered. */
- parport_write_control (port, ctl);
- break;
- }
-
- parport_write_control (port, ctl);
- udelay (50);
- if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
- break;
-
- DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
- port->name);
-
- if (time_after_eq (jiffies, expire)) break;
- goto try_again;
- success:
- parport_write_control (port, ctl);
- udelay (5);
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_BUSY,
- PARPORT_STATUS_BUSY))
- /* Peripheral hasn't accepted the data. */
- break;
- }
-
- port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
- return written;
-#endif /* IEEE1284 support */
-}
-
-/*** *
- * EPP functions. *
- * ***/
-
-/* EPP mode, forward channel, data. */
-size_t parport_ieee1284_epp_write_data (struct parport *port,
- const void *buffer, size_t len,
- int flags)
-{
- /* This is untested */
- unsigned char *bp = (unsigned char *) buffer;
- size_t ret = 0;
-
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_AUTOFD |
- PARPORT_CONTROL_SELECT,
- PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_SELECT);
- port->ops->data_forward (port);
- for (; len > 0; len--, bp++) {
- parport_write_data (port, *bp);
-
- if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
- PARPORT_STATUS_BUSY))
- break;
-
- /* Strobe data */
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
- break;
-
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
- ret++;
- }
-
- return ret;
-}
-
-/* EPP mode, reverse channel, data. */
-size_t parport_ieee1284_epp_read_data (struct parport *port,
- void *buffer, size_t len,
- int flags)
-{
- /* This is untested. */
- unsigned char *bp = (unsigned char *) buffer;
- unsigned ret = 0;
-
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_AUTOFD |
- PARPORT_CONTROL_SELECT, 0);
- port->ops->data_reverse (port);
- for (; len > 0; len--, bp++) {
- if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
- PARPORT_STATUS_BUSY))
- break;
-
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
- break;
-
- *bp = parport_read_data (port);
-
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
- ret++;
- }
- port->ops->data_forward (port);
-
- return ret;
-}
-
-/* EPP mode, forward channel, addresses. */
-size_t parport_ieee1284_epp_write_addr (struct parport *port,
- const void *buffer, size_t len,
- int flags)
-{
- /* This is untested */
- unsigned char *bp = (unsigned char *) buffer;
- size_t ret = 0;
-
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_SELECT |
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_SELECT);
- port->ops->data_forward (port);
- for (; len > 0; len--, bp++) {
- parport_write_data (port, *bp);
-
- if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
- PARPORT_STATUS_BUSY))
- break;
-
- /* Strobe data */
- parport_frob_control (port, PARPORT_CONTROL_SELECT,
- PARPORT_CONTROL_SELECT);
-
- if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
- break;
-
- parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
- ret++;
- }
-
- return ret;
-}
-
-/* EPP mode, reverse channel, addresses. */
-size_t parport_ieee1284_epp_read_addr (struct parport *port,
- void *buffer, size_t len,
- int flags)
-{
- /* This is untested. */
- unsigned char *bp = (unsigned char *) buffer;
- unsigned ret = 0;
-
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_SELECT |
- PARPORT_CONTROL_AUTOFD, 0);
- port->ops->data_reverse (port);
- for (; len > 0; len--, bp++) {
- if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
- PARPORT_STATUS_BUSY))
- break;
-
- parport_frob_control (port, PARPORT_CONTROL_SELECT,
- PARPORT_CONTROL_SELECT);
-
- if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
- break;
-
- *bp = parport_read_data (port);
-
- parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
- ret++;
- }
- port->ops->data_forward (port);
-
- return ret;
-}
+++ /dev/null
-/* Parallel-port initialisation code.
- *
- * Authors: David Campbell <campbell@torque.net>
- * Tim Waugh <tim@cyberelk.demon.co.uk>
- * Jose Renau <renau@acm.org>
- *
- * based on work by Grant Guenther <grant@torque.net>
- * and Philip Blundell <Philip.Blundell@pobox.com>
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/threads.h>
-
-#include <linux/parport.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/init.h>
-
-#ifndef MODULE
-static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
-static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
-static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
-static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
-
-extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma);
-extern int parport_ax_init(void);
-
-static int parport_setup_ptr __initdata = 0;
-
-__initfunc(void parport_setup(char *str, int *ints))
-{
- if (ints[0] == 0) {
- if (str && !strncmp(str, "auto", 4)) {
- irq[0] = PARPORT_IRQ_AUTO;
- dma[0] = PARPORT_DMA_AUTO;
- }
- else if (str)
- printk (KERN_ERR "parport: `%s': huh?\n", str);
- else
- printk (KERN_ERR "parport: parport=.. what?\n");
-
- return;
- }
- else if (ints[1] == 0) {
- /* Disable parport if "parport=0" in cmdline */
- io[0] = PARPORT_DISABLE;
- return;
- }
-
- if (parport_setup_ptr < PARPORT_MAX) {
- char *sep;
- io[parport_setup_ptr] = ints[1];
- irq[parport_setup_ptr] = PARPORT_IRQ_NONE;
- dma[parport_setup_ptr] = PARPORT_DMA_NONE;
- if (ints[0] > 1) {
- irq[parport_setup_ptr] = ints[2];
- if (ints[0] > 2) {
- dma[parport_setup_ptr] = ints[3];
- goto done;
- }
-
- if (str == NULL)
- goto done;
-
- goto dma_from_str;
- }
- else if (str == NULL)
- goto done;
- else if (!strncmp(str, "auto", 4))
- irq[parport_setup_ptr] = PARPORT_IRQ_AUTO;
- else if (strncmp(str, "none", 4) != 0) {
- printk(KERN_ERR "parport: bad irq `%s'\n", str);
- return;
- }
-
- if ((sep = strchr(str, ',')) == NULL) goto done;
- str = sep+1;
- dma_from_str:
- if (!strncmp(str, "auto", 4))
- dma[parport_setup_ptr] = PARPORT_DMA_AUTO;
- else if (strncmp(str, "none", 4) != 0) {
- char *ep;
- dma[parport_setup_ptr] = simple_strtoul(str, &ep, 0);
- if (ep == str) {
- printk(KERN_ERR "parport: bad dma `%s'\n",
- str);
- return;
- }
- }
- done:
- parport_setup_ptr++;
- } else
- printk(KERN_ERR "parport=%s ignored, too many ports\n", str);
-}
-#endif
-
-#ifdef MODULE
-int init_module(void)
-{
-#ifdef CONFIG_SYSCTL
- parport_default_proc_register ();
-#endif
- return 0;
-}
-
-void cleanup_module(void)
-{
-#ifdef CONFIG_SYSCTL
- parport_default_proc_unregister ();
-#endif
-}
-
-#else
-
-__initfunc(int parport_init(void))
-{
- if (io[0] == PARPORT_DISABLE)
- return 1;
-
-#ifdef CONFIG_SYSCTL
- parport_default_proc_register ();
-#endif
-
-#ifdef CONFIG_PARPORT_PC
- parport_pc_init(io, io_hi, irq, dma);
-#endif
-#ifdef CONFIG_PARPORT_AX
- parport_ax_init();
-#endif
-#ifdef CONFIG_PARPORT_AMIGA
- parport_amiga_init();
-#endif
-#ifdef CONFIG_PARPORT_MFC3
- parport_mfc3_init();
-#endif
-#ifdef CONFIG_PARPORT_ATARI
- parport_atari_init();
-#endif
-#ifdef CONFIG_PARPORT_ARC
- parport_arc_init();
-#endif
- return 0;
-}
-#endif
-
-/* Exported symbols for modules. */
-
-EXPORT_SYMBOL(parport_claim);
-EXPORT_SYMBOL(parport_claim_or_block);
-EXPORT_SYMBOL(parport_release);
-EXPORT_SYMBOL(parport_register_port);
-EXPORT_SYMBOL(parport_announce_port);
-EXPORT_SYMBOL(parport_unregister_port);
-EXPORT_SYMBOL(parport_register_driver);
-EXPORT_SYMBOL(parport_unregister_driver);
-EXPORT_SYMBOL(parport_register_device);
-EXPORT_SYMBOL(parport_unregister_device);
-EXPORT_SYMBOL(parport_enumerate);
-EXPORT_SYMBOL(parport_negotiate);
-EXPORT_SYMBOL(parport_write);
-EXPORT_SYMBOL(parport_read);
-EXPORT_SYMBOL(parport_ieee1284_wakeup);
-EXPORT_SYMBOL(parport_wait_peripheral);
-EXPORT_SYMBOL(parport_wait_event);
-EXPORT_SYMBOL(parport_set_timeout);
-EXPORT_SYMBOL(parport_ieee1284_interrupt);
-EXPORT_SYMBOL(parport_ieee1284_ecp_write_data);
-EXPORT_SYMBOL(parport_ieee1284_ecp_read_data);
-EXPORT_SYMBOL(parport_ieee1284_ecp_write_addr);
-EXPORT_SYMBOL(parport_ieee1284_write_compat);
-EXPORT_SYMBOL(parport_ieee1284_read_nibble);
-EXPORT_SYMBOL(parport_ieee1284_read_byte);
-EXPORT_SYMBOL(parport_ieee1284_epp_write_data);
-EXPORT_SYMBOL(parport_ieee1284_epp_read_data);
-EXPORT_SYMBOL(parport_ieee1284_epp_write_addr);
-EXPORT_SYMBOL(parport_ieee1284_epp_read_addr);
-EXPORT_SYMBOL(parport_proc_register);
-EXPORT_SYMBOL(parport_proc_unregister);
-EXPORT_SYMBOL(parport_device_proc_register);
-EXPORT_SYMBOL(parport_device_proc_unregister);
-EXPORT_SYMBOL(parport_default_proc_register);
-EXPORT_SYMBOL(parport_default_proc_unregister);
-EXPORT_SYMBOL(parport_parse_irqs);
-EXPORT_SYMBOL(parport_parse_dmas);
-#ifdef CONFIG_PARPORT_1284
-EXPORT_SYMBOL(parport_open);
-EXPORT_SYMBOL(parport_close);
-EXPORT_SYMBOL(parport_device_id);
-EXPORT_SYMBOL(parport_device_num);
-EXPORT_SYMBOL(parport_device_coords);
-EXPORT_SYMBOL(parport_daisy_deselect_all);
-EXPORT_SYMBOL(parport_daisy_select);
-EXPORT_SYMBOL(parport_daisy_init);
-#endif
-
-void inc_parport_count(void)
-{
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
-}
-
-void dec_parport_count(void)
-{
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
-}
+++ /dev/null
-/* Low-level parallel port routines for the Multiface 3 card
- *
- * Author: Joerg Dorchain <dorchain@wirbel.com>
- *
- * (C) The elitist m68k Users(TM)
- *
- * based on the existing parport_amiga and lp_mfc
- *
- *
- * From the MFC3 documentation:
- *
- * Miscellaneous PIA Details
- * -------------------------
- *
- * The two open-drain interrupt outputs /IRQA and /IRQB are routed to
- * /INT2 of the Z2 bus.
- *
- * The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2
- * bus. This means that any PIA registers are accessed at even addresses.
- *
- * Centronics Pin Connections for the PIA
- * --------------------------------------
- *
- * The following table shows the connections between the PIA and the
- * Centronics interface connector. These connections implement a single, but
- * very complete, Centronics type interface. The Pin column gives the pin
- * numbers of the PIA. The Centronics pin numbers can be found in the section
- * "Parallel Connectors".
- *
- *
- * Pin | PIA | Dir | Centronics Names
- * -------+-----+-----+---------------------------------------------------------
- * 19 | CB2 | --> | /STROBE (aka /DRDY)
- * 10-17 | PBx | <-> | DATA0 - DATA7
- * 18 | CB1 | <-- | /ACK
- * 40 | CA1 | <-- | BUSY
- * 3 | PA1 | <-- | PAPER-OUT (aka POUT)
- * 4 | PA2 | <-- | SELECTED (aka SEL)
- * 9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME)
- * 6 | PA4 | <-- | /ERROR (aka /FAULT)
- * 7 | PA5 | --> | DIR (aka /SELECT-IN)
- * 8 | PA6 | --> | /AUTO-FEED-XT
- * 39 | CA2 | --> | open
- * 5 | PA3 | <-- | /ACK (same as CB1!)
- * 2 | PA0 | <-- | BUSY (same as CA1!)
- * -------+-----+-----+---------------------------------------------------------
- *
- * Should be enough to understand some of the driver.
- */
-
-#include "multiface.h"
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <linux/mc6821.h>
-#include <linux/zorro.h>
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/irq.h>
-#include <asm/amigaints.h>
-
-/* Maximum Number of Cards supported */
-#define MAX_MFC 5
-
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTK printk
-#else
-static inline int DPRINTK() {return 0;}
-#endif
-
-static struct parport *this_port[MAX_MFC] = {NULL, };
-static volatile int dummy; /* for trigger readds */
-
-#define pia(dev) ((struct pia *)(dev->base))
-static struct parport_operations pp_mfc3_ops;
-
-static void mfc3_write_data(struct parport *p, unsigned char data)
-{
-DPRINTK("write_data %c\n",data);
-
- dummy = pia(p)->pprb; /* clears irq bit */
- /* Triggers also /STROBE.*/
- pia(p)->pprb = data;
-}
-
-static unsigned char mfc3_read_data(struct parport *p)
-{
- /* clears interupt bit. Triggers also /STROBE. */
- return pia(p)->pprb;
-}
-
-static unsigned char control_pc_to_mfc3(unsigned char control)
-{
- unsigned char ret = 32|64;
-
- if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
- ;
- if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
- ;
- if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
- ret &= ~32; /* /SELECT_IN */
- if (control & PARPORT_CONTROL_INIT) /* INITP */
- ret |= 128;
- if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
- ret &= ~64;
- if (control & PARPORT_CONTROL_STROBE) /* Strobe */
- /* Handled directly by hardware */;
- return ret;
-}
-
-static unsigned char control_mfc3_to_pc(unsigned char control)
-{
- unsigned char ret = PARPORT_CONTROL_INTEN | PARPORT_CONTROL_STROBE
- | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT;
-
- if (control & 128) /* /INITP */
- ret |= PARPORT_CONTROL_INIT;
- if (control & 64) /* /AUTOLF */
- ret &= ~PARPORT_CONTROL_AUTOFD;
- if (control & 32) /* /SELECT_IN */
- ret &= ~PARPORT_CONTROL_SELECT;
- return ret;
-}
-
-static void mfc3_write_control(struct parport *p, unsigned char control)
-{
-DPRINTK("write_control %02x\n",control);
- pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control);
-}
-
-static unsigned char mfc3_read_control( struct parport *p)
-{
-DPRINTK("read_control \n");
- return control_mfc3_to_pc(pia(p)->ppra & 0xe0);
-}
-
-static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val)
-{
- unsigned char old;
-
-DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
- old = mfc3_read_control(p);
- mfc3_write_control(p, (old & ~mask) ^ val);
- return old;
-}
-
-
-static unsigned char status_pc_to_mfc3(unsigned char status)
-{
- unsigned char ret = 1;
-
- if (status & PARPORT_STATUS_BUSY) /* Busy */
- ret &= ~1;
- if (status & PARPORT_STATUS_ACK) /* Ack */
- ret |= 8;
- if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
- ret |= 2;
- if (status & PARPORT_STATUS_SELECT) /* select */
- ret |= 4;
- if (status & PARPORT_STATUS_ERROR) /* error */
- ret |= 16;
- return ret;
-}
-
-static unsigned char status_mfc3_to_pc(unsigned char status)
-{
- unsigned char ret = PARPORT_STATUS_BUSY;
-
- if (status & 1) /* Busy */
- ret &= ~PARPORT_STATUS_BUSY;
- if (status & 2) /* PaperOut */
- ret |= PARPORT_STATUS_PAPEROUT;
- if (status & 4) /* Selected */
- ret |= PARPORT_STATUS_SELECT;
- if (status & 8) /* Ack */
- ret |= PARPORT_STATUS_ACK;
- if (status & 16) /* /ERROR */
- ret |= PARPORT_STATUS_ERROR;
-
- return ret;
-}
-
-static void mfc3_write_status( struct parport *p, unsigned char status)
-{
-DPRINTK("write_status %02x\n",status);
- pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status);
-}
-
-static unsigned char mfc3_read_status(struct parport *p)
-{
- unsigned char status;
-
- status = status_mfc3_to_pc(pia(p)->ppra & 0x1f);
-DPRINTK("read_status %02x\n", status);
- return status;
-}
-
-static void mfc3_change_mode( struct parport *p, int m)
-{
- /* XXX: This port only has one mode, and I am
- not sure about the corresponding PC-style mode*/
-}
-
-static int use_cnt = 0;
-
-static void mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- int i;
-
- for( i = 0; i < MAX_MFC; i++)
- if (this_port[i] != NULL)
- if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
- dummy = pia(this_port[i])->pprb; /* clear irq bit */
- parport_generic_irq(irq, this_port[i], regs);
- }
-}
-
-static int mfc3_claim_resources(struct parport *p)
-{
-DPRINTK("claim_resources\n");
-}
-
-static void mfc3_init_state(struct parport_state *s)
-{
- s->u.amiga.data = 0;
- s->u.amiga.datadir = 255;
- s->u.amiga.status = 0;
- s->u.amiga.statusdir = 0xe0;
-}
-
-static void mfc3_save_state(struct parport *p, struct parport_state *s)
-{
- s->u.amiga.data = pia(p)->pprb;
- pia(p)->crb &= ~PIA_DDR;
- s->u.amiga.datadir = pia(p)->pddrb;
- pia(p)->crb |= PIA_DDR;
- s->u.amiga.status = pia(p)->ppra;
- pia(p)->cra &= ~PIA_DDR;
- s->u.amiga.statusdir = pia(p)->pddrb;
- pia(p)->cra |= PIA_DDR;
-}
-
-static void mfc3_restore_state(struct parport *p, struct parport_state *s)
-{
- pia(p)->pprb = s->u.amiga.data;
- pia(p)->crb &= ~PIA_DDR;
- pia(p)->pddrb = s->u.amiga.datadir;
- pia(p)->crb |= PIA_DDR;
- pia(p)->ppra = s->u.amiga.status;
- pia(p)->cra &= ~PIA_DDR;
- pia(p)->pddrb = s->u.amiga.statusdir;
- pia(p)->cra |= PIA_DDR;
-}
-
-static void mfc3_enable_irq(struct parport *p)
-{
- pia(p)->crb |= PIA_C1_ENABLE_IRQ;
-}
-
-static void mfc3_disable_irq(struct parport *p)
-{
- pia(p)->crb &= ~PIA_C1_ENABLE_IRQ;
-}
-
-static void mfc3_inc_use_count(void)
-{
- MOD_INC_USE_COUNT;
-}
-
-static void mfc3_dec_use_count(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static void mfc3_fill_inode(struct inode *inode, int fill)
-{
-#ifdef MODULE
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-#endif
-}
-
-static struct parport_operations pp_mfc3_ops = {
- mfc3_write_data,
- mfc3_read_data,
-
- mfc3_write_control,
- mfc3_read_control,
- mfc3_frob_control,
-
- NULL, /* write_econtrol */
- NULL, /* read_econtrol */
- NULL, /* frob_econtrol */
-
- mfc3_write_status,
- mfc3_read_status,
-
- NULL, /* write fifo */
- NULL, /* read fifo */
-
- mfc3_change_mode,
-
-
- mfc3_release_resources,
- mfc3_claim_resources,
-
-
- NULL, /* epp_write_data */
- NULL, /* epp_read_data */
- NULL, /* epp_write_addr */
- NULL, /* epp_read_addr */
- NULL, /* epp_check_timeout */
-
- NULL, /* epp_write_block */
- NULL, /* epp_read_block */
-
- NULL, /* ecp_write_block */
- NULL, /* ecp_read_block */
-
- mfc3_init_state,
- mfc3_save_state,
- mfc3_restore_state,
-
- mfc3_enable_irq,
- mfc3_disable_irq,
- mfc3_interrupt,
-
- mfc3_inc_use_count,
- mfc3_dec_use_count,
- mfc3_fill_inode
-};
-
-/* ----------- Initialisation code --------------------------------- */
-
-__initfunc(int parport_mfc3_init(void))
-{
- struct parport *p;
- int pias = 0;
- struct pia *pp;
- unsigned int key = 0;
- const struct ConfigDev *cd;
-
- if (MACH_IS_AMIGA) {
- while ((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0, key))) {
- cd = zorro_get_board(key);
- pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE));
- if (pias < MAX_MFC) {
- pp->crb = 0;
- pp->pddrb = 255; /* all data pins output */
- pp->crb = PIA_DDR|32|8;
- dummy = pp->pddrb; /* reading clears interrupt */
- pp->cra = 0;
- pp->pddra = 0xe0; /* /RESET, /DIR ,/AUTO-FEED output */
- pp->cra = PIA_DDR;
- pp->ppra = 0; /* reset printer */
- udelay(10);
- pp->ppra = 128;
- if ((p = parport_register_port((unsigned long)pp,
- IRQ_AMIGA_PORTS, PARPORT_DMA_NONE,
- &pp_mfc3_ops))) {
- this_port[pias++] = p;
- printk(KERN_INFO "%s: Multiface III port using irq\n", p->name);
- /* XXX: set operating mode */
- parport_proc_register(p);
-
- if (p->irq != PARPORT_IRQ_NONE)
- if (use_cnt++ == 0)
- if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, 0, p->name, &pp_mfc3_ops))
- use_cnt--;
-
- if (parport_probe_hook)
- (*parport_probe_hook)(p);
- zorro_config_board(key, 0);
- p->private_data = (void *)key;
- parport_announce_port (p);
- }
- }
- }
- }
- return pias;
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Joerg Dorchain");
-MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port");
-MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port");
-
-int init_module(void)
-{
- return ! parport_mfc3_init();
-}
-
-void cleanup_module(void)
-{
- int i;
-
- for (i = 0; i < MAX_MFC; i++)
- if (this_port[i] != NULL) {
- if (p->irq != PARPORT_IRQ_NONE)
- if (--use_cnt == 0)
- free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops);
- parport_proc_unregister(this_port[i]);
- parport_unregister_port(this_port[i]);
- zorro_unconfig_board((unsigned int)this_port[i]->private_data, 0);
- }
-}
-#endif
-
-
+++ /dev/null
-/* Low-level parallel-port routines for 8255-based PC-style hardware.
- *
- * Authors: Phil Blundell <Philip.Blundell@pobox.com>
- * Tim Waugh <tim@cyberelk.demon.co.uk>
- * Jose Renau <renau@acm.org>
- * David Campbell <campbell@torque.net>
- * Andrea Arcangeli
- *
- * based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
- *
- * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
- * DMA support - Bert De Jonghe <bert@sophis.be>
- * Better EPP probing - Carlos Henrique Bauer <chbauer@acm.org>
- */
-
-/* This driver should work with any hardware that is broadly compatible
- * with that in the IBM PC. This applies to the majority of integrated
- * I/O chipsets that are commonly available. The expected register
- * layout is:
- *
- * base+0 data
- * base+1 status
- * base+2 control
- *
- * In addition, there are some optional registers:
- *
- * base+3 EPP address
- * base+4 EPP data
- * base+0x400 ECP config A
- * base+0x401 ECP config B
- * base+0x402 ECP control
- *
- * All registers are 8 bits wide and read/write. If your hardware differs
- * only in register addresses (eg because your registers are on 32-bit
- * word boundaries) then you can alter the constants in parport_pc.h to
- * accomodate this.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/pci.h>
-#include <linux/sysctl.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include <linux/parport.h>
-#include <linux/parport_pc.h>
-
-/* Maximum number of ports to support. It is useless to set this greater
- than PARPORT_MAX (in <linux/parport.h>). */
-#define PARPORT_PC_MAX_PORTS 8
-
-/* ECR modes */
-#define ECR_SPP 00
-#define ECR_PS2 01
-#define ECR_PPF 02
-#define ECR_ECP 03
-#define ECR_EPP 04
-#define ECR_VND 05
-#define ECR_TST 06
-#define ECR_CNF 07
-
-static int user_specified __initdata = 0;
-
-/* frob_control, but for ECR */
-static void frob_econtrol (struct parport *pb, unsigned char m,
- unsigned char v)
-{
- outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
-}
-
-#ifdef CONFIG_PARPORT_1284
-/* Safely change the mode bits in the ECR */
-static int change_mode(struct parport *p, int m)
-{
- const struct parport_pc_private *priv = p->physport->private_data;
- int ecr = ECONTROL(p);
- unsigned char oecr;
- int mode;
-
- if (!priv->ecr) {
- printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
- return 0;
- }
-
- /* Bits <7:5> contain the mode. */
- oecr = inb (ecr);
- mode = (oecr >> 5) & 0x7;
- if (mode == m) return 0;
- if (mode && m)
- /* We have to go through mode 000 */
- change_mode (p, ECR_SPP);
-
- if (m < 2 && !(parport_read_control (p) & 0x20)) {
- /* This mode resets the FIFO, so we may
- * have to wait for it to drain first. */
- long expire = jiffies + p->physport->cad->timeout;
- int counter;
- switch (mode) {
- case ECR_PPF: /* Parallel Port FIFO mode */
- case ECR_ECP: /* ECP Parallel Port mode */
- /* Busy wait for 200us */
- for (counter = 0; counter < 40; counter++) {
- if (inb (ECONTROL (p)) & 0x01)
- break;
- if (signal_pending (current)) break;
- udelay (5);
- }
-
- /* Poll slowly. */
- while (!(inb (ECONTROL (p)) & 0x01)) {
- if (time_after_eq (jiffies, expire))
- /* The FIFO is stuck. */
- return -EBUSY;
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout ((HZ + 99) / 100);
- if (signal_pending (current))
- break;
- }
- }
- }
-
- /* Set the mode. */
- oecr &= ~(7 << 5);
- oecr |= m << 5;
- outb (oecr, ecr);
- return 0;
-}
-
-/* Find FIFO lossage; FIFO is reset */
-static int get_fifo_residue (struct parport *p)
-{
- int residue;
- int cnfga;
- const struct parport_pc_private *priv = p->physport->private_data;
-
- /* Prevent further data transfer. */
- parport_frob_control (p,
- PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_STROBE);
-
- /* Adjust for the contents of the FIFO. */
- for (residue = priv->fifo_depth; ; residue--) {
- if (inb (ECONTROL (p)) & 0x2)
- /* Full up. */
- break;
-
- outb (0, FIFO (p));
- }
-
- printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
- residue);
-
- /* Reset the FIFO. */
- frob_econtrol (p, 0xe0, 0x20);
- parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
-
- /* Now change to config mode and clean up. FIXME */
- frob_econtrol (p, 0xe0, 0xe0);
- cnfga = inb (CONFIGA (p));
- printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
-
- if (!(cnfga & (1<<2))) {
- printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
- residue++;
- }
-
- /* Don't care about partial PWords until support is added for
- * PWord != 1 byte. */
-
- /* Back to PS2 mode. */
- frob_econtrol (p, 0xe0, 0x20);
-
- return residue;
-}
-
-#endif /* IEEE 1284 support */
-
-/*
- * Clear TIMEOUT BIT in EPP MODE
- *
- * This is also used in SPP detection.
- */
-static int clear_epp_timeout(struct parport *pb)
-{
- unsigned char r;
-
- if (!(parport_pc_read_status(pb) & 0x01))
- return 1;
-
- /* To clear timeout some chips require double read */
- parport_pc_read_status(pb);
- r = parport_pc_read_status(pb);
- outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */
- outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */
- r = parport_pc_read_status(pb);
-
- return !(r & 0x01);
-}
-
-/*
- * Access functions.
- *
- * These aren't static because they may be used by the parport_xxx_yyy
- * macros. extern __inline__ versions of several of these are in
- * parport_pc.h.
- */
-
-static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- parport_generic_irq(irq, (struct parport *) dev_id, regs);
-}
-
-void parport_pc_write_data(struct parport *p, unsigned char d)
-{
- outb (d, DATA (p));
-}
-
-unsigned char parport_pc_read_data(struct parport *p)
-{
- return inb (DATA (p));
-}
-
-unsigned char __frob_control (struct parport *p, unsigned char mask,
- unsigned char val)
-{
- struct parport_pc_private *priv = p->physport->private_data;
- unsigned char ctr = priv->ctr;
- ctr = (ctr & ~mask) ^ val;
- ctr &= priv->ctr_writable; /* only write writable bits. */
- outb (ctr, CONTROL (p));
- return priv->ctr = ctr; /* update soft copy */
-}
-
-void parport_pc_write_control(struct parport *p, unsigned char d)
-{
- const unsigned char wm = (PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_AUTOFD |
- PARPORT_CONTROL_INIT |
- PARPORT_CONTROL_SELECT);
-
- /* Take this out when drivers have adapted to the newer interface. */
- if (d & 0x20) {
- printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
- p->name, p->cad->name);
- parport_pc_data_reverse (p);
- }
-
- __frob_control (p, wm, d & wm);
-}
-
-unsigned char parport_pc_read_control(struct parport *p)
-{
- const struct parport_pc_private *priv = p->physport->private_data;
- return priv->ctr; /* Use soft copy */
-}
-
-unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
- unsigned char val)
-{
- const unsigned char wm = (PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_AUTOFD |
- PARPORT_CONTROL_INIT |
- PARPORT_CONTROL_SELECT);
-
- /* Take this out when drivers have adapted to the newer interface. */
- if (mask & 0x20) {
- printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
- p->name, p->cad->name);
- parport_pc_data_reverse (p);
- }
-
- /* Restrict mask and val to control lines. */
- mask &= wm;
- val &= wm;
-
- return __frob_control (p, mask, val);
-}
-
-unsigned char parport_pc_read_status(struct parport *p)
-{
- return inb (STATUS (p));
-}
-
-void parport_pc_disable_irq(struct parport *p)
-{
- __frob_control (p, 0x10, 0);
-}
-
-void parport_pc_enable_irq(struct parport *p)
-{
- __frob_control (p, 0x10, 0x10);
-}
-
-void parport_pc_data_forward (struct parport *p)
-{
- __frob_control (p, 0x20, 0);
-}
-
-void parport_pc_data_reverse (struct parport *p)
-{
- __frob_control (p, 0x20, 0x20);
-}
-
-void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
-{
- s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
- s->u.pc.ecr = 0x24;
-}
-
-void parport_pc_save_state(struct parport *p, struct parport_state *s)
-{
- const struct parport_pc_private *priv = p->physport->private_data;
- s->u.pc.ctr = inb (CONTROL (p));
- if (priv->ecr)
- s->u.pc.ecr = inb (ECONTROL (p));
-}
-
-void parport_pc_restore_state(struct parport *p, struct parport_state *s)
-{
- const struct parport_pc_private *priv = p->physport->private_data;
- outb (s->u.pc.ctr, CONTROL (p));
- if (priv->ecr)
- outb (s->u.pc.ecr, ECONTROL (p));
-}
-
-#ifdef CONFIG_PARPORT_1284
-static size_t parport_pc_epp_read_data (struct parport *port, void *buf,
- size_t length, int flags)
-{
- size_t got = 0;
- for (; got < length; got++) {
- *((char*)buf)++ = inb (EPPDATA(port));
- if (inb (STATUS(port)) & 0x01) {
- clear_epp_timeout (port);
- break;
- }
- }
-
- return got;
-}
-
-static size_t parport_pc_epp_write_data (struct parport *port, const void *buf,
- size_t length, int flags)
-{
- size_t written = 0;
- for (; written < length; written++) {
- outb (*((char*)buf)++, EPPDATA(port));
- if (inb (STATUS(port)) & 0x01) {
- clear_epp_timeout (port);
- break;
- }
- }
-
- return written;
-}
-
-static size_t parport_pc_epp_read_addr (struct parport *port, void *buf,
- size_t length, int flags)
-{
- size_t got = 0;
- for (; got < length; got++) {
- *((char*)buf)++ = inb (EPPADDR (port));
- if (inb (STATUS (port)) & 0x01) {
- clear_epp_timeout (port);
- break;
- }
- }
-
- return got;
-}
-
-static size_t parport_pc_epp_write_addr (struct parport *port,
- const void *buf, size_t length,
- int flags)
-{
- size_t written = 0;
- for (; written < length; written++) {
- outb (*((char*)buf)++, EPPADDR (port));
- if (inb (STATUS (port)) & 0x01) {
- clear_epp_timeout (port);
- break;
- }
- }
-
- return written;
-}
-
-static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf,
- size_t length, int flags)
-{
- size_t got;
-
- frob_econtrol (port, 0xe0, ECR_EPP << 5);
- got = parport_pc_epp_read_data (port, buf, length, flags);
- frob_econtrol (port, 0xe0, ECR_PS2 << 5);
-
- return got;
-}
-
-static size_t parport_pc_ecpepp_write_data (struct parport *port,
- const void *buf, size_t length,
- int flags)
-{
- size_t written;
-
- frob_econtrol (port, 0xe0, ECR_EPP << 5);
- written = parport_pc_epp_write_data (port, buf, length, flags);
- frob_econtrol (port, 0xe0, ECR_PS2 << 5);
-
- return written;
-}
-
-static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf,
- size_t length, int flags)
-{
- size_t got;
-
- frob_econtrol (port, 0xe0, ECR_EPP << 5);
- got = parport_pc_epp_read_addr (port, buf, length, flags);
- frob_econtrol (port, 0xe0, ECR_PS2 << 5);
-
- return got;
-}
-
-static size_t parport_pc_ecpepp_write_addr (struct parport *port,
- const void *buf, size_t length,
- int flags)
-{
- size_t written;
-
- frob_econtrol (port, 0xe0, ECR_EPP << 5);
- written = parport_pc_epp_write_addr (port, buf, length, flags);
- frob_econtrol (port, 0xe0, ECR_PS2 << 5);
-
- return written;
-}
-#endif /* IEEE 1284 support */
-
-#ifdef CONFIG_PARPORT_PC_FIFO
-static size_t parport_pc_fifo_write_block_pio (struct parport *port,
- const void *buf, size_t length)
-{
- int ret = 0;
- const unsigned char *bufp = buf;
- size_t left = length;
- long expire = jiffies + port->physport->cad->timeout;
- const int fifo = FIFO (port);
- int poll_for = 8; /* 80 usecs */
- const struct parport_pc_private *priv = port->physport->private_data;
- const int fifo_depth = priv->fifo_depth;
-
- port = port->physport;
-
- /* We don't want to be interrupted every character. */
- parport_pc_disable_irq (port);
- frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
-
- /* Forward mode. */
- parport_pc_data_forward (port);
-
- while (left) {
- unsigned char byte;
- unsigned char ecrval = inb (ECONTROL (port));
- int i = 0;
-
- if (current->need_resched && time_before (jiffies, expire))
- /* Can't yield the port. */
- schedule ();
-
- /* Anyone else waiting for the port? */
- if (port->waithead) {
- printk (KERN_DEBUG "Somebody wants the port\n");
- break;
- }
-
- if (ecrval & 0x02) {
- /* FIFO is full. Wait for interrupt. */
-
- /* Clear serviceIntr */
- outb (ecrval & ~(1<<2), ECONTROL (port));
- false_alarm:
- ret = parport_wait_event (port, HZ);
- if (ret < 0) break;
- ret = 0;
- if (!time_before (jiffies, expire)) {
- /* Timed out. */
- printk (KERN_DEBUG "Timed out\n");
- break;
- }
- ecrval = inb (ECONTROL (port));
- if (!(ecrval & (1<<2))) {
- if (current->need_resched &&
- time_before (jiffies, expire))
- schedule ();
-
- goto false_alarm;
- }
-
- continue;
- }
-
- /* Can't fail now. */
- expire = jiffies + port->cad->timeout;
-
- poll:
- if (signal_pending (current))
- break;
-
- if (ecrval & 0x01) {
- /* FIFO is empty. Blast it full. */
- const int n = left < fifo_depth ? left : fifo_depth;
- outsb (fifo, bufp, n);
- bufp += n;
- left -= n;
-
- /* Adjust the poll time. */
- if (i < (poll_for - 2)) poll_for--;
- continue;
- } else if (i++ < poll_for) {
- udelay (10);
- ecrval = inb (ECONTROL (port));
- goto poll;
- }
-
- /* Half-full (call me an optimist) */
- byte = *bufp++;
- outb (byte, fifo);
- left--;
- }
-
- return length - left;
-}
-
-static size_t parport_pc_fifo_write_block_dma (struct parport *port,
- const void *buf, size_t length)
-{
- int ret = 0;
- unsigned long dmaflag;
- size_t left = length;
- const struct parport_pc_private *priv = port->physport->private_data;
-
- port = port->physport;
-
- /* We don't want to be interrupted every character. */
- parport_pc_disable_irq (port);
- frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
-
- /* Forward mode. */
- parport_pc_data_forward (port);
-
- while (left) {
- long expire = jiffies + port->physport->cad->timeout;
-
- size_t count = left;
-
- if (count > PAGE_SIZE)
- count = PAGE_SIZE;
-
- memcpy(priv->dma_buf, buf, count);
-
- dmaflag = claim_dma_lock();
- disable_dma(port->dma);
- clear_dma_ff(port->dma);
- set_dma_mode(port->dma, DMA_MODE_WRITE);
- set_dma_addr(port->dma, virt_to_bus((volatile char *) priv->dma_buf));
- set_dma_count(port->dma, count);
-
- /* Set DMA mode */
- frob_econtrol (port, 1<<3, 1<<3);
-
- /* Clear serviceIntr */
- frob_econtrol (port, 1<<2, 0);
-
- enable_dma(port->dma);
- release_dma_lock(dmaflag);
-
- /* assume DMA will be successful */
- left -= count;
- buf += count;
-
- /* Wait for interrupt. */
- false_alarm:
- ret = parport_wait_event (port, HZ);
- if (ret < 0) break;
- ret = 0;
- if (!time_before (jiffies, expire)) {
- /* Timed out. */
- printk (KERN_DEBUG "Timed out\n");
- break;
- }
- /* Is serviceIntr set? */
- if (!(inb (ECONTROL (port)) & (1<<2))) {
- if (current->need_resched)
- schedule ();
-
- goto false_alarm;
- }
-
- dmaflag = claim_dma_lock();
- disable_dma(port->dma);
- clear_dma_ff(port->dma);
- count = get_dma_residue(port->dma);
- release_dma_lock(dmaflag);
-
- if (current->need_resched)
- /* Can't yield the port. */
- schedule ();
-
- /* Anyone else waiting for the port? */
- if (port->waithead) {
- printk (KERN_DEBUG "Somebody wants the port\n");
- break;
- }
-
- /* update for possible DMA residue ! */
- buf -= count;
- left += count;
- }
-
- /* Maybe got here through break, so adjust for DMA residue! */
- dmaflag = claim_dma_lock();
- disable_dma(port->dma);
- clear_dma_ff(port->dma);
- left += get_dma_residue(port->dma);
- release_dma_lock(dmaflag);
-
- /* Turn off DMA mode */
- frob_econtrol (port, 1<<3, 0);
-
- return length - left;
-}
-
-/* Parallel Port FIFO mode (ECP chipsets) */
-size_t parport_pc_compat_write_block_pio (struct parport *port,
- const void *buf, size_t length,
- int flags)
-{
- size_t written;
-
- /* Special case: a timeout of zero means we cannot call schedule(). */
- if (!port->physport->cad->timeout)
- return parport_ieee1284_write_compat (port, buf,
- length, flags);
-
- /* Set up parallel port FIFO mode.*/
- change_mode (port, ECR_PPF); /* Parallel port FIFO */
- parport_pc_data_forward (port);
- port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
-
- /* Write the data to the FIFO. */
- if (port->dma != PARPORT_DMA_NONE)
- written = parport_pc_fifo_write_block_dma (port, buf, length);
- else
- written = parport_pc_fifo_write_block_pio (port, buf, length);
-
- /* Finish up. */
- if (change_mode (port, ECR_PS2) == -EBUSY) {
- const struct parport_pc_private *priv =
- port->physport->private_data;
-
- printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
-
- /* Prevent further data transfer. */
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_STROBE);
-
- /* Adjust for the contents of the FIFO. */
- for (written -= priv->fifo_depth; ; written++) {
- if (inb (ECONTROL (port)) & 0x2)
- /* Full up. */
- break;
-
- outb (0, FIFO (port));
- }
-
- /* Reset the FIFO. */
- frob_econtrol (port, 0xe0, 0);
-
- /* De-assert strobe. */
- parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
- }
-
- parport_wait_peripheral (port,
- PARPORT_STATUS_BUSY,
- PARPORT_STATUS_BUSY);
- port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
- return written;
-}
-
-/* ECP */
-#ifdef CONFIG_PARPORT_1284
-size_t parport_pc_ecp_write_block_pio (struct parport *port,
- const void *buf, size_t length,
- int flags)
-{
- size_t written;
-
- /* Special case: a timeout of zero means we cannot call schedule(). */
- if (!port->physport->cad->timeout)
- return parport_ieee1284_ecp_write_data (port, buf,
- length, flags);
-
- /* Switch to forward mode if necessary. */
- if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
- /* Event 47: Set nInit high. */
- parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
-
- /* Event 40: PError goes high. */
- parport_wait_peripheral (port,
- PARPORT_STATUS_PAPEROUT,
- PARPORT_STATUS_PAPEROUT);
- }
-
- /* Set up ECP parallel port mode.*/
- change_mode (port, ECR_ECP); /* ECP FIFO */
- parport_pc_data_forward (port);
- port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
-
- /* Write the data to the FIFO. */
- if (port->dma != PARPORT_DMA_NONE)
- written = parport_pc_fifo_write_block_dma (port, buf, length);
- else
- written = parport_pc_fifo_write_block_pio (port, buf, length);
-
- /* Finish up. */
- if (change_mode (port, ECR_PS2) == -EBUSY) {
- const struct parport_pc_private *priv =
- port->physport->private_data;
-
- printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
-
- /* Prevent further data transfer. */
- parport_frob_control (port,
- PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_STROBE);
-
- /* Adjust for the contents of the FIFO. */
- for (written -= priv->fifo_depth; ; written++) {
- if (inb (ECONTROL (port)) & 0x2)
- /* Full up. */
- break;
-
- outb (0, FIFO (port));
- }
-
- /* Reset the FIFO. */
- frob_econtrol (port, 0xe0, 0);
- parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
-
- /* Host transfer recovery. */
- parport_frob_control (port,
- PARPORT_CONTROL_INIT,
- PARPORT_CONTROL_INIT);
- parport_pc_data_reverse (port);
- parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
- parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
- parport_wait_peripheral (port,
- PARPORT_STATUS_PAPEROUT,
- PARPORT_STATUS_PAPEROUT);
- }
-
- parport_wait_peripheral (port,
- PARPORT_STATUS_BUSY,
- PARPORT_STATUS_BUSY);
- port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
- return written;
-}
-
-size_t parport_pc_ecp_read_block_pio (struct parport *port,
- void *buf, size_t length, int flags)
-{
- size_t left = length;
- size_t fifofull;
- const int fifo = FIFO(port);
- const struct parport_pc_private *priv = port->physport->private_data;
- const int fifo_depth = priv->fifo_depth;
- char *bufp = buf;
-
- port = port->physport;
-
- /* Special case: a timeout of zero means we cannot call schedule(). */
- if (!port->cad->timeout)
- return parport_ieee1284_ecp_read_data (port, buf,
- length, flags);
-
- fifofull = fifo_depth;
- if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE)
- /* If the peripheral is allowed to send RLE compressed
- * data, it is possible for a byte to expand to 128
- * bytes in the FIFO. */
- fifofull = 128;
-
- /* If the caller wants less than a full FIFO's worth of data,
- * go through software emulation. Otherwise we may have to through
- * away data. */
- if (length < fifofull)
- return parport_ieee1284_ecp_read_data (port, buf,
- length, flags);
-
- /* Switch to reverse mode if necessary. */
- if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
- /* Event 38: Set nAutoFd low */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
- parport_pc_data_reverse (port);
- udelay (5);
-
- /* Event 39: Set nInit low to initiate bus reversal */
- parport_frob_control (port,
- PARPORT_CONTROL_INIT,
- PARPORT_CONTROL_INIT);
-
- /* Event 40: PError goes low */
- parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
- }
-
- /* Set up ECP parallel port mode.*/
- change_mode (port, ECR_ECP); /* ECP FIFO */
- parport_pc_data_reverse (port);
- port->ieee1284.phase = IEEE1284_PH_REV_DATA;
-
- /* Do the transfer. */
- while (left > fifofull) {
- int ret;
- long int expire = jiffies + port->cad->timeout;
- unsigned char ecrval = inb (ECONTROL (port));
-
- if (current->need_resched && time_before (jiffies, expire))
- /* Can't yield the port. */
- schedule ();
-
- /* At this point, the FIFO may already be full.
- * Ideally, we'd be able to tell the port to hold on
- * for a second while we empty the FIFO, and we'd be
- * able to ensure that no data is lost. I'm not sure
- * that's the case. :-( It might be that you can play
- * games with STB, as in the forward case; someone should
- * look at a datasheet. */
-
- if (ecrval & 0x01) {
- /* FIFO is empty. Wait for interrupt. */
-
- /* Anyone else waiting for the port? */
- if (port->waithead) {
- printk (KERN_DEBUG
- "Somebody wants the port\n");
- break;
- }
-
- /* Clear serviceIntr */
- outb (ecrval & ~(1<<2), ECONTROL (port));
- false_alarm:
- ret = parport_wait_event (port, HZ);
- if (ret < 0) break;
- ret = 0;
- if (!time_before (jiffies, expire)) {
- /* Timed out. */
- printk (KERN_DEBUG "Timed out\n");
- break;
- }
- ecrval = inb (ECONTROL (port));
- if (!(ecrval & (1<<2))) {
- if (current->need_resched &&
- time_before (jiffies, expire))
- schedule ();
-
- goto false_alarm;
- }
-
- continue;
- }
-
- if (ecrval & 0x02) {
- /* FIFO is full. */
- insb (fifo, bufp, fifo_depth);
- bufp += fifo_depth;
- left -= fifo_depth;
- continue;
- }
-
- *bufp++ = inb (fifo);
- left--;
- }
-
- /* Finish up. */
- if (change_mode (port, ECR_PS2) == -EBUSY) {
- int lost = get_fifo_residue (port);
- printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name,
- lost);
- }
-
- port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
-
- return length - left;
-}
-
-#endif /* IEEE 1284 support */
-
-#endif /* Allowed to use FIFO/DMA */
-
-void parport_pc_inc_use_count(void)
-{
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
-}
-
-void parport_pc_dec_use_count(void)
-{
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
-}
-
-static void parport_pc_fill_inode(struct inode *inode, int fill)
-{
- /* Is this still needed? -tim */
-#ifdef MODULE
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-#endif
-}
-
-struct parport_operations parport_pc_ops =
-{
- parport_pc_write_data,
- parport_pc_read_data,
-
- parport_pc_write_control,
- parport_pc_read_control,
- parport_pc_frob_control,
-
- parport_pc_read_status,
-
- parport_pc_enable_irq,
- parport_pc_disable_irq,
-
- parport_pc_data_forward,
- parport_pc_data_reverse,
-
- parport_pc_interrupt,
- parport_pc_init_state,
- parport_pc_save_state,
- parport_pc_restore_state,
-
- parport_pc_inc_use_count,
- parport_pc_dec_use_count,
- parport_pc_fill_inode,
-
- parport_ieee1284_epp_write_data,
- parport_ieee1284_epp_read_data,
- parport_ieee1284_epp_write_addr,
- parport_ieee1284_epp_read_addr,
-
- parport_ieee1284_ecp_write_data,
- parport_ieee1284_ecp_read_data,
- parport_ieee1284_ecp_write_addr,
-
- parport_ieee1284_write_compat,
- parport_ieee1284_read_nibble,
- parport_ieee1284_read_byte,
-};
-
-/* --- Mode detection ------------------------------------- */
-
-/*
- * Checks for port existence, all ports support SPP MODE
- */
-static int __init parport_SPP_supported(struct parport *pb)
-{
- unsigned char r, w;
-
- /*
- * first clear an eventually pending EPP timeout
- * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
- * that does not even respond to SPP cycles if an EPP
- * timeout is pending
- */
- clear_epp_timeout(pb);
-
- /* Do a simple read-write test to make sure the port exists. */
- w = 0xc;
- outb (w, CONTROL (pb));
-
- /* Is there a control register that we can read from? Some
- * ports don't allow reads, so read_control just returns a
- * software copy. Some ports _do_ allow reads, so bypass the
- * software copy here. In addition, some bits aren't
- * writable. */
- r = inb (CONTROL (pb));
- if ((r & 0xf) == w) {
- w = 0xe;
- outb (w, CONTROL (pb));
- r = inb (CONTROL (pb));
- outb (0xc, CONTROL (pb));
- if ((r & 0xf) == w)
- return PARPORT_MODE_PCSPP;
- }
-
- if (user_specified)
- /* That didn't work, but the user thinks there's a
- * port here. */
- printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n",
- pb->base, w, r);
-
- /* Try the data register. The data lines aren't tri-stated at
- * this stage, so we expect back what we wrote. */
- w = 0xaa;
- parport_pc_write_data (pb, w);
- r = parport_pc_read_data (pb);
- if (r == w) {
- w = 0x55;
- parport_pc_write_data (pb, w);
- r = parport_pc_read_data (pb);
- if (r == w)
- return PARPORT_MODE_PCSPP;
- }
-
- if (user_specified)
- /* Didn't work, but the user is convinced this is the
- * place. */
- printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
- pb->base, w, r);
-
- /* It's possible that we can't read the control register or
- * the data register. In that case just believe the user. */
- if (user_specified)
- return PARPORT_MODE_PCSPP;
-
- return 0;
-}
-
-/* Check for ECR
- *
- * Old style XT ports alias io ports every 0x400, hence accessing ECR
- * on these cards actually accesses the CTR.
- *
- * Modern cards don't do this but reading from ECR will return 0xff
- * regardless of what is written here if the card does NOT support
- * ECP.
- *
- * We first check to see if ECR is the same as CTR. If not, the low
- * two bits of ECR aren't writable, so we check by writing ECR and
- * reading it back to see if it's what we expect.
- */
-static int __init parport_ECR_present(struct parport *pb)
-{
- struct parport_pc_private *priv = pb->private_data;
- unsigned char r = 0xc;
-
- priv->ecr = 0;
- outb (r, CONTROL (pb));
- if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
- outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */
-
- r = inb (CONTROL (pb));
- if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2))
- goto no_reg; /* Sure that no ECR register exists */
- }
-
- if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1)
- goto no_reg;
-
- outb (0x34, ECONTROL (pb));
- if (inb (ECONTROL (pb)) != 0x35)
- goto no_reg;
-
- priv->ecr = 1;
- outb (0xc, CONTROL (pb));
-
- /* Go to mode 000 */
- frob_econtrol (pb, 0xe0, ECR_SPP << 5);
-
- return 1;
-
- no_reg:
- outb (0xc, CONTROL (pb));
- return 0;
-}
-
-#ifdef CONFIG_PARPORT_1284
-/* Detect PS/2 support.
- *
- * Bit 5 (0x20) sets the PS/2 data direction; setting this high
- * allows us to read data from the data lines. In theory we would get back
- * 0xff but any peripheral attached to the port may drag some or all of the
- * lines down to zero. So if we get back anything that isn't the contents
- * of the data register we deem PS/2 support to be present.
- *
- * Some SPP ports have "half PS/2" ability - you can't turn off the line
- * drivers, but an external peripheral with sufficiently beefy drivers of
- * its own can overpower them and assert its own levels onto the bus, from
- * where they can then be read back as normal. Ports with this property
- * and the right type of device attached are likely to fail the SPP test,
- * (as they will appear to have stuck bits) and so the fact that they might
- * be misdetected here is rather academic.
- */
-
-static int __init parport_PS2_supported(struct parport *pb)
-{
- int ok = 0;
-
- clear_epp_timeout(pb);
-
- /* try to tri-state the buffer */
- parport_pc_data_reverse (pb);
-
- parport_pc_write_data(pb, 0x55);
- if (parport_pc_read_data(pb) != 0x55) ok++;
-
- parport_pc_write_data(pb, 0xaa);
- if (parport_pc_read_data(pb) != 0xaa) ok++;
-
- /* cancel input mode */
- parport_pc_data_forward (pb);
-
- if (ok)
- pb->modes |= PARPORT_MODE_TRISTATE;
- else {
- struct parport_pc_private *priv = pb->private_data;
- priv->ctr_writable &= ~0x20;
- }
-
- return ok;
-}
-
-static int __init parport_ECP_supported(struct parport *pb)
-{
- int i;
- int config;
- int pword;
- struct parport_pc_private *priv = pb->private_data;
-
- /* If there is no ECR, we have no hope of supporting ECP. */
- if (!priv->ecr)
- return 0;
-
- /* Find out FIFO depth */
- outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
- outb (ECR_TST << 5, ECONTROL (pb)); /* TEST FIFO */
- for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++)
- outb (0xaa, FIFO (pb));
-
- /*
- * Using LGS chipset it uses ECR register, but
- * it doesn't support ECP or FIFO MODE
- */
- if (i == 1024) {
- outb (ECR_SPP << 5, ECONTROL (pb));
- return 0;
- }
-
- priv->fifo_depth = i;
- printk (KERN_INFO "0x%lx: FIFO is %d bytes\n", pb->base, i);
-
- /* Find out writeIntrThreshold */
- frob_econtrol (pb, 1<<2, 1<<2);
- frob_econtrol (pb, 1<<2, 0);
- for (i = 1; i <= priv->fifo_depth; i++) {
- inb (FIFO (pb));
- udelay (50);
- if (inb (ECONTROL (pb)) & (1<<2))
- break;
- }
-
- if (i <= priv->fifo_depth)
- printk (KERN_INFO "0x%lx: writeIntrThreshold is %d\n",
- pb->base, i);
- else
- /* Number of bytes we know we can write if we get an
- interrupt. */
- i = 0;
-
- priv->writeIntrThreshold = i;
-
- /* Find out readIntrThreshold */
- frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */
- parport_pc_data_reverse (pb);
- frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */
- frob_econtrol (pb, 1<<2, 1<<2);
- frob_econtrol (pb, 1<<2, 0);
- for (i = 1; i <= priv->fifo_depth; i++) {
- outb (0xaa, FIFO (pb));
- if (inb (ECONTROL (pb)) & (1<<2))
- break;
- }
-
- if (i <= priv->fifo_depth)
- printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n",
- pb->base, i);
- else
- /* Number of bytes we can read if we get an interrupt. */
- i = 0;
-
- priv->readIntrThreshold = i;
-
- outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
- outb (0xf4, ECONTROL (pb)); /* Configuration mode */
- config = inb (FIFO (pb));
- pword = (config >> 4) & 0x7;
- switch (pword) {
- case 0:
- pword = 2;
- printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
- pb->base);
- break;
- case 2:
- pword = 4;
- printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
- pb->base);
- break;
- default:
- printk (KERN_WARNING "0x%lx: Unknown implementation ID\n",
- pb->base);
- /* Assume 1 */
- case 1:
- pword = 1;
- }
- priv->pword = pword;
- printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword);
-
- config = inb (CONFIGB (pb));
- printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
- config & 0x80 ? "Level" : "Pulses");
-
- if (!(config & 0x40)) {
- printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base);
- pb->irq = PARPORT_IRQ_NONE;
- }
-
- /* Go back to mode 000 */
- frob_econtrol (pb, 0xe0, ECR_SPP << 5);
- pb->modes |= PARPORT_MODE_ECP;
-
- return 1;
-}
-
-static int __init parport_ECPPS2_supported(struct parport *pb)
-{
- const struct parport_pc_private *priv = pb->private_data;
- int result;
- unsigned char oecr;
-
- if (!priv->ecr)
- return 0;
-
- oecr = inb (ECONTROL (pb));
- outb (ECR_PS2 << 5, ECONTROL (pb));
-
- result = parport_PS2_supported(pb);
-
- outb (oecr, ECONTROL (pb));
- return result;
-}
-
-/* EPP mode detection */
-
-static int __init parport_EPP_supported(struct parport *pb)
-{
- const struct parport_pc_private *priv = pb->private_data;
-
- /*
- * Theory:
- * Bit 0 of STR is the EPP timeout bit, this bit is 0
- * when EPP is possible and is set high when an EPP timeout
- * occurs (EPP uses the HALT line to stop the CPU while it does
- * the byte transfer, an EPP timeout occurs if the attached
- * device fails to respond after 10 micro seconds).
- *
- * This bit is cleared by either reading it (National Semi)
- * or writing a 1 to the bit (SMC, UMC, WinBond), others ???
- * This bit is always high in non EPP modes.
- */
-
- /* If EPP timeout bit clear then EPP available */
- if (!clear_epp_timeout(pb))
- return 0; /* No way to clear timeout */
-
- /* Check for Intel bug. */
- if (priv->ecr) {
- unsigned char i;
- for (i = 0x00; i < 0x80; i += 0x20) {
- outb (i, ECONTROL (pb));
- if (clear_epp_timeout (pb))
- /* Phony EPP in ECP. */
- return 0;
- }
- }
-
- pb->modes |= PARPORT_MODE_EPP;
-
- /* Set up access functions to use EPP hardware. */
- parport_pc_ops.epp_read_data = parport_pc_epp_read_data;
- parport_pc_ops.epp_write_data = parport_pc_epp_write_data;
- parport_pc_ops.epp_read_addr = parport_pc_epp_read_addr;
- parport_pc_ops.epp_write_addr = parport_pc_epp_write_addr;
-
- return 1;
-}
-
-static int __init parport_ECPEPP_supported(struct parport *pb)
-{
- struct parport_pc_private *priv = pb->private_data;
- int result;
- unsigned char oecr;
-
- if (!priv->ecr)
- return 0;
-
- oecr = inb (ECONTROL (pb));
- /* Search for SMC style EPP+ECP mode */
- outb (0x80, ECONTROL (pb));
-
- result = parport_EPP_supported(pb);
-
- outb (oecr, ECONTROL (pb));
-
- if (result) {
- /* Set up access functions to use ECP+EPP hardware. */
- parport_pc_ops.epp_read_data = parport_pc_ecpepp_read_data;
- parport_pc_ops.epp_write_data = parport_pc_ecpepp_write_data;
- parport_pc_ops.epp_read_addr = parport_pc_ecpepp_read_addr;
- parport_pc_ops.epp_write_addr = parport_pc_ecpepp_write_addr;
- }
-
- return result;
-}
-
-#else /* No IEEE 1284 support */
-
-/* Don't bother probing for modes we know we won't use. */
-static int __init parport_PS2_supported(struct parport *pb) { return 0; }
-static int __init parport_ECP_supported(struct parport *pb) { return 0; }
-static int __init parport_EPP_supported(struct parport *pb) { return 0; }
-static int __init parport_ECPEPP_supported(struct parport *pb) { return 0; }
-static int __init parport_ECPPS2_supported(struct parport *pb) { return 0; }
-
-#endif /* No IEEE 1284 support */
-
-/* --- IRQ detection -------------------------------------- */
-
-/* Only if supports ECP mode */
-static int __init programmable_irq_support(struct parport *pb)
-{
- int irq, intrLine;
- unsigned char oecr = inb (ECONTROL (pb));
- static const int lookup[8] = {
- PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5
- };
-
- outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */
-
- intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07;
- irq = lookup[intrLine];
-
- outb (oecr, ECONTROL (pb));
- return irq;
-}
-
-static int __init irq_probe_ECP(struct parport *pb)
-{
- int i;
- unsigned long irqs;
-
- sti();
- irqs = probe_irq_on();
-
- outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
- outb ((ECR_TST << 5) | 0x04, ECONTROL (pb));
- outb (ECR_TST << 5, ECONTROL (pb));
-
- /* If Full FIFO sure that writeIntrThreshold is generated */
- for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++)
- outb (0xaa, FIFO (pb));
-
- pb->irq = probe_irq_off(irqs);
- outb (ECR_SPP << 5, ECONTROL (pb));
-
- if (pb->irq <= 0)
- pb->irq = PARPORT_IRQ_NONE;
-
- return pb->irq;
-}
-
-/*
- * This detection seems that only works in National Semiconductors
- * This doesn't work in SMC, LGS, and Winbond
- */
-static int __init irq_probe_EPP(struct parport *pb)
-{
-#ifndef ADVANCED_DETECT
- return PARPORT_IRQ_NONE;
-#else
- int irqs;
- unsigned char oecr;
-
- if (pb->modes & PARPORT_MODE_PCECR)
- oecr = inb (ECONTROL (pb));
-
- sti();
- irqs = probe_irq_on();
-
- if (pb->modes & PARPORT_MODE_PCECR)
- frob_econtrol (pb, 0x10, 0x10);
-
- clear_epp_timeout(pb);
- parport_pc_frob_control (pb, 0x20, 0x20);
- parport_pc_frob_control (pb, 0x10, 0x10);
- clear_epp_timeout(pb);
-
- /* Device isn't expecting an EPP read
- * and generates an IRQ.
- */
- parport_pc_read_epp(pb);
- udelay(20);
-
- pb->irq = probe_irq_off (irqs);
- if (pb->modes & PARPORT_MODE_PCECR)
- outb (oecr, ECONTROL (pb));
- parport_pc_write_control(pb, 0xc);
-
- if (pb->irq <= 0)
- pb->irq = PARPORT_IRQ_NONE;
-
- return pb->irq;
-#endif /* Advanced detection */
-}
-
-static int __init irq_probe_SPP(struct parport *pb)
-{
- /* Don't even try to do this. */
- return PARPORT_IRQ_NONE;
-}
-
-/* We will attempt to share interrupt requests since other devices
- * such as sound cards and network cards seem to like using the
- * printer IRQs.
- *
- * When ECP is available we can autoprobe for IRQs.
- * NOTE: If we can autoprobe it, we can register the IRQ.
- */
-static int __init parport_irq_probe(struct parport *pb)
-{
- const struct parport_pc_private *priv = pb->private_data;
-
- if (priv->ecr) {
- pb->irq = programmable_irq_support(pb);
- if (pb->irq != PARPORT_IRQ_NONE)
- goto out;
- }
-
- if (pb->modes & PARPORT_MODE_ECP)
- pb->irq = irq_probe_ECP(pb);
-
- if (pb->irq == PARPORT_IRQ_NONE && priv->ecr &&
- (pb->modes & PARPORT_MODE_EPP))
- pb->irq = irq_probe_EPP(pb);
-
- clear_epp_timeout(pb);
-
- if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP))
- pb->irq = irq_probe_EPP(pb);
-
- clear_epp_timeout(pb);
-
- if (pb->irq == PARPORT_IRQ_NONE)
- pb->irq = irq_probe_SPP(pb);
-
-out:
- return pb->irq;
-}
-
-/* --- DMA detection -------------------------------------- */
-
-/* Only if supports ECP mode */
-static int __init programmable_dma_support (struct parport *p)
-{
- unsigned char oecr = inb (ECONTROL (p));
- int dma;
-
- frob_econtrol (p, 0xe0, ECR_CNF << 5);
-
- dma = inb (CONFIGB(p)) & 0x03;
- if (!dma)
- dma = PARPORT_DMA_NONE;
-
- outb (oecr, ECONTROL (p));
- return dma;
-}
-
-static int __init parport_dma_probe (struct parport *p)
-{
- const struct parport_pc_private *priv = p->private_data;
- if (priv->ecr)
- p->dma = programmable_dma_support(p);
-
- return p->dma;
-}
-
-/* --- Initialisation code -------------------------------- */
-
-static int __init probe_one_port(unsigned long int base,
- unsigned long int base_hi,
- int irq, int dma)
-{
- struct parport_pc_private *priv;
- struct parport tmp;
- struct parport *p = &tmp;
- int probedirq = PARPORT_IRQ_NONE;
- if (check_region(base, 3)) return 0;
- priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL);
- if (!priv) {
- printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
- return 0;
- }
- priv->ctr = 0xc;
- priv->ctr_writable = 0xff;
- priv->ecr = 0;
- priv->fifo_depth = 0;
- priv->dma_buf = 0;
- p->base = base;
- p->base_hi = base_hi;
- p->irq = irq;
- p->dma = dma;
- p->modes = PARPORT_MODE_PCSPP;
- p->ops = &parport_pc_ops;
- p->private_data = priv;
- p->physport = p;
- if (base_hi && !check_region(base_hi,3)) {
- parport_ECR_present(p);
- parport_ECP_supported(p);
- parport_ECPPS2_supported(p);
- }
- if (base != 0x3bc) {
- if (!check_region(base+0x3, 5)) {
- parport_EPP_supported(p);
- if (!(p->modes & PARPORT_MODE_EPP))
- parport_ECPEPP_supported(p);
- }
- }
- if (!parport_SPP_supported (p)) {
- /* No port. */
- kfree (priv);
- return 0;
- }
-
- parport_PS2_supported (p);
-
- if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
- PARPORT_DMA_NONE, &parport_pc_ops))) {
- kfree (priv);
- return 0;
- }
-
- p->base_hi = base_hi;
- p->modes = tmp.modes;
- p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
- p->private_data = priv;
-
- printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
- if (p->base_hi && (p->modes & PARPORT_MODE_ECP))
- printk(" (0x%lx)", p->base_hi);
- p->irq = irq;
- p->dma = dma;
- if (p->irq == PARPORT_IRQ_AUTO) {
- p->irq = PARPORT_IRQ_NONE;
- parport_irq_probe(p);
- } else if (p->irq == PARPORT_IRQ_PROBEONLY) {
- p->irq = PARPORT_IRQ_NONE;
- parport_irq_probe(p);
- probedirq = p->irq;
- p->irq = PARPORT_IRQ_NONE;
- }
- if (p->irq != PARPORT_IRQ_NONE) {
- printk(", irq %d", p->irq);
-
- if (p->dma == PARPORT_DMA_AUTO) {
- p->dma = PARPORT_DMA_NONE;
- parport_dma_probe(p);
- }
- }
- if (p->dma == PARPORT_DMA_AUTO)
- p->dma = PARPORT_DMA_NONE;
- if (p->dma != PARPORT_DMA_NONE)
- printk(", dma %d", p->dma);
-
-#ifdef CONFIG_PARPORT_PC_FIFO
- if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
- parport_pc_ops.compat_write_data =
- parport_pc_compat_write_block_pio;
-#ifdef CONFIG_PARPORT_1284
- parport_pc_ops.ecp_write_data =
- parport_pc_ecp_write_block_pio;
-#endif /* IEEE 1284 support */
- if (p->dma != PARPORT_DMA_NONE)
- p->modes |= PARPORT_MODE_DMA;
- printk(", using FIFO");
- }
-#endif /* Allowed to use FIFO/DMA */
-
- printk(" [");
-#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
- {
- int f = 0;
- printmode(PCSPP);
- printmode(TRISTATE);
- printmode(COMPAT)
- printmode(EPP);
- printmode(ECP);
- printmode(DMA);
- }
-#undef printmode
- printk("]\n");
- if (probedirq != PARPORT_IRQ_NONE)
- printk("%s: irq %d detected\n", p->name, probedirq);
- parport_proc_register(p);
-
- request_region (p->base, 3, p->name);
- if (p->size > 3)
- request_region (p->base + 3, p->size - 3, p->name);
- if (p->modes & PARPORT_MODE_ECP)
- request_region (p->base_hi, 3, p->name);
-
- if (p->irq != PARPORT_IRQ_NONE) {
- if (request_irq (p->irq, parport_pc_interrupt,
- 0, p->name, p)) {
- printk (KERN_WARNING "%s: irq %d in use, "
- "resorting to polled operation\n",
- p->name, p->irq);
- p->irq = PARPORT_IRQ_NONE;
- p->dma = PARPORT_DMA_NONE;
- }
-
- if (p->dma != PARPORT_DMA_NONE) {
- if (request_dma (p->dma, p->name)) {
- printk (KERN_WARNING "%s: dma %d in use, "
- "resorting to PIO operation\n",
- p->name, p->dma);
- p->dma = PARPORT_DMA_NONE;
- } else {
- priv->dma_buf = (char *) __get_dma_pages(GFP_KERNEL, 1);
- if (! priv->dma_buf) {
- printk (KERN_WARNING "%s: "
- "cannot get buffer for DMA, "
- "resorting to PIO operation\n",
- p->name);
- free_dma(p->dma);
- p->dma = PARPORT_DMA_NONE;
- }
- }
- }
- }
-
- /* Done probing. Now put the port into a sensible start-up state.
- * SELECT | INIT also puts IEEE1284-compliant devices into
- * compatibility mode. */
- if (p->modes & PARPORT_MODE_ECP)
- /*
- * Put the ECP detected port in PS2 mode.
- */
- outb (0x24, ECONTROL (p));
-
- parport_pc_write_data(p, 0);
- parport_pc_data_forward (p);
- parport_pc_write_control(p, PARPORT_CONTROL_SELECT);
- udelay (50);
- parport_pc_write_control(p,
- PARPORT_CONTROL_SELECT
- | PARPORT_CONTROL_INIT);
- udelay (50);
-
- /* Now that we've told the sharing engine about the port, and
- found out its characteristics, let the high-level drivers
- know about it. */
- parport_announce_port (p);
-
- return 1;
-}
-
-/* Look for PCI parallel port cards. */
-static int __init parport_pc_init_pci (int irq, int dma)
-{
-/* These need to go in pci.h: */
-#ifndef PCI_VENDOR_ID_SIIG
-#define PCI_VENDOR_ID_SIIG 0x131f
-#define PCI_DEVICE_ID_SIIG_1S1P_10x_550 0x1010
-#define PCI_DEVICE_ID_SIIG_1S1P_10x_650 0x1011
-#define PCI_DEVICE_ID_SIIG_1S1P_10x_850 0x1012
-#define PCI_DEVICE_ID_SIIG_1P_10x 0x1020
-#define PCI_DEVICE_ID_SIIG_2P_10x 0x1021
-#define PCI_DEVICE_ID_SIIG_2S1P_10x_550 0x1034
-#define PCI_DEVICE_ID_SIIG_2S1P_10x_650 0x1035
-#define PCI_DEVICE_ID_SIIG_2S1P_10x_850 0x1036
-#define PCI_DEVICE_ID_SIIG_1P_20x 0x2020
-#define PCI_DEVICE_ID_SIIG_2P_20x 0x2021
-#define PCI_DEVICE_ID_SIIG_2P1S_20x_550 0x2040
-#define PCI_DEVICE_ID_SIIG_2P1S_20x_650 0x2041
-#define PCI_DEVICE_ID_SIIG_2P1S_20x_850 0x2042
-#define PCI_DEVICE_ID_SIIG_1S1P_20x_550 0x2010
-#define PCI_DEVICE_ID_SIIG_1S1P_20x_650 0x2011
-#define PCI_DEVICE_ID_SIIG_1S1P_20x_850 0x2012
-#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060
-#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061
-#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062
-#define PCI_VENDOR_ID_LAVA 0x1407
-#define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000
-#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8001 /* The Lava Dual Parallel is */
-#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8002 /* two PCI devices on a card */
-#endif
-
- struct {
- unsigned int vendor;
- unsigned int device;
- unsigned int numports;
- struct {
- unsigned int lo;
- unsigned int hi; /* -ve if not there */
- } addr[4];
- } cards[] = {
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, 1,
- { { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, 1,
- { { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, 1,
- { { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x, 1,
- { { 2, 3 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x, 2,
- { { 2, 3 }, { 4, 5 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, 1,
- { { 4, 5 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, 1,
- { { 4, 5 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, 1,
- { { 4, 5 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x, 1,
- { { 0, 1 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x, 2,
- { { 0, 1 }, { 2, 3 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, 2,
- { { 1, 2 }, { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, 2,
- { { 1, 2 }, { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, 2,
- { { 1, 2 }, { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, 1,
- { { 1, 2 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, 1,
- { { 1, 2 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, 1,
- { { 1, 2 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, 1,
- { { 2, 3 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, 1,
- { { 2, 3 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, 1,
- { { 2, 3 }, } },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL, 1,
- { { 0, -1 }, } },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A, 1,
- { { 0, -1 }, } },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1,
- { { 0, -1 }, } },
- { 0, }
- };
-
- int count = 0;
- int i;
-
- if (!pci_present ())
- return 0;
-
- for (i = 0; cards[i].vendor; i++) {
- struct pci_dev *pcidev = NULL;
- while ((pcidev = pci_find_device (cards[i].vendor,
- cards[i].device,
- pcidev)) != NULL) {
- int n;
- for (n = 0; n < cards[i].numports; n++) {
- int lo = cards[i].addr[n].lo;
- int hi = cards[i].addr[n].hi;
- int io_lo = pcidev->base_address[lo];
- int io_hi = ((hi < 0) ? 0 :
- pcidev->base_address[hi]);
- io_lo &= PCI_BASE_ADDRESS_IO_MASK;
- io_hi &= PCI_BASE_ADDRESS_IO_MASK;
- count += probe_one_port (io_lo, io_hi,
- irq, dma);
- }
- }
- }
-
- return count;
-}
-
-int __init parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
-{
- int count = 0, i = 0;
- if (io && *io) {
- /* Only probe the ports we were given. */
- user_specified = 1;
- do {
- if (!*io_hi) *io_hi = 0x400 + *io;
- count += probe_one_port(*(io++), *(io_hi++),
- *(irq++), *(dma++));
- } while (*io && (++i < PARPORT_PC_MAX_PORTS));
- } else {
- /* Probe all the likely ports. */
- count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]);
- count += probe_one_port(0x378, 0x778, irq[0], dma[0]);
- count += probe_one_port(0x278, 0x678, irq[0], dma[0]);
- count += parport_pc_init_pci (irq[0], dma[0]);
- }
-
- return count;
-}
-
-#ifdef MODULE
-static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
-static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
-static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
-static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
-static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
-static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
-MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-
-int init_module(void)
-{
- /* Work out how many ports we have, then get parport_share to parse
- the irq values. */
- unsigned int i;
- for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
- if (i) {
- if (parport_parse_irqs(i, irq, irqval)) return 1;
- if (parport_parse_dmas(i, dma, dmaval)) return 1;
- }
- else {
- /* The user can make us use any IRQs or DMAs we find. */
- int val;
-
- if (irq[0] && !parport_parse_irqs (1, irq, &val))
- switch (val) {
- case PARPORT_IRQ_NONE:
- case PARPORT_IRQ_AUTO:
- irqval[0] = val;
- }
-
- if (dma[0] && !parport_parse_dmas (1, dma, &val))
- switch (val) {
- case PARPORT_DMA_NONE:
- case PARPORT_DMA_AUTO:
- dmaval[0] = val;
- }
- }
-
- return (parport_pc_init(io, io_hi, irqval, dmaval)?0:1);
-}
-
-void cleanup_module(void)
-{
- struct parport *p = parport_enumerate(), *tmp;
- while (p) {
- tmp = p->next;
- if (p->modes & PARPORT_MODE_PCSPP) {
- struct parport_pc_private *priv = p->private_data;
- if (p->dma != PARPORT_DMA_NONE)
- free_dma(p->dma);
- if (p->irq != PARPORT_IRQ_NONE)
- free_irq(p->irq, p);
- release_region(p->base, 3);
- if (p->size > 3);
- release_region(p->base + 3, p->size - 3);
- if (p->modes & PARPORT_MODE_ECP)
- release_region(p->base_hi, 3);
- parport_proc_unregister(p);
- if (priv->dma_buf)
- free_page((unsigned long) priv->dma_buf);
- kfree (p->private_data);
- parport_unregister_port(p);
- }
- p = tmp;
- }
-}
-#endif
+++ /dev/null
-/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $
- * Parallel port device probing code
- *
- * Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
- * Philip Blundell <Philip.Blundell@pobox.com>
- */
-
-#include <linux/parport.h>
-#include <linux/ctype.h>
-#include <asm/uaccess.h>
-
-static struct {
- char *token;
- char *descr;
-} classes[] = {
- { "", "Legacy device" },
- { "PRINTER", "Printer" },
- { "MODEM", "Modem" },
- { "NET", "Network device" },
- { "HDC", "Hard disk" },
- { "PCMCIA", "PCMCIA" },
- { "MEDIA", "Multimedia device" },
- { "FDC", "Floppy disk" },
- { "PORTS", "Ports" },
- { "SCANNER", "Scanner" },
- { "DIGICAM", "Digital camera" },
- { "", "Unknown device" },
- { "", "Unspecified" },
- { "SCSIADAPTER", "SCSI adapter" },
- { NULL, NULL }
-};
-
-static void pretty_print(struct parport *port, int device)
-{
- struct parport_device_info *info = &port->probe_info[device + 1];
-
- printk(KERN_INFO "%s", port->name);
-
- if (device >= 0)
- printk (" (addr %d)", device);
-
- printk (": %s", classes[info->class].descr);
- if (info->class)
- printk(", %s %s", info->mfr, info->model);
-
- printk("\n");
-}
-
-static char *strdup(char *str)
-{
- int n = strlen(str)+1;
- char *s = kmalloc(n, GFP_KERNEL);
- if (!s) return NULL;
- return strcpy(s, str);
-}
-
-static void parse_data(struct parport *port, int device, char *str)
-{
- char *txt = kmalloc(strlen(str)+1, GFP_KERNEL);
- char *p = txt, *q;
- int guessed_class = PARPORT_CLASS_UNSPEC;
- struct parport_device_info *info = &port->probe_info[device + 1];
-
- if (!txt) {
- printk("%s probe: memory squeeze\n", port->name);
- return;
- }
- strcpy(txt, str);
- while (p) {
- char *sep;
- q = strchr(p, ';');
- if (q) *q = 0;
- sep = strchr(p, ':');
- if (sep) {
- char *u = p;
- *(sep++) = 0;
- while (*u) {
- *u = toupper(*u);
- u++;
- }
- if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
- if (info->mfr)
- kfree (info->mfr);
- info->mfr = strdup(sep);
- } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
- if (info->model)
- kfree (info->model);
- info->model = strdup(sep);
- } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
- int i;
- if (info->class_name)
- kfree (info->class_name);
- info->class_name = strdup(sep);
- for (u = sep; *u; u++)
- *u = toupper(*u);
- for (i = 0; classes[i].token; i++) {
- if (!strcmp(classes[i].token, sep)) {
- info->class = i;
- goto rock_on;
- }
- }
- printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep);
- info->class = PARPORT_CLASS_OTHER;
- } else if (!strcmp(p, "CMD") ||
- !strcmp(p, "COMMAND SET")) {
- if (info->cmdset)
- kfree (info->cmdset);
- info->cmdset = strdup(sep);
- /* if it speaks printer language, it's
- probably a printer */
- if (strstr(sep, "PJL") || strstr(sep, "PCL"))
- guessed_class = PARPORT_CLASS_PRINTER;
- } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
- if (info->description)
- kfree (info->description);
- info->description = strdup(sep);
- }
- }
- rock_on:
- if (q) p = q+1; else p=NULL;
- }
-
- /* If the device didn't tell us its class, maybe we have managed to
- guess one from the things it did say. */
- if (info->class == PARPORT_CLASS_UNSPEC)
- info->class = guessed_class;
-
- pretty_print (port, device);
-
- kfree(txt);
-}
-
-/* Get Std 1284 Device ID. */
-ssize_t parport_device_id (int devnum, char *buffer, size_t len)
-{
- ssize_t retval = -ENXIO;
- struct pardevice *dev = parport_open (devnum, "Device ID probe",
- NULL, NULL, NULL, 0, NULL);
- if (!dev)
- return -ENXIO;
-
- parport_claim_or_block (dev);
-
- /* Negotiate to compatibility mode, and then to device ID mode.
- * (This is in case we are already in device ID mode.) */
- parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
- retval = parport_negotiate (dev->port,
- IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID);
-
- if (!retval) {
- int idlen;
- unsigned char length[2];
- mm_segment_t oldfs = get_fs ();
- set_fs (get_ds ());
-
- /* First two bytes are MSB,LSB of inclusive length. */
- retval = parport_read (dev->port, length, 2);
-
- if (retval != 2) goto restore_fs;
-
- idlen = (length[0] << 8) + length[1] - 2;
- if (idlen < len)
- len = idlen;
- retval = parport_read (dev->port, buffer, len);
-
- if (retval != len) {
- printk (KERN_DEBUG "%s: only read %d of %d ID bytes\n",
- dev->port->name, retval, len);
- goto restore_fs;
- }
-
- /* Some printer manufacturers mistakenly believe that
- the length field is supposed to be _exclusive_. */
- /* In addition, there are broken devices out there
- that don't even finish off with a semi-colon. */
- if (idlen == len && buffer[len - 1] != ';') {
- ssize_t diff;
- diff = parport_read (dev->port, buffer + len, 2);
- retval += diff;
-
- if (diff)
- printk (KERN_DEBUG
- "%s: device reported incorrect "
- "length field (%d, should be %d)\n",
- dev->port->name, idlen, retval);
- else {
- /* One semi-colon short of a device ID. */
- buffer[len++] = ';';
- buffer[len] = '\0';
- printk (KERN_DEBUG "%s: faking semi-colon\n",
- dev->port->name);
-
- /* If we get here, I don't think we
- need to worry about the possible
- standard violation of having read
- more than we were told to. The
- device is non-compliant anyhow. */
- }
- }
-
- restore_fs:
- set_fs (oldfs);
- parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
- }
- parport_release (dev);
-
- if (retval > 0)
- parse_data (dev->port, dev->daisy, buffer);
-
- parport_close (dev);
- return retval;
-}
+++ /dev/null
-/* Sysctl interface for parport devices.
- *
- * Authors: David Campbell <campbell@torque.net>
- * Tim Waugh <tim@cyberelk.demon.co.uk>
- * Philip Blundell <philb@gnu.org>
- * Andrea Arcangeli
- * Riccardo Facchetti <fizban@tin.it>
- *
- * based on work by Grant Guenther <grant@torque.net>
- * and Philip Blundell
- *
- * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
- */
-
-#include <linux/string.h>
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/parport.h>
-#include <linux/ctype.h>
-#include <linux/sysctl.h>
-
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_SYSCTL
-
-
-static int do_active_device(ctl_table *table, int write, struct file *filp,
- void *result, size_t *lenp)
-{
- struct parport *port = (struct parport *)table->extra1;
- char buffer[256];
- struct pardevice *dev;
- int len = 0;
-
- if (write) /* can't happen anyway */
- return -EACCES;
-
- if (filp->f_pos) {
- *lenp = 0;
- return 0;
- }
-
- for (dev = port->devices; dev ; dev = dev->next) {
- if(dev == port->cad) {
- len += sprintf(buffer, "%s\n", dev->name);
- }
- }
-
- if(!len) {
- len += sprintf(buffer, "%s\n", "none");
- }
-
- if (len > *lenp)
- len = *lenp;
- else
- *lenp = len;
-
- filp->f_pos += len;
-
- return copy_to_user(result, buffer, len) ? -EFAULT : 0;
-}
-
-#ifdef CONFIG_PARPORT_1284
-static int do_autoprobe(ctl_table *table, int write, struct file *filp,
- void *result, size_t *lenp)
-{
- struct parport_device_info *info = table->extra2;
- const char *str;
- char buffer[256];
- int len = 0;
-
- if (write) /* permissions stop this */
- return -EACCES;
-
- if (filp->f_pos) {
- *lenp = 0;
- return 0;
- }
-
- if ((str = info->class_name) != NULL)
- len += sprintf (buffer + len, "CLASS:%s;\n", str);
-
- if ((str = info->model) != NULL)
- len += sprintf (buffer + len, "MODEL:%s;\n", str);
-
- if ((str = info->mfr) != NULL)
- len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str);
-
- if ((str = info->description) != NULL)
- len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str);
-
- if ((str = info->cmdset) != NULL)
- len += sprintf (buffer + len, "COMMAND SET:%s;\n", str);
-
- if (len > *lenp)
- len = *lenp;
- else
- *lenp = len;
-
- filp->f_pos += len;
-
- return copy_to_user (result, buffer, len) ? -EFAULT : 0;
-}
-#endif /* IEEE1284.3 support. */
-
-static int do_hardware(ctl_table *table, int write, struct file *filp,
- void *result, size_t *lenp)
-{
- struct parport *port = (struct parport *)table->extra1;
- char buffer[256];
- int len = 0;
-
- if (filp->f_pos) {
- *lenp = 0;
- return 0;
- }
-
- if (write) /* can't happen anyway */
- return -EACCES;
-
- len += sprintf(buffer+len, "base:\t0x%lx", port->base);
- if (port->base_hi)
- len += sprintf(buffer+len, " (0x%lx)", port->base_hi);
- buffer[len++] = '\n';
-
- if (port->irq == PARPORT_IRQ_NONE) {
- len += sprintf(buffer+len, "irq:\tnone\n");
- } else {
-#ifdef __sparc__
- len += sprintf(buffer+len, "irq:\t%s\n",
- __irq_itoa(port->irq));
-#else
- len += sprintf(buffer+len, "irq:\t%d\n", port->irq);
-#endif
- }
-
- if (port->dma == PARPORT_DMA_NONE)
- len += sprintf(buffer+len, "dma:\tnone\n");
- else
- len += sprintf(buffer+len, "dma:\t%d\n", port->dma);
-
- len += sprintf(buffer+len, "modes:\t");
- {
-#define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}}
- int f = 0;
- printmode(PCSPP);
- printmode(TRISTATE);
- printmode(COMPAT);
- printmode(EPP);
- printmode(ECP);
- printmode(DMA);
-#undef printmode
- }
- buffer[len++] = '\n';
-
- if (len > *lenp)
- len = *lenp;
- else
- *lenp = len;
-
- filp->f_pos += len;
-
- return copy_to_user(result, buffer, len) ? -EFAULT : 0;
-}
-
-#define PARPORT_PORT_DIR(child) { 0, NULL, NULL, 0, 0555, child }
-#define PARPORT_PARPORT_DIR(child) { DEV_PARPORT, "parport", \
- NULL, 0, 0555, child }
-#define PARPORT_DEV_DIR(child) { CTL_DEV, "dev", NULL, 0, 0555, child }
-#define PARPORT_DEVICES_ROOT_DIR { DEV_PARPORT_DEVICES, "devices", \
- NULL, 0, 0555, NULL }
-
-
-struct parport_sysctl_table {
- struct ctl_table_header *sysctl_header;
- ctl_table vars[9];
- ctl_table device_dir[2];
- ctl_table port_dir[2];
- ctl_table parport_dir[2];
- ctl_table dev_dir[2];
-};
-
-static const struct parport_sysctl_table parport_sysctl_template = {
- NULL,
- {
- { DEV_PARPORT_SPINTIME, "spintime",
- NULL, sizeof(int), 0644, NULL,
- &proc_dointvec },
- { DEV_PARPORT_HARDWARE, "hardware",
- NULL, 0, 0444, NULL,
- &do_hardware },
- PARPORT_DEVICES_ROOT_DIR,
-#ifdef CONFIG_PARPORT_1284
- { DEV_PARPORT_AUTOPROBE, "autoprobe",
- NULL, 0, 0444, NULL,
- &do_autoprobe },
- { DEV_PARPORT_AUTOPROBE + 1, "autoprobe0",
- NULL, 0, 0444, NULL,
- &do_autoprobe },
- { DEV_PARPORT_AUTOPROBE + 2, "autoprobe1",
- NULL, 0, 0444, NULL,
- &do_autoprobe },
- { DEV_PARPORT_AUTOPROBE + 3, "autoprobe2",
- NULL, 0, 0444, NULL,
- &do_autoprobe },
- { DEV_PARPORT_AUTOPROBE + 4, "autoprobe3",
- NULL, 0, 0444, NULL,
- &do_autoprobe },
-#endif /* IEEE 1284 support */
- {0}
- },
- { {DEV_PARPORT_DEVICES_ACTIVE, "active", NULL, 0, 444, NULL,
- &do_active_device }, {0}},
- { PARPORT_PORT_DIR(NULL), {0}},
- { PARPORT_PARPORT_DIR(NULL), {0}},
- { PARPORT_DEV_DIR(NULL), {0}}
-};
-
-struct parport_device_sysctl_table
-{
- struct ctl_table_header *sysctl_header;
- ctl_table vars[2];
- ctl_table device_dir[2];
- ctl_table devices_root_dir[2];
- ctl_table port_dir[2];
- ctl_table parport_dir[2];
- ctl_table dev_dir[2];
-};
-
-static const struct parport_device_sysctl_table
-parport_device_sysctl_template = {
- NULL,
- {
- { DEV_PARPORT_DEVICE_TIMESLICE, "timeslice",
- NULL, sizeof(int), 0644, NULL,
- &proc_dointvec },
- },
- { {0, NULL, NULL, 0, 0555, NULL}, {0}},
- { PARPORT_DEVICES_ROOT_DIR, {0}},
- { PARPORT_PORT_DIR(NULL), {0}},
- { PARPORT_PARPORT_DIR(NULL), {0}},
- { PARPORT_DEV_DIR(NULL), {0}}
-};
-
-struct parport_default_sysctl_table
-{
- struct ctl_table_header *sysctl_header;
- ctl_table vars[3];
- ctl_table default_dir[2];
- ctl_table parport_dir[2];
- ctl_table dev_dir[2];
-};
-
-extern unsigned long parport_default_timeslice;
-extern int parport_default_spintime;
-
-static struct parport_default_sysctl_table
-parport_default_sysctl_table = {
- NULL,
- {
- { DEV_PARPORT_DEFAULT_TIMESLICE, "timeslice",
- &parport_default_timeslice,
- sizeof(parport_default_timeslice), 0644, NULL,
- &proc_dointvec },
- { DEV_PARPORT_DEFAULT_SPINTIME, "spintime",
- &parport_default_spintime,
- sizeof(parport_default_timeslice), 0644, NULL,
- &proc_dointvec },
- {0}
- },
- { { DEV_PARPORT_DEFAULT, "default", NULL, 0, 0555,
- parport_default_sysctl_table.vars },{0}},
- {
- PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir),
- {0}},
- { PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir), {0}}
-};
-
-
-int parport_proc_register(struct parport *port)
-{
- struct parport_sysctl_table *t;
- int i;
-
- t = kmalloc(sizeof(*t), GFP_KERNEL);
- if (t == NULL)
- return -ENOMEM;
- memcpy(t, &parport_sysctl_template, sizeof(*t));
-
- t->device_dir[0].extra1 = port;
-
- for (i = 0; i < 8; i++)
- t->vars[i].extra1 = port;
-
- t->vars[0].data = &port->spintime;
- t->vars[2].child = t->device_dir;
-
- for (i = 0; i < 5; i++)
- t->vars[3 + i].extra2 = &port->probe_info[i];
-
- t->port_dir[0].procname = port->name;
- t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
-
- t->port_dir[0].child = t->vars;
- t->parport_dir[0].child = t->port_dir;
- t->dev_dir[0].child = t->parport_dir;
-
- t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
- if (t->sysctl_header == NULL) {
- kfree(t);
- t = NULL;
- }
- port->sysctl_table = t;
- return 0;
-}
-
-int parport_proc_unregister(struct parport *port)
-{
- if (port->sysctl_table) {
- struct parport_sysctl_table *t = port->sysctl_table;
- port->sysctl_table = NULL;
- unregister_sysctl_table(t->sysctl_header);
- kfree(t);
- }
- return 0;
-}
-
-int parport_device_proc_register(struct pardevice *device)
-{
- struct parport_device_sysctl_table *t;
- struct parport * port = device->port;
-
- t = kmalloc(sizeof(*t), GFP_KERNEL);
- if (t == NULL)
- return -ENOMEM;
- memcpy(t, &parport_device_sysctl_template, sizeof(*t));
-
- t->dev_dir[0].child = t->parport_dir;
- t->parport_dir[0].child = t->port_dir;
- t->port_dir[0].procname = port->name;
- t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
- t->port_dir[0].child = t->devices_root_dir;
- t->devices_root_dir[0].child = t->device_dir;
-
-#ifdef CONFIG_PARPORT_1284
-
- t->device_dir[0].ctl_name =
- parport_device_num(port->number, port->muxport,
- device->daisy)
- + 1; /* nb 0 isn't legal here */
-
-#else /* No IEEE 1284 support */
-
- /* parport_device_num isn't available. */
- t->device_dir[0].ctl_name = 1;
-
-#endif /* IEEE 1284 support or not */
-
- t->device_dir[0].procname = device->name;
- t->device_dir[0].extra1 = device;
- t->device_dir[0].child = t->vars;
- t->vars[0].data = &device->timeslice;
-
- t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
- if (t->sysctl_header == NULL) {
- kfree(t);
- t = NULL;
- }
- device->sysctl_table = t;
- return 0;
-}
-
-int parport_device_proc_unregister(struct pardevice *device)
-{
- if (device->sysctl_table) {
- struct parport_device_sysctl_table *t = device->sysctl_table;
- device->sysctl_table = NULL;
- unregister_sysctl_table(t->sysctl_header);
- kfree(t);
- }
- return 0;
-}
-
-int parport_default_proc_register(void)
-{
- parport_default_sysctl_table.sysctl_header =
- register_sysctl_table(parport_default_sysctl_table.dev_dir, 0);
- return 0;
-}
-
-int parport_default_proc_unregister(void)
-{
- if (parport_default_sysctl_table.sysctl_header) {
- unregister_sysctl_table(parport_default_sysctl_table.
- sysctl_header);
- parport_default_sysctl_table.sysctl_header = NULL;
- }
- return 0;
-}
-
-#else /* no sysctl */
-
-int parport_proc_register(struct parport *pp)
-{
- return 0;
-}
-
-int parport_proc_unregister(struct parport *pp)
-{
- return 0;
-}
-
-int parport_device_proc_register(struct pardevice *device)
-{
- return 0;
-}
-
-int parport_device_proc_unregister(struct pardevice *device)
-{
- return 0;
-}
-
-int parport_default_proc_register (void)
-{
- return 0;
-}
-
-int parport_default_proc_unregister (void)
-{
- return 0;
-}
-#endif
+++ /dev/null
-/* $Id: parport_share.c,v 1.15 1998/01/11 12:06:17 philip Exp $
- * Parallel-port resource manager code.
- *
- * Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
- * Tim Waugh <tim@cyberelk.demon.co.uk>
- * Jose Renau <renau@acm.org>
- * Philip Blundell <philb@gnu.org>
- * Andrea Arcangeli
- *
- * based on work by Grant Guenther <grant@torque.net>
- * and Philip Blundell
- */
-
-#undef PARPORT_DEBUG_SHARING /* undef for production */
-
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/threads.h>
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/sched.h>
-
-#include <asm/spinlock.h>
-#include <asm/irq.h>
-
-#undef PARPORT_PARANOID
-
-#define PARPORT_DEFAULT_TIMESLICE (HZ/5)
-
-unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE;
-int parport_default_spintime = DEFAULT_SPIN_TIME;
-
-static struct parport *portlist = NULL, *portlist_tail = NULL;
-spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;
-
-static struct parport_driver *driver_chain = NULL;
-spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED;
-
-static void call_driver_chain(int attach, struct parport *port)
-{
- struct parport_driver *drv;
-
- for (drv = driver_chain; drv; drv = drv->next) {
- if (attach)
- drv->attach (port);
- else
- drv->detach (port);
- }
-}
-
-int parport_register_driver (struct parport_driver *drv)
-{
- struct parport *port;
-
- spin_lock (&driverlist_lock);
- drv->next = driver_chain;
- driver_chain = drv;
- spin_unlock (&driverlist_lock);
-
- for (port = portlist; port; port = port->next)
- drv->attach (port);
-
- return 0;
-}
-
-void parport_unregister_driver (struct parport_driver *arg)
-{
- struct parport_driver *drv = driver_chain, *olddrv = NULL;
-
- while (drv) {
- if (drv == arg) {
- spin_lock (&driverlist_lock);
- if (olddrv)
- olddrv->next = drv->next;
- else
- driver_chain = drv->next;
- spin_unlock (&driverlist_lock);
- return;
- }
- olddrv = drv;
- drv = drv->next;
- }
-}
-
-/* Return a list of all the ports we know about. */
-struct parport *parport_enumerate(void)
-{
- return portlist;
-}
-
-struct parport *parport_register_port(unsigned long base, int irq, int dma,
- struct parport_operations *ops)
-{
- struct parport *tmp;
- int portnum;
- int device;
- char *name;
-
- tmp = kmalloc(sizeof(struct parport), GFP_KERNEL);
- if (!tmp) {
- printk(KERN_WARNING "parport: memory squeeze\n");
- return NULL;
- }
-
- /* Search for the lowest free parport number. */
- for (portnum = 0; ; portnum++) {
- struct parport *itr = portlist;
- while (itr) {
- if (itr->number == portnum)
- /* No good, already used. */
- break;
- else
- itr = itr->next;
- }
-
- if (itr == NULL)
- /* Got to the end of the list. */
- break;
- }
-
- /* Init our structure */
- memset(tmp, 0, sizeof(struct parport));
- tmp->base = base;
- tmp->irq = irq;
- tmp->dma = dma;
- tmp->muxport = tmp->daisy = tmp->muxsel = -1;
- tmp->modes = 0;
- tmp->next = NULL;
- tmp->devices = tmp->cad = NULL;
- tmp->flags = 0;
- tmp->ops = ops;
- tmp->portnum = tmp->number = portnum;
- tmp->physport = tmp;
- memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info));
- tmp->cad_lock = RW_LOCK_UNLOCKED;
- spin_lock_init(&tmp->waitlist_lock);
- spin_lock_init(&tmp->pardevice_lock);
- tmp->ieee1284.mode = IEEE1284_MODE_COMPAT;
- tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
- init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */
- tmp->spintime = parport_default_spintime;
-
- name = kmalloc(15, GFP_KERNEL);
- if (!name) {
- printk(KERN_ERR "parport: memory squeeze\n");
- kfree(tmp);
- return NULL;
- }
- sprintf(name, "parport%d", portnum);
- tmp->name = name;
-
- /*
- * Chain the entry to our list.
- *
- * This function must not run from an irq handler so we don' t need
- * to clear irq on the local CPU. -arca
- */
- spin_lock(&parportlist_lock);
- if (portlist_tail)
- portlist_tail->next = tmp;
- portlist_tail = tmp;
- if (!portlist)
- portlist = tmp;
- spin_unlock(&parportlist_lock);
-
- for (device = 0; device < 5; device++)
- /* assume the worst */
- tmp->probe_info[device].class = PARPORT_CLASS_LEGACY;
-
- tmp->waithead = tmp->waittail = NULL;
-
- return tmp;
-}
-
-void parport_announce_port (struct parport *port)
-{
-#ifdef CONFIG_PARPORT_1284
- /* Analyse the IEEE1284.3 topology of the port. */
- parport_daisy_init (port);
-#endif
-
- /* Let drivers know that a new port has arrived. */
- call_driver_chain (1, port);
-}
-
-void parport_unregister_port(struct parport *port)
-{
- struct parport *p;
- int d;
-
- /* Spread the word. */
- call_driver_chain (0, port);
-
-#ifdef CONFIG_PARPORT_1284
- /* Forget the IEEE1284.3 topology of the port. */
- parport_daisy_fini (port);
-#endif
-
- spin_lock(&parportlist_lock);
- if (portlist == port) {
- if ((portlist = port->next) == NULL)
- portlist_tail = NULL;
- } else {
- for (p = portlist; (p != NULL) && (p->next != port);
- p=p->next);
- if (p) {
- if ((p->next = port->next) == NULL)
- portlist_tail = p;
- }
- else printk (KERN_WARNING
- "%s not found in port list!\n", port->name);
- }
- spin_unlock(&parportlist_lock);
-
- for (d = 0; d < 5; d++) {
- if (port->probe_info[d].class_name)
- kfree (port->probe_info[d].class_name);
- if (port->probe_info[d].mfr)
- kfree (port->probe_info[d].mfr);
- if (port->probe_info[d].model)
- kfree (port->probe_info[d].model);
- if (port->probe_info[d].cmdset)
- kfree (port->probe_info[d].cmdset);
- if (port->probe_info[d].description)
- kfree (port->probe_info[d].description);
- }
-
- kfree(port->name);
- kfree(port);
-}
-
-struct pardevice *parport_register_device(struct parport *port, const char *name,
- int (*pf)(void *), void (*kf)(void *),
- void (*irq_func)(int, void *, struct pt_regs *),
- int flags, void *handle)
-{
- struct pardevice *tmp;
-
- if (port->physport->flags & PARPORT_FLAG_EXCL) {
- /* An exclusive device is registered. */
- printk (KERN_DEBUG "%s: no more devices allowed\n",
- port->name);
- return NULL;
- }
-
- if (flags & PARPORT_DEV_LURK) {
- if (!pf || !kf) {
- printk(KERN_INFO "%s: refused to register lurking device (%s) without callbacks\n", port->name, name);
- return NULL;
- }
- }
-
- tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL);
- if (tmp == NULL) {
- printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
- return NULL;
- }
-
- tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL);
- if (tmp->state == NULL) {
- printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
- kfree(tmp);
- return NULL;
- }
-
- tmp->name = name;
- tmp->port = port;
- tmp->daisy = -1;
- tmp->preempt = pf;
- tmp->wakeup = kf;
- tmp->private = handle;
- tmp->flags = flags;
- tmp->irq_func = irq_func;
- tmp->waiting = 0;
- tmp->timeout = 5 * HZ;
-
- /* Chain this onto the list */
- tmp->prev = NULL;
- /*
- * This function must not run from an irq handler so we don' t need
- * to clear irq on the local CPU. -arca
- */
- spin_lock(&port->physport->pardevice_lock);
-
- if (flags & PARPORT_DEV_EXCL) {
- if (port->physport->devices) {
- spin_unlock (&port->physport->pardevice_lock);
- kfree (tmp->state);
- kfree (tmp);
- printk (KERN_DEBUG
- "%s: cannot grant exclusive access for "
- "device %s\n", port->name, name);
- return NULL;
- }
- port->flags |= PARPORT_FLAG_EXCL;
- }
-
- tmp->next = port->physport->devices;
- if (port->physport->devices)
- port->physport->devices->prev = tmp;
- port->physport->devices = tmp;
- spin_unlock(&port->physport->pardevice_lock);
-
- inc_parport_count();
- port->ops->inc_use_count();
-
- init_waitqueue_head(&tmp->wait_q);
- tmp->timeslice = parport_default_timeslice;
- tmp->waitnext = tmp->waitprev = NULL;
-
- /*
- * This has to be run as last thing since init_state may need other
- * pardevice fields. -arca
- */
- port->ops->init_state(tmp, tmp->state);
- parport_device_proc_register(tmp);
- return tmp;
-}
-
-void parport_unregister_device(struct pardevice *dev)
-{
- struct parport *port;
-
-#ifdef PARPORT_PARANOID
- if (dev == NULL) {
- printk(KERN_ERR "parport_unregister_device: passed NULL\n");
- return;
- }
-#endif
-
- parport_device_proc_unregister(dev);
-
- port = dev->port->physport;
-
- if (port->cad == dev) {
- printk(KERN_DEBUG "%s: %s forgot to release port\n",
- port->name, dev->name);
- parport_release (dev);
- }
-
- spin_lock(&port->pardevice_lock);
- if (dev->next)
- dev->next->prev = dev->prev;
- if (dev->prev)
- dev->prev->next = dev->next;
- else
- port->devices = dev->next;
-
- if (dev->flags & PARPORT_DEV_EXCL)
- port->flags &= ~PARPORT_FLAG_EXCL;
-
- spin_unlock(&port->pardevice_lock);
-
- kfree(dev->state);
- kfree(dev);
-
- dec_parport_count();
- port->ops->dec_use_count();
-}
-
-int parport_claim(struct pardevice *dev)
-{
- struct pardevice *oldcad;
- struct parport *port = dev->port->physport;
- unsigned long flags;
-
- if (port->cad == dev) {
- printk(KERN_INFO "%s: %s already owner\n",
- dev->port->name,dev->name);
- return 0;
- }
-
-try_again:
- /* Preempt any current device */
- if ((oldcad = port->cad) != NULL) {
- if (oldcad->preempt) {
- if (oldcad->preempt(oldcad->private))
- goto blocked;
- port->ops->save_state(port, dev->state);
- } else
- goto blocked;
-
- if (port->cad != oldcad) {
- printk(KERN_WARNING
- "%s: %s released port when preempted!\n",
- port->name, oldcad->name);
- if (port->cad)
- goto blocked;
- }
- }
-
- /* Can't fail from now on, so mark ourselves as no longer waiting. */
- if (dev->waiting & 1) {
- dev->waiting = 0;
-
- /* Take ourselves out of the wait list again. */
- spin_lock_irqsave (&port->waitlist_lock, flags);
- if (dev->waitprev)
- dev->waitprev->waitnext = dev->waitnext;
- else
- port->waithead = dev->waitnext;
- if (dev->waitnext)
- dev->waitnext->waitprev = dev->waitprev;
- else
- port->waittail = dev->waitprev;
- spin_unlock_irqrestore (&port->waitlist_lock, flags);
- dev->waitprev = dev->waitnext = NULL;
- }
-
- /* Now we do the change of devices */
- write_lock_irqsave(&port->cad_lock, flags);
- port->cad = dev;
- write_unlock_irqrestore(&port->cad_lock, flags);
-
-#ifdef CONFIG_PARPORT_1284
- /* If it's a mux port, select it. */
- if (dev->port->muxport >= 0) {
- /* FIXME */
- port->muxsel = dev->port->muxport;
- }
-
- /* If it's a daisy chain device, select it. */
- if (dev->daisy >= 0) {
- /* This could be lazier. */
- if (!parport_daisy_select (port, dev->daisy,
- IEEE1284_MODE_COMPAT))
- port->daisy = dev->daisy;
- }
-#endif /* IEEE1284.3 support */
-
- /* Restore control registers */
- port->ops->restore_state(port, dev->state);
- dev->time = jiffies;
- return 0;
-
-blocked:
- /* If this is the first time we tried to claim the port, register an
- interest. This is only allowed for devices sleeping in
- parport_claim_or_block(), or those with a wakeup function. */
- if (dev->waiting & 2 || dev->wakeup) {
- spin_lock_irqsave (&port->waitlist_lock, flags);
- if (port->cad == NULL) {
- /* The port got released in the meantime. */
- spin_unlock_irqrestore (&port->waitlist_lock, flags);
- goto try_again;
- }
- if (test_and_set_bit(0, &dev->waiting) == 0) {
- /* First add ourselves to the end of the wait list. */
- dev->waitnext = NULL;
- dev->waitprev = port->waittail;
- if (port->waittail) {
- port->waittail->waitnext = dev;
- port->waittail = dev;
- } else
- port->waithead = port->waittail = dev;
- }
- spin_unlock_irqrestore (&port->waitlist_lock, flags);
- }
- return -EAGAIN;
-}
-
-int parport_claim_or_block(struct pardevice *dev)
-{
- int r;
-
- /* Signal to parport_claim() that we can wait even without a
- wakeup function. */
- dev->waiting = 2;
-
- /* Try to claim the port. If this fails, we need to sleep. */
- r = parport_claim(dev);
- if (r == -EAGAIN) {
- unsigned long flags;
-#ifdef PARPORT_DEBUG_SHARING
- printk(KERN_DEBUG "%s: parport_claim() returned -EAGAIN\n", dev->name);
-#endif
- save_flags (flags);
- cli();
- /* If dev->waiting is clear now, an interrupt
- gave us the port and we would deadlock if we slept. */
- if (dev->waiting) {
- sleep_on(&dev->wait_q);
- r = 1;
- } else {
- r = 0;
-#ifdef PARPORT_DEBUG_SHARING
- printk(KERN_DEBUG "%s: didn't sleep in parport_claim_or_block()\n",
- dev->name);
-#endif
- }
- restore_flags(flags);
-#ifdef PARPORT_DEBUG_SHARING
- if (dev->port->physport->cad != dev)
- printk(KERN_DEBUG "%s: exiting parport_claim_or_block "
- "but %s owns port!\n", dev->name,
- dev->port->physport->cad ?
- dev->port->physport->cad->name:"nobody");
-#endif
- }
- dev->waiting = 0;
- return r;
-}
-
-void parport_release(struct pardevice *dev)
-{
- struct parport *port = dev->port->physport;
- struct pardevice *pd;
- unsigned long flags;
-
- /* Make sure that dev is the current device */
- if (port->cad != dev) {
- printk(KERN_WARNING "%s: %s tried to release parport "
- "when not owner\n", port->name, dev->name);
- return;
- }
-
-#ifdef CONFIG_PARPORT_1284
- /* If this is on a mux port, deselect it. */
- if (dev->port->muxport >= 0) {
- /* FIXME */
- port->muxsel = -1;
- }
-
- /* If this is a daisy device, deselect it. */
- if (dev->daisy >= 0) {
- parport_daisy_deselect_all (port);
- port->daisy = -1;
- }
-#endif
-
- write_lock_irqsave(&port->cad_lock, flags);
- port->cad = NULL;
- write_unlock_irqrestore(&port->cad_lock, flags);
-
- /* Save control registers */
- port->ops->save_state(port, dev->state);
-
- /* If anybody is waiting, find out who's been there longest and
- then wake them up. (Note: no locking required) */
- for (pd = port->waithead; pd; pd = pd->waitnext) {
- if (pd->waiting & 2) { /* sleeping in claim_or_block */
- parport_claim(pd);
- if (waitqueue_active(&pd->wait_q))
- wake_up(&pd->wait_q);
- return;
- } else if (pd->wakeup) {
- pd->wakeup(pd->private);
- if (dev->port->cad)
- return;
- } else {
- printk(KERN_ERR "%s: don't know how to wake %s\n", port->name, pd->name);
- }
- }
-
- /* Nobody was waiting, so walk the list to see if anyone is
- interested in being woken up. */
- for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) {
- if (pd->wakeup && pd != dev)
- pd->wakeup(pd->private);
- }
-}
-
-static int parport_parse_params (int nports, const char *str[], int val[],
- int automatic, int none)
-{
- unsigned int i;
- for (i = 0; i < nports && str[i]; i++) {
- if (!strncmp(str[i], "auto", 4))
- val[i] = automatic;
- else if (!strncmp(str[i], "none", 4))
- val[i] = none;
- else {
- char *ep;
- unsigned long r = simple_strtoul(str[i], &ep, 0);
- if (ep != str[i])
- val[i] = r;
- else {
- printk("parport: bad specifier `%s'\n", str[i]);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-int parport_parse_irqs(int nports, const char *irqstr[], int irqval[])
-{
- return parport_parse_params (nports, irqstr, irqval, PARPORT_IRQ_AUTO,
- PARPORT_IRQ_NONE);
-}
-
-int parport_parse_dmas(int nports, const char *dmastr[], int dmaval[])
-{
- return parport_parse_params (nports, dmastr, dmaval, PARPORT_DMA_AUTO,
- PARPORT_DMA_NONE);
-}
--- /dev/null
+Currently known (or at least suspected) bugs in parport:
+
+o lp doesn't allow you to read status while printing is in progress.
+
+See <URL:http://www.cyberelk.demon.co.uk/parport.html>.
--- /dev/null
+#
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+# Parport configuration.
+#
+
+tristate 'Parallel port support' CONFIG_PARPORT
+if [ "$CONFIG_PARPORT" != "n" ]; then
+ dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT_PC" != "n" ]; then
+ bool ' Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO
+ fi
+ if [ "$CONFIG_ARM" = "y" ]; then
+ dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
+ fi
+ if [ "$CONFIG_AMIGA" = "y" ]; then
+ dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+ if [ "$CONFIG_ZORRO" != "n" ]; then
+ dep_tristate ' Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+ fi
+ else
+ define_bool CONFIG_PARPORT_AMIGA n
+ define_bool CONFIG_PARPORT_MFC3 n
+ fi
+ if [ "$CONFIG_ATARI" = "y" ]; then
+ dep_tristate ' Atari hardware' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
+ else
+ define_bool CONFIG_PARPORT_ATARI n
+ fi
+
+ # If exactly one hardware type is selected then parport will optimise away
+ # support for loading any others. Defeat this if the user is keen.
+ bool ' Support foreign hardware' CONFIG_PARPORT_OTHER
+
+ bool ' IEEE 1284 transfer modes' CONFIG_PARPORT_1284
+fi
--- /dev/null
+#
+# Makefile for the kernel miscellaneous drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+# Note 3! Parport is the Borg. We have assimilated some other
+# drivers in the `char', `net' and `scsi' directories, but left them
+# there to allay suspicion.
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := parport.a
+MX_OBJS :=
+LX_OBJS :=
+MI_OBJS :=
+MIX_OBJS :=
+
+ifeq ($(CONFIG_PARPORT),y)
+ L_OBJS += share.o ieee1284.o ieee1284_ops.o procfs.o
+
+ ifeq ($(CONFIG_PARPORT_1284),y)
+ L_OBJS += daisy.o probe.o
+ endif
+
+ ifeq ($(CONFIG_PARPORT_PC),y)
+ LX_OBJS += parport_pc.o
+ else
+ ifeq ($(CONFIG_PARPORT_PC),m)
+ M_OBJS += parport_pc.o
+ endif
+ endif
+ ifeq ($(CONFIG_PARPORT_AX),y)
+ LX_OBJS += parport_ax.o
+ else
+ ifeq ($(CONFIG_PARPORT_AX),m)
+ M_OBJS += parport_ax.o
+ endif
+ endif
+ ifeq ($(CONFIG_PARPORT_AMIGA),y)
+ LX_OBJS += parport_amiga.o
+ else
+ ifeq ($(CONFIG_PARPORT_AMIGA),m)
+ M_OBJS += parport_amiga.o
+ endif
+ endif
+ ifeq ($(CONFIG_PARPORT_MFC3),y)
+ LX_OBJS += parport_mfc3.o
+ else
+ ifeq ($(CONFIG_PARPORT_MFC3),m)
+ M_OBJS += parport_mfc3.o
+ endif
+ endif
+ ifeq ($(CONFIG_PARPORT_ATARI),y)
+ LX_OBJS += parport_atari.o
+ else
+ ifeq ($(CONFIG_PARPORT_ATARI),m)
+ M_OBJS += parport_atari.o
+ endif
+ endif
+ LX_OBJS += init.o
+else
+ ifeq ($(CONFIG_PARPORT),m)
+ MI_OBJS += share.o ieee1284.o ieee1284_ops.o
+ ifeq ($(CONFIG_PARPORT_1284),y)
+ MI_OBJS += daisy.o probe.o
+ endif
+ ifneq ($(CONFIG_PROC_FS),n)
+ MI_OBJS += procfs.o
+ endif
+ MIX_OBJS += init.o
+ M_OBJS += parport.o
+ endif
+ ifeq ($(CONFIG_PARPORT_PC),m)
+ M_OBJS += parport_pc.o
+ endif
+ ifeq ($(CONFIG_PARPORT_AX),m)
+ M_OBJS += parport_ax.o
+ endif
+ ifeq ($(CONFIG_PARPORT_AMIGA),m)
+ M_OBJS += parport_amiga.o
+ endif
+ ifeq ($(CONFIG_PARPORT_MFC3),m)
+ M_OBJS += parport_mfc3.o
+ endif
+ ifeq ($(CONFIG_PARPORT_ATARI),m)
+ M_OBJS += parport_atari.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+# Special rule to build the composite parport.o module
+parport.o: $(MI_OBJS) $(MIX_OBJS)
+ $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS)
--- /dev/null
+Things to be done.
+
+0. Fix the bugs (see BUGS-parport).
+
+1. Proper documentation.
+
+2. A better lp.c:
+
+ a) ECP support would be nice. This can only work if both the port and
+ the printer support it.
+
+ b) Handle status readback automatically. IEEE1284 printers can post status
+ bits when they have something to say. We should read out and deal
+ with (maybe just log) whatever the printer wants to tell the world.
+
+3. Support more hardware (eg m68k, Sun bpp).
+
+4. A better PLIP (make use of bidirectional/ECP/EPP ports).
+
+See <URL:http://www.cyberelk.demon.co.uk/parport.html>.
--- /dev/null
+/*
+ * IEEE 1284.3 Parallel port daisy chain and multiplexor code
+ *
+ * Copyright (C) 1999 Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * ??-12-1998: Initial implementation.
+ * 31-01-1999: Make port-cloning transparent.
+ * 13-02-1999: Move DeviceID technique from parport_probe.
+ * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too.
+ *
+ */
+
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#define DEBUG /* undef me for production */
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+static struct daisydev {
+ struct daisydev *next;
+ struct parport *port;
+ int daisy;
+ int devnum;
+} *topology = NULL;
+
+static int numdevs = 0;
+
+/* Forward-declaration of lower-level functions. */
+static int mux_present (struct parport *port);
+static int num_mux_ports (struct parport *port);
+static int select_port (struct parport *port);
+static int assign_addrs (struct parport *port);
+
+/* Add a device to the discovered topology. */
+static void add_dev (int devnum, struct parport *port, int daisy)
+{
+ struct daisydev *newdev;
+ newdev = kmalloc (GFP_KERNEL, sizeof (struct daisydev));
+ if (newdev) {
+ newdev->port = port;
+ newdev->daisy = daisy;
+ newdev->devnum = devnum;
+ newdev->next = topology;
+ if (!topology || topology->devnum >= devnum)
+ topology = newdev;
+ else {
+ struct daisydev *prev = topology;
+ while (prev->next && prev->next->devnum < devnum)
+ prev = prev->next;
+ newdev->next = prev->next;
+ prev->next = newdev;
+ }
+ }
+}
+
+/* Clone a parport (actually, make an alias). */
+static struct parport *clone_parport (struct parport *real, int muxport)
+{
+ struct parport *extra = parport_register_port (real->base,
+ real->irq,
+ real->dma,
+ real->ops);
+ if (extra) {
+ extra->portnum = real->portnum;
+ extra->physport = real;
+ extra->muxport = muxport;
+ }
+
+ return extra;
+}
+
+/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */
+int parport_daisy_init (struct parport *port)
+{
+ char *deviceid;
+ static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
+ int num_ports;
+ int i;
+
+ /* Because this is called before any other devices exist,
+ * we don't have to claim exclusive access. */
+
+ /* If mux present on normal port, need to create new
+ * parports for each extra port. */
+ if (port->muxport < 0 && mux_present (port) &&
+ /* don't be fooled: a mux must have 2 or 4 ports. */
+ ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) {
+ /* Leave original as port zero. */
+ port->muxport = 0;
+ printk (KERN_INFO
+ "%s: 1st (default) port of %d-way multiplexor\n",
+ port->name, num_ports);
+ for (i = 1; i < num_ports; i++) {
+ /* Clone the port. */
+ struct parport *extra = clone_parport (port, i);
+ if (!extra) {
+ if (signal_pending (current))
+ break;
+
+ schedule ();
+ continue;
+ }
+
+ printk (KERN_INFO
+ "%s: %d%s port of %d-way multiplexor on %s\n",
+ extra->name, i + 1, th[i + 1], num_ports,
+ port->name);
+
+ /* Analyse that port too. We won't recurse
+ forever because of the 'port->muxport < 0'
+ test above. */
+ parport_announce_port (extra);
+ }
+ }
+
+ if (port->muxport >= 0)
+ select_port (port);
+
+ parport_daisy_deselect_all (port);
+ assign_addrs (port);
+
+ /* Count the potential legacy device at the end. */
+ add_dev (numdevs++, port, -1);
+
+ /* Find out the legacy device's IEEE 1284 device ID. */
+ deviceid = kmalloc (1000, GFP_KERNEL);
+ if (deviceid) {
+ parport_device_id (numdevs - 1, deviceid, 1000);
+ kfree (deviceid);
+ }
+
+ return 0;
+}
+
+/* Forget about devices on a physical port. */
+void parport_daisy_fini (struct parport *port)
+{
+ struct daisydev *dev, *prev = topology;
+ while (prev && prev->port == port)
+ prev = topology = topology->next;
+
+ while (prev) {
+ dev = prev->next;
+ if (dev && dev->port == port)
+ prev->next = dev->next;
+
+ prev = prev->next;
+ }
+
+ /* Gaps in the numbering could be handled better. How should
+ someone enumerate through all IEEE1284.3 devices in the
+ topology?. */
+ if (!topology) numdevs = 0;
+ return; }
+
+/* Find a device by canonical device number. */
+struct pardevice *parport_open (int devnum, const char *name,
+ int (*pf) (void *), void (*kf) (void *),
+ void (*irqf) (int, void *, struct pt_regs *),
+ int flags, void *handle)
+{
+ struct parport *port = parport_enumerate ();
+ struct pardevice *dev;
+ int portnum;
+ int muxnum;
+ int daisynum;
+
+ if (parport_device_coords (devnum, &portnum, &muxnum, &daisynum))
+ return NULL;
+
+ while (port && ((port->portnum != portnum) ||
+ (port->muxport != muxnum)))
+ port = port->next;
+
+ if (!port)
+ /* No corresponding parport. */
+ return NULL;
+
+ dev = parport_register_device (port, name, pf, kf,
+ irqf, flags, handle);
+ if (dev)
+ dev->daisy = daisynum;
+
+ /* Check that there really is a device to select. */
+ if (daisynum >= 0) {
+ int selected;
+ parport_claim_or_block (dev);
+ selected = port->daisy;
+ parport_release (dev);
+
+ if (selected != port->daisy) {
+ /* No corresponding device. */
+ parport_unregister_device (dev);
+ return NULL;
+ }
+ }
+
+ return dev;
+}
+
+/* The converse of parport_open. */
+void parport_close (struct pardevice *dev)
+{
+ parport_unregister_device (dev);
+}
+
+/* Convert device coordinates into a canonical device number. */
+int parport_device_num (int parport, int mux, int daisy)
+{
+ struct daisydev *dev = topology;
+
+ while (dev && dev->port->portnum != parport &&
+ dev->port->muxport != mux && dev->daisy != daisy)
+ dev = dev->next;
+
+ if (!dev)
+ return -ENXIO;
+
+ return dev->devnum;
+}
+
+/* Convert a canonical device number into device coordinates. */
+int parport_device_coords (int devnum, int *parport, int *mux, int *daisy)
+{
+ struct daisydev *dev = topology;
+
+ while (dev && dev->devnum != devnum)
+ dev = dev->next;
+
+ if (!dev)
+ return -ENXIO;
+
+ if (parport) *parport = dev->port->portnum;
+ if (mux) *mux = dev->port->muxport;
+ if (daisy) *daisy = dev->daisy;
+ return 0;
+}
+
+/* Send a daisy-chain-style CPP command packet. */
+static int cpp_daisy (struct parport *port, int cmd)
+{
+ unsigned char s;
+
+ parport_write_data (port, 0xaa); udelay (2);
+ parport_write_data (port, 0x55); udelay (2);
+ parport_write_data (port, 0x00); udelay (2);
+ parport_write_data (port, 0xff); udelay (2);
+ s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+ if (s != (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR)) {
+ DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
+ port->name, s);
+ return -ENXIO;
+ }
+
+ parport_write_data (port, 0x87); udelay (2);
+ s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+ if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+ DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
+ port->name, s);
+ return -ENXIO;
+ }
+
+ parport_write_data (port, 0x78); udelay (2);
+ parport_write_data (port, cmd); udelay (2);
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+ udelay (1);
+ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+ udelay (1);
+ s = parport_read_status (port);
+ parport_write_data (port, 0xff); udelay (2);
+
+ return s;
+}
+
+/* Send a mux-style CPP command packet. */
+static int cpp_mux (struct parport *port, int cmd)
+{
+ unsigned char s;
+ int rc;
+
+ parport_write_data (port, 0xaa); udelay (2);
+ parport_write_data (port, 0x55); udelay (2);
+ parport_write_data (port, 0xf0); udelay (2);
+ parport_write_data (port, 0x0f); udelay (2);
+ parport_write_data (port, 0x52); udelay (2);
+ parport_write_data (port, 0xad); udelay (2);
+ parport_write_data (port, cmd); udelay (2);
+
+ s = parport_read_status (port);
+ if (!(s & PARPORT_STATUS_ACK)) {
+ DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
+ port->name, cmd, s);
+ return -EIO;
+ }
+
+ rc = (((s & PARPORT_STATUS_SELECT ? 1 : 0) << 0) |
+ ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) |
+ ((s & PARPORT_STATUS_BUSY ? 0 : 1) << 2) |
+ ((s & PARPORT_STATUS_ERROR ? 0 : 1) << 3));
+
+ return rc;
+}
+
+void parport_daisy_deselect_all (struct parport *port)
+{
+ cpp_daisy (port, 0x30);
+}
+
+int parport_daisy_select (struct parport *port, int daisy, int mode)
+{
+ /* mode is currently ignored. FIXME? */
+ return cpp_daisy (port, 0xe0 + daisy) & PARPORT_STATUS_ERROR;
+}
+
+static int mux_present (struct parport *port)
+{
+ return cpp_mux (port, 0x51) == 3;
+}
+
+static int num_mux_ports (struct parport *port)
+{
+ return cpp_mux (port, 0x58);
+}
+
+static int select_port (struct parport *port)
+{
+ int muxport = port->muxport;
+ return cpp_mux (port, 0x60 + muxport) == muxport;
+}
+
+static int assign_addrs (struct parport *port)
+{
+ unsigned char s, last_dev;
+ unsigned char daisy;
+ int thisdev = numdevs;
+ char *deviceid;
+
+ parport_write_data (port, 0xaa); udelay (2);
+ parport_write_data (port, 0x55); udelay (2);
+ parport_write_data (port, 0x00); udelay (2);
+ parport_write_data (port, 0xff); udelay (2);
+ s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+ if (s != (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR)) {
+ DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
+ port->name, s);
+ return -ENXIO;
+ }
+
+ parport_write_data (port, 0x87); udelay (2);
+ s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+ if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+ DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
+ port->name, s);
+ return -ENXIO;
+ }
+
+ parport_write_data (port, 0x78); udelay (2);
+ last_dev = 0; /* We've just been speaking to a device, so we
+ know there must be at least _one_ out there. */
+
+ for (daisy = 0; daisy < 4; daisy++) {
+ parport_write_data (port, daisy);
+ udelay (2);
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+ udelay (1);
+ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+ udelay (1);
+
+ if (last_dev)
+ /* No more devices. */
+ break;
+
+ last_dev = !(parport_read_status (port)
+ & PARPORT_STATUS_BUSY);
+
+ add_dev (numdevs++, port, daisy);
+ }
+
+ parport_write_data (port, 0xff); udelay (2);
+ DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
+ numdevs - thisdev);
+
+ /* Ask the new devices to introduce themselves. */
+ deviceid = kmalloc (1000, GFP_KERNEL);
+ if (!deviceid) return 0;
+
+ for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
+ parport_device_id (thisdev, deviceid, 1000);
+
+ kfree (deviceid);
+ return 0;
+}
+
+/* Find a device with a particular manufacturer and model string,
+ starting from a given device number. Like the PCI equivalent,
+ 'from' itself is skipped. */
+int parport_find_device (const char *mfg, const char *mdl, int from)
+{
+ struct daisydev *d = topology; /* sorted by devnum */
+
+ /* Find where to start. */
+ while (d && d->devnum <= from)
+ d = d->next;
+
+ /* Search. */
+ while (d) {
+ struct parport_device_info *info;
+ info = &d->port->probe_info[1 + d->daisy];
+ if ((!mfg || !strcmp (mfg, info->mfr)) &&
+ (!mdl || !strcmp (mdl, info->model)))
+ break;
+
+ d = d->next;
+ }
+
+ if (d)
+ return d->devnum;
+
+ return -1;
+}
+
+/* Find a device in a particular class. Like the PCI equivalent,
+ 'from' itself is skipped. */
+int parport_find_class (parport_device_class cls, int from)
+{
+ struct daisydev *d = topology; /* sorted by devnum */
+
+ /* Find where to start. */
+ while (d && d->devnum <= from)
+ d = d->next;
+
+ /* Search. */
+ while (d && d->port->probe_info[1 + d->daisy].class != cls)
+ d = d->next;
+
+ if (d)
+ return d->devnum;
+
+ return -1;
+}
--- /dev/null
+/* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $
+ * IEEE-1284 implementation for parport.
+ *
+ * Authors: Phil Blundell <Philip.Blundell@pobox.com>
+ * Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
+ * Jose Renau <renau@acm.org>
+ * Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten)
+ *
+ * This file is responsible for IEEE 1284 negotiation, and for handing
+ * read/write requests to low-level drivers.
+ */
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+
+#undef DEBUG /* undef me for production */
+
+#ifdef CONFIG_LP_CONSOLE
+#undef DEBUG /* Don't want a garbled console */
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+/* Make parport_wait_peripheral wake up.
+ * It will be useful to call this from an interrupt handler. */
+void parport_ieee1284_wakeup (struct parport *port)
+{
+ up (&port->physport->ieee1284.irq);
+}
+
+static struct parport *port_from_cookie[PARPORT_MAX];
+static void timeout_waiting_on_port (unsigned long cookie)
+{
+ parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]);
+}
+
+/* Wait for a parport_ieee1284_wakeup.
+ * 0: success
+ * <0: error (exit as soon as possible)
+ * >0: timed out
+ */
+int parport_wait_event (struct parport *port, signed long timeout)
+{
+ int ret;
+ struct timer_list timer;
+
+ if (!port->physport->cad->timeout)
+ /* Zero timeout is special, and we can't down() the
+ semaphore. */
+ return 1;
+
+ init_timer (&timer);
+ timer.expires = jiffies + timeout;
+ timer.function = timeout_waiting_on_port;
+ port_from_cookie[port->number % PARPORT_MAX] = port;
+ timer.data = port->number;
+
+ add_timer (&timer);
+ ret = down_interruptible (&port->physport->ieee1284.irq);
+ if (!del_timer (&timer) && !ret)
+ /* Timed out. */
+ ret = 1;
+
+ return ret;
+}
+
+/* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to
+ * 25 for this. After this time we can create a timeout because the
+ * peripheral doesn't conform to IEEE1284. We want to save CPU time: we are
+ * waiting a maximum time of 500 us busy (this is for speed). If there is
+ * not the right answer in this time, we call schedule and other processes
+ * are able to eat the time up to 40ms.
+ */
+
+int parport_wait_peripheral(struct parport *port,
+ unsigned char mask,
+ unsigned char result)
+{
+ int counter;
+ long deadline;
+ unsigned char status;
+
+ counter = port->physport->spintime; /* usecs of fast polling */
+ if (!port->physport->cad->timeout)
+ /* A zero timeout is "special": busy wait for the
+ entire 35ms. */
+ counter = 35000;
+
+ /* Fast polling.
+ *
+ * This should be adjustable.
+ * How about making a note (in the device structure) of how long
+ * it takes, so we know for next time?
+ */
+ for (counter /= 5; counter > 0; counter--) {
+ status = parport_read_status (port);
+ if ((status & mask) == result)
+ return 0;
+ if (signal_pending (current))
+ return -EINTR;
+ if (current->need_resched)
+ break;
+ udelay(5);
+ }
+
+ if (!port->physport->cad->timeout)
+ /* We may be in an interrupt handler, so we can't poll
+ * slowly anyway. */
+ return 1;
+
+ /* 40ms of slow polling. */
+ deadline = jiffies + (HZ + 24) / 25;
+ while (time_before (jiffies, deadline)) {
+ int ret;
+
+ if (signal_pending (current))
+ return -EINTR;
+
+ /* Wait for 10ms (or until an interrupt occurs if
+ * the handler is set) */
+ if ((ret = parport_wait_event (port, (HZ + 99) / 100)) < 0)
+ return ret;
+
+ status = parport_read_status (port);
+ if ((status & mask) == result)
+ return 0;
+
+ if (!ret) {
+ /* parport_wait_event didn't time out, but the
+ * peripheral wasn't actually ready either.
+ * Wait for another 10ms. */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout ((HZ+ 99) / 100);
+ }
+ }
+
+ return 1;
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Terminate a negotiated mode. */
+static void parport_ieee1284_terminate (struct parport *port)
+{
+ port = port->physport;
+
+ port->ieee1284.phase = IEEE1284_PH_TERMINATE;
+
+ /* EPP terminates differently. */
+ switch (port->ieee1284.mode) {
+ case IEEE1284_MODE_EPP:
+ case IEEE1284_MODE_EPPSL:
+ case IEEE1284_MODE_EPPSWE:
+ /* Terminate from EPP mode. */
+
+ /* Event 68: Set nInit low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_INIT);
+ udelay (50);
+
+ /* Event 69: Set nInit high, nSelectIn low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_SELECT,
+ PARPORT_CONTROL_SELECT);
+ break;
+
+ default:
+ /* Terminate from all other modes. */
+
+ /* Event 22: Set nSelectIn low, nAutoFd high */
+ parport_frob_control (port,
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_SELECT);
+
+ /* Event 24: nAck goes low */
+ parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0);
+
+ /* Event 25: Set nAutoFd low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 27: nAck goes high */
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ACK);
+
+ /* Event 29: Set nAutoFd high */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+ }
+
+ port->ieee1284.mode = IEEE1284_MODE_COMPAT;
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ DPRINTK (KERN_DEBUG "%s: In compatibility (forward idle) mode\n",
+ port->name);
+}
+#endif /* IEEE1284 support */
+
+/* Negotiate an IEEE 1284 mode.
+ * return values are:
+ * 0 - handshake OK; IEEE1284 peripheral and mode available
+ * -1 - handshake failed; peripheral is not compliant (or none present)
+ * 1 - handshake OK; IEEE1284 peripheral present but mode not available
+ */
+int parport_negotiate (struct parport *port, int mode)
+{
+#ifndef CONFIG_PARPORT_1284
+ if (mode == IEEE1284_MODE_COMPAT)
+ return 0;
+ printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
+ return -1;
+#else
+ int m = mode & ~IEEE1284_ADDR;
+ unsigned char xflag;
+
+ port = port->physport;
+
+ /* Is there anything to do? */
+ if (port->ieee1284.mode == mode)
+ return 0;
+
+ /* Is the difference just an address-or-not bit? */
+ if ((port->ieee1284.mode & ~IEEE1284_ADDR) == (mode & ~IEEE1284_ADDR)){
+ port->ieee1284.mode = mode;
+ return 0;
+ }
+
+ /* Go to compability forward idle mode */
+ if (port->ieee1284.mode != IEEE1284_MODE_COMPAT)
+ parport_ieee1284_terminate (port);
+
+ if (mode == IEEE1284_MODE_COMPAT)
+ /* Compatibility mode: no negotiation. */
+ return 0;
+
+ switch (mode) {
+ case IEEE1284_MODE_ECPSWE:
+ m = IEEE1284_MODE_ECP;
+ break;
+ case IEEE1284_MODE_EPPSL:
+ case IEEE1284_MODE_EPPSWE:
+ m = IEEE1284_MODE_EPP;
+ break;
+ case IEEE1284_MODE_BECP:
+ return -ENOSYS; /* FIXME (implement BECP) */
+ }
+
+ port->ieee1284.phase = IEEE1284_PH_NEGOTIATION;
+
+ /* Start off with nStrobe and nAutoFd high, and nSelectIn low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE
+ | PARPORT_CONTROL_AUTOFD
+ | PARPORT_CONTROL_SELECT,
+ PARPORT_CONTROL_SELECT);
+ udelay(1);
+
+ /* Event 0: Set data */
+ parport_write_data (port, m);
+ udelay (400); /* Shouldn't need to wait this long. */
+
+ /* Event 1: Set nSelectIn high, nAutoFd low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 2: PError, Select, nFault go high, nAck goes low */
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ERROR
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ERROR
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_PAPEROUT)) {
+ /* Timeout */
+ parport_frob_control (port,
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_SELECT);
+ DPRINTK (KERN_DEBUG
+ "%s: Peripheral not IEEE1284 compliant (0x%02X)\n",
+ port->name, parport_read_status (port));
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+ return -1; /* Not IEEE1284 compliant */
+ }
+
+ /* Event 3: Set nStrobe low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+
+ /* Event 4: Set nStrobe and nAutoFd high */
+ udelay (5);
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE
+ | PARPORT_CONTROL_AUTOFD,
+ 0);
+
+ /* Event 6: nAck goes high */
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK
+ | PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_ACK)) {
+ if (parport_read_status (port) & PARPORT_STATUS_ACK)
+ printk (KERN_DEBUG
+ "%s: working around buggy peripheral: tell "
+ "Tim what make it is\n", port->name);
+ DPRINTK (KERN_DEBUG
+ "%s: Mode 0x%02x not supported? (0x%02x)\n",
+ port->name, mode, port->ops->read_status (port));
+ parport_ieee1284_terminate (port);
+ return 1;
+ }
+
+ xflag = parport_read_status (port) & PARPORT_STATUS_SELECT;
+
+ /* xflag should be high for all modes other than nibble (0). */
+ if (mode && !xflag) {
+ /* Mode not supported. */
+ DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported\n",
+ port->name, mode);
+ parport_ieee1284_terminate (port);
+ return 1;
+ }
+
+ /* Mode is supported */
+ DPRINTK (KERN_DEBUG "%s: In mode 0x%02x\n", port->name, mode);
+ port->ieee1284.mode = mode;
+
+ /* But ECP is special */
+ if (mode & IEEE1284_MODE_ECP) {
+ port->ieee1284.phase = IEEE1284_PH_ECP_SETUP;
+
+ /* Event 30: Set nAutoFd low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 31: PError goes high. */
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_PAPEROUT);
+ /* (Should check that this works..) */
+
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+ DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+ port->name);
+ } else switch (mode) {
+ case IEEE1284_MODE_NIBBLE:
+ case IEEE1284_MODE_BYTE:
+ port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+ break;
+ default:
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+ }
+
+
+ return 0;
+#endif /* IEEE1284 support */
+}
+
+/* Acknowledge that the peripheral has data available.
+ * Events 18-20, in order to get from Reverse Idle phase
+ * to Host Busy Data Available.
+ * This will most likely be called from an interrupt.
+ * Returns zero if data was available.
+ */
+#ifdef CONFIG_PARPORT_1284
+static int parport_ieee1284_ack_data_avail (struct parport *port)
+{
+ if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+ /* Event 18 didn't happen. */
+ return -1;
+
+ /* Event 20: nAutoFd goes high. */
+ port->ops->frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+ port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+ return 0;
+}
+#endif /* IEEE1284 support */
+
+/* Handle an interrupt. */
+void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs)
+{
+ struct parport *port = handle;
+ parport_ieee1284_wakeup (port);
+
+#ifdef CONFIG_PARPORT_1284
+ if (port->ieee1284.phase == IEEE1284_PH_REV_IDLE) {
+ /* An interrupt in this phase means that data
+ * is now available. */
+ DPRINTK (KERN_DEBUG "%s: Data available\n", port->name);
+ parport_ieee1284_ack_data_avail (port);
+ }
+#endif /* IEEE1284 support */
+}
+
+/* Write a block of data. */
+ssize_t parport_write (struct parport *port, const void *buffer, size_t len)
+{
+#ifndef CONFIG_PARPORT_1284
+ return port->ops->compat_write_data (port, buffer, len, 0);
+#else
+ ssize_t retval;
+ int mode = port->ieee1284.mode;
+ int addr = mode & IEEE1284_ADDR;
+ size_t (*fn) (struct parport *, const void *, size_t, int);
+
+ /* Ignore the device-ID-request bit and the address bit. */
+ mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
+
+ /* Use the mode we're in. */
+ switch (mode) {
+ case IEEE1284_MODE_NIBBLE:
+ parport_negotiate (port, IEEE1284_MODE_COMPAT);
+ case IEEE1284_MODE_COMPAT:
+ DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n",
+ port->name);
+ fn = port->ops->compat_write_data;
+ break;
+
+ case IEEE1284_MODE_EPP:
+ DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
+ if (addr)
+ fn = port->ops->epp_write_addr;
+ else
+ fn = port->ops->epp_write_data;
+ break;
+
+ case IEEE1284_MODE_ECP:
+ case IEEE1284_MODE_ECPRLE:
+ DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
+ if (addr)
+ fn = port->ops->ecp_write_addr;
+ else
+ fn = port->ops->ecp_write_data;
+ break;
+
+ case IEEE1284_MODE_ECPSWE:
+ DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
+ port->name);
+ /* The caller has specified that it must be emulated,
+ * even if we have ECP hardware! */
+ if (addr)
+ fn = parport_ieee1284_ecp_write_addr;
+ else
+ fn = parport_ieee1284_ecp_write_data;
+ break;
+
+ default:
+ DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
+ port->ieee1284.mode);
+ return -ENOSYS;
+ }
+
+ retval = (*fn) (port, buffer, len, 0);
+ DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval,
+ len);
+ return retval;
+#endif /* IEEE1284 support */
+}
+
+/* Read a block of data. */
+ssize_t parport_read (struct parport *port, void *buffer, size_t len)
+{
+#ifndef CONFIG_PARPORT_1284
+ printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
+ return -ENODEV;
+#else
+ int mode = port->physport->ieee1284.mode;
+ int addr = mode & IEEE1284_ADDR;
+ size_t (*fn) (struct parport *, void *, size_t, int);
+
+ /* Ignore the device-ID-request bit and the address bit. */
+ mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
+
+ /* Use the mode we're in. */
+ switch (mode) {
+ case IEEE1284_MODE_COMPAT:
+ if (parport_negotiate (port, IEEE1284_MODE_NIBBLE))
+ return -EIO;
+ case IEEE1284_MODE_NIBBLE:
+ DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name);
+ fn = port->ops->nibble_read_data;
+ break;
+
+ case IEEE1284_MODE_BYTE:
+ DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name);
+ fn = port->ops->byte_read_data;
+ break;
+
+ case IEEE1284_MODE_EPP:
+ DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
+ if (addr)
+ fn = port->ops->epp_read_addr;
+ else
+ fn = port->ops->epp_read_data;
+ break;
+
+ case IEEE1284_MODE_ECP:
+ case IEEE1284_MODE_ECPRLE:
+ DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
+ fn = port->ops->ecp_read_data;
+ break;
+
+ case IEEE1284_MODE_ECPSWE:
+ DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
+ port->name);
+ fn = parport_ieee1284_ecp_read_data;
+ break;
+
+ default:
+ DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
+ port->physport->ieee1284.mode);
+ return -ENOSYS;
+ }
+
+ return (*fn) (port, buffer, len, 0);
+#endif /* IEEE1284 support */
+}
+
+/* Set the amount of time we wait while nothing's happening. */
+long parport_set_timeout (struct pardevice *dev, long inactivity)
+{
+ long int old = dev->timeout;
+
+ dev->timeout = inactivity;
+
+ if (dev->port->physport->cad == dev)
+ parport_ieee1284_wakeup (dev->port);
+
+ return old;
+}
--- /dev/null
+/* IEEE-1284 operations for parport.
+ *
+ * This file is for generic IEEE 1284 operations. The idea is that
+ * they are used by the low-level drivers. If they have a special way
+ * of doing something, they can provide their own routines (and put
+ * the function pointers in port->ops); if not, they can just use these
+ * as a fallback.
+ *
+ * Note: Make no assumptions about hardware or architecture in this file!
+ *
+ * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
+ */
+
+#include <linux/config.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#define DEBUG /* undef me for production */
+
+#ifdef CONFIG_LP_CONSOLE
+#undef DEBUG /* Don't want a garbled console */
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+/*** *
+ * One-way data transfer functions. *
+ * ***/
+
+static inline
+int polling (struct pardevice *dev)
+{
+ return dev->port->irq == PARPORT_IRQ_NONE;
+}
+
+/* Compatibility mode. */
+size_t parport_ieee1284_write_compat (struct parport *port,
+ const void *buffer, size_t len,
+ int flags)
+{
+ ssize_t count = 0;
+ const unsigned char *addr = buffer;
+ unsigned char byte;
+ struct pardevice *dev = port->physport->cad;
+ unsigned char ctl = (PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_INIT);
+
+ if (port->irq != PARPORT_IRQ_NONE)
+ parport_enable_irq (port);
+
+ port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+ while (count < len) {
+ long expire = jiffies + dev->timeout;
+ long wait = (HZ + 99) / 100;
+ unsigned char mask = (PARPORT_STATUS_ERROR
+ | PARPORT_STATUS_BUSY);
+ unsigned char val = (PARPORT_STATUS_ERROR
+ | PARPORT_STATUS_BUSY);
+ int i;
+
+ /* Write the character to the data lines. */
+ byte = *addr++;
+ parport_write_data (port, byte);
+ udelay (1);
+
+ /* Wait until the peripheral's ready */
+ do {
+ /* Is the peripheral ready yet? */
+ if (!parport_wait_peripheral (port, mask, val))
+ /* Skip the loop */
+ goto ready;
+
+ /* Is the peripheral upset? */
+ if ((parport_read_status (port) &
+ (PARPORT_STATUS_PAPEROUT |
+ PARPORT_STATUS_SELECT |
+ PARPORT_STATUS_ERROR))
+ != (PARPORT_STATUS_SELECT |
+ PARPORT_STATUS_ERROR))
+ /* If nFault is asserted (i.e. no
+ * error) and PAPEROUT and SELECT are
+ * just red herrings, give the driver
+ * a chance to check it's happy with
+ * that before continuing. */
+ goto stop;
+
+ /* Have we run out of time? */
+ if (!time_before (jiffies, expire))
+ break;
+
+ /* Yield the port for a while. If this is the
+ first time around the loop, don't let go of
+ the port. This way, we find out if we have
+ our interrupt handler called. */
+ if (count && polling (dev)) {
+ parport_release (dev);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout (wait);
+ parport_claim_or_block (dev);
+ }
+ else
+ /* We must have the device claimed here */
+ parport_wait_event (port, wait);
+
+ /* Is there a signal pending? */
+ if (signal_pending (current))
+ goto stop;
+
+ /* Wait longer next time. */
+ wait *= 2;
+ } while (time_before (jiffies, expire));
+
+ DPRINTK (KERN_DEBUG "%s: Timed out\n", port->name);
+ break;
+
+ ready:
+ /* Clear out previous irqs. */
+ while (!down_trylock (&port->physport->ieee1284.irq));
+
+ /* Pulse strobe. */
+ parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+ udelay (1); /* strobe */
+
+ parport_write_control (port, ctl);
+ udelay (1); /* hold */
+
+ /* Wait until it's received (up to 20us). */
+ for (i = 0; i < 20; i++) {
+ if (!down_trylock (&port->physport->ieee1284.irq) ||
+ !(parport_read_status (port) & PARPORT_STATUS_ACK))
+ break;
+ udelay (1);
+ }
+
+ count++;
+
+ /* Let another process run if it needs to. */
+ if (time_before (jiffies, expire))
+ if (!parport_yield_blocking (dev)
+ && current->need_resched)
+ schedule ();
+ }
+ stop:
+ port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return count;
+}
+
+/* Nibble mode. */
+size_t parport_ieee1284_read_nibble (struct parport *port,
+ void *buffer, size_t len,
+ int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+ return 0;
+#else
+ unsigned char *buf = buffer;
+ int i;
+ unsigned char byte = 0;
+
+ len *= 2; /* in nibbles */
+ for (i=0; i < len; i++) {
+ unsigned char nibble;
+
+ /* Does the error line indicate end of data? */
+ if (((i & 1) == 0) &&
+ (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
+ port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+ DPRINTK (KERN_DEBUG
+ "%s: No more nibble data (%d bytes)\n",
+ port->name, i/2);
+
+ /* Go to reverse idle phase. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+ port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+ break;
+ }
+
+ /* Event 7: Set nAutoFd low. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 9: nAck goes low. */
+ port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK, 0)) {
+ /* Timeout -- no more data? */
+ DPRINTK (KERN_DEBUG
+ "%s: Nibble timeout at event 9 (%d bytes)\n",
+ port->name, i/2);
+ break;
+ }
+
+
+ /* Read a nibble. */
+ nibble = parport_read_status (port) >> 3;
+ nibble &= ~8;
+ if ((nibble & 0x10) == 0)
+ nibble |= 8;
+ nibble &= 0xf;
+
+ /* Event 10: Set nAutoFd high. */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+ /* Event 11: nAck goes high. */
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ACK)) {
+ /* Timeout -- no more data? */
+ DPRINTK (KERN_DEBUG
+ "%s: Nibble timeout at event 11\n",
+ port->name);
+ break;
+ }
+
+ if (i & 1) {
+ /* Second nibble */
+ byte |= nibble << 4;
+ *buf++ = byte;
+ } else
+ byte = nibble;
+ }
+
+ i /= 2; /* i is now in bytes */
+
+ if (i == len) {
+ /* Read the last nibble without checking data avail. */
+ port = port->physport;
+ if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+ port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+ else
+ port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+ }
+
+ return i;
+#endif /* IEEE1284 support */
+}
+
+/* Byte mode. */
+size_t parport_ieee1284_read_byte (struct parport *port,
+ void *buffer, size_t len,
+ int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+ return 0;
+#else
+ unsigned char *buf = buffer;
+ ssize_t count = 0;
+
+ for (count = 0; count < len; count++) {
+ unsigned char byte;
+
+ /* Data available? */
+ if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
+ port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+ DPRINTK (KERN_DEBUG
+ "%s: No more byte data (%d bytes)\n",
+ port->name, count);
+
+ /* Go to reverse idle phase. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+ port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+ break;
+ }
+
+ /* Event 7: Set nAutoFd low. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 9: nAck goes low. */
+ port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA;
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ 0)) {
+ /* Timeout -- no more data? */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+ 0);
+ DPRINTK (KERN_DEBUG "%s: Byte timeout at event 9\n",
+ port->name);
+ break;
+ }
+
+ byte = parport_read_data (port);
+ *buf++ = byte;
+
+ /* Event 10: Set nAutoFd high */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+ /* Event 11: nAck goes high. */
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ACK)) {
+ /* Timeout -- no more data? */
+ DPRINTK (KERN_DEBUG "%s: Byte timeout at event 11\n",
+ port->name);
+ break;
+ }
+
+ /* Event 16: Set nStrobe low. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+ udelay (5);
+
+ /* Event 17: Set nStrobe high. */
+ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+ }
+
+ if (count == len) {
+ /* Read the last byte without checking data avail. */
+ port = port->physport;
+ if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+ port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+ else
+ port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+ }
+
+ return count;
+#endif /* IEEE1284 support */
+}
+
+/*** *
+ * ECP Functions. *
+ * ***/
+
+#ifdef CONFIG_PARPORT_1284
+
+static inline
+int ecp_forward_to_reverse (struct parport *port)
+{
+ int retval;
+
+ /* Event 38: Set nAutoFd low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+ parport_data_reverse (port);
+ udelay (5);
+
+ /* Event 39: Set nInit low to initiate bus reversal */
+ parport_frob_control (port,
+ PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_INIT);
+
+ /* Event 40: PError goes low */
+ retval = parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT, 0);
+
+ if (!retval) {
+ DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n",
+ port->name);
+ port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+ }
+
+ return retval;
+}
+
+static inline
+int ecp_reverse_to_forward (struct parport *port)
+{
+ int retval;
+
+ /* Event 47: Set nInit high */
+ parport_frob_control (port,
+ PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_INIT);
+ parport_data_reverse (port);
+
+ /* Event 49: PError goes high */
+ retval = parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_PAPEROUT);
+
+ if (!retval) {
+ parport_data_forward (port);
+ DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+ port->name);
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+ }
+
+ return retval;
+}
+
+#endif /* IEEE1284 support */
+
+/* ECP mode, forward channel, data. */
+size_t parport_ieee1284_ecp_write_data (struct parport *port,
+ const void *buffer, size_t len,
+ int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+ return 0;
+#else
+ const unsigned char *buf = buffer;
+ size_t written;
+ int ctl = parport_read_control (port) & ~PARPORT_CONTROL_AUTOFD;
+ int retry;
+
+ port = port->physport;
+
+ if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
+ if (ecp_reverse_to_forward (port))
+ return 0;
+
+ port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+ /* HostAck high (data, not command) */
+ parport_write_control (port, ctl);
+ for (written = 0; written < len; written++, buf++) {
+ long expire = jiffies + port->cad->timeout;
+ unsigned char byte;
+
+ byte = *buf;
+ try_again:
+ parport_write_data (port, byte);
+ parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+ udelay (5);
+ for (retry = 0; retry < 100; retry++) {
+ if (!parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY, 0))
+ goto success;
+
+ if (signal_pending (current)) {
+ parport_write_control (port, ctl);
+ break;
+ }
+ }
+
+ /* Time for Host Transfer Recovery (page 41 of IEEE1284) */
+ DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
+
+ parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
+ udelay (50);
+ if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
+ /* It's buggered. */
+ parport_write_control (port, ctl);
+ break;
+ }
+
+ parport_write_control (port, ctl);
+ udelay (50);
+ if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
+ break;
+
+ DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
+ port->name);
+
+ if (time_after_eq (jiffies, expire)) break;
+ goto try_again;
+ success:
+ parport_write_control (port, ctl);
+ udelay (5);
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ /* Peripheral hasn't accepted the data. */
+ break;
+ }
+
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return written;
+#endif /* IEEE1284 support */
+}
+
+/* ECP mode, reverse channel, data. */
+size_t parport_ieee1284_ecp_read_data (struct parport *port,
+ void *buffer, size_t len, int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+ return 0;
+#else
+ struct pardevice *dev = port->cad;
+ unsigned char *buf = buffer;
+ int rle_count = 0; /* shut gcc up */
+ int rle = 0;
+ ssize_t count = 0;
+
+ port = port->physport;
+
+ if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE)
+ if (ecp_forward_to_reverse (port))
+ return 0;
+
+ port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+
+ /* Set HostAck low to start accepting data. */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+ while (count < len) {
+ long expire = jiffies + dev->timeout;
+ unsigned char byte;
+ int command;
+
+ /* Event 43: Peripheral sets nAck low. It can take as
+ long as it wants. */
+ while (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ACK)) {
+ /* The peripheral hasn't given us data in
+ 35ms. If we have data to give back to the
+ caller, do it now. */
+ if (count)
+ goto out;
+
+ /* If we've used up all the time we were allowed,
+ give up altogether. */
+ if (!time_before (jiffies, expire))
+ goto out;
+
+ /* Yield the port for a while. */
+ if (count && polling (dev)) {
+ parport_release (dev);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout ((HZ + 99) / 25);
+ parport_claim_or_block (dev);
+ }
+ else
+ /* We must have the device claimed here. */
+ parport_wait_event (port, (HZ + 99) / 25);
+
+ /* Is there a signal pending? */
+ if (signal_pending (current))
+ goto out;
+ }
+
+ /* Is this a command? */
+ if (rle)
+ /* The last byte was a run-length count, so
+ this can't be as well. */
+ command = 0;
+ else
+ command = (parport_read_status (port) &
+ PARPORT_STATUS_BUSY) ? 1 : 0;
+
+ /* Read the data. */
+ byte = parport_read_data (port);
+
+ /* If this is a channel command, rather than an RLE
+ command or a normal data byte, don't accept it. */
+ if (command) {
+ if (byte & 0x80) {
+ DPRINTK (KERN_DEBUG "%s: stopping short at "
+ "channel command (%02x)\n",
+ port->name, byte);
+ goto out;
+ }
+ else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE)
+ DPRINTK (KERN_DEBUG "%s: device illegally "
+ "using RLE; accepting anyway\n",
+ port->name);
+
+ rle_count = byte + 1;
+
+ /* Are we allowed to read that many bytes? */
+ if (rle_count > (len - count)) {
+ DPRINTK (KERN_DEBUG "%s: leaving %d RLE bytes "
+ "for next time\n", port->name,
+ rle_count);
+ break;
+ }
+
+ rle = 1;
+ }
+
+ /* Event 44: Set HostAck high, acknowledging handshake. */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+ /* Event 45: The peripheral has 35ms to set nAck high. */
+ if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
+ /* It's gone wrong. Return what data we have
+ to the caller. */
+ DPRINTK (KERN_DEBUG "ECP read timed out at 45\n");
+
+ if (command)
+ printk (KERN_WARNING
+ "%s: command ignored (%02x)\n",
+ port->name, byte);
+
+ break;
+ }
+
+ /* Event 46: Set HostAck low and accept the data. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* If we just read a run-length count, fetch the data. */
+ if (command)
+ continue;
+
+ /* If this is the byte after a run-length count, decompress. */
+ if (rle) {
+ rle = 0;
+ memset (buf, byte, rle_count);
+ buf += rle_count;
+ count += rle_count;
+ DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n",
+ port->name, rle_count);
+ }
+ else
+ /* Normal data byte. */
+ *buf++ = byte, count++;
+ }
+
+ out:
+ return count;
+#endif /* IEEE1284 support */
+}
+
+/* ECP mode, forward channel, commands. */
+size_t parport_ieee1284_ecp_write_addr (struct parport *port,
+ const void *buffer, size_t len,
+ int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+ return 0;
+#else
+ const unsigned char *buf = buffer;
+ size_t written;
+ int ctl = parport_read_control (port) | PARPORT_CONTROL_AUTOFD;
+ int retry;
+
+ port = port->physport;
+
+ if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
+ if (ecp_reverse_to_forward (port))
+ return 0;
+
+ port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+ /* HostAck low (command, not data) */
+ parport_write_control (port, ctl);
+ for (written = 0; written < len; written++, buf++) {
+ long expire = jiffies + port->cad->timeout;
+ unsigned char byte;
+
+ byte = *buf;
+ try_again:
+ parport_write_data (port, byte);
+ parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+ udelay (5);
+ for (retry = 0; retry < 100; retry++) {
+ if (!parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY, 0))
+ goto success;
+
+ if (signal_pending (current)) {
+ parport_write_control (port, ctl);
+ break;
+ }
+ }
+
+ /* Time for Host Transfer Recovery (page 41 of IEEE1284) */
+ DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
+
+ parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
+ udelay (50);
+ if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
+ /* It's buggered. */
+ parport_write_control (port, ctl);
+ break;
+ }
+
+ parport_write_control (port, ctl);
+ udelay (50);
+ if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
+ break;
+
+ DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
+ port->name);
+
+ if (time_after_eq (jiffies, expire)) break;
+ goto try_again;
+ success:
+ parport_write_control (port, ctl);
+ udelay (5);
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ /* Peripheral hasn't accepted the data. */
+ break;
+ }
+
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return written;
+#endif /* IEEE1284 support */
+}
+
+/*** *
+ * EPP functions. *
+ * ***/
+
+/* EPP mode, forward channel, data. */
+size_t parport_ieee1284_epp_write_data (struct parport *port,
+ const void *buffer, size_t len,
+ int flags)
+{
+ /* This is untested */
+ unsigned char *bp = (unsigned char *) buffer;
+ size_t ret = 0;
+
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_SELECT,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_SELECT);
+ port->ops->data_forward (port);
+ for (; len > 0; len--, bp++) {
+ parport_write_data (port, *bp);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ break;
+
+ /* Strobe data */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+ break;
+
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+ ret++;
+ }
+
+ return ret;
+}
+
+/* EPP mode, reverse channel, data. */
+size_t parport_ieee1284_epp_read_data (struct parport *port,
+ void *buffer, size_t len,
+ int flags)
+{
+ /* This is untested. */
+ unsigned char *bp = (unsigned char *) buffer;
+ unsigned ret = 0;
+
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_SELECT, 0);
+ port->ops->data_reverse (port);
+ for (; len > 0; len--, bp++) {
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ break;
+
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+ break;
+
+ *bp = parport_read_data (port);
+
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+ ret++;
+ }
+ port->ops->data_forward (port);
+
+ return ret;
+}
+
+/* EPP mode, forward channel, addresses. */
+size_t parport_ieee1284_epp_write_addr (struct parport *port,
+ const void *buffer, size_t len,
+ int flags)
+{
+ /* This is untested */
+ unsigned char *bp = (unsigned char *) buffer;
+ size_t ret = 0;
+
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_SELECT |
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_SELECT);
+ port->ops->data_forward (port);
+ for (; len > 0; len--, bp++) {
+ parport_write_data (port, *bp);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ break;
+
+ /* Strobe data */
+ parport_frob_control (port, PARPORT_CONTROL_SELECT,
+ PARPORT_CONTROL_SELECT);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+ break;
+
+ parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+ ret++;
+ }
+
+ return ret;
+}
+
+/* EPP mode, reverse channel, addresses. */
+size_t parport_ieee1284_epp_read_addr (struct parport *port,
+ void *buffer, size_t len,
+ int flags)
+{
+ /* This is untested. */
+ unsigned char *bp = (unsigned char *) buffer;
+ unsigned ret = 0;
+
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_SELECT |
+ PARPORT_CONTROL_AUTOFD, 0);
+ port->ops->data_reverse (port);
+ for (; len > 0; len--, bp++) {
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ break;
+
+ parport_frob_control (port, PARPORT_CONTROL_SELECT,
+ PARPORT_CONTROL_SELECT);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+ break;
+
+ *bp = parport_read_data (port);
+
+ parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+ ret++;
+ }
+ port->ops->data_forward (port);
+
+ return ret;
+}
--- /dev/null
+/* Parallel-port initialisation code.
+ *
+ * Authors: David Campbell <campbell@torque.net>
+ * Tim Waugh <tim@cyberelk.demon.co.uk>
+ * Jose Renau <renau@acm.org>
+ *
+ * based on work by Grant Guenther <grant@torque.net>
+ * and Philip Blundell <Philip.Blundell@pobox.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/threads.h>
+
+#include <linux/parport.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+
+#ifndef MODULE
+static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
+static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
+static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
+static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
+
+extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma);
+extern int parport_ax_init(void);
+
+static int parport_setup_ptr __initdata = 0;
+
+__initfunc(void parport_setup(char *str, int *ints))
+{
+ if (ints[0] == 0) {
+ if (str && !strncmp(str, "auto", 4)) {
+ irq[0] = PARPORT_IRQ_AUTO;
+ dma[0] = PARPORT_DMA_AUTO;
+ }
+ else if (str)
+ printk (KERN_ERR "parport: `%s': huh?\n", str);
+ else
+ printk (KERN_ERR "parport: parport=.. what?\n");
+
+ return;
+ }
+ else if (ints[1] == 0) {
+ /* Disable parport if "parport=0" in cmdline */
+ io[0] = PARPORT_DISABLE;
+ return;
+ }
+
+ if (parport_setup_ptr < PARPORT_MAX) {
+ char *sep;
+ io[parport_setup_ptr] = ints[1];
+ irq[parport_setup_ptr] = PARPORT_IRQ_NONE;
+ dma[parport_setup_ptr] = PARPORT_DMA_NONE;
+ if (ints[0] > 1) {
+ irq[parport_setup_ptr] = ints[2];
+ if (ints[0] > 2) {
+ dma[parport_setup_ptr] = ints[3];
+ goto done;
+ }
+
+ if (str == NULL)
+ goto done;
+
+ goto dma_from_str;
+ }
+ else if (str == NULL)
+ goto done;
+ else if (!strncmp(str, "auto", 4))
+ irq[parport_setup_ptr] = PARPORT_IRQ_AUTO;
+ else if (strncmp(str, "none", 4) != 0) {
+ printk(KERN_ERR "parport: bad irq `%s'\n", str);
+ return;
+ }
+
+ if ((sep = strchr(str, ',')) == NULL) goto done;
+ str = sep+1;
+ dma_from_str:
+ if (!strncmp(str, "auto", 4))
+ dma[parport_setup_ptr] = PARPORT_DMA_AUTO;
+ else if (strncmp(str, "none", 4) != 0) {
+ char *ep;
+ dma[parport_setup_ptr] = simple_strtoul(str, &ep, 0);
+ if (ep == str) {
+ printk(KERN_ERR "parport: bad dma `%s'\n",
+ str);
+ return;
+ }
+ }
+ done:
+ parport_setup_ptr++;
+ } else
+ printk(KERN_ERR "parport=%s ignored, too many ports\n", str);
+}
+#endif
+
+#ifdef MODULE
+int init_module(void)
+{
+#ifdef CONFIG_SYSCTL
+ parport_default_proc_register ();
+#endif
+ return 0;
+}
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_SYSCTL
+ parport_default_proc_unregister ();
+#endif
+}
+
+#else
+
+__initfunc(int parport_init(void))
+{
+ if (io[0] == PARPORT_DISABLE)
+ return 1;
+
+#ifdef CONFIG_SYSCTL
+ parport_default_proc_register ();
+#endif
+
+#ifdef CONFIG_PARPORT_PC
+ parport_pc_init(io, io_hi, irq, dma);
+#endif
+#ifdef CONFIG_PARPORT_AX
+ parport_ax_init();
+#endif
+#ifdef CONFIG_PARPORT_AMIGA
+ parport_amiga_init();
+#endif
+#ifdef CONFIG_PARPORT_MFC3
+ parport_mfc3_init();
+#endif
+#ifdef CONFIG_PARPORT_ATARI
+ parport_atari_init();
+#endif
+#ifdef CONFIG_PARPORT_ARC
+ parport_arc_init();
+#endif
+ return 0;
+}
+#endif
+
+/* Exported symbols for modules. */
+
+EXPORT_SYMBOL(parport_claim);
+EXPORT_SYMBOL(parport_claim_or_block);
+EXPORT_SYMBOL(parport_release);
+EXPORT_SYMBOL(parport_register_port);
+EXPORT_SYMBOL(parport_announce_port);
+EXPORT_SYMBOL(parport_unregister_port);
+EXPORT_SYMBOL(parport_register_driver);
+EXPORT_SYMBOL(parport_unregister_driver);
+EXPORT_SYMBOL(parport_register_device);
+EXPORT_SYMBOL(parport_unregister_device);
+EXPORT_SYMBOL(parport_enumerate);
+EXPORT_SYMBOL(parport_negotiate);
+EXPORT_SYMBOL(parport_write);
+EXPORT_SYMBOL(parport_read);
+EXPORT_SYMBOL(parport_ieee1284_wakeup);
+EXPORT_SYMBOL(parport_wait_peripheral);
+EXPORT_SYMBOL(parport_wait_event);
+EXPORT_SYMBOL(parport_set_timeout);
+EXPORT_SYMBOL(parport_ieee1284_interrupt);
+EXPORT_SYMBOL(parport_ieee1284_ecp_write_data);
+EXPORT_SYMBOL(parport_ieee1284_ecp_read_data);
+EXPORT_SYMBOL(parport_ieee1284_ecp_write_addr);
+EXPORT_SYMBOL(parport_ieee1284_write_compat);
+EXPORT_SYMBOL(parport_ieee1284_read_nibble);
+EXPORT_SYMBOL(parport_ieee1284_read_byte);
+EXPORT_SYMBOL(parport_ieee1284_epp_write_data);
+EXPORT_SYMBOL(parport_ieee1284_epp_read_data);
+EXPORT_SYMBOL(parport_ieee1284_epp_write_addr);
+EXPORT_SYMBOL(parport_ieee1284_epp_read_addr);
+EXPORT_SYMBOL(parport_proc_register);
+EXPORT_SYMBOL(parport_proc_unregister);
+EXPORT_SYMBOL(parport_device_proc_register);
+EXPORT_SYMBOL(parport_device_proc_unregister);
+EXPORT_SYMBOL(parport_default_proc_register);
+EXPORT_SYMBOL(parport_default_proc_unregister);
+EXPORT_SYMBOL(parport_parse_irqs);
+EXPORT_SYMBOL(parport_parse_dmas);
+#ifdef CONFIG_PARPORT_1284
+EXPORT_SYMBOL(parport_open);
+EXPORT_SYMBOL(parport_close);
+EXPORT_SYMBOL(parport_device_id);
+EXPORT_SYMBOL(parport_device_num);
+EXPORT_SYMBOL(parport_device_coords);
+EXPORT_SYMBOL(parport_daisy_deselect_all);
+EXPORT_SYMBOL(parport_daisy_select);
+EXPORT_SYMBOL(parport_daisy_init);
+#endif
+
+void inc_parport_count(void)
+{
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+}
+
+void dec_parport_count(void)
+{
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
--- /dev/null
+#ifndef _MULTIFACE_H_
+#define _MULTIFACE_H_
+
+/*
+ * Defines for SerialMaster, Multiface Card II and Multiface Card III
+ * The addresses given below are offsets to the board base address
+ *
+ * 6.11.95 Joerg Dorchain (dorchain@mpi-sb.mpg.de)
+ *
+ */
+
+#define PIA_REG_PADWIDTH 255
+
+#define DUARTBASE 0x0000
+#define PITBASE 0x0100
+#define ROMBASE 0x0200
+#define PIABASE 0x4000
+
+#endif
+
--- /dev/null
+/* Low-level parallel port routines for the Amiga buildin port
+ *
+ * Author: Joerg Dorchain <dorchain@wirbel.com>
+ *
+ * This is a complete rewrite of the code, but based heaviy upon the old
+ * lp_intern. code.
+ *
+ * The built-in Amiga parallel port provides one port at a fixed address
+ * with 8 bisdirecttional data lines (D0 - D7) and 3 bidirectional status
+ * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically in
+ * hardware when the data register is accessed), and 1 input control line
+ * /ACK, able to cause an interrupt, but both not directly settable by
+ * software.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port = NULL;
+
+static void amiga_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+ /* Triggers also /STROBE. This behavior cannot be changed */
+ ciaa.prb = data;
+}
+
+static unsigned char amiga_read_data(struct parport *p)
+{
+ /* Triggers also /STROBE. This behavior cannot be changed */
+ return ciaa.prb;
+}
+
+#if 0
+static unsigned char control_pc_to_amiga(unsigned char control)
+{
+ unsigned char ret = 0;
+
+ if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+ ;
+ if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+ ;
+ if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+ ;
+ if (control & PARPORT_CONTROL_INIT) /* INITP */
+ /* reset connected to cpu reset pin */;
+ if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+ /* Not connected */;
+ if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+ /* Handled only directly by hardware */;
+ return ret;
+}
+#endif
+
+static unsigned char control_amiga_to_pc(unsigned char control)
+{
+ return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT |
+ PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
+ /* fake value: interrupt enable, select in, no reset,
+ no autolf, no strobe - seems to be closest the wiring diagram */
+}
+
+static void amiga_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+ /* No implementation possible */
+}
+
+static unsigned char amiga_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+ return control_amiga_to_pc(0);
+}
+
+static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+ unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+ old = amiga_read_control(p);
+ amiga_write_control(p, (old & ~mask) ^ val);
+ return old;
+}
+
+
+static unsigned char status_pc_to_amiga(unsigned char status)
+{
+ unsigned char ret = 1;
+
+ if (status & PARPORT_STATUS_BUSY) /* Busy */
+ ret &= ~1;
+ if (status & PARPORT_STATUS_ACK) /* Ack */
+ /* handled in hardware */;
+ if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+ ret |= 2;
+ if (status & PARPORT_STATUS_SELECT) /* select */
+ ret |= 4;
+ if (status & PARPORT_STATUS_ERROR) /* error */
+ /* not connected */;
+ return ret;
+}
+
+static unsigned char status_amiga_to_pc(unsigned char status)
+{
+ unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
+
+ if (status & 1) /* Busy */
+ ret &= ~PARPORT_STATUS_BUSY;
+ if (status & 2) /* PaperOut */
+ ret |= PARPORT_STATUS_PAPEROUT;
+ if (status & 4) /* Selected */
+ ret |= PARPORT_STATUS_SELECT;
+ /* the rest is not connected or handled autonomously in hardware */
+
+ return ret;
+}
+
+static void amiga_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+ ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status);
+}
+
+static unsigned char amiga_read_status(struct parport *p)
+{
+ unsigned char status;
+
+ status = status_amiga_to_pc(ciab.pra & 7);
+DPRINTK("read_status %02x\n", status);
+ return status;
+}
+
+static void amiga_change_mode( struct parport *p, int m)
+{
+ /* XXX: This port only has one mode, and I am
+ not sure about the corresponding PC-style mode*/
+}
+
+/* as this ports irq handling is already done, we use a generic funktion */
+static void amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+
+static void amiga_init_state(struct parport_state *s)
+{
+ s->u.amiga.data = 0;
+ s->u.amiga.datadir = 255;
+ s->u.amiga.status = 0;
+ s->u.amiga.statusdir = 0;
+}
+
+static void amiga_save_state(struct parport *p, struct parport_state *s)
+{
+ s->u.amiga.data = ciaa.prb;
+ s->u.amiga.datadir = ciaa.ddrb;
+ s->u.amiga.status = ciab.pra & 7;
+ s->u.amiga.statusdir = ciab.ddra & 7;
+}
+
+static void amiga_restore_state(struct parport *p, struct parport_state *s)
+{
+ ciaa.prb = s->u.amiga.data;
+ ciaa.ddrb = s->u.amiga.datadir;
+ ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status;
+ ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir;
+}
+
+static void amiga_enable_irq(struct parport *p)
+{
+ enable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_disable_irq(struct parport *p)
+{
+ disable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void amiga_dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static void amiga_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations pp_amiga_ops = {
+ amiga_write_data,
+ amiga_read_data,
+
+ amiga_write_control,
+ amiga_read_control,
+ amiga_frob_control,
+
+ NULL, /* write_econtrol */
+ NULL, /* read_econtrol */
+ NULL, /* frob_econtrol */
+
+ amiga_write_status,
+ amiga_read_status,
+
+ NULL, /* write fifo */
+ NULL, /* read fifo */
+
+ amiga_change_mode,
+
+
+ NULL, /* epp_write_data */
+ NULL, /* epp_read_data */
+ NULL, /* epp_write_addr */
+ NULL, /* epp_read_addr */
+ NULL, /* epp_check_timeout */
+
+ NULL, /* epp_write_block */
+ NULL, /* epp_read_block */
+
+ NULL, /* ecp_write_block */
+ NULL, /* ecp_read_block */
+
+ amiga_init_state,
+ amiga_save_state,
+ amiga_restore_state,
+
+ amiga_enable_irq,
+ amiga_disable_irq,
+ amiga_interrupt,
+
+ amiga_inc_use_count,
+ amiga_dec_use_count,
+ amiga_fill_inode
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_amiga_init(void))
+{
+ struct parport *p;
+
+ if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) {
+ ciaa.ddrb = 0xff;
+ ciab.ddra &= 0xf8;
+ if (!(p = parport_register_port((unsigned long)&ciaa.prb,
+ IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
+ &pp_amiga_ops)))
+ return 0;
+ this_port = p;
+ printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
+ /* XXX: set operating mode */
+ parport_proc_register(p);
+ if (request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0,
+ p->name, p)) {
+ parport_unregister_port (p);
+ return 0;
+ }
+
+ if (parport_probe_hook)
+ (*parport_probe_hook)(p);
+
+ parport_announce_port (p);
+
+ return 1;
+
+ }
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Joerg Dorchain");
+MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
+MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port");
+
+int init_module(void)
+{
+ return ! parport_amiga_init();
+}
+
+void cleanup_module(void)
+{
+ if (p->irq != PARPORT_IRQ_NONE)
+ free_irq(IRQ_AMIGA_CIAA_FLG, p);
+ parport_proc_unregister(this_port);
+ parport_unregister_port(this_port);
+}
+#endif
+
+
--- /dev/null
+/* Low-level parallel port routines for Archimedes onboard hardware
+ *
+ * Author: Phil Blundell <Philip.Blundell@pobox.com>
+ */
+
+/* This driver is for the parallel port hardware found on Acorn's old
+ * range of Archimedes machines. The A5000 and newer systems have PC-style
+ * I/O hardware and should use the parport_pc driver instead.
+ *
+ * The Acorn printer port hardware is very simple. There is a single 8-bit
+ * write-only latch for the data port and control/status bits are handled
+ * with various auxilliary input and output lines. The port is not
+ * bidirectional, does not support any modes other than SPP, and has only
+ * a subset of the standard printer control lines connected.
+ */
+
+#include <linux/threads.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/parport.h>
+
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/arch/oldlatches.h>
+#include <asm/arch/irqs.h>
+
+#define DATA_ADDRESS 0x3350010
+
+/* This is equivalent to the above and only used for request_region. */
+#define PORT_BASE 0x80000000 | ((DATA_ADDRESS - IO_BASE) >> 2)
+
+/* The hardware can't read from the data latch, so we must use a soft
+ copy. */
+static unsigned char data_copy;
+
+/* These are pretty simple. We know the irq is never shared and the
+ kernel does all the magic that's required. */
+static void arc_enable_irq(struct parport *p)
+{
+ enable_irq(p->irq);
+}
+
+static void arc_disable_irq(struct parport *p)
+{
+ disable_irq(p->irq);
+}
+
+static void arc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+static void arc_write_data(struct parport *p, unsigned char data)
+{
+ data_copy = data;
+ outb_t(data, DATA_LATCH);
+}
+
+static unsigned char arc_read_data(struct parport *p)
+{
+ return data_copy;
+}
+
+static void arc_inc_use_count(void)
+{
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+}
+
+static void arc_dec_use_count(void)
+{
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+static void arc_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations parport_arc_ops =
+{
+ arc_write_data,
+ arc_read_data,
+
+ arc_write_control,
+ arc_read_control,
+ arc_frob_control,
+
+ arc_read_status,
+
+ arc_enable_irq,
+ arc_disable_irq,
+
+ arc_data_forward,
+ arc_data_reverse,
+
+ arc_interrupt,
+
+ arc_init_state,
+ arc_save_state,
+ arc_restore_state,
+
+ arc_inc_use_count,
+ arc_dec_use_count,
+ arc_fill_inode,
+
+ parport_ieee1284_epp_write_data,
+ parport_ieee1284_epp_read_data,
+ parport_ieee1284_epp_write_addr,
+ parport_ieee1284_epp_read_addr,
+
+ parport_ieee1284_ecp_write_data,
+ parport_ieee1284_ecp_read_data,
+ parport_ieee1284_ecp_write_addr,
+
+ parport_ieee1284_write_compat,
+ parport_ieee1284_read_nibble,
+ parport_ieee1284_read_byte,
+};
+
+/* --- Initialisation code -------------------------------- */
+
+int parport_arc_init(void)
+{
+ /* Archimedes hardware provides only one port, at a fixed address */
+ struct parport *p;
+
+ if (check_region(PORT_BASE, 1))
+ return 0;
+
+ p = parport_register_port (PORT_BASE, IRQ_PRINTERACK,
+ PARPORT_DMA_NONE, &parport_arc_ops);
+
+ if (!p)
+ return 0;
+
+ p->modes = PARPORT_MODE_ARCSPP;
+ p->size = 1;
+
+ printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n",
+ p->irq);
+ parport_proc_register(p);
+
+ /* Tell the high-level drivers about the port. */
+ parport_announce_port (p);
+
+ return 1;
+}
--- /dev/null
+/* Low-level parallel port routines for the Atari builtin port
+ *
+ * Author: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+ *
+ * Based on parport_amiga.c.
+ *
+ * The built-in Atari parallel port provides one port at a fixed address
+ * with 8 output data lines (D0 - D7), 1 output control line (STROBE)
+ * and 1 input status line (BUSY) able to cause an interrupt.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/irq.h>
+#include <asm/atariints.h>
+
+static struct parport *this_port = NULL;
+
+static unsigned char
+parport_atari_read_data(struct parport *p)
+{
+ unsigned long flags;
+ unsigned char data;
+
+ save_flags(flags);
+ cli();
+ sound_ym.rd_data_reg_sel = 15;
+ data = sound_ym.rd_data_reg_sel;
+ restore_flags(flags);
+ return data;
+}
+
+static void
+parport_atari_write_data(struct parport *p, unsigned char data)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ sound_ym.rd_data_reg_sel = 15;
+ sound_ym.wd_data = data;
+ restore_flags(flags);
+}
+
+static unsigned char
+parport_atari_read_control(struct parport *p)
+{
+ unsigned long flags;
+ unsigned char control = 0;
+
+ save_flags(flags);
+ cli();
+ sound_ym.rd_data_reg_sel = 14;
+ if (!(sound_ym.rd_data_reg_sel & (1 << 5)))
+ control = PARPORT_CONTROL_STROBE;
+ restore_flags(flags);
+ return control;
+}
+
+static void
+parport_atari_write_control(struct parport *p, unsigned char control)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ sound_ym.rd_data_reg_sel = 14;
+ if (control & PARPORT_CONTROL_STROBE)
+ sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
+ else
+ sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
+ restore_flags(flags);
+}
+
+static unsigned char
+parport_atari_frob_control(struct parport *p, unsigned char mask,
+ unsigned char val)
+{
+ unsigned char old = parport_atari_read_control(p);
+ parport_atari_write_control(p, (old & ~mask) ^ val);
+ return old;
+}
+
+static unsigned char
+parport_atari_read_status(struct parport *p)
+{
+ return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
+ PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
+}
+
+static void
+parport_atari_write_status(struct parport *p, unsigned char status)
+{
+}
+
+static void
+parport_atari_init_state(struct parport_state *s)
+{
+}
+
+static void
+parport_atari_save_state(struct parport *p, struct parport_state *s)
+{
+}
+
+static void
+parport_atari_restore_state(struct parport *p, struct parport_state *s)
+{
+}
+
+static void
+parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+static void
+parport_atari_inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void
+parport_atari_dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static void
+parport_atari_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations parport_atari_ops = {
+ parport_atari_write_data,
+ parport_atari_read_data,
+
+ parport_atari_write_control,
+ parport_atari_read_control,
+ parport_atari_frob_control,
+
+ NULL, /* write_econtrol */
+ NULL, /* read_econtrol */
+ NULL, /* frob_econtrol */
+
+ parport_atari_write_status,
+ parport_atari_read_status,
+
+ NULL, /* write fifo */
+ NULL, /* read fifo */
+
+ NULL, /* change_mode */
+
+ NULL, /* epp_write_data */
+ NULL, /* epp_read_data */
+ NULL, /* epp_write_addr */
+ NULL, /* epp_read_addr */
+ NULL, /* epp_check_timeout */
+
+ NULL, /* epp_write_block */
+ NULL, /* epp_read_block */
+
+ NULL, /* ecp_write_block */
+ NULL, /* ecp_read_block */
+
+ parport_atari_init_state,
+ parport_atari_save_state,
+ parport_atari_restore_state,
+
+ NULL, /* enable_irq */
+ NULL, /* disable_irq */
+ parport_atari_interrupt,
+
+ parport_atari_inc_use_count,
+ parport_atari_dec_use_count,
+ parport_atari_fill_inode
+};
+
+
+int __init
+parport_atari_init(void)
+{
+ struct parport *p;
+ unsigned long flags;
+
+ if (MACH_IS_ATARI) {
+ save_flags(flags);
+ cli();
+ /* Soundchip port A/B as output. */
+ sound_ym.rd_data_reg_sel = 7;
+ sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
+ /* STROBE high. */
+ sound_ym.rd_data_reg_sel = 14;
+ sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
+ restore_flags(flags);
+ /* MFP port I0 as input. */
+ mfp.data_dir &= ~1;
+ /* MFP port I0 interrupt on high->low edge. */
+ mfp.active_edge &= ~1;
+ p = parport_register_port((unsigned long)&sound_ym.wd_data,
+ IRQ_MFP_BUSY, PARPORT_DMA_NONE,
+ &parport_atari_ops);
+ if (!p)
+ return 0;
+ if (request_irq(IRQ_MFP_BUSY, parport_atari_interrupt,
+ IRQ_TYPE_SLOW, p->name, p)) {
+ parport_unregister_port (p);
+ return 0;
+ }
+
+ this_port = p;
+ printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name);
+ parport_proc_register(p);
+
+ parport_announce_port (p);
+
+ return 1;
+ }
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Andreas Schwab");
+MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
+MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
+
+int
+init_module(void)
+{
+ return parport_atari_init() ? 0 : -ENODEV;
+}
+
+void
+cleanup_module(void)
+{
+ if (p->irq != PARPORT_IRQ_NONE)
+ free_irq(IRQ_MFP_BUSY, p);
+ parport_proc_unregister(this_port);
+ parport_unregister_port(this_port);
+}
+#endif
--- /dev/null
+/* $Id: parport_ax.c,v 1.20 1999/07/03 08:56:21 davem Exp $
+ * Parallel-port routines for Sun Ultra/AX architecture
+ *
+ * Author: Eddie C. Dost <ecd@skynet.be>
+ *
+ * based on work by:
+ * Phil Blundell <Philip.Blundell@pobox.com>
+ * Tim Waugh <tim@cyberelk.demon.co.uk>
+ * Jose Renau <renau@acm.org>
+ * David Campbell <campbell@tirian.che.curtin.edu.au>
+ * Grant Guenther <grant@torque.net>
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+
+#include <linux/parport.h>
+
+#include <asm/ptrace.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/ebus.h>
+#include <asm/ns87303.h>
+#include <asm/irq.h>
+
+
+/*
+ * Define this if you have Devices which don't support short
+ * host read/write cycles.
+ */
+#undef HAVE_SLOW_DEVICES
+
+
+#define DATA 0x00
+#define STATUS 0x01
+#define CONTROL 0x02
+#define EPPADDR 0x03
+#define EPPDATA 0x04
+
+#define CFIFO 0x400
+#define DFIFO 0x400
+#define TFIFO 0x400
+#define CONFIGA 0x400
+#define CONFIGB 0x401
+#define ECONTROL 0x402
+
+static void parport_ax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+void
+parport_ax_write_epp(struct parport *p, unsigned char d)
+{
+ outb(d, p->base + EPPDATA);
+}
+
+unsigned char
+parport_ax_read_epp(struct parport *p)
+{
+ return inb(p->base + EPPDATA);
+}
+
+void
+parport_ax_write_epp_addr(struct parport *p, unsigned char d)
+{
+ outb(d, p->base + EPPADDR);
+}
+
+unsigned char
+parport_ax_read_epp_addr(struct parport *p)
+{
+ return inb(p->base + EPPADDR);
+}
+
+int parport_ax_epp_clear_timeout(struct parport *pb);
+
+int
+parport_ax_check_epp_timeout(struct parport *p)
+{
+ if (!(inb(p->base+STATUS) & 1))
+ return 0;
+ parport_ax_epp_clear_timeout(p);
+ return 1;
+}
+
+unsigned char
+parport_ax_read_configb(struct parport *p)
+{
+ return inb(p->base + CONFIGB);
+}
+
+void
+parport_ax_write_data(struct parport *p, unsigned char d)
+{
+ outb(d, p->base + DATA);
+}
+
+unsigned char
+parport_ax_read_data(struct parport *p)
+{
+ return inb(p->base + DATA);
+}
+
+void
+parport_ax_write_control(struct parport *p, unsigned char d)
+{
+ outb(d, p->base + CONTROL);
+}
+
+unsigned char
+parport_ax_read_control(struct parport *p)
+{
+ return inb(p->base + CONTROL);
+}
+
+unsigned char
+parport_ax_frob_control(struct parport *p, unsigned char mask, unsigned char val)
+{
+ unsigned char old = inb(p->base + CONTROL);
+ outb(((old & ~mask) ^ val), p->base + CONTROL);
+ return old;
+}
+
+void
+parport_ax_write_status(struct parport *p, unsigned char d)
+{
+ outb(d, p->base + STATUS);
+}
+
+unsigned char
+parport_ax_read_status(struct parport *p)
+{
+ return inb(p->base + STATUS);
+}
+
+void
+parport_ax_write_econtrol(struct parport *p, unsigned char d)
+{
+ outb(d, p->base + ECONTROL);
+}
+
+unsigned char
+parport_ax_read_econtrol(struct parport *p)
+{
+ return inb(p->base + ECONTROL);
+}
+
+unsigned char
+parport_ax_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val)
+{
+ unsigned char old = inb(p->base + ECONTROL);
+ outb(((old & ~mask) ^ val), p->base + ECONTROL);
+ return old;
+}
+
+void
+parport_ax_change_mode(struct parport *p, int m)
+{
+ /* FIXME */
+ parport_ax_frob_econtrol(p, 0xe0, m << 5);
+}
+
+void
+parport_ax_write_fifo(struct parport *p, unsigned char v)
+{
+ outb(v, p->base + DFIFO);
+}
+
+unsigned char
+parport_ax_read_fifo(struct parport *p)
+{
+ return inb(p->base + DFIFO);
+}
+
+void
+parport_ax_disable_irq(struct parport *p)
+{
+ struct linux_ebus_dma *dma = p->private_data;
+ unsigned int dcsr;
+
+ dcsr = readl((unsigned long)&dma->dcsr);
+ dcsr &= ~(EBUS_DCSR_INT_EN);
+ writel(dcsr, (unsigned long)&dma->dcsr);
+}
+
+void
+parport_ax_enable_irq(struct parport *p)
+{
+ struct linux_ebus_dma *dma = p->private_data;
+ unsigned int dcsr;
+
+ dcsr = readl((unsigned long)&dma->dcsr);
+ dcsr |= EBUS_DCSR_INT_EN;
+ writel(dcsr, (unsigned long)&dma->dcsr);
+}
+
+void
+parport_ax_init_state(struct pardevice *dev, struct parport_state *s)
+{
+ struct linux_ebus_dma *dma = dev->port->private_data;
+
+ s->u.ax.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+ s->u.ax.ecr = 0x0;
+
+ if (dev->irq_func)
+ s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
+ | EBUS_DCSR_INT_EN);
+ else
+ s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
+ & ~EBUS_DCSR_INT_EN);
+}
+
+void
+parport_ax_save_state(struct parport *p, struct parport_state *s)
+{
+ struct linux_ebus_dma *dma = p->private_data;
+
+ s->u.ax.ctr = parport_ax_read_control(p);
+ s->u.ax.ecr = parport_ax_read_econtrol(p);
+ s->u.ax.dcsr = readl((unsigned long)&dma->dcsr);
+}
+
+void
+parport_ax_restore_state(struct parport *p, struct parport_state *s)
+{
+ struct linux_ebus_dma *dma = p->private_data;
+
+ parport_ax_write_control(p, s->u.ax.ctr);
+ parport_ax_write_econtrol(p, s->u.ax.ecr);
+ writel(s->u.ax.dcsr, (unsigned long)&dma->dcsr);
+}
+
+void
+parport_ax_inc_use_count(void)
+{
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+}
+
+void
+parport_ax_dec_use_count(void)
+{
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+static void parport_ax_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations parport_ax_ops =
+{
+ parport_ax_write_data,
+ parport_ax_read_data,
+
+ parport_ax_write_control,
+ parport_ax_read_control,
+ parport_ax_frob_control,
+
+ parport_ax_read_status,
+
+ parport_ax_enable_irq,
+ parport_ax_disable_irq,
+
+ parport_ax_data_forward,
+ parport_ax_data_reverse,
+
+ parport_ax_interrupt,
+
+ parport_ax_init_state,
+ parport_ax_save_state,
+ parport_ax_restore_state,
+
+ parport_ax_inc_use_count,
+ parport_ax_dec_use_count,
+ parport_ax_fill_inode,
+
+ parport_ieee1284_epp_write_data,
+ parport_ieee1284_epp_read_data,
+ parport_ieee1284_epp_write_addr,
+ parport_ieee1284_epp_read_addr,
+
+ parport_ieee1284_ecp_write_data,
+ parport_ieee1284_ecp_read_data,
+ parport_ieee1284_ecp_write_addr,
+
+ parport_ieee1284_write_compat,
+ parport_ieee1284_read_nibble,
+ parport_ieee1284_read_byte,
+};
+
+
+/******************************************************
+ * MODE detection section:
+ */
+
+/*
+ * Clear TIMEOUT BIT in EPP MODE
+ */
+int parport_ax_epp_clear_timeout(struct parport *pb)
+{
+ unsigned char r;
+
+ if (!(parport_ax_read_status(pb) & 0x01))
+ return 1;
+
+ /* To clear timeout some chips require double read */
+ parport_ax_read_status(pb);
+ r = parport_ax_read_status(pb);
+ parport_ax_write_status(pb, r | 0x01); /* Some reset by writing 1 */
+ parport_ax_write_status(pb, r & 0xfe); /* Others by writing 0 */
+ r = parport_ax_read_status(pb);
+
+ return !(r & 0x01);
+}
+
+/* Check for ECP
+ *
+ * Old style XT ports alias io ports every 0x400, hence accessing ECONTROL
+ * on these cards actually accesses the CTR.
+ *
+ * Modern cards don't do this but reading from ECONTROL will return 0xff
+ * regardless of what is written here if the card does NOT support
+ * ECP.
+ *
+ * We will write 0x2c to ECONTROL and 0xcc to CTR since both of these
+ * values are "safe" on the CTR since bits 6-7 of CTR are unused.
+ */
+static int parport_ECR_present(struct parport *pb)
+{
+ unsigned int r;
+ unsigned char octr = pb->ops->read_control(pb),
+ oecr = pb->ops->read_econtrol(pb);
+
+ r = pb->ops->read_control(pb);
+ if ((pb->ops->read_econtrol(pb) & 0x3) == (r & 0x3)) {
+ pb->ops->write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */
+
+ r = pb->ops->read_control(pb);
+ if ((pb->ops->read_econtrol(pb) & 0x2) == (r & 0x2)) {
+ pb->ops->write_control(pb, octr);
+ return 0; /* Sure that no ECONTROL register exists */
+ }
+ }
+
+ if ((pb->ops->read_econtrol(pb) & 0x3 ) != 0x1)
+ return 0;
+
+ pb->ops->write_econtrol(pb, 0x34);
+ if (pb->ops->read_econtrol(pb) != 0x35)
+ return 0;
+
+ pb->ops->write_econtrol(pb, oecr);
+ pb->ops->write_control(pb, octr);
+
+ return PARPORT_MODE_PCECR;
+}
+
+static int parport_ECP_supported(struct parport *pb)
+{
+ int i;
+ unsigned char oecr = pb->ops->read_econtrol(pb);
+
+ /* If there is no ECONTROL, we have no hope of supporting ECP. */
+ if (!(pb->modes & PARPORT_MODE_PCECR))
+ return 0;
+
+ /*
+ * Using LGS chipset it uses ECONTROL register, but
+ * it doesn't support ECP or FIFO MODE
+ */
+
+ pb->ops->write_econtrol(pb, 0xc0); /* TEST FIFO */
+ for (i=0; i < 1024 && (pb->ops->read_econtrol(pb) & 0x01); i++)
+ pb->ops->write_fifo(pb, 0xaa);
+
+ pb->ops->write_econtrol(pb, oecr);
+ return (i == 1024) ? 0 : PARPORT_MODE_PCECP;
+}
+
+/* Detect PS/2 support.
+ *
+ * Bit 5 (0x20) sets the PS/2 data direction; setting this high
+ * allows us to read data from the data lines. In theory we would get back
+ * 0xff but any peripheral attached to the port may drag some or all of the
+ * lines down to zero. So if we get back anything that isn't the contents
+ * of the data register we deem PS/2 support to be present.
+ *
+ * Some SPP ports have "half PS/2" ability - you can't turn off the line
+ * drivers, but an external peripheral with sufficiently beefy drivers of
+ * its own can overpower them and assert its own levels onto the bus, from
+ * where they can then be read back as normal. Ports with this property
+ * and the right type of device attached are likely to fail the SPP test,
+ * (as they will appear to have stuck bits) and so the fact that they might
+ * be misdetected here is rather academic.
+ */
+
+static int parport_PS2_supported(struct parport *pb)
+{
+ int ok = 0;
+ unsigned char octr = pb->ops->read_control(pb);
+
+ pb->ops->write_control(pb, octr | 0x20); /* try to tri-state buffer */
+
+ pb->ops->write_data(pb, 0x55);
+ if (pb->ops->read_data(pb) != 0x55) ok++;
+
+ pb->ops->write_data(pb, 0xaa);
+ if (pb->ops->read_data(pb) != 0xaa) ok++;
+
+ pb->ops->write_control(pb, octr); /* cancel input mode */
+
+ return ok ? PARPORT_MODE_PCPS2 : 0;
+}
+
+static int parport_ECPPS2_supported(struct parport *pb)
+{
+ int mode;
+ unsigned char oecr = pb->ops->read_econtrol(pb);
+
+ if (!(pb->modes & PARPORT_MODE_PCECR))
+ return 0;
+
+ pb->ops->write_econtrol(pb, 0x20);
+
+ mode = parport_PS2_supported(pb);
+
+ pb->ops->write_econtrol(pb, oecr);
+ return mode ? PARPORT_MODE_PCECPPS2 : 0;
+}
+
+#define printmode(x) \
+{ \
+ if (p->modes & PARPORT_MODE_PC##x) { \
+ printk("%s%s", f ? "," : "", #x); \
+ f++; \
+ } \
+}
+
+int
+init_one_port(struct linux_ebus_device *dev)
+{
+ struct parport tmpport, *p;
+ unsigned long base;
+ unsigned long config;
+ unsigned char tmp;
+ int irq, dma;
+
+ /* Pointer to NS87303 Configuration Registers */
+ config = dev->base_address[1];
+
+ /* Setup temporary access to Device operations */
+ tmpport.base = dev->base_address[0];
+ tmpport.ops = &parport_ax_ops;
+
+ /* Enable ECP mode, set bit 2 of the CTR first */
+ tmpport.ops->write_control(&tmpport, 0x04);
+ tmp = ns87303_readb(config, PCR);
+ tmp |= (PCR_EPP_IEEE | PCR_ECP_ENABLE | PCR_ECP_CLK_ENA);
+ ns87303_writeb(config, PCR, tmp);
+
+ /* LPT CTR bit 5 controls direction of parallel port */
+ tmp = ns87303_readb(config, PTR);
+ tmp |= PTR_LPT_REG_DIR;
+ ns87303_writeb(config, PTR, tmp);
+
+ /* Configure IRQ to Push Pull, Level Low */
+ tmp = ns87303_readb(config, PCR);
+ tmp &= ~(PCR_IRQ_ODRAIN);
+ tmp |= PCR_IRQ_POLAR;
+ ns87303_writeb(config, PCR, tmp);
+
+#ifndef HAVE_SLOW_DEVICES
+ /* Enable Zero Wait State for ECP */
+ tmp = ns87303_readb(config, FCR);
+ tmp |= FCR_ZWS_ENA;
+ ns87303_writeb(config, FCR, tmp);
+#endif
+
+ /*
+ * Now continue initializing the port
+ */
+ base = dev->base_address[0];
+ irq = dev->irqs[0];
+ dma = PARPORT_DMA_AUTO;
+
+ if (!(p = parport_register_port(base, irq, dma, &parport_ax_ops)))
+ return 0;
+
+ /* Save away pointer to our EBus DMA */
+ p->private_data = (void *)dev->base_address[2];
+
+ p->modes = PARPORT_MODE_PCSPP | parport_PS2_supported(p);
+ if (!check_region(p->base + 0x400, 3)) {
+ p->modes |= parport_ECR_present(p);
+ p->modes |= parport_ECP_supported(p);
+ p->modes |= parport_ECPPS2_supported(p);
+ }
+ p->size = 3;
+
+ if (p->dma == PARPORT_DMA_AUTO)
+ p->dma = (p->modes & PARPORT_MODE_PCECP) ? 0 : PARPORT_DMA_NONE;
+
+ printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
+ if (p->irq != PARPORT_IRQ_NONE)
+ printk(", irq %s", __irq_itoa(p->irq));
+ if (p->dma != PARPORT_DMA_NONE)
+ printk(", dma %d", p->dma);
+ printk(" [");
+ {
+ int f = 0;
+ printmode(SPP);
+ printmode(PS2);
+ printmode(ECP);
+ printmode(ECPPS2);
+ }
+ printk("]\n");
+ parport_proc_register(p);
+
+ if (p->irq != PARPORT_IRQ_NONE)
+ if ((err = request_irq(p->irq, parport_ax_interrupt,
+ 0, p->name, p)) != 0)
+ return 0; /* @@@ FIXME */
+
+ request_region(p->base, p->size, p->name);
+ if (p->modes & PARPORT_MODE_PCECR)
+ request_region(p->base+0x400, 3, p->name);
+ request_region((unsigned long)p->private_data,
+ sizeof(struct linux_ebus_dma), p->name);
+
+ p->ops->write_control(p, 0x0c);
+ p->ops->write_data(p, 0);
+
+ /* Tell the high-level drivers about the port. */
+ parport_announce_port (p);
+
+ return 1;
+}
+
+EXPORT_NO_SYMBOLS;
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int parport_ax_init(void))
+#endif
+{
+ struct linux_ebus *ebus;
+ struct linux_ebus_device *edev;
+ int count = 0;
+
+ for_each_ebus(ebus) {
+ for_each_ebusdev(edev, ebus) {
+ if (!strcmp(edev->prom_name, "ecpp"))
+ count += init_one_port(edev);
+ }
+ }
+ return count ? 0 : -ENODEV;
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+ struct parport *p = parport_enumerate(), *tmp;
+ while (p) {
+ tmp = p->next;
+ if (p->modes & PARPORT_MODE_PCSPP) {
+ if (p->irq != PARPORT_IRQ_NONE) {
+ parport_ax_disable_irq(p);
+ free_irq(p->irq, p);
+ }
+ release_region(p->base, p->size);
+ if (p->modes & PARPORT_MODE_PCECR)
+ release_region(p->base+0x400, 3);
+ release_region((unsigned long)p->private_data,
+ sizeof(struct linux_ebus_dma));
+ parport_proc_unregister(p);
+ parport_unregister_port(p);
+ }
+ p = tmp;
+ }
+}
+#endif
--- /dev/null
+/* Low-level parallel port routines for the Multiface 3 card
+ *
+ * Author: Joerg Dorchain <dorchain@wirbel.com>
+ *
+ * (C) The elitist m68k Users(TM)
+ *
+ * based on the existing parport_amiga and lp_mfc
+ *
+ *
+ * From the MFC3 documentation:
+ *
+ * Miscellaneous PIA Details
+ * -------------------------
+ *
+ * The two open-drain interrupt outputs /IRQA and /IRQB are routed to
+ * /INT2 of the Z2 bus.
+ *
+ * The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2
+ * bus. This means that any PIA registers are accessed at even addresses.
+ *
+ * Centronics Pin Connections for the PIA
+ * --------------------------------------
+ *
+ * The following table shows the connections between the PIA and the
+ * Centronics interface connector. These connections implement a single, but
+ * very complete, Centronics type interface. The Pin column gives the pin
+ * numbers of the PIA. The Centronics pin numbers can be found in the section
+ * "Parallel Connectors".
+ *
+ *
+ * Pin | PIA | Dir | Centronics Names
+ * -------+-----+-----+---------------------------------------------------------
+ * 19 | CB2 | --> | /STROBE (aka /DRDY)
+ * 10-17 | PBx | <-> | DATA0 - DATA7
+ * 18 | CB1 | <-- | /ACK
+ * 40 | CA1 | <-- | BUSY
+ * 3 | PA1 | <-- | PAPER-OUT (aka POUT)
+ * 4 | PA2 | <-- | SELECTED (aka SEL)
+ * 9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME)
+ * 6 | PA4 | <-- | /ERROR (aka /FAULT)
+ * 7 | PA5 | --> | DIR (aka /SELECT-IN)
+ * 8 | PA6 | --> | /AUTO-FEED-XT
+ * 39 | CA2 | --> | open
+ * 5 | PA3 | <-- | /ACK (same as CB1!)
+ * 2 | PA0 | <-- | BUSY (same as CA1!)
+ * -------+-----+-----+---------------------------------------------------------
+ *
+ * Should be enough to understand some of the driver.
+ */
+
+#include "multiface.h"
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <linux/mc6821.h>
+#include <linux/zorro.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+/* Maximum Number of Cards supported */
+#define MAX_MFC 5
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port[MAX_MFC] = {NULL, };
+static volatile int dummy; /* for trigger readds */
+
+#define pia(dev) ((struct pia *)(dev->base))
+static struct parport_operations pp_mfc3_ops;
+
+static void mfc3_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+
+ dummy = pia(p)->pprb; /* clears irq bit */
+ /* Triggers also /STROBE.*/
+ pia(p)->pprb = data;
+}
+
+static unsigned char mfc3_read_data(struct parport *p)
+{
+ /* clears interupt bit. Triggers also /STROBE. */
+ return pia(p)->pprb;
+}
+
+static unsigned char control_pc_to_mfc3(unsigned char control)
+{
+ unsigned char ret = 32|64;
+
+ if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+ ;
+ if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+ ;
+ if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+ ret &= ~32; /* /SELECT_IN */
+ if (control & PARPORT_CONTROL_INIT) /* INITP */
+ ret |= 128;
+ if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+ ret &= ~64;
+ if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+ /* Handled directly by hardware */;
+ return ret;
+}
+
+static unsigned char control_mfc3_to_pc(unsigned char control)
+{
+ unsigned char ret = PARPORT_CONTROL_INTEN | PARPORT_CONTROL_STROBE
+ | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT;
+
+ if (control & 128) /* /INITP */
+ ret |= PARPORT_CONTROL_INIT;
+ if (control & 64) /* /AUTOLF */
+ ret &= ~PARPORT_CONTROL_AUTOFD;
+ if (control & 32) /* /SELECT_IN */
+ ret &= ~PARPORT_CONTROL_SELECT;
+ return ret;
+}
+
+static void mfc3_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+ pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control);
+}
+
+static unsigned char mfc3_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+ return control_mfc3_to_pc(pia(p)->ppra & 0xe0);
+}
+
+static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+ unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+ old = mfc3_read_control(p);
+ mfc3_write_control(p, (old & ~mask) ^ val);
+ return old;
+}
+
+
+static unsigned char status_pc_to_mfc3(unsigned char status)
+{
+ unsigned char ret = 1;
+
+ if (status & PARPORT_STATUS_BUSY) /* Busy */
+ ret &= ~1;
+ if (status & PARPORT_STATUS_ACK) /* Ack */
+ ret |= 8;
+ if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+ ret |= 2;
+ if (status & PARPORT_STATUS_SELECT) /* select */
+ ret |= 4;
+ if (status & PARPORT_STATUS_ERROR) /* error */
+ ret |= 16;
+ return ret;
+}
+
+static unsigned char status_mfc3_to_pc(unsigned char status)
+{
+ unsigned char ret = PARPORT_STATUS_BUSY;
+
+ if (status & 1) /* Busy */
+ ret &= ~PARPORT_STATUS_BUSY;
+ if (status & 2) /* PaperOut */
+ ret |= PARPORT_STATUS_PAPEROUT;
+ if (status & 4) /* Selected */
+ ret |= PARPORT_STATUS_SELECT;
+ if (status & 8) /* Ack */
+ ret |= PARPORT_STATUS_ACK;
+ if (status & 16) /* /ERROR */
+ ret |= PARPORT_STATUS_ERROR;
+
+ return ret;
+}
+
+static void mfc3_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+ pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status);
+}
+
+static unsigned char mfc3_read_status(struct parport *p)
+{
+ unsigned char status;
+
+ status = status_mfc3_to_pc(pia(p)->ppra & 0x1f);
+DPRINTK("read_status %02x\n", status);
+ return status;
+}
+
+static void mfc3_change_mode( struct parport *p, int m)
+{
+ /* XXX: This port only has one mode, and I am
+ not sure about the corresponding PC-style mode*/
+}
+
+static int use_cnt = 0;
+
+static void mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int i;
+
+ for( i = 0; i < MAX_MFC; i++)
+ if (this_port[i] != NULL)
+ if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
+ dummy = pia(this_port[i])->pprb; /* clear irq bit */
+ parport_generic_irq(irq, this_port[i], regs);
+ }
+}
+
+static int mfc3_claim_resources(struct parport *p)
+{
+DPRINTK("claim_resources\n");
+}
+
+static void mfc3_init_state(struct parport_state *s)
+{
+ s->u.amiga.data = 0;
+ s->u.amiga.datadir = 255;
+ s->u.amiga.status = 0;
+ s->u.amiga.statusdir = 0xe0;
+}
+
+static void mfc3_save_state(struct parport *p, struct parport_state *s)
+{
+ s->u.amiga.data = pia(p)->pprb;
+ pia(p)->crb &= ~PIA_DDR;
+ s->u.amiga.datadir = pia(p)->pddrb;
+ pia(p)->crb |= PIA_DDR;
+ s->u.amiga.status = pia(p)->ppra;
+ pia(p)->cra &= ~PIA_DDR;
+ s->u.amiga.statusdir = pia(p)->pddrb;
+ pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_restore_state(struct parport *p, struct parport_state *s)
+{
+ pia(p)->pprb = s->u.amiga.data;
+ pia(p)->crb &= ~PIA_DDR;
+ pia(p)->pddrb = s->u.amiga.datadir;
+ pia(p)->crb |= PIA_DDR;
+ pia(p)->ppra = s->u.amiga.status;
+ pia(p)->cra &= ~PIA_DDR;
+ pia(p)->pddrb = s->u.amiga.statusdir;
+ pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_enable_irq(struct parport *p)
+{
+ pia(p)->crb |= PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_disable_irq(struct parport *p)
+{
+ pia(p)->crb &= ~PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void mfc3_dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static void mfc3_fill_inode(struct inode *inode, int fill)
+{
+#ifdef MODULE
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations pp_mfc3_ops = {
+ mfc3_write_data,
+ mfc3_read_data,
+
+ mfc3_write_control,
+ mfc3_read_control,
+ mfc3_frob_control,
+
+ NULL, /* write_econtrol */
+ NULL, /* read_econtrol */
+ NULL, /* frob_econtrol */
+
+ mfc3_write_status,
+ mfc3_read_status,
+
+ NULL, /* write fifo */
+ NULL, /* read fifo */
+
+ mfc3_change_mode,
+
+
+ mfc3_release_resources,
+ mfc3_claim_resources,
+
+
+ NULL, /* epp_write_data */
+ NULL, /* epp_read_data */
+ NULL, /* epp_write_addr */
+ NULL, /* epp_read_addr */
+ NULL, /* epp_check_timeout */
+
+ NULL, /* epp_write_block */
+ NULL, /* epp_read_block */
+
+ NULL, /* ecp_write_block */
+ NULL, /* ecp_read_block */
+
+ mfc3_init_state,
+ mfc3_save_state,
+ mfc3_restore_state,
+
+ mfc3_enable_irq,
+ mfc3_disable_irq,
+ mfc3_interrupt,
+
+ mfc3_inc_use_count,
+ mfc3_dec_use_count,
+ mfc3_fill_inode
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_mfc3_init(void))
+{
+ struct parport *p;
+ int pias = 0;
+ struct pia *pp;
+ unsigned int key = 0;
+ const struct ConfigDev *cd;
+
+ if (MACH_IS_AMIGA) {
+ while ((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0, key))) {
+ cd = zorro_get_board(key);
+ pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE));
+ if (pias < MAX_MFC) {
+ pp->crb = 0;
+ pp->pddrb = 255; /* all data pins output */
+ pp->crb = PIA_DDR|32|8;
+ dummy = pp->pddrb; /* reading clears interrupt */
+ pp->cra = 0;
+ pp->pddra = 0xe0; /* /RESET, /DIR ,/AUTO-FEED output */
+ pp->cra = PIA_DDR;
+ pp->ppra = 0; /* reset printer */
+ udelay(10);
+ pp->ppra = 128;
+ if ((p = parport_register_port((unsigned long)pp,
+ IRQ_AMIGA_PORTS, PARPORT_DMA_NONE,
+ &pp_mfc3_ops))) {
+ this_port[pias++] = p;
+ printk(KERN_INFO "%s: Multiface III port using irq\n", p->name);
+ /* XXX: set operating mode */
+ parport_proc_register(p);
+
+ if (p->irq != PARPORT_IRQ_NONE)
+ if (use_cnt++ == 0)
+ if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, 0, p->name, &pp_mfc3_ops))
+ use_cnt--;
+
+ if (parport_probe_hook)
+ (*parport_probe_hook)(p);
+ zorro_config_board(key, 0);
+ p->private_data = (void *)key;
+ parport_announce_port (p);
+ }
+ }
+ }
+ }
+ return pias;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Joerg Dorchain");
+MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port");
+MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port");
+
+int init_module(void)
+{
+ return ! parport_mfc3_init();
+}
+
+void cleanup_module(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_MFC; i++)
+ if (this_port[i] != NULL) {
+ if (p->irq != PARPORT_IRQ_NONE)
+ if (--use_cnt == 0)
+ free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops);
+ parport_proc_unregister(this_port[i]);
+ parport_unregister_port(this_port[i]);
+ zorro_unconfig_board((unsigned int)this_port[i]->private_data, 0);
+ }
+}
+#endif
+
+
--- /dev/null
+/* Low-level parallel-port routines for 8255-based PC-style hardware.
+ *
+ * Authors: Phil Blundell <Philip.Blundell@pobox.com>
+ * Tim Waugh <tim@cyberelk.demon.co.uk>
+ * Jose Renau <renau@acm.org>
+ * David Campbell <campbell@torque.net>
+ * Andrea Arcangeli
+ *
+ * based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
+ *
+ * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
+ * DMA support - Bert De Jonghe <bert@sophis.be>
+ * Better EPP probing - Carlos Henrique Bauer <chbauer@acm.org>
+ */
+
+/* This driver should work with any hardware that is broadly compatible
+ * with that in the IBM PC. This applies to the majority of integrated
+ * I/O chipsets that are commonly available. The expected register
+ * layout is:
+ *
+ * base+0 data
+ * base+1 status
+ * base+2 control
+ *
+ * In addition, there are some optional registers:
+ *
+ * base+3 EPP address
+ * base+4 EPP data
+ * base+0x400 ECP config A
+ * base+0x401 ECP config B
+ * base+0x402 ECP control
+ *
+ * All registers are 8 bits wide and read/write. If your hardware differs
+ * only in register addresses (eg because your registers are on 32-bit
+ * word boundaries) then you can alter the constants in parport_pc.h to
+ * accomodate this.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/sysctl.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include <linux/parport.h>
+#include <linux/parport_pc.h>
+
+/* Maximum number of ports to support. It is useless to set this greater
+ than PARPORT_MAX (in <linux/parport.h>). */
+#define PARPORT_PC_MAX_PORTS 8
+
+/* ECR modes */
+#define ECR_SPP 00
+#define ECR_PS2 01
+#define ECR_PPF 02
+#define ECR_ECP 03
+#define ECR_EPP 04
+#define ECR_VND 05
+#define ECR_TST 06
+#define ECR_CNF 07
+
+static int user_specified __initdata = 0;
+
+/* frob_control, but for ECR */
+static void frob_econtrol (struct parport *pb, unsigned char m,
+ unsigned char v)
+{
+ outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Safely change the mode bits in the ECR */
+static int change_mode(struct parport *p, int m)
+{
+ const struct parport_pc_private *priv = p->physport->private_data;
+ int ecr = ECONTROL(p);
+ unsigned char oecr;
+ int mode;
+
+ if (!priv->ecr) {
+ printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
+ return 0;
+ }
+
+ /* Bits <7:5> contain the mode. */
+ oecr = inb (ecr);
+ mode = (oecr >> 5) & 0x7;
+ if (mode == m) return 0;
+ if (mode && m)
+ /* We have to go through mode 000 */
+ change_mode (p, ECR_SPP);
+
+ if (m < 2 && !(parport_read_control (p) & 0x20)) {
+ /* This mode resets the FIFO, so we may
+ * have to wait for it to drain first. */
+ long expire = jiffies + p->physport->cad->timeout;
+ int counter;
+ switch (mode) {
+ case ECR_PPF: /* Parallel Port FIFO mode */
+ case ECR_ECP: /* ECP Parallel Port mode */
+ /* Busy wait for 200us */
+ for (counter = 0; counter < 40; counter++) {
+ if (inb (ECONTROL (p)) & 0x01)
+ break;
+ if (signal_pending (current)) break;
+ udelay (5);
+ }
+
+ /* Poll slowly. */
+ while (!(inb (ECONTROL (p)) & 0x01)) {
+ if (time_after_eq (jiffies, expire))
+ /* The FIFO is stuck. */
+ return -EBUSY;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout ((HZ + 99) / 100);
+ if (signal_pending (current))
+ break;
+ }
+ }
+ }
+
+ /* Set the mode. */
+ oecr &= ~(7 << 5);
+ oecr |= m << 5;
+ outb (oecr, ecr);
+ return 0;
+}
+
+/* Find FIFO lossage; FIFO is reset */
+static int get_fifo_residue (struct parport *p)
+{
+ int residue;
+ int cnfga;
+ const struct parport_pc_private *priv = p->physport->private_data;
+
+ /* Prevent further data transfer. */
+ parport_frob_control (p,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+
+ /* Adjust for the contents of the FIFO. */
+ for (residue = priv->fifo_depth; ; residue--) {
+ if (inb (ECONTROL (p)) & 0x2)
+ /* Full up. */
+ break;
+
+ outb (0, FIFO (p));
+ }
+
+ printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
+ residue);
+
+ /* Reset the FIFO. */
+ frob_econtrol (p, 0xe0, 0x20);
+ parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
+
+ /* Now change to config mode and clean up. FIXME */
+ frob_econtrol (p, 0xe0, 0xe0);
+ cnfga = inb (CONFIGA (p));
+ printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
+
+ if (!(cnfga & (1<<2))) {
+ printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
+ residue++;
+ }
+
+ /* Don't care about partial PWords until support is added for
+ * PWord != 1 byte. */
+
+ /* Back to PS2 mode. */
+ frob_econtrol (p, 0xe0, 0x20);
+
+ return residue;
+}
+
+#endif /* IEEE 1284 support */
+
+/*
+ * Clear TIMEOUT BIT in EPP MODE
+ *
+ * This is also used in SPP detection.
+ */
+static int clear_epp_timeout(struct parport *pb)
+{
+ unsigned char r;
+
+ if (!(parport_pc_read_status(pb) & 0x01))
+ return 1;
+
+ /* To clear timeout some chips require double read */
+ parport_pc_read_status(pb);
+ r = parport_pc_read_status(pb);
+ outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */
+ outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */
+ r = parport_pc_read_status(pb);
+
+ return !(r & 0x01);
+}
+
+/*
+ * Access functions.
+ *
+ * These aren't static because they may be used by the parport_xxx_yyy
+ * macros. extern __inline__ versions of several of these are in
+ * parport_pc.h.
+ */
+
+static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+void parport_pc_write_data(struct parport *p, unsigned char d)
+{
+ outb (d, DATA (p));
+}
+
+unsigned char parport_pc_read_data(struct parport *p)
+{
+ return inb (DATA (p));
+}
+
+unsigned char __frob_control (struct parport *p, unsigned char mask,
+ unsigned char val)
+{
+ struct parport_pc_private *priv = p->physport->private_data;
+ unsigned char ctr = priv->ctr;
+ ctr = (ctr & ~mask) ^ val;
+ ctr &= priv->ctr_writable; /* only write writable bits. */
+ outb (ctr, CONTROL (p));
+ return priv->ctr = ctr; /* update soft copy */
+}
+
+void parport_pc_write_control(struct parport *p, unsigned char d)
+{
+ const unsigned char wm = (PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_INIT |
+ PARPORT_CONTROL_SELECT);
+
+ /* Take this out when drivers have adapted to the newer interface. */
+ if (d & 0x20) {
+ printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+ p->name, p->cad->name);
+ parport_pc_data_reverse (p);
+ }
+
+ __frob_control (p, wm, d & wm);
+}
+
+unsigned char parport_pc_read_control(struct parport *p)
+{
+ const struct parport_pc_private *priv = p->physport->private_data;
+ return priv->ctr; /* Use soft copy */
+}
+
+unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
+ unsigned char val)
+{
+ const unsigned char wm = (PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_INIT |
+ PARPORT_CONTROL_SELECT);
+
+ /* Take this out when drivers have adapted to the newer interface. */
+ if (mask & 0x20) {
+ printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+ p->name, p->cad->name);
+ parport_pc_data_reverse (p);
+ }
+
+ /* Restrict mask and val to control lines. */
+ mask &= wm;
+ val &= wm;
+
+ return __frob_control (p, mask, val);
+}
+
+unsigned char parport_pc_read_status(struct parport *p)
+{
+ return inb (STATUS (p));
+}
+
+void parport_pc_disable_irq(struct parport *p)
+{
+ __frob_control (p, 0x10, 0);
+}
+
+void parport_pc_enable_irq(struct parport *p)
+{
+ __frob_control (p, 0x10, 0x10);
+}
+
+void parport_pc_data_forward (struct parport *p)
+{
+ __frob_control (p, 0x20, 0);
+}
+
+void parport_pc_data_reverse (struct parport *p)
+{
+ __frob_control (p, 0x20, 0x20);
+}
+
+void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
+{
+ s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+ s->u.pc.ecr = 0x24;
+}
+
+void parport_pc_save_state(struct parport *p, struct parport_state *s)
+{
+ const struct parport_pc_private *priv = p->physport->private_data;
+ s->u.pc.ctr = inb (CONTROL (p));
+ if (priv->ecr)
+ s->u.pc.ecr = inb (ECONTROL (p));
+}
+
+void parport_pc_restore_state(struct parport *p, struct parport_state *s)
+{
+ const struct parport_pc_private *priv = p->physport->private_data;
+ outb (s->u.pc.ctr, CONTROL (p));
+ if (priv->ecr)
+ outb (s->u.pc.ecr, ECONTROL (p));
+}
+
+#ifdef CONFIG_PARPORT_1284
+static size_t parport_pc_epp_read_data (struct parport *port, void *buf,
+ size_t length, int flags)
+{
+ size_t got = 0;
+ for (; got < length; got++) {
+ *((char*)buf)++ = inb (EPPDATA(port));
+ if (inb (STATUS(port)) & 0x01) {
+ clear_epp_timeout (port);
+ break;
+ }
+ }
+
+ return got;
+}
+
+static size_t parport_pc_epp_write_data (struct parport *port, const void *buf,
+ size_t length, int flags)
+{
+ size_t written = 0;
+ for (; written < length; written++) {
+ outb (*((char*)buf)++, EPPDATA(port));
+ if (inb (STATUS(port)) & 0x01) {
+ clear_epp_timeout (port);
+ break;
+ }
+ }
+
+ return written;
+}
+
+static size_t parport_pc_epp_read_addr (struct parport *port, void *buf,
+ size_t length, int flags)
+{
+ size_t got = 0;
+ for (; got < length; got++) {
+ *((char*)buf)++ = inb (EPPADDR (port));
+ if (inb (STATUS (port)) & 0x01) {
+ clear_epp_timeout (port);
+ break;
+ }
+ }
+
+ return got;
+}
+
+static size_t parport_pc_epp_write_addr (struct parport *port,
+ const void *buf, size_t length,
+ int flags)
+{
+ size_t written = 0;
+ for (; written < length; written++) {
+ outb (*((char*)buf)++, EPPADDR (port));
+ if (inb (STATUS (port)) & 0x01) {
+ clear_epp_timeout (port);
+ break;
+ }
+ }
+
+ return written;
+}
+
+static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf,
+ size_t length, int flags)
+{
+ size_t got;
+
+ frob_econtrol (port, 0xe0, ECR_EPP << 5);
+ got = parport_pc_epp_read_data (port, buf, length, flags);
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+ return got;
+}
+
+static size_t parport_pc_ecpepp_write_data (struct parport *port,
+ const void *buf, size_t length,
+ int flags)
+{
+ size_t written;
+
+ frob_econtrol (port, 0xe0, ECR_EPP << 5);
+ written = parport_pc_epp_write_data (port, buf, length, flags);
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+ return written;
+}
+
+static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf,
+ size_t length, int flags)
+{
+ size_t got;
+
+ frob_econtrol (port, 0xe0, ECR_EPP << 5);
+ got = parport_pc_epp_read_addr (port, buf, length, flags);
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+ return got;
+}
+
+static size_t parport_pc_ecpepp_write_addr (struct parport *port,
+ const void *buf, size_t length,
+ int flags)
+{
+ size_t written;
+
+ frob_econtrol (port, 0xe0, ECR_EPP << 5);
+ written = parport_pc_epp_write_addr (port, buf, length, flags);
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+ return written;
+}
+#endif /* IEEE 1284 support */
+
+#ifdef CONFIG_PARPORT_PC_FIFO
+static size_t parport_pc_fifo_write_block_pio (struct parport *port,
+ const void *buf, size_t length)
+{
+ int ret = 0;
+ const unsigned char *bufp = buf;
+ size_t left = length;
+ long expire = jiffies + port->physport->cad->timeout;
+ const int fifo = FIFO (port);
+ int poll_for = 8; /* 80 usecs */
+ const struct parport_pc_private *priv = port->physport->private_data;
+ const int fifo_depth = priv->fifo_depth;
+
+ port = port->physport;
+
+ /* We don't want to be interrupted every character. */
+ parport_pc_disable_irq (port);
+ frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+
+ /* Forward mode. */
+ parport_pc_data_forward (port);
+
+ while (left) {
+ unsigned char byte;
+ unsigned char ecrval = inb (ECONTROL (port));
+ int i = 0;
+
+ if (current->need_resched && time_before (jiffies, expire))
+ /* Can't yield the port. */
+ schedule ();
+
+ /* Anyone else waiting for the port? */
+ if (port->waithead) {
+ printk (KERN_DEBUG "Somebody wants the port\n");
+ break;
+ }
+
+ if (ecrval & 0x02) {
+ /* FIFO is full. Wait for interrupt. */
+
+ /* Clear serviceIntr */
+ outb (ecrval & ~(1<<2), ECONTROL (port));
+ false_alarm:
+ ret = parport_wait_event (port, HZ);
+ if (ret < 0) break;
+ ret = 0;
+ if (!time_before (jiffies, expire)) {
+ /* Timed out. */
+ printk (KERN_DEBUG "Timed out\n");
+ break;
+ }
+ ecrval = inb (ECONTROL (port));
+ if (!(ecrval & (1<<2))) {
+ if (current->need_resched &&
+ time_before (jiffies, expire))
+ schedule ();
+
+ goto false_alarm;
+ }
+
+ continue;
+ }
+
+ /* Can't fail now. */
+ expire = jiffies + port->cad->timeout;
+
+ poll:
+ if (signal_pending (current))
+ break;
+
+ if (ecrval & 0x01) {
+ /* FIFO is empty. Blast it full. */
+ const int n = left < fifo_depth ? left : fifo_depth;
+ outsb (fifo, bufp, n);
+ bufp += n;
+ left -= n;
+
+ /* Adjust the poll time. */
+ if (i < (poll_for - 2)) poll_for--;
+ continue;
+ } else if (i++ < poll_for) {
+ udelay (10);
+ ecrval = inb (ECONTROL (port));
+ goto poll;
+ }
+
+ /* Half-full (call me an optimist) */
+ byte = *bufp++;
+ outb (byte, fifo);
+ left--;
+ }
+
+ return length - left;
+}
+
+static size_t parport_pc_fifo_write_block_dma (struct parport *port,
+ const void *buf, size_t length)
+{
+ int ret = 0;
+ unsigned long dmaflag;
+ size_t left = length;
+ const struct parport_pc_private *priv = port->physport->private_data;
+
+ port = port->physport;
+
+ /* We don't want to be interrupted every character. */
+ parport_pc_disable_irq (port);
+ frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+
+ /* Forward mode. */
+ parport_pc_data_forward (port);
+
+ while (left) {
+ long expire = jiffies + port->physport->cad->timeout;
+
+ size_t count = left;
+
+ if (count > PAGE_SIZE)
+ count = PAGE_SIZE;
+
+ memcpy(priv->dma_buf, buf, count);
+
+ dmaflag = claim_dma_lock();
+ disable_dma(port->dma);
+ clear_dma_ff(port->dma);
+ set_dma_mode(port->dma, DMA_MODE_WRITE);
+ set_dma_addr(port->dma, virt_to_bus((volatile char *) priv->dma_buf));
+ set_dma_count(port->dma, count);
+
+ /* Set DMA mode */
+ frob_econtrol (port, 1<<3, 1<<3);
+
+ /* Clear serviceIntr */
+ frob_econtrol (port, 1<<2, 0);
+
+ enable_dma(port->dma);
+ release_dma_lock(dmaflag);
+
+ /* assume DMA will be successful */
+ left -= count;
+ buf += count;
+
+ /* Wait for interrupt. */
+ false_alarm:
+ ret = parport_wait_event (port, HZ);
+ if (ret < 0) break;
+ ret = 0;
+ if (!time_before (jiffies, expire)) {
+ /* Timed out. */
+ printk (KERN_DEBUG "Timed out\n");
+ break;
+ }
+ /* Is serviceIntr set? */
+ if (!(inb (ECONTROL (port)) & (1<<2))) {
+ if (current->need_resched)
+ schedule ();
+
+ goto false_alarm;
+ }
+
+ dmaflag = claim_dma_lock();
+ disable_dma(port->dma);
+ clear_dma_ff(port->dma);
+ count = get_dma_residue(port->dma);
+ release_dma_lock(dmaflag);
+
+ if (current->need_resched)
+ /* Can't yield the port. */
+ schedule ();
+
+ /* Anyone else waiting for the port? */
+ if (port->waithead) {
+ printk (KERN_DEBUG "Somebody wants the port\n");
+ break;
+ }
+
+ /* update for possible DMA residue ! */
+ buf -= count;
+ left += count;
+ }
+
+ /* Maybe got here through break, so adjust for DMA residue! */
+ dmaflag = claim_dma_lock();
+ disable_dma(port->dma);
+ clear_dma_ff(port->dma);
+ left += get_dma_residue(port->dma);
+ release_dma_lock(dmaflag);
+
+ /* Turn off DMA mode */
+ frob_econtrol (port, 1<<3, 0);
+
+ return length - left;
+}
+
+/* Parallel Port FIFO mode (ECP chipsets) */
+size_t parport_pc_compat_write_block_pio (struct parport *port,
+ const void *buf, size_t length,
+ int flags)
+{
+ size_t written;
+
+ /* Special case: a timeout of zero means we cannot call schedule(). */
+ if (!port->physport->cad->timeout)
+ return parport_ieee1284_write_compat (port, buf,
+ length, flags);
+
+ /* Set up parallel port FIFO mode.*/
+ change_mode (port, ECR_PPF); /* Parallel port FIFO */
+ parport_pc_data_forward (port);
+ port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+ /* Write the data to the FIFO. */
+ if (port->dma != PARPORT_DMA_NONE)
+ written = parport_pc_fifo_write_block_dma (port, buf, length);
+ else
+ written = parport_pc_fifo_write_block_pio (port, buf, length);
+
+ /* Finish up. */
+ if (change_mode (port, ECR_PS2) == -EBUSY) {
+ const struct parport_pc_private *priv =
+ port->physport->private_data;
+
+ printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+
+ /* Prevent further data transfer. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+
+ /* Adjust for the contents of the FIFO. */
+ for (written -= priv->fifo_depth; ; written++) {
+ if (inb (ECONTROL (port)) & 0x2)
+ /* Full up. */
+ break;
+
+ outb (0, FIFO (port));
+ }
+
+ /* Reset the FIFO. */
+ frob_econtrol (port, 0xe0, 0);
+
+ /* De-assert strobe. */
+ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+ }
+
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY);
+ port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return written;
+}
+
+/* ECP */
+#ifdef CONFIG_PARPORT_1284
+size_t parport_pc_ecp_write_block_pio (struct parport *port,
+ const void *buf, size_t length,
+ int flags)
+{
+ size_t written;
+
+ /* Special case: a timeout of zero means we cannot call schedule(). */
+ if (!port->physport->cad->timeout)
+ return parport_ieee1284_ecp_write_data (port, buf,
+ length, flags);
+
+ /* Switch to forward mode if necessary. */
+ if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
+ /* Event 47: Set nInit high. */
+ parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+
+ /* Event 40: PError goes high. */
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_PAPEROUT);
+ }
+
+ /* Set up ECP parallel port mode.*/
+ change_mode (port, ECR_ECP); /* ECP FIFO */
+ parport_pc_data_forward (port);
+ port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+ /* Write the data to the FIFO. */
+ if (port->dma != PARPORT_DMA_NONE)
+ written = parport_pc_fifo_write_block_dma (port, buf, length);
+ else
+ written = parport_pc_fifo_write_block_pio (port, buf, length);
+
+ /* Finish up. */
+ if (change_mode (port, ECR_PS2) == -EBUSY) {
+ const struct parport_pc_private *priv =
+ port->physport->private_data;
+
+ printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+
+ /* Prevent further data transfer. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+
+ /* Adjust for the contents of the FIFO. */
+ for (written -= priv->fifo_depth; ; written++) {
+ if (inb (ECONTROL (port)) & 0x2)
+ /* Full up. */
+ break;
+
+ outb (0, FIFO (port));
+ }
+
+ /* Reset the FIFO. */
+ frob_econtrol (port, 0xe0, 0);
+ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+
+ /* Host transfer recovery. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_INIT);
+ parport_pc_data_reverse (port);
+ parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+ parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_PAPEROUT);
+ }
+
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY);
+ port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return written;
+}
+
+size_t parport_pc_ecp_read_block_pio (struct parport *port,
+ void *buf, size_t length, int flags)
+{
+ size_t left = length;
+ size_t fifofull;
+ const int fifo = FIFO(port);
+ const struct parport_pc_private *priv = port->physport->private_data;
+ const int fifo_depth = priv->fifo_depth;
+ char *bufp = buf;
+
+ port = port->physport;
+
+ /* Special case: a timeout of zero means we cannot call schedule(). */
+ if (!port->cad->timeout)
+ return parport_ieee1284_ecp_read_data (port, buf,
+ length, flags);
+
+ fifofull = fifo_depth;
+ if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE)
+ /* If the peripheral is allowed to send RLE compressed
+ * data, it is possible for a byte to expand to 128
+ * bytes in the FIFO. */
+ fifofull = 128;
+
+ /* If the caller wants less than a full FIFO's worth of data,
+ * go through software emulation. Otherwise we may have to through
+ * away data. */
+ if (length < fifofull)
+ return parport_ieee1284_ecp_read_data (port, buf,
+ length, flags);
+
+ /* Switch to reverse mode if necessary. */
+ if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
+ /* Event 38: Set nAutoFd low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+ parport_pc_data_reverse (port);
+ udelay (5);
+
+ /* Event 39: Set nInit low to initiate bus reversal */
+ parport_frob_control (port,
+ PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_INIT);
+
+ /* Event 40: PError goes low */
+ parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+ }
+
+ /* Set up ECP parallel port mode.*/
+ change_mode (port, ECR_ECP); /* ECP FIFO */
+ parport_pc_data_reverse (port);
+ port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+
+ /* Do the transfer. */
+ while (left > fifofull) {
+ int ret;
+ long int expire = jiffies + port->cad->timeout;
+ unsigned char ecrval = inb (ECONTROL (port));
+
+ if (current->need_resched && time_before (jiffies, expire))
+ /* Can't yield the port. */
+ schedule ();
+
+ /* At this point, the FIFO may already be full.
+ * Ideally, we'd be able to tell the port to hold on
+ * for a second while we empty the FIFO, and we'd be
+ * able to ensure that no data is lost. I'm not sure
+ * that's the case. :-( It might be that you can play
+ * games with STB, as in the forward case; someone should
+ * look at a datasheet. */
+
+ if (ecrval & 0x01) {
+ /* FIFO is empty. Wait for interrupt. */
+
+ /* Anyone else waiting for the port? */
+ if (port->waithead) {
+ printk (KERN_DEBUG
+ "Somebody wants the port\n");
+ break;
+ }
+
+ /* Clear serviceIntr */
+ outb (ecrval & ~(1<<2), ECONTROL (port));
+ false_alarm:
+ ret = parport_wait_event (port, HZ);
+ if (ret < 0) break;
+ ret = 0;
+ if (!time_before (jiffies, expire)) {
+ /* Timed out. */
+ printk (KERN_DEBUG "Timed out\n");
+ break;
+ }
+ ecrval = inb (ECONTROL (port));
+ if (!(ecrval & (1<<2))) {
+ if (current->need_resched &&
+ time_before (jiffies, expire))
+ schedule ();
+
+ goto false_alarm;
+ }
+
+ continue;
+ }
+
+ if (ecrval & 0x02) {
+ /* FIFO is full. */
+ insb (fifo, bufp, fifo_depth);
+ bufp += fifo_depth;
+ left -= fifo_depth;
+ continue;
+ }
+
+ *bufp++ = inb (fifo);
+ left--;
+ }
+
+ /* Finish up. */
+ if (change_mode (port, ECR_PS2) == -EBUSY) {
+ int lost = get_fifo_residue (port);
+ printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name,
+ lost);
+ }
+
+ port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+
+ return length - left;
+}
+
+#endif /* IEEE 1284 support */
+
+#endif /* Allowed to use FIFO/DMA */
+
+void parport_pc_inc_use_count(void)
+{
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+}
+
+void parport_pc_dec_use_count(void)
+{
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+static void parport_pc_fill_inode(struct inode *inode, int fill)
+{
+ /* Is this still needed? -tim */
+#ifdef MODULE
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+struct parport_operations parport_pc_ops =
+{
+ parport_pc_write_data,
+ parport_pc_read_data,
+
+ parport_pc_write_control,
+ parport_pc_read_control,
+ parport_pc_frob_control,
+
+ parport_pc_read_status,
+
+ parport_pc_enable_irq,
+ parport_pc_disable_irq,
+
+ parport_pc_data_forward,
+ parport_pc_data_reverse,
+
+ parport_pc_interrupt,
+ parport_pc_init_state,
+ parport_pc_save_state,
+ parport_pc_restore_state,
+
+ parport_pc_inc_use_count,
+ parport_pc_dec_use_count,
+ parport_pc_fill_inode,
+
+ parport_ieee1284_epp_write_data,
+ parport_ieee1284_epp_read_data,
+ parport_ieee1284_epp_write_addr,
+ parport_ieee1284_epp_read_addr,
+
+ parport_ieee1284_ecp_write_data,
+ parport_ieee1284_ecp_read_data,
+ parport_ieee1284_ecp_write_addr,
+
+ parport_ieee1284_write_compat,
+ parport_ieee1284_read_nibble,
+ parport_ieee1284_read_byte,
+};
+
+/* --- Mode detection ------------------------------------- */
+
+/*
+ * Checks for port existence, all ports support SPP MODE
+ */
+static int __init parport_SPP_supported(struct parport *pb)
+{
+ unsigned char r, w;
+
+ /*
+ * first clear an eventually pending EPP timeout
+ * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
+ * that does not even respond to SPP cycles if an EPP
+ * timeout is pending
+ */
+ clear_epp_timeout(pb);
+
+ /* Do a simple read-write test to make sure the port exists. */
+ w = 0xc;
+ outb (w, CONTROL (pb));
+
+ /* Is there a control register that we can read from? Some
+ * ports don't allow reads, so read_control just returns a
+ * software copy. Some ports _do_ allow reads, so bypass the
+ * software copy here. In addition, some bits aren't
+ * writable. */
+ r = inb (CONTROL (pb));
+ if ((r & 0xf) == w) {
+ w = 0xe;
+ outb (w, CONTROL (pb));
+ r = inb (CONTROL (pb));
+ outb (0xc, CONTROL (pb));
+ if ((r & 0xf) == w)
+ return PARPORT_MODE_PCSPP;
+ }
+
+ if (user_specified)
+ /* That didn't work, but the user thinks there's a
+ * port here. */
+ printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n",
+ pb->base, w, r);
+
+ /* Try the data register. The data lines aren't tri-stated at
+ * this stage, so we expect back what we wrote. */
+ w = 0xaa;
+ parport_pc_write_data (pb, w);
+ r = parport_pc_read_data (pb);
+ if (r == w) {
+ w = 0x55;
+ parport_pc_write_data (pb, w);
+ r = parport_pc_read_data (pb);
+ if (r == w)
+ return PARPORT_MODE_PCSPP;
+ }
+
+ if (user_specified)
+ /* Didn't work, but the user is convinced this is the
+ * place. */
+ printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
+ pb->base, w, r);
+
+ /* It's possible that we can't read the control register or
+ * the data register. In that case just believe the user. */
+ if (user_specified)
+ return PARPORT_MODE_PCSPP;
+
+ return 0;
+}
+
+/* Check for ECR
+ *
+ * Old style XT ports alias io ports every 0x400, hence accessing ECR
+ * on these cards actually accesses the CTR.
+ *
+ * Modern cards don't do this but reading from ECR will return 0xff
+ * regardless of what is written here if the card does NOT support
+ * ECP.
+ *
+ * We first check to see if ECR is the same as CTR. If not, the low
+ * two bits of ECR aren't writable, so we check by writing ECR and
+ * reading it back to see if it's what we expect.
+ */
+static int __init parport_ECR_present(struct parport *pb)
+{
+ struct parport_pc_private *priv = pb->private_data;
+ unsigned char r = 0xc;
+
+ priv->ecr = 0;
+ outb (r, CONTROL (pb));
+ if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
+ outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */
+
+ r = inb (CONTROL (pb));
+ if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2))
+ goto no_reg; /* Sure that no ECR register exists */
+ }
+
+ if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1)
+ goto no_reg;
+
+ outb (0x34, ECONTROL (pb));
+ if (inb (ECONTROL (pb)) != 0x35)
+ goto no_reg;
+
+ priv->ecr = 1;
+ outb (0xc, CONTROL (pb));
+
+ /* Go to mode 000 */
+ frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+
+ return 1;
+
+ no_reg:
+ outb (0xc, CONTROL (pb));
+ return 0;
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Detect PS/2 support.
+ *
+ * Bit 5 (0x20) sets the PS/2 data direction; setting this high
+ * allows us to read data from the data lines. In theory we would get back
+ * 0xff but any peripheral attached to the port may drag some or all of the
+ * lines down to zero. So if we get back anything that isn't the contents
+ * of the data register we deem PS/2 support to be present.
+ *
+ * Some SPP ports have "half PS/2" ability - you can't turn off the line
+ * drivers, but an external peripheral with sufficiently beefy drivers of
+ * its own can overpower them and assert its own levels onto the bus, from
+ * where they can then be read back as normal. Ports with this property
+ * and the right type of device attached are likely to fail the SPP test,
+ * (as they will appear to have stuck bits) and so the fact that they might
+ * be misdetected here is rather academic.
+ */
+
+static int __init parport_PS2_supported(struct parport *pb)
+{
+ int ok = 0;
+
+ clear_epp_timeout(pb);
+
+ /* try to tri-state the buffer */
+ parport_pc_data_reverse (pb);
+
+ parport_pc_write_data(pb, 0x55);
+ if (parport_pc_read_data(pb) != 0x55) ok++;
+
+ parport_pc_write_data(pb, 0xaa);
+ if (parport_pc_read_data(pb) != 0xaa) ok++;
+
+ /* cancel input mode */
+ parport_pc_data_forward (pb);
+
+ if (ok)
+ pb->modes |= PARPORT_MODE_TRISTATE;
+ else {
+ struct parport_pc_private *priv = pb->private_data;
+ priv->ctr_writable &= ~0x20;
+ }
+
+ return ok;
+}
+
+static int __init parport_ECP_supported(struct parport *pb)
+{
+ int i;
+ int config;
+ int pword;
+ struct parport_pc_private *priv = pb->private_data;
+
+ /* If there is no ECR, we have no hope of supporting ECP. */
+ if (!priv->ecr)
+ return 0;
+
+ /* Find out FIFO depth */
+ outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+ outb (ECR_TST << 5, ECONTROL (pb)); /* TEST FIFO */
+ for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++)
+ outb (0xaa, FIFO (pb));
+
+ /*
+ * Using LGS chipset it uses ECR register, but
+ * it doesn't support ECP or FIFO MODE
+ */
+ if (i == 1024) {
+ outb (ECR_SPP << 5, ECONTROL (pb));
+ return 0;
+ }
+
+ priv->fifo_depth = i;
+ printk (KERN_INFO "0x%lx: FIFO is %d bytes\n", pb->base, i);
+
+ /* Find out writeIntrThreshold */
+ frob_econtrol (pb, 1<<2, 1<<2);
+ frob_econtrol (pb, 1<<2, 0);
+ for (i = 1; i <= priv->fifo_depth; i++) {
+ inb (FIFO (pb));
+ udelay (50);
+ if (inb (ECONTROL (pb)) & (1<<2))
+ break;
+ }
+
+ if (i <= priv->fifo_depth)
+ printk (KERN_INFO "0x%lx: writeIntrThreshold is %d\n",
+ pb->base, i);
+ else
+ /* Number of bytes we know we can write if we get an
+ interrupt. */
+ i = 0;
+
+ priv->writeIntrThreshold = i;
+
+ /* Find out readIntrThreshold */
+ frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */
+ parport_pc_data_reverse (pb);
+ frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */
+ frob_econtrol (pb, 1<<2, 1<<2);
+ frob_econtrol (pb, 1<<2, 0);
+ for (i = 1; i <= priv->fifo_depth; i++) {
+ outb (0xaa, FIFO (pb));
+ if (inb (ECONTROL (pb)) & (1<<2))
+ break;
+ }
+
+ if (i <= priv->fifo_depth)
+ printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n",
+ pb->base, i);
+ else
+ /* Number of bytes we can read if we get an interrupt. */
+ i = 0;
+
+ priv->readIntrThreshold = i;
+
+ outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+ outb (0xf4, ECONTROL (pb)); /* Configuration mode */
+ config = inb (FIFO (pb));
+ pword = (config >> 4) & 0x7;
+ switch (pword) {
+ case 0:
+ pword = 2;
+ printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+ pb->base);
+ break;
+ case 2:
+ pword = 4;
+ printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+ pb->base);
+ break;
+ default:
+ printk (KERN_WARNING "0x%lx: Unknown implementation ID\n",
+ pb->base);
+ /* Assume 1 */
+ case 1:
+ pword = 1;
+ }
+ priv->pword = pword;
+ printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword);
+
+ config = inb (CONFIGB (pb));
+ printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
+ config & 0x80 ? "Level" : "Pulses");
+
+ if (!(config & 0x40)) {
+ printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base);
+ pb->irq = PARPORT_IRQ_NONE;
+ }
+
+ /* Go back to mode 000 */
+ frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+ pb->modes |= PARPORT_MODE_ECP;
+
+ return 1;
+}
+
+static int __init parport_ECPPS2_supported(struct parport *pb)
+{
+ const struct parport_pc_private *priv = pb->private_data;
+ int result;
+ unsigned char oecr;
+
+ if (!priv->ecr)
+ return 0;
+
+ oecr = inb (ECONTROL (pb));
+ outb (ECR_PS2 << 5, ECONTROL (pb));
+
+ result = parport_PS2_supported(pb);
+
+ outb (oecr, ECONTROL (pb));
+ return result;
+}
+
+/* EPP mode detection */
+
+static int __init parport_EPP_supported(struct parport *pb)
+{
+ const struct parport_pc_private *priv = pb->private_data;
+
+ /*
+ * Theory:
+ * Bit 0 of STR is the EPP timeout bit, this bit is 0
+ * when EPP is possible and is set high when an EPP timeout
+ * occurs (EPP uses the HALT line to stop the CPU while it does
+ * the byte transfer, an EPP timeout occurs if the attached
+ * device fails to respond after 10 micro seconds).
+ *
+ * This bit is cleared by either reading it (National Semi)
+ * or writing a 1 to the bit (SMC, UMC, WinBond), others ???
+ * This bit is always high in non EPP modes.
+ */
+
+ /* If EPP timeout bit clear then EPP available */
+ if (!clear_epp_timeout(pb))
+ return 0; /* No way to clear timeout */
+
+ /* Check for Intel bug. */
+ if (priv->ecr) {
+ unsigned char i;
+ for (i = 0x00; i < 0x80; i += 0x20) {
+ outb (i, ECONTROL (pb));
+ if (clear_epp_timeout (pb))
+ /* Phony EPP in ECP. */
+ return 0;
+ }
+ }
+
+ pb->modes |= PARPORT_MODE_EPP;
+
+ /* Set up access functions to use EPP hardware. */
+ parport_pc_ops.epp_read_data = parport_pc_epp_read_data;
+ parport_pc_ops.epp_write_data = parport_pc_epp_write_data;
+ parport_pc_ops.epp_read_addr = parport_pc_epp_read_addr;
+ parport_pc_ops.epp_write_addr = parport_pc_epp_write_addr;
+
+ return 1;
+}
+
+static int __init parport_ECPEPP_supported(struct parport *pb)
+{
+ struct parport_pc_private *priv = pb->private_data;
+ int result;
+ unsigned char oecr;
+
+ if (!priv->ecr)
+ return 0;
+
+ oecr = inb (ECONTROL (pb));
+ /* Search for SMC style EPP+ECP mode */
+ outb (0x80, ECONTROL (pb));
+
+ result = parport_EPP_supported(pb);
+
+ outb (oecr, ECONTROL (pb));
+
+ if (result) {
+ /* Set up access functions to use ECP+EPP hardware. */
+ parport_pc_ops.epp_read_data = parport_pc_ecpepp_read_data;
+ parport_pc_ops.epp_write_data = parport_pc_ecpepp_write_data;
+ parport_pc_ops.epp_read_addr = parport_pc_ecpepp_read_addr;
+ parport_pc_ops.epp_write_addr = parport_pc_ecpepp_write_addr;
+ }
+
+ return result;
+}
+
+#else /* No IEEE 1284 support */
+
+/* Don't bother probing for modes we know we won't use. */
+static int __init parport_PS2_supported(struct parport *pb) { return 0; }
+static int __init parport_ECP_supported(struct parport *pb) { return 0; }
+static int __init parport_EPP_supported(struct parport *pb) { return 0; }
+static int __init parport_ECPEPP_supported(struct parport *pb) { return 0; }
+static int __init parport_ECPPS2_supported(struct parport *pb) { return 0; }
+
+#endif /* No IEEE 1284 support */
+
+/* --- IRQ detection -------------------------------------- */
+
+/* Only if supports ECP mode */
+static int __init programmable_irq_support(struct parport *pb)
+{
+ int irq, intrLine;
+ unsigned char oecr = inb (ECONTROL (pb));
+ static const int lookup[8] = {
+ PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5
+ };
+
+ outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */
+
+ intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07;
+ irq = lookup[intrLine];
+
+ outb (oecr, ECONTROL (pb));
+ return irq;
+}
+
+static int __init irq_probe_ECP(struct parport *pb)
+{
+ int i;
+ unsigned long irqs;
+
+ sti();
+ irqs = probe_irq_on();
+
+ outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+ outb ((ECR_TST << 5) | 0x04, ECONTROL (pb));
+ outb (ECR_TST << 5, ECONTROL (pb));
+
+ /* If Full FIFO sure that writeIntrThreshold is generated */
+ for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++)
+ outb (0xaa, FIFO (pb));
+
+ pb->irq = probe_irq_off(irqs);
+ outb (ECR_SPP << 5, ECONTROL (pb));
+
+ if (pb->irq <= 0)
+ pb->irq = PARPORT_IRQ_NONE;
+
+ return pb->irq;
+}
+
+/*
+ * This detection seems that only works in National Semiconductors
+ * This doesn't work in SMC, LGS, and Winbond
+ */
+static int __init irq_probe_EPP(struct parport *pb)
+{
+#ifndef ADVANCED_DETECT
+ return PARPORT_IRQ_NONE;
+#else
+ int irqs;
+ unsigned char oecr;
+
+ if (pb->modes & PARPORT_MODE_PCECR)
+ oecr = inb (ECONTROL (pb));
+
+ sti();
+ irqs = probe_irq_on();
+
+ if (pb->modes & PARPORT_MODE_PCECR)
+ frob_econtrol (pb, 0x10, 0x10);
+
+ clear_epp_timeout(pb);
+ parport_pc_frob_control (pb, 0x20, 0x20);
+ parport_pc_frob_control (pb, 0x10, 0x10);
+ clear_epp_timeout(pb);
+
+ /* Device isn't expecting an EPP read
+ * and generates an IRQ.
+ */
+ parport_pc_read_epp(pb);
+ udelay(20);
+
+ pb->irq = probe_irq_off (irqs);
+ if (pb->modes & PARPORT_MODE_PCECR)
+ outb (oecr, ECONTROL (pb));
+ parport_pc_write_control(pb, 0xc);
+
+ if (pb->irq <= 0)
+ pb->irq = PARPORT_IRQ_NONE;
+
+ return pb->irq;
+#endif /* Advanced detection */
+}
+
+static int __init irq_probe_SPP(struct parport *pb)
+{
+ /* Don't even try to do this. */
+ return PARPORT_IRQ_NONE;
+}
+
+/* We will attempt to share interrupt requests since other devices
+ * such as sound cards and network cards seem to like using the
+ * printer IRQs.
+ *
+ * When ECP is available we can autoprobe for IRQs.
+ * NOTE: If we can autoprobe it, we can register the IRQ.
+ */
+static int __init parport_irq_probe(struct parport *pb)
+{
+ const struct parport_pc_private *priv = pb->private_data;
+
+ if (priv->ecr) {
+ pb->irq = programmable_irq_support(pb);
+ if (pb->irq != PARPORT_IRQ_NONE)
+ goto out;
+ }
+
+ if (pb->modes & PARPORT_MODE_ECP)
+ pb->irq = irq_probe_ECP(pb);
+
+ if (pb->irq == PARPORT_IRQ_NONE && priv->ecr &&
+ (pb->modes & PARPORT_MODE_EPP))
+ pb->irq = irq_probe_EPP(pb);
+
+ clear_epp_timeout(pb);
+
+ if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP))
+ pb->irq = irq_probe_EPP(pb);
+
+ clear_epp_timeout(pb);
+
+ if (pb->irq == PARPORT_IRQ_NONE)
+ pb->irq = irq_probe_SPP(pb);
+
+out:
+ return pb->irq;
+}
+
+/* --- DMA detection -------------------------------------- */
+
+/* Only if supports ECP mode */
+static int __init programmable_dma_support (struct parport *p)
+{
+ unsigned char oecr = inb (ECONTROL (p));
+ int dma;
+
+ frob_econtrol (p, 0xe0, ECR_CNF << 5);
+
+ dma = inb (CONFIGB(p)) & 0x03;
+ if (!dma)
+ dma = PARPORT_DMA_NONE;
+
+ outb (oecr, ECONTROL (p));
+ return dma;
+}
+
+static int __init parport_dma_probe (struct parport *p)
+{
+ const struct parport_pc_private *priv = p->private_data;
+ if (priv->ecr)
+ p->dma = programmable_dma_support(p);
+
+ return p->dma;
+}
+
+/* --- Initialisation code -------------------------------- */
+
+static int __init probe_one_port(unsigned long int base,
+ unsigned long int base_hi,
+ int irq, int dma)
+{
+ struct parport_pc_private *priv;
+ struct parport tmp;
+ struct parport *p = &tmp;
+ int probedirq = PARPORT_IRQ_NONE;
+ if (check_region(base, 3)) return 0;
+ priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL);
+ if (!priv) {
+ printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
+ return 0;
+ }
+ priv->ctr = 0xc;
+ priv->ctr_writable = 0xff;
+ priv->ecr = 0;
+ priv->fifo_depth = 0;
+ priv->dma_buf = 0;
+ p->base = base;
+ p->base_hi = base_hi;
+ p->irq = irq;
+ p->dma = dma;
+ p->modes = PARPORT_MODE_PCSPP;
+ p->ops = &parport_pc_ops;
+ p->private_data = priv;
+ p->physport = p;
+ if (base_hi && !check_region(base_hi,3)) {
+ parport_ECR_present(p);
+ parport_ECP_supported(p);
+ parport_ECPPS2_supported(p);
+ }
+ if (base != 0x3bc) {
+ if (!check_region(base+0x3, 5)) {
+ parport_EPP_supported(p);
+ if (!(p->modes & PARPORT_MODE_EPP))
+ parport_ECPEPP_supported(p);
+ }
+ }
+ if (!parport_SPP_supported (p)) {
+ /* No port. */
+ kfree (priv);
+ return 0;
+ }
+
+ parport_PS2_supported (p);
+
+ if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
+ PARPORT_DMA_NONE, &parport_pc_ops))) {
+ kfree (priv);
+ return 0;
+ }
+
+ p->base_hi = base_hi;
+ p->modes = tmp.modes;
+ p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
+ p->private_data = priv;
+
+ printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
+ if (p->base_hi && (p->modes & PARPORT_MODE_ECP))
+ printk(" (0x%lx)", p->base_hi);
+ p->irq = irq;
+ p->dma = dma;
+ if (p->irq == PARPORT_IRQ_AUTO) {
+ p->irq = PARPORT_IRQ_NONE;
+ parport_irq_probe(p);
+ } else if (p->irq == PARPORT_IRQ_PROBEONLY) {
+ p->irq = PARPORT_IRQ_NONE;
+ parport_irq_probe(p);
+ probedirq = p->irq;
+ p->irq = PARPORT_IRQ_NONE;
+ }
+ if (p->irq != PARPORT_IRQ_NONE) {
+ printk(", irq %d", p->irq);
+
+ if (p->dma == PARPORT_DMA_AUTO) {
+ p->dma = PARPORT_DMA_NONE;
+ parport_dma_probe(p);
+ }
+ }
+ if (p->dma == PARPORT_DMA_AUTO)
+ p->dma = PARPORT_DMA_NONE;
+ if (p->dma != PARPORT_DMA_NONE)
+ printk(", dma %d", p->dma);
+
+#ifdef CONFIG_PARPORT_PC_FIFO
+ if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
+ parport_pc_ops.compat_write_data =
+ parport_pc_compat_write_block_pio;
+#ifdef CONFIG_PARPORT_1284
+ parport_pc_ops.ecp_write_data =
+ parport_pc_ecp_write_block_pio;
+#endif /* IEEE 1284 support */
+ if (p->dma != PARPORT_DMA_NONE)
+ p->modes |= PARPORT_MODE_DMA;
+ printk(", using FIFO");
+ }
+#endif /* Allowed to use FIFO/DMA */
+
+ printk(" [");
+#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
+ {
+ int f = 0;
+ printmode(PCSPP);
+ printmode(TRISTATE);
+ printmode(COMPAT)
+ printmode(EPP);
+ printmode(ECP);
+ printmode(DMA);
+ }
+#undef printmode
+ printk("]\n");
+ if (probedirq != PARPORT_IRQ_NONE)
+ printk("%s: irq %d detected\n", p->name, probedirq);
+ parport_proc_register(p);
+
+ request_region (p->base, 3, p->name);
+ if (p->size > 3)
+ request_region (p->base + 3, p->size - 3, p->name);
+ if (p->modes & PARPORT_MODE_ECP)
+ request_region (p->base_hi, 3, p->name);
+
+ if (p->irq != PARPORT_IRQ_NONE) {
+ if (request_irq (p->irq, parport_pc_interrupt,
+ 0, p->name, p)) {
+ printk (KERN_WARNING "%s: irq %d in use, "
+ "resorting to polled operation\n",
+ p->name, p->irq);
+ p->irq = PARPORT_IRQ_NONE;
+ p->dma = PARPORT_DMA_NONE;
+ }
+
+ if (p->dma != PARPORT_DMA_NONE) {
+ if (request_dma (p->dma, p->name)) {
+ printk (KERN_WARNING "%s: dma %d in use, "
+ "resorting to PIO operation\n",
+ p->name, p->dma);
+ p->dma = PARPORT_DMA_NONE;
+ } else {
+ priv->dma_buf = (char *) __get_dma_pages(GFP_KERNEL, 1);
+ if (! priv->dma_buf) {
+ printk (KERN_WARNING "%s: "
+ "cannot get buffer for DMA, "
+ "resorting to PIO operation\n",
+ p->name);
+ free_dma(p->dma);
+ p->dma = PARPORT_DMA_NONE;
+ }
+ }
+ }
+ }
+
+ /* Done probing. Now put the port into a sensible start-up state.
+ * SELECT | INIT also puts IEEE1284-compliant devices into
+ * compatibility mode. */
+ if (p->modes & PARPORT_MODE_ECP)
+ /*
+ * Put the ECP detected port in PS2 mode.
+ */
+ outb (0x24, ECONTROL (p));
+
+ parport_pc_write_data(p, 0);
+ parport_pc_data_forward (p);
+ parport_pc_write_control(p, PARPORT_CONTROL_SELECT);
+ udelay (50);
+ parport_pc_write_control(p,
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_INIT);
+ udelay (50);
+
+ /* Now that we've told the sharing engine about the port, and
+ found out its characteristics, let the high-level drivers
+ know about it. */
+ parport_announce_port (p);
+
+ return 1;
+}
+
+/* Look for PCI parallel port cards. */
+static int __init parport_pc_init_pci (int irq, int dma)
+{
+/* These need to go in pci.h: */
+#ifndef PCI_VENDOR_ID_SIIG
+#define PCI_VENDOR_ID_SIIG 0x131f
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_550 0x1010
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_650 0x1011
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_850 0x1012
+#define PCI_DEVICE_ID_SIIG_1P_10x 0x1020
+#define PCI_DEVICE_ID_SIIG_2P_10x 0x1021
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_550 0x1034
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_650 0x1035
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_850 0x1036
+#define PCI_DEVICE_ID_SIIG_1P_20x 0x2020
+#define PCI_DEVICE_ID_SIIG_2P_20x 0x2021
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_550 0x2040
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_650 0x2041
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_850 0x2042
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_550 0x2010
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_650 0x2011
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_850 0x2012
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062
+#define PCI_VENDOR_ID_LAVA 0x1407
+#define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8001 /* The Lava Dual Parallel is */
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8002 /* two PCI devices on a card */
+#endif
+
+ struct {
+ unsigned int vendor;
+ unsigned int device;
+ unsigned int numports;
+ struct {
+ unsigned int lo;
+ unsigned int hi; /* -ve if not there */
+ } addr[4];
+ } cards[] = {
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, 1,
+ { { 3, 4 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, 1,
+ { { 3, 4 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, 1,
+ { { 3, 4 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x, 1,
+ { { 2, 3 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x, 2,
+ { { 2, 3 }, { 4, 5 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, 1,
+ { { 4, 5 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, 1,
+ { { 4, 5 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, 1,
+ { { 4, 5 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x, 1,
+ { { 0, 1 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x, 2,
+ { { 0, 1 }, { 2, 3 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, 2,
+ { { 1, 2 }, { 3, 4 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, 2,
+ { { 1, 2 }, { 3, 4 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, 2,
+ { { 1, 2 }, { 3, 4 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, 1,
+ { { 1, 2 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, 1,
+ { { 1, 2 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, 1,
+ { { 1, 2 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, 1,
+ { { 2, 3 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, 1,
+ { { 2, 3 }, } },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, 1,
+ { { 2, 3 }, } },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL, 1,
+ { { 0, -1 }, } },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A, 1,
+ { { 0, -1 }, } },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1,
+ { { 0, -1 }, } },
+ { 0, }
+ };
+
+ int count = 0;
+ int i;
+
+ if (!pci_present ())
+ return 0;
+
+ for (i = 0; cards[i].vendor; i++) {
+ struct pci_dev *pcidev = NULL;
+ while ((pcidev = pci_find_device (cards[i].vendor,
+ cards[i].device,
+ pcidev)) != NULL) {
+ int n;
+ for (n = 0; n < cards[i].numports; n++) {
+ int lo = cards[i].addr[n].lo;
+ int hi = cards[i].addr[n].hi;
+ int io_lo = pcidev->base_address[lo];
+ int io_hi = ((hi < 0) ? 0 :
+ pcidev->base_address[hi]);
+ io_lo &= PCI_BASE_ADDRESS_IO_MASK;
+ io_hi &= PCI_BASE_ADDRESS_IO_MASK;
+ count += probe_one_port (io_lo, io_hi,
+ irq, dma);
+ }
+ }
+ }
+
+ return count;
+}
+
+int __init parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
+{
+ int count = 0, i = 0;
+ if (io && *io) {
+ /* Only probe the ports we were given. */
+ user_specified = 1;
+ do {
+ if (!*io_hi) *io_hi = 0x400 + *io;
+ count += probe_one_port(*(io++), *(io_hi++),
+ *(irq++), *(dma++));
+ } while (*io && (++i < PARPORT_PC_MAX_PORTS));
+ } else {
+ /* Probe all the likely ports. */
+ count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]);
+ count += probe_one_port(0x378, 0x778, irq[0], dma[0]);
+ count += probe_one_port(0x278, 0x678, irq[0], dma[0]);
+ count += parport_pc_init_pci (irq[0], dma[0]);
+ }
+
+ return count;
+}
+
+#ifdef MODULE
+static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
+static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
+static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
+static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
+static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
+static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
+MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
+MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
+
+int init_module(void)
+{
+ /* Work out how many ports we have, then get parport_share to parse
+ the irq values. */
+ unsigned int i;
+ for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
+ if (i) {
+ if (parport_parse_irqs(i, irq, irqval)) return 1;
+ if (parport_parse_dmas(i, dma, dmaval)) return 1;
+ }
+ else {
+ /* The user can make us use any IRQs or DMAs we find. */
+ int val;
+
+ if (irq[0] && !parport_parse_irqs (1, irq, &val))
+ switch (val) {
+ case PARPORT_IRQ_NONE:
+ case PARPORT_IRQ_AUTO:
+ irqval[0] = val;
+ }
+
+ if (dma[0] && !parport_parse_dmas (1, dma, &val))
+ switch (val) {
+ case PARPORT_DMA_NONE:
+ case PARPORT_DMA_AUTO:
+ dmaval[0] = val;
+ }
+ }
+
+ return (parport_pc_init(io, io_hi, irqval, dmaval)?0:1);
+}
+
+void cleanup_module(void)
+{
+ struct parport *p = parport_enumerate(), *tmp;
+ while (p) {
+ tmp = p->next;
+ if (p->modes & PARPORT_MODE_PCSPP) {
+ struct parport_pc_private *priv = p->private_data;
+ if (p->dma != PARPORT_DMA_NONE)
+ free_dma(p->dma);
+ if (p->irq != PARPORT_IRQ_NONE)
+ free_irq(p->irq, p);
+ release_region(p->base, 3);
+ if (p->size > 3);
+ release_region(p->base + 3, p->size - 3);
+ if (p->modes & PARPORT_MODE_ECP)
+ release_region(p->base_hi, 3);
+ parport_proc_unregister(p);
+ if (priv->dma_buf)
+ free_page((unsigned long) priv->dma_buf);
+ kfree (p->private_data);
+ parport_unregister_port(p);
+ }
+ p = tmp;
+ }
+}
+#endif
--- /dev/null
+/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $
+ * Parallel port device probing code
+ *
+ * Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
+ * Philip Blundell <Philip.Blundell@pobox.com>
+ */
+
+#include <linux/parport.h>
+#include <linux/ctype.h>
+#include <asm/uaccess.h>
+
+static struct {
+ char *token;
+ char *descr;
+} classes[] = {
+ { "", "Legacy device" },
+ { "PRINTER", "Printer" },
+ { "MODEM", "Modem" },
+ { "NET", "Network device" },
+ { "HDC", "Hard disk" },
+ { "PCMCIA", "PCMCIA" },
+ { "MEDIA", "Multimedia device" },
+ { "FDC", "Floppy disk" },
+ { "PORTS", "Ports" },
+ { "SCANNER", "Scanner" },
+ { "DIGICAM", "Digital camera" },
+ { "", "Unknown device" },
+ { "", "Unspecified" },
+ { "SCSIADAPTER", "SCSI adapter" },
+ { NULL, NULL }
+};
+
+static void pretty_print(struct parport *port, int device)
+{
+ struct parport_device_info *info = &port->probe_info[device + 1];
+
+ printk(KERN_INFO "%s", port->name);
+
+ if (device >= 0)
+ printk (" (addr %d)", device);
+
+ printk (": %s", classes[info->class].descr);
+ if (info->class)
+ printk(", %s %s", info->mfr, info->model);
+
+ printk("\n");
+}
+
+static char *strdup(char *str)
+{
+ int n = strlen(str)+1;
+ char *s = kmalloc(n, GFP_KERNEL);
+ if (!s) return NULL;
+ return strcpy(s, str);
+}
+
+static void parse_data(struct parport *port, int device, char *str)
+{
+ char *txt = kmalloc(strlen(str)+1, GFP_KERNEL);
+ char *p = txt, *q;
+ int guessed_class = PARPORT_CLASS_UNSPEC;
+ struct parport_device_info *info = &port->probe_info[device + 1];
+
+ if (!txt) {
+ printk("%s probe: memory squeeze\n", port->name);
+ return;
+ }
+ strcpy(txt, str);
+ while (p) {
+ char *sep;
+ q = strchr(p, ';');
+ if (q) *q = 0;
+ sep = strchr(p, ':');
+ if (sep) {
+ char *u = p;
+ *(sep++) = 0;
+ while (*u) {
+ *u = toupper(*u);
+ u++;
+ }
+ if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
+ if (info->mfr)
+ kfree (info->mfr);
+ info->mfr = strdup(sep);
+ } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
+ if (info->model)
+ kfree (info->model);
+ info->model = strdup(sep);
+ } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
+ int i;
+ if (info->class_name)
+ kfree (info->class_name);
+ info->class_name = strdup(sep);
+ for (u = sep; *u; u++)
+ *u = toupper(*u);
+ for (i = 0; classes[i].token; i++) {
+ if (!strcmp(classes[i].token, sep)) {
+ info->class = i;
+ goto rock_on;
+ }
+ }
+ printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep);
+ info->class = PARPORT_CLASS_OTHER;
+ } else if (!strcmp(p, "CMD") ||
+ !strcmp(p, "COMMAND SET")) {
+ if (info->cmdset)
+ kfree (info->cmdset);
+ info->cmdset = strdup(sep);
+ /* if it speaks printer language, it's
+ probably a printer */
+ if (strstr(sep, "PJL") || strstr(sep, "PCL"))
+ guessed_class = PARPORT_CLASS_PRINTER;
+ } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
+ if (info->description)
+ kfree (info->description);
+ info->description = strdup(sep);
+ }
+ }
+ rock_on:
+ if (q) p = q+1; else p=NULL;
+ }
+
+ /* If the device didn't tell us its class, maybe we have managed to
+ guess one from the things it did say. */
+ if (info->class == PARPORT_CLASS_UNSPEC)
+ info->class = guessed_class;
+
+ pretty_print (port, device);
+
+ kfree(txt);
+}
+
+/* Get Std 1284 Device ID. */
+ssize_t parport_device_id (int devnum, char *buffer, size_t len)
+{
+ ssize_t retval = -ENXIO;
+ struct pardevice *dev = parport_open (devnum, "Device ID probe",
+ NULL, NULL, NULL, 0, NULL);
+ if (!dev)
+ return -ENXIO;
+
+ parport_claim_or_block (dev);
+
+ /* Negotiate to compatibility mode, and then to device ID mode.
+ * (This is in case we are already in device ID mode.) */
+ parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
+ retval = parport_negotiate (dev->port,
+ IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID);
+
+ if (!retval) {
+ int idlen;
+ unsigned char length[2];
+ mm_segment_t oldfs = get_fs ();
+ set_fs (get_ds ());
+
+ /* First two bytes are MSB,LSB of inclusive length. */
+ retval = parport_read (dev->port, length, 2);
+
+ if (retval != 2) goto restore_fs;
+
+ idlen = (length[0] << 8) + length[1] - 2;
+ if (idlen < len)
+ len = idlen;
+ retval = parport_read (dev->port, buffer, len);
+
+ if (retval != len) {
+ printk (KERN_DEBUG "%s: only read %d of %d ID bytes\n",
+ dev->port->name, retval, len);
+ goto restore_fs;
+ }
+
+ /* Some printer manufacturers mistakenly believe that
+ the length field is supposed to be _exclusive_. */
+ /* In addition, there are broken devices out there
+ that don't even finish off with a semi-colon. */
+ if (idlen == len && buffer[len - 1] != ';') {
+ ssize_t diff;
+ diff = parport_read (dev->port, buffer + len, 2);
+ retval += diff;
+
+ if (diff)
+ printk (KERN_DEBUG
+ "%s: device reported incorrect "
+ "length field (%d, should be %d)\n",
+ dev->port->name, idlen, retval);
+ else {
+ /* One semi-colon short of a device ID. */
+ buffer[len++] = ';';
+ buffer[len] = '\0';
+ printk (KERN_DEBUG "%s: faking semi-colon\n",
+ dev->port->name);
+
+ /* If we get here, I don't think we
+ need to worry about the possible
+ standard violation of having read
+ more than we were told to. The
+ device is non-compliant anyhow. */
+ }
+ }
+
+ restore_fs:
+ set_fs (oldfs);
+ parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
+ }
+ parport_release (dev);
+
+ if (retval > 0)
+ parse_data (dev->port, dev->daisy, buffer);
+
+ parport_close (dev);
+ return retval;
+}
--- /dev/null
+/* Sysctl interface for parport devices.
+ *
+ * Authors: David Campbell <campbell@torque.net>
+ * Tim Waugh <tim@cyberelk.demon.co.uk>
+ * Philip Blundell <philb@gnu.org>
+ * Andrea Arcangeli
+ * Riccardo Facchetti <fizban@tin.it>
+ *
+ * based on work by Grant Guenther <grant@torque.net>
+ * and Philip Blundell
+ *
+ * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
+ */
+
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/parport.h>
+#include <linux/ctype.h>
+#include <linux/sysctl.h>
+
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_SYSCTL
+
+
+static int do_active_device(ctl_table *table, int write, struct file *filp,
+ void *result, size_t *lenp)
+{
+ struct parport *port = (struct parport *)table->extra1;
+ char buffer[256];
+ struct pardevice *dev;
+ int len = 0;
+
+ if (write) /* can't happen anyway */
+ return -EACCES;
+
+ if (filp->f_pos) {
+ *lenp = 0;
+ return 0;
+ }
+
+ for (dev = port->devices; dev ; dev = dev->next) {
+ if(dev == port->cad) {
+ len += sprintf(buffer, "%s\n", dev->name);
+ }
+ }
+
+ if(!len) {
+ len += sprintf(buffer, "%s\n", "none");
+ }
+
+ if (len > *lenp)
+ len = *lenp;
+ else
+ *lenp = len;
+
+ filp->f_pos += len;
+
+ return copy_to_user(result, buffer, len) ? -EFAULT : 0;
+}
+
+#ifdef CONFIG_PARPORT_1284
+static int do_autoprobe(ctl_table *table, int write, struct file *filp,
+ void *result, size_t *lenp)
+{
+ struct parport_device_info *info = table->extra2;
+ const char *str;
+ char buffer[256];
+ int len = 0;
+
+ if (write) /* permissions stop this */
+ return -EACCES;
+
+ if (filp->f_pos) {
+ *lenp = 0;
+ return 0;
+ }
+
+ if ((str = info->class_name) != NULL)
+ len += sprintf (buffer + len, "CLASS:%s;\n", str);
+
+ if ((str = info->model) != NULL)
+ len += sprintf (buffer + len, "MODEL:%s;\n", str);
+
+ if ((str = info->mfr) != NULL)
+ len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str);
+
+ if ((str = info->description) != NULL)
+ len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str);
+
+ if ((str = info->cmdset) != NULL)
+ len += sprintf (buffer + len, "COMMAND SET:%s;\n", str);
+
+ if (len > *lenp)
+ len = *lenp;
+ else
+ *lenp = len;
+
+ filp->f_pos += len;
+
+ return copy_to_user (result, buffer, len) ? -EFAULT : 0;
+}
+#endif /* IEEE1284.3 support. */
+
+static int do_hardware(ctl_table *table, int write, struct file *filp,
+ void *result, size_t *lenp)
+{
+ struct parport *port = (struct parport *)table->extra1;
+ char buffer[256];
+ int len = 0;
+
+ if (filp->f_pos) {
+ *lenp = 0;
+ return 0;
+ }
+
+ if (write) /* can't happen anyway */
+ return -EACCES;
+
+ len += sprintf(buffer+len, "base:\t0x%lx", port->base);
+ if (port->base_hi)
+ len += sprintf(buffer+len, " (0x%lx)", port->base_hi);
+ buffer[len++] = '\n';
+
+ if (port->irq == PARPORT_IRQ_NONE) {
+ len += sprintf(buffer+len, "irq:\tnone\n");
+ } else {
+#ifdef __sparc__
+ len += sprintf(buffer+len, "irq:\t%s\n",
+ __irq_itoa(port->irq));
+#else
+ len += sprintf(buffer+len, "irq:\t%d\n", port->irq);
+#endif
+ }
+
+ if (port->dma == PARPORT_DMA_NONE)
+ len += sprintf(buffer+len, "dma:\tnone\n");
+ else
+ len += sprintf(buffer+len, "dma:\t%d\n", port->dma);
+
+ len += sprintf(buffer+len, "modes:\t");
+ {
+#define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}}
+ int f = 0;
+ printmode(PCSPP);
+ printmode(TRISTATE);
+ printmode(COMPAT);
+ printmode(EPP);
+ printmode(ECP);
+ printmode(DMA);
+#undef printmode
+ }
+ buffer[len++] = '\n';
+
+ if (len > *lenp)
+ len = *lenp;
+ else
+ *lenp = len;
+
+ filp->f_pos += len;
+
+ return copy_to_user(result, buffer, len) ? -EFAULT : 0;
+}
+
+#define PARPORT_PORT_DIR(child) { 0, NULL, NULL, 0, 0555, child }
+#define PARPORT_PARPORT_DIR(child) { DEV_PARPORT, "parport", \
+ NULL, 0, 0555, child }
+#define PARPORT_DEV_DIR(child) { CTL_DEV, "dev", NULL, 0, 0555, child }
+#define PARPORT_DEVICES_ROOT_DIR { DEV_PARPORT_DEVICES, "devices", \
+ NULL, 0, 0555, NULL }
+
+
+struct parport_sysctl_table {
+ struct ctl_table_header *sysctl_header;
+ ctl_table vars[9];
+ ctl_table device_dir[2];
+ ctl_table port_dir[2];
+ ctl_table parport_dir[2];
+ ctl_table dev_dir[2];
+};
+
+static const struct parport_sysctl_table parport_sysctl_template = {
+ NULL,
+ {
+ { DEV_PARPORT_SPINTIME, "spintime",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec },
+ { DEV_PARPORT_HARDWARE, "hardware",
+ NULL, 0, 0444, NULL,
+ &do_hardware },
+ PARPORT_DEVICES_ROOT_DIR,
+#ifdef CONFIG_PARPORT_1284
+ { DEV_PARPORT_AUTOPROBE, "autoprobe",
+ NULL, 0, 0444, NULL,
+ &do_autoprobe },
+ { DEV_PARPORT_AUTOPROBE + 1, "autoprobe0",
+ NULL, 0, 0444, NULL,
+ &do_autoprobe },
+ { DEV_PARPORT_AUTOPROBE + 2, "autoprobe1",
+ NULL, 0, 0444, NULL,
+ &do_autoprobe },
+ { DEV_PARPORT_AUTOPROBE + 3, "autoprobe2",
+ NULL, 0, 0444, NULL,
+ &do_autoprobe },
+ { DEV_PARPORT_AUTOPROBE + 4, "autoprobe3",
+ NULL, 0, 0444, NULL,
+ &do_autoprobe },
+#endif /* IEEE 1284 support */
+ {0}
+ },
+ { {DEV_PARPORT_DEVICES_ACTIVE, "active", NULL, 0, 444, NULL,
+ &do_active_device }, {0}},
+ { PARPORT_PORT_DIR(NULL), {0}},
+ { PARPORT_PARPORT_DIR(NULL), {0}},
+ { PARPORT_DEV_DIR(NULL), {0}}
+};
+
+struct parport_device_sysctl_table
+{
+ struct ctl_table_header *sysctl_header;
+ ctl_table vars[2];
+ ctl_table device_dir[2];
+ ctl_table devices_root_dir[2];
+ ctl_table port_dir[2];
+ ctl_table parport_dir[2];
+ ctl_table dev_dir[2];
+};
+
+static const struct parport_device_sysctl_table
+parport_device_sysctl_template = {
+ NULL,
+ {
+ { DEV_PARPORT_DEVICE_TIMESLICE, "timeslice",
+ NULL, sizeof(int), 0644, NULL,
+ &proc_dointvec },
+ },
+ { {0, NULL, NULL, 0, 0555, NULL}, {0}},
+ { PARPORT_DEVICES_ROOT_DIR, {0}},
+ { PARPORT_PORT_DIR(NULL), {0}},
+ { PARPORT_PARPORT_DIR(NULL), {0}},
+ { PARPORT_DEV_DIR(NULL), {0}}
+};
+
+struct parport_default_sysctl_table
+{
+ struct ctl_table_header *sysctl_header;
+ ctl_table vars[3];
+ ctl_table default_dir[2];
+ ctl_table parport_dir[2];
+ ctl_table dev_dir[2];
+};
+
+extern unsigned long parport_default_timeslice;
+extern int parport_default_spintime;
+
+static struct parport_default_sysctl_table
+parport_default_sysctl_table = {
+ NULL,
+ {
+ { DEV_PARPORT_DEFAULT_TIMESLICE, "timeslice",
+ &parport_default_timeslice,
+ sizeof(parport_default_timeslice), 0644, NULL,
+ &proc_dointvec },
+ { DEV_PARPORT_DEFAULT_SPINTIME, "spintime",
+ &parport_default_spintime,
+ sizeof(parport_default_timeslice), 0644, NULL,
+ &proc_dointvec },
+ {0}
+ },
+ { { DEV_PARPORT_DEFAULT, "default", NULL, 0, 0555,
+ parport_default_sysctl_table.vars },{0}},
+ {
+ PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir),
+ {0}},
+ { PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir), {0}}
+};
+
+
+int parport_proc_register(struct parport *port)
+{
+ struct parport_sysctl_table *t;
+ int i;
+
+ t = kmalloc(sizeof(*t), GFP_KERNEL);
+ if (t == NULL)
+ return -ENOMEM;
+ memcpy(t, &parport_sysctl_template, sizeof(*t));
+
+ t->device_dir[0].extra1 = port;
+
+ for (i = 0; i < 8; i++)
+ t->vars[i].extra1 = port;
+
+ t->vars[0].data = &port->spintime;
+ t->vars[2].child = t->device_dir;
+
+ for (i = 0; i < 5; i++)
+ t->vars[3 + i].extra2 = &port->probe_info[i];
+
+ t->port_dir[0].procname = port->name;
+ t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
+
+ t->port_dir[0].child = t->vars;
+ t->parport_dir[0].child = t->port_dir;
+ t->dev_dir[0].child = t->parport_dir;
+
+ t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
+ if (t->sysctl_header == NULL) {
+ kfree(t);
+ t = NULL;
+ }
+ port->sysctl_table = t;
+ return 0;
+}
+
+int parport_proc_unregister(struct parport *port)
+{
+ if (port->sysctl_table) {
+ struct parport_sysctl_table *t = port->sysctl_table;
+ port->sysctl_table = NULL;
+ unregister_sysctl_table(t->sysctl_header);
+ kfree(t);
+ }
+ return 0;
+}
+
+int parport_device_proc_register(struct pardevice *device)
+{
+ struct parport_device_sysctl_table *t;
+ struct parport * port = device->port;
+
+ t = kmalloc(sizeof(*t), GFP_KERNEL);
+ if (t == NULL)
+ return -ENOMEM;
+ memcpy(t, &parport_device_sysctl_template, sizeof(*t));
+
+ t->dev_dir[0].child = t->parport_dir;
+ t->parport_dir[0].child = t->port_dir;
+ t->port_dir[0].procname = port->name;
+ t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
+ t->port_dir[0].child = t->devices_root_dir;
+ t->devices_root_dir[0].child = t->device_dir;
+
+#ifdef CONFIG_PARPORT_1284
+
+ t->device_dir[0].ctl_name =
+ parport_device_num(port->number, port->muxport,
+ device->daisy)
+ + 1; /* nb 0 isn't legal here */
+
+#else /* No IEEE 1284 support */
+
+ /* parport_device_num isn't available. */
+ t->device_dir[0].ctl_name = 1;
+
+#endif /* IEEE 1284 support or not */
+
+ t->device_dir[0].procname = device->name;
+ t->device_dir[0].extra1 = device;
+ t->device_dir[0].child = t->vars;
+ t->vars[0].data = &device->timeslice;
+
+ t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
+ if (t->sysctl_header == NULL) {
+ kfree(t);
+ t = NULL;
+ }
+ device->sysctl_table = t;
+ return 0;
+}
+
+int parport_device_proc_unregister(struct pardevice *device)
+{
+ if (device->sysctl_table) {
+ struct parport_device_sysctl_table *t = device->sysctl_table;
+ device->sysctl_table = NULL;
+ unregister_sysctl_table(t->sysctl_header);
+ kfree(t);
+ }
+ return 0;
+}
+
+int parport_default_proc_register(void)
+{
+ parport_default_sysctl_table.sysctl_header =
+ register_sysctl_table(parport_default_sysctl_table.dev_dir, 0);
+ return 0;
+}
+
+int parport_default_proc_unregister(void)
+{
+ if (parport_default_sysctl_table.sysctl_header) {
+ unregister_sysctl_table(parport_default_sysctl_table.
+ sysctl_header);
+ parport_default_sysctl_table.sysctl_header = NULL;
+ }
+ return 0;
+}
+
+#else /* no sysctl */
+
+int parport_proc_register(struct parport *pp)
+{
+ return 0;
+}
+
+int parport_proc_unregister(struct parport *pp)
+{
+ return 0;
+}
+
+int parport_device_proc_register(struct pardevice *device)
+{
+ return 0;
+}
+
+int parport_device_proc_unregister(struct pardevice *device)
+{
+ return 0;
+}
+
+int parport_default_proc_register (void)
+{
+ return 0;
+}
+
+int parport_default_proc_unregister (void)
+{
+ return 0;
+}
+#endif
--- /dev/null
+/* $Id: parport_share.c,v 1.15 1998/01/11 12:06:17 philip Exp $
+ * Parallel-port resource manager code.
+ *
+ * Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
+ * Tim Waugh <tim@cyberelk.demon.co.uk>
+ * Jose Renau <renau@acm.org>
+ * Philip Blundell <philb@gnu.org>
+ * Andrea Arcangeli
+ *
+ * based on work by Grant Guenther <grant@torque.net>
+ * and Philip Blundell
+ */
+
+#undef PARPORT_DEBUG_SHARING /* undef for production */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/threads.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+
+#include <asm/spinlock.h>
+#include <asm/irq.h>
+
+#undef PARPORT_PARANOID
+
+#define PARPORT_DEFAULT_TIMESLICE (HZ/5)
+
+unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE;
+int parport_default_spintime = DEFAULT_SPIN_TIME;
+
+static struct parport *portlist = NULL, *portlist_tail = NULL;
+spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;
+
+static struct parport_driver *driver_chain = NULL;
+spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED;
+
+static void call_driver_chain(int attach, struct parport *port)
+{
+ struct parport_driver *drv;
+
+ for (drv = driver_chain; drv; drv = drv->next) {
+ if (attach)
+ drv->attach (port);
+ else
+ drv->detach (port);
+ }
+}
+
+int parport_register_driver (struct parport_driver *drv)
+{
+ struct parport *port;
+
+ spin_lock (&driverlist_lock);
+ drv->next = driver_chain;
+ driver_chain = drv;
+ spin_unlock (&driverlist_lock);
+
+ for (port = portlist; port; port = port->next)
+ drv->attach (port);
+
+ return 0;
+}
+
+void parport_unregister_driver (struct parport_driver *arg)
+{
+ struct parport_driver *drv = driver_chain, *olddrv = NULL;
+
+ while (drv) {
+ if (drv == arg) {
+ spin_lock (&driverlist_lock);
+ if (olddrv)
+ olddrv->next = drv->next;
+ else
+ driver_chain = drv->next;
+ spin_unlock (&driverlist_lock);
+ return;
+ }
+ olddrv = drv;
+ drv = drv->next;
+ }
+}
+
+/* Return a list of all the ports we know about. */
+struct parport *parport_enumerate(void)
+{
+ return portlist;
+}
+
+struct parport *parport_register_port(unsigned long base, int irq, int dma,
+ struct parport_operations *ops)
+{
+ struct parport *tmp;
+ int portnum;
+ int device;
+ char *name;
+
+ tmp = kmalloc(sizeof(struct parport), GFP_KERNEL);
+ if (!tmp) {
+ printk(KERN_WARNING "parport: memory squeeze\n");
+ return NULL;
+ }
+
+ /* Search for the lowest free parport number. */
+ for (portnum = 0; ; portnum++) {
+ struct parport *itr = portlist;
+ while (itr) {
+ if (itr->number == portnum)
+ /* No good, already used. */
+ break;
+ else
+ itr = itr->next;
+ }
+
+ if (itr == NULL)
+ /* Got to the end of the list. */
+ break;
+ }
+
+ /* Init our structure */
+ memset(tmp, 0, sizeof(struct parport));
+ tmp->base = base;
+ tmp->irq = irq;
+ tmp->dma = dma;
+ tmp->muxport = tmp->daisy = tmp->muxsel = -1;
+ tmp->modes = 0;
+ tmp->next = NULL;
+ tmp->devices = tmp->cad = NULL;
+ tmp->flags = 0;
+ tmp->ops = ops;
+ tmp->portnum = tmp->number = portnum;
+ tmp->physport = tmp;
+ memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info));
+ tmp->cad_lock = RW_LOCK_UNLOCKED;
+ spin_lock_init(&tmp->waitlist_lock);
+ spin_lock_init(&tmp->pardevice_lock);
+ tmp->ieee1284.mode = IEEE1284_MODE_COMPAT;
+ tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+ init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */
+ tmp->spintime = parport_default_spintime;
+
+ name = kmalloc(15, GFP_KERNEL);
+ if (!name) {
+ printk(KERN_ERR "parport: memory squeeze\n");
+ kfree(tmp);
+ return NULL;
+ }
+ sprintf(name, "parport%d", portnum);
+ tmp->name = name;
+
+ /*
+ * Chain the entry to our list.
+ *
+ * This function must not run from an irq handler so we don' t need
+ * to clear irq on the local CPU. -arca
+ */
+ spin_lock(&parportlist_lock);
+ if (portlist_tail)
+ portlist_tail->next = tmp;
+ portlist_tail = tmp;
+ if (!portlist)
+ portlist = tmp;
+ spin_unlock(&parportlist_lock);
+
+ for (device = 0; device < 5; device++)
+ /* assume the worst */
+ tmp->probe_info[device].class = PARPORT_CLASS_LEGACY;
+
+ tmp->waithead = tmp->waittail = NULL;
+
+ return tmp;
+}
+
+void parport_announce_port (struct parport *port)
+{
+#ifdef CONFIG_PARPORT_1284
+ /* Analyse the IEEE1284.3 topology of the port. */
+ parport_daisy_init (port);
+#endif
+
+ /* Let drivers know that a new port has arrived. */
+ call_driver_chain (1, port);
+}
+
+void parport_unregister_port(struct parport *port)
+{
+ struct parport *p;
+ int d;
+
+ /* Spread the word. */
+ call_driver_chain (0, port);
+
+#ifdef CONFIG_PARPORT_1284
+ /* Forget the IEEE1284.3 topology of the port. */
+ parport_daisy_fini (port);
+#endif
+
+ spin_lock(&parportlist_lock);
+ if (portlist == port) {
+ if ((portlist = port->next) == NULL)
+ portlist_tail = NULL;
+ } else {
+ for (p = portlist; (p != NULL) && (p->next != port);
+ p=p->next);
+ if (p) {
+ if ((p->next = port->next) == NULL)
+ portlist_tail = p;
+ }
+ else printk (KERN_WARNING
+ "%s not found in port list!\n", port->name);
+ }
+ spin_unlock(&parportlist_lock);
+
+ for (d = 0; d < 5; d++) {
+ if (port->probe_info[d].class_name)
+ kfree (port->probe_info[d].class_name);
+ if (port->probe_info[d].mfr)
+ kfree (port->probe_info[d].mfr);
+ if (port->probe_info[d].model)
+ kfree (port->probe_info[d].model);
+ if (port->probe_info[d].cmdset)
+ kfree (port->probe_info[d].cmdset);
+ if (port->probe_info[d].description)
+ kfree (port->probe_info[d].description);
+ }
+
+ kfree(port->name);
+ kfree(port);
+}
+
+struct pardevice *parport_register_device(struct parport *port, const char *name,
+ int (*pf)(void *), void (*kf)(void *),
+ void (*irq_func)(int, void *, struct pt_regs *),
+ int flags, void *handle)
+{
+ struct pardevice *tmp;
+
+ if (port->physport->flags & PARPORT_FLAG_EXCL) {
+ /* An exclusive device is registered. */
+ printk (KERN_DEBUG "%s: no more devices allowed\n",
+ port->name);
+ return NULL;
+ }
+
+ if (flags & PARPORT_DEV_LURK) {
+ if (!pf || !kf) {
+ printk(KERN_INFO "%s: refused to register lurking device (%s) without callbacks\n", port->name, name);
+ return NULL;
+ }
+ }
+
+ tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL);
+ if (tmp == NULL) {
+ printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
+ return NULL;
+ }
+
+ tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL);
+ if (tmp->state == NULL) {
+ printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
+ kfree(tmp);
+ return NULL;
+ }
+
+ tmp->name = name;
+ tmp->port = port;
+ tmp->daisy = -1;
+ tmp->preempt = pf;
+ tmp->wakeup = kf;
+ tmp->private = handle;
+ tmp->flags = flags;
+ tmp->irq_func = irq_func;
+ tmp->waiting = 0;
+ tmp->timeout = 5 * HZ;
+
+ /* Chain this onto the list */
+ tmp->prev = NULL;
+ /*
+ * This function must not run from an irq handler so we don' t need
+ * to clear irq on the local CPU. -arca
+ */
+ spin_lock(&port->physport->pardevice_lock);
+
+ if (flags & PARPORT_DEV_EXCL) {
+ if (port->physport->devices) {
+ spin_unlock (&port->physport->pardevice_lock);
+ kfree (tmp->state);
+ kfree (tmp);
+ printk (KERN_DEBUG
+ "%s: cannot grant exclusive access for "
+ "device %s\n", port->name, name);
+ return NULL;
+ }
+ port->flags |= PARPORT_FLAG_EXCL;
+ }
+
+ tmp->next = port->physport->devices;
+ if (port->physport->devices)
+ port->physport->devices->prev = tmp;
+ port->physport->devices = tmp;
+ spin_unlock(&port->physport->pardevice_lock);
+
+ inc_parport_count();
+ port->ops->inc_use_count();
+
+ init_waitqueue_head(&tmp->wait_q);
+ tmp->timeslice = parport_default_timeslice;
+ tmp->waitnext = tmp->waitprev = NULL;
+
+ /*
+ * This has to be run as last thing since init_state may need other
+ * pardevice fields. -arca
+ */
+ port->ops->init_state(tmp, tmp->state);
+ parport_device_proc_register(tmp);
+ return tmp;
+}
+
+void parport_unregister_device(struct pardevice *dev)
+{
+ struct parport *port;
+
+#ifdef PARPORT_PARANOID
+ if (dev == NULL) {
+ printk(KERN_ERR "parport_unregister_device: passed NULL\n");
+ return;
+ }
+#endif
+
+ parport_device_proc_unregister(dev);
+
+ port = dev->port->physport;
+
+ if (port->cad == dev) {
+ printk(KERN_DEBUG "%s: %s forgot to release port\n",
+ port->name, dev->name);
+ parport_release (dev);
+ }
+
+ spin_lock(&port->pardevice_lock);
+ if (dev->next)
+ dev->next->prev = dev->prev;
+ if (dev->prev)
+ dev->prev->next = dev->next;
+ else
+ port->devices = dev->next;
+
+ if (dev->flags & PARPORT_DEV_EXCL)
+ port->flags &= ~PARPORT_FLAG_EXCL;
+
+ spin_unlock(&port->pardevice_lock);
+
+ kfree(dev->state);
+ kfree(dev);
+
+ dec_parport_count();
+ port->ops->dec_use_count();
+}
+
+int parport_claim(struct pardevice *dev)
+{
+ struct pardevice *oldcad;
+ struct parport *port = dev->port->physport;
+ unsigned long flags;
+
+ if (port->cad == dev) {
+ printk(KERN_INFO "%s: %s already owner\n",
+ dev->port->name,dev->name);
+ return 0;
+ }
+
+try_again:
+ /* Preempt any current device */
+ if ((oldcad = port->cad) != NULL) {
+ if (oldcad->preempt) {
+ if (oldcad->preempt(oldcad->private))
+ goto blocked;
+ port->ops->save_state(port, dev->state);
+ } else
+ goto blocked;
+
+ if (port->cad != oldcad) {
+ printk(KERN_WARNING
+ "%s: %s released port when preempted!\n",
+ port->name, oldcad->name);
+ if (port->cad)
+ goto blocked;
+ }
+ }
+
+ /* Can't fail from now on, so mark ourselves as no longer waiting. */
+ if (dev->waiting & 1) {
+ dev->waiting = 0;
+
+ /* Take ourselves out of the wait list again. */
+ spin_lock_irqsave (&port->waitlist_lock, flags);
+ if (dev->waitprev)
+ dev->waitprev->waitnext = dev->waitnext;
+ else
+ port->waithead = dev->waitnext;
+ if (dev->waitnext)
+ dev->waitnext->waitprev = dev->waitprev;
+ else
+ port->waittail = dev->waitprev;
+ spin_unlock_irqrestore (&port->waitlist_lock, flags);
+ dev->waitprev = dev->waitnext = NULL;
+ }
+
+ /* Now we do the change of devices */
+ write_lock_irqsave(&port->cad_lock, flags);
+ port->cad = dev;
+ write_unlock_irqrestore(&port->cad_lock, flags);
+
+#ifdef CONFIG_PARPORT_1284
+ /* If it's a mux port, select it. */
+ if (dev->port->muxport >= 0) {
+ /* FIXME */
+ port->muxsel = dev->port->muxport;
+ }
+
+ /* If it's a daisy chain device, select it. */
+ if (dev->daisy >= 0) {
+ /* This could be lazier. */
+ if (!parport_daisy_select (port, dev->daisy,
+ IEEE1284_MODE_COMPAT))
+ port->daisy = dev->daisy;
+ }
+#endif /* IEEE1284.3 support */
+
+ /* Restore control registers */
+ port->ops->restore_state(port, dev->state);
+ dev->time = jiffies;
+ return 0;
+
+blocked:
+ /* If this is the first time we tried to claim the port, register an
+ interest. This is only allowed for devices sleeping in
+ parport_claim_or_block(), or those with a wakeup function. */
+ if (dev->waiting & 2 || dev->wakeup) {
+ spin_lock_irqsave (&port->waitlist_lock, flags);
+ if (port->cad == NULL) {
+ /* The port got released in the meantime. */
+ spin_unlock_irqrestore (&port->waitlist_lock, flags);
+ goto try_again;
+ }
+ if (test_and_set_bit(0, &dev->waiting) == 0) {
+ /* First add ourselves to the end of the wait list. */
+ dev->waitnext = NULL;
+ dev->waitprev = port->waittail;
+ if (port->waittail) {
+ port->waittail->waitnext = dev;
+ port->waittail = dev;
+ } else
+ port->waithead = port->waittail = dev;
+ }
+ spin_unlock_irqrestore (&port->waitlist_lock, flags);
+ }
+ return -EAGAIN;
+}
+
+int parport_claim_or_block(struct pardevice *dev)
+{
+ int r;
+
+ /* Signal to parport_claim() that we can wait even without a
+ wakeup function. */
+ dev->waiting = 2;
+
+ /* Try to claim the port. If this fails, we need to sleep. */
+ r = parport_claim(dev);
+ if (r == -EAGAIN) {
+ unsigned long flags;
+#ifdef PARPORT_DEBUG_SHARING
+ printk(KERN_DEBUG "%s: parport_claim() returned -EAGAIN\n", dev->name);
+#endif
+ save_flags (flags);
+ cli();
+ /* If dev->waiting is clear now, an interrupt
+ gave us the port and we would deadlock if we slept. */
+ if (dev->waiting) {
+ sleep_on(&dev->wait_q);
+ r = 1;
+ } else {
+ r = 0;
+#ifdef PARPORT_DEBUG_SHARING
+ printk(KERN_DEBUG "%s: didn't sleep in parport_claim_or_block()\n",
+ dev->name);
+#endif
+ }
+ restore_flags(flags);
+#ifdef PARPORT_DEBUG_SHARING
+ if (dev->port->physport->cad != dev)
+ printk(KERN_DEBUG "%s: exiting parport_claim_or_block "
+ "but %s owns port!\n", dev->name,
+ dev->port->physport->cad ?
+ dev->port->physport->cad->name:"nobody");
+#endif
+ }
+ dev->waiting = 0;
+ return r;
+}
+
+void parport_release(struct pardevice *dev)
+{
+ struct parport *port = dev->port->physport;
+ struct pardevice *pd;
+ unsigned long flags;
+
+ /* Make sure that dev is the current device */
+ if (port->cad != dev) {
+ printk(KERN_WARNING "%s: %s tried to release parport "
+ "when not owner\n", port->name, dev->name);
+ return;
+ }
+
+#ifdef CONFIG_PARPORT_1284
+ /* If this is on a mux port, deselect it. */
+ if (dev->port->muxport >= 0) {
+ /* FIXME */
+ port->muxsel = -1;
+ }
+
+ /* If this is a daisy device, deselect it. */
+ if (dev->daisy >= 0) {
+ parport_daisy_deselect_all (port);
+ port->daisy = -1;
+ }
+#endif
+
+ write_lock_irqsave(&port->cad_lock, flags);
+ port->cad = NULL;
+ write_unlock_irqrestore(&port->cad_lock, flags);
+
+ /* Save control registers */
+ port->ops->save_state(port, dev->state);
+
+ /* If anybody is waiting, find out who's been there longest and
+ then wake them up. (Note: no locking required) */
+ for (pd = port->waithead; pd; pd = pd->waitnext) {
+ if (pd->waiting & 2) { /* sleeping in claim_or_block */
+ parport_claim(pd);
+ if (waitqueue_active(&pd->wait_q))
+ wake_up(&pd->wait_q);
+ return;
+ } else if (pd->wakeup) {
+ pd->wakeup(pd->private);
+ if (dev->port->cad)
+ return;
+ } else {
+ printk(KERN_ERR "%s: don't know how to wake %s\n", port->name, pd->name);
+ }
+ }
+
+ /* Nobody was waiting, so walk the list to see if anyone is
+ interested in being woken up. */
+ for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) {
+ if (pd->wakeup && pd != dev)
+ pd->wakeup(pd->private);
+ }
+}
+
+static int parport_parse_params (int nports, const char *str[], int val[],
+ int automatic, int none)
+{
+ unsigned int i;
+ for (i = 0; i < nports && str[i]; i++) {
+ if (!strncmp(str[i], "auto", 4))
+ val[i] = automatic;
+ else if (!strncmp(str[i], "none", 4))
+ val[i] = none;
+ else {
+ char *ep;
+ unsigned long r = simple_strtoul(str[i], &ep, 0);
+ if (ep != str[i])
+ val[i] = r;
+ else {
+ printk("parport: bad specifier `%s'\n", str[i]);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int parport_parse_irqs(int nports, const char *irqstr[], int irqval[])
+{
+ return parport_parse_params (nports, irqstr, irqval, PARPORT_IRQ_AUTO,
+ PARPORT_IRQ_NONE);
+}
+
+int parport_parse_dmas(int nports, const char *dmastr[], int dmaval[])
+{
+ return parport_parse_params (nports, dmastr, dmaval, PARPORT_DMA_AUTO,
+ PARPORT_DMA_NONE);
+}
struct mm_struct * mm = p->mm;
if (mm) {
- struct vm_area_struct * vma = mm->mmap;
+ struct vm_area_struct * vma;
unsigned long data = 0, stack = 0;
unsigned long exec = 0, lib = 0;
+ down(&mm->mmap_sem);
for (vma = mm->mmap; vma; vma = vma->vm_next) {
unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
if (!vma->vm_file) {
continue;
lib += len;
}
- }
+ }
buffer += sprintf(buffer,
"VmSize:\t%8lu kB\n"
"VmLck:\t%8lu kB\n"
mm->rss << (PAGE_SHIFT-10),
data - stack, stack,
exec - lib, lib);
+ up(&mm->mmap_sem);
}
return buffer;
}
struct vm_area_struct * vma;
if (!p->mm)
goto out_unlock;
+ down(&p->mm->mmap_sem);
vma = p->mm->mmap;
while (vma) {
if ((vma->vm_flags & VM_EXECUTABLE) &&
vma->vm_file) {
result = vma->vm_file->f_dentry;
+ up(&p->mm->mmap_sem);
goto out_dget;
}
vma = vma->vm_next;
}
+ up(&p->mm->mmap_sem);
goto out_unlock;
}
default:
* potential and subtle race discovered by Ulrich Schmid
* in down_interruptible(). Since I started to play here I
* also implemented the `trylock' semaphore operation.
+ * 1999-07-02 Artur Skawina <skawina@geocities.com>
+ * Optimized "0(ecx)" -> "(ecx)" (the assembler does not
+ * do this). Changed calling sequences from push/jmp to
+ * traditional call/ret.
*
* If you would like to see an analysis of this implementation, please
* ftp to gcom.com and download the file
#ifdef __SMP__
"lock ; "
#endif
- "decl 0(%0)\n\t"
+ "decl (%0)\n\t" /* --sem->count */
"js 2f\n"
"1:\n"
".section .text.lock,\"ax\"\n"
- "2:\tpushl $1b\n\t"
- "jmp __down_failed\n"
+ "2:\tcall __down_failed\n\t"
+ "jmp 1b\n"
".previous"
:/* no outputs */
:"c" (sem)
#ifdef __SMP__
"lock ; "
#endif
- "decl 0(%1)\n\t"
+ "decl (%1)\n\t" /* --sem->count */
"js 2f\n\t"
"xorl %0,%0\n"
"1:\n"
".section .text.lock,\"ax\"\n"
- "2:\tpushl $1b\n\t"
- "jmp __down_failed_interruptible\n"
+ "2:\tcall __down_failed_interruptible\n\t"
+ "jmp 1b\n"
".previous"
:"=a" (result)
:"c" (sem)
#ifdef __SMP__
"lock ; "
#endif
- "decl 0(%1)\n\t"
+ "decl (%1)\n\t" /* --sem->count */
"js 2f\n\t"
"xorl %0,%0\n"
"1:\n"
".section .text.lock,\"ax\"\n"
- "2:\tpushl $1b\n\t"
- "jmp __down_failed_trylock\n"
+ "2:\tcall __down_failed_trylock\n\t"
+ "jmp 1b\n"
".previous"
:"=a" (result)
:"c" (sem)
#ifdef __SMP__
"lock ; "
#endif
- "incl 0(%0)\n\t"
+ "incl (%0)\n\t" /* ++sem->count */
"jle 2f\n"
"1:\n"
".section .text.lock,\"ax\"\n"
- "2:\tpushl $1b\n\t"
- "jmp __up_wakeup\n"
+ "2:\tcall __up_wakeup\n\t"
+ "jmp 1b\n"
".previous"
:/* no outputs */
:"c" (sem)
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */
+ /* 'z' support added 23/7/1999 S.H. */
+
for (str=buf ; *fmt ; ++fmt) {
if (*fmt != '%') {
*str++ = *fmt;
/* get the conversion qualifier */
qualifier = -1;
- if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='z') {
qualifier = *fmt;
++fmt;
}
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = (str - buf);
+ } else if (qualifier == 'z') {
+ size_t * ip = va_arg(args, size_t *);
+ *ip = (str - buf);
} else {
int * ip = va_arg(args, int *);
*ip = (str - buf);
}
if (qualifier == 'l')
num = va_arg(args, unsigned long);
+ else if (qualifier == 'z')
+ num = va_arg(args, size_t);
else if (qualifier == 'h') {
num = (unsigned short) va_arg(args, int);
if (flags & SIGN)