mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
[media] cpia, stradis: remove deprecated V4L1 drivers
Nobody stepped in to convert these drivers to V4L2, so they are now removed from the kernel. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
71bb2876a3
commit
39c3d48845
@ -1,191 +0,0 @@
|
|||||||
This is a driver for the CPiA PPC2 driven parallel connected
|
|
||||||
Camera. For example the Creative WebcamII is CPiA driven.
|
|
||||||
|
|
||||||
) [1]Peter Pregler, Linz 2000, published under the [2]GNU GPL
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
|
|
||||||
General:
|
|
||||||
========
|
|
||||||
|
|
||||||
1) Make sure you have created the video devices (/dev/video*):
|
|
||||||
|
|
||||||
- if you have a recent MAKEDEV do a 'cd /dev;./MAKEDEV video'
|
|
||||||
- otherwise do a:
|
|
||||||
|
|
||||||
cd /dev
|
|
||||||
mknod video0 c 81 0
|
|
||||||
ln -s video0 video
|
|
||||||
|
|
||||||
2) Compile the kernel (see below for the list of options to use),
|
|
||||||
configure your parport and reboot.
|
|
||||||
|
|
||||||
3) If all worked well you should get messages similar
|
|
||||||
to the following (your versions may be different) on the console:
|
|
||||||
|
|
||||||
V4L-Driver for Vision CPiA based cameras v0.7.4
|
|
||||||
parport0: read2 timeout.
|
|
||||||
parport0: Multimedia device, VLSI Vision Ltd PPC2
|
|
||||||
Parallel port driver for Vision CPiA based camera
|
|
||||||
CPIA Version: 1.20 (2.0)
|
|
||||||
CPIA PnP-ID: 0553:0002:0100
|
|
||||||
VP-Version: 1.0 0100
|
|
||||||
1 camera(s) found
|
|
||||||
|
|
||||||
|
|
||||||
As modules:
|
|
||||||
===========
|
|
||||||
|
|
||||||
Make sure you have selected the following kernel options (you can
|
|
||||||
select all stuff as modules):
|
|
||||||
|
|
||||||
The cpia-stuff is in the section 'Character devices -> Video For Linux'.
|
|
||||||
|
|
||||||
CONFIG_PARPORT=m
|
|
||||||
CONFIG_PARPORT_PC=m
|
|
||||||
CONFIG_PARPORT_PC_FIFO=y
|
|
||||||
CONFIG_PARPORT_1284=y
|
|
||||||
CONFIG_VIDEO_DEV=m
|
|
||||||
CONFIG_VIDEO_CPIA=m
|
|
||||||
CONFIG_VIDEO_CPIA_PP=m
|
|
||||||
|
|
||||||
For autoloading of all those modules you need to tell module-init-tools
|
|
||||||
some stuff. Add the following line to your module-init-tools config-file
|
|
||||||
(e.g. /etc/modprobe.conf or wherever your distribution does store that
|
|
||||||
stuff):
|
|
||||||
|
|
||||||
options parport_pc io=0x378 irq=7 dma=3
|
|
||||||
alias char-major-81 cpia_pp
|
|
||||||
|
|
||||||
The first line tells the dma/irq channels to use. Those _must_ match
|
|
||||||
the settings of your BIOS. Do NOT simply use the values above. See
|
|
||||||
Documentation/parport.txt for more information about this. The second
|
|
||||||
line associates the video-device file with the driver. Of cause you
|
|
||||||
can also load the modules once upon boot (usually done in /etc/modules).
|
|
||||||
|
|
||||||
Linked into the kernel:
|
|
||||||
=======================
|
|
||||||
|
|
||||||
Make sure you have selected the following kernel options. Note that
|
|
||||||
you cannot compile the parport-stuff as modules and the cpia-driver
|
|
||||||
statically (the other way round is okay though).
|
|
||||||
|
|
||||||
The cpia-stuff is in the section 'Character devices -> Video For Linux'.
|
|
||||||
|
|
||||||
CONFIG_PARPORT=y
|
|
||||||
CONFIG_PARPORT_PC=y
|
|
||||||
CONFIG_PARPORT_PC_FIFO=y
|
|
||||||
CONFIG_PARPORT_1284=y
|
|
||||||
CONFIG_VIDEO_DEV=y
|
|
||||||
CONFIG_VIDEO_CPIA=y
|
|
||||||
CONFIG_VIDEO_CPIA_PP=y
|
|
||||||
|
|
||||||
To use DMA/irq you will need to tell the kernel upon boot time the
|
|
||||||
hardware configuration of the parport. You can give the boot-parameter
|
|
||||||
at the LILO-prompt or specify it in lilo.conf. I use the following
|
|
||||||
append-line in lilo.conf:
|
|
||||||
|
|
||||||
append="parport=0x378,7,3"
|
|
||||||
|
|
||||||
See Documentation/parport.txt for more information about the
|
|
||||||
configuration of the parport and the values given above. Do not simply
|
|
||||||
use the values given above.
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
FEATURES:
|
|
||||||
|
|
||||||
- mmap/read v4l-interface (but no overlay)
|
|
||||||
- image formats: CIF/QCIF, SIF/QSIF, various others used by isabel;
|
|
||||||
note: all sizes except CIF/QCIF are implemented by clipping, i.e.
|
|
||||||
pixels are not uploaded from the camera
|
|
||||||
- palettes: VIDEO_PALETTE_GRAY, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB555,
|
|
||||||
VIDEO_PALETTE_RGB24, VIDEO_PALETTE_RGB32, VIDEO_PALETTE_YUYV,
|
|
||||||
VIDEO_PALETTE_UYVY, VIDEO_PALETTE_YUV422
|
|
||||||
- state information (color balance, exposure, ...) is preserved between
|
|
||||||
device opens
|
|
||||||
- complete control over camera via proc-interface (_all_ camera settings are
|
|
||||||
supported), there is also a python-gtk application available for this [3]
|
|
||||||
- works under SMP (but the driver is completely serialized and synchronous)
|
|
||||||
so you get no benefit from SMP, but at least it does not crash your box
|
|
||||||
- might work for non-Intel architecture, let us know about this
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
TESTED APPLICATIONS:
|
|
||||||
|
|
||||||
- a simple test application based on Xt is available at [3]
|
|
||||||
- another test-application based on gqcam-0.4 (uses GTK)
|
|
||||||
- gqcam-0.6 should work
|
|
||||||
- xawtv-3.x (also the webcam software)
|
|
||||||
- xawtv-2.46
|
|
||||||
- w3cam (cgi-interface and vidcat, e.g. you may try out 'vidcat |xv
|
|
||||||
-maxpect -root -quit +noresetroot -rmode 5 -')
|
|
||||||
- vic, the MBONE video conferencing tool (version 2.8ucl4-1)
|
|
||||||
- isabel 3R4beta (barely working, but AFAICT all the problems are on
|
|
||||||
their side)
|
|
||||||
- camserv-0.40
|
|
||||||
|
|
||||||
See [3] for pointers to v4l-applications.
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
KNOWN PROBLEMS:
|
|
||||||
|
|
||||||
- some applications do not handle the image format correctly, you will
|
|
||||||
see strange horizontal stripes instead of a nice picture -> make sure
|
|
||||||
your application does use a supported image size or queries the driver
|
|
||||||
for the actually used size (reason behind this: the camera cannot
|
|
||||||
provide any image format, so if size NxM is requested the driver will
|
|
||||||
use a format to the closest fitting N1xM1, the application should now
|
|
||||||
query for this granted size, most applications do not).
|
|
||||||
- all the todo ;)
|
|
||||||
- if there is not enough light and the picture is too dark try to
|
|
||||||
adjust the SetSensorFPS setting, automatic frame rate adjustment
|
|
||||||
has its price
|
|
||||||
- do not try out isabel 3R4beta (built 135), you will be disappointed
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
TODO:
|
|
||||||
|
|
||||||
- multiple camera support (struct camera or something) - This should work,
|
|
||||||
but hasn't been tested yet.
|
|
||||||
- architecture independence?
|
|
||||||
- SMP-safe asynchronous mmap interface
|
|
||||||
- nibble mode for old parport interfaces
|
|
||||||
- streaming capture, this should give a performance gain
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
IMPLEMENTATION NOTES:
|
|
||||||
|
|
||||||
The camera can act in two modes, streaming or grabbing. Right now a
|
|
||||||
polling grab-scheme is used. Maybe interrupt driven streaming will be
|
|
||||||
used for a asynchronous mmap interface in the next major release of the
|
|
||||||
driver. This might give a better frame rate.
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
THANKS (in no particular order):
|
|
||||||
|
|
||||||
- Scott J. Bertin <sbertin@mindspring.com> for cleanups, the proc-filesystem
|
|
||||||
and much more
|
|
||||||
- Henry Bruce <whb@vvl.co.uk> for providing developers information about
|
|
||||||
the CPiA chip, I wish all companies would treat Linux as seriously
|
|
||||||
- Karoly Erdei <Karoly.Erdei@risc.uni-linz.ac.at> and RISC-Linz for being
|
|
||||||
my boss ;) resp. my employer and for providing me the hardware and
|
|
||||||
allow me to devote some working time to this project
|
|
||||||
- Manuel J. Petit de Gabriel <mpetit@dit.upm.es> for providing help
|
|
||||||
with Isabel (http://isabel.dit.upm.es/)
|
|
||||||
- Bas Huisman <bhuism@cs.utwente.nl> for writing the initial parport code
|
|
||||||
- Jarl Totland <Jarl.Totland@bdc.no> for setting up the mailing list
|
|
||||||
and maintaining the web-server[3]
|
|
||||||
- Chris Whiteford <Chris@informinteractive.com> for fixes related to the
|
|
||||||
1.02 firmware
|
|
||||||
- special kudos to all the tester whose machines crashed and/or
|
|
||||||
will crash. :)
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
REFERENCES
|
|
||||||
|
|
||||||
1. http://www.risc.uni-linz.ac.at/
|
|
||||||
mailto:Peter_Pregler@email.com
|
|
||||||
2. see the file COPYING in the top directory of the kernel tree
|
|
||||||
3. http://webcam.sourceforge.net/
|
|
@ -464,10 +464,6 @@ Siemens
|
|||||||
-------
|
-------
|
||||||
Multimedia eXtension Board (MXB) (SAA7146, SAA7111)
|
Multimedia eXtension Board (MXB) (SAA7146, SAA7111)
|
||||||
|
|
||||||
Stradis
|
|
||||||
-------
|
|
||||||
SDM275,SDM250,SDM026,SDM025 (SAA7146, IBMMPEG2): MPEG2 decoder only
|
|
||||||
|
|
||||||
Powercolor
|
Powercolor
|
||||||
----------
|
----------
|
||||||
MTV878
|
MTV878
|
||||||
|
@ -5697,12 +5697,6 @@ M: Ion Badulescu <ionut@badula.org>
|
|||||||
S: Odd Fixes
|
S: Odd Fixes
|
||||||
F: drivers/net/starfire*
|
F: drivers/net/starfire*
|
||||||
|
|
||||||
STRADIS MPEG-2 DECODER DRIVER
|
|
||||||
M: Nathan Laredo <laredo@gnu.org>
|
|
||||||
W: http://www.stradis.com/
|
|
||||||
S: Maintained
|
|
||||||
F: drivers/media/video/stradis.c
|
|
||||||
|
|
||||||
SUN3/3X
|
SUN3/3X
|
||||||
M: Sam Creasey <sammy@sammy.net>
|
M: Sam Creasey <sammy@sammy.net>
|
||||||
W: http://sammy.net/sun3/
|
W: http://sammy.net/sun3/
|
||||||
|
@ -51,10 +51,6 @@ source "drivers/staging/cx25821/Kconfig"
|
|||||||
|
|
||||||
source "drivers/staging/tm6000/Kconfig"
|
source "drivers/staging/tm6000/Kconfig"
|
||||||
|
|
||||||
source "drivers/staging/cpia/Kconfig"
|
|
||||||
|
|
||||||
source "drivers/staging/stradis/Kconfig"
|
|
||||||
|
|
||||||
source "drivers/staging/se401/Kconfig"
|
source "drivers/staging/se401/Kconfig"
|
||||||
|
|
||||||
source "drivers/staging/usbvideo/Kconfig"
|
source "drivers/staging/usbvideo/Kconfig"
|
||||||
|
@ -8,8 +8,6 @@ obj-$(CONFIG_SLICOSS) += slicoss/
|
|||||||
obj-$(CONFIG_VIDEO_GO7007) += go7007/
|
obj-$(CONFIG_VIDEO_GO7007) += go7007/
|
||||||
obj-$(CONFIG_VIDEO_CX25821) += cx25821/
|
obj-$(CONFIG_VIDEO_CX25821) += cx25821/
|
||||||
obj-$(CONFIG_VIDEO_TM6000) += tm6000/
|
obj-$(CONFIG_VIDEO_TM6000) += tm6000/
|
||||||
obj-$(CONFIG_VIDEO_CPIA) += cpia/
|
|
||||||
obj-$(CONFIG_VIDEO_STRADIS) += stradis/
|
|
||||||
obj-$(CONFIG_USB_VICAM) += usbvideo/
|
obj-$(CONFIG_USB_VICAM) += usbvideo/
|
||||||
obj-$(CONFIG_USB_SE401) += se401/
|
obj-$(CONFIG_USB_SE401) += se401/
|
||||||
obj-$(CONFIG_LIRC_STAGING) += lirc/
|
obj-$(CONFIG_LIRC_STAGING) += lirc/
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
config VIDEO_CPIA
|
|
||||||
tristate "CPiA Video For Linux (DEPRECATED)"
|
|
||||||
depends on VIDEO_V4L1
|
|
||||||
default n
|
|
||||||
---help---
|
|
||||||
This driver is DEPRECATED please use the gspca cpia1 module
|
|
||||||
instead. Note that you need atleast version 0.6.4 of libv4l for
|
|
||||||
the cpia1 gspca module.
|
|
||||||
|
|
||||||
This is the video4linux driver for cameras based on Vision's CPiA
|
|
||||||
(Colour Processor Interface ASIC), such as the Creative Labs Video
|
|
||||||
Blaster Webcam II. If you have one of these cameras, say Y here
|
|
||||||
and select parallel port and/or USB lowlevel support below,
|
|
||||||
otherwise say N. This will not work with the Creative Webcam III.
|
|
||||||
|
|
||||||
Please read <file:Documentation/video4linux/README.cpia> for more
|
|
||||||
information.
|
|
||||||
|
|
||||||
This driver is also available as a module (cpia).
|
|
||||||
|
|
||||||
config VIDEO_CPIA_PP
|
|
||||||
tristate "CPiA Parallel Port Lowlevel Support"
|
|
||||||
depends on PARPORT_1284 && VIDEO_CPIA && PARPORT
|
|
||||||
help
|
|
||||||
This is the lowlevel parallel port support for cameras based on
|
|
||||||
Vision's CPiA (Colour Processor Interface ASIC), such as the
|
|
||||||
Creative Webcam II. If you have the parallel port version of one
|
|
||||||
of these cameras, say Y here, otherwise say N. It is also available
|
|
||||||
as a module (cpia_pp).
|
|
||||||
|
|
||||||
config VIDEO_CPIA_USB
|
|
||||||
tristate "CPiA USB Lowlevel Support"
|
|
||||||
depends on VIDEO_CPIA && USB
|
|
||||||
help
|
|
||||||
This is the lowlevel USB support for cameras based on Vision's CPiA
|
|
||||||
(Colour Processor Interface ASIC), such as the Creative Webcam II.
|
|
||||||
If you have the USB version of one of these cameras, say Y here,
|
|
||||||
otherwise say N. This will not work with the Creative Webcam III.
|
|
||||||
It is also available as a module (cpia_usb).
|
|
@ -1,5 +0,0 @@
|
|||||||
obj-$(CONFIG_VIDEO_CPIA) += cpia.o
|
|
||||||
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
|
|
||||||
obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
|
|
||||||
|
|
||||||
EXTRA_CFLAGS += -Idrivers/media/video
|
|
@ -1,8 +0,0 @@
|
|||||||
This is an obsolete driver for some cpia-based webcams that use the parallel port.
|
|
||||||
We couldn't find anyone with this hardware in order to port it to use V4L2.
|
|
||||||
|
|
||||||
Also, parallel-port webcams are obsolete nowadays.
|
|
||||||
|
|
||||||
If nobody take care on it, the driver will be removed for 2.6.38.
|
|
||||||
|
|
||||||
Please send patches to linux-media@vger.kernel.org
|
|
File diff suppressed because it is too large
Load Diff
@ -1,432 +0,0 @@
|
|||||||
#ifndef cpia_h
|
|
||||||
#define cpia_h
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CPiA Parallel Port Video4Linux driver
|
|
||||||
*
|
|
||||||
* Supports CPiA based parallel port Video Camera's.
|
|
||||||
*
|
|
||||||
* (C) Copyright 1999 Bas Huisman,
|
|
||||||
* Peter Pregler,
|
|
||||||
* Scott J. Bertin,
|
|
||||||
* VLSI Vision Ltd.
|
|
||||||
*
|
|
||||||
* 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_MAJ_VER 1
|
|
||||||
#define CPIA_MIN_VER 2
|
|
||||||
#define CPIA_PATCH_VER 3
|
|
||||||
|
|
||||||
#define CPIA_PP_MAJ_VER CPIA_MAJ_VER
|
|
||||||
#define CPIA_PP_MIN_VER CPIA_MIN_VER
|
|
||||||
#define CPIA_PP_PATCH_VER CPIA_PATCH_VER
|
|
||||||
|
|
||||||
#define CPIA_USB_MAJ_VER CPIA_MAJ_VER
|
|
||||||
#define CPIA_USB_MIN_VER CPIA_MIN_VER
|
|
||||||
#define CPIA_USB_PATCH_VER CPIA_PATCH_VER
|
|
||||||
|
|
||||||
#define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */
|
|
||||||
#define CPIA_MAX_FRAME_SIZE ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
|
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
|
||||||
#include <linux/videodev.h>
|
|
||||||
#include <media/v4l2-common.h>
|
|
||||||
#include <media/v4l2-ioctl.h>
|
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/mutex.h>
|
|
||||||
|
|
||||||
struct cpia_camera_ops
|
|
||||||
{
|
|
||||||
/* open sets privdata to point to structure for this camera.
|
|
||||||
* Returns negative value on error, otherwise 0.
|
|
||||||
*/
|
|
||||||
int (*open)(void *privdata);
|
|
||||||
|
|
||||||
/* Registers callback function cb to be called with cbdata
|
|
||||||
* when an image is ready. If cb is NULL, only single image grabs
|
|
||||||
* should be used. cb should immediately call streamRead to read
|
|
||||||
* the data or data may be lost. Returns negative value on error,
|
|
||||||
* otherwise 0.
|
|
||||||
*/
|
|
||||||
int (*registerCallback)(void *privdata, void (*cb)(void *cbdata),
|
|
||||||
void *cbdata);
|
|
||||||
|
|
||||||
/* transferCmd sends commands to the camera. command MUST point to
|
|
||||||
* an 8 byte buffer in kernel space. data can be NULL if no extra
|
|
||||||
* data is needed. The size of the data is given by the last 2
|
|
||||||
* bytes of command. data must also point to memory in kernel space.
|
|
||||||
* Returns negative value on error, otherwise 0.
|
|
||||||
*/
|
|
||||||
int (*transferCmd)(void *privdata, u8 *command, u8 *data);
|
|
||||||
|
|
||||||
/* streamStart initiates stream capture mode.
|
|
||||||
* Returns negative value on error, otherwise 0.
|
|
||||||
*/
|
|
||||||
int (*streamStart)(void *privdata);
|
|
||||||
|
|
||||||
/* streamStop terminates stream capture mode.
|
|
||||||
* Returns negative value on error, otherwise 0.
|
|
||||||
*/
|
|
||||||
int (*streamStop)(void *privdata);
|
|
||||||
|
|
||||||
/* streamRead reads a frame from the camera. buffer points to a
|
|
||||||
* buffer large enough to hold a complete frame in kernel space.
|
|
||||||
* noblock indicates if this should be a non blocking read.
|
|
||||||
* Returns the number of bytes read, or negative value on error.
|
|
||||||
*/
|
|
||||||
int (*streamRead)(void *privdata, u8 *buffer, int noblock);
|
|
||||||
|
|
||||||
/* close disables the device until open() is called again.
|
|
||||||
* Returns negative value on error, otherwise 0.
|
|
||||||
*/
|
|
||||||
int (*close)(void *privdata);
|
|
||||||
|
|
||||||
/* If wait_for_stream_ready is non-zero, wait until the streamState
|
|
||||||
* is STREAM_READY before calling streamRead.
|
|
||||||
*/
|
|
||||||
int wait_for_stream_ready;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Used to maintain lowlevel module usage counts
|
|
||||||
*/
|
|
||||||
struct module *owner;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cpia_frame {
|
|
||||||
u8 *data;
|
|
||||||
int count;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
volatile int state;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cam_params {
|
|
||||||
struct {
|
|
||||||
u8 firmwareVersion;
|
|
||||||
u8 firmwareRevision;
|
|
||||||
u8 vcVersion;
|
|
||||||
u8 vcRevision;
|
|
||||||
} version;
|
|
||||||
struct {
|
|
||||||
u16 vendor;
|
|
||||||
u16 product;
|
|
||||||
u16 deviceRevision;
|
|
||||||
} pnpID;
|
|
||||||
struct {
|
|
||||||
u8 vpVersion;
|
|
||||||
u8 vpRevision;
|
|
||||||
u16 cameraHeadID;
|
|
||||||
} vpVersion;
|
|
||||||
struct {
|
|
||||||
u8 systemState;
|
|
||||||
u8 grabState;
|
|
||||||
u8 streamState;
|
|
||||||
u8 fatalError;
|
|
||||||
u8 cmdError;
|
|
||||||
u8 debugFlags;
|
|
||||||
u8 vpStatus;
|
|
||||||
u8 errorCode;
|
|
||||||
} status;
|
|
||||||
struct {
|
|
||||||
u8 brightness;
|
|
||||||
u8 contrast;
|
|
||||||
u8 saturation;
|
|
||||||
} colourParams;
|
|
||||||
struct {
|
|
||||||
u8 gainMode;
|
|
||||||
u8 expMode;
|
|
||||||
u8 compMode;
|
|
||||||
u8 centreWeight;
|
|
||||||
u8 gain;
|
|
||||||
u8 fineExp;
|
|
||||||
u8 coarseExpLo;
|
|
||||||
u8 coarseExpHi;
|
|
||||||
u8 redComp;
|
|
||||||
u8 green1Comp;
|
|
||||||
u8 green2Comp;
|
|
||||||
u8 blueComp;
|
|
||||||
} exposure;
|
|
||||||
struct {
|
|
||||||
u8 balanceMode;
|
|
||||||
u8 redGain;
|
|
||||||
u8 greenGain;
|
|
||||||
u8 blueGain;
|
|
||||||
} colourBalance;
|
|
||||||
struct {
|
|
||||||
u8 divisor;
|
|
||||||
u8 baserate;
|
|
||||||
} sensorFps;
|
|
||||||
struct {
|
|
||||||
u8 gain1;
|
|
||||||
u8 gain2;
|
|
||||||
u8 gain4;
|
|
||||||
u8 gain8;
|
|
||||||
} apcor;
|
|
||||||
struct {
|
|
||||||
u8 disabled;
|
|
||||||
u8 flickerMode;
|
|
||||||
u8 coarseJump;
|
|
||||||
int allowableOverExposure;
|
|
||||||
} flickerControl;
|
|
||||||
struct {
|
|
||||||
u8 gain1;
|
|
||||||
u8 gain2;
|
|
||||||
u8 gain4;
|
|
||||||
u8 gain8;
|
|
||||||
} vlOffset;
|
|
||||||
struct {
|
|
||||||
u8 mode;
|
|
||||||
u8 decimation;
|
|
||||||
} compression;
|
|
||||||
struct {
|
|
||||||
u8 frTargeting;
|
|
||||||
u8 targetFR;
|
|
||||||
u8 targetQ;
|
|
||||||
} compressionTarget;
|
|
||||||
struct {
|
|
||||||
u8 yThreshold;
|
|
||||||
u8 uvThreshold;
|
|
||||||
} yuvThreshold;
|
|
||||||
struct {
|
|
||||||
u8 hysteresis;
|
|
||||||
u8 threshMax;
|
|
||||||
u8 smallStep;
|
|
||||||
u8 largeStep;
|
|
||||||
u8 decimationHysteresis;
|
|
||||||
u8 frDiffStepThresh;
|
|
||||||
u8 qDiffStepThresh;
|
|
||||||
u8 decimationThreshMod;
|
|
||||||
} compressionParams;
|
|
||||||
struct {
|
|
||||||
u8 videoSize; /* CIF/QCIF */
|
|
||||||
u8 subSample;
|
|
||||||
u8 yuvOrder;
|
|
||||||
} format;
|
|
||||||
struct { /* Intel QX3 specific data */
|
|
||||||
u8 qx3_detected; /* a QX3 is present */
|
|
||||||
u8 toplight; /* top light lit , R/W */
|
|
||||||
u8 bottomlight; /* bottom light lit, R/W */
|
|
||||||
u8 button; /* snapshot button pressed (R/O) */
|
|
||||||
u8 cradled; /* microscope is in cradle (R/O) */
|
|
||||||
} qx3;
|
|
||||||
struct {
|
|
||||||
u8 colStart; /* skip first 8*colStart pixels */
|
|
||||||
u8 colEnd; /* finish at 8*colEnd pixels */
|
|
||||||
u8 rowStart; /* skip first 4*rowStart lines */
|
|
||||||
u8 rowEnd; /* finish at 4*rowEnd lines */
|
|
||||||
} roi;
|
|
||||||
u8 ecpTiming;
|
|
||||||
u8 streamStartLine;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum v4l_camstates {
|
|
||||||
CPIA_V4L_IDLE = 0,
|
|
||||||
CPIA_V4L_ERROR,
|
|
||||||
CPIA_V4L_COMMAND,
|
|
||||||
CPIA_V4L_GRABBING,
|
|
||||||
CPIA_V4L_STREAMING,
|
|
||||||
CPIA_V4L_STREAMING_PAUSED,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define FRAME_NUM 2 /* double buffering for now */
|
|
||||||
|
|
||||||
struct cam_data {
|
|
||||||
struct list_head cam_data_list;
|
|
||||||
|
|
||||||
struct mutex busy_lock; /* guard against SMP multithreading */
|
|
||||||
struct cpia_camera_ops *ops; /* lowlevel driver operations */
|
|
||||||
void *lowlevel_data; /* private data for lowlevel driver */
|
|
||||||
u8 *raw_image; /* buffer for raw image data */
|
|
||||||
struct cpia_frame decompressed_frame;
|
|
||||||
/* buffer to hold decompressed frame */
|
|
||||||
int image_size; /* sizeof last decompressed image */
|
|
||||||
int open_count; /* # of process that have camera open */
|
|
||||||
|
|
||||||
/* camera status */
|
|
||||||
int fps; /* actual fps reported by the camera */
|
|
||||||
int transfer_rate; /* transfer rate from camera in kB/s */
|
|
||||||
u8 mainsFreq; /* for flicker control */
|
|
||||||
|
|
||||||
/* proc interface */
|
|
||||||
struct mutex param_lock; /* params lock for this camera */
|
|
||||||
struct cam_params params; /* camera settings */
|
|
||||||
struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */
|
|
||||||
|
|
||||||
/* v4l */
|
|
||||||
int video_size; /* VIDEO_SIZE_ */
|
|
||||||
volatile enum v4l_camstates camstate; /* v4l layer status */
|
|
||||||
struct video_device vdev; /* v4l videodev */
|
|
||||||
struct video_picture vp; /* v4l camera settings */
|
|
||||||
struct video_window vw; /* v4l capture area */
|
|
||||||
struct video_capture vc; /* v4l subcapture area */
|
|
||||||
|
|
||||||
/* mmap interface */
|
|
||||||
int curframe; /* the current frame to grab into */
|
|
||||||
u8 *frame_buf; /* frame buffer data */
|
|
||||||
struct cpia_frame frame[FRAME_NUM];
|
|
||||||
/* FRAME_NUM-buffering, so we need a array */
|
|
||||||
|
|
||||||
int first_frame;
|
|
||||||
int mmap_kludge; /* 'wrong' byte order for mmap */
|
|
||||||
volatile u32 cmd_queue; /* queued commands */
|
|
||||||
int exposure_status; /* EXPOSURE_* */
|
|
||||||
int exposure_count; /* number of frames at this status */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* cpia_register_camera is called by low level driver for each camera.
|
|
||||||
* A unique camera number is returned, or a negative value on error */
|
|
||||||
struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel);
|
|
||||||
|
|
||||||
/* cpia_unregister_camera is called by low level driver when a camera
|
|
||||||
* is removed. This must not fail. */
|
|
||||||
void cpia_unregister_camera(struct cam_data *cam);
|
|
||||||
|
|
||||||
/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI +
|
|
||||||
* one byte 16bit DMA alignment
|
|
||||||
*/
|
|
||||||
#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5)
|
|
||||||
|
|
||||||
/* constant value's */
|
|
||||||
#define MAGIC_0 0x19
|
|
||||||
#define MAGIC_1 0x68
|
|
||||||
#define DATA_IN 0xC0
|
|
||||||
#define DATA_OUT 0x40
|
|
||||||
#define VIDEOSIZE_QCIF 0 /* 176x144 */
|
|
||||||
#define VIDEOSIZE_CIF 1 /* 352x288 */
|
|
||||||
#define VIDEOSIZE_SIF 2 /* 320x240 */
|
|
||||||
#define VIDEOSIZE_QSIF 3 /* 160x120 */
|
|
||||||
#define VIDEOSIZE_48_48 4 /* where no one has gone before, iconsize! */
|
|
||||||
#define VIDEOSIZE_64_48 5
|
|
||||||
#define VIDEOSIZE_128_96 6
|
|
||||||
#define VIDEOSIZE_160_120 VIDEOSIZE_QSIF
|
|
||||||
#define VIDEOSIZE_176_144 VIDEOSIZE_QCIF
|
|
||||||
#define VIDEOSIZE_192_144 7
|
|
||||||
#define VIDEOSIZE_224_168 8
|
|
||||||
#define VIDEOSIZE_256_192 9
|
|
||||||
#define VIDEOSIZE_288_216 10
|
|
||||||
#define VIDEOSIZE_320_240 VIDEOSIZE_SIF
|
|
||||||
#define VIDEOSIZE_352_288 VIDEOSIZE_CIF
|
|
||||||
#define VIDEOSIZE_88_72 11 /* quarter CIF */
|
|
||||||
#define SUBSAMPLE_420 0
|
|
||||||
#define SUBSAMPLE_422 1
|
|
||||||
#define YUVORDER_YUYV 0
|
|
||||||
#define YUVORDER_UYVY 1
|
|
||||||
#define NOT_COMPRESSED 0
|
|
||||||
#define COMPRESSED 1
|
|
||||||
#define NO_DECIMATION 0
|
|
||||||
#define DECIMATION_ENAB 1
|
|
||||||
#define EOI 0xff /* End Of Image */
|
|
||||||
#define EOL 0xfd /* End Of Line */
|
|
||||||
#define FRAME_HEADER_SIZE 64
|
|
||||||
|
|
||||||
/* Image grab modes */
|
|
||||||
#define CPIA_GRAB_SINGLE 0
|
|
||||||
#define CPIA_GRAB_CONTINUOUS 1
|
|
||||||
|
|
||||||
/* Compression parameters */
|
|
||||||
#define CPIA_COMPRESSION_NONE 0
|
|
||||||
#define CPIA_COMPRESSION_AUTO 1
|
|
||||||
#define CPIA_COMPRESSION_MANUAL 2
|
|
||||||
#define CPIA_COMPRESSION_TARGET_QUALITY 0
|
|
||||||
#define CPIA_COMPRESSION_TARGET_FRAMERATE 1
|
|
||||||
|
|
||||||
/* Return offsets for GetCameraState */
|
|
||||||
#define SYSTEMSTATE 0
|
|
||||||
#define GRABSTATE 1
|
|
||||||
#define STREAMSTATE 2
|
|
||||||
#define FATALERROR 3
|
|
||||||
#define CMDERROR 4
|
|
||||||
#define DEBUGFLAGS 5
|
|
||||||
#define VPSTATUS 6
|
|
||||||
#define ERRORCODE 7
|
|
||||||
|
|
||||||
/* SystemState */
|
|
||||||
#define UNINITIALISED_STATE 0
|
|
||||||
#define PASS_THROUGH_STATE 1
|
|
||||||
#define LO_POWER_STATE 2
|
|
||||||
#define HI_POWER_STATE 3
|
|
||||||
#define WARM_BOOT_STATE 4
|
|
||||||
|
|
||||||
/* GrabState */
|
|
||||||
#define GRAB_IDLE 0
|
|
||||||
#define GRAB_ACTIVE 1
|
|
||||||
#define GRAB_DONE 2
|
|
||||||
|
|
||||||
/* StreamState */
|
|
||||||
#define STREAM_NOT_READY 0
|
|
||||||
#define STREAM_READY 1
|
|
||||||
#define STREAM_OPEN 2
|
|
||||||
#define STREAM_PAUSED 3
|
|
||||||
#define STREAM_FINISHED 4
|
|
||||||
|
|
||||||
/* Fatal Error, CmdError, and DebugFlags */
|
|
||||||
#define CPIA_FLAG 1
|
|
||||||
#define SYSTEM_FLAG 2
|
|
||||||
#define INT_CTRL_FLAG 4
|
|
||||||
#define PROCESS_FLAG 8
|
|
||||||
#define COM_FLAG 16
|
|
||||||
#define VP_CTRL_FLAG 32
|
|
||||||
#define CAPTURE_FLAG 64
|
|
||||||
#define DEBUG_FLAG 128
|
|
||||||
|
|
||||||
/* VPStatus */
|
|
||||||
#define VP_STATE_OK 0x00
|
|
||||||
|
|
||||||
#define VP_STATE_FAILED_VIDEOINIT 0x01
|
|
||||||
#define VP_STATE_FAILED_AECACBINIT 0x02
|
|
||||||
#define VP_STATE_AEC_MAX 0x04
|
|
||||||
#define VP_STATE_ACB_BMAX 0x08
|
|
||||||
|
|
||||||
#define VP_STATE_ACB_RMIN 0x10
|
|
||||||
#define VP_STATE_ACB_GMIN 0x20
|
|
||||||
#define VP_STATE_ACB_RMAX 0x40
|
|
||||||
#define VP_STATE_ACB_GMAX 0x80
|
|
||||||
|
|
||||||
/* default (minimum) compensation values */
|
|
||||||
#define COMP_RED 220
|
|
||||||
#define COMP_GREEN1 214
|
|
||||||
#define COMP_GREEN2 COMP_GREEN1
|
|
||||||
#define COMP_BLUE 230
|
|
||||||
|
|
||||||
/* exposure status */
|
|
||||||
#define EXPOSURE_VERY_LIGHT 0
|
|
||||||
#define EXPOSURE_LIGHT 1
|
|
||||||
#define EXPOSURE_NORMAL 2
|
|
||||||
#define EXPOSURE_DARK 3
|
|
||||||
#define EXPOSURE_VERY_DARK 4
|
|
||||||
|
|
||||||
/* ErrorCode */
|
|
||||||
#define ERROR_FLICKER_BELOW_MIN_EXP 0x01 /*flicker exposure got below minimum exposure */
|
|
||||||
#define ALOG(fmt,args...) printk(fmt, ##args)
|
|
||||||
#define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __func__ , __LINE__ , ##args)
|
|
||||||
|
|
||||||
#ifdef _CPIA_DEBUG_
|
|
||||||
#define ADBG(fmt,args...) printk(fmt, jiffies, ##args)
|
|
||||||
#define DBG(fmt,args...) ADBG(KERN_DEBUG __FILE__" (%ld):%s(%d):" fmt, __func__, __LINE__ , ##args)
|
|
||||||
#else
|
|
||||||
#define DBG(fmn,args...) do {} while(0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEB_BYTE(p)\
|
|
||||||
DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\
|
|
||||||
(p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
|
|
||||||
(p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
|
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
|
||||||
|
|
||||||
#endif /* cpia_h */
|
|
@ -1,869 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/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/sched.h>
|
|
||||||
#include <linux/slab.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
|
|
||||||
|
|
||||||
static 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.");
|
|
||||||
|
|
||||||
struct pp_cam_entry {
|
|
||||||
struct pardevice *pdev;
|
|
||||||
struct parport *port;
|
|
||||||
struct work_struct cb_task;
|
|
||||||
void (*cb_func)(void *cbdata);
|
|
||||||
void *cb_data;
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
static void cpia_pp_run_callback(struct work_struct *work)
|
|
||||||
{
|
|
||||||
void (*cb_func)(void *cbdata);
|
|
||||||
void *cb_data;
|
|
||||||
struct pp_cam_entry *cam;
|
|
||||||
|
|
||||||
cam = container_of(work, struct pp_cam_entry, cb_task);
|
|
||||||
cb_func = cam->cb_func;
|
|
||||||
cb_data = cam->cb_data;
|
|
||||||
|
|
||||||
cb_func(cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
*
|
|
||||||
* 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)) {
|
|
||||||
DBG("%s: No more nibble data (%d bytes)\n",
|
|
||||||
port->name, i/2);
|
|
||||||
goto end_of_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == len) {
|
|
||||||
/* Read the last nibble without checking data avail. */
|
|
||||||
if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
|
|
||||||
end_of_data:
|
|
||||||
/* Go to reverse idle phase. */
|
|
||||||
parport_frob_control (port,
|
|
||||||
PARPORT_CONTROL_AUTOFD,
|
|
||||||
PARPORT_CONTROL_AUTOFD);
|
|
||||||
port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i/2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
if(cam->port->ieee1284.mode == IEEE1284_MODE_NIBBLE) {
|
|
||||||
if(cpia_read_nibble(cam->port, packet, size, 0) != size)
|
|
||||||
retval = -EIO;
|
|
||||||
} else {
|
|
||||||
if(parport_read(cam->port, packet, size) != size)
|
|
||||||
retval = -EIO;
|
|
||||||
}
|
|
||||||
EndTransferMode(cam);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
*
|
|
||||||
* cpia_pp_streamStart
|
|
||||||
*
|
|
||||||
***************************************************************************/
|
|
||||||
static int cpia_pp_streamStart(void *privdata)
|
|
||||||
{
|
|
||||||
struct pp_cam_entry *cam = privdata;
|
|
||||||
DBG("\n");
|
|
||||||
cam->streaming=1;
|
|
||||||
cam->image_ready=0;
|
|
||||||
//if (ReverseSetup(cam,1)) return -EIO;
|
|
||||||
if(cam->stream_irq) cpia_parport_enable_irq(cam->port);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
*
|
|
||||||
* cpia_pp_streamStop
|
|
||||||
*
|
|
||||||
***************************************************************************/
|
|
||||||
static int cpia_pp_streamStop(void *privdata)
|
|
||||||
{
|
|
||||||
struct pp_cam_entry *cam = privdata;
|
|
||||||
|
|
||||||
DBG("\n");
|
|
||||||
cam->streaming=0;
|
|
||||||
cpia_parport_disable_irq(cam->port);
|
|
||||||
//EndTransferMode(cam);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
*
|
|
||||||
* cpia_pp_streamRead
|
|
||||||
*
|
|
||||||
***************************************************************************/
|
|
||||||
static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
|
|
||||||
{
|
|
||||||
int bytes_read;
|
|
||||||
|
|
||||||
/* support for CPiA variant "nibble stream" reads */
|
|
||||||
if(port->ieee1284.mode == IEEE1284_MODE_NIBBLE)
|
|
||||||
bytes_read = cpia_read_nibble_stream(port,buffer,len,0);
|
|
||||||
else {
|
|
||||||
int new_bytes;
|
|
||||||
for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
|
|
||||||
new_bytes = parport_read(port, buffer+bytes_read,
|
|
||||||
len-bytes_read);
|
|
||||||
if(new_bytes < 0) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
|
|
||||||
{
|
|
||||||
struct pp_cam_entry *cam = privdata;
|
|
||||||
int read_bytes = 0;
|
|
||||||
int i, endseen, block_size, new_bytes;
|
|
||||||
|
|
||||||
if(cam == NULL) {
|
|
||||||
DBG("Internal driver error: cam is NULL\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if(buffer == NULL) {
|
|
||||||
DBG("Internal driver error: buffer is NULL\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
//if(cam->streaming) DBG("%d / %d\n", cam->image_ready, noblock);
|
|
||||||
if( cam->stream_irq ) {
|
|
||||||
DBG("%d\n", cam->image_ready);
|
|
||||||
cam->image_ready--;
|
|
||||||
}
|
|
||||||
cam->image_complete=0;
|
|
||||||
if (0/*cam->streaming*/) {
|
|
||||||
if(!cam->image_ready) {
|
|
||||||
if(noblock) return -EWOULDBLOCK;
|
|
||||||
interruptible_sleep_on(&cam->wq_stream);
|
|
||||||
if( signal_pending(current) ) return -EINTR;
|
|
||||||
DBG("%d\n", cam->image_ready);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ReverseSetup(cam, 1)) {
|
|
||||||
DBG("unable to ReverseSetup\n");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
endseen = 0;
|
|
||||||
block_size = PARPORT_CHUNK_SIZE;
|
|
||||||
while( !cam->image_complete ) {
|
|
||||||
cond_resched();
|
|
||||||
|
|
||||||
new_bytes = cpia_pp_read(cam->port, buffer, block_size );
|
|
||||||
if( new_bytes <= 0 ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i=-1;
|
|
||||||
while(++i<new_bytes && endseen<4) {
|
|
||||||
if(*buffer==EOI) {
|
|
||||||
endseen++;
|
|
||||||
} else {
|
|
||||||
endseen=0;
|
|
||||||
}
|
|
||||||
buffer++;
|
|
||||||
}
|
|
||||||
read_bytes += i;
|
|
||||||
if( endseen==4 ) {
|
|
||||||
cam->image_complete=1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
|
|
||||||
block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EndTransferMode(cam);
|
|
||||||
return cam->image_complete ? read_bytes : -EIO;
|
|
||||||
}
|
|
||||||
/****************************************************************************
|
|
||||||
*
|
|
||||||
* cpia_pp_transferCmd
|
|
||||||
*
|
|
||||||
***************************************************************************/
|
|
||||||
static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
int retval=0;
|
|
||||||
int databytes;
|
|
||||||
struct pp_cam_entry *cam = privdata;
|
|
||||||
|
|
||||||
if(cam == NULL) {
|
|
||||||
DBG("Internal driver error: cam is NULL\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if(command == NULL) {
|
|
||||||
DBG("Internal driver error: command is NULL\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
databytes = (((int)command[7])<<8) | command[6];
|
|
||||||
if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) {
|
|
||||||
DBG("Error writing command\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if(command[0] == DATA_IN) {
|
|
||||||
u8 buffer[8];
|
|
||||||
if(data == NULL) {
|
|
||||||
DBG("Internal driver error: data is NULL\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if((err = ReadPacket(cam, buffer, 8)) < 0) {
|
|
||||||
DBG("Error reading command result\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
memcpy(data, buffer, databytes);
|
|
||||||
} else if(command[0] == DATA_OUT) {
|
|
||||||
if(databytes > 0) {
|
|
||||||
if(data == NULL) {
|
|
||||||
DBG("Internal driver error: data is NULL\n");
|
|
||||||
retval = -EINVAL;
|
|
||||||
} else {
|
|
||||||
if((err=WritePacket(cam, data, databytes)) < 0){
|
|
||||||
DBG("Error writing command data\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DBG("Unexpected first byte of command: %x\n", command[0]);
|
|
||||||
retval = -EINVAL;
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
*
|
|
||||||
* cpia_pp_open
|
|
||||||
*
|
|
||||||
***************************************************************************/
|
|
||||||
static int cpia_pp_open(void *privdata)
|
|
||||||
{
|
|
||||||
struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata;
|
|
||||||
|
|
||||||
if (cam == NULL)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if(cam->open_count == 0) {
|
|
||||||
if (parport_claim(cam->pdev)) {
|
|
||||||
DBG("failed to claim the port\n");
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
|
|
||||||
parport_data_forward(cam->port);
|
|
||||||
parport_write_control(cam->port, PARPORT_CONTROL_SELECT);
|
|
||||||
udelay(50);
|
|
||||||
parport_write_control(cam->port,
|
|
||||||
PARPORT_CONTROL_SELECT
|
|
||||||
| PARPORT_CONTROL_INIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
++cam->open_count;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
*
|
|
||||||
* cpia_pp_registerCallback
|
|
||||||
*
|
|
||||||
***************************************************************************/
|
|
||||||
static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), void *cbdata)
|
|
||||||
{
|
|
||||||
struct pp_cam_entry *cam = privdata;
|
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
if(cam->port->irq != PARPORT_IRQ_NONE) {
|
|
||||||
cam->cb_func = cb;
|
|
||||||
cam->cb_data = cbdata;
|
|
||||||
INIT_WORK(&cam->cb_task, cpia_pp_run_callback);
|
|
||||||
} else {
|
|
||||||
retval = -1;
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
*
|
|
||||||
* cpia_pp_close
|
|
||||||
*
|
|
||||||
***************************************************************************/
|
|
||||||
static int cpia_pp_close(void *privdata)
|
|
||||||
{
|
|
||||||
struct pp_cam_entry *cam = privdata;
|
|
||||||
if (--cam->open_count == 0) {
|
|
||||||
parport_release(cam->pdev);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
*
|
|
||||||
* cpia_pp_register
|
|
||||||
*
|
|
||||||
***************************************************************************/
|
|
||||||
static int cpia_pp_register(struct parport *port)
|
|
||||||
{
|
|
||||||
struct pardevice *pdev = NULL;
|
|
||||||
struct pp_cam_entry *cam;
|
|
||||||
struct cam_data *cpia;
|
|
||||||
|
|
||||||
if (!(port->modes & PARPORT_MODE_PCSPP)) {
|
|
||||||
LOG("port is not supported by CPiA driver\n");
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
cam = kzalloc(sizeof(struct pp_cam_entry), GFP_KERNEL);
|
|
||||||
if (cam == NULL) {
|
|
||||||
LOG("failed to allocate camera structure\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdev = parport_register_device(port, "cpia_pp", NULL, NULL,
|
|
||||||
NULL, 0, cam);
|
|
||||||
|
|
||||||
if (!pdev) {
|
|
||||||
LOG("failed to parport_register_device\n");
|
|
||||||
kfree(cam);
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
cam->pdev = pdev;
|
|
||||||
cam->port = port;
|
|
||||||
init_waitqueue_head(&cam->wq_stream);
|
|
||||||
|
|
||||||
cam->streaming = 0;
|
|
||||||
cam->stream_irq = 0;
|
|
||||||
|
|
||||||
if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) {
|
|
||||||
LOG("failed to cpia_register_camera\n");
|
|
||||||
parport_unregister_device(pdev);
|
|
||||||
kfree(cam);
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
spin_lock( &cam_list_lock_pp );
|
|
||||||
list_add( &cpia->cam_data_list, &cam_list );
|
|
||||||
spin_unlock( &cam_list_lock_pp );
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cpia_pp_detach (struct parport *port)
|
|
||||||
{
|
|
||||||
struct list_head *tmp;
|
|
||||||
struct cam_data *cpia = NULL;
|
|
||||||
struct pp_cam_entry *cam;
|
|
||||||
|
|
||||||
spin_lock( &cam_list_lock_pp );
|
|
||||||
list_for_each (tmp, &cam_list) {
|
|
||||||
cpia = list_entry(tmp, struct cam_data, cam_data_list);
|
|
||||||
cam = (struct pp_cam_entry *) cpia->lowlevel_data;
|
|
||||||
if (cam && cam->port->number == port->number) {
|
|
||||||
list_del(&cpia->cam_data_list);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cpia = NULL;
|
|
||||||
}
|
|
||||||
spin_unlock( &cam_list_lock_pp );
|
|
||||||
|
|
||||||
if (!cpia) {
|
|
||||||
DBG("cpia_pp_detach failed to find cam_data in cam_list\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cam = (struct pp_cam_entry *) cpia->lowlevel_data;
|
|
||||||
cpia_unregister_camera(cpia);
|
|
||||||
if(cam->open_count > 0)
|
|
||||||
cpia_pp_close(cam);
|
|
||||||
parport_unregister_device(cam->pdev);
|
|
||||||
cpia->lowlevel_data = NULL;
|
|
||||||
kfree(cam);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cpia_pp_attach (struct parport *port)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
switch (parport_nr[0])
|
|
||||||
{
|
|
||||||
case PPCPIA_PARPORT_UNSPEC:
|
|
||||||
case PPCPIA_PARPORT_AUTO:
|
|
||||||
if (port->probe_info[0].class != PARPORT_CLASS_MEDIA ||
|
|
||||||
port->probe_info[0].cmdset == NULL ||
|
|
||||||
strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
cpia_pp_register(port);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
for (i = 0; i < PARPORT_MAX; ++i) {
|
|
||||||
if (port->number == parport_nr[i]) {
|
|
||||||
cpia_pp_register(port);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct parport_driver cpia_pp_driver = {
|
|
||||||
.name = "cpia_pp",
|
|
||||||
.attach = cpia_pp_attach,
|
|
||||||
.detach = cpia_pp_detach,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __init cpia_pp_init(void)
|
|
||||||
{
|
|
||||||
printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
|
|
||||||
CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
|
|
||||||
|
|
||||||
if(parport_nr[0] == PPCPIA_PARPORT_OFF) {
|
|
||||||
printk(" disabled\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_init( &cam_list_lock_pp );
|
|
||||||
|
|
||||||
if (parport_register_driver (&cpia_pp_driver)) {
|
|
||||||
LOG ("unable to register with parport\n");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init cpia_init(void)
|
|
||||||
{
|
|
||||||
if (parport[0]) {
|
|
||||||
/* The user gave some parameters. Let's see what they were. */
|
|
||||||
if (!strncmp(parport[0], "auto", 4)) {
|
|
||||||
parport_nr[0] = PPCPIA_PARPORT_AUTO;
|
|
||||||
} else {
|
|
||||||
int n;
|
|
||||||
for (n = 0; n < PARPORT_MAX && parport[n]; n++) {
|
|
||||||
if (!strncmp(parport[n], "none", 4)) {
|
|
||||||
parport_nr[n] = PPCPIA_PARPORT_NONE;
|
|
||||||
} else {
|
|
||||||
char *ep;
|
|
||||||
unsigned long r = simple_strtoul(parport[n], &ep, 0);
|
|
||||||
if (ep != parport[n]) {
|
|
||||||
parport_nr[n] = r;
|
|
||||||
} else {
|
|
||||||
LOG("bad port specifier `%s'\n", parport[n]);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cpia_pp_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit cpia_cleanup(void)
|
|
||||||
{
|
|
||||||
parport_unregister_driver(&cpia_pp_driver);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(cpia_init);
|
|
||||||
module_exit(cpia_cleanup);
|
|
@ -1,640 +0,0 @@
|
|||||||
/*
|
|
||||||
* cpia_usb CPiA USB driver
|
|
||||||
*
|
|
||||||
* Supports CPiA based parallel port Video Camera's.
|
|
||||||
*
|
|
||||||
* Copyright (C) 1999 Jochen Scharrlach <Jochen.Scharrlach@schwaben.de>
|
|
||||||
* Copyright (C) 1999, 2000 Johannes Erdfelt <johannes@erdfelt.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/module.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/wait.h>
|
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/vmalloc.h>
|
|
||||||
#include <linux/usb.h>
|
|
||||||
|
|
||||||
#include "cpia.h"
|
|
||||||
|
|
||||||
#define USB_REQ_CPIA_GRAB_FRAME 0xC1
|
|
||||||
#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2
|
|
||||||
#define WAIT_FOR_NEXT_FRAME 0
|
|
||||||
#define FORCE_FRAME_UPLOAD 1
|
|
||||||
|
|
||||||
#define FRAMES_PER_DESC 10
|
|
||||||
#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */
|
|
||||||
#define CPIA_NUMSBUF 2
|
|
||||||
#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
|
|
||||||
#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
|
|
||||||
|
|
||||||
struct cpia_sbuf {
|
|
||||||
char *data;
|
|
||||||
struct urb *urb;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
|
|
||||||
enum framebuf_status {
|
|
||||||
FRAME_EMPTY,
|
|
||||||
FRAME_READING,
|
|
||||||
FRAME_READY,
|
|
||||||
FRAME_ERROR,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct framebuf {
|
|
||||||
int length;
|
|
||||||
enum framebuf_status status;
|
|
||||||
u8 data[FRAMEBUF_LEN];
|
|
||||||
struct framebuf *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct usb_cpia {
|
|
||||||
/* Device structure */
|
|
||||||
struct usb_device *dev;
|
|
||||||
|
|
||||||
unsigned char iface;
|
|
||||||
wait_queue_head_t wq_stream;
|
|
||||||
|
|
||||||
int cursbuf; /* Current receiving sbuf */
|
|
||||||
struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */
|
|
||||||
|
|
||||||
int streaming;
|
|
||||||
int open;
|
|
||||||
int present;
|
|
||||||
struct framebuf *buffers[3];
|
|
||||||
struct framebuf *curbuff, *workbuff;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int cpia_usb_open(void *privdata);
|
|
||||||
static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
|
|
||||||
void *cbdata);
|
|
||||||
static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data);
|
|
||||||
static int cpia_usb_streamStart(void *privdata);
|
|
||||||
static int cpia_usb_streamStop(void *privdata);
|
|
||||||
static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock);
|
|
||||||
static int cpia_usb_close(void *privdata);
|
|
||||||
|
|
||||||
#define ABOUT "USB driver for Vision CPiA based cameras"
|
|
||||||
|
|
||||||
static struct cpia_camera_ops cpia_usb_ops = {
|
|
||||||
cpia_usb_open,
|
|
||||||
cpia_usb_registerCallback,
|
|
||||||
cpia_usb_transferCmd,
|
|
||||||
cpia_usb_streamStart,
|
|
||||||
cpia_usb_streamStop,
|
|
||||||
cpia_usb_streamRead,
|
|
||||||
cpia_usb_close,
|
|
||||||
0,
|
|
||||||
THIS_MODULE
|
|
||||||
};
|
|
||||||
|
|
||||||
static LIST_HEAD(cam_list);
|
|
||||||
static spinlock_t cam_list_lock_usb;
|
|
||||||
|
|
||||||
static void cpia_usb_complete(struct urb *urb)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *cdata;
|
|
||||||
struct usb_cpia *ucpia;
|
|
||||||
|
|
||||||
if (!urb || !urb->context)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ucpia = (struct usb_cpia *) urb->context;
|
|
||||||
|
|
||||||
if (!ucpia->dev || !ucpia->streaming || !ucpia->present || !ucpia->open)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ucpia->workbuff->status == FRAME_EMPTY) {
|
|
||||||
ucpia->workbuff->status = FRAME_READING;
|
|
||||||
ucpia->workbuff->length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < urb->number_of_packets; i++) {
|
|
||||||
int n = urb->iso_frame_desc[i].actual_length;
|
|
||||||
int st = urb->iso_frame_desc[i].status;
|
|
||||||
|
|
||||||
cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
|
|
||||||
|
|
||||||
if (st)
|
|
||||||
printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", i, n, st);
|
|
||||||
|
|
||||||
if (FRAMEBUF_LEN < ucpia->workbuff->length + n) {
|
|
||||||
printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n", ucpia->workbuff->length, n);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n) {
|
|
||||||
if ((ucpia->workbuff->length > 0) ||
|
|
||||||
(0x19 == cdata[0] && 0x68 == cdata[1])) {
|
|
||||||
memcpy(ucpia->workbuff->data + ucpia->workbuff->length, cdata, n);
|
|
||||||
ucpia->workbuff->length += n;
|
|
||||||
} else
|
|
||||||
DBG("Ignoring packet!\n");
|
|
||||||
} else {
|
|
||||||
if (ucpia->workbuff->length > 4 &&
|
|
||||||
0xff == ucpia->workbuff->data[ucpia->workbuff->length-1] &&
|
|
||||||
0xff == ucpia->workbuff->data[ucpia->workbuff->length-2] &&
|
|
||||||
0xff == ucpia->workbuff->data[ucpia->workbuff->length-3] &&
|
|
||||||
0xff == ucpia->workbuff->data[ucpia->workbuff->length-4]) {
|
|
||||||
ucpia->workbuff->status = FRAME_READY;
|
|
||||||
ucpia->curbuff = ucpia->workbuff;
|
|
||||||
ucpia->workbuff = ucpia->workbuff->next;
|
|
||||||
ucpia->workbuff->status = FRAME_EMPTY;
|
|
||||||
ucpia->workbuff->length = 0;
|
|
||||||
|
|
||||||
if (waitqueue_active(&ucpia->wq_stream))
|
|
||||||
wake_up_interruptible(&ucpia->wq_stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* resubmit */
|
|
||||||
urb->dev = ucpia->dev;
|
|
||||||
if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
|
|
||||||
printk(KERN_ERR "%s: usb_submit_urb ret %d\n", __func__, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cpia_usb_open(void *privdata)
|
|
||||||
{
|
|
||||||
struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
|
|
||||||
struct urb *urb;
|
|
||||||
int ret, retval = 0, fx, err;
|
|
||||||
|
|
||||||
if (!ucpia)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
ucpia->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
|
|
||||||
if (!ucpia->sbuf[0].data)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
ucpia->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
|
|
||||||
if (!ucpia->sbuf[1].data) {
|
|
||||||
retval = -EINVAL;
|
|
||||||
goto error_0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = usb_set_interface(ucpia->dev, ucpia->iface, 3);
|
|
||||||
if (ret < 0) {
|
|
||||||
printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret);
|
|
||||||
retval = -EBUSY;
|
|
||||||
goto error_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ucpia->buffers[0]->status = FRAME_EMPTY;
|
|
||||||
ucpia->buffers[0]->length = 0;
|
|
||||||
ucpia->buffers[1]->status = FRAME_EMPTY;
|
|
||||||
ucpia->buffers[1]->length = 0;
|
|
||||||
ucpia->buffers[2]->status = FRAME_EMPTY;
|
|
||||||
ucpia->buffers[2]->length = 0;
|
|
||||||
ucpia->curbuff = ucpia->buffers[0];
|
|
||||||
ucpia->workbuff = ucpia->buffers[1];
|
|
||||||
|
|
||||||
/* We double buffer the Iso lists, and also know the polling
|
|
||||||
* interval is every frame (1 == (1 << (bInterval -1))).
|
|
||||||
*/
|
|
||||||
urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
|
|
||||||
if (!urb) {
|
|
||||||
printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
|
|
||||||
retval = -ENOMEM;
|
|
||||||
goto error_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ucpia->sbuf[0].urb = urb;
|
|
||||||
urb->dev = ucpia->dev;
|
|
||||||
urb->context = ucpia;
|
|
||||||
urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
|
|
||||||
urb->transfer_flags = URB_ISO_ASAP;
|
|
||||||
urb->transfer_buffer = ucpia->sbuf[0].data;
|
|
||||||
urb->complete = cpia_usb_complete;
|
|
||||||
urb->number_of_packets = FRAMES_PER_DESC;
|
|
||||||
urb->interval = 1;
|
|
||||||
urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
|
|
||||||
for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
|
|
||||||
urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
|
|
||||||
urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
|
|
||||||
}
|
|
||||||
|
|
||||||
urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
|
|
||||||
if (!urb) {
|
|
||||||
printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 1\n");
|
|
||||||
retval = -ENOMEM;
|
|
||||||
goto error_urb0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ucpia->sbuf[1].urb = urb;
|
|
||||||
urb->dev = ucpia->dev;
|
|
||||||
urb->context = ucpia;
|
|
||||||
urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
|
|
||||||
urb->transfer_flags = URB_ISO_ASAP;
|
|
||||||
urb->transfer_buffer = ucpia->sbuf[1].data;
|
|
||||||
urb->complete = cpia_usb_complete;
|
|
||||||
urb->number_of_packets = FRAMES_PER_DESC;
|
|
||||||
urb->interval = 1;
|
|
||||||
urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
|
|
||||||
for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
|
|
||||||
urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
|
|
||||||
urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* queue the ISO urbs, and resubmit in the completion handler */
|
|
||||||
err = usb_submit_urb(ucpia->sbuf[0].urb, GFP_KERNEL);
|
|
||||||
if (err) {
|
|
||||||
printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n",
|
|
||||||
err);
|
|
||||||
goto error_urb1;
|
|
||||||
}
|
|
||||||
err = usb_submit_urb(ucpia->sbuf[1].urb, GFP_KERNEL);
|
|
||||||
if (err) {
|
|
||||||
printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n",
|
|
||||||
err);
|
|
||||||
goto error_urb1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ucpia->streaming = 1;
|
|
||||||
ucpia->open = 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error_urb1: /* free urb 1 */
|
|
||||||
usb_free_urb(ucpia->sbuf[1].urb);
|
|
||||||
ucpia->sbuf[1].urb = NULL;
|
|
||||||
error_urb0: /* free urb 0 */
|
|
||||||
usb_free_urb(ucpia->sbuf[0].urb);
|
|
||||||
ucpia->sbuf[0].urb = NULL;
|
|
||||||
error_1:
|
|
||||||
kfree (ucpia->sbuf[1].data);
|
|
||||||
ucpia->sbuf[1].data = NULL;
|
|
||||||
error_0:
|
|
||||||
kfree (ucpia->sbuf[0].data);
|
|
||||||
ucpia->sbuf[0].data = NULL;
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// convenience functions
|
|
||||||
//
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
*
|
|
||||||
* WritePacket
|
|
||||||
*
|
|
||||||
***************************************************************************/
|
|
||||||
static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_t size)
|
|
||||||
{
|
|
||||||
if (!packet)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
|
||||||
packet[1] + (packet[0] << 8),
|
|
||||||
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
||||||
packet[2] + (packet[3] << 8),
|
|
||||||
packet[4] + (packet[5] << 8), buf, size, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
*
|
|
||||||
* ReadPacket
|
|
||||||
*
|
|
||||||
***************************************************************************/
|
|
||||||
static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size)
|
|
||||||
{
|
|
||||||
if (!packet || size <= 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
|
||||||
packet[1] + (packet[0] << 8),
|
|
||||||
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
||||||
packet[2] + (packet[3] << 8),
|
|
||||||
packet[4] + (packet[5] << 8), buf, size, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
int databytes;
|
|
||||||
struct usb_cpia *ucpia = (struct usb_cpia *)privdata;
|
|
||||||
struct usb_device *udev = ucpia->dev;
|
|
||||||
|
|
||||||
if (!udev) {
|
|
||||||
DBG("Internal driver error: udev is NULL\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!command) {
|
|
||||||
DBG("Internal driver error: command is NULL\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
databytes = (((int)command[7])<<8) | command[6];
|
|
||||||
|
|
||||||
if (command[0] == DATA_IN) {
|
|
||||||
u8 buffer[8];
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
DBG("Internal driver error: data is NULL\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ReadPacket(udev, command, buffer, 8);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
memcpy(data, buffer, databytes);
|
|
||||||
} else if(command[0] == DATA_OUT)
|
|
||||||
WritePacket(udev, command, data, databytes);
|
|
||||||
else {
|
|
||||||
DBG("Unexpected first byte of command: %x\n", command[0]);
|
|
||||||
err = -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
|
|
||||||
void *cbdata)
|
|
||||||
{
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cpia_usb_streamStart(void *privdata)
|
|
||||||
{
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cpia_usb_streamStop(void *privdata)
|
|
||||||
{
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
|
|
||||||
{
|
|
||||||
struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
|
|
||||||
struct framebuf *mybuff;
|
|
||||||
|
|
||||||
if (!ucpia || !ucpia->present)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (ucpia->curbuff->status != FRAME_READY)
|
|
||||||
interruptible_sleep_on(&ucpia->wq_stream);
|
|
||||||
else
|
|
||||||
DBG("Frame already waiting!\n");
|
|
||||||
|
|
||||||
mybuff = ucpia->curbuff;
|
|
||||||
|
|
||||||
if (!mybuff)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (mybuff->status != FRAME_READY || mybuff->length < 4) {
|
|
||||||
DBG("Something went wrong!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(frame, mybuff->data, mybuff->length);
|
|
||||||
mybuff->status = FRAME_EMPTY;
|
|
||||||
|
|
||||||
/* DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n", */
|
|
||||||
/* mybuff->length, frame[0], frame[1], */
|
|
||||||
/* frame[mybuff->length-4], frame[mybuff->length-3], */
|
|
||||||
/* frame[mybuff->length-2], frame[mybuff->length-1]); */
|
|
||||||
|
|
||||||
return mybuff->length;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try)
|
|
||||||
{
|
|
||||||
if (!ucpia->streaming)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ucpia->streaming = 0;
|
|
||||||
|
|
||||||
/* Set packet size to 0 */
|
|
||||||
if (try) {
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = usb_set_interface(ucpia->dev, ucpia->iface, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
printk(KERN_ERR "usb_set_interface error (ret = %d)\n", ret);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unschedule all of the iso td's */
|
|
||||||
if (ucpia->sbuf[1].urb) {
|
|
||||||
usb_kill_urb(ucpia->sbuf[1].urb);
|
|
||||||
usb_free_urb(ucpia->sbuf[1].urb);
|
|
||||||
ucpia->sbuf[1].urb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(ucpia->sbuf[1].data);
|
|
||||||
ucpia->sbuf[1].data = NULL;
|
|
||||||
|
|
||||||
if (ucpia->sbuf[0].urb) {
|
|
||||||
usb_kill_urb(ucpia->sbuf[0].urb);
|
|
||||||
usb_free_urb(ucpia->sbuf[0].urb);
|
|
||||||
ucpia->sbuf[0].urb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(ucpia->sbuf[0].data);
|
|
||||||
ucpia->sbuf[0].data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cpia_usb_close(void *privdata)
|
|
||||||
{
|
|
||||||
struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
|
|
||||||
|
|
||||||
if(!ucpia)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
ucpia->open = 0;
|
|
||||||
|
|
||||||
/* ucpia->present = 0 protects against trying to reset the
|
|
||||||
* alt setting if camera is physically disconnected while open */
|
|
||||||
cpia_usb_free_resources(ucpia, ucpia->present);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Probing and initializing */
|
|
||||||
|
|
||||||
static int cpia_probe(struct usb_interface *intf,
|
|
||||||
const struct usb_device_id *id)
|
|
||||||
{
|
|
||||||
struct usb_device *udev = interface_to_usbdev(intf);
|
|
||||||
struct usb_host_interface *interface;
|
|
||||||
struct usb_cpia *ucpia;
|
|
||||||
struct cam_data *cam;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* A multi-config CPiA camera? */
|
|
||||||
if (udev->descriptor.bNumConfigurations != 1)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
interface = intf->cur_altsetting;
|
|
||||||
|
|
||||||
printk(KERN_INFO "USB CPiA camera found\n");
|
|
||||||
|
|
||||||
ucpia = kzalloc(sizeof(*ucpia), GFP_KERNEL);
|
|
||||||
if (!ucpia) {
|
|
||||||
printk(KERN_ERR "couldn't kmalloc cpia struct\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
ucpia->dev = udev;
|
|
||||||
ucpia->iface = interface->desc.bInterfaceNumber;
|
|
||||||
init_waitqueue_head(&ucpia->wq_stream);
|
|
||||||
|
|
||||||
ucpia->buffers[0] = vmalloc(sizeof(*ucpia->buffers[0]));
|
|
||||||
if (!ucpia->buffers[0]) {
|
|
||||||
printk(KERN_ERR "couldn't vmalloc frame buffer 0\n");
|
|
||||||
goto fail_alloc_0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ucpia->buffers[1] = vmalloc(sizeof(*ucpia->buffers[1]));
|
|
||||||
if (!ucpia->buffers[1]) {
|
|
||||||
printk(KERN_ERR "couldn't vmalloc frame buffer 1\n");
|
|
||||||
goto fail_alloc_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ucpia->buffers[2] = vmalloc(sizeof(*ucpia->buffers[2]));
|
|
||||||
if (!ucpia->buffers[2]) {
|
|
||||||
printk(KERN_ERR "couldn't vmalloc frame buffer 2\n");
|
|
||||||
goto fail_alloc_2;
|
|
||||||
}
|
|
||||||
|
|
||||||
ucpia->buffers[0]->next = ucpia->buffers[1];
|
|
||||||
ucpia->buffers[1]->next = ucpia->buffers[2];
|
|
||||||
ucpia->buffers[2]->next = ucpia->buffers[0];
|
|
||||||
|
|
||||||
ret = usb_set_interface(udev, ucpia->iface, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n", ret);
|
|
||||||
/* goto fail_all; */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Before register_camera, important */
|
|
||||||
ucpia->present = 1;
|
|
||||||
|
|
||||||
cam = cpia_register_camera(&cpia_usb_ops, ucpia);
|
|
||||||
if (!cam) {
|
|
||||||
LOG("failed to cpia_register_camera\n");
|
|
||||||
goto fail_all;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock( &cam_list_lock_usb );
|
|
||||||
list_add( &cam->cam_data_list, &cam_list );
|
|
||||||
spin_unlock( &cam_list_lock_usb );
|
|
||||||
|
|
||||||
usb_set_intfdata(intf, cam);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fail_all:
|
|
||||||
vfree(ucpia->buffers[2]);
|
|
||||||
ucpia->buffers[2] = NULL;
|
|
||||||
fail_alloc_2:
|
|
||||||
vfree(ucpia->buffers[1]);
|
|
||||||
ucpia->buffers[1] = NULL;
|
|
||||||
fail_alloc_1:
|
|
||||||
vfree(ucpia->buffers[0]);
|
|
||||||
ucpia->buffers[0] = NULL;
|
|
||||||
fail_alloc_0:
|
|
||||||
kfree(ucpia);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cpia_disconnect(struct usb_interface *intf);
|
|
||||||
|
|
||||||
static struct usb_device_id cpia_id_table [] = {
|
|
||||||
{ USB_DEVICE(0x0553, 0x0002) },
|
|
||||||
{ USB_DEVICE(0x0813, 0x0001) },
|
|
||||||
{ } /* Terminating entry */
|
|
||||||
};
|
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE (usb, cpia_id_table);
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
|
|
||||||
|
|
||||||
static struct usb_driver cpia_driver = {
|
|
||||||
.name = "cpia",
|
|
||||||
.probe = cpia_probe,
|
|
||||||
.disconnect = cpia_disconnect,
|
|
||||||
.id_table = cpia_id_table,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void cpia_disconnect(struct usb_interface *intf)
|
|
||||||
{
|
|
||||||
struct cam_data *cam = usb_get_intfdata(intf);
|
|
||||||
struct usb_cpia *ucpia;
|
|
||||||
|
|
||||||
usb_set_intfdata(intf, NULL);
|
|
||||||
if (!cam)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ucpia = (struct usb_cpia *) cam->lowlevel_data;
|
|
||||||
spin_lock( &cam_list_lock_usb );
|
|
||||||
list_del(&cam->cam_data_list);
|
|
||||||
spin_unlock( &cam_list_lock_usb );
|
|
||||||
|
|
||||||
ucpia->present = 0;
|
|
||||||
|
|
||||||
cpia_unregister_camera(cam);
|
|
||||||
if(ucpia->open)
|
|
||||||
cpia_usb_close(cam->lowlevel_data);
|
|
||||||
|
|
||||||
ucpia->curbuff->status = FRAME_ERROR;
|
|
||||||
|
|
||||||
if (waitqueue_active(&ucpia->wq_stream))
|
|
||||||
wake_up_interruptible(&ucpia->wq_stream);
|
|
||||||
|
|
||||||
ucpia->curbuff = ucpia->workbuff = NULL;
|
|
||||||
|
|
||||||
vfree(ucpia->buffers[2]);
|
|
||||||
ucpia->buffers[2] = NULL;
|
|
||||||
|
|
||||||
vfree(ucpia->buffers[1]);
|
|
||||||
ucpia->buffers[1] = NULL;
|
|
||||||
|
|
||||||
vfree(ucpia->buffers[0]);
|
|
||||||
ucpia->buffers[0] = NULL;
|
|
||||||
|
|
||||||
cam->lowlevel_data = NULL;
|
|
||||||
kfree(ucpia);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init usb_cpia_init(void)
|
|
||||||
{
|
|
||||||
printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
|
|
||||||
CPIA_USB_MAJ_VER,CPIA_USB_MIN_VER,CPIA_USB_PATCH_VER);
|
|
||||||
|
|
||||||
spin_lock_init(&cam_list_lock_usb);
|
|
||||||
return usb_register(&cpia_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit usb_cpia_cleanup(void)
|
|
||||||
{
|
|
||||||
usb_deregister(&cpia_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module_init (usb_cpia_init);
|
|
||||||
module_exit (usb_cpia_cleanup);
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
|||||||
config VIDEO_STRADIS
|
|
||||||
tristate "Stradis 4:2:2 MPEG-2 video driver (DEPRECATED)"
|
|
||||||
depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS && BKL
|
|
||||||
help
|
|
||||||
Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
|
|
||||||
driver for PCI. There is a product page at
|
|
||||||
<http://www.stradis.com/>.
|
|
@ -1,3 +0,0 @@
|
|||||||
obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
|
|
||||||
|
|
||||||
EXTRA_CFLAGS += -Idrivers/media/video
|
|
@ -1,6 +0,0 @@
|
|||||||
This is an obsolete driver for ancient stradis hardware.
|
|
||||||
We couldn't find anyone with this hardware in order to port it to use V4L2.
|
|
||||||
|
|
||||||
If nobody take care on it, the driver will be removed for 2.6.38.
|
|
||||||
|
|
||||||
Please send patches to linux-media@vger.kernel.org
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user