

IMPORTANT NOTE:  version  0.19  supports  color  acquisition, but  the
documentation  doesn't  talk about it.  Sequence  acquisition has been
temporarily disabled as  I have to  check it in its interactions  with
color support.


      pxdrv: a driver for the PXC200 frame grabber by ImageNation
      ===========================================================

This is a short text introducing to the driver's features. I'll try to
produce more featured documentation as time goes by.  Feel free to ask
for features if you  need them: I'll feel  more inclined to write code
if somene is going to use it.  Please note  that the documentation may
not be exactly in sync with the software.
intend to get out of these sources.

This driver is only tested with 2.0.3x. All 2.0.x kernels should work,
support for 2.2 is upcoming.

The latest releases are always available from either of this places:
	ftp://ftp.systemy.it/pub/develop        (original)
	ftp://ftp.prosa.it/pub/people/rubini    (nightly mirror)
	ftp://animal.unipv.it/pub/people/rubini (nightly mirror)

I created two mailing lists related to this project:

	pxc@prosa.it           is devoted to technical discussion
	pxc-announce@prosa.it  is where I announce releases

To get subscribed:

	echo subscribe | mail pxc-request@prosa.it
	echo subscribe | mail pxc-announce-request@prosa.it


GENERAL
=======

Basically,  the driver creates   a  few streams  that can  be  used to
retrieve image data. The devices are created for four grabbers, if you
have more devices,   you need to create   the nodes for them   in /dev
(there are no  limits in the driver, as  allocation of data structures
is dynamic).

The following devices exist for the first grabber (nr. 0)

/dev/pxc0 

	A binary   device,   returning  a continous stream    of   low
	resolution  (single-field) images.  To   avoid  jitter  across
	successive images, only  the even field is grabbed. Continuous
	acquisition can be disabled via  ioctl() commands, so that you
	can    acquire a specific number    of  images, either using a
	hardware  trigger or software  control. A DMA buffer is needed
	in order to be able to read this device.

/dev/pxc0H 

	The hi-res binary node: it returns  a continous stream of high
	resolution  (two fields)   images.   Ioctl() can be  used   to
	configure this device, like /dev/pxc0.  A DMA buffer is needed
	to access this device.

/dev/pxc0pgm 

	The pmg  device associated to the previous  one.  It returns a
	single PGM image,  in  low resolution. You can   just "xv -  <
	/dev/pxc0pgm" to preview your data. Once again, DMA is needed
	to use this device.

/dev/pxc0Hpgm 

	The pgm node that returns an high resolution (two fields)
	gray-scale image.

/dev/pxc0ctl 

	A control   device.  Opening it    doesn't allocate  the   DMA
	buffer. Reading returns the   Bt848 registers; ioctl()  can be
	used as well on this device.

/dev/pxc0rgb
/dev/pxc0Hrgb

	These devices  return a continuous stream  of rgb  color data,
	low   and   high  resolution, respectively.    Each   pixel is
	identified by three data bytes.

/dev/pxc0ppm
/dev/pxc0Hppm

	Color ``portable pixmap'' devices.

/dev/pxc0bgr
/dev/pxc0Hbgr

	The device transfers data in BGR format  instead of RGB. While
	both the "rgb" and "ppm" devices  take care of pixel swapping,
	these  devices do not. They   therefore provide faster access.
	Note  that when you issue  mmap() on a  color  device you will
	alwaysy access BGR data, as the RGB conversion is performed by
	the read() system call.

All of the devices except the control node can be accessed via mmap().

COMPILING
=========

Just "make". If needed, "make install".


LOADING
=======

Use  ./pxc_load  to load the  driver.   Edit  the script  to configure
permission bits and owners of the  devices being created. Any argument
that you pass on the pxc_load command  line are passed to insmod. This
allows load-time configuration of internal variables.

If the driver doesn't detect the pxc200 and you find "unexpected
result" messages in your system logs, please try adding the parameters
"really_pxc200=1". The command will be

	./pxc_load really_pxc200=1

I can't reproduce the errors and I can't tell why they happen, but I
would be interested in knowing whether this option works (actually, it
just tells to ignore the errors).


UNLOADING
=========

./px_unload unloads the driver, shutting down the device.


DEVICE METHODS
==============

The  driver responds to system  calls by  declaring  a table of device
methods.    The following  system calls    are  implemented, with  the
following behaviour.


Open 
----

The  open method  allocates resources. On   first open  the  device is
initialized  and its DMA  engine is programmed for correct opoeration.
Since high resolution (frame  acquisitioon) and low  resolution (field
acquisition) use different DMA programs,  they are incompatible; i.e.,
opening a high-resolutioon device will return EBUSY (device busy) if a
low-resolution  device is  currently  open. The same  incompatibiliity
exists for color vs. B/W mode.

On the  other hand, opening   the control  entry point,  /dev/pxc0ctl,
won't   ever return EBUSY,  so you  can use it  to issue configuration
commands independent of current device setup.

Close 
-----

Nothing strange: closing  the device releases  the resources  it uses.
On  last close the grabber is  shut down unless PX_FLAG_PERSIST is set
(see below, where flags are described).

Read 
----

Reding the device returns acquired data. According to the device being
read  you'll  get  different  results   (see the  device  list above).
Reading the control node returns the BT848 configuration registers, as
a continuous stream of binary data.  After the device is first opened,
the read() system call  will block until  data is available.  This can
take up to two frames.

Write
-----

No write is  implemented.  If and when  it is impemented it will allow
text-mode control of grabber features, without  the need to go through
ioctl().

Select
------

Select should tell whether read() or write() will block. It is currently
unimplemented.

Mmap 
----

You    can memory-map the      image region.  Both low-resolution  and
high-resolution regions  can be memory-mapped.  No  extensive test has
been performed, in particular things may  fail if you close the device
before releasing the mapping. This happens  because open() and close()
are used to control  device initialization and  shutdown even though a
memory map can survive after the  device is closed. Memory-mapping can
be tested by running the "mapper" program, as explained later.

During continuous grabbing (the  default after open()ing the  device),
the  mmap()able region is   as large as one frame   (or field,  if you
access  the  low-res  image).  If  the device  is  instructed to leave
continuous acquisition and  just grab a  few fields instead, you'll be
able to map  exactly that  number  of fields  as a  continuous  memory
region. As of release 0.20, this feature is untested.

Ioctl 
-----

The ioctl() function is supported by  the device, to see and/or change
what is happening in the  internals. A few  of the ioctl commands  are
very low level, and  I'd suggest using them only  if you have hardware
knowledge of the device.

I implemented no kind of protection on the device: you must protect it
using the normal unix permission/owner techniques. It might make sense
to implement some access  restriction in the  device, but I'm not sure
about it.

The following list describes all the commands currently implemented in
the driver. All  of them can be  issued by means of the  "pxc_control"
application as well.

PX_IOCRESET (no arguments needed)

	The command   resets the device by   bringing it down   and up
	again.

PX_IOCHARDRESET (no arguments needed)

	This is mainly a debugging tool: it  decreases the usage count
	of the module  to  one (and  resets  the device as well).  The
	command is needed when oops() happen; in  this case the faulty
	process won't  close the device,  and  the usage count  of the
	module  won't decrease  to  zero any more.  Opening the device
	once more to issue PX_IOCHARDRESET will  bring the usage count
	to zero  when the device will  be closed, thus allowing module
	unload.

PX_IOCGFLAGS (unsigned long * argument)

	Return to user  space the current  value of device  flags. See
	pxc200.h for the meaning of each bit.
		
PX_IOCSFLAGS (unsigned long * argument)

	Set the device  flags from the value  pointed by the argument.
	Only PX_USER_FLAGS are copied to the device.

PX_IOCGDMASIZE (unsigned long * argument)

	Return to user  space the size  of the  DMA buffer, using  the
	pointer argument.

PX_IOCGDMABUF (unsigned long * argument)

	Return to user  space the physical address  of  the DMA buffer
	being used.

PX_IOCGIRQCOUNT (unsigned long * argument)

	Return to   user space  the number  of   interrupts the device
	received.  The counter is reset at each device initialization;
	set PX_FLAG_PERSIST  to avoid  resetting the device  each time
	its user count drops to zero.

PX_IOCGRISCADDE (unsigned long * argument)
PX_IOCGRISCADDO (unsigned long * argument)

	Return tu user space the physical  address of the RISC program
	used to  control data acquisition  for each field.  The driver
	uses two  different physical pages  to store the  programs for
	even-field and odd-field acquisition.

PX_IOCGPROGRAME (void *argument)
PX_IOCGPROGRAMO (void *argument)

	Return to user space  the actual program  used by the RISC DMA
	controller.  The program is at  most one page long (PAGE_SIZE,
	as defined in  <asm/page.h>). Two   different pages (and   two
	different programs are used for the even and the odd field.

PX_IOCGREFV (unsigned long * argument)

	Retrieves  the  reference voltage  set in  the DAC  chip. This
	defaults to 128 at initialization time (i.e., 1.25 volts).
	
PX_IOCSREFV (unsigned long * argument)

	Set the reference  voltage value: the voltage  is used by  the
	By848   to scale  video    samples. The  PXC200  generates the
	reference   using an  8-bit  DAC  powered by   a 2.5V  voltage
	reference.

PX_IOCSMUX (unsigned long * argument)
PX_IOCGMUX (unsigned long * argument)

	These  commands are used  to control the  input multiplexer of
	the  Bt848 chip.  The   chip can  choose between  three   or 4
	(Bt848A) video signals. The default is using  input 0 (the one
	connected to the BNC connector of the PXC200), but this can be
	changed.

PX_IOCSTRIG (unsigned long * argument)

	The   command  is used   to  set   the   trigger mode used  in
	acquisition.    The value pointed  to  by  the  argument  is a
	combination of ther trig-related  flags (which can't be set by
	IOCSFLAGS). No "IOCGTRIG" is there,  as the information can be
	retrieved via "IOCGFLAGS".

	When  trigger  mode is    enabled  or disabled,    any  active
	acquisition  is stopped.  Use  IOCACQNOW to re-enable grabbing
	after disabling trigger  mode. After trigger-mode acquisition,
	another IOCSTRIG must be    actively  issued if you  want   to
	respond to another trigger.

PX_IOCSACQLEN (unsigned long * argument)
PX_IOCGACQLEN (unsigned long * argument)

	These commands  are used to set and  ask  the number of images
	that you want  to grab.  If the number  of images is set to 0,
	continuous acquisition will  apply (the default mode when  you
	open the device). If   the number is  one  or more, only  that
	number of images is  acquired. Acquisition starts either  when
	the hardware trigger  is  received (if the  device is   set in
	trigger mode),  or when PX_IOCACQNOW  is issued.  In any case,
	setting the  acquisition length  disables acquisition -- thus,
	IOCSACQLEN 0 stops continuous grabbing.

	Note that the DMA  buffer must be large enough  to host all of
	the grabbed images (frames or fields, according to whether you
	use the low-res device or the hi-res one).

	You should not change  the acquisition length while mmap()  is
	active, as this changes  the size of the  DMA buffer, and thus
	the active acquisition memory.

PX_IOCACQNOW (no arguments)

	The command  starts acquisition (either continuous acquisition
	or   N images,   according  to IOCSACQLEN   above).    To stop
	grabbing, use IOCSACQLEN.

PX_IOCACWAITVB (unsigned long * argument)

	In continuos grabbing  mode: if the  integer pointed-to by the
	argument is 0,  this command will wait until  a full  image is
	acquired (thus, two vertical blanks in high resolution, one in
	low   resolution).  If the integer  is  not 0, the system call
	only returns after that many images are received.  Thus, 0 and
	1 have the same meaning.

	In ``grab  N images (ACQLEN)''  mode:  the system call returns
	after at  least image number  M  is  grabbed, where M  is  the
	integer   being passed to ioctl().   On  return, the number is
	modified to tell how many images have been grabbed. Therefore,
	a value of 0 can be used to inquire acquisition status without
	introducing delays.
	
	The command can only be used during acquisition, as the driver
	is currently  not able  to  count VB's unless it  is grabbing.
	The command returns an  error of EAGAIN  if no acquisition  is
	active. The system  call can block indefinitely if acquisition
	is  interrupted before it   terminates;   however, it can   be
	interrupted by non-blocked signals.
	
PX_IOCSEQUENCE (Px_AcqControl * argument)

	This command tells the frame grabber to  acquire a sequence of
	images/frames. The   command only works  on  pgm  devices, and
	-EINVAL is  returned if you  invoke  it on  raw devices.  When
	issued on  an  hires device  this instructs to   acquire whole
	frames, when   issued on a low-res  device  this instructs the
	driver  to  acquire fields  (but  always the same  field). The
	structure, defined in pxc200.h, includes the following fields:

	    __u32 flags    Various flags, currently unused.
	    __u32 count    How many images to grab before EOF is seen.
	    __u32 step     Grab one every that many frames (this is
				independent of the camera being PAL
				or NTSC, the user program must make its
				own timing calculations.
	    __u32 buflen   Allocate a vmalloc() buffer that big. The
				number is an image count, so you can
				for example require 50 images using
				a 10-image buffer.

	The command can return -ENOMEM if the requested buffer cannot
	be allocated.

	If this ioctl() returns success,  successive read() calls will
	read from the allocated buffer instead of the current acquired
	image.   This  effectively  allows  to   read   a sequence  of
	evenly-spaced  images to  user  space.  Data  being  read will
	always be in  raw  format, independently  of whether you   are
	reading the  PGM or non-PGM device  node. When every field has
	been transferred to user space, the reader will se EOF.

	If  the device   is  opened  multiple  times,  only one   file
	descriptor  at a time can acquire  a sequence. This means that
	you  can spawn  acquisition of a   sequence  even while  other
	program are  accessing the device  in the default way.  If you
	invoke  IOCSEQUENCE  on a  device  that already has a sequence
	defined, you'll get -EBUSY.

	Acquisition of     a sequence is     terminated at file close.
	Disabling   an ongoing  sequence   to get   back to continuous
	acquisitionis not possible at the time being.

	The command is used in pxc_grab.

PX_IOCGHWOVERRUN (unsigned long * argument)

	Returns   to   user space the  number     of hardware overruns
	experienced up to now.  The counter is reset at device bringup
	time (see the description of IOCGIRQCOUNT above).

PX_IOCGSWOVERRUN (unsigned long * argument)

	Returns to  user     space the number    of  software overruns
	experienced up to now.  The counter is reset at device bringup
	time (see the   description of  IOCGIRQCOUNT  above). Software
	overruns can only happen during sequence acquisition.


SAMPLE APPLICATIONS
===================

The  following sample  applications are  distributed with  the driver.
All of them  open a file in  /dev, the file will be  taken from either
the first or last argument in  the command line, from PXCDEVICE in the
environment or from a compiled in default.

./pxc_status 

	Show   the  current   status  of   the  device   (through  the
	informational  registers).  Since this  is quite  fussy, you'd
	better  grep  for the  information  you  need (information  is
	organized by  lines).  The  program uses /dev/pxc0ctl  (or the
	control  file  associated  to  another  grabber)  to  retrieve
	information, and  will complain if  the file is not  a control
	entry point.

./pxc_control 

	This  tool is a frontend to  the ioctl() method of the device.
	Call it without arguments to get a list of supported commands.
	I do my best to implement here any command I add to the kernel
	driver (I don't like to compile special  programs just to test
	things out, shell  scripts are easier).  The device being used
	for control operation is specified on  the command line (first
	or last  argument),  retrieved  from the environment  variable
	PXCDEVICE or /dev/pxc0ctl by default.

./pxc_show 

	The program displays on a  text screen a live-video display of
	the data being grabbed.  It reads data from a PGM device so it
	can adapt to  the real image size, whether it  is NTSC or PAL.
	This is different from  earlier versione (pre-0.21) which used
	the raw entry point and couldn't tell what the image size was.

./pxc_live 

	A simple live-video  application.  It uses either  the "pacco"
	tool      (a     GPL         package,   available         from
	ftp://ftp.prosa.it/pub/software/pacco)  or the photo widget of
	tk  (the photo  widget   is  slower).   Part of this   code is
	contributed by Daniel  Scharstein.  The  device being used  is
	retrieved from the command line, from the environment variable
	PXCDEVICE  or defaults  to /dev/pxc0pgm.    Both  pgm and  ppm
	devices   will  work (currently pacco    only  works with  pgm
	devices).

./pxc_grab 

	A command line tool for grabbing to disk. Use the '-h' option
	to see how it works, or check source code for pxc_xgrab.

./pxc_xgrab 

	An X tool to grab to disk, an ehanced pxc_live which relies on
	pxc_grab.  The current version  is only tested using the Pacco
	tool (ftp.systemy.it/pub/develop)  and there are  some pending
	bugs  when using  the photo  widget.  It  only works  with b/w
	devices.

./mapper 

	A basic mmap() engine:   it prints to    stdout data that   is
	accessed via memory map.  It takes three  arguments: filename,
	starting offset and  final offset. To  try out memory mapping,
	run the following commandline:

		./mapper /dev/pxc0H 0 `expr 640 "*" 480` | \
			rawtopgm 640 480 | xv -

	Note that this won't work with PAL cameras unless you tune the
	numeric arguments.

MISSING FEATURES
================

Some features are  missing. Some of  them are just "not yet" features,
and some are missing by design --  i.e., I have  no plans to implement
them in the  near future, unless someone  shows interest in them. This
section describes only  those kind of  deficiencies (or ideas that are
not scheduled to be implemented).

Regions of interest
-------------------

There's no  support for acquiring  subregions of an image: this driver
grabs  either whole  fields  or whole   frames.  Grabbing regions will
definitely be implemented, as I'm going to use  three PXC200 boards in
an university project.

Anything else
-------------

No support for controlling gain, contrast, etc., by now.

THE DMA BUFFER
==============

One of the most compelling problems with any DMA-capable device is the
allocation  of a suitable memory   buffer.  The pxc200  driver uses  a
module of mine, called "allocator".  The allocator is able to use high
memory (above the one used in normal operation) for DMA allocation.

To prevent  the  kernel for using   high memory,  so  that it  remains
available for  DMA, you should  pass a  command  line argument to  the
kernel.  Command line arguments  can be passed to  Lilo, to Loadlin or
to whichever loader  you are using  (unless it's very poor in design).
For Lilo, either use  "append=" in  /etc/lilo.conf or add  commandline
arguments to the  interactive prompt. For  example, I have a 32MB  box
and reserve one meg for DMA:

In lilo.conf:
        image = /zImage
        label = linux
        append = "mem=31M"

Or, interactively:
        LILO: linux mem=31M




Enjoy
/alessandro
--
    __ o       Tu vuo` fa` l'americano: sient'a me chi t'o fa fa`.
   _`\<,                                            (Renato Carosone)
__( )/( )__ alessandro.rubini@linux.it  +39-382-529554


