diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-19 01:28:40 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-19 01:28:40 +0000 |
commit | 8abb719409c9060a7c0676f76e9182c1e0b8ca46 (patch) | |
tree | b88cc5a6cd513a04a512b7e6215c873c90a1c5dd /Documentation | |
parent | f01bd7aeafd95a08aafc9e3636bb26974df69d82 (diff) |
Merge with 2.3.99-pre1.
Diffstat (limited to 'Documentation')
-rw-r--r-- | Documentation/Configure.help | 364 | ||||
-rw-r--r-- | Documentation/DocBook/Makefile | 29 | ||||
-rw-r--r-- | Documentation/DocBook/mcabook.tmpl | 105 | ||||
-rw-r--r-- | Documentation/DocBook/parport-multi.fig | 59 | ||||
-rw-r--r-- | Documentation/DocBook/parport-share.fig | 154 | ||||
-rw-r--r-- | Documentation/DocBook/parport-structure.fig | 60 | ||||
-rw-r--r-- | Documentation/DocBook/parportbook.sgml | 1747 | ||||
-rw-r--r-- | Documentation/DocBook/videobook.tmpl | 1663 | ||||
-rw-r--r-- | Documentation/DocBook/wanbook.tmpl | 97 | ||||
-rw-r--r-- | Documentation/DocBook/z8530book.tmpl | 383 | ||||
-rw-r--r-- | Documentation/networking/comx.txt | 248 | ||||
-rw-r--r-- | Documentation/networking/dmfe.txt | 63 | ||||
-rw-r--r-- | Documentation/sound/ALS | 43 | ||||
-rw-r--r-- | Documentation/sound/Maestro | 29 | ||||
-rw-r--r-- | Documentation/usb/ov511.txt | 160 | ||||
-rw-r--r-- | Documentation/video4linux/CQcam.txt | 414 | ||||
-rw-r--r-- | Documentation/video4linux/bttv/README | 2 |
17 files changed, 5555 insertions, 65 deletions
diff --git a/Documentation/Configure.help b/Documentation/Configure.help index cee6bef35..64bdd50f2 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -2109,6 +2109,13 @@ CONFIG_SYSVIPC section 6.4 of the Linux Programmer's Guide, available from http://www.linuxdoc.org/docs.html#guide . + Shared memory is now implemented using a new (minimal) virtual file + system, which you need to mount before programs can use shared memory. + To do this automatically at system startup just add the following line + to your /etc/fstab: + + none /var/shm shm defaults 0 0 + Saying Y here enlarges your kernel by about 18 KB. Just say Y. BSD Process Accounting @@ -2546,6 +2553,16 @@ CONFIG_FBCON_FONTWIDTH8_ONLY Answer Y here will make the kernel provide only the 8x8 fonts (these are the less readable). +Sparc console 8x16 font +CONFIG_FONT_SUN8x16 + This is the high resolution console font for Sun machines. Say Y. + +Sparc console 12x22 font (not supported by all drivers) +CONFIG_FONT_SUN12x22 + This is the high resolution console font for Sun machines with very big + letters (like the letters used in the SPARC PROM). If the standard font + is unreadable for you, say Y, otherwise say N. + VGA 8x8 font CONFIG_FONT_8x8 This is the "high resolution" font for the VGA frame buffer (the one @@ -2877,6 +2894,12 @@ CONFIG_PARPORT_PC_FIFO FIFO. See Documentation/parport.txt to find out how to specify which IRQ/DMA to use. +SuperIO chipset support (EXPERIMENTAL) +CONFIG_PARPORT_PC_SUPERIO + Saying Y here enables some probes for Super-IO chipsets in order to + find out things like base addresses, IRQ lines and DMA channels. It + is safe to say N. + Support for PCMCIA management for PC-style ports CONFIG_PARPORT_PC_PCMCIA Say Y here if you need PCMCIA support for your PC-style parallel @@ -4478,18 +4501,6 @@ CONFIG_CHR_DEV_ST module, say M here and read Documentation/modules.txt and Documentation/scsi.txt . -Extra SCSI Tapes -CONFIG_ST_EXTRA_DEVS - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In the - event that the SCSI core itself was loaded as a module, this this value - is the number of additional tape devices that can be loaded after the - first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - SCSI CDROM support CONFIG_BLK_DEV_SR If you want to use a SCSI CDROM under Linux, say Y and read the @@ -5650,21 +5661,55 @@ CONFIG_FC4 the system using Fibre Optic and the "X3.269-199X Fibre Channel Protocol for SCSI" specification. You'll also need the generic SCSI support, as well as the drivers for the storage array itself and - for the interface adapter such as SOC. This subsystem could even - serve for IP networking, with some code extensions. - - If unsure, say N. + for the interface adapter such as SOC or SOC+. This subsystem could even + serve for IP networking, with some code extensions. If unsure, say N. Sun SOC CONFIG_FC4_SOC Serial Optical Channel is an interface card with one or two Fibre - Optic ports, each of which can be connected to a disk array. Only - the SBus incarnation of the adapter is supported at the moment. + Optic ports, each of which can be connected to a disk array. Note that + if you have older firmware in the card, you'll need the microcode from + the Solaris driver to make it work. + + This support is also available as a module called soc.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Sun SOC+ (aka SOCAL) +CONFIG_FC4_SOCAL + Serial Optical Channel Plus is an interface card with up to two Fibre + Optic ports. This card supports FC Arbitrated Loop (usually A5000 or + internal FC disks in E[3-6]000 machines through the Interface Board). + You'll probably need the microcode from the Solaris driver to make it + work. + + This support is also available as a module called socal.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. SparcSTORAGE Array 100 and 200 series CONFIG_SCSI_PLUTO If you never bought a disk array made by Sun, go with N. + This support is also available as a module called pluto.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Sun Enterprise Network Array (A5000 and EX500) +CONFIG_SCSI_FCAL + This driver drives FC-AL disks connected through a Fibre Channel card + using the drivers/fc4 layer (currently only SOCAL). + The most common is either A5000 array or internal disks in E[3-6]000 + machines. + + This support is also available as a module called fcal.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. If unsure, say N. + AcornSCSI support CONFIG_SCSI_ACORNSCSI_3 This enables support for the Acorn SCSI card (aka30). If you have an @@ -6185,16 +6230,6 @@ CONFIG_PCMCIA_3C575 The module will be called 3c575_cb.o. If you want to do that, say M here and read Documentation/modules.txt. If unsure, say N. -DEC Tulip CardBus support -CONFIG_PCMCIA_TULIP - This driver supports CardBus Fast Ethernet adapters based on DEC - Tulip and compatible chipsets. - - This driver can only be compiled as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called tulip_cb.o. If you want to do that, say M - here and read Documentation/modules.txt. If unsure, say N. - SMC EPIC CardBus support CONFIG_PCMCIA_EPIC100 This driver supports CardBus Fast Ethernet adapters based on the SMC @@ -6809,6 +6844,77 @@ CONFIG_WANPIPE_PPP you say N, the PPP support will not be included in the driver (saves about 16 KB of kernel memory). +MultiGate/COMX support +CONFIG_COMX + Say Y if you want to use any board from the MultiGate (COMX) family. + These boards are synchronous serial adapters for the PC, manufactured + by ITConsult-Pro Co, Hungary. + + Read linux/Documentation/networking/comx.txt for help on configuring + and using COMX interfaces. Further info on these cards can be found at + http://www.itc.hu or <info@itc.hu>. + + If you want to compile this as a module, say M and read + Documentation/modules.txt. The module will be called comx.o. + +COMX/CMX/HiCOMX board support +CONFIG_COMX_HW_COMX + Hardware driver for the 'CMX', 'COMX' and 'HiCOMX' boards from the + MultiGate family. Say Y if you have one of these. + + You will need additional firmware to use these cards, which are + downloadable from ftp://ftp.itc.hu/. + + If you want to compile this as a module, say M and read + Documentation/modules.txt. The module will be called comx-hw-comx.o. + +LoCOMX board support +CONFIG_COMX_HW_LOCOMX + Hardware driver for the 'LoCOMX' board from the MultiGate family. Say Y + if you have a board like this. + + If you want to compile this as a module, say M and read + Documentation/modules.txt. The module will be called comx-hw-locomx.o. + +MixCOM board support +CONFIG_COMX_HW_MIXCOM + Hardware driver for the 'MixCOM' board from the MultiGate family. Say Y + if you have a board like this. + + If you want to use the watchdog device on this card, you should + select it in the Watchdog Cards section of the Character Devices + configuration. The ISDN interface of this card is Teles 16.3 compatible, + you should enable it in the ISDN configuration menu. The driver for the + flash ROM of this card is available separately on ftp://ftp.itc.hu/. + + If you want to compile this as a module, say M and read + Documentation/modules.txt. The module will be called comx-hw-mixcom.o. + +MultiGate Cisco-HDLC and synchronous PPP protocol support +CONFIG_COMX_PROTO_PPP + Cisco-HDLC and synchronous PPP protocol driver for all MultiGate boards. + Say Y if you want to use either protocol on your MultiGate boards. + + If you want to compile this as a module, say M and read + Documentation/modules.txt. The module will be called + comx-proto-ppp.o. + +MultiGate LAPB protocol support +CONFIG_COMX_PROTO_LAPB + LAPB protocol driver for all MultiGate boards. Say Y if you + want to use this protocol on your MultiGate boards. + + If you want to compile this as a module, say M and read + Documentation/modules.txt. The module will be called comx-proto-lapb.o. + +MultiGate Frame Relay protocol support +CONFIG_COMX_PROTO_FR + Frame Relay protocol driver for all MultiGate boards. Say Y if you + want to use this protocol on your MultiGate boards. + + If you want to compile this as a module, say M and read + Documentation/modules.txt. The module will be called comx-proto-fr.o. + Cyclom 2X(tm) multiprotocol cards (EXPERIMENTAL) CONFIG_CYCLADES_SYNC Cyclom 2X from Cyclades Corporation (http://www.cyclades.com and @@ -7162,6 +7268,10 @@ CONFIG_SK98LIN say M here and read Documentation/modules.txt. This is recommended. The module will be called sk98lin.o. +MyriCOM Gigabit Ethernet support +CONFIG_MYRI_SBUS + This driver supports MyriCOM Sbus gigabit ethernet cards. + AMD LANCE and PCnet (AT1500 and NE2100) support CONFIG_LANCE If you have a network (Ethernet) card of this type, say Y and read @@ -7943,6 +8053,19 @@ CONFIG_IBMOL Linux Token Ring Project site for the latest information at http://www.linuxtr.net +IBM Lanstreamer chipset PCI adapter support +CONFIG_IBMLS + This is support for IBM Lanstreamer PCI Token Ring Cards. + + If you have such an adapter, say Y and read the Token-Ring mini-HOWTO + available via FTP (user:anonymous) from + ftp://metalab.unc/edu/pub/Linux/docs/HOWTO. + + This driver is also available as a modules ( = code which can be + inserted in and removed from the running kernel whenever you want). + The modules will be called lanstreamer.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + Generic TMS380 Token Ring ISA/PCI/MCA/EISA adapter support CONFIG_TMS380TR This driver provides generic support for token ring adapters @@ -7989,6 +8112,49 @@ CONFIG_SMCTR read the Token-Ring mini-HOWTO, available from http://www.linuxdoc.org/docs.html#howto . +Sun Happy Meal 10/100baseT support +CONFIG_HAPPYMEAL + This driver supports the "hme" interface present on most Ultra systems + and as an option on older Sbus systems. This driver supports both PCI + and Sbus devices. This driver also supports the "qfe" quad 100baseT + device available in both PCI and Sbus configurations. + + This support is also available as a module called sunhme.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Sun Lance support +CONFIG_SUNLANCE + This driver supports the "le" interface present on all 32-bit Sparc + systems, on some older Ultra systems and as an Sbus option. + + This support is also available as a module called sunlance.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Sun BigMAC 10/100baseT support (EXPERIMENTAL) +CONFIG_SUNBMAC + This driver supports the "be" interface available as an Sbus option. + This is Sun's older 100baseT ethernet device. + + This support is also available as a module called sunbmac.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Sun QuadEthernet support +CONFIG_SUNQE + This driver supports the "qe" 10baseT ethernet device, available as + an Sbus option. Note that this is not the same as Quad FastEthernet + "qfe" which is supported by the Happy Meal driver instead. + + This support is also available as a module called sunqe.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + Traffic Shaper (EXPERIMENTAL) CONFIG_SHAPER The traffic shaper is a virtual network device that allows you to @@ -8778,7 +8944,25 @@ CONFIG_USB_RIO500 inserted in and removed from the running kernel whenever you want). The module will be called rio500.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. - + +D-Link DSB-R100 FM radio upport +CONFIG_USB_DSBR + Say Y here if you want to connect this type of radio to your + computer's USB port. Note that the audio is not digital, and + you must connect the line out connector to a sound card or a + set of speakers. + + This driver uses the Video For Linux API. You must enable + (Y or M in config) Video For Linux (under Character Devices) + to use this driver. Information on this API and pointers to + "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dsbr100.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + ACPI support CONFIG_ACPI Advanced Configuration and Power Interface (ACPI) is an interface @@ -12465,7 +12649,24 @@ CONFIG_SUN4 SPARC ESP SCSI support CONFIG_SCSI_SUNESP This is the driver for the Sun ESP SCSI host adapter. The ESP - chipset is present in most SPARC-based computers. + chipset is present in most SPARC SBUS-based computers. + + This support is also available as a module called esp.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +PTI Qlogic, ISP Driver +CONFIG_SCSI_QLOGICPTI + This driver supports SBUS SCSI controllers from PTI or QLogic. These + controllers are known under Solaris as qpti and in the openprom as + PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are driven + by a different driver. + + This support is also available as a module called qlogicpti.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. SPARC /dev/openprom compatibility driver (EXPERIMENTAL) CONFIG_SUN_OPENPROMIO @@ -12477,24 +12678,101 @@ CONFIG_SUN_OPENPROMIO inserted in and removed from the running kernel whenever you want), say M and read Documentation/modules.txt. If unsure, say Y. +Openprom tree appears in /proc/openprom +CONFIG_SUN_OPENPROMFS + If you say Y, the OpenPROM device tree will be available as a virtual + file system, which you can mount to /proc/openprom by + "mount -t openpromfs none /proc/openprom". + + If you want to compile the /proc/openprom support as a module ( = code + which can be inserted in and removed from the running kernel whenever + you want), say M here and read Documentation/modules.txt. The module + will be called openpromfs.o. If unsure, say M. + +Kernel support for Linux/Sparc 32bit binary compatibility +CONFIG_SPARC32_COMPAT + This allows you to run 32-bit binaries on your Ultra. + Everybody wants this; say Y. + +Kernel support for 32-bit ELF binaries +CONFIG_BINFMT_ELF32 + This allows you to run 32-bit Linux/ELF binaries on your Ultra. + Everybody wants this; say Y. + +Kernel support for 32-bit (ie. SunOS) a.out binaries +CONFIG_BINFMT_AOUT32 + This allows you to run 32-bit a.out format binaries on your Ultra. + If you want to run SunOS binaries (see SunOS binary emulation below) + or other a.out binaries, say Y. If unsure, say N. + +SunOS binary emulation +CONFIG_SUNOS_EMUL + This allows you to run most SunOS binaries. If you want to do this, + say Y here and place appropriate files in /usr/gnemul/sunos. See + http://www.ultralinux.org/faq.html for more information. If you want + to run SunOS binaries on an Ultra you must also say Y to "Kernel + support for 32-bit a.out binaries" above. + Mostek real time clock support CONFIG_SUN_MOSTEK_RTC - The Mostek RTC chip is used on all knows Sun computers except + The Mostek RTC chip is used on all known Sun computers except some JavaStations. For a JavaStation you need to say Y both here and to "Enhanced Real Time Clock Support". Say Y here unless you are building a special purpose kernel. +OBP Flash Device support +CONFIG_OBP_FLASH + The OpenBoot PROM on Ultra systems is flashable. If you want to be + able to upgrade the OBP firmware, say Y here. + JavaStation OS Flash SIMM (EXPERIMENTAL) CONFIG_SUN_JSFLASH This option enables a driver for JavaStation OS Flash driver. Say N unless you want to boot from your Flash SIMM. -#Siemens SAB82532 serial support -#CONFIG_SAB82532 -### -### Please someone fill these in. -### +Siemens SAB82532 serial support +CONFIG_SAB82532 + This driver supports the serial ports on newer (PCI) Ultra systems. + Say Y if you want to be able to use your serial ports. + +Aurora Multiboard 1600se (EXPERIMENTAL) +CONFIG_SUN_AURORA + The Aurora Multiboard is a multi-port high-speed serial controller. + If you have one of these, say Y. + +Audio support (EXPERIMENTAL) +CONFIG_SPARCAUDIO + This driver provides support for the build-in sound devices on most + Sun machines. If you want to be able to use this, select this option + and one or more of the lowlevel drivers below. See + http://www.dementia.org/~shadow/sparcaudio.html for more information. + +AMD7930 Lowlevel Driver +CONFIG_SPARCAUDIO_AMD7930 + This driver supports the AMD 7930 chip found on sun4c, 4/6xx, and + SparcClassic systems. + +CS4231 Lowlevel Driver +CONFIG_SPARCAUDIO_CS4231 + This driver supports the Crystal Semiconductor CS4231 chip found on + the SS4, SS5, and Ultras. + +DBRI Lowlevel Driver +CONFIG_SPARCAUDIO_DBRI + This driver supports the DBRI audio interface found on the SS10, SS20, + Sparcbook 3, and Voyager systems. + +Dummy lowlevel Driver +CONFIG_SPARCAUDIO_DUMMY + This is a pseudo-driver used for debugging and testing the sparcaudio + subsystem. Say N unless you want to work on this subsystem. + +Sparc hardware (EXPERIMENTAL) +CONFIG_PARPORT_SUNBPP + This driver provides support for the bidirectional parallel port found + on many Sun machines. Note that many of the newer Ultras actually have + pc style hardware instead. IEEE 1394 (aka FireWire) support CONFIG_IEEE1394 @@ -13629,6 +13907,20 @@ Include support for the NetWinder CONFIG_ARCH_NETWINDER Say Y here if you intend to run this kernel on the NetWinder. +Include support for the Compaq Personal Server +CONFIG_PERSONAL_SERVER + Say Y here if you intend to run this kernel on the Compaq + Personal Server. + + The Compaq Personal Server is not available for purchase. + There are no product plans beyond the current research + prototypes at this time. Information is available at: + + http://crl.research.compaq.com/projects/personalserver + + If you have any questions or comments about the Compaq Personal + Server, send e-mail to skiff@crl.dec.com + Virtual/Physical Memory Split CONFIG_1GB If you are compiling a kernel which will never run on a machine diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile new file mode 100644 index 000000000..6bc727e43 --- /dev/null +++ b/Documentation/DocBook/Makefile @@ -0,0 +1,29 @@ +BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml + +books: docproc $(BOOKS) + +docproc: + $(MAKE) -C $(TOPDIR)/scripts docproc + +wanbook.sgml: wanbook.tmpl + $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/wan/syncppp.c \ + <wanbook.tmpl >wanbook.sgml + +z8530book.sgml: z8530book.tmpl + $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/wan/syncppp.c \ + <z8530book.tmpl >z8530book.sgml + +mcabook.sgml: mcabook.tmpl + $(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \ + <mcabook.tmpl >mcabook.sgml + +videobook.sgml: videobook.tmpl + $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/char/videodev.c \ + <videobook.tmpl >videobook.sgml + +clean: + rm -f core *~ + rm -r $(BOOKS) + +include $(TOPDIR)/Rules.make + diff --git a/Documentation/DocBook/mcabook.tmpl b/Documentation/DocBook/mcabook.tmpl new file mode 100644 index 000000000..a8902e333 --- /dev/null +++ b/Documentation/DocBook/mcabook.tmpl @@ -0,0 +1,105 @@ +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]> + +<book id="MCAGuide"> + <bookinfo> + <title>MCA Driver Programming Interface</title> + + <authorgroup> + <author> + <firstname>Alan</firstname> + <surname>Cox</surname> + <affiliation> + <address> + <email>alan@redhat.com</email> + </address> + </affiliation> + </author> + <author> + <firstname>David</firstname> + <surname>Weinehall</surname> + </author> + <author> + <firstname>Chris</firstname> + <surname>Beauregard</surname> + </author> + </authorgroup> + + <copyright> + <year>2000</year> + <holder>Alan Cox</holder> + <holder>David Weinehall</holder> + <holder>Chris Beauregard</holder> + </copyright> + + <legalnotice> + <para> + This documentation 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. + </para> + + <para> + 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. + </para> + + <para> + 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., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + </para> + + <para> + For more details see the file COPYING in the source + distribution of Linux. + </para> + </legalnotice> + </bookinfo> + +<toc></toc> + + <chapter id="intro"> + <title>Introduction</title> + <para> + The MCA bus functions provide a generalised interface to find MCA + bus cards, to claim them for a driver, and to read and manipulate POS + registers without being aware of the motherboard internals or + certain deep magic specific to onboard devices. + </para> + <para> + The basic interface to the MCA bus devices is the slot. Each slot + is numbered and virtual slot numbers are assigned to the internal + devices. Using a pci_dev as other busses do does not really make + sense in the MCA context as the MCA bus resources require card + specific interpretation. + </para> + <para> + Finally the MCA bus functions provide a parallel set of DMA + functions mimicing the ISA bus DMA functions as closely as possible, + although also supporting the additional DMA functionality on the + MCA bus controllers. + </para> + </chapter> + <chapter id="bugs"> + <title>Known Bugs And Assumptions</title> + <para> + None. + </para> + </chapter> + + <chapter id="pubfunctions"> + <title>Public Functions Provided</title> +!Earch/i386/kernel/mca.c + </chapter> + + <chapter id="dmafunctions"> + <title>DMA Functions Provided</title> +!Iinclude/asm-i386/mca_dma.h + </chapter> + +</book> diff --git a/Documentation/DocBook/parport-multi.fig b/Documentation/DocBook/parport-multi.fig new file mode 100644 index 000000000..e0517b36f --- /dev/null +++ b/Documentation/DocBook/parport-multi.fig @@ -0,0 +1,59 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +6 1425 4350 5175 5475 +6 3450 5100 4425 5475 +2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 + 4425 5475 4425 5100 3450 5100 3450 5475 4425 5475 +4 0 0 50 0 0 12 0.0000 4 135 510 3600 5400 Printer\001 +-6 +6 3375 4350 5175 4725 +2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 + 5175 4725 5175 4350 3375 4350 3375 4725 5175 4725 +4 0 0 50 0 0 12 0.0000 4 180 870 3825 4650 Multiplexor\001 +-6 +6 1425 4650 2775 5475 +6 1425 4650 2775 5475 +2 4 0 1 0 7 50 0 -1 0.000 0 0 6 0 0 5 + 2757 5475 2757 4650 1425 4650 1425 5475 2757 5475 +4 0 0 50 0 0 12 0.0000 4 180 735 1725 5100 Computer\001 +-6 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 2775 4875 2700 4875 2700 5025 2775 5025 2775 4875 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 2775 5175 2700 5175 2700 5325 2775 5325 2775 5175 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 2775 4950 3600 4725 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 2775 5250 3450 5325 +-6 +6 3150 2625 4125 3525 +2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 + 4125 3075 4125 2625 3150 2625 3150 3075 4125 3075 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 3675 3075 3675 3525 +4 0 0 50 0 0 12 0.0000 4 135 510 3300 2925 Printer\001 +-6 +6 4275 3450 5250 4350 +2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 + 5250 3900 5250 3450 4275 3450 4275 3900 5250 3900 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 4800 3900 4800 4350 +4 0 0 50 0 0 12 0.0000 4 135 510 4425 3750 Printer\001 +-6 +2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 + 3900 4050 3900 3525 3375 3525 3375 4050 3900 4050 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 3675 4050 3675 4350 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 3600 4350 3750 4350 3750 4425 3600 4425 3600 4350 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 4725 4350 4875 4350 4875 4425 4725 4425 4725 4350 +4 0 0 50 0 0 12 0.0000 4 135 285 3450 3900 ZIP\001 diff --git a/Documentation/DocBook/parport-share.fig b/Documentation/DocBook/parport-share.fig new file mode 100644 index 000000000..fe4f37322 --- /dev/null +++ b/Documentation/DocBook/parport-share.fig @@ -0,0 +1,154 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +0 32 #8e8e8e +0 33 #8e8e8e +0 34 #aeaaae +0 35 #515551 +0 36 #414141 +0 37 #868286 +0 38 #8e8e8e +0 39 #414141 +0 40 #868286 +0 41 #c7c3c7 +0 42 #e7e3e7 +0 43 #414141 +0 44 #868286 +0 45 #c7c3c7 +0 46 #e7e3e7 +0 47 #868286 +0 48 #c7c3c7 +0 49 #e7e3e7 +6 1200 3000 2250 4950 +6 1275 3150 2175 3675 +6 1312 3487 1837 3637 +2 1 0 1 40 -1 19 0 -1 0.000 2 0 -1 0 0 5 + 1312 3562 1312 3524 1474 3524 1474 3487 1675 3487 +2 1 0 1 40 -1 19 0 -1 0.000 2 0 -1 0 0 3 + 1474 3637 1474 3562 1675 3562 +2 1 0 1 40 -1 19 0 -1 0.000 2 0 -1 0 0 2 + 1675 3524 1837 3524 +2 1 0 1 7 -1 19 0 -1 0.000 2 0 -1 0 0 2 + 1675 3487 1675 3524 +2 1 0 1 7 -1 19 0 -1 0.000 2 0 -1 0 0 2 + 1312 3562 1474 3562 +2 1 0 1 7 -1 19 0 -1 0.000 2 0 -1 0 0 5 + 1474 3637 1675 3637 1675 3562 1837 3562 1837 3524 +2 1 0 1 40 -1 19 0 -1 0.000 2 0 -1 0 0 3 + 1716 3637 1797 3637 1797 3600 +2 1 0 1 7 -1 19 0 -1 0.000 2 0 -1 0 0 3 + 1716 3637 1716 3600 1797 3600 +-6 +6 1413 3345 2070 3397 +6 1994 3352 2070 3390 +2 1 0 1 7 40 19 0 -1 0.000 2 0 -1 0 0 3 + 1994 3390 1994 3352 2070 3352 +2 1 0 1 40 -1 19 0 -1 0.000 2 0 -1 0 0 3 + 1994 3390 2070 3390 2070 3352 +-6 +6 1531 3353 1643 3389 +2 2 0 0 40 41 19 0 20 0.000 2 0 -1 0 0 5 + 1568 3353 1606 3353 1606 3389 1568 3389 1568 3353 +2 2 0 0 40 39 19 0 20 0.000 2 0 -1 0 0 5 + 1606 3353 1643 3353 1643 3389 1606 3389 1606 3353 +2 2 0 0 40 41 19 0 20 0.000 2 0 -1 0 0 5 + 1568 3353 1531 3353 1531 3389 1568 3389 1568 3353 +-6 +6 1413 3345 1465 3397 +1 3 0 0 0 39 18 0 20 0.000 1 0.0000 1439 3371 26 26 1439 3371 1439 3397 +1 3 0 0 40 41 18 0 20 0.000 1 0.0000 1439 3371 15 15 1439 3371 1443 3385 +-6 +2 2 0 0 40 7 19 0 20 0.000 2 0 -1 0 0 3 + 1950 3371 1875 3371 1950 3371 +2 2 0 0 40 41 19 0 20 0.000 2 0 -1 0 0 5 + 1945 3384 1896 3384 1896 3357 1945 3357 1945 3384 +-6 +6 1350 3183 2100 3300 +2 1 0 1 7 40 19 0 -1 0.000 2 0 -1 0 0 3 + 1350 3300 1350 3183 2100 3183 +2 1 0 1 40 -1 19 0 -1 0.000 2 0 -1 0 0 3 + 1350 3300 2100 3300 2100 3183 +-6 +2 1 0 1 7 7 19 0 -1 0.000 2 0 -1 0 0 5 + 1275 3675 1875 3675 1875 3450 2175 3450 2175 3150 +2 1 0 1 40 7 19 0 -1 0.000 2 0 -1 0 0 3 + 1275 3675 1275 3150 2175 3150 +-6 +6 1950 3750 2175 3975 +5 1 0 1 7 7 19 0 -1 0.000 0 0 0 0 2038.000 3900.000 1985 3953 1985 3847 2091 3847 +5 1 0 1 40 7 19 0 -1 0.000 0 1 0 0 2038.000 3900.000 1985 3953 2091 3953 2091 3847 +-6 +6 1200 4050 1800 4800 +2 1 0 2 40 7 19 0 -1 0.000 2 1 -1 0 0 2 + 1275 4125 1725 4125 +2 1 0 2 40 7 19 0 -1 0.000 2 1 -1 0 0 2 + 1275 4200 1725 4200 +2 1 0 2 40 7 19 0 -1 0.000 2 1 -1 0 0 2 + 1275 4275 1725 4275 +2 1 0 2 40 7 19 0 -1 0.000 2 1 -1 0 0 2 + 1275 4350 1725 4350 +2 1 0 2 40 7 19 0 -1 0.000 2 1 -1 0 0 2 + 1275 4425 1725 4425 +2 1 0 2 40 7 19 0 -1 0.000 2 1 -1 0 0 2 + 1275 4500 1725 4500 +2 1 0 2 40 7 19 0 -1 0.000 2 1 -1 0 0 2 + 1275 4575 1725 4575 +2 1 0 2 40 7 19 0 -1 0.000 2 1 -1 0 0 2 + 1275 4650 1725 4650 +2 1 0 2 40 7 19 0 -1 0.000 2 1 -1 0 0 2 + 1275 4725 1725 4725 +-6 +2 2 0 1 0 39 20 0 20 0.000 2 0 -1 0 0 5 + 1200 4950 1425 4950 1425 4911 1200 4911 1200 4950 +2 2 0 1 0 39 20 0 20 0.000 2 0 -1 0 0 5 + 2025 4950 2250 4950 2250 4911 2025 4911 2025 4950 +2 2 0 1 0 42 20 0 20 0.000 2 0 -1 0 0 5 + 1200 4907 2250 4907 2250 3000 1200 3000 1200 4907 +-6 +6 2374 3225 3375 4050 +3 2 0 1 0 37 50 0 -1 0.000 0 0 0 3 + 2374 3402 3139 3402 3257 4050 + 0.000 -1.000 0.000 +3 2 0 1 0 37 50 0 -1 0.000 0 0 0 3 + 2374 3461 3096 3437 3198 4050 + 0.000 -1.000 0.000 +-6 +2 2 0 1 0 1 50 0 20 0.000 0 0 -1 0 0 5 + 2925 4575 4050 4575 4050 4875 2925 4875 2925 4575 +2 3 0 1 0 32 50 0 20 0.000 0 0 -1 0 0 5 + 1200 3000 1575 2475 2400 2475 2250 3000 1200 3000 +2 3 0 1 0 8 50 0 20 0.000 0 0 -1 0 0 5 + 2925 4575 3000 4200 4050 4200 4050 4575 2925 4575 +2 2 0 1 0 0 50 0 20 0.000 0 0 -1 0 0 5 + 3075 4725 3900 4725 3900 4800 3075 4800 3075 4725 +2 2 0 1 0 46 50 0 20 0.000 0 0 -1 0 0 5 + 4800 3975 6450 3975 6450 4875 4800 4875 4800 3975 +2 2 0 1 0 36 50 0 20 0.000 0 0 -1 0 0 5 + 5025 4575 6225 4575 6225 4725 5025 4725 5025 4575 +2 2 0 1 0 36 50 0 20 0.000 0 0 -1 0 0 5 + 5025 3975 6225 3975 6225 3300 5025 3300 5025 3975 +2 3 0 1 0 37 50 0 20 0.000 0 0 -1 0 0 5 + 4800 3975 4800 3825 5025 3825 5025 3975 4800 3975 +2 3 0 1 0 37 50 0 20 0.000 0 0 -1 0 0 5 + 6225 3825 6375 3825 6450 3975 6225 3975 6225 3825 +2 3 0 1 0 32 50 0 20 0.000 0 0 -1 0 0 5 + 2400 2475 2250 3000 2250 4875 2400 4350 2400 2475 +2 3 0 1 0 37 50 0 -1 0.000 0 0 -1 0 0 6 + 3075 4200 3075 4050 3300 4050 3375 4050 3375 4200 3075 4200 +2 3 0 1 0 37 50 0 -1 0.000 0 0 -1 0 0 6 + 3900 4200 3900 4050 3675 4050 3600 4050 3600 4200 3900 4200 +3 2 0 1 0 37 50 0 -1 0.000 0 0 0 5 + 3705 4050 3825 3675 4185 3390 4590 3615 4800 4035 + 0.000 -1.000 -1.000 -1.000 0.000 +3 2 0 1 0 37 50 0 -1 0.000 0 0 0 5 + 3765 4050 3874 3708 4202 3449 4571 3654 4800 4185 + 0.000 -1.000 -1.000 -1.000 0.000 +4 0 0 50 0 0 12 0.0000 4 180 735 1350 5400 Computer\001 +4 0 0 50 0 0 12 0.0000 4 180 675 3150 5400 Zip drive\001 +4 0 0 50 0 0 12 0.0000 4 135 510 5325 5400 Printer\001 diff --git a/Documentation/DocBook/parport-structure.fig b/Documentation/DocBook/parport-structure.fig new file mode 100644 index 000000000..4299ce687 --- /dev/null +++ b/Documentation/DocBook/parport-structure.fig @@ -0,0 +1,60 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +0 32 #414541 +0 33 #8e8e8e +0 34 #414541 +0 35 #8e8e8e +0 36 #414541 +0 37 #8e8e8e +0 38 #414541 +0 39 #8e8e8e +0 40 #414541 +0 41 #8e8e8e +0 42 #414541 +0 43 #8e8e8e +0 44 #414141 +0 45 #868286 +0 46 #c7c3c7 +0 47 #8e8e8e +0 48 #414141 +0 49 #868286 +0 50 #c7c3c7 +0 51 #e7e3e7 +6 2025 1800 3075 2250 +2 4 0 1 0 7 50 0 -1 0.000 0 0 3 0 0 5 + 3045 2250 3045 1800 2025 1800 2025 2250 3045 2250 +4 0 0 50 0 14 12 0.0000 4 180 210 2400 2100 lp\001 +-6 +6 4125 1800 5175 2250 +2 4 0 1 0 7 50 0 -1 0.000 0 0 3 0 0 5 + 5145 2250 5145 1800 4125 1800 4125 2250 5145 2250 +4 0 0 50 0 14 12 0.0000 4 135 315 4425 2100 ppa\001 +-6 +6 3225 3075 4275 3525 +6 3375 3225 4125 3450 +4 0 0 50 0 14 12 0.0000 4 165 735 3375 3375 parport\001 +-6 +2 4 0 1 0 7 50 0 -1 0.000 0 0 3 0 0 5 + 4245 3525 4245 3075 3225 3075 3225 3525 4245 3525 +-6 +6 3000 4350 4500 4800 +2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 + 4500 4800 4500 4350 3000 4350 3000 4800 4500 4800 +4 0 0 50 0 14 12 0.0000 4 165 1050 3225 4650 parport_pc\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 2550 2250 3600 3075 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 4650 2250 3825 3075 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 3750 3525 3750 4350 diff --git a/Documentation/DocBook/parportbook.sgml b/Documentation/DocBook/parportbook.sgml new file mode 100644 index 000000000..1644748ad --- /dev/null +++ b/Documentation/DocBook/parportbook.sgml @@ -0,0 +1,1747 @@ +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]> + +<book id="ParportGuide"> + <bookinfo> + <title>The Parallel Port Subsystem</title> + + <authorgroup> + <author> + <firstname>Tim</firstname> + <surname>Waugh</surname> + <affiliation> + <address> + <email>twaugh@redhat.com</email> + </address> + </affiliation> + </author> + </authorgroup> + + <copyright> + <year>1999-2000</year> + <holder>Tim Waugh</holder> + </copyright> + + <legalnotice> + <para> + This documentation 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. + </para> + + <para> + 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. + </para> + + <para> + 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., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + </para> + + <para> + For more details see the file COPYING in the source + distribution of Linux. + </para> + </legalnotice> + </bookinfo> + +<toc></toc> + +<chapter id="design"> +<title>Design goals</title> + +<sect1> +<title>The problems</title> + +<!-- Short-comings --> +<!-- How they are addressed --> + +<!-- Short-comings + - simplistic lp driver + - platform differences + - no support for Zip drive pass-through + - no support for readback? When did Carsten add it? + - more parallel port devices. Figures? + - IEEE 1284 transfer modes: no advanced modes + --> + +<para>The first parallel port support for Linux came with the line +printer driver, <filename>lp</filename>. The printer driver is a +character special device, and (in Linux 2.0) had support for writing, +via <function>write</function>, and configuration and statistics +reporting via <function>ioctl</function>.</para> + +<para>The printer driver could be used on any computer that had an IBM +PC-compatible parallel port. Because some architectures have parallel +ports that aren't really the same as PC-style ports, other variants of +the printer driver were written in order to support Amiga and Atari +parallel ports.</para> + +<para>When the Iomega Zip drive was released, and a driver written for +it, a problem became apparent. The Zip drive is a parallel port +device that provides a parallel port of its own---it is designed to +sit between a computer and an attached printer, with the printer +plugged into the Zip drive, and the Zip drive plugged into the +computer.</para> + +<para>The problem was that, although printers and Zip drives were both +supported, for any given port only one could be used at a time. Only +one of the two drivers could be present in the kernel at once. This +was because of the fact that both drivers wanted to drive the same +hardware---the parallel port. When the printer driver initialised, it +would call the <function>check_region</function> function to make sure +that the IO region associated with the parallel port was free, and +then it would call <function>request_region</function> to allocate it. +The Zip drive used the same mechanism. Whichever driver initialised +first would gain exclusive control of the parallel port.</para> + +<para>The only way around this problem at the time was to make sure +that both drivers were available as loadable kernel modules. To use +the printer, load the printer driver module; then for the Zip drive, +unload the printer driver module and load the Zip driver +module.</para> + +<para>The net effect was that printing a document that was stored on a Zip +drive was a bit of an ordeal, at least if the Zip drive and printer +shared a parallel port. A better solution was needed.</para> + +<para>Zip drives are not the only devices that presented problems for +Linux. There are other devices with pass-through ports, for example +parallel port CD-ROM drives. There are also printers that report +their status textually rather than using simple error pins: sending a +command to the printer can cause it to report the number of pages that +it has ever printed, or how much free memory it has, or whether it is +running out of toner, and so on. The printer driver didn't originally +offer any facility for reading back this information (although Carsten +Gross added nibble mode readback support for kernel 2.2).</para> + +<!-- IEEE 1284 transfer modes: no advanced modes --> + +<para>The IEEE has issued a standards document called IEEE 1284, which +documents existing practice for parallel port communications in a +variety of modes. Those modes are: <quote>compatibility</quote>, +reverse nibble, reverse byte, ECP and EPP. Newer devices often use +the more advanced modes of transfer (ECP and EPP). In Linux 2.0, the +printer driver only supported <quote>compatibility mode</quote> +(i.e. normal printer protocol) and reverse nibble mode.</para> + +</sect1> + +<sect1> +<title>The solutions</title> + +<!-- How they are addressed + - sharing model + - overview of structure (i.e. port drivers) in 2.2 and 2.3. + - IEEE 1284 stuff + - whether or not 'platform independence' goal was met + --> + +<para>The <filename>parport</filename> code in Linux 2.2 was designed +to meet these problems of architectural differences in parallel ports, +of port-sharing between devices with pass-through ports, and of lack +of support for IEEE 1284 transfer modes.</para> + +<!-- platform differences --> + +<para>There are two layers to the +<filename>parport</filename> subsystem, only one of which deals +directly with the hardware. The other layer deals with sharing and +IEEE 1284 transfer modes. In this way, parallel support for a +particular architecture comes in the form of a module which registers +itself with the generic sharing layer.</para> + +<!-- sharing model --> + +<para>The sharing model provided by the <filename>parport</filename> +subsystem is one of exclusive access. A device driver, such as the +printer driver, must ask the <filename>parport</filename> layer for +access to the port, and can only use the port once access has been +granted. When it has finished a <quote>transaction</quote>, it can +tell the <filename>parport</filename> layer that it may release the +port for other device drivers to use.</para> + +<!-- talk a bit about how drivers can share devices on the same port --> + +<para>Devices with pass-through ports all manage to share a parallel +port with other devices in generally the same way. The device has a +latch for each of the pins on its pass-through port. The normal state +of affairs is pass-through mode, with the device copying the signal +lines between its host port and its pass-through port. When the +device sees a special signal from the host port, it latches the +pass-through port so that devices further downstream don't get +confused by the pass-through device's conversation with the host +parallel port: the device connected to the pass-through port (and any +devices connected in turn to it) are effectively cut off from the +computer. When the pass-through device has completed its transaction +with the computer, it enables the pass-through port again.</para> + +<mediaobject> +<imageobject> +<imagedata Align=center scalefit=1 fileref="parport-share.eps"> +</imageobject> +</mediaobject> + +<para>This technique relies on certain <quote>special signals</quote> +being invisible to devices that aren't watching for them. This tends +to mean only changing the data signals and leaving the control signals +alone. IEEE 1284.3 documents a standard protocol for daisy-chaining +devices together with parallel ports.</para> + +<!-- transfer modes --> + +<para>Support for standard transfer modes are provided as operations +that can be performed on a port, along with operations for setting the +data lines, or the control lines, or reading the status lines. These +operations appear to the device driver as function pointers; more +later.</para> + +</sect1> + +</chapter> + +<chapter id="transfermodes"> +<title>Standard transfer modes</title> + +<!-- Defined by IEEE, but in common use (even though there are widely --> +<!-- varying implementations). --> + +<para>The <quote>standard</quote> transfer modes in use over the +parallel port are <quote>defined</quote> by a document called IEEE +1284. It really just codifies existing practice and documents +protocols (and variations on protocols) that have been in common use +for quite some time.</para> + +<para>The original definitions of which pin did what were set out by +Centronics Data Computer Corporation, but only the printer-side +interface signals were specified.</para> + +<para>By the early 1980s, IBM's host-side implementation had become +the most widely used. New printers emerged that claimed Centronics +compatibility, but although compatible with Centronics they differed +from one another in a number of ways.</para> + +<para>As a result of this, when IEEE 1284 was published in 1994, all +that it could really do was document the various protocols that are +used for printers (there are about six variations on a theme).</para> + +<para>In addition to the protocol used to talk to +Centronics-compatible printers, IEEE 1284 defined other protocols that +are used for unidirectional peripheral-to-host transfers (reverse +nibble and reverse byte) and for fast bidirectional transfers (ECP and +EPP).</para> + +</chapter> + +<chapter id="structure"> +<title>Structure</title> + +<!-- Main structure + - sharing core + - parports and their IEEE 1284 overrides + - IEEE 1284 transfer modes for generic ports + - maybe mention muxes here + - pardevices + - IEEE 1284.3 API + --> + +<!-- Diagram --> + +<mediaobject> +<imageobject> +<imagedata Align=Center ScaleFit=1 fileref="parport-structure.eps"> +</imageobject> +</mediaobject> + +<sect1> +<title>Sharing core</title> + +<!-- sharing core --> + +<para>At the core of the <filename>parport</filename> subsystem is the +sharing mechanism (see <filename>drivers/parport/share.c</filename>). +This module, <filename>parport</filename>, is responsible for +keeping track of which ports there are in the system, which device +drivers might be interested in new ports, and whether or not each port +is available for use (or if not, which driver is currently using +it).</para> + +</sect1> + +<sect1> +<title>Parports and their overrides</title> +<!-- parports and their overrides --> + +<para>The generic <filename>parport</filename> sharing code doesn't +directly handle the parallel port hardware. That is done instead by +<quote>low-level</quote> <filename>parport</filename> drivers. The +function of a low-level <filename>parport</filename> driver is to +detect parallel ports, register them with the sharing code, and +provide a list of access functions for each port.</para> + +<para>The most basic access functions that must be provided are ones +for examining the status lines, for setting the control lines, and for +setting the data lines. There are also access functions for setting +the direction of the data lines; normally they are in the +<quote>forward</quote> direction (that is, the computer drives them), +but some ports allow switching to <quote>reverse</quote> mode (driven +by the peripheral). There is an access function for examining the +data lines once in reverse mode.</para> + +</sect1> + +<sect1> +<title>IEEE 1284 transfer modes</title> +<!-- IEEE 1284 transfer modes --> + +<para>Stacked on top of the sharing mechanism, but still in the +<filename>parport</filename> module, are functions for transferring +data. They are provided for the device drivers to use, and are very +much like library routines. Since these transfer functions are +provided by the generic <filename>parport</filename> core they must +use the <quote>lowest common denominator</quote> set of access +functions: they can set the control lines, examine the status lines, +and use the data lines. With some parallel ports the data lines can +only be set and not examined, and with other ports accessing the data +register causes control line activity; with these types of situations, +the IEEE 1284 transfer functions make a best effort attempt to do the +right thing. In some cases, it is not physically possible to use +particular IEEE 1284 transfer modes.</para> + +<para>The low-level <filename>parport</filename> drivers also provide +IEEE 1284 transfer functions, as names in the access function list. +The low-level driver can just name the generic IEEE 1284 transfer +functions for this. Some parallel ports can do IEEE 1284 transfers in +hardware; for those ports, the low-level driver can provide functions +to utilise that feature.</para> + +</sect1> + +<!-- muxes? --> + +<!-- pardevices and pardrivers --> + +<sect1> +<title>Pardevices and parport_drivers</title> + +<para>When a parallel port device driver (such as +<filename>lp</filename>) initialises it tells the sharing layer about +itself using <function>parport_register_driver</function>. The +information is put into a <structname>struct +parport_driver</structname>, which is put into a linked list. The +information in a <structname>struct parport_driver</structname> really +just amounts to some function pointers to callbacks in the parallel +port device driver.</para> + +<para>During its initialisation, a low-level port driver tells the +sharing layer about all the ports that it has found (using +<function>parport_register_port</function>), and the sharing layer +creates a <structname>struct parport</structname> for each of them. +Each <structname>struct parport</structname> contains (among other +things) a pointer to a <structname>struct +parport_operations</structname>, which is a list of function pointers +for the various operations that can be performed on a port. You can +think of a <structname>struct parport</structname> as a parallel port +<quote>object</quote>, if <quote>object-orientated</quote> programming +is your thing. The <structname>parport</structname> structures are +chained in a linked list, whose head is <varname>portlist</varname> +(in <filename>drivers/parport/share.c</filename>).</para> + +<para>Once the port has been registered, the low-level port driver +announces it. The <function>parport_announce_port</function> function +walks down the list of parallel port device drivers +(<structname>struct parport_driver</structname>s) calling the +<function>attach</function> function of each.</para> + +<para>Similarly, a low-level port driver can undo the effect of +registering a port with the +<function>parport_unregister_port</function> function, and device +drivers are notified using the <function>detach</function> +callback.</para> + +<para>Device drivers can undo the effect of registering themselves +with the <function>parport_unregister_driver</function> +function.</para> + +</sect1> + +<!-- IEEE 1284.3 API --> + +<sect1> +<title>The IEEE 1284.3 API</title> + +<para>The ability to daisy-chain devices is very useful, but if every +device does it in a different way it could lead to lots of +complications for device driver writers. Fortunately, the IEEE are +standardising it in IEEE 1284.3, which covers daisy-chain devices and +port multiplexors.</para> + +<para>At the time of writing, IEEE 1284.3 has not been published, but +the draft specifies the on-the-wire protocol for daisy-chaining and +multiplexing, and also suggests a programming interface for using it. +That interface (or most of it) has been implemented in the +<filename>parport</filename> code in Linux.</para> + +<para>At initialisation of the parallel port <quote>bus</quote>, daisy-chained +devices are assigned addresses starting from zero. There can only be +four devices with daisy-chain addresses, plus one device on the end +that doesn't know about daisy-chaining and thinks it's connected +directly to a computer.</para> + +<para>Another way of connecting more parallel port devices is to use a +multiplexor. The idea is to have a device that is connected directly +to a parallel port on a computer, but has a number of parallel ports +on the other side for other peripherals to connect to (two or four +ports are allowed). The multiplexor switches control to different +ports under software control---it is, in effect, a programmable +printer switch.</para> + +<para>Combining the ability of daisy-chaining five devices together +with the ability to multiplex one parallel port between four gives the +potential to have twenty peripherals connected to the same parallel +port!</para> + +<para>In addition, of course, a single computer can have multiple +parallel ports. So, each parallel port peripheral in the system can +be identified with three numbers, or co-ordinates: the parallel port, +the multiplexed port, and the daisy-chain address.</para> + +<mediaobject> +<imageobject> +<imagedata align=center scalefit=1 fileref="parport-multi.eps"> +</imageobject> +</mediaobject> + +<!-- x parport_open --> +<!-- x parport_close --> +<!-- x parport_device_id --> +<!-- x parport_device_num --> +<!-- x parport_device_coords --> +<!-- x parport_find_device --> +<!-- x parport_find_class --> + +<para>Each device in the system is numbered at initialisation (by +<function>parport_daisy_init</function>). You can convert between +this device number and its co-ordinates with +<function>parport_device_num</function> and +<function>parport_device_coords</function>.</para> + +<funcsynopsis><funcprototype> + <funcdef>int <function>parport_device_num</function></funcdef> + <paramdef>int <parameter>parport</parameter></paramdef> + <paramdef>int <parameter>mux</parameter></paramdef> + <paramdef>int <parameter>daisy</parameter></paramdef> +</funcprototype></funcsynopsis> + +<funcsynopsis><funcprototype> + <funcdef>int <function>parport_device_coords</function></funcdef> + <paramdef>int <parameter>devnum</parameter></paramdef> + <paramdef>int *<parameter>parport</parameter></paramdef> + <paramdef>int *<parameter>mux</parameter></paramdef> + <paramdef>int *<parameter>daisy</parameter></paramdef> +</funcprototype></funcsynopsis> + +<para>Any parallel port peripheral will be connected directly or +indirectly to a parallel port on the system, but it won't have a +daisy-chain address if it does not know about daisy-chaining, and it +won't be connected through a multiplexor port if there is no +multiplexor. The special co-ordinate value <constant>-1</constant> is +used to indicate these cases.</para> + +<para>Two functions are provided for finding devices based on their +IEEE 1284 Device ID: <function>parport_find_device</function> and +<function>parport_find_class</function>.</para> + +<funcsynopsis><funcprototype> + <funcdef>int <function>parport_find_device</function></funcdef> + <paramdef>const char *<parameter>mfg</parameter></paramdef> + <paramdef>const char *<parameter>mdl</parameter></paramdef> + <paramdef>int <parameter>from</parameter></paramdef> +</funcprototype></funcsynopsis> + +<funcsynopsis><funcprototype> + <funcdef>int <function>parport_find_class</function></funcdef> + <paramdef>parport_device_class <parameter>cls</parameter></paramdef> + <paramdef>int <parameter>from</parameter></paramdef> +</funcprototype></funcsynopsis> + +<para>These functions take a device number (in addition to some other +things), and return another device number. They walk through the list +of detected devices until they find one that matches the requirements, +and then return that device number (or <constant>-1</constant> if +there are no more such devices). They start their search at the +device after the one in the list with the number given (at +<parameter>from</parameter>+1, in other words).</para> + +</sect1> + +</chapter> + +<chapter id="drivers"> +<title>Device driver's view</title> + +<!-- Cover: + - sharing interface, preemption, interrupts, wakeups... + - IEEE 1284.3 interface + - port operations + - why can read data but ctr is faked, etc. + --> + +<!-- I should take a look at the kernel hackers' guide bit I wrote, --> +<!-- as that deals with a lot of this. The main complaint with it --> +<!-- was that there weren't enough examples, but 'The printer --> +<!-- driver' should deal with that later; might be worth mentioning --> +<!-- in the text. --> + +<para>This section is written from the point of view of the device +driver programmer, who might be writing a driver for a printer or a +scanner or else anything that plugs into the parallel port. It +explains how to use the <filename>parport</filename> interface to find +parallel ports, use them, and share them with other device +drivers.</para> + +<para>We'll start out with a description of the various functions that +can be called, and then look at a reasonably simple example of their +use: the printer driver.</para> + +<para>The interactions between the device driver and the +<filename>parport</filename> layer are as follows. First, the device +driver registers its existence with <filename>parport</filename>, in +order to get told about any parallel ports that have been (or will be) +detected. When it gets told about a parallel port, it then tells +<filename>parport</filename> that it wants to drive a device on that +port. Thereafter it can claim exclusive access to the port in order +to talk to its device.</para> + +<para>So, the first thing for the device driver to do is tell +<filename>parport</filename> that it wants to know what parallel ports +are on the system. To do this, it uses the +<function>parport_register_device</function> function:</para> + +<programlisting> +<![CDATA[ +struct parport_driver { + const char *name; + void (*attach) (struct parport *); + void (*detach) (struct parport *); + struct parport_driver *next; +}; +]]></programlisting> + +<funcsynopsis><funcprototype> + <funcdef>int <function>parport_register_driver</function></funcdef> + <paramdef>struct parport_driver *<parameter>driver</parameter></paramdef> +</funcprototype></funcsynopsis> + +<para>In other words, the device driver passes pointers to a couple of +functions to <filename>parport</filename>, and +<filename>parport</filename> calls <function>attach</function> for +each port that's detected (and <function>detach</function> for each +port that disappears -- yes, this can happen).</para> + +<para>The next thing that happens is that the device driver tells +<filename>parport</filename> that it thinks there's a device on the +port that it can drive. This typically will happen in the driver's +<function>attach</function> function, and is done with +<function>parport_register_device</function>:</para> + +<funcsynopsis><funcprototype> + <funcdef>struct pardevice *<function>parport_register_device</function></funcdef> + <paramdef>struct parport *<parameter>port</parameter></paramdef> + <paramdef>const char *<parameter>name</parameter></paramdef> + <paramdef>int <parameter>(*pf)</parameter> + <funcparams>void *</funcparams></paramdef> + <paramdef>void <parameter>(*kf)</parameter> + <funcparams>void *</funcparams></paramdef> + <paramdef>void <parameter>(*irq_func)</parameter> + <funcparams>int, void *, struct pt_regs *</funcparams></paramdef> + <paramdef>int <parameter>flags</parameter></paramdef> + <paramdef>void *<parameter>handle</parameter></paramdef> +</funcprototype></funcsynopsis> + +<para>The <parameter>port</parameter> comes from the parameter supplied +to the <function>attach</function> function when it is called, or +alternatively can be found from the list of detected parallel ports +directly with the (now deprecated) +<function>parport_enumerate</function> function.</para> + +<para>The next three parameters, <parameter>pf</parameter>, +<parameter>kf</parameter>, and <parameter>irq_func</parameter>, are +more function pointers. These callback functions get called under +various circumstances, and are always given the +<parameter>handle</parameter> as one of their parameters.</para> + +<para>The preemption callback, <parameter>pf</parameter>, is called +when the driver has claimed access to the port but another device +driver wants access. If the driver is willing to let the port go, it +should return zero and the port will be released on its behalf. There +is no need to call <function>parport_release</function>. If +<parameter>pf</parameter> gets called at a bad time for letting the +port go, it should return non-zero and no action will be taken. It is +good manners for the driver to try to release the port at the earliest +opportunity after its preemption callback is called.</para> + +<para>The <quote>kick</quote> callback, <parameter>kf</parameter>, is +called when the port can be claimed for exclusive access; that is, +<function>parport_claim</function> is guaranteed to succeed inside the +<quote>kick</quote> callback. If the driver wants to claim the port +it should do so; otherwise, it need not take any action.</para> + +<para>The <parameter>irq_func</parameter> callback is called, +predictably, when a parallel port interrupt is generated. But it is +not the only code that hooks on the interrupt. The sequence is this: +the lowlevel driver is the one that has done +<function>request_irq</function>; it then does whatever +hardware-specific things it needs to do to the parallel port hardware +(for PC-style ports, there is nothing special to do); it then tells +the IEEE 1284 code about the interrupt, which may involve reacting to +an IEEE 1284 event, depending on the current IEEE 1284 phase; and +finally the <parameter>irq_func</parameter> function is called.</para> + +<para>None of the callback functions are allowed to block.</para> + +<para>The <parameter>flags</parameter> are for telling +<filename>parport</filename> any requirements or hints that are +useful. The only useful value here (other than +<constant>0</constant>, which is the usual value) is +<constant>PARPORT_DEV_EXCL</constant>. The point of that flag is to +request exclusive access at all times---once a driver has successfully +called <function>parport_register_device</function> with that flag, no +other device drivers will be able to register devices on that port +(until the successful driver deregisters its device, of +course).</para> + +<para>The <constant>PARPORT_DEV_EXCL</constant> flag is for preventing +port sharing, and so should only be used when sharing the port with +other device drivers is impossible and would lead to incorrect +behaviour. Use it sparingly!</para> + +<para>Devices can also be registered by device drivers based on their +device numbers (the same device numbers as in the previous +section).</para> + +<para>The <function>parport_open</function> function is similar to +<function>parport_register_device</function>, and +<function>parport_close</function> is the equivalent of +<function>parport_unregister_device</function>. The difference is +that <function>parport_open</function> takes a device number rather +than a pointer to a <structname>struct parport</structname>.</para> + +<funcsynopsis><funcprototype> + <funcdef>struct pardevice *<function>parport_open</function></funcdef> + <paramdef>int <parameter>devnum</parameter></paramdef> + <paramdef>int <parameter>(*pf)</parameter> + <funcparams>void *</funcparams></paramdef> + <paramdef>int <parameter>(*kf)</parameter> + <funcparams>void *</funcparams></paramdef> + <paramdef>int <parameter>(*irqf)</parameter> + <funcparams>int, void *, struct pt_regs *</funcparams></paramdef> + <paramdef>int <parameter>flags</parameter></paramdef> + <paramdef>void *<parameter>handle</parameter></paramdef> +</funcprototype></funcsynopsis> + +<funcsynopsis><funcprototype> + <funcdef>void <function>parport_close</function></funcdef> + <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> +</funcprototype></funcsynopsis> + +<funcsynopsis><funcprototype> + <funcdef>struct pardevice *<function>parport_register_device</function></funcdef> + <paramdef>struct parport *<parameter>port</parameter></paramdef> + <paramdef>const char *<parameter>name</parameter></paramdef> + <paramdef>int <parameter>(*pf)</parameter> + <funcparams>void *</funcparams></paramdef> + <paramdef>int <parameter>(*kf)</parameter> + <funcparams>void *</funcparams></paramdef> + <paramdef>int <parameter>(*irqf)</parameter> + <funcparams>int, void *, struct pt_regs *</funcparams></paramdef> + <paramdef>int <parameter>flags</parameter></paramdef> + <paramdef>void *<parameter>handle</parameter></paramdef> +</funcprototype></funcsynopsis> + +<funcsynopsis><funcprototype> + <funcdef>void <function>parport_unregister_device</function></funcdef> + <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> +</funcprototype></funcsynopsis> + +<para>The intended use of these functions is during driver +initialisation while the driver looks for devices that it supports, as +demonstrated by the following code fragment:</para> + +<programlisting> +<![CDATA[ +int devnum = -1; +while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, + devnum)) != -1) { + struct pardevice *dev = parport_open (devnum, ...); + ... +} +]]></programlisting> + +<para>Once your device driver has registered its device and been +handed a pointer to a <structname>struct pardevice</structname>, the +next thing you are likely to want to do is communicate with the device +you think is there. To do that you'll need to claim access to the +port.</para> + +<funcsynopsis><funcprototype> + <funcdef>int <function>parport_claim</function></funcdef> + <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> +</funcprototype></funcsynopsis> + +<funcsynopsis><funcprototype> + <funcdef>int <function>parport_claim_or_block</function></funcdef> + <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> +</funcprototype></funcsynopsis> + +<funcsynopsis><funcprototype> + <funcdef>void <function>parport_release</function></funcdef> + <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> +</funcprototype></funcsynopsis> + +<para>To claim access to the port, use +<function>parport_claim</function> or +<function>parport_claim_or_block</function>. The first of these will +not block, and so can be used from interrupt context. If +<function>parport_claim</function> succeeds it will return zero and +the port is available to use. It may fail (returning non-zero) if the +port is in use by another driver and that driver is not willing to +relinquish control of the port.</para> + +<para>The other function, <function>parport_claim_or_block</function>, +will block if necessary to wait for the port to be free. If it slept, +it returns <constant>1</constant>; if it succeeded without needing to +sleep it returns <constant>0</constant>. If it fails it will return a +negative error code.</para> + +<para>When you have finished communicating with the device, you can +give up access to the port so that other drivers can communicate with +their devices. The <function>parport_release</function> function +cannot fail, but it should not be called without the port claimed. +Similarly, you should not try to claim the port if you already have it +claimed.</para> + +<para>You may find that although there are convenient points for your +driver to relinquish the parallel port and allow other drivers to talk +to their devices, it would be preferable to keep hold of the port. +The printer driver only needs the port when there is data to print, +for example, but a network driver (such as PLIP) could be sent a +remote packet at any time. With PLIP, it is no huge catastrophe if a +network packet is dropped, since it will likely be sent again, so it +is possible for that kind of driver to share the port with other +(pass-through) devices.</para> + +<para>The <function>parport_yield</function> and +<function>parport_yield_blocking</function> functions are for marking +points in the driver at which other drivers may claim the port and use +their devices. Yielding the port is similar to releasing it and +reclaiming it, but it more efficient because nothing is done if there +are no other devices needing the port. In fact, nothing is done even +if there are other devices waiting but the current device is still +within its <quote>timeslice</quote>. The default timeslice is half a +second, but it can be adjusted via a <filename>/proc</filename> +entry.</para> + +<funcsynopsis><funcprototype> + <funcdef>int <function>parport_yield</function></funcdef> + <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> +</funcprototype></funcsynopsis> + +<funcsynopsis><funcprototype> + <funcdef>int <function>parport_yield_blocking</function></funcdef> + <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> +</funcprototype></funcsynopsis> + +<para>The first of these, <function>parport_yield</function>, will not +block but as a result may fail. The return value for +<function>parport_yield</function> is the same as for +<function>parport_claim</function>. The blocking version, +<function>parport_yield_blocking</function>, has the same return code +as <function>parport_claim_or_block</function>.</para> + +<para>Once the port has been claimed, the device driver can use the +functions in the <structname>struct parport_operations</structname> +pointer in the <structname>struct parport</structname> it has a +pointer to. For example:</para> + +<programlisting> +<![CDATA[ +port->ops->write_data (port, d); +]]></programlisting> + +<para>Some of these operations have <quote>shortcuts</quote>. For +instance, <function>parport_write_data</function> is equivalent to the +above, but may be a little bit faster (it's a macro that in some cases +can avoid needing to indirect through <varname>port</varname> and +<varname>ops</varname>).</para> + +</chapter> + +<chapter id="portdrivers"> +<title>Port drivers</title> + +<!-- What port drivers are for (i.e. implementing parport objects). --> + +<para>To recap, then:</para> + +<itemizedlist spacing=compact> + +<listitem> +<para> +The device driver registers itself with <filename>parport</filename>. +</para> +</listitem> + +<listitem> +<para> +A low-level driver finds a parallel port and registers it with +<filename>parport</filename> (these first two things can happen in +either order). This registration creates a <structname>struct +parport</structname> which is linked onto a list of known ports. +</para> +</listitem> + +<listitem> +<para> +<filename>parport</filename> calls the <function>attach</function> +function of each registered device driver, passing it the pointer to +the new <structname>struct parport</structname>. +</para> +</listitem> + +<listitem> +<para> +The device driver gets a handle from <filename>parport</filename>, for +use with +<function>parport_claim</function>/<function>release</function>. This +handle takes the form of a pointer to a <structname>struct +pardevice</structname>, representing a particular device on the +parallel port, and is acquired using +<function>parport_register_device</function>. +</para> +</listitem> + +<listitem> +<para> +The device driver claims the port using +<function>parport_claim</function> (or +<function>function_claim_or_block</function>). +</para> +</listitem> + +<listitem> +<para> +Then it goes ahead and uses the port. When finished it releases the +port. +</para> +</listitem> + +</itemizedlist> + +<para>The purpose of the low-level drivers, then, is to detect +parallel ports and provide methods of accessing them +(i.e. implementing the operations in <structname>struct +parport_operations</structname>).</para> + +<!-- Interaction with sharing engine; port state --> +<!-- What did I mean by that? --> + +<!-- Talk about parport_pc implementation, and contrast with e.g. amiga --> + +<para>A more complete description of which operation is supposed to do +what is available in +<filename>Documentation/parport-lowlevel.txt</filename>.</para> + +</chapter> + +<chapter id="lp"> +<title>The printer driver</title> + +<!-- Talk the reader through the printer driver. --> +<!-- Could even talk about parallel port console here. --> + +<para>The printer driver, <filename>lp</filename> is a character +special device driver and a <filename>parport</filename> client. As a +character special device driver it registers a <structname>struct +file_operations</structname> using +<function>register_chrdev</function>, with pointers filled in for +<structfield>write</structfield>, <structfield>ioctl</structfield>, +<structfield>open</structfield> and +<structfield>release</structfield>. As a client of +<filename>parport</filename>, it registers a <structname>struct +parport_driver</structname> using +<function>parport_register_driver</function>, so that +<filename>parport</filename> knows to call +<function>lp_attach</function> when a new parallel port is discovered +(and <function>lp_detach</function> when it goes away).</para> + +<para>The parallel port console functionality is also implemented in +<filename>lp.c</filename>, but that won't be covered here (it's quite +simple though).</para> + +<para>The initialisation of the driver is quite easy to understand +(see <function>lp_init</function>). The <varname>lp_table</varname> +is an array of structures that contain information about a specific +device (the <structname>struct pardevice</structname> associated with +it, for example). That array is initialised to sensible values first +of all.</para> + +<para>Next, the printer driver calls +<function>register_chrdev</function> passing it a pointer to +<varname>lp_fops</varname>, which contains function pointers for the +printer driver's implementation of <function>open</function>, +<function>write</function>, and so on. This part is the same as for +any character special device driver.</para> + +<para>After successfully registering itself as a character special +device driver, the printer driver registers itself as a +<filename>parport</filename> client using +<function>parport_register_driver</function>. It passes a pointer to +this structure:</para> + +<programlisting> +<![CDATA[ +static struct parport_driver lp_driver = { + "lp", + lp_attach, + lp_detach, + NULL +}; +]]></programlisting> + +<para>The <function>lp_detach</function> function is not very +interesting (it does nothing); the interesting bit is +<function>lp_attach</function>. What goes on here depends on whether +the user supplied any parameters. The possibilities are: no +parameters supplied, in which case the printer driver uses every port +that is detected; the user supplied the parameter <quote>auto</quote>, +in which case only ports on which the device ID string indicates a +printer is present are used; or the user supplied a list of parallel +port numbers to try, in which case only those are used.</para> + +<para>For each port that the printer driver wants to use (see +<function>lp_register</function>), it calls +<function>parport_register_device</function> and stores the resulting +<structname>struct pardevice</structname> pointer in the +<varname>lp_table</varname>. If the user told it to do so, it then +resets the printer.</para> + +<para>The other interesting piece of the printer driver, from the +point of view of <filename>parport</filename>, is +<function>lp_write</function>. In this function, the user space +process has data that it wants printed, and the printer driver hands +it off to the <filename>parport</filename> code to deal with.</para> + +<para>The <filename>parport</filename> functions it uses that we have +not seen yet are <function>parport_negotiate</function>, +<function>parport_set_timeout</function>, and +<function>parport_write</function>. These functions are part of the +IEEE 1284 implementation.</para> + +<para>The way the IEEE 1284 protocol works is that the host tells the +peripheral what transfer mode it would like to use, and the peripheral +either accepts that mode or rejects it; if the mode is rejected, the +host can try again with a different mode. This is the negotation +phase. Once the peripheral has accepted a particular transfer mode, +data transfer can begin that mode.</para> + +<para>The particular transfer mode that the printer driver wants to +use is named in IEEE 1284 as <quote>compatibility</quote> mode, and +the function to request a particular mode is called +<function>parport_negotiate</function>.</para> + +<funcsynopsis><funcprototype> + <funcdef>int <function>parport_negotiate</function></funcdef> + <paramdef>struct parport *<parameter>port</parameter></paramdef> + <paramdef>int <parameter>mode</parameter></paramdef> +</funcprototype></funcsynopsis> + +<para>The <parameter>modes</parameter> parameter is a symbolic +constant representing an IEEE 1284 mode; in this instance, it is +<constant>IEEE1284_MODE_COMPAT</constant>. (Compatibility mode is +slightly different to the other modes---rather than being specifically +requested, it is the default until another mode is selected.)</para> + +<para>Back to <function>lp_write</function> then. First, access to +the parallel port is secured with +<function>parport_claim_or_block</function>. At this point the driver +might sleep, waiting for another driver (perhaps a Zip drive driver, +for instance) to let the port go. Next, it goes to compatibility mode +using <function>parport_negotiate</function>.</para> + +<para>The main work is done in the write-loop. In particular, the +line that hands the data over to <filename>parport</filename> +reads:</para> + +<programlisting> +<![CDATA[ + written = parport_write (port, kbuf, copy_size); +]]></programlisting> + +<para>The <function>parport_write</function> function writes data to +the peripheral using the currently selected transfer mode +(compatibility mode, in this case). It returns the number of bytes +successfully written:</para> + +<funcsynopsis><funcprototype> + <funcdef>ssize_t <function>parport_write</function></funcdef> + <paramdef>struct parport *<parameter>port</parameter></paramdef> + <paramdef>const void *<parameter>buf</parameter></paramdef> + <paramdef>size_t <parameter>len</parameter></paramdef> +</funcprototype></funcsynopsis> + +<funcsynopsis><funcprototype> + <funcdef>ssize_t <function>parport_read</function></funcdef> + <paramdef>struct parport *<parameter>port</parameter></paramdef> + <paramdef>void *<parameter>buf</parameter></paramdef> + <paramdef>size_t <parameter>len</parameter></paramdef> +</funcprototype></funcsynopsis> + +<para>(<function>parport_read</function> does what it sounds like, but +only works for modes in which reverse transfer is possible. Of +course, <function>parport_write</function> only works in modes in +which forward transfer is possible, too.)</para> + +<para>The <parameter>buf</parameter> pointer should be to kernel space +memory, and obviously the <parameter>len</parameter> parameter +specifies the amount of data to transfer.</para> + +<para>In fact what <function>parport_write</function> does is call the +appropriate block transfer function from the <structname>struct +parport_operations</structname>:</para> + +<programlisting> +<![CDATA[ +struct parport_operations { + [...] + + /* Block read/write */ + size_t (*epp_write_data) (struct parport *port, const void *buf, + size_t len, int flags); + size_t (*epp_read_data) (struct parport *port, void *buf, size_t len, + int flags); + size_t (*epp_write_addr) (struct parport *port, const void *buf, + size_t len, int flags); + size_t (*epp_read_addr) (struct parport *port, void *buf, size_t len, + int flags); + + size_t (*ecp_write_data) (struct parport *port, const void *buf, + size_t len, int flags); + size_t (*ecp_read_data) (struct parport *port, void *buf, size_t len, + int flags); + size_t (*ecp_write_addr) (struct parport *port, const void *buf, + size_t len, int flags); + + size_t (*compat_write_data) (struct parport *port, const void *buf, + size_t len, int flags); + size_t (*nibble_read_data) (struct parport *port, void *buf, + size_t len, int flags); + size_t (*byte_read_data) (struct parport *port, void *buf, + size_t len, int flags); +}; +]]></programlisting> + +<para>The transfer code in <filename>parport</filename> will tolerate +a data transfer stall only for so long, and this timeout can be +specified with <function>parport_set_timeout</function>, which returns +the previous timeout:</para> + +<funcsynopsis><funcprototype> + <funcdef>long <function>parport_set_timeout</function></funcdef> + <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> + <paramdef>long <parameter>inactivity</parameter></paramdef> +</funcprototype></funcsynopsis> + +<para>This timeout is specific to the device, and is restored on +<function>parport_claim</function>.</para> + +</chapter> + +<chapter id="ppdev"> +<title>User-level device drivers</title> + +<!-- ppdev --> +<sect1> +<title>Introduction to ppdev</title> + +<para>The printer is accessible through <filename>/dev/lp0</filename>; +in the same way, the parallel port itself is accessible through +<filename>/dev/parport0</filename>. The difference is in the level of +control that you have over the wires in the parallel port +cable.</para> + +<para>With the printer driver, a user-space program (such as the +printer spooler) can send bytes in <quote>printer protocol</quote>. +Briefly, this means that for each byte, the eight data lines are set +up, then a <quote>strobe</quote> line tells the printer to look at the +data lines, and the printer sets an <quote>acknowledgement</quote> +line to say that it got the byte. The printer driver also allows the +user-space program to read bytes in <quote>nibble mode</quote>, which +is a way of transferring data from the peripheral to the computer half +a byte at a time (and so it's quite slow).</para> + +<para>In contrast, the <filename>ppdev</filename> driver (accessed via +<filename>/dev/parport0</filename>) allows you to:</para> + +<itemizedlist spacing=compact> + +<listitem> +<para> +examine status lines, +</para> +</listitem> + +<listitem> +<para> +set control lines, +</para> +</listitem> + +<listitem> +<para> +set/examine data lines (and control the direction of the data lines), +</para> +</listitem> + +<listitem> +<para> +wait for an interrupt (triggered by one of the status lines), +</para> +</listitem> + +<listitem> +<para> +find out how many new interrupts have occurred, +</para> +</listitem> + +<listitem> +<para> +set up a response to an interrupt, +</para> +</listitem> + +<listitem> +<para> +use IEEE 1284 negotiation (for telling peripheral which transfer mode, +to use) +</para> +</listitem> + +<listitem> +<para> +transfer data using a specified IEEE 1284 mode. +</para> +</listitem> + +</itemizedlist> + +</sect1> + +<sect1> +<title>User-level or kernel-level driver?</title> + +<para>The decision of whether to choose to write a kernel-level device +driver or a user-level device driver depends on several factors. One +of the main ones from a practical point of view is speed: kernel-level +device drivers get to run faster because they are not preemptable, +unlike user-level applications.</para> + +<para>Another factor is ease of development. It is in general easier +to write a user-level driver because (a) one wrong move does not +result in a crashed machine, (b) you have access to user libraries +(such as the C library), and (c) debugging is easier.</para> + +</sect1> + +<sect1> +<title>Programming interface</title> + +<para>The <filename>ppdev</filename> interface is largely the same as +that of other character special devices, in that it supports +<function>open</function>, <function>close</function>, +<function>read</function>, <function>write</function>, and +<function>ioctl</function>.</para> + +<sect2> +<title>Starting and stopping: <function>open</function> and +<function>close</function></title> + +<para>The device node <filename>/dev/parport0</filename> represents +any device that is connected to <filename>parport0</filename>, the +first parallel port in the system. Each time the device node is +opened, it represents (to the process doing the opening) a different +device. It can be opened more than once, but only one instance can +actually be in control of the parallel port at any time. A process +that has opened <filename>/dev/parport0</filename> shares the parallel +port in the same way as any other device driver. A user-land driver +may be sharing the parallel port with in-kernel device drivers as well +as other user-land drivers.</para> +</sect2> + +<sect2> +<title>Control: <function>ioctl</function></title> + +<para>Most of the control is done, naturally enough, via the +<function>ioctl</function> call. Using <function>ioctl</function>, +the user-land driver can control both the <filename>ppdev</filename> +driver in the kernel and the physical parallel port itself. The +<function>ioctl</function> call takes as parameters a file descriptor +(the one returned from opening the device node), a command, and +optionally (a pointer to) some data.</para> + +<variablelist> +<varlistentry><term><constant>PPCLAIM</constant></term> +<listitem> + +<para>Claims access to the port. As a user-land device driver writer, +you will need to do this before you are able to actually change the +state of the parallel port in any way. Note that some operations only +affect the <filename>ppdev</filename> driver and not the port, such as +<constant>PPSETMODE</constant>; they can be performed while access to +the port is not claimed.</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPEXCL</constant></term> +<listitem> + +<para>Instructs the kernel driver to forbid any sharing of the port +with other drivers, i.e. it requests exclusivity. The +<constant>PPEXCL</constant> command is only valid when the port is not +already claimed for use, and it may mean that the next +<constant>PPCLAIM</constant> <function>ioctl</function> will fail: +some other driver may already have registered itself on that +port.</para> + +<para>Most device drivers don't need exclusive access to the port. +It's only provided in case it is really needed, for example for +devices where access to the port is required for extensive periods of +time (many seconds).</para> + +<para>Note that the <constant>PPEXCL</constant> +<function>ioctl</function> doesn't actually claim the port there and +then---action is deferred until the <constant>PPCLAIM</constant> +<function>ioctl</function> is performed.</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPRELEASE</constant></term> +<listitem> + +<para>Releases the port. Releasing the port undoes the effect of +claiming the port. It allows other device drivers to talk to their +devices (assuming that there are any).</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPYIELD</constant></term> +<listitem> + +<para>Yields the port to another driver. This +<function>ioctl</function> is a kind of short-hand for releasing the +port and immediately reclaiming it. It gives other drivers a chance +to talk to their devices, but afterwards claims the port back. An +example of using this would be in a user-land printer driver: once a +few characters have been written we could give the port to another +device driver for a while, but if we still have characters to send to +the printer we would want the port back as soon as possible.</para> + +<para>It is important not to claim the parallel port for too long, as +other device drivers will have no time to service their devices. If +your device does not allow for parallel port sharing at all, it is +better to claim the parallel port exclusively (see +<constant>PPEXCL</constant>).</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPNEGOT</constant></term> +<listitem> + +<para>Performs IEEE 1284 negotiation into a particular mode. Briefly, +negotiation is the method by which the host and the peripheral decide +on a protocol to use when transferring data.</para> + +<para>An IEEE 1284 compliant device will start out in compatibility +mode, and then the host can negotiate to another mode (such as +ECP).</para> + +<para>The <function>ioctl</function> parameter should be a pointer to +an <type>int</type>; values for this are in +<filename>parport.h</filename> and include:</para> + +<itemizedlist spacing=compact> +<listitem><para><constant>IEEE1284_MODE_COMPAT</constant></para></listitem> +<listitem><para><constant>IEEE1284_MODE_NIBBLE</constant></para></listitem> +<listitem><para><constant>IEEE1284_MODE_BYTE</constant></para></listitem> +<listitem><para><constant>IEEE1284_MODE_EPP</constant></para></listitem> +<listitem><para><constant>IEEE1284_MODE_ECP</constant></para></listitem> +</itemizedlist> + +<para>The <constant>PPNEGOT</constant> <function>ioctl</function> +actually does two things: it performs the on-the-wire negotiation, and +it sets the behaviour of subsequent +<function>read</function>/<function>write</function> calls so that +they use that mode (but see <constant>PPSETMODE</constant>).</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPSETMODE</constant></term> +<listitem> + +<para>Sets which IEEE 1284 protocol to use for the +<function>read</function> and <function>write</function> calls.</para> + +<para>The <function>ioctl</function> parameter should be a pointer to +an <type>int</type>.</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPGETTIME</constant></term> +<listitem> + +<para>Retrieves the time-out value. The <function>read</function> and +<function>write</function> calls will time out if the peripheral +doesn't respond quickly enough. The <constant>PPGETTIME</constant> +<function>ioctl</function> retrieves the length of time that the +peripheral is allowed to have before giving up.</para> + +<para>The <function>ioctl</function> parameter should be a pointer to +a <structname>struct timeval</structname>.</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPSETTIME</constant></term> +<listitem> + +<para>Sets the time-out. The <function>ioctl</function> parameter +should be a pointer to a <structname>struct +timeval</structname>.</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPWCONTROL</constant></term> +<listitem> + +<para>Sets the control lines. The <function>ioctl</function> +parameter is a pointer to an <type>unsigned char</type>, the bitwise +OR of the control line values in +<filename>parport.h</filename>.</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPRCONTROL</constant></term> +<listitem> + +<para>Returns the last value written to the control register, in the +form of an <type>unsigned char</type>: each bit corresponds to a +control line (although some are unused). The +<function>ioctl</function> parameter should be a pointer to an +<type>unsigned char</type>.</para> + +<para>This doesn't actually touch the hardware; the last value written +is remembered in software. This is because some parallel port +hardware does not offer read access to the control register.</para> + +<para>The control lines bits are defined in +<filename>parport.h</filename>:</para> + +<itemizedlist spacing=compact> +<listitem><para><constant>PARPORT_CONTROL_STROBE</constant></para></listitem> +<listitem><para><constant>PARPORT_CONTROL_AUTOFD</constant></para></listitem> +<listitem><para><constant>PARPORT_CONTROL_SELECT</constant></para></listitem> +<listitem><para><constant>PARPORT_CONTROL_INIT</constant></para></listitem> +</itemizedlist> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPFCONTROL</constant></term> +<listitem> + +<para>Frobs the control lines. Since a common operation is to change +one of the control signals while leaving the others alone, it would be +quite inefficient for the user-land driver to have to use +<constant>PPRCONTROL</constant>, make the change, and then use +<constant>PPWCONTROL</constant>. Of course, each driver could +remember what state the control lines are supposed to be in (they are +never changed by anything else), but in order to provide +<constant>PPRCONTROL</constant>, <filename>ppdev</filename> must +remember the state of the control lines anyway.</para> + +<para>The <constant>PPFCONTROL</constant> <function>ioctl</function> +is for <quote>frobbing</quote> control lines, and is like +<constant>PPWCONTROL</constant> but acts on a restricted set of +control lines. The <function>ioctl</function> parameter is a pointer +to a <structname>struct ppdev_frob_struct</structname>:</para> + +<programlisting> +<![CDATA[ +struct ppdev_frob_struct { + unsigned char mask; + unsigned char val; +}; +]]> +</programlisting> + +<para>The <structfield>mask</structfield> and +<structfield>val</structfield> fields are bitwise ORs of control line +names (such as in <constant>PPWCONTROL</constant>). The operation +performed by <constant>PPFCONTROL</constant> is:</para> + +<programlisting> +<![CDATA[new_ctr = (old_ctr & ~mask) | val;]]> +</programlisting> + +<para>In other words, the signals named in +<structfield>mask</structfield> are set to the values in +<structfield>val</structfield>.</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPRSTATUS</constant></term> +<listitem> + +<para>Returns an <type>unsigned char</type> containing bits set for +each status line that is set (for instance, +<constant>PARPORT_STATUS_BUSY</constant>). The +<function>ioctl</function> parameter should be a pointer to an +<type>unsigned char</type>.</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPDATADIR</constant></term> +<listitem> + +<para>Controls the data line drivers. Normally the computer's +parallel port will drive the data lines, but for byte-wide transfers +from the peripheral to the host it is useful to turn off those drivers +and let the peripheral drive the signals. (If the drivers on the +computer's parallel port are left on when this happens, the port might +be damaged.)</para> + +<para>This is only needed in conjunction with +<constant>PPWDATA</constant> or <constant>PPRDATA</constant>.</para> + +<para>The <function>ioctl</function> parameter is a pointer to an +<type>int</type>. If the <type>int</type> is zero, the drivers are +turned on (forward direction); if non-zero, the drivers are turned off +(reverse direction).</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPWDATA</constant></term> +<listitem> + +<para>Sets the data lines (if in forward mode). The +<function>ioctl</function> parameter is a pointer to an <type>unsigned +char</type>.</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPRDATA</constant></term> +<listitem> + +<para>Reads the data lines (if in reverse mode). The +<function>ioctl</function> parameter is a pointer to an <type>unsigned +char</type>.</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPCLRIRQ</constant></term> +<listitem> + +<para>Clears the interrupt count. The <filename>ppdev</filename> +driver keeps a count of interrupts as they are triggered. +<constant>PPCLRIRQ</constant> stores this count in an +<type>int</type>, a pointer to which is passed in as the +<function>ioctl</function> parameter.</para> + +<para>In addition, the interrupt count is reset to zero.</para> + +</listitem></varlistentry> + +<varlistentry><term><constant>PPWCTLONIRQ</constant></term> +<listitem> + +<para>Set a trigger response. Afterwards when an interrupt is +triggered, the interrupt handler will set the control lines as +requested. The <function>ioctl</function> parameter is a pointer to +an <type>unsigned char</type>, which is interpreted in the same way as +for <constant>PPWCONTROL</constant>.</para> + +<para>The reason for this <function>ioctl</function> is simply speed. +Without this <function>ioctl</function>, responding to an interrupt +would start in the interrupt handler, switch context to the user-land +driver via <function>poll</function> or <function>select</function>, +and then switch context back to the kernel in order to handle +<constant>PPWCONTROL</constant>. Doing the whole lot in the interrupt +handler is a lot faster.</para> + +</listitem></varlistentry> + +<!-- PPSETPHASE? --> + +</variablelist> + +</sect2> + +<sect2> +<title>Transferring data: <function>read</function> and +<function>write</function></title> + +<para>Transferring data using <function>read</function> and +<function>write</function> is straightforward. The data is +transferring using the current IEEE 1284 mode (see the +<constant>PPSETMODE</constant> <function>ioctl</function>). For modes +which can only transfer data in one direction, only the appropriate +function will work, of course.</para> +</sect2> + +<sect2> +<title>Waiting for events: <function>poll</function> and +<function>select</function></title> + +<para>The <filename>ppdev</filename> driver provides user-land device +drivers with the ability to wait for interrupts, and this is done +using <function>poll</function> (and <function>select</function>, +which is implemented in terms of <function>poll</function>).</para> + +<para>When a user-land device driver wants to wait for an interrupt, +it sleeps with <function>poll</function>. When the interrupt arrives, +<filename>ppdev</filename> wakes it up (with a <quote>read</quote> +event, although strictly speaking there is nothing to actually +<function>read</function>).</para> + +</sect2> + +</sect1> + +<sect1> +<title>Examples</title> + +<para>Presented here are two demonstrations of how to write a simple +printer driver for <filename>ppdev</filename>. Firstly we will use +the <function>write</function> function, and after that we will drive +the control and data lines directly.</para> + +<para>The first thing to do is to actually open the device.</para> + +<programlisting><![CDATA[ +int drive_printer (const char *name) +{ + int fd; + int mode; /* We'll need this later. */ + + fd = open (name, O_RDWR); + if (fd == -1) { + perror ("open"); + return 1; + } +]]></programlisting> + +<para>Here <varname>name</varname> should be something along the lines +of <filename>"/dev/parport0"</filename>. (If you don't have any +<filename>/dev/parport</filename> files, you can make them with +<command>mknod</command>; they are character special device nodes with +major 99.)</para> + +<para>In order to do anything with the port we need to claim access to +it.</para> + +<programlisting><![CDATA[ + if (ioctl (fd, PPCLAIM)) { + perror ("PPCLAIM"); + close (fd); + return 1; + } +]]></programlisting> + +<para>Our printer driver will copy its input (from +<varname>stdin</varname>) to the printer, and it can do that it one of +two ways. The first way is to hand it all off to the kernel driver, +with the knowledge that the protocol that the printer speaks is IEEE +1284's <quote>compatibility</quote> mode.</para> + +<programlisting><![CDATA[ + /* Switch to compatibility mode. (In fact we don't need + * to do this, since we start off in compatibility mode + * anyway, but this demonstrates PPNEGOT.) + mode = IEEE1284_MODE_COMPAT; + if (ioctl (fd, PPNEGOT, &mode)) { + perror ("PPNEGOT"); + close (fd); + return 1; + } + + for (;;) { + char buffer[1000]; + char *ptr = buffer; + size_t got; + + got = read (0 /* stdin */, buffer, 1000); + if (got < 0) { + perror ("read"); + close (fd); + return 1; + } + + if (got == 0) + /* End of input */ + break; + + while (got > 0) { + int written = write_printer (fd, ptr, got); + + if (written < 0) { + perror ("write"); + close (fd); + return 1; + } + + ptr += written; + got -= written; + } + } +]]></programlisting> + +<para>The <function>write_printer</function> function is not pictured +above. This is because the main loop that is shown can be used for +both methods of driving the printer. Here is one implementation of +<function>write_printer</function>:</para> + +<programlisting><![CDATA[ +ssize_t write_printer (int fd, const void *ptr, size_t count) +{ + return write (fd, ptr, count); +} +]]></programlisting> + +<para>We hand the data to the kernel-level driver (using +<function>write</function>) and it handles the printer +protocol.</para> + +<para>Now let's do it the hard way! In this particular example there +is no practical reason to do anything other than just call +<function>write</function>, because we know that the printer talks an +IEEE 1284 protocol. On the other hand, this particular example does +not even need a user-land driver since there is already a kernel-level +one; for the purpose of this discussion, try to imagine that the +printer speaks a protocol that is not already implemented under +Linux.</para> + +<para>So, here is the alternative implementation of +<function>write_printer</function> (for brevity, error checking has +been omitted):</para> + +<programlisting><![CDATA[ +ssize_t write_printer (int fd, const void *ptr, size_t count) +{ + ssize_t wrote = 0; + + while (wrote < count) { + unsigned char status, control, data; + unsigned char mask = (PARPORT_STATUS_ERROR + | PARPORT_STATUS_BUSY); + unsigned char val = (PARPORT_STATUS_ERROR + | PARPORT_STATUS_BUSY); + struct parport_frob_struct frob; + struct timespec ts; + + /* Wait for printer to be ready */ + for (;;) { + ioctl (fd, PPRSTATUS, &status); + + if ((status & mask) == val) + break; + + ioctl (fd, PPRELEASE); + sleep (1); + ioctl (fd, PPCLAIM); + } + + /* Set the data lines */ + data = * ((char *) ptr)++; + ioctl (fd, PPWDATA, &data); + + /* Delay for a bit */ + ts.tv_sec = 0; + ts.tv_nsec = 1000; + nanosleep (&ts, NULL); + + /* Pulse strobe */ + frob.mask = PARPORT_CONTROL_STROBE; + frob.val = PARPORT_CONTROL_STROBE; + ioctl (fd, PPFCONTROL, &frob); + nanosleep (&ts, NULL); + + /* End the pulse */ + frob.val = 0; + ioctl (fd, PPFCONTROL, &frob); + nanosleep (&ts, NULL); + + wrote++; + } + + return wrote; +} +]]></programlisting> + +<para>To show a bit more of the <filename>ppdev</filename> interface, +here is a small piece of code that is intended to mimic the printer's +side of printer protocol.</para> + +<programlisting><![CDATA[ + for (;;) + { + int irqc; + int busy = nAck | nFault; + int acking = nFault; + int ready = Busy | nAck | nFault; + char ch; + + /* Set up the control lines when an interrupt happens. */ + ioctl (fd, PPWCTLONIRQ, &busy); + + /* Now we're ready. */ + ioctl (fd, PPWCONTROL, &ready); + + /* Wait for an interrupt. */ + { + fd_set rfds; + FD_ZERO (&rfds); + FD_SET (fd, &rfds); + if (!select (fd + 1, &rfds, NULL, NULL, NULL)) + /* Caught a signal? */ + continue; + } + + /* We are now marked as busy. */ + + /* Fetch the data. */ + ioctl (fd, PPRDATA, &ch); + + /* Clear the interrupt. */ + ioctl (fd, PPCLRIRQ, &irqc); + if (irqc > 1) + fprintf (stderr, "Arghh! Missed %d interrupt%s!\n", + irqc - 1, irqc == 2 ? "s" : ""); + + /* Ack it. */ + ioctl (fd, PPWCONTROL, &acking); + usleep (2); + ioctl (fd, PPWCONTROL, &busy); + + putchar (ch); + } +]]></programlisting> + +</sect1> + +</chapter> +</book>
\ No newline at end of file diff --git a/Documentation/DocBook/videobook.tmpl b/Documentation/DocBook/videobook.tmpl new file mode 100644 index 000000000..c152abf31 --- /dev/null +++ b/Documentation/DocBook/videobook.tmpl @@ -0,0 +1,1663 @@ +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]> + +<book id="V4LGuide"> + <bookinfo> + <title>Video4Linux Programming</title> + + <authorgroup> + <author> + <firstname>Alan</firstname> + <surname>Cox</surname> + <affiliation> + <address> + <email>alan@redhat.com</email> + </address> + </affiliation> + </author> + </authorgroup> + + <copyright> + <year>2000</year> + <holder>Alan Cox</holder> + </copyright> + + <legalnotice> + <para> + This documentation 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. + </para> + + <para> + 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. + </para> + + <para> + 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., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + </para> + + <para> + For more details see the file COPYING in the source + distribution of Linux. + </para> + </legalnotice> + </bookinfo> + +<toc></toc> + + <chapter id="intro"> + <title>Introduction</title> + <para> + Parts of this document first appeared in Linux Magazine under a + ninety day exclusivity. + </para> + <para> + Video4Linux is intended to provide a common programming interface + for the many TV and capture cards now on the market, as well as + parallel port and USB video cameras. Radio, teletext decoders and + vertical blanking data interfaces are also provided. + </para> + </chapter> + <chapter> + <title>Radio Devices</title> + <para> + There are a wide variety of radio interfaces available for PC's, and these + are generally very simple to program. The biggest problem with supporting + such devices is normally extracting documentation from the vendor. + </para> + <para> + The radio interface supports a simple set of control ioctls standardised + across all radio and tv interfaces. It does not support read or write, which + are used for video streams. The reason radio cards do not allow you to read + the audio stream into an application is that without exception they provide + a connection on to a soundcard. Soundcards can be used to read the radio + data just fine. + </para> + <sect1 id="registerradio"> + <title>Registering Radio Devices</title> + <para> + The Video4linux core provides an interface for registering devices. The + first step in writing our radio card driver is to register it. + </para> + <programlisting> + + +static struct video_device my_radio +{ + "My radio", + VID_TYPE_TUNER, + VID_HARDWARE_MYRADIO, + radio_open. + radio_close, + NULL, /* no read */ + NULL, /* no write */ + NULL, /* no poll */ + radio_ioctl, + NULL, /* no special init function */ + NULL /* no private data */ +}; + + + </programlisting> + <para> + This declares our video4linux device driver interface. The VID_TYPE_ value + defines what kind of an interface we are, and defines basic capabilities. + </para> + <para> + The only defined value relevant for a radio card is VID_TYPE_TUNER which + indicates that the device can be tuned. Clearly our radio is going to have some + way to change channel so it is tuneable. + </para> + <para> + The VID_HARDWARE_ types are unique to each device. Numbers are assigned by + <email>alan@redhat.com</email> when device drivers are going to be released. Until then you + can pull a suitably large number out of your hat and use it. 10000 should be + safe for a very long time even allowing for the huge number of vendors + making new and different radio cards at the moment. + </para> + <para> + We declare an open and close routine, but we do not need read or write, + which are used to read and write video data to or from the card itself. As + we have no read or write there is no poll function. + </para> + <para> + The private initialise function is run when the device is registered. In + this driver we've already done all the work needed. The final pointer is a + private data pointer that can be used by the device driver to attach and + retrieve private data structures. We set this field "priv" to NULL for + the moment. + </para> + <para> + Having the structure defined is all very well but we now need to register it + with the kernel. + </para> + <programlisting> + + +static int io = 0x320; + +int __init myradio_init(struct video_init *v) +{ + if(check_region(io, MY_IO_SIZE)) + { + printk(KERN_ERR + "myradio: port 0x%03X is in use.\n", io); + return -EBUSY; + } + + if(video_device_register(&my_radio, VFL_TYPE_RADIO)==-1) + return -EINVAL; + request_region(io, MY_IO_SIZE, "myradio"); + return 0; +} + + </programlisting> + <para> + The first stage of the initialisation, as is normally the case, is to check + that the I/O space we are about to fiddle with doesn't belong to some other + driver. If it is we leave well alone. If the user gives the address of the + wrong device then we will spot this. These policies will generally avoid + crashing the machine. + </para> + <para> + Now we ask the Video4Linux layer to register the device for us. We hand it + our carefully designed video_device structure and also tell it which group + of devices we want it registered with. In this case VFL_TYPE_RADIO. + </para> + <para> + The types available are + </para> + <table frame=all><title>Device Types</title> + <tgroup cols=3 align=left> + <tbody> + <row> + <entry>VFL_TYPE_RADIO</><>/dev/radio{n}</><> + + Radio devices are assigned in this block. As with all of these + selections the actual number assignment is done by the video layer + accordijng to what is free.</entry> + </row><row> + <entry>VFL_TYPE_GRABBER</><>/dev/video{n}</><> + Video capture devices and also -- counter-intuitively for the name -- + hardware video playback devices such as MPEG2 cards.</entry> + </row><row> + <entry>VFL_TYPE_VBI</><>/dev/vbi{n}</><> + The VBI devices capture the hidden lines on a television picture + that carry further information like closed caption data, teletext + (primarily in Europe) and now Intercast and the ATVEC internet + television encodings.</entry> + </row><row> + <entry>VFL_TYPE_VTX</><>/dev/vtx[n}</><> + VTX is 'Videotext' also known as 'Teletext'. This is a system for + sending numbered, 40x25, mostly textual page images over the hidden + lines. Unlike the /dev/vbi interfaces, this is for 'smart' decoder + chips. (The use of the word smart here has to be taken in context, + the smartest teletext chips are fairly dumb pieces of technology). + </entry> + </row> + </tbody> + </tgroup> + </table> + <para> + We are most definitely a radio. + </para> + <para> + Finally we allocate our I/O space so that nobody treads on us and return 0 + to signify general happiness with the state of the universe. + </para> + </sect1> + <sect1 id="openradio"> + <title>Opening And Closing The Radio</title> + + <para> + The functions we declared in our video_device are mostly very simple. + Firstly we can drop in what is basically standard code for open and close. + </para> + <programlisting> + + +static int users = 0; + +static int radio_open(stuct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + + </programlisting> + <para> + At open time we need to do nothing but check if someone else is also using + the radio card. If nobody is using it we make a note that we are using it, + then we ensure that nobody unloads our driver on us. + </para> + <programlisting> + + +static int radio_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + + </programlisting> + <para> + At close time we simply need to reduce the user count and allow the module + to become unloadable. + </para> + <para> + If you are sharp you will have noticed neither the open nor the close + routines attempt to reset or change the radio settings. This is intentional. + It allows an application to set up the radio and exit. It avoids a user + having to leave an application running all the time just to listen to the + radio. + </para> + </sect1> + <sect1 id="ioctlradio"> + <title>The Ioctl Interface</title> + <para> + This leaves the ioctl routine, without which the driver will not be + terribly useful to anyone. + </para> + <programlisting> + + +static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability v; + v.type = VID_TYPE_TUNER; + v.channels = 1; + v.audios = 1; + v.maxwidth = 0; + v.minwidth = 0; + v.maxheight = 0; + v.minheight = 0; + strcpy(v.name, "My Radio"); + if(copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + + </programlisting> + <para> + VIDIOCGCAP is the first ioctl all video4linux devices must support. It + allows the applications to find out what sort of a card they have found and + to figure out what they want to do about it. The fields in the structure are + </para> + <table frame=all><title>struct video_capability fields</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>name</><>The device text name. This is intended for the user.</> + </row><row> + <entry>channels</><>The number of different channels you can tune on + this card. It could even by zero for a card that has + no tuning capability. For our simple FM radio it is 1. + An AM/FM radio would report 2.</entry> + </row><row> + <entry>audios</><>The number of audio inputs on this device. For our + radio there is only one audio input.</entry> + </row><row> + <entry>minwidth,minheight</><>The smallest size the card is capable of capturing + images in. We set these to zero. Radios do not + capture pictures</entry> + </row><row> + <entry>maxwidth,maxheight</><>The largest image size the card is capable of + capturing. For our radio we report 0. + </entry> + </row><row> + <entry>type</><>This reports the capabilities of the device, and + matches the field we filled in in the struct + video_device when registering.</entry> + </row> + </tbody> + </tgroup> + </table> + <para> + Having filled in the fields, we use copy_to_user to copy the structure into + the users buffer. If the copy fails we return an EFAULT to the application + so that it knows it tried to feed us garbage. + </para> + <para> + The next pair of ioctl operations select which tuner is to be used and let + the application find the tuner properties. We have only a single FM band + tuner in our example device. + </para> + <programlisting> + + + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))!=0) + return -EFAULT; + if(v.tuner) + return -EINVAL; + v.rangelow=(87*16000); + v.rangehigh=(108*16000); + v.flags = VIDEO_TUNER_LOW; + v.mode = VIDEO_MODE_AUTO; + v.signal = 0xFFFF; + strcpy(v.name, "FM"); + if(copy_to_user(&v, arg, sizeof(v))!=0) + return -EFAULT; + return 0; + } + + </programlisting> + <para> + The VIDIOCGTUNER ioctl allows applications to query a tuner. The application + sets the tuner field to the tuner number it wishes to query. The query does + not change the tuner that is being used, it merely enquires about the tuner + in question. + </para> + <para> + We have exactly one tuner so after copying the user buffer to our temporary + structure we complain if they asked for a tuner other than tuner 0. + </para> + <para> + The video_tuner structure has the following fields + </para> + <table frame=all><title>struct video_tuner fields</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>int tuner</><entry>The number of the tuner in question</entry> + </row><row> + <entry>char name[32]</><entry>A text description of this tuner. "FM" will do fine. + This is intended for the application.</entry> + </row><row> + <entry>u32 flags</> + <entry>Tuner capability flags</entry> + </row> + <row> + <entry>u16 mode</><entry>The current reception mode</entry> + + </row><row> + <entry>u16 signal</><entry>The signal strength scaled between 0 and 65535. If + a device cannot tell the signal strength it should + report 65535. Many simple cards contain only a + signal/no signal bit. Such cards will report either + 0 or 65535.</entry> + + </row><row> + <entry>u32 rangelow, rangehigh</><entry> + The range of frequencies supported by the radio + or TV. It is scaled according to the VIDEO_TUNER_LOW + flag.</entry> + + </row> + </tbody> + </tgroup> + </table> + + <table frame=all><title>struct video_tuner flags</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>VIDEO_TUNER_PAL</><entry>A PAL TV tuner</entry> + </row><row> + <entry>VIDEO_TUNER_NTSC</><entry>An NTSC (US) TV tuner</entry> + </row><row> + <entry>VIDEO_TUNER_SECAM</><entry>A SECAM (French) TV tuner</entry> + </row><row> + <entry>VIDEO_TUNER_LOW</><> + The tuner frequency is scaled in 1/16th of a KHz + steps. If not it is in 1/16th of a MHz steps + </entry> + </row><row> + <entry>VIDEO_TUNER_NORM</><entry>The tuner can set its format</entry> + </row><row> + <entry>VIDEO_TUNER_STEREO_ON</><entry>The tuner is currently receiving a stereo signal</entry> + </row> + </tbody> + </tgroup> + </table> + + <table frame=all><title>struct video_tuner modes</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>VIDEO_MODE_PAL</><>PAL Format</entry> + </row><row> + <entry>VIDEO_MODE_NTSC</><>NTSC Format (USA)</entry> + </row><row> + <entry>VIDEO_MODE_SECAM</><>French Format</entry> + </row><row> + <entry>VIDEO_MODE_AUTO</><>A device that does not need to do + TV format switching</entry> + </row> + </tbody> + </tgroup> + </table> + <para> + The settings for the radio card are thus fairly simple. We report that we + are a tuner called "FM" for FM radio. In order to get the best tuning + resolution we report VIDEO_TUNER_LOW and select tuning to 1/16th of KHz. Its + unlikely our card can do that resolution but it is a fair bet the card can + do better than 1/16th of a MHz. VIDEO_TUNER_LOW is appropriate to almost all + radio usage. + </para> + <para> + We report that the tuner automatically handles deciding what format it is + receiving - true enough as it only handles FM radio. Our example card is + also incapable of detecting stereo or signal strengths so it reports a + strength of 0xFFFF (maximum) and no stereo detected. + </para> + <para> + To finish off we set the range that can be tuned to be 87-108Mhz, the normal + FM broadcast radio range. It is important to find out what the card is + actually capable of tuning. It is easy enough to simply use the FM broadcast + range. Unfortunately if you do this you will discover the FM broadcast + ranges in the USA, Europe and Japan are all subtly different and some users + cannot receive all the stations they wish. + </para> + <para> + The application also needs to be able to set the tuner it wishes to use. In + our case, with a single tuner this is rather simple to arrange. + </para> + <programlisting> + + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner != 0) + return -EINVAL; + return 0; + } + + </programlisting> + <para> + We copy the user supplied structure into kernel memory so we can examine it. + If the user has selected a tuner other than zero we reject the request. If + they wanted tuner 0 then, suprisingly enough, that is the current tuner already. + </para> + <para> + The next two ioctls we need to provide are to get and set the frequency of + the radio. These both use an unsigned long argument which is the frequency. + The scale of the frequency depends on the VIDEO_TUNER_LOW flag as I + mentioned earlier on. Since we have VIDEO_TUNER_LOW set this will be in + 1/16ths of a KHz. + </para> + <programlisting> + +static unsigned long current_freq; + + + + case VIDIOCGFREQ: + if(copy_to_user(arg, &current_freq, + sizeof(unsigned long)) + return -EFAULT; + return 0; + + </programlisting> + <para> + Querying the frequency in our case is relatively simple. Our radio card is + too dumb to let us query the signal strength so we remember our setting if + we know it. All we have to do is copy it to the user. + </para> + <programlisting> + + + case VIDIOCSFREQ: + { + u32 freq; + if(copy_from_user(arg, &freq, + sizeof(unsigned long))!=0) + return -EFAULT; + if(hardware_set_freq(freq)<0) + return -EINVAL; + current_freq = freq; + return 0; + } + + </programlisting> + <para> + Setting the frequency is a little more complex. We begin by copying the + desired frequency into kernel space. Next we call a hardware specific routine + to set the radio up. This might be as simple as some scaling and a few + writes to an I/O port. For most radio cards it turns out a good deal more + complicated and may involve programming things like a phase locked loop on + the card. This is what documentation is for. + </para> + <para> + The final set of operations we need to provide for our radio are the + volume controls. Not all radio cards can even do volume control. After all + there is a perfectly good volume control on the sound card. We will assume + our radio card has a simple 4 step volume control. + </para> + <para> + There are two ioctls with audio we need to support + </para> + <programlisting> + +static int current_volume=0; + + case VIDIOCGAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio != 0) + return -EINVAL; + v.volume = 16384*current_volume; + v.step = 16384; + strcpy(v.name, "Radio"); + v.mode = VIDEO_SOUND_MONO; + v.balance = 0; + v.base = 0; + v.treble = 0; + + if(copy_to_user(arg. &v, sizeof(v))) + return -EFAULT; + return 0; + } + + </programlisting> + <para> + Much like the tuner we start by copying the user structure into kernel + space. Again we check if the user has asked for a valid audio input. We have + only input 0 and we punt if they ask for another input. + </para> + <para> + Then we fill in the video_audio structure. This has the following format + </para> + <table frame=all><title>struct video_audio fields</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>audio</><>The input the user wishes to query</> + </row><row> + <entry>volume</><>The volume setting on a scale of 0-65535</> + </row><row> + <entry>base</><>The base level on a scale of 0-65535</> + </row><row> + <entry>treble</><>The treble level on a scale of 0-65535</> + </row><row> + <entry>flags</><>The features this audio device supports + </entry> + </row><row> + <entry>name</><>A text name to display to the user. We picked + "Radio" as it explains things quite nicely.</> + </row><row> + <entry>mode</><>The current reception mode for the audio + + We report MONO because our card is too stupid to know if it is in + mono or stereo. + </entry> + </row><row> + <entry>balance</><>The stereo balance on a scale of 0-65535, 32768 is + middle.</> + </row><row> + <entry>step</><>The step by which the volume control jumps. This is + used to help make it easy for applications to set + slider behaviour.</> + </row> + </tbody> + </tgroup> + </table> + + <table frame=all><title>struct video_audio flags</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>VIDEO_AUDIO_MUTE</><>The audio is currently muted. We + could fake this in our driver but we + choose not to bother.</entry> + </row><row> + <entry>VIDEO_AUDIO_MUTABLE</><>The input has a mute option</entry> + </row><row> + <entry>VIDEO_AUDIO_TREBLE</><>The input has a treble control</entry> + </row><row> + <entry>VIDEO_AUDIO_BASS</><>The input has a base control</entry> + </row> + </tbody> + </tgroup> + </table> + + <table frame=all><title>struct video_audio modes</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>VIDEO_SOUND_MONO</><>Mono sound</entry> + </row><row> + <entry>VIDEO_SOUND_STEREO</><>Stereo sound</entry> + </row><row> + <entry>VIDEO_SOUND_LANG1</><>Alternative language 1 (TV specific)</entry> + </row><row> + <entry>VIDEO_SOUND_LANG2</><>Alternative language 2 (TV specific)</entry> + </row> + </tbody> + </tgroup> + </table> + <para> + Having filled in the structure we copy it back to user space. + </para> + <para> + The VIDIOCSAUDIO ioctl allows the user to set the audio parameters in the + video_audio stucture. The driver does its best to honour the request. + </para> + <programlisting> + + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + current_volume = v/16384; + hardware_set_volume(current_volume); + return 0; + } + + </programlisting> + <para> + In our case there is very little that the user can set. The volume is + basically the limit. Note that we could pretend to have a mute feature + by rewriting this to + </para> + <programlisting> + + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + current_volume = v/16384; + if(v.flags&VIDEO_AUDIO_MUTE) + hardware_set_volume(0); + else + hardware_set_volume(current_volume); + current_muted = v.flags & + VIDEO_AUDIO_MUTE; + return 0; + } + + </programlisting> + <para> + This with the corresponding changes to the VIDIOCGAUDIO code to report the + state of the mute flag we save and to report the card has a mute function, + will allow applications to use a mute facility with this card. It is + questionable whether this is a good idea however. User applications can already + fake this themselves and kernel space is precious. + </para> + <para> + We now have a working radio ioctl handler. So we just wrap up the function + </para> + <programlisting> + + + } + return -ENOIOCTLCMD; +} + + </programlisting> + <para> + and pass the Video4Linux layer back an error so that it knows we did not + understand the request we got passed. + </para> + </sect1> + <sect1 id="modradio"> + <title>Module Wrapper</title> + <para> + Finally we add in the usual module wrapping and the driver is done. + </para> + <programlisting> + +#ifndef MODULE + +static int io = 0x300; + +#else + +static int io = -1; + + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("A driver for an imaginary radio card."); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O address of the card."); + +EXPORT_NO_SYMBOLS; + +int init_module(void) +{ + if(io==-1) + { + printk(KERN_ERR + "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } + return myradio_init(NULL); +} + +void cleanup_module(void) +{ + video_unregister_device(&my_radio); + release_region(io, MY_IO_SIZE); +} + +#endif + + </programlisting> + <para> + In this example we set the IO base by default if the driver is compiled into + the kernel where you cannot pass a parameter. For the module we require the + user sets the parameter. We set io to a nonsense port (-1) so that we can + tell if the user supplied an io parameter or not. + </para> + <para> + We use MODULE_ defines to give an author for the card driver and a + description. We also use them to declare that io is an integer and it is the + address of the card. + </para> + <para> + The clean-up routine unregisters the video_device we registered, and frees + up the I/O space. Note that the unregister takes the actual video_device + structure as its argument. Unlike the file operations structure which can be + shared by all instances of a device a video_device structure as an actual + instance of the device. If you are registering multiple radio devices you + need to fill in one structure per device (most likely by setting up a + template and copying it to each of the actual device structures). + </para> + </sect1> + </chapter> + <chapter> + <title>Video Capture Devices</title> + <sect1 id="introvid"> + <title>Video Capture Device Types</title> + <para> + The video capture devices share the same interfaces as radio devices. In + order to explain the video capture interface I will use the example of a + camera that has no tuners or audio input. This keeps the example relatively + clean. To get both combine the two driver examples. + </para> + <para> + Video capture devices divide into four categories. A little technology + backgrounder. Full motion video even at television resolution (which is + actually fairly low) is pretty resource-intensive. You are continually + passing megabytes of data every second from the capture card to the display. + several alternative approaches have emerged because copying this through the + processor and the user program is a particularly bad idea . + </para> + <para> + The first is to add the television image onto the video output directly. + This is also how some 3D cards work. These basic cards can generally drop the + video into any chosen rectangle of the display. Cards like this, which + include most mpeg1 cards that used the feature connector, aren't very + friendly in a windowing environment. They don't understand windows or + clipping. The video window is always on the top of the display. + </para> + <para> + Chroma keying is a technique used by cards to get around this. It is an old + television mixing trick where you mark all the areas you wish to replace + with a single clear colour that isn't used in the image - TV people use an + incredibly bright blue while computing people often use a paticularly + virulent purple. Bright blue occurs on the desktop. Anyone with virulent + purple windows has another problem besides their TV overlay. + </para> + <para> + The third approach is to copy the data from the capture card to the video + card, but to do it directly across the PCI bus. This relieves the processor + from doing the work but does require some smartness on the part of the video + capture chip, as well as a suitable video card. Programming this kind of + card and more so debugging it can be extremely tricky. There are some quite + complicated interactions with the display and you may also have to cope with + various chipset bugs that show up when PCI cards start talking to each + other. + </para> + <para> + To keep our example fairly simple we will assume a card that supports + overlaying a flat rectangular image onto the frame buffer output, and which + can also capture stuff into processor memory. + </para> + </sect1> + <sect1 id="regvid"> + <title>Registering Video Capture Devices</title> + <para> + This time we need to add more functions for our camera device. + </para> + <programlisting> +static struct video_device my_camera +{ + "My Camera", + VID_TYPE_OVERLAY|VID_TYPE_SCALES|\ + VID_TYPE_CAPTURE|VID_TYPE_CHROMAKEY, + VID_HARDWARE_MYCAMERA, + camera_open. + camera_close, + camera_read, /* no read */ + NULL, /* no write */ + camera_poll, /* no poll */ + camera_ioctl, + NULL, /* no special init function */ + NULL /* no private data */ +}; + </programlisting> + <para> + We need a read() function which is used for capturing data from + the card, and we need a poll function so that a driver can wait for the next + frame to be captured. + </para> + <para> + We use the extra video capability flags that did not apply to the + radio interface. The video related flags are + </para> + <table frame=all><title>Capture Capabilities</title> + <tgroup cols=2 align=left> + <tbody> + <row> +<entry>VID_TYPE_CAPTURE</><>We support image capture</> +</row><row> +<entry>VID_TYPE_TELETEXT</><>A teletext capture device (vbi{n])</> +</row><row> +<entry>VID_TYPE_OVERLAY</><>The image can be directly overlaid onto the + frame buffer</> +</row><row> +<entry>VID_TYPE_CHROMAKEY</><>Chromakey can be used to select which parts + of the image to display</> +</row><row> +<entry>VID_TYPE_CLIPPING</><>It is possible to give the board a list of + rectangles to draw around. </> +</row><row> +<entry>VID_TYPE_FRAMERAM</><>The video capture goes into the video memory + and actually changes it. Applications need + to know this so they can clean up after the + card</> +</row><row> +<entry>VID_TYPE_SCALES</><>The image can be scaled to various sizes, + rather than being a single fixed size.</> +</row><row> +<entry>VID_TYPE_MONOCHROME</><>The capture will be monochrome. This isn't a + complete answer to the question since a mono + camera on a colour capture card will still + produce mono output.</> +</row><row> +<entry>VID_TYPE_SUBCAPTURE</><>The card allows only part of its field of + view to be captured. This enables + applications to avoid copying all of a large + image into memory when only some section is + relevant.</> + </row> + </tbody> + </tgroup> + </table> + <para> + We set VID_TYPE_CAPTURE so that we are seen as a capture card, + VID_TYPE_CHROMAKEY so the application knows it is time to draw in virulent + purple, and VID_TYPE_SCALES because we can be resized. + </para> + <para> + Our setup is fairly similar. This time we also want an interrupt line + for the 'frame captured' signal. Not all cards have this so some of them + cannot handle poll(). + </para> + <programlisting> + + +static int io = 0x320; +static int irq = 11; + +int __init mycamera_init(struct video_init *v) +{ + if(check_region(io, MY_IO_SIZE)) + { + printk(KERN_ERR + "mycamera: port 0x%03X is in use.\n", io); + return -EBUSY; + } + + if(video_device_register(&my_camera, + VFL_TYPE_GRABBER)==-1) + return -EINVAL; + request_region(io, MY_IO_SIZE, "mycamera"); + return 0; +} + + </programlisting> + <para> + This is little changed from the needs of the radio card. We specify + VFL_TYPE_GRABBER this time as we want to be allocated a /dev/video name. + </para> + </sect1> + <sect1 id="opvid"> + <title>Opening And Closing The Capture Device</title> + <programlisting> + + +static int users = 0; + +static int camera_open(stuct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + if(request_irq(irq, camera_irq, 0, "camera", dev)<0) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + + +static int camera_close(struct video_device *dev) +{ + users--; + free_irq(irq, dev); + MOD_DEC_USE_COUNT; +} + </programlisting> + <para> + The open and close routines are also quite similar. The only real change is + that we now request an interrupt for the camera device interrupt line. If we + cannot get the interrupt we report EBUSY to the application and give up. + </para> + </sect1> + <sect1 id="irqvid"> + <title>Interrupt Handling</title> + <para> + Our example handler is for an ISA bus device. If it was PCI you would be + able to share the interrupt and would have set SA_SHIRQ to indicate a + shared IRQ. We pass the device pointer as the interrupt routine argument. We + don't need to since we only support one card but doing this will make it + easier to upgrade the driver for multiple devices in the future. + </para> + <para> + Our interrupt routine needs to do little if we assume the card can simply + queue one frame to be read after it captures it. + </para> + <programlisting> + + +static struct wait_queue *capture_wait; +static int capture_ready = 0; + +static void camera_irq(int irq, void *dev_id, + struct pt_regs *regs) +{ + capture_ready=1; + wake_up_interruptible(&capture_wait); +} + </programlisting> + <para> + The interrupt handler is nice and simple for this card as we are assuming + the card is buffering the frame for us. This means we have little to do but + wake up anybody interested. We also set a capture_ready flag, as we may + capture a frame before an application needs it. In this case we need to know + that a frame is ready. If we had to collect the frame on the interrupt life + would be more complex. + </para> + <para> + The two new routines we need to supply are camera_read which returns a + frame, and camera_poll which waits for a frame to become ready. + </para> + <programlisting> + + +static int camera_poll(struct video_device *dev, + struct file *file, struct poll_table *wait) +{ + poll_wait(file, &capture_wait, wait); + if(capture_read) + return POLLIN|POLLRDNORM; + return 0; +} + + </programlisting> + <para> + Our wait queue for polling is the capture_wait queue. This will cause the + task to be woken up by our camera_irq routine. We check capture_read to see + if there is an image present and if so report that it is readable. + </para> + </sect1> + <sect1 id="rdvid"> + <title>Reading The Video Image</title> + <programlisting> + + +static long camera_read(struct video_device *dev, char *buf, + unsigned long count) +{ + struct wait_queue wait = { current, NULL }; + u8 *ptr; + int len; + int i; + + add_wait_queue(&capture_wait, &wait); + + while(!capture_ready) + { + if(file->flags&O_NDELAY) + { + remove_wait_queue(&capture_wait, &wait); + current->state = TASK_RUNNING; + return -EWOULDBLOCK; + } + if(signal_pending(current)) + { + remove_wait_queue(&capture_wait, &wait); + current->state = TASK_RUNNING; + return -ERESTARTSYS; + } + schedule(); + current->state = TASK_INTERRUPTIBLE; + } + remove_wait_queue(&capture_wait, &wait); + current->state = TASK_RUNNING; + + </programlisting> + <para> + The first thing we have to do is to ensure that the application waits until + the next frame is ready. The code here is almost identical to the mouse code + we used earlier in this chapter. It is one of the common building blocks of + Linux device driver code and probably one which you will find occurs in any + drivers you write. + </para> + <para> + We wait for a frame to be ready, or for a signal to interrupt our waiting. If a + signal occurs we need to return from the system call so that the signal can + be sent to the application itself. We also check to see if the user actually + wanted to avoid waiting - ie if they are using non-blocking I/O and have other things + to get on with. + </para> + <para> + Next we copy the data from the card to the user application. This is rarely + as easy as our example makes out. We will add capture_w, and capture_h here + to hold the width and height of the captured image. We assume the card only + supports 24bit RGB for now. + </para> + <programlisting> + + + + capture_ready = 0; + + ptr=(u8 *)buf; + len = capture_w * 3 * capture_h; /* 24bit RGB */ + + if(len>count) + len=count; /* Doesn't all fit */ + + for(i=0; i<len; i++) + { + put_user(inb(io+IMAGE_DATA), ptr); + ptr++; + } + + hardware_restart_capture(); + + return i; +} + + </programlisting> + <para> + For a real hardware device you would try to avoid the loop with put_user(). + Each call to put_user() has a time overhead checking whether the accesses to user + space are allowed. It would be better to read a line into a temporary buffer + then copy this to user space in one go. + </para> + <para> + Having captured the image and put it into user space we can kick the card to + get the next frame acquired. + </para> + </sect1> + <sect1 id="iocvid"> + <title>Video Ioctl Handling</title> + <para> + As with the radio driver the major control interface is via the ioctl() + function. Video capture devices support the same tuner calls as a radio + device and also support additional calls to control how the video functions + are handled. In this simple example the card has no tuners to avoid making + the code complex. + </para> + <programlisting> + + + +static int camera_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + switch(cmd) + { + case VIDIOCGCAP: + { + struct video_capability v; + v.type = VID_TYPE_CAPTURE|\ + VID_TYPE_CHROMAKEY|\ + VID_TYPE_SCALES|\ + VID_TYPE_OVERLAY; + v.channels = 1; + v.audios = 0; + v.maxwidth = 640; + v.minwidth = 16; + v.maxheight = 480; + v.minheight = 16; + strcpy(v.name, "My Camera"); + if(copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + + + </programlisting> + <para> + The first ioctl we must support and which all video capture and radio + devices are required to support is VIDIOCGCAP. This behaves exactly the same + as with a radio device. This time, however, we report the extra capabilities + we outlined earlier on when defining our video_dev structure. + </para> + <para> + We now set the video flags saying that we support overlay, capture, + scaling and chromakey. We also report size limits - our smallest image is + 16x16 pixels, our largest is 640x480. + </para> + <para> + To keep things simple we report no audio and no tuning capabilities at all. + </para> + <programlisting> + + case VIDIOCGCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.channel != 0) + return -EINVAL; + v.flags = 0; + v.tuners = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = VIDEO_MODE_AUTO; + strcpy(v.name, "Camera Input");break; + if(copy_to_user(&v, arg, sizeof(v))) + return -EFAULT; + return 0; + } + + + </programlisting> + <para> + This follows what is very much the standard way an ioctl handler looks + in Linux. We copy the data into a kernel space variable and we check that the + request is valid (in this case that the input is 0). Finally we copy the + camera info back to the user. + </para> + <para> + The VIDIOCGCHAN ioctl allows a user to ask about video channels (that is + inputs to the video card). Our example card has a single camera input. The + fields in the structure are + </para> + <table frame=all><title>struct video_channel fields</title> + <tgroup cols=2 align=left> + <tbody> + <row> + + <entry>channel</><>The channel number we are selecting</entry> + </row><row> + <entry>name</><>The name for this channel. This is intended + to describe the port to the user. + Appropriate names are therefore things like + "Camera" "SCART input"</entry> + </row><row> + <entry>flags</><>Channel properties</entry> + </row><row> + <entry>type</><>Input type</entry> + </row><row> + <entry>norm</><>The current television encoding being used + if relevant for this channel. + </entry> + </row> + </tbody> + </tgroup> + </table> + <table frame=all><title>struct video_channel flags</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>VIDEO_VC_TUNER</><>Channel has a tuner.</entry> + </row><row> + <entry>VIDEO_VC_AUDIO</><>Channel has audio.</entry> + </row> + </tbody> + </tgroup> + </table> + <table frame=all><title>struct video_channel types</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>VIDEO_TYPE_TV</><>Television input.</entry> + </row><row> + <entry>VIDEO_TYPE_CAMERA</><>Fixed camera input.</entry> + </row><row> + <entry>0</><>Type is unknown.</entry> + </row> + </tbody> + </tgroup> + </table> + <table frame=all><title>struct video_channel norms</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>VIDEO_MODE_PAL</><>PAL encoded Television</entry> + </row><row> + <entry>VIDEO_MODE_NTSC</><>NTSC (US) encoded Television</entry> + </row><row> + <entry>VIDEO_MODE_SECAM</><>SECAM (French) Televison </entry> + </row><row> + <entry>VIDEO_MODE_AUTO</><>Automatic switching, or format does not + matter</entry> + </row> + </tbody> + </tgroup> + </table> + <para> + The corresponding VIDIOCSCHAN ioctl allows a user to change channel and to + request the norm is changed - for exaple to switch between a PAL or an NTSC + format camera. + </para> + <programlisting> + + + case VIDIOCSCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.channel != 0) + return -EINVAL; + if(v.norm != VIDEO_MODE_AUTO) + return -EINVAL; + return 0; + } + + + </programlisting> + <para> + The implementation of this call in our driver is remarkably easy. Because we + are assuming fixed format hardware we need only check that the user has not + tried to change anything. + </para> + <para> + The user also needs to be able to configure and adjust the picture they are + seeing. This is much like adjusting a television set. A user application + also needs to know the palette being used so that it knows how to display + the image that has been captured. The VIDIOCGPICT and VIDIOCSPICT ioctl + calls provide this information. + </para> + <programlisting> + + + case VIDIOCGPICT + { + struct video_picture v; + v.brightness = hardware_brightness(); + v.hue = hardware_hue(); + v.colour = hardware_saturation(); + v.contrast = hardware_brightness(); + /* Not settable */ + v.whiteness = 32768; + v.depth = 24; /* 24bit */ + v.palette = VIDEO_PALETTE_RGB24; + if(copy_to_user(&v, arg, + sizeof(v))) + return -EFAULT; + return 0; + } + + + </programlisting> + <para> + The brightness, hue, color, and contrast provide the picture controls that + are akin to a conventional television. Whiteness provides additional + control for greyscale images. All of these values are scaled between 0-65535 + and have 32768 as the mid point setting. The scaling means that applications + do not have to worry about the capability range of the hardware but can let + it make a best effort attempt. + </para> + <para> + Our depth is 24, as this is in bits. We will be returing RGB24 format. This + has one byte of red, then one of green, then one of blue. This then repeats + for every other pixel in the image. The other common formats the interface + defines are + </para> + <table frame=all><title>Framebuffer Encodings</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>GREY</><>Linear greyscale. This is for simple cameras and the + like</> + </row><row> + <entry>RGB565</><>The top 5 bits hold 32 red levels, the next six bits + hold green and the low 5 bits hold blue. </> + </row><row> + <entry>RGB555</><>The top bit is clear. The red green and blue levels + each occupy five bits.</> + </row> + </tbody> + </tgroup> + </table> + <para> + Additional modes are support for YUV capture formats. These are common for + TV and video conferencing applications. + </para> + <para> + The VIDIOCSPICT ioctl allows a user to set some of the picture parameters. + Exactly which ones are supported depends heavily on the card itself. It is + possible to support many modes and effects in software. In general doing + this in the kernel is a bad idea. Video capture is a performance-sensitive + application and the programs can often do better if they aren't being + 'helped' by an overkeen driver writer. Thus for our device we will report + RGB24 only and refuse to allow a change. + </para> + <programlisting> + + + case VIDIOCSPICT: + { + struct video_picture v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.depth!=24 || + v.palette != VIDEO_PALETTE_RGB24) + return -EINVAL; + set_hardware_brightness(v.brightness); + set_hardware_hue(v.hue); + set_hardware_saturation(v.colour); + set_hardware_brightness(v.contrast); + return 0; + } + + + </programlisting> + <para> + We check the user has not tried to change the palette or the depth. We do + not want to carry out some of the changes and then return an error. This may + confuse the application which will be assuming no change occurred. + </para> + <para> + In much the same way as you need to be able to set the picture controls to + get the right capture images, many cards need to know what they are + displaying onto when generating overlay output. In some cases getting this + wrong even makes a nasty mess or may crash the computer. For that reason + the VIDIOCSBUF ioctl used to set up the frame buffer information may well + only be usable by root. + </para> + <para> + We will assume our card is one of the old ISA devices with feature connector + and only supports a couple of standard video modes. Very common for older + cards although the PCI devices are way smarter than this. + </para> + <programlisting> + + +static struct video_buffer capture_fb; + + case VIDIOCGFBUF: + { + if(copy_to_user(arg, &capture_fb, + sizeof(capture_fb))) + return -EFAULT; + return 0; + + } + + + </programlisting> + <para> + We keep the frame buffer information in the format the ioctl uses. This + makes it nice and easy to work with in the ioctl calls. + </para> + <programlisting> + + case VIDIOCSFBUF: + { + struct video_buffer v; + + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.width!=320 && v.width!=640) + return -EINVAL; + if(v.height!=200 && v.height!=240 + && v.height!=400 + && v.height !=480) + return -EINVAL; + memcpy(&capture_fb, &v, sizeof(v)); + hardware_set_fb(&v); + return 0; + } + + + + </programlisting> + <para> + The capable() function checks a user has the required capability. The Linux + operating system has a set of about 30 capabilities indicating privileged + access to services. The default set up gives the superuser (uid 0) all of + them and nobody else has any. + </para> + <para> + We check that the user has the SYS_ADMIN capability, that is they are + allowed to operate as the machine administrator. We don't want anyone but + the administrator making a mess of the display. + </para> + <para> + Next we check for standard PC video modes (320 or 640 wide with either + EGA or VGA depths). If the mode is not a standard video mode we reject it as + not supported by our card. If the mode is acceptable we save it so that + VIDIOCFBUF will give the right answer next time it is called. The + hardware_set_fb() function is some undescribed card specific function to + program the card for the desired mode. + </para> + <para> + Before the driver can display an overlay window it needs to know where the + window should be placed, and also how large it should be. If the card + supports clipping it needs to know which rectangles to omit from the + display. The video_window structure is used to describe the way the image + should be displayed. + </para> + <table frame=all><title>struct video_window fields</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>width</><>The width in pixels of the desired image. The card + may use a smaller size if this size is not available</> + </row><row> + <entry>height</><>The height of the image. The card may use a smaller + size if this size is not available.</> + </row><row> + <entry>x</><> The X position of the top left of the window. This + is in pixels relative to the left hand edge of the + picture. Not all cards can display images aligned on + any pixel boundary. If the position is unsuitable + the card adjusts the image right and reduces the + width.</> + </row><row> + <entry>y</><> The Y position of the top left of the window. This + is counted in pixels relative to the top edge of the + picture. As with the width if the card cannot + display starting on this line it will adjust the + values.</> + </row><row> + <entry>chromakey</><>The colour (expressed in RGB32 format) for the + chromakey colour if chroma keying is being used. </> + </row><row> + <entry>clips</><>An array of rectangles that must not be drawn + over.</> + </row><row> + <entry>clipcount</><>The number of clips in this array.</> + </row> + </tbody> + </tgroup> + </table> + <para> + Each clip is a struct video_clip which has the following fields + </para> + <table frame=all><title>video_clip fields</title> + <tgroup cols=2 align=left> + <tbody> + <row> + <entry>x, y</><>Co-ordinates relative to the display</> + </row><row> + <entry>width, height</><>Width and height in pixels</> + </row><row> + <entry>next</><>A spare field for the application to use</> + </row> + </tbody> + </tgroup> + </table> + <para> + The driver is required to ensure it always draws in the area requested or a smaller area, and that it never draws in any of the areas that are clipped. + This may well mean it has to leave alone. small areas the application wished to be + drawn. + </para> + <para> + Our example card uses chromakey so does not have to address most of the + clipping. We will add a video_window structure to our global variables to + remember our parameters, as we did with the frame buffer. + </para> + <programlisting> + + + case VIDIOCGWIN: + { + if(copy_to_user(arg, &capture_win, + sizeof(capture_win))) + return -EFAULT; + return 0; + } + + + case VIDIOCSWIN: + { + struct video_window v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.width > 640 || v.height > 480) + return -EINVAL; + if(v.width < 16 || v.height < 16) + return -EINVAL; + hardware_set_key(v.chromakey); + hardware_set_window(v); + memcpy(&capture_win, &v, sizeof(v)); + capture_w = v.width; + capture_h = v.height; + return 0; + } + + + </programlisting> + <para> + Because we are using Chromakey our setup is fairly simple. Mostly we have to + check the values are sane and load them into the capture card. + </para> + <para> + With all the setup done we can now turn on the actual capture/overlay. This + is done with the VIDIOCCAPTURE ioctl. This takes a single integer argument + where 0 is on and 1 is off. + </para> + <programlisting> + + + case VIDIOCCAPTURE: + { + int v; + if(get_user(v, (int *)arg)) + return -EFAULT; + if(v==0) + hardware_capture_off(); + else + { + if(capture_fb.width == 0 + || capture_w == 0) + return -EINVAL; + hardware_capture_on(); + } + return 0; + } + + + </programlisting> + <para> + We grab the flag from user space and either enable or disable according to + its value. There is one small corner case we have to consider here. Suppose + that the capture was requested before the video window or the frame buffer + had been set up. In those cases there will be unconfigured fields in our + card data, as well as unconfigured hardware settings. We check for this case and + return an error if the frame buffer or the capture window width is zero. + </para> + <programlisting> + + + default: + return -ENOIOCTLCMD; + } +} + </programlisting> + <para> + + We don't need to support any other ioctls, so if we get this far, it is time + to tell the video layer that we don't now what the user is talking about. + </para> + </sect1> + <sect1 id="endvid"> + <title>Other Functionality</title> + <para> + The Video4Linux layer supports additional features, including a high + performance mmap() based capture mode and capturing part of the image. + These features are out of the scope of the book. You should however have enough + example code to implement most simple video4linux devices for radio and TV + cards. + </para> + </sect1> + </chapter> + <chapter id="bugs"> + <title>Known Bugs And Assumptions</title> + <para> + <variablelist> + <varlistentry><term>Multiple Opens</term> + <listitem> + <para> + The driver assumes multiple opens should not be allowed. A driver + can work around this but not cleanly. + </para> + </listitem></varlistentry> + + <varlistentry><term>API Deficiences</term> + <listitem> + <para> + The existing API poorly reflects compression capable devices. There + are plans afoot to merge V4L, V4L2 and some other ideas into a + better interface. + </para> + </listitem></varlistentry> + </variablelist> + + </para> + </chapter> + + <chapter id="pubfunctions"> + <title>Public Functions Provided</title> +!Edrivers/char/videodev.c + </chapter> + +</book> diff --git a/Documentation/DocBook/wanbook.tmpl b/Documentation/DocBook/wanbook.tmpl new file mode 100644 index 000000000..9b18bb2d8 --- /dev/null +++ b/Documentation/DocBook/wanbook.tmpl @@ -0,0 +1,97 @@ +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]> + +<book id="WANGuide"> + <bookinfo> + <title>Synchronous PPP and Cisco HDLC Programming Guide</title> + + <authorgroup> + <author> + <firstname>Alan</firstname> + <surname>Cox</surname> + <affiliation> + <address> + <email>alan@redhat.com</email> + </address> + </affiliation> + </author> + </authorgroup> + + <copyright> + <year>2000</year> + <holder>Alan Cox</holder> + </copyright> + + <legalnotice> + <para> + This documentation 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. + </para> + + <para> + 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. + </para> + + <para> + 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., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + </para> + + <para> + For more details see the file COPYING in the source + distribution of Linux. + </para> + </legalnotice> + </bookinfo> + +<toc></toc> + + <chapter id="intro"> + <title>Introduction</title> + <para> + The syncppp drivers in Linux provide a fairly complete + implementation of Cisco HDLC and a minimal implementation of + PPP. The longer term goal is to switch the PPP layer to the + generic PPP interface that is new in Linux 2.3.x. The API should + remain unchanged when this is done, but support will then be + available for IPX, compression and other PPP features + </para> + </chapter> + <chapter id="bugs"> + <title>Known Bugs And Assumptions</title> + <para> + <variablelist> + <varlistentry><term>PPP is minimal</term> + <listitem> + <para> + The current PPP implementation is very basic, although sufficient + for most wan usages. + </para> + </listitem></varlistentry> + + <varlistentry><term>Cisco HDLC Quirks</term> + <listitem> + <para> + Currently we do not end all packets with the correct Cisco multicast + or unicast flags. Nothing appears to mind too much but this should + be corrected. + </para> + </listitem></varlistentry> + </variablelist> + + </para> + </chapter> + + <chapter id="pubfunctions"> + <title>Public Functions Provided</title> +!Edrivers/net/wan/syncppp.c + </chapter> + +</book> diff --git a/Documentation/DocBook/z8530book.tmpl b/Documentation/DocBook/z8530book.tmpl new file mode 100644 index 000000000..364c9126d --- /dev/null +++ b/Documentation/DocBook/z8530book.tmpl @@ -0,0 +1,383 @@ +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]> + +<book id="Z85230Guide"> + <bookinfo> + <title>Z8530 Programming Guide</title> + + <authorgroup> + <author> + <firstname>Alan</firstname> + <surname>Cox</surname> + <affiliation> + <address> + <email>alan@redhat.com</email> + </address> + </affiliation> + </author> + </authorgroup> + + <copyright> + <year>2000</year> + <holder>Alan Cox</holder> + </copyright> + + <legalnotice> + <para> + This documentation 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. + </para> + + <para> + 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. + </para> + + <para> + 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., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + </para> + + <para> + For more details see the file COPYING in the source + distribution of Linux. + </para> + </legalnotice> + </bookinfo> + +<toc></toc> + + <chapter id="intro"> + <title>Introduction</title> + <para> + The Z85x30 family synchronous/asynchronous controller chips are + used on a larg number of cheap network interface cards. The + kernel provides a core interface layer that is designed to make + it easy to provide WAN services using this chip. + </para> + <para> + The current driver only support synchronous operation. Merging the + asynchronous driver support into this code to allow any Z85x30 + device to be used as both a tty interface and as a synchronous + controller is a project for Linux post the 2.4 release + </para> + <para> + The support code handles most common card configurations and + supports running both Cisco HDLC and Synchronous PPP. With extra + glue the frame relay and X.25 protocols can also be used with this + driver. + </para> + </chapter> + + <chapter> + <title>Driver Modes</title> + <para> + The Z85230 driver layer can drive Z8530, Z85C30 and Z85230 devices + in three different modes. Each mode can be applied to an individual + channel on the chip (each chip has two channels). + </para> + <para> + The PIO synchronous mode supports the most common Z8530 wiring. Here + the chip is interface to the I/O and interrupt facilities of the + host machine but not to the DMA subsystem. When running PIO the + Z8530 has extremely tight timing requirements. Doing high speeds, + even with a Z85230 will be tricky. Typically you should expect to + achieve at best 9600 baud with a Z8C530 and 64Kbits with a Z85230. + </para> + <para> + The DMA mode supports the chip when it is configured to use dual DMA + channels on an ISA bus. The better cards tend to support this mode + of operation for a single channel. With DMA running the Z85230 tops + out when it starts to hit ISA DMA constraints at about 512Kbits. It + is worth noting here that many PC machines hang or crash when the + chip is driven fast enough to hold the ISA bus solid. + </para> + <para> + Transmit DMA mode uses a single DMA channel. The DMA channel is used + for transmission as the transmit FIFO is smaller than the receive + FIFO. it gives better performance than pure PIO mode but is nowhere + near as ideal as pure DMA mode. + </para> + </chapter> + + <chapter> + <title>Using the Z85230 driver</title> + <para> + The Z85230 driver provides the back end interface to your board. To + configure a Z8530 interface you need to detect the board and to + identify its ports and interrupt resources. It is also your problem + to verify the resources are available. + </para> + <para> + Having identified the chip you need to fill in a struct z8530_dev, + which describes each chip. This object must exist until you finally + shutdown the board. Firstly zero the active field. This ensures + nothing goes off without you intending it. The irq field should + be set to the interrupt number of the chip. (Each chip has a single + interrupt source rather than each channel). You are responsible + for allocating the interrupt line. The interrupt handler should be + set to <function>z8530_interrupt</function>. The device id should + be set to the z8530_dev structure pointer. Whether the interrupt can + be shared or not is board dependant, and up to you to initialise. + </para> + <para> + The structure holds two channel structures. + Initialise chanA.ctrlio and chanA.dataio with the address of the + control and data ports. You can or this with Z8530_PORT_SLEEP to + indicate your interface needs the 5uS delay for chip settling done + in software. The PORT_SLEEP option is architecture specific. Other + flags may become available on future platforms, eg for MMIO. + Initialise the chanA.irqs to &z8530_nop to start the chip up + as disabled and discarding interrupt events. This ensures that + stray interrupts will be mopped up and not hang the bus. Set + chanA.dev to point to the device structure itself. The + private and name field you may use as you wish. The private field + is unused by the Z85230 layer. The name is used for error reporting + and it may thus make sense to make it match the network name. + </para> + <para> + Repeat the same operation with the B channel if your chip has + both channels wired to something useful. This isnt always the + case. If it is not wired then the I/O values do not matter, but + you must initialise chanB.dev. + </para> + <para> + If your board has DMA facilities then initialise the txdma and + rxdma fields for the relevant channels. You must also allocate the + ISA DMA channels and do any neccessary board level initialisation + to configure them. The low level driver will do the Z8530 and + DMA controller programming but not board specific magic. + </para> + <para> + Having intialised the device you can then call + <function>z8530_init</function>. This will probe the chip and + reset it into a known state. An identification sequence is then + run to identify the chip type. If the checks fail to pass the + function returns a non zero error code. Typically this indicates + that the port given is not valid. After this call the + type field of the z8530_dev structure is initialised to either + Z8530, Z85C30 or Z85230 according to the chip found. + </para> + <para> + Once you have called z8530_init you can also make use of the utility + function <function>z8530_describe</function>. This provides a + consistant reporting format for the Z8530 devices, and allows all + the drivers to provide consistent reporting. + </para> + </chapter> + + <chapter> + <title>Attaching Network Interfaces</title> + <para> + If you wish to use the network interface facilities of the driver, + then you need to attach a network device to each channel that is + present and in use. In addition to use the SyncPPP and Cisco HDLC + you need to follow some additional plumbing rules. They may seem + complex but a look at the example hostess_sv11 driver should + reassure you. + </para> + <para> + The network device used for each channel should be pointed to by + the netdevice field of each channel. The dev-> priv field of the + network device points to your private data - you will need to be + able to find your ppp device from this. In addition to use the + sync ppp layer the private data must start with a void * pointer + to the syncppp structures. + </para> + <para> + The way most drivers approach this paticular problem is to + create a structure holding the Z8530 device definition and + put that and the syncppp pointer into the private field of + the network device. The network device fields of the channels + then point back to the network devices. The ppp_device can also + be put in the private structure conveniently. + </para> + <para> + If you wish to use the synchronous ppp then you need to attach + the syncppp layer to the network device. You should do this before + you register the network device. The + <function>sppp_attach</function> requires that the first void * + pointer in your private data is pointing to an empty struct + ppp_device. The function fills in the initial data for the + ppp/hdlc layer. + </para> + <para> + Before you register your network device you will also need to + provide suitable handlers for most of the network device callbacks. + See the network device documentation for more details on this. + </para> + </chapter> + + <chapter> + <title>Configuring And Activating The Port</title> + <para> + The Z85230 driver provides helper functions and tables to load the + port registers on the Z8530 chips. When programming the register + settings for a channel be aware that the documentation recommends + initialisation orders. Strange things happen when these are not + followed. + </para> + <para> + <function>z8530_channel_load</function> takes an array of + pairs of initialisation values in an array of u8 type. The first + value is the Z8530 register number. Add 16 to indicate the alternate + register bank on the later chips. The array is terminated by a 255. + </para> + <para> + The driver provides a pair of public tables. The + z8530_hdlc_kilostream table is for the UK 'Kilostream' service and + also happens to cover most other end host configurations. The + z8530_hdlc_kilostream_85230 table is the same configuration using + the enhancements of the 85230 chip. The configuration loaded is + standard NRZ encoded synchronous data with HDLC bitstuffing. All + of the timing is taken from the other end of the link. + </para> + <para> + When writing your own tables be aware that the driver internally + tracks register values. It may need to reload values. You should + therefore be sure to set registers 1-7, 9-11, 14 and 15 in all + configurations. Where the register settings depend on DMA selection + the driver will update the bits itself when you open or close. + Loading a new table with the interface open is not recommended. + </para> + <para> + There are three standard configurations supported by the core + code. In PIO mode the interface is programmed up to use + interrupt driven PIO. This places high demands on the host processor + to avoid latency. The driver is written to take account of latency + issues but it cannot avoid latencies caused by other drivers, + notably IDE in PIO mode. Because the drivers allocate buffers you + must also prevent MTU changes while the port is open. + </para> + <para> + Once the port is open it will call the rx_function of each channel + whenever a completed packet arrived. This is invoked from + interrupt context and passes you the channel and a network + buffer (struct sk_buff) holding the data. The data includes + the CRC bytes so most users will want to trim the last two + bytes before processing the data. This function is very timing + critical. When you wish to simply discard data the support + code provides the function <function>z8530_null_rx</function> + to discard the data. + </para> + <para> + To active PIO mode sending and receiving the <function> + z8530_sync_open</function> is called. This expects to be passed + the network device and the channel. Typically this is called from + your network device open callback. On a failure a non zero error + status is returned. The <function>z8530_sync_close</function> + function shuts down a PIO channel. This must be done before the + channel is opened again and before the driver shuts down + and unloads. + </para> + <para> + The ideal mode of operation is dual channel DMA mode. Here the + kernel driver will configure the board for DMA in both directions. + The driver also handles ISA DMA issues such as controller + programming and the memory range limit for you. This mode is + activated by calling the <function>z8530_sync_dma_open</function> + function. On failure a non zero error value is returned. + Once this mode is activated it can be shut down by calling the + <function>z8530_sync_dma_close</function>. You must call the close + function matching the open mode you used. + </para> + <para> + The final supported mode uses a single DMA channel to drive the + transmit side. As the Z85C30 has a larger FIFO on the receive + channel this tends to increase the maximum speed a little. + This is activated by calling the <function>z8530_sync_txdma_open + </function>. This returns a non zero error code on failure. The + <function>z8530_sync_txdma_close</function> function closes down + the Z8530 interface from this mode. + </para> + </chapter> + + <chapter> + <title>Network Layer Functions</title> + <para> + The Z8530 layer provides functions to queue packets for + transmission. The driver internally buffers the frame currently + being transmitted and one further frame (in order to keep back + to back transmission running). Any further buffering is up to + the caller. + </para> + <para> + The function <function>z8530_queue_xmit</function> takes a network + buffer in sk_buff format and queues it for transmission. The + caller must provide the entire packet with the exception of the + bitstuffing and CRC. This is normally done by the caller via + the syncppp interface layer. It returns 0 if the buffer has been + queued and non zero values for queue full. If the function accepts + the buffer it becomes property of the Z8530 layer and the caller + should not free it. + </para> + <para> + The function <function>z8530_get_stats</function> returns a pointer + to an internally maintained per interface statistics block. This + provides most of the interface code needed to implement the network + layer get_stats callback. + </para> + </chapter> + + <chapter> + <title>Porting The Z8530 Driver</title> + <para> + The Z8530 driver is written to be portable. In DMA mode it makes + assumptions about the use of ISA DMA. These are probably warranted + in most cases as the Z85230 in paticular was designed to glue to PC + type machines. The PIO mode makes no real assumptions. + </para> + <para> + Should you need to retarget the Z8530 driver to another architecture + the only code that should need changing are the port I/O functions. + At the moment these assume PC I/O port accesses. This may not be + appropriate for all platforms. Replacing + <function>z8530_read_port</function> and <function>z8530_write_port + </function> is intended to be all that is required to port this + driver layer. + </para> + </chapter> + + <chapter id="bugs"> + <title>Known Bugs And Assumptions</title> + <para> + <variablelist> + <varlistentry><term>Interrupt Locking</term> + <listitem> + <para> + The locking in the driver is done via the global cli/sti lock. This + makes for relatively poor SMP performance. Switching this to use a + per device spin lock would probably materially improve performance. + </para> + </listitem></varlistentry> + + <varlistentry><term>Occasional Failures</term> + <listitem> + <para> + We have reports of occasional failures when run for very long + periods of time and the driver starts to receive junk frames. At + the moment the cause of this is not clear. + </para> + </listitem></varlistentry> + </variablelist> + + </para> + </chapter> + + <chapter id="pubfunctions"> + <title>Public Functions Provided</title> +!Edrivers/net/wan/z85230.c + </chapter> + + <chapter id="intfunctions"> + <title>Internal Functions</title> +!Idrivers/net/wan/z85230.c + </chapter> + +</book> diff --git a/Documentation/networking/comx.txt b/Documentation/networking/comx.txt new file mode 100644 index 000000000..a58e78d90 --- /dev/null +++ b/Documentation/networking/comx.txt @@ -0,0 +1,248 @@ + + COMX drivers for the 2.2 kernel + +Originally written by: Tivadar Szemethy, <tiv@itc.hu> +Currently maintained by: Gergely Madarasz <gorgo@itc.hu> + +Last change: 21/06/1999. + +INTRODUCTION + +This document describes the software drivers and their use for the +COMX line of synchronous serial adapters for Linux version 2.2.0 and +above. +The cards are produced and sold by ITC-Pro Ltd. Budapest, Hungary +For further info contact <info@itc.hu> +or http://www.itc.hu (mostly in Hungarian). +The firmware files and software are available from ftp://ftp.itc.hu + +Currently, the drivers support the following cards and protocols: + +COMX (2x64 kbps intelligent board) +CMX (1x256 + 1x128 kbps intelligent board) +HiCOMX (2x2Mbps intelligent board) +LoCOMX (1x512 kbps passive board) +MixCOM (1x512 or 2x512kbps passive board with a hardware watchdog an + optional BRI interface and optional flashROM (1-32M)) + +At the moment of writing this document, the (Cisco)-HDLC, LAPB, SyncPPP and +Frame Relay (DTE, rfc1294 IP encapsulation with partially implemented Q933a +LMI) protocols are available as link-level protocol. +X.25 support is being worked on. + +USAGE + +Load the comx.o module and the hardware-specific and protocol-specific +modules you'll need into the running kernel using the insmod utility. +This creates the /proc/comx directory. +See the example scripts in the 'etc' directory. + +/proc INTERFACE INTRO + +The COMX driver set has a new type of user interface based on the /proc +filesystem which eliminates the need for external user-land software doing +IOCTL calls. +Each network interface or device (i.e. those ones you configure with 'ifconfig' +and 'route' etc.) has a corresponding directory under /proc/comx. You can +dynamically create a new interface by saying 'mkdir /proc/comx/comx0' (or you +can name it whatever you want up to 8 characters long, comx[n] is just a +convention). +Generally the files contained in these directories are text files, which can +be viewed by 'cat filename' and you can write a string to such a file by +saying 'echo _string_ >filename'. This is very similar to the sysctl interface. +Don't use a text editor to edit these files, always use 'echo' (or 'cat' +where appropriate). +When you've created the comx[n] directory, two files are created automagically +in it: 'boardtype' and 'protocol'. You have to fill in these files correctly +for your board and protocol you intend to use (see the board and protocol +descriptions in this file below or the example scripts in the 'etc' directory). +After filling in these files, other files will appear in the directory for +setting the various hardware- and protocol-related informations (for example +irq and io addresses, keepalive values etc.) These files are set to default +values upon creation, so you don't necessarily have to change all of them. + +When you're ready with filling in the files in the comx[n] directory, you can +configure the corresponding network interface with the standard network +configuration utilites. If you're unble to bring the interfaces up, look up +the various kernel log files on your system, and consult the messages for +a probable reason. + +EXAMPLE + +To create the interface 'comx0' which is the first channel of a COMX card: + +insmod comx +# insmod comx-hw-comx ; insmod comx-proto-hdlc (these are usually +autoloaded if you use the kernel module loader) + +mkdir /proc/comx/comx0 +echo comx >/proc/comx/comx0/boardtype +echo 0x360 >/proc/comx/comx0/io <- jumper-selectable I/O port +echo 0x0a >/proc/comx/comx0/irq <- jumper-selectable IRQ line +echo 0xd000 >/proc/comx/comx0/memaddr <- software-configurable memory + address. COMX uses 64 KB, and this + can be: 0xa000, 0xb000, 0xc000, + 0xd000, 0xe000. Avoid conflicts + with other hardware. +cat </etc/siol1.rom >/proc/comx/comx0/firmware <- the firmware for the card +echo HDLC >/proc/comx/comx0/protocol <- the data-link protocol +echo 10 >/proc/comx/comx0/keepalive <- the keepalive for the protocol +ifconfig comx0 1.2.3.4 pointopoint 5.6.7.8 netmask 255.255.255.255 <- + finally configure it with ifconfig +Check its status: +cat /proc/comx/comx0/status + +If you want to use the second channel of this board: + +mkdir /proc/comx/comx1 +echo comx >/proc/comx/comx1/boardtype +echo 0x360 >/proc/comx/comx1/io +echo 10 >/proc/comx/comx1/irq +echo 0xd000 >/proc/comx/comx1/memaddr +echo 1 >/proc/comx/comx1/channel <- channels are numbered + as 0 (default) and 1 + +Now, check if the driver recognized that you're going to use the other +channel of the same adapter: + +cat /proc/comx/comx0/twin +comx1 +cat /proc/comx/comx1/twin +comx0 + +You don't have to load the firmware twice, if you use both channels of +an adapter, just write it into the channel 0's /proc firmware file. + +Default values: io 0x360 for COMX, 0x320 (HICOMX), irq 10, memaddr 0xd0000 + +THE LOCOMX HARDWARE DRIVER + +The LoCOMX driver doesn't require firmware, and it doesn't use memory either, +but it uses DMA channels 1 and 3. You can set the clock rate (if enabled by +jumpers on the board) by writing the kbps value into the file named 'clock'. +Set it to 'external' (it is the default) if you have external clock source. + +(Note: currently the LoCOMX driver does not support the internal clock) + +THE COMX, CMX AND HICOMX DRIVERS + +On the HICOMX, COMX and CMX, you have to load the firmware (it is different for +the three cards!). All these adapters can share the same memory +address (we usually use 0xd0000). On the CMX you can set the internal +clock rate (if enabled by jumpers on the small adapter boards) by writing +the kbps value into the 'clock' file. You have to do this before initializing +the card. If you use both HICOMX and CMX/COMX cards, initialize the HICOMX +first. The I/O address of the HICOMX board is not configurable by any +method available to the user: it is hardwired to 0x320, and if you have to +change it, consult ITC-Pro Ltd. + +THE MIXCOM DRIVER + +The MixCOM board doesn't require firmware, the driver communicates with +it through I/O ports. You can have three of these cards in one machine. + +THE HDLC LINE PROTOCOL DRIVER + +There's only one configurable parameter with this protocol: the 'keepalive' +value. You can set this in seconds or set to 'off'. Agree with the administrator +of your peer router on this setting. The default is 10 (seconds). + +EXAMPLE + +(setting up hw parameters, see above) +echo hdlc >/proc/comx/comx0/protocol +echo 10 >/proc/comx/comx0/keepalive <- not necessary, 10 is the default +ifconfig comx0 1.2.3.4 pointopoint 5.6.7.8 netmask 255.255.255.255 + + +THE PPP LINE PROTOCOL DRIVER + +To use this driver, you have to have ppp-2.3.4, and have a modified version of +pppd (this pppd will work as async pppd to, the modifiactions merely relax +some restricions in order to be able to use non-async lines too. +If configured, this driver can use Van Jacobson TCP header compression (you'll +need the slhc.o module for this). +Additionaly to use this protocol, enable async ppp in your kernel config, and +create the comx device special files in /dev. They're character special files +with major 88, and their names must be the same as their network interface +counterparts (i.e /dev/comx0 with minor 0 corresponds interface comx0 and so +on). + +EXAMPLE + +(setting up hw parameters, see above) +echo ppp >/proc/comx/comx0/protocol +ifconfig comx0 up +pppd comx0 1.2.3.4:5.6.7.8 persist <- with this option pppd won't exit + when the line goes down + +THE LAPB LINE PROTOCOL DRIVER + +For this, you'll need to configure LAPB support (See 'LAPB Data Link Driver' in +'Network options' section) into your kernel (thanks to Jonathan Naylor for his +excellent implementation). +comxlapb.o provides the following files in the appropriate directory +(the default values in parens): t1 (5), t2 (1), n2 (20), mode (DTE, STD) and +window (7). Agree with the administrator of your peer router on these +settings (most people use defaults, but you have to know if you are DTE or +DCE). + +EXAMPLE + +(setting up hw parameters, see above) +echo lapb >/proc/comx/comx0/protocol +echo dce >/proc/comx/comx0/mode <- DCE interface in this example +ifconfig comx0 1.2.3.4 pointopoint 5.6.7.8 netmask 255.255.255.255 + + +THE FRAME RELAY PROTOCOL DRIVER + +You DON'T need any other frame relay related modules from the kernel to use +COMX-Frame Relay. This protocol is a bit more complicated than the others, +because it allows to use 'subinterfaces' or DLCIs within one physical device. +First you have to create the 'master' device (the actual physical interface) +as you would do for other protocols. Specify 'frad' as protocol type. +Now you can bring this interface up by saying 'ifconfig comx0 up' (or whatever +you've named the interface). Do not assign any IP address to this interface +and do not set any routes through it. +Then, set up your DLCIs the following way: create a comx interface for each +DLCI you intend to use (with mkdir), and write 'dlci' to the 'boardtype' file, +and 'ietf-ip' to the 'protocol' file. Currently, the only supported +encapsulation type is this (also called as RFC1294/1490 IP encapsulation). +Write the DLCI number to the 'dlci' file, and write the name of the physical +COMX device to the file called 'master'. +Now you can assign an IP address to this interface and set routes using it. +See the example file for further info and example config script. +Notes: this driver implements a DTE interface with partially implemented +Q933a LMI. +You can find an extensively commented example in the 'etc' directory. + +FURTHER /proc FILES + +boardtype: +Type of the hardware. Valid values are: + 'comx', 'hicomx', 'locomx', 'cmx'. + +protocol: +Data-link protocol on this channel. Can be: HDLC, LAPB, PPP, FRAD + +status: +You can read the channel's actual status from the 'status' file, for example +'cat /proc/comx/comx3/status'. + +lineup_delay: +Interpreted in seconds (default is 1). Used to avoid line jitter: the system +will consider the line status 'UP' only if it is up for at least this number +of seconds. + +debug: +You can set various debug options through this file. Valid options are: +'comx_events', 'comx_tx', 'comx_rx', 'hw_events', 'hw_tx', 'hw_rx'. +You can enable a debug options by writing its name prepended by a '+' into +the debug file, for example 'echo +comx_rx >comx0/debug'. +Disabling an option happens similarly, use the '-' prefix +(e.g. 'echo -hw_rx >debug'). +Debug results can be read from the debug file, for example: +tail -f /proc/comx/comx2/debug + + diff --git a/Documentation/networking/dmfe.txt b/Documentation/networking/dmfe.txt new file mode 100644 index 000000000..158e94ba6 --- /dev/null +++ b/Documentation/networking/dmfe.txt @@ -0,0 +1,63 @@ + dmfe.c: Version 1.28 01/18/2000 + + A Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux. + Copyright (C) 1997 Sten Wang + + 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. + + + A. Compiler command: + + A-1: For normal single processor kernel + "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall + -Wstrict-prototypes -O6 -c dmfe.c" + + A-2: For single processor and enable kernel module version function + "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I/usr/src/linux/net/inet + -Wall -Wstrict-prototypes -O6 -c dmfe.c" + + A-3: For multiple processors(SMP) and enable the module version function + "gcc -D__SMP__ -DMODULE -DMODVERSIONS -D__KERNEL__ -I/usr/src/linux + /net/inet -Wall -Wstrict-prototypes -O6 -c dmfe.c" + + + B. The following steps teach you how to active DM9102 board: + + 1. Used the upper compiler command to compile dmfe.c + + 2. Insert dmfe module into kernel + "insmod dmfe" ;;Auto Detection Mode (Suggest) + "insmod dmfe mode=0" ;;Force 10M Half Duplex + "insmod dmfe mode=1" ;;Force 100M Half Duplex + "insmod dmfe mode=4" ;;Force 10M Full Duplex + "insmod dmfe mode=5" ;;Force 100M Full Duplex + + 3. Config a dm9102 network interface + "ifconfig eth0 172.22.3.18" + ^^^^^^^^^^^ Your IP address + + 4. Active the IP routing table. For some distributions, it is not + necessary. You can type "route" to check. + + "route add default eth0" + + + 5. Well done. Your DM9102 adapter actived now. + + + C. Object files description: + 1. dmfe_rh61.o: For Redhat 6.1 + + If you can make sure your kernel version, you can rename + to dmfe.o and directly use it without re-compiling. + + + Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw diff --git a/Documentation/sound/ALS b/Documentation/sound/ALS new file mode 100644 index 000000000..db98daf30 --- /dev/null +++ b/Documentation/sound/ALS @@ -0,0 +1,43 @@ +ALS-007/ALS-100/ALS-200 based sound cards +========================================= + +Support for sound cards based around the Avance Logic +ALS-007/ALS-100/ALS-200 chip is included. These chips are a single +chip PnP sound solution which is mostly hardware compatible with the +Sound Blaster 16 card, with most differences occurring in the use of +the mixer registers. For this reason the ALS code is integrated +as part of the Sound Blaster 16 driver (adding only 800 bytes to the +SB16 driver). + +To use an ALS sound card under Linux, enable the following options in the +sound configuration section of the kernel config: + - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support + - FM synthesizer (YM3812/OPL-3) support +Since the ALS-007/100/200 is a PnP card, the sound driver probably should be +compiled as a module, with the isapnptools used to wake up the sound card. +Set the "I/O base for SB", "Sound Blaster IRQ" and "Sound Blaster DMA" (8 bit - +either 0, 1 or 3) to the values used in your particular installation (they +should match the values used to configure the card using isapnp). The +ALS-007 does NOT implement 16 bit DMA, so the "Sound Blaster 16 bit DMA" +should be set to -1. If you wish to use the external MPU-401 interface on +the card, "MPU401 I/O base of SB16" and "SB MPU401 IRQ" should be set to +the appropriate values for your installation. (Note that the ALS-007 +requires a separate IRQ for the MPU-401, so don't specify -1 here). (Note +that the base port of the internal FM synth is fixed at 0x388 on the ALS007; +in any case the FM synth location cannot be set in the kernel configuration). + +The resulting sound driver will provide the following capabilities: + - 8 and 16 bit audio playback + - 8 and 16 bit audio recording + - Software selection of record source (line in, CD, FM, mic, master) + - Record and playback of midi data via the external MPU-401 + - Playback of midi data using inbuilt FM synthesizer + - Control of the ALS-007 mixer via any OSS-compatible mixer programs. + Controls available are Master (L&R), Line in (L&R), CD (L&R), + DSP/PCM/audio out (L&R), FM (L&R) and Mic in (mono). + +Jonathan Woithe +jwoithe@physics.adelaide.edu.au +30 March 1998 + +Modified 2000-02-26 by Dave Forrest, drf5n@virginia.edu to add ALS100/ALS200 diff --git a/Documentation/sound/Maestro b/Documentation/sound/Maestro index 8d0fd215d..b7e1334cd 100644 --- a/Documentation/sound/Maestro +++ b/Documentation/sound/Maestro @@ -24,7 +24,7 @@ The Maestro 2 claims 0x1968 while the Maestro 2e has 0x1978. The various families of Maestro are mostly identical as far as this driver is concerned. It doesn't touch the DSP parts that differ (though -it could for FM synthesis) +it could for FM synthesis). Driver OSS Behavior -------------------- @@ -90,8 +90,33 @@ to be allocated, as a power of two. Up to 4 devices can be registered ( dsps_order=2 ). These devices act as fully distinct units and use separate channels in the maestro. +Power Management +---------------- + +As of version 0.14, this driver has a minimal understanding of PCI +Power Management. If it finds a valid power management capability +on the PCI device it will attempt to use the power management +functions of the maestro. It will only do this on Maestro 2Es and +only on machines that are known to function well. You can +force the use of power management by setting the 'use_pm' module +option to 1, or can disable it entirely by setting it to 0. + +When using power management, the driver does a few things +differently. It will keep the chip in a lower power mode +when the module is inserted but /dev/dsp is not open. This +allows the mixer to function but turns off the clocks +on other parts of the chip. When /dev/dsp is opened the chip +is brought into full power mode, and brought back down +when it is closed. It also powers down the chip entirely +when the module is removed or the machine is shutdown. This +can have nonobvious consequences. CD audio may not work +after a power managing driver is removed. Also, software that +doesn't understand power management may not be able to talk +to the powered down chip until the machine goes through a hard +reboot to bring it back. + .. more details .. ------------------ +------------------ drivers/sound/maestro.c contains comments that hopefully explain the maestro implementation. diff --git a/Documentation/usb/ov511.txt b/Documentation/usb/ov511.txt index c13fc4c52..757f7458f 100644 --- a/Documentation/usb/ov511.txt +++ b/Documentation/usb/ov511.txt @@ -3,7 +3,7 @@ Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC ------------------------------------------------------------------------------- Author: Mark McClelland -Homepage: http://people.delphi.com/mmcclelland/linux/ +Homepage: http://alpha.dyndns.org/ov511 INTRODUCTION: @@ -11,25 +11,41 @@ This is a preliminary version of my OV511 Linux device driver. Currently, it can grab a frame in color (YUV420) at 640x480 or 320x240 using either vidcat or xawtv. Other utilities may work but have not yet been tested. +NEW IN THIS VERSION: + o Preliminary snapshot support + o Experimental red-blue misalignment fixes + o Better YUV420 color conversion + o Module options + o Finer-grained debug message control + o Support for new cameras (4, 36) + o Uses initcalls + SUPPORTED CAMERAS: -________________________________________________________ -Manufacturer | Model | Custom ID | Status ------------------+----------------+-----------+--------- -MediaForte | MV300 | 0 | Working -D-Link | DSB-C300 | 3 | Working -Puretek | PT-6007 | 5 | Untested -Creative Labs | WebCam 3 | 21 | Working -Lifeview | RoboCam | 100 | Untested -AverMedia | InterCam Elite | 102 | Working -MediaForte | MV300 | 112 | Working --------------------------------------------------------- +_________________________________________________________ +Manufacturer | Model | Custom ID | Status +-----------------+-----------------+-----------+--------- +MediaForte | MV300 | 0 | Working +Aiptek | HyperVCam ? | 0 | Working +NetView | NV300M | 0 | Working +D-Link | DSB-C300 | 3 | Working +Hawking Tech. | ??? | 3 | Working +??? | Generic | 4 | Untested +Puretek | PT-6007 | 5 | Working +Creative Labs | WebCam 3 | 21 | Working +??? | Koala-Cam | 36 | Untested +Lifeview | RoboCam | 100 | Untested +AverMedia | InterCam Elite | 102 | Working +MediaForte | MV300 | 112 | Working +Omnivision | OV7110 EV board | 112 | Working* +--------------------------------------------------------- +(*) uses OV7110 (monochrome) Any camera using the OV511 and the OV7610 CCD should work with this driver. The driver only detects known cameras though, based on their custom id number. If you have a currently unsupported camera, the ID number should be reported to you -in the kernel logs. If you have an unsupported camera, please send me the model, -manufacturer and ID number and I will add it to the detection code. In the -meantime, you can add to the code yourself in the function ov511_probe() +in the kernel logs. Please send me the model, manufacturer and ID number and I +will add it to the detection code. In the meantime, you can add to the code +yourself in the function ov511_probe(). WHAT YOU NEED: @@ -44,7 +60,7 @@ HOW TO USE IT: You must have first compiled USB support, support for your specific USB host controller (UHCI or OHCI), and Video4Linux support for your kernel (I recommend -making them modules.) +making them modules.) Next, (as root) from your appropriate modules directory (lib/modules/2.3.XX): @@ -56,6 +72,14 @@ Next, (as root) from your appropriate modules directory (lib/modules/2.3.XX): If it is not already there (it usually is), create the video device: mknod /dev/video c 81 0 + +Sometimes /dev/video is a symlink to /dev/video0 + +You will have to set permissions on this device to allow you to read/write +from it: + + chmod 666 /dev/video + chmod 666 /dev/video0 (if necessary) Now you are ready to run a video app! Both vidcat and xawtv work well for me at 640x480. @@ -83,20 +107,103 @@ Now you should be able to run xawtv. Right click for the options dialog. If you get a scrambled image it is likely that you made a mistake in Xawtv.ad. Try setting the size to 320x240 if all else fails. +FAQ: +Q: "Why does the picture have noise and look grainy" +A: This is a problem at low light levels, and may be also due to subtle bugs in + the code. The cause is most likely the OV7610 settings we are currently + using. I am looking into this problem. + +Q: "The driver sometimes says `Failed to read OV7610 ID.' What is the deal?" +A: The I2C code that allows the OV511 to communicate with the camera chip is a + bit flaky right now. This message means that the I2C bus never got + initialized properly, and the camera will most likely not work even if you + disable this warning. Try unloading/reloading the driver or unplugging/re- + plugging the camera if this happens. + +Q: "Why do you bother with this phony camera detection crap? It doesn't do + anything useful!" +A: The main purpose of only supporting known camera models is to force people + with new camera models to tell me about them, so I can assemble the list + above, and so the code can know what CCD chip you have. Right now, nearly all + of the cameras use the OV7610 and consequently I have not put support for + other ones in, so the value of the detection code is questionable. Eventually + though, new CCDs might appear and we will be fortunate to have the detection. + +MODULE PARAMETERS: + + You can set these with: insmod ov511 NAME=VALUE + There is currently no way to set these on a per-camera basis. + + NAME: autoadjust + TYPE: integer (boolean) + DEFAULT: 1 + DESC: The camera normally adjusts exposure, gain, and hue automatically. This + can be set to 0 to disable this automatic adjustment. Note that there is + currently no way to set these parameters manually once autoadjust is + disabled. (This feature is not working yet) + + NAME: debug + TYPE: integer (0-6) + DEFAULT: 3 + DESC: Sets the threshold for printing debug messages. The higher the value, + the more is printed. The levels are cumulative, and are as follows: + 0=no debug messages + 1=init/detection/unload and other significant messages + 2=some warning messages + 3=config/control function calls + 4=most function calls and data parsing messages + 5=highly repetitive mesgs + + NAME: fix_rgb_offset + TYPE: integer (boolean) + DEFAULT: 0 + DESC: Some people have reported that the blue component of the image is one + or so lines higher than the red component. This is only apparent in + images with white objects on black backgrounds at 640x480. Setting this + to 1 will realign the color planes correctly. NOTE: This is still + experimental and very buggy. + + NAME: snapshot + TYPE: integer (boolean) + DEFAULT: 0 + DESC: Set to 1 to enable snapshot mode. read() will block until the snapshot + button is pressed. Note that this does not yet work with most apps, + including xawtv and vidcat. NOTE: See the section "TODO" for more info. + WORKING FEATURES: o Color streaming/capture at 640x480 and 320x240 o YUV420 color + o Monochrome o Setting/getting of saturation, contrast and brightness (no color yet) -WHAT NEEDS TO BE DONE: - -The rest of the work will involve implementing support for all the different -resolutions, color depths, etc. Also, while support for the OV511's proprietary -lossy compression is apparently not necessary (the code currently disables it,) -it would be a nice addition as it improves performance quite a bit. OmniVision -wouldn't tell me how the algorithm works, so we can't really work on that yet. -Please kindly inform OmniVision that you would like them to release their -specifications to the Linux community. +EXPERIMENTAL FEATURES: + o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and + corrupted frames. + o Snapshot mode (only works with some read() based apps; see below for more) + +TODO: + o Fix the noise / grainy image problem. + o Get compression working. It would be a nice addition as it improves + frame rate quite a bit. OmniVision wouldn't tell me how the algorithm works, + so we can't really work on that yet. Please kindly inform OmniVision that you + would like them to release their specifications to the Linux community. + o Get 160x120 working + o YUV422 (and other color modes) + o Fix read(). It only works right now if you run an mmap() based app like xawtv + or vidcat after loading the module and before using read(). Apparently there + are some initialization issues. + o Get snapshot mode working with mmap(). + o Fix fixFrameRGBoffset(). It is not stable yet with streaming video. + o Get hue (red/blue channel balance) adjustment working (in ov511_get_picture() + and ov511_set_picture()) + o Get autoadjust disable working + o Devise some clean way to support different types of CCDs (based on Custom ID) + o OV511A support + o V4L2 support (Probably not until it goes into the kernel) + o Fix I2C initialization. Some people are reporting problems with reading the + 7610 registers. This could be due to timing differences, an excessive I2C + clock rate, or a problem with ov511_i2c_read(). + o Get rid of the memory management functions (put them in videodev.c??) HOW TO CONTACT ME: @@ -108,4 +215,5 @@ CREDITS: The code is based in no small part on the CPiA driver by Johannes Erdfelt, Randy Dunlap, and others. Big thanks to them for their pioneering work on that and the USB stack. Thanks to Bret Wallach for getting camera reg IO , ISOC, and -image capture working. +image capture working. Thanks to Orion Sky Lawlor and Kevin Moore for their +work as well. diff --git a/Documentation/video4linux/CQcam.txt b/Documentation/video4linux/CQcam.txt new file mode 100644 index 000000000..6d54c07c0 --- /dev/null +++ b/Documentation/video4linux/CQcam.txt @@ -0,0 +1,414 @@ +c-qcam - Connectix Color QuickCam video4linux kernel driver + +Copyright (C) 1999 Dave Forrest <drf5n@virginia.edu> + released under GNU GPL. + +1999-12-08 Dave Forrest, written with kernel version 2.2.12 in mind + + +Table of Contents + +1.0 Introduction +2.0 Compilation, Installation, and Configuration +3.0 Troubleshooting +4.0 Future Work / current work arounds +9.0 Sample Program, v4lgrab +10.0 Other Information + + +1.0 Introduction + + The file ../drivers/char/c-qcam.c is a device driver for the +Logitech (nee Connectix) parallel port interface color CCD camera. +This is a fairly inexpensive device for capturing images. Logitech +does not currently provide information for developers, but many people +have engineered several solutions for non-Microsoft use of the Color +Quickcam. + +1.1 Motivation + + I spent a number of hours trying to get my camera to work, and I +hope this document saves you some time. My camera will not work with +the 2.2.13 kernel as distributed, but with a few patches to the +module, I was able to grab some frames. See 4.0, Future Work. + + + +2.0 Compilation, Installation, and Configuration + + The c-qcam depends on parallel port support, video4linux, and the +Color Quickcam. It is also nice to have the parallel port readback +support enabled. I enabled these as modules during the kernel +configuration. The appropriate flags are: + + CONFIG_PRINTER M for lp.o, parport.o parport_pc.o modules + CONFIG_PNP_PARPORT M for autoprobe.o IEEE1284 readback module + CONFIG_PRINTER_READBACK M for parport_probe.o IEEE1284 readback module + CONFIG_VIDEO_DEV M for videodev.o video4linux module + CONFIG_VIDEO_CQCAM M for c-qcam.o Color Quickcam module + + With these flags, the kernel should compile and install the modules. +To record and monitor the compilation, I use: + + (make dep; \ + make zlilo ; \ + make modules; \ + make modules_install ; + depmod -a ) &>log & + less log # then a capital 'F' to watch the progress + +But that is my personal preference. + +2.2 Configuration + + The configuration requires module configuration and device +configuration. I like kmod or kerneld process with the +/etc/modules.conf file so the modules can automatically load/unload as +they are used. The video devices could already exist, be generated +using MAKEDEV, or need to be created. The following sections detail +these procedures. + + +2.1 Module Configuration + + Using modules requires a bit of work to install and pass the +parameters. Do read ../modules.txt, and understand that entries +in /etc/modules.conf of: + + alias parport_lowlevel parport_pc + options parport_pc io=0x378 irq=none + alias char-major-81 videodev + alias char-major-81-0 c-qcam + +will cause the kmod/kerneld/modprobe to do certain things. If you are +using kmod or kerneld, then a request for a 'char-major-81-0' will cause +the 'c-qcam' module to load. If you have other video sources with +modules, you might want to assign the different minor numbers to +different modules. + +2.2 Device Configuration + + At this point, we need to ensure that the device files exist. +Video4linux used the /dev/video* files, and we want to attach the +Quickcam to one of these. + + ls -lad /dev/video* # should produce a list of the video devices + +If the video devices do not exist, you can create them with: + + su + cd /dev + for ii in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do + mknod video$ii c 81 $ii # char-major-81-[0-16] + chown root.root video$ii # owned by root + chmod 600 video$ii # read/writable by root only + done + + Lots of people connect video0 to video and bttv, but you might want +your c-qcam to mean something more: + + ln -s video0 c-qcam # make /dev/c-qcam a working file + ln -s c-qcam video # make /dev/c-qcam your default video source + + But these are conveniences. The important part is to make the proper +special character files with the right major and minor numbers. All +of the special device files are listed in ../devices.txt. If you +would like the c-qcam readable by non-root users, you will need to +change the permissions. + +3.0 Troubleshooting + + If the sample program below, v4lgrab, gives you output then +everything is working. + + v4lgrab | wc # should give you a count of characters + + Otherwise, you have some problem. + + The c-qcam is IEEE1284 compatible, so if you are using the proc file +system (CONFIG_PROC_FS), the parallel printer support +(CONFIG_PRINTER), the IEEE 1284 sytem,(CONFIG_PRINTER_READBACK), you +should be able to read some identification from your quickcam with + + modprobe -v parport + modprobe -v parport_probe + cat /proc/parport/PORTNUMBER/autoprobe +Returns: + CLASS:MEDIA; + MODEL:Color QuickCam 2.0; + MANUFACTURER:Connectix; + + A good response to this indicates that your color quickcam is alive +and well. A common problem is that the current driver does not +reliably detect a c-qcam, even though one is attached. In this case, + + modprobe -v c-qcam +or + insmod -v c-qcam + + Returns a message saying "Device or resource busy" Development is +currently underway, but a workaround is to patch the module to skip +the detection code and attach to a defined port. Check the +video4linux mailing list and archive for more current information. + +3.1 Checklist: + + Can you get an image? + v4lgrab >qcam.ppm ; wc qcam.ppm ; xv qcam.ppm + + Is a working c-qcam connected to the port? + grep ^ /proc/parport/?/autoprobe + + Do the /dev/video* files exist? + ls -lad /dev/video + + Is the c-qcam module loaded? + modprobe -v c-qcam ; lsmod + + Does the camera work with alternate programs? cqcam, etc? + + + + +4.0 Future Work / current workarounds + + It is hoped that this section will soon become obsolete, but if it +isn't, you might try patching the c-qcam module to add a parport=xxx +option as in the bw-qcam module so you can specify the parallel port: + + insmod -v c-qcam parport=0 + +And bypass the detection code, see ../../drivers/char/c-qcam.c and +look for the 'qc_detect' code and call. + + Note that there is work in progress to change the video4linux API, +this work is documented at the video4linux2 site listed below. + + +9.0 --- A sample program using v4lgrabber, + +This program is a simple image grabber that will copy a frame from the +first video device, /dev/video0 to standard output in portable pixmap +format (.ppm) Using this like: 'v4lgrab | convert - c-qcam.jpg' +produced this picture of me at + http://mug.sys.virginia.edu/~drf5n/extras/c-qcam.jpg + +-------------------- 8< ---------------- 8< ----------------------------- + +/* Simple Video4Linux image grabber. */ +/* + * Video4Linux Driver Test/Example Framegrabbing Program + * + * Compile with: + * gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab + * Use as: + * v4lgrab >image.ppm + * + * Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org> + * Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c + * with minor modifications (Dave Forrest, drf5n@virginia.edu). + * + */ + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <stdlib.h> + +#include <linux/types.h> +#include <linux/videodev.h> + +#define FILE "/dev/video0" + +/* Stole this from tvset.c */ + +#define READ_VIDEO_PIXEL(buf, format, depth, r, g, b) \ +{ \ + switch (format) \ + { \ + case VIDEO_PALETTE_GREY: \ + switch (depth) \ + { \ + case 4: \ + case 6: \ + case 8: \ + (r) = (g) = (b) = (*buf++ << 8);\ + break; \ + \ + case 16: \ + (r) = (g) = (b) = \ + *((unsigned short *) buf); \ + buf += 2; \ + break; \ + } \ + break; \ + \ + \ + case VIDEO_PALETTE_RGB565: \ + { \ + unsigned short tmp = *(unsigned short *)buf; \ + (r) = tmp&0xF800; \ + (g) = (tmp<<5)&0xFC00; \ + (b) = (tmp<<11)&0xF800; \ + buf += 2; \ + } \ + break; \ + \ + case VIDEO_PALETTE_RGB555: \ + (r) = (buf[0]&0xF8)<<8; \ + (g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8; \ + (b) = ((buf[1] << 2 ) & 0xF8)<<8; \ + buf += 2; \ + break; \ + \ + case VIDEO_PALETTE_RGB24: \ + (r) = buf[0] << 8; (g) = buf[1] << 8; \ + (b) = buf[2] << 8; \ + buf += 3; \ + break; \ + \ + default: \ + fprintf(stderr, \ + "Format %d not yet supported\n", \ + format); \ + } \ +} + +int get_brightness_adj(unsigned char *image, long size, int *brightness) { + long i, tot = 0; + for (i=0;i<size*3;i++) + tot += image[i]; + *brightness = (128 - tot/(size*3))/3; + return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130); +} + +int main(int argc, char ** argv) +{ + int fd = open(FILE, O_RDONLY), f; + struct video_capability cap; + struct video_window win; + struct video_picture vpic; + + unsigned char *buffer, *src; + int bpp = 24, r, g, b; + unsigned int i, src_depth; + + if (fd < 0) { + perror(FILE); + exit(1); + } + + if (ioctl(fd, VIDIOCGCAP, &cap) < 0) { + perror("VIDIOGCAP"); + fprintf(stderr, "(" FILE " not a video4linux device?)\n"); + close(fd); + exit(1); + } + + if (ioctl(fd, VIDIOCGWIN, &win) < 0) { + perror("VIDIOCGWIN"); + close(fd); + exit(1); + } + + if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) { + perror("VIDIOCGPICT"); + close(fd); + exit(1); + } + + if (cap.type & VID_TYPE_MONOCHROME) { + vpic.depth=8; + vpic.palette=VIDEO_PALETTE_GREY; /* 8bit grey */ + if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) { + vpic.depth=6; + if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) { + vpic.depth=4; + if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) { + fprintf(stderr, "Unable to find a supported capture format.\n"); + close(fd); + exit(1); + } + } + } + } else { + vpic.depth=24; + vpic.palette=VIDEO_PALETTE_RGB24; + + if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) { + vpic.palette=VIDEO_PALETTE_RGB565; + vpic.depth=16; + + if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) { + vpic.palette=VIDEO_PALETTE_RGB555; + vpic.depth=15; + + if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) { + fprintf(stderr, "Unable to find a supported capture format.\n"); + return -1; + } + } + } + } + + buffer = malloc(win.width * win.height * bpp); + if (!buffer) { + fprintf(stderr, "Out of memory.\n"); + exit(1); + } + + do { + int newbright; + read(fd, buffer, win.width * win.height * bpp); + f = get_brightness_adj(buffer, win.width * win.height, &newbright); + if (f) { + vpic.brightness += (newbright << 8); + if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) { + perror("VIDIOSPICT"); + break; + } + } + } while (f); + + fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height); + + src = buffer; + + for (i = 0; i < win.width * win.height; i++) { + READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b); + fputc(r>>8, stdout); + fputc(g>>8, stdout); + fputc(b>>8, stdout); + } + + close(fd); + return 0; +} +-------------------- 8< ---------------- 8< ----------------------------- + + +10.0 --- Other Information + +Use the ../../Maintainers file, particularly the VIDEO FOR LINUX and PARALLEL +PORT SUPPORT sections + +The video4linux page: + http://roadrunner.swansea.linux.org.uk/v4l.shtml + +The video4linux2 page: + http://millennium.diads.com/bdirks/v4l2.htm + +Some web pages about the quickcams: + http://www.dkfz-heidelberg.de/Macromol/wedemann/mini-HOWTO-cqcam.html + + http://www.crynwr.com/qcpc/ QuickCam Third-Party Drivers + http://www.crynwr.com/qcpc/re.html Some Reverse Engineering + http://cse.unl.edu/~cluening/gqcam/ v4l client + http://phobos.illtel.denver.co.us/pub/qcread/ doesn't use v4l + ftp://ftp.cs.unm.edu/pub/chris/quickcam/ Has lots of drivers + http://www.cs.duke.edu/~reynolds/quickcam/ Has lots of information + + diff --git a/Documentation/video4linux/bttv/README b/Documentation/video4linux/bttv/README index 9d0709a57..4d8298772 100644 --- a/Documentation/video4linux/bttv/README +++ b/Documentation/video4linux/bttv/README @@ -17,7 +17,7 @@ CONFIG_I2C=m CONFIG_I2C_ALGOBIT=m The latest bttv version is available here: - http://www.in-berlin.de/User/kraxel/v4l/ + http://me.in-berlin.de/~kraxel/bttv.html You'll find Ralphs original (mostly outdated) documentation in the ralphs-doc subdirectory. |