Uwe Klein (uwe.klein@flensburg.netsurf.de)
Fri, 30 Oct 1998 00:31:37 +0100
Hi,
thanks for your kind reply.
i've got basic knowledge about PC's ISA and PCI, but i am based in 68K
stuff, having done VME Boards in MVME167 Systems running Motorola
SysVr3/4 and embedded Systems with my own brand of RT System.
1MB ok: i get about 800k outbound.
inbound i get about 1.6Mb witch seem to be the "unbraked" transfer rate
of the chips. the IF side is handshaking wildly, but no bytes in the
fifo (dcr:0xe0,ecr:0x79),
I've joined this list day before yesterday, how do i access any
archive??
method: the fifo remains stubornly empty.
the dir bit was set
rev: set mode bidi, set dir bit, negotiate to ecp, set mode ecp;
forw: set mode bidi, neg to forw, clr dir bit, set mode ecp;
iv'e attached my testfile, it looks terrible, ignore the german
comments.
Read and Write is a unified func, only dir is set appropriately?,
writing is async, threre is a lot of debug msg in it, iv'e used another
port for dbg sigs for my osz.
i'm heading for my mattress now
G!
UK
-- Uwe Klein [mailto:uwe.klein@flensburg.netsurf.de] KLEIN MESSGERAETE Habertwedt 1 D-24376 Groedersby b. Kappeln, GERMANY phone: +49 4642 920 123 FAX: +49 4642 920 125/* ACHTUNG dies ist lpp.c mit mittlerweilse grosszuegigen Aenderungen von lp.c uebernommen * Copyright (C) 1992 by Jim Weigand and Linus Torvalds * Copyright (C) 1992,1993 by Michael K. Johnson * - Thanks much to Gunter Windau for pointing out to me where the error * checking ought to be. * Copyright (C) 1993 by Nigel Gamble (added interrupt code) * Copyright (C) 1994 by Alan Cox (Modularised it) * Copyright (C) 1998 by Uwe Klein Habertwedt * LPCAREFUL, LPABORT, LPGETSTATUS added by Chris Metcalf, metcalf@lcs.mit.edu * Statistics and support for slow printers by Rob Janssen, rob@knoware.nl * "lp=" command line parameters added by Grant Guenther, grant@torque.net * und nun endlose aenderungen um die DMA zum lesen zu bewegen:!! */
#include <linux/module.h>
#include <linux/errno.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/sched.h> #include <linux/malloc.h> #include <linux/ioport.h> #include <linux/fcntl.h> #include <linux/delay.h>
#include <asm/io.h> #include <asm/dma.h> #include <asm/segment.h> #include <asm/system.h> #include <linux/parport.h> #include <linux/lpp.h>
/* the BIOS manuals say there can be up to 4 lpt devices * but I have not seen a board where the 4th address is listed * if you have different hardware change the table below * please let me know if you have different equipment * if you have more than 3 printers, remember to increase LP_NO */ struct lp_struct lp_table[] = { {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0}}, {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0}}, {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0}} }; #define LP_NO 3 #define LP_DEBUG1
/* Device name */ static char *dev_name = "lpp";
static int lpp_actmode[] = { M_SPP, M_SPP , M_SPP } ; static int lpp_intcount = 0; static int lpp_dmacount = 0;
/* Test if printer is ready (and optionally has no error conditions) */ #define LP_READY(minor, status) \ ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : (status & LP_PBUSY)) #define LP_CAREFUL_READY(minor, status) \ ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : 1) #define _LP_CAREFUL_READY(status) \ (status & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \ (LP_PBUSY|LP_PSELECD|LP_PERRORP)
/* * All my debugging code assumes that you debug with only one printer at * a time. RWWH * Debug info moved into stats area, so this is no longer true (Rob Janssen) */
#undef LP_DEBUG
static int lp_reset(int minor) { w_ctr(minor, LP_PSELECP); udelay(LP_DELAY); w_ctr(minor, LP_PSELECP | LP_PINITP); lpp_actmode[minor] = M_SPP ; return r_str(minor); }
static int lp_dir( int minor, int mode ) { if ( mode == ( lpp_actmode[minor] ) ) { return 0; } else if ( mode == ( lpp_actmode[minor] ^ 1 ) ) { /* mode=001(ps2), no serv int, no dma, no error int */ w_ecr( minor, ( r_ecr(minor) & ~0xe8 ) | 0x34 ); if ( mode & 1 ) { udelay(5); w_ctr(minor, r_ctr(minor) | LP_PDIR ); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 1 */ udelay(5); /* mode=011(ecp) */ w_ecr( minor, r_ecr(minor) | 0x40 ); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 1 */ udelay(5); w_ctr(minor, r_ctr(minor) & ~LP_PAUTOLF ); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 1 */ udelay(5); w_ctr(minor, r_ctr(minor) & ~LP_PINITP ); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 1 */ udelay(5); lpp_actmode[minor] += 1 ; w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 1 */ } else { w_ctr(minor, r_ctr(minor) | LP_PINITP ); udelay(5); w_ctr(minor, r_ctr(minor) | LP_PAUTOLF ); udelay(5); w_ctr(minor, r_ctr(minor) & ~LP_PDIR ); udelay(5); /* mode=011(ecp) */ w_ecr( minor, r_ecr(minor) | 0x40 ); udelay(5); lpp_actmode[minor] -= 1 ; } printk(KERN_INFO "lpp%d lp_dir:ok act: %x mode: %x ecr(%x) ctr(%x)\n", minor, lpp_actmode[minor], mode, r_ecr(minor), r_ctr(minor)); return 0 ; } else printk(KERN_INFO "lpp%d lp_dir:err act: %x mode: %x ecr(%x) ctr(%x)\n", minor, lpp_actmode[minor], mode, r_ecr(minor), r_ctr(minor)); return -1 ; }
static int lp_neg2(int minor, int mode) { int ecrstat ; int ecrmode ;
printk(KERN_INFO "lpp%d lp_neg2: act: %x mode: %x ecr(%x) \n", minor, lpp_actmode[minor], mode, r_ecr(minor));
/* same procedure as .. */ if ( mode == lpp_actmode[minor] ) return 0 ;
ecrstat = r_ecr(minor) & 0x03; /* change to mode 001 */ w_ecr( minor, ( ecrstat & ~0xe0) | 0x20 | 0x010 | 0x00 | 0x04 ); /* isa bidi , noerrorint, nodma, noserviceint */
if ( mode == ( lpp_actmode[minor] ^ 1 ) ) { lp_dir(minor, mode ); } else { if ( lpp_actmode[minor] & 1 ) lp_dir( minor, lpp_actmode[minor] & ~1); switch ( lpp_actmode[minor] ) { case M_SPP : w_dtr(minor, 0x010); /* extensibility Byte */ w_ctr(minor, r_ctr(minor) & ~LP_PSELECP); udelay(5); w_ctr(minor, r_ctr(minor) | LP_PAUTOLF); udelay(5); w_ctr(minor, r_ctr(minor) | LP_PSTROBE); udelay(5); w_ctr(minor, r_ctr(minor) & ~LP_PSTROBE); udelay(5); w_ctr(minor, r_ctr(minor) & ~LP_PAUTOLF);
ecrstat |= 0x0e0 | 0x010 | 0x00 | 0x04 ; /* ecp, noerrorint, nodma, noserviceint */ printk(KERN_INFO "lpp%d neg2ecp: mode %x ecr(%x) \n", minor, mode, r_ecr(minor)); lpp_actmode[minor] = M_ECP ; break ; case M_ECP : ecrstat |= 0x020 | 0x010 | 0x00 | 0x04 ; /* isa bidi , noerrorint, nodma, noserviceint */ printk(KERN_INFO "lpp%d neg2spp: mode %x ecr(%x) %x \n", minor, mode, r_ecr(minor), lpp_actmode[minor]); w_ctr(minor, r_ctr(minor) | LP_PSELECP); lpp_actmode[minor] = M_SPP ; break ; } } w_ecr( minor, ecrstat ); if ( mode & 1 ) lp_dir(minor, mode ); printk(KERN_INFO "lpp%d neg2end mode %x ecr(%x) ctr(%x)\n", minor, mode, r_ecr(minor), r_ctr(minor)); return 0 ; }
/* this function takes over from rd or wr sets up dma, dir and gives it a push */
static inline int lp_dma_interrupt(char *lpchar, int dir ,int max_cnt, int minor ) { struct lp_struct *lp = &lp_table[minor]; int dma = LP_DMA(minor); int ecrstat ; int residue = 0; #ifdef LP_DEBUG1 printk(KERN_INFO "lpp%d dmaint : %d ok count: %d res: %d\n", minor, dma , max_cnt,get_dma_residue( dma ) ); #endif cli(); if ( ( residue = get_dma_residue( dma ) )) { #ifdef LP_DEBUG1 printk(KERN_INFO "lpp%d remain: %d busy??\n", minor, residue ); #endif current->timeout = jiffies + LP_TIMEOUT_INTERRUPT; interruptible_sleep_on(&lp->lp_wait_q); if ( current->timeout == 0 ) { printk(KERN_INFO "lpp%d timeout: %ld ??\n", minor, current->timeout ); return ( 0 ); /* zurueck hier geht nichts */ }
} sti(); w_ctr(0,r_ctr(0) | LP_PSTROBE ); /* 0 */ disable_dma(dma); clear_dma_ff( dma ); set_dma_mode( dma, ( ( dir ) ? DMA_MODE_READ : DMA_MODE_WRITE ) ); set_dma_addr( dma, (int) lpchar ); set_dma_count( dma, max_cnt );
udelay(5); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 1 */ udelay(5); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 1a */
lp_dir( minor, M_ECP | dir ); /* negotiate mode & forw/rev */
udelay(5); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 2 */ udelay(5); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 3 */ { /* int i; for ( i=0; (i<10) ; i++ ) lpchar[i]= ( '0' + i ) ; */ int i; for ( i=0; (i<max_cnt, 0) ; i++ ) w_fifo( minor, i ) ; }
ecrstat = r_ecr(minor ) ; ecrstat |= 0x08 | 0x010; /* en dma no error int */ udelay(15); w_ecr(minor,ecrstat); /* enable int & dma */ udelay(15); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 4 */ udelay(15); ecrstat &= ~0x04 ; /* en service int */
printk(KERN_INFO "lpp%d dma: starteda: %d ecr(%x) ctr(%x)\n", minor, get_dma_residue( dma ) , r_ecr(minor ), r_ctr(minor)); { int i; for ( i=16; (i<24 , 0 ) ; i++ ) lpchar[i]= r_fifo(minor) ; }
udelay(15); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 5 */ udelay(5); w_ecr(minor,ecrstat); /* enable int & dma */ udelay(5); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 6 */ udelay(15); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 7 */ udelay(15); enable_dma(dma); udelay(15); w_ctr(0,r_ctr(0) ^ LP_PSTROBE ); /* 8 */ udelay(15); w_ctr(0,r_ctr(0) | LP_PSTROBE ); /* 9 */ { /* int i; for ( i=0; (i<10) ; i++ ) lpchar[i]= ( '0' + i ) ; */ int i; int ecrret; for ( i=0; (i<max_cnt) ; i++ ) { w_fifo( minor, i ) ; } ecrret = r_ecr(minor); printk(KERN_INFO "lpp%d dma: ecrret: %x startedx: %d ecr(%x) ctr(%x)\n", minor, ecrret, get_dma_residue( dma ) , r_ecr(minor ), r_ctr(minor)); }
/* und los, zum User zurueck, damit er schon mal weiterrechnen kann */ if ( ! dir ) { printk(KERN_INFO "lpp%d write: started: %d busy?? %x \n", minor, get_dma_residue( dma ) , r_ecr(minor )); return ( max_cnt ); } printk(KERN_INFO "lpp%d read: started: %d busy?? %x \n", minor, get_dma_residue( dma ) , r_ecr(minor )); /* oder wenn lesen erstmal abwarten */
cli(); if ( ( residue = get_dma_residue( dma ) )) { printk(KERN_INFO "lpp%d read: remain: %d busy?? %x \n", minor, get_dma_residue( dma ) , r_ecr(minor )); #ifdef LP_DEBUG1 #endif current->timeout = jiffies + LP_TIMEOUT_INTERRUPT; interruptible_sleep_on(&lp->lp_wait_q); if ( current->timeout == 0 ) { printk(KERN_INFO "lpp%d timeout0: ecr(%x) remain: %d \n", minor, r_ecr(minor ), get_dma_residue( dma )); printk(KERN_INFO "lpp%d timeout1: ecr(%x) remain: %d \n", minor, r_ecr(minor ), get_dma_residue( dma )); printk(KERN_INFO "lpp%d timeout2: ecr(%x) remain: %d \n", minor, r_ecr(minor ), get_dma_residue( dma )); printk(KERN_INFO "lpp%d timeout3: ecr(%x) remain: %d \n", minor, r_ecr(minor ), get_dma_residue( dma )); printk(KERN_INFO "lpp%d timeout4: ecr(%x) remain: %d \n", minor, r_ecr(minor ), get_dma_residue( dma )); return ( 0 ); /* zurueck hier geht nichts */ }
} sti();
return ( max_cnt ); }
/* this is the actual irq handler function */
static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct parport *pb = (struct parport *) dev_id; struct ppd *pd = pb->cad; struct lp_struct *lp_dev = (struct lp_struct *) pd->private; lpp_intcount ++; printk(KERN_INFO "lpp irq: %d dma: %d residue: %d ecp(%x)\n", lpp_intcount, lpp_dmacount,get_dma_residue(lp_dev->dev->bus->dma),inb(lp_dev->dev->bus->base + 0x402) ); /* if ( lpp_intcount == lpp_dmacount ) parport_release(lp_dev->dev); */ printk(KERN_INFO "lpp irq: vorbei \n" ); if (lp_dev->lp_wait_q) wake_up(&lp_dev->lp_wait_q); }
static inline int lp_read_dma(unsigned int minor, char *buf, int count) { unsigned long copy_size; unsigned long total_bytes_read = 0; unsigned long bytes_read; struct lp_struct *lp = &lp_table[minor]; unsigned char status;
if (minor >= LP_NO) return -ENXIO; if (lp_table[minor].dev == NULL) return -ENXIO;
do { int blk_rd = 0; bytes_read = 0; copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
while (copy_size) { printk(KERN_INFO "lpp top: cnt: %ld cpz: %ld done: %d \n", count, copy_size, bytes_read ); if ( (blk_rd = lp_dma_interrupt(&lp->lp_buffer[bytes_read], 1, copy_size, minor)) ) { copy_size -= blk_rd; bytes_read += blk_rd; lp_table[minor].runchars += blk_rd; if ( count > LP_BUFFER_SIZE ) lpp_dmacount++;
} else { int rc = total_bytes_read + bytes_read;
printk(KERN_INFO "lpp top: else: %ld cpz: %ld done: %d \n", count, copy_size, bytes_read ); blk_rd = copy_size ; copy_size -= blk_rd; bytes_read += blk_rd; lp_table[minor].runchars += blk_rd; if ( count > LP_BUFFER_SIZE ) lpp_dmacount++; /* return -EIO; */ } } total_bytes_read += bytes_read; memcpy_tofs( buf, lp->lp_buffer, bytes_read); buf += bytes_read; count -= bytes_read;
} while (count > 0);
return total_bytes_read; }
static inline int lp_write_dma(unsigned int minor, const char *buf, int count) { unsigned long copy_size; unsigned long total_bytes_written = 0; unsigned long bytes_written; struct lp_struct *lp = &lp_table[minor]; unsigned char status;
if (minor >= LP_NO) return -ENXIO; if (lp_table[minor].dev == NULL) return -ENXIO;
do { int blk_wr = 0; bytes_written = 0; copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE); memcpy_fromfs(lp->lp_buffer, buf, copy_size);
while (copy_size) { if ( (blk_wr = lp_dma_interrupt(&lp->lp_buffer[bytes_written], 0, copy_size, minor)) ) { copy_size -= blk_wr; bytes_written += blk_wr; lp_table[minor].runchars += blk_wr; if ( count > LP_BUFFER_SIZE ) lpp_dmacount++; } else { int rc = total_bytes_written + bytes_written; if (lp_table[minor].runchars > LP_STAT(minor).maxrun) LP_STAT(minor).maxrun = lp_table[minor].runchars; status = r_str(minor); if ((status & LP_POUTPA)) { printk(KERN_INFO "lpp%d out of paper\n", minor); if (LP_F(minor) & LP_ABORT) return rc ? rc : -ENOSPC; } else if (!(status & LP_PSELECD)) { printk(KERN_INFO "lpp%d off-line\n", minor); if (LP_F(minor) & LP_ABORT) return rc ? rc : -EIO; } else if (!(status & LP_PERRORP)) { printk(KERN_ERR "lpp%d printer error\n", minor); if (LP_F(minor) & LP_ABORT) return rc ? rc : -EIO; } LP_STAT(minor).sleeps++; cli(); w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN); status = r_str(minor); if ((!(status & LP_PACK) || (status & LP_PBUSY)) && LP_CAREFUL_READY(minor, status)) { w_ctr(minor, LP_PSELECP | LP_PINITP); sti(); continue; } lp_table[minor].runchars = 0; current->timeout = jiffies + LP_TIMEOUT_INTERRUPT; interruptible_sleep_on(&lp->lp_wait_q); w_ctr(minor, LP_PSELECP | LP_PINITP); sti(); if (current->signal & ~current->blocked) { if (total_bytes_written + bytes_written) return total_bytes_written + bytes_written; else return -EINTR; } } }
total_bytes_written += bytes_written; buf += bytes_written; count -= bytes_written;
} while (count > 0);
return total_bytes_written; }
static int lp_read(struct inode * inode, struct file * file, char * buf, int count) { unsigned int minor = MINOR(inode->i_rdev); int retv;
if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) lp_table[minor].runchars = 0;
lp_table[minor].lastcall = jiffies;
/* Claim Parport or sleep until it becomes available * (see lp_wakeup() for details) */ printk(KERN_INFO "lpp read:irq: %d dma: %d \n", lpp_intcount, lpp_dmacount); cli(); if ( lpp_intcount == lpp_dmacount++) { sti(); /* if ( parport_claim(lp_table[minor].dev)) { sleep_on(&lp_table[minor].lp_wait_q); lp_table[minor].lp_wait_q = NULL; } */ } sti();
if (LP_IRQ(minor) > 0) { retv = lp_read_dma(minor, buf, count); #ifdef LP_DEBUG2 printk(KERN_INFO "lpp%d read intr: ret %d counts %d intr: %d fifo: %d flow: %d\n", minor, retv, count,lpp_intcount,fifo_ovfl,-flow); #endif } else { retv = -1; } return retv; }
static int lp_write(struct inode * inode, struct file * file, const char * buf, int count) { unsigned int minor = MINOR(inode->i_rdev); int retv;
if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) lp_table[minor].runchars = 0;
lp_table[minor].lastcall = jiffies;
/* Claim Parport or sleep until it becomes available * (see lp_wakeup() for details) */ printk(KERN_INFO "lpp write:irq: %d dma: %d \n", lpp_intcount, lpp_dmacount); cli(); if ( lpp_intcount == lpp_dmacount++) { sti(); /* if ( parport_claim(lp_table[minor].dev)) { sleep_on(&lp_table[minor].lp_wait_q); lp_table[minor].lp_wait_q = NULL; } */ } sti();
if (LP_IRQ(minor) > 0) { retv = lp_write_dma(minor, buf, count); #ifdef LP_DEBUG2 printk(KERN_INFO "lpp%d write intr: ret %d counts %d intr: %d fifo: %d flow: %d\n", minor, retv, count,lpp_intcount,fifo_ovfl,-flow); #endif } else { retv = -1 ; } return retv; }
static int lp_lseek(struct inode * inode, struct file * file, off_t offset, int origin) { return -ESPIPE; }
static int lp_open(struct inode * inode, struct file * file) { unsigned int minor = MINOR(inode->i_rdev);
if (minor >= LP_NO) return -ENXIO; if ((LP_F(minor) & LP_EXIST) == 0) return -ENXIO; if (LP_F(minor) & LP_BUSY) return -EBUSY; request_region(lp_table[minor].dev->bus->base,3,"lpp(std)"); request_region(lp_table[minor].dev->bus->base+0x400,3,"lpp(ecp)"); MOD_INC_USE_COUNT;
/* If ABORTOPEN is set and the printer is offline or out of paper, we may still want to open it to perform ioctl()s. Therefore we have commandeered O_NONBLOCK, even though it is being used in a non-standard manner. This is strictly a Linux hack, and should most likely only ever be used by the tunelp application. */ if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) { int status = r_str(minor); if (status & LP_POUTPA) { printk(KERN_INFO "lpp%d out of paper\n", minor); MOD_DEC_USE_COUNT; return -ENOSPC; } else if (!(status & LP_PSELECD)) { printk(KERN_INFO "lpp%d off-line\n", minor); MOD_DEC_USE_COUNT; return -EIO; } else if (!(status & LP_PERRORP)) { printk(KERN_ERR "lpp%d printer error\n", minor); MOD_DEC_USE_COUNT; return -EIO; } } if (LP_IRQ(minor) > 0) { printk(KERN_INFO "lpp%d open: kmalloc +\n", minor); lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE + 20, GFP_KERNEL | GFP_DMA ); printk(KERN_INFO "lpp%d open: kmalloc -\n", minor); if (!lp_table[minor].lp_buffer) { MOD_DEC_USE_COUNT; return -ENOMEM; } } LP_F(minor) |= LP_BUSY;
if ( parport_claim(lp_table[minor].dev)) { sleep_on(&lp_table[minor].lp_wait_q); lp_table[minor].lp_wait_q = NULL; } lpp_dmacount = lpp_intcount; { int ecrstat = r_ecr(minor ); ecrstat &= 0x03; /* fifo stats erhalten */ ecrstat |= 0x020 | 0x010 | 0x00 | 0x04 ; /* isa bidi , noerrorint, nodma, noserviceint */ w_ecr(minor,ecrstat); ecrstat = r_ecr(minor ); lp_reset(minor); printk(KERN_INFO "lpp%d open: ecr1 %x (%x) \n", minor,lpp_actmode[minor],ecrstat); } if (LP_DMA(minor) > 0) { cli(); disable_dma( LP_DMA( minor ) ); set_dma_count( LP_DMA(minor), 0 ); sti(); } lp_neg2( minor, M_ECP ); /* change mode to ECP */ return 0; }
static void lp_release(struct inode *inode, struct file *file) { unsigned int minor = MINOR(inode->i_rdev); unsigned int irq = LP_IRQ(minor); unsigned int dma = LP_DMA(minor); int ecrstat = 0; int residue = 0;
if ( dma ) { cli(); if ( ( residue = get_dma_residue( dma ) )) { #ifdef LP_DEBUG1 printk(KERN_INFO "lpp%d close: %d busy??\n", minor, residue ); #endif current->timeout = jiffies + LP_TIMEOUT_INTERRUPT; interruptible_sleep_on(&lp_table[minor].lp_wait_q); if ( ( current->timeout == 0 ) && ( residue == get_dma_residue( dma ) ) ) printk(KERN_INFO "lpp%d close: %d frozen??\n", minor, get_dma_residue ( dma ) ); } cli(); disable_dma( dma ); set_dma_count( dma, 0 ); sti(); } if ( irq ) { lp_neg2( minor, M_SPP );
ecrstat = r_ecr(minor ); kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE); lp_table[minor].lp_buffer = NULL; } parport_release(lp_table[minor].dev); printk(KERN_INFO "lpp%d release: ecr1 %x (%x) \n", minor,lpp_actmode[minor],ecrstat); LP_F(minor) &= ~LP_BUSY; release_region(lp_table[minor].dev->bus->base,3); release_region(lp_table[minor].dev->bus->base+0x400,3); MOD_DEC_USE_COUNT; }
static int lp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { unsigned int minor = MINOR(inode->i_rdev); int retval = 0;
#ifdef LP_DEBUG printk(KERN_DEBUG "lpp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg); #endif if (minor >= LP_NO) return -ENODEV; if ((LP_F(minor) & LP_EXIST) == 0) return -ENODEV; switch ( cmd ) { case LPTIME: LP_TIME(minor) = arg * HZ/100; break; case LPCHAR: LP_CHAR(minor) = arg; break; case LPABORT: if (arg) LP_F(minor) |= LP_ABORT; else LP_F(minor) &= ~LP_ABORT; break; case LPABORTOPEN: if (arg) LP_F(minor) |= LP_ABORTOPEN; else LP_F(minor) &= ~LP_ABORTOPEN; break; case LPCAREFUL: if (arg) LP_F(minor) |= LP_CAREFUL; else LP_F(minor) &= ~LP_CAREFUL; break; case LPWAIT: LP_WAIT(minor) = arg; break; case LPSETIRQ: { int oldirq; int newirq = arg; struct lp_struct *lp = &lp_table[minor];
if (!suser()) return -EPERM;
oldirq = LP_IRQ(minor);
/* Allocate buffer now if we are going to need it */ if (!oldirq && newirq) { lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL); if (!lp->lp_buffer) return -ENOMEM; }
if (oldirq) { free_irq(oldirq, NULL); } if (newirq) { /* Install new irq */ if ((retval = request_irq(newirq, lp_interrupt, SA_INTERRUPT, "printer", NULL))) { if (oldirq) { /* restore old irq */ request_irq(oldirq, lp_interrupt, SA_INTERRUPT, "printer", NULL); } else { /* We don't need the buffer */ kfree_s(lp->lp_buffer, LP_BUFFER_SIZE); lp->lp_buffer = NULL; } return retval; } } if (oldirq && !newirq) { /* We don't need the buffer */ kfree_s(lp->lp_buffer, LP_BUFFER_SIZE); lp->lp_buffer = NULL; } LP_IRQ(minor) = newirq; lp_reset(minor); break; } case LPGETIRQ: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); if (retval) return retval; memcpy_tofs((int *) arg, &LP_IRQ(minor), sizeof(int)); break; case LPGETSTATUS: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); if (retval) return retval; else { int status = r_str(minor); memcpy_tofs((int *) arg, &status, sizeof(int)); } break; case LPRESET: lp_reset(minor); break; case LPGETSTATS: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct lp_stats)); if (retval) return retval; else { memcpy_tofs((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats)); if (suser()) memset(&LP_STAT(minor), 0, sizeof(struct lp_stats)); } break; case LPGETFLAGS: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); if (retval) return retval; else { int status = LP_F(minor); memcpy_tofs((int *) arg, &status, sizeof(int)); } break; default: retval = -EINVAL; } return retval; }
static struct file_operations lp_fops = { lp_lseek, lp_read, /* lp_read */ lp_write, NULL, /* lp_readdir */ NULL, /* lp_select */ lp_ioctl, NULL, /* lp_mmap */ lp_open, lp_release };
static int parport[LP_NO] = { -1, };
#ifdef MODULE #define lp_init init_module
#else
static int parport_ptr = 0;
void lpp_setup(char *str, int *ints) { /* Ugh. */ printk(KERN_INFO "lpp: str: %s ??\n",str); if (!strncmp(str, "parport", 7)) { int n = simple_strtoul(str+7, NULL, 10); if (parport_ptr < LP_NO) parport[parport_ptr++] = n; else printk(KERN_INFO "lpp: too many ports, %s ignored.\n", str); } else if (!strcmp(str, "auto")) { parport[0] = -3; } else { if (ints[0] == 0 || ints[1] == 0) { /* disable driver on "parport=" or "parport=0" */ parport[0] = -2; } else { printk(KERN_WARNING "warning: 'lpp=0x%x' is deprecated, ignored\n", ints[1]); } } }
#endif
int lp_wakeup(void *ref) { struct lp_struct *lp_dev = (struct lp_struct *) ref;
if (!lp_dev->lp_wait_q) return 1; /* Wake up whom? */
/* Claim the Parport */ if (parport_claim(lp_dev->dev)) return 1; /* Shouldn't happen */
wake_up(&lp_dev->lp_wait_q); return 0; }
static int inline lp_searchfor(int list[], int a) { int i; for (i = 0; i < LP_NO && list[i] != -1; i++) { if (list[i] == a) return 1; } return 0; }
int lp_init(void) { int count = 0; struct parport *pb; if (register_chrdev(LPP_MAJOR, "lpp", &lp_fops)) { printk("lpp: unable to get major %d\n", LPP_MAJOR); return -EIO; }
if (parport[0] == -2) return 0;
pb = parport_enumerate();
while (pb) { if (parport[0] == -1 || lp_searchfor(parport, count) || (parport[0] == -3 && pb->probe_info.class == PARPORT_CLASS_PRINTER)) { lp_table[count].dev = parport_register_device(pb, dev_name, NULL, lp_wakeup, lp_interrupt, PARPORT_DEV_TRAN, (void *) &lp_table[count]); lp_table[count].flags |= LP_EXIST; printk(KERN_INFO "lpp%d: using %s at 0x%x, ", count, pb->name, pb->base); if (pb->irq == -1) printk("polling.\n"); else printk("irq %d.\n", pb->irq); } if (++count == LP_NO) break; pb = pb->next; }
/* Successful specified devices increase count * Unsuccessful specified devices increase failed */ if (count) return 0; printk(KERN_INFO "lpp: driver loaded but no devices found\n"); return 1; }
#ifdef MODULE void cleanup_module(void) { int offset;
unregister_chrdev(LPP_MAJOR, "lpp"); for (offset = 0; offset < LP_NO; offset++) { if (lp_table[offset].dev == NULL) continue; parport_unregister_device(lp_table[offset].dev); } } #endif
-- To unsubscribe, send mail to: linux-parport-request@torque.net -- -- with the single word "unsubscribe" in the body of the message. --
This archive was generated by hypermail 2.0b3 on Wed 30 Dec 1998 - 10:18:42 EST