📄 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 */ #include <linux/config.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/workqueue.h>#include <linux/smp_lock.h>#include <linux/sched.h>#include <linux/kmod.h>/* #define _CPIA_DEBUG_ define for verbose debug output */#include "cpia.h"static int cpia_pp_open(void *privdata);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);#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");MODULE_LICENSE("GPL");module_param_array(parport, charp, NULL, 0);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;#endifstruct pp_cam_entry { struct pardevice *pdev; struct parport *port; struct work_struct cb_task; 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;};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, 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;}/* Special CPiA PPC modes: These are invoked by using the 1284 Extensibility * Link Flag during negotiation */ #define UPLOAD_FLAG 0x08#define NIBBLE_TRANSFER 0x01#define ECP_TRANSFER 0x03#define PARPORT_CHUNK_SIZE PAGE_SIZE/**************************************************************************** * * CPiA-specific low-level parport functions for nibble 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 */ 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;}/**************************************************************************** * * EndTransferMode * ***************************************************************************/static void EndTransferMode(struct pp_cam_entry *cam){ parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);}/**************************************************************************** * * ForwardSetup * ***************************************************************************/static int ForwardSetup(struct pp_cam_entry *cam){ int retry; /* The CPiA uses ECP protocol for Downloads from the Host to the camera. * This will be software-emulated if ECP hardware is not present */ /* the usual camera maximum response time is 10ms, but after receiving * some commands, it needs up to 40ms. (Data Sheet p. 32)*/ for(retry = 0; retry < 4; ++retry) { if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) { break; } mdelay(10); } if(retry == 4) { DBG("Unable to negotiate IEEE1284 ECP Download mode\n"); return -1; } return 0;}/**************************************************************************** * * ReverseSetup * ***************************************************************************/static int ReverseSetup(struct pp_cam_entry *cam, int extensibility){ int retry; int upload_mode, mode = IEEE1284_MODE_ECP; int transfer_mode = ECP_TRANSFER; if (!(cam->port->modes & PARPORT_MODE_ECP) && !(cam->port->modes & PARPORT_MODE_TRISTATE)) { mode = IEEE1284_MODE_NIBBLE; transfer_mode = NIBBLE_TRANSFER; } upload_mode = mode; if(extensibility) mode = UPLOAD_FLAG|transfer_mode|IEEE1284_EXT_LINK; /* the usual camera maximum response time is 10ms, but after * receiving some commands, it needs up to 40ms. */ for(retry = 0; retry < 4; ++retry) { if(!parport_negotiate(cam->port, mode)) { break; } mdelay(10); } if(retry == 4) { if(extensibility) DBG("Unable to negotiate upload extensibility mode\n"); else DBG("Unable to negotiate upload mode\n"); return -1; } if(extensibility) cam->port->ieee1284.mode = upload_mode; return 0;}/**************************************************************************** * * WritePacket * ***************************************************************************/static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size){ int retval=0; int size_written; if (packet == NULL) { return -EINVAL; } if (ForwardSetup(cam)) { DBG("Write failed in setup\n"); return -EIO; } size_written = parport_write(cam->port, packet, size); if(size_written != size) { DBG("Write failed, wrote %d/%d\n", size_written, size); retval = -EIO; } EndTransferMode(cam); return retval;}/**************************************************************************** * * ReadPacket * ***************************************************************************/static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size){ int retval=0; if (packet == NULL) { return -EINVAL; } if (ReverseSetup(cam, 0)) { return -EIO; } /* support for CPiA variant nibble reads */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -