📄 cpia_pp.c
字号:
/* * cpia_pp CPiA Parallel Port driver * * Supports CPiA based parallel port Video Camera's. * * (C) Copyright 1999 Bas Huisman <bhuism@cs.utwente.nl> * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@securenym.net>, * (C) Copyright 1999-2000 Peter Pregler <Peter_Pregler@email.com> * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) *//* #define _CPIA_DEBUG_ 1 */ #undef CPIA_PARPORT_DMA#define CPIA_PARPORT_DMA 1 /* comment this out to remove ECP DMA support */#include <linux/config.h>#include <linux/version.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/parport.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/smp_lock.h>#include <linux/sched.h>#include <linux/pci.h>#include <asm/dma.h>#include <linux/parport_pc.h>#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3))#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif#else#include <linux/kmod.h>#endif#include "cpia.h"static int cpia_pp_open(void *privdata, int alt);static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata), void *cbdata);static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data);static int cpia_pp_streamStart(void *privdata);static int cpia_pp_streamStop(void *privdata);static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock);static int cpia_pp_close(void *privdata);static int cpia_pp_upload_mode(void *privdata);#define ABOUT "Parallel port driver for Vision CPiA based cameras"#define PACKET_LENGTH 8/* Magic numbers for defining port-device mappings */#define PPCPIA_PARPORT_UNSPEC -4#define PPCPIA_PARPORT_AUTO -3#define PPCPIA_PARPORT_OFF -2#define PPCPIA_PARPORT_NONE -1#ifdef MODULEstatic int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};static char *parport[PARPORT_MAX] = {NULL,};MODULE_AUTHOR("B. Huisman <bhuism@cs.utwente.nl> & Peter Pregler <Peter_Pregler@email.com>");MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras");#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10))MODULE_LICENSE("GPL");#endifMODULE_PARM(parport, "1-" __MODULE_STRING(PARPORT_MAX) "s");MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp.");#elsestatic int parport_nr[PARPORT_MAX] __initdata = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};static int parport_ptr = 0;#endif#define NIBBLE_UPLOAD 0x00#define ECP_UPLOAD 0x01struct pp_cam_entry { struct pardevice *pdev; struct parport *port;#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)) struct tq_struct cb_task;#else struct work_struct cb_task;#endif int open_count; wait_queue_head_t wq_stream; /* image state flags */ int image_ready; /* we got an interrupt */ int image_complete; /* we have seen 4 EOI */ int streaming; /* we are in streaming mode */ int stream_irq; int upload_mode; /* IEEE1284 mode used for uploads */};static struct cpia_camera_ops cpia_pp_ops = { cpia_pp_open, cpia_pp_registerCallback, cpia_pp_transferCmd, cpia_pp_streamStart, cpia_pp_streamStop, cpia_pp_streamRead, cpia_pp_close, CAM_TYPE_PP, cpia_pp_upload_mode, 1, THIS_MODULE};static LIST_HEAD(cam_list);static spinlock_t cam_list_lock_pp;/* FIXME */static void cpia_parport_enable_irq( struct parport *port ) { parport_enable_irq(port); mdelay(10); return;}static void cpia_parport_disable_irq( struct parport *port ) { parport_disable_irq(port); mdelay(10); return;}/**************************************************************************** * * Low level parport functions for nibble and ECP DMA uploads * ***************************************************************************//* Special CPiA PPC modes: These are invoked by using the 1284 Extensibilty * Link Flag during negotiation */ #define UPLOAD_FLAG 0x08#define NIBBLE_TRANSFER 0x01#define ECP_TRANSFER 0x03#define CPIA_UPLOAD_CHUNKSIZE 4096 /* for non-ECP hardware uploads *//* FIXME: what chunksize for non-DMA ECP hardware (PIO) ? */#define CPIA_FIFO_UPLOAD_CHUNKSIZE 4096 /* for ECP PIO hardware uploads *//* CPiA nonstandard "Nibble" mode (no nDataAvail signal after each byte). *//* The standard kernel parport_ieee1284_read_nibble() fails with the CPiA... */static size_t cpia_read_nibble (struct parport *port, void *buffer, size_t len, int flags){ /* adapted verbatim, with one change, from parport_ieee1284_read_nibble() in drivers/parport/ieee1284-ops.c, by Tim Waugh */ unsigned char *buf = buffer; int i; unsigned char byte = 0; len *= 2; /* in nibbles */ for (i=0; i < len; i++) { unsigned char nibble; /* The CPiA firmware suppresses the use of nDataAvail (nFault LO) * after every second nibble to signal that more * data is available. (the total number of Bytes that * should be sent is known; if too few are received, an error * will be recorded after a timeout). * This is incompatible with parport_ieee1284_read_nibble(), * which expects to find nFault LO after every second nibble. */ /* Solution: modify cpia_read_nibble to only check for * nDataAvail before the first nibble is sent. */ /* 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; DBG("%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? */ DBG("%s: Nibble timeout at event 9 (%d bytes)\n", port->name, i/2); parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); 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? */ DBG("%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;}/* CPiA nonstandard "Nibble Stream" mode (2 nibbles per cycle, instead of 1) * (See CPiA Data sheet p. 31) * * "Nibble Stream" mode used by CPiA for uploads to non-ECP ports is a * nonstandard variant of nibble mode which allows the same (mediocre) * data flow of 8 bits per cycle as software-enabled ECP by TRISTATE-capable * parallel ports, but works also for non-TRISTATE-capable ports. * (Standard nibble mode only send 4 bits per cycle) * */static size_t cpia_read_nibble_stream(struct parport *port, void *buffer, size_t len, int flags){ int i; unsigned char *buf = buffer; int endseen = 0; for (i=0; i < len; i++) { unsigned char nibble[2], byte = 0; int j; /* Image Data is complete when 4 consecutive EOI bytes (0xff) are seen */ if (endseen > 3 ) 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? */ DBG("%s: Nibble timeout at event 9 (%d bytes)\n", port->name, i/2); parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); break; } /* Read lower nibble */ nibble[0] = parport_read_status (port) >>3; /* 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? */ DBG("%s: Nibble timeout at event 11\n", port->name); break; } /* Read upper nibble */ nibble[1] = parport_read_status (port) >>3; /* reassemble the byte */ for (j = 0; j < 2 ; j++ ) { nibble[j] &= ~8; if ((nibble[j] & 0x10) == 0) nibble[j] |= 8; nibble[j] &= 0xf; } byte = (nibble[0] |(nibble[1] << 4)); *buf++ = byte; if(byte == EOI) endseen++; else endseen = 0; } return i;}#ifdef CPIA_PARPORT_DMA/* forward declarations for IEEE1284 ECP DMA read support */static int change_mode(struct parport *, int );static void frob_econtrol (struct parport *, unsigned char, unsigned char);/* DMA support here thanks to: Blaise Gassend <blaise@gassend.com> *//*ECP parport lowlevel IEEE1284 DMA read support: */#define ECR_PS2 01#define ECR_ECP 03/* this an adaptation of code from parport_pc_ecp_read_block_pio() and * parport_pc_fifo_write_block_dma() */static size_t cpia_ecp_read_block_dma (struct parport *port, void *bufv, size_t length, int flags){ int r = 0, endseen = 0; unsigned long dmaflag; size_t left = length; const struct parport_pc_private *priv = port->physport->private_data; dma_addr_t dma_addr, dma_handle = 0; size_t maxlen = 0x10000; /* max 64k per DMA transfer */ char *buf = bufv; unsigned long start = (unsigned long) buf; unsigned long end = (unsigned long) buf + length - 1; size_t count = length; if (length == 0) return 0; /* 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); port = port->physport; if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) { /* change to reverse-idle phase (must be in forward-idle) */ /* Event 38: Set nAutoFd low (also make sure nStrobe is high) */ parport_frob_control (port, PARPORT_CONTROL_STROBE |PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); parport_pc_data_reverse (port); /* Must be in PS2 mode */ udelay (5); /* Event 39: Set nInit low to initiate bus reversal */ parport_frob_control (port, PARPORT_CONTROL_INIT, 0); /* Event 40: Wait for nAckReverse (PError) to go low */ if ((r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0))){ printk (KERN_DEBUG "%s: PE timeout Event 40 (%d) " "in ecp_read_block_dma\n", port->name, r); return 0; } port->ieee1284.phase = IEEE1284_PH_REV_DATA; parport_frob_control (port, PARPORT_CONTROL_STROBE |PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); if (change_mode (port, ECR_ECP)) /* ECP FIFO */ printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name); /* the first byte must be collected manually */ /* Event 43: Wait for nAck to go low */ if( parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) { /* timed out while reading -- no data */ printk (KERN_DEBUG "DMA read timed out (initial byte)\n"); goto out_no_data; }#if 0 /* this is active in parport_pc_ecp_read_block_pio */ /* read byte */ *buf++ = inb (DATA (port)); left--;#endif /* Event 44: nAutoFd (HostAck) goes high to acknowledge */ parport_pc_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); #if 1 /* this is commented out in parport_pc_ecp_read_block_pio */ /* Event 45: Wait for nAck to go high */ if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK)) { /* timed out while waiting for peripheral to respond to ack */ printk (KERN_DEBUG "ECP DMA read timed out (waiting for nAck)\n"); /* keep hold of the byte we've got already */ goto out_no_data; }#endif } #if 0 /* active in parport_pc_ecp_read_block_pio */ /* Event 46: nAutoFd (HostAck) goes low to accept more data */ parport_pc_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);#endif if (!left) goto out_no_data; /* now do the DMA transfer (adapted from parport_pc_fifo_write_block_dma) */ if (end < MAX_DMA_ADDRESS) { /* If it would cross a 64k boundary, cap it at the end. */ if ((start ^ end) & ~0xffffUL) maxlen = 0x10000 - (start & 0xffff); dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length, PCI_DMA_FROMDEVICE); } else { /* above 16 MB we use a bounce buffer as ISA-DMA is not possible */ maxlen = PAGE_SIZE; /* sizeof(priv->dma_buf) */ dma_addr = priv->dma_handle; } DBG ("DMA buffer is ready\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -