S: Mountain View, California 94040
S: USA
+N: Jeff Garzik
+E: jgarzik@mandrakesoft.com
+
N: Jacques Gelinas
E: jacques@solucorp.qc.ca
D: Author of the Umsdos file system
Framebuffer driver for Cirrus Logic chipsets
- Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
ipfrag_time - INTEGER
Time in seconds to keep an IP fragment in memory.
+INET peer storage:
+
+inet_peer_threshold - INTEGER
+ The approximate size of the storage. Starting from this threshold
+ entries will be thrown aggressively. This threshold also determines
+ entries' time-to-live and time intervals between garbage collection
+ passes. More entries, less time-to-live, less GC interval.
+
+inet_peer_minttl - INTEGER
+ Minimum time-to-live of entries. Should be enough to cover fragment
+ time-to-live on the reassembling side. This minimum time-to-live is
+ guaranteed if the pool size is less than inet_peer_threshold.
+ Measured in jiffies.
+
+inet_peer_maxttl - INTEGER
+ Maximum time-to-live of entries. Unused entries will expire after
+ this period of time if there is no memory pressure on the pool (i.e.
+ when the number of entries in the pool is very small).
+ Measured in jiffies.
+
+inet_peer_gc_mintime - INTEGER
+ Minimum interval between garbage collection passes. This interval is
+ in effect under high memory pressure on the pool.
+ Measured in jiffies.
+
+inet_peer_gc_maxtime - INTEGER
+ Minimum interval between garbage collection passes. This interval is
+ in effect under low (or absent) memory pressure on the pool.
+ Measured in jiffies.
+
TCP variables:
tcp_syn_retries - INTEGER
Updated by:
Andi Kleen
ak@muc.de
-$Id: ip-sysctl.txt,v 1.9 1999/05/08 02:58:44 davem Exp $
+$Id: ip-sysctl.txt,v 1.10 2000/01/06 00:41:42 davem Exp $
VENDOR_ID or DEVICE_ID. This allows searching for any device from a
specific vendor, for example.
- In case you want to do some complex matching, look at pci_devices -- it's
-a linked list of pci_dev structures for all PCI devices in the system.
+ In case you want to do some complex matching, you can walk the list of all
+known PCI devices:
+
+ struct pci_dev *dev;
+ pci_for_each_dev(dev) {
+ ... do anything you want with dev ...
+ }
The `struct pci_dev *' pointer serves as an identification of a PCI device
and is passed to all other functions operating on PCI devices.
+++ /dev/null
-/proc/bus/usb filesystem output
-===============================
-(version 19991218)
-
-
-The /proc filesystem for USB devices generates
-/proc/bus/usb/drivers and /proc/bus/usb/devices.
-
-/proc/bus/usb/drivers just lists the registered drivers,
-one per line. Not very interesting or pretty.
-
-In /proc/bus/usb/devices, each device's output has multiple
-lines (except for a root hub) of ASCII output.
-I made it ASCII instead of binary on purpose, so that someone
-can obtain some useful data from it without the use of an
-auxiliary program. However, with an auxiliary program, the numbers
-in the first 4 columns of each "T:" line (topology info:
-Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram.
-(I think. I haven't proved this, but I have tested it with 3
-different topo/connections and it looked possible.)
-
-Each line is tagged with a one-character ID for that line:
-
-T = Topology (etc.)
-B = Bandwidth
-D = Device descriptor info.
-P = Product ID info. (from Device descriptor, but they won't fit
- together on one line)
-S = String info
-C = Configuration descriptor info. (* = active configuration)
-I = Interface descriptor info.
-E = Endpoint descriptor info.
-
-=======================================================================
-
-/proc/bus/usb/devices output format:
-
-Legend:
- d = decimal number (may have leading spaces or 0's)
- x = hexadecimal number (may have leading spaces or 0's)
- s = string
-
-
-Topology info:
-
-T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
-| | | | | | | | |__MaxChildren
-| | | | | | | |__Device Speed in Mbps
-| | | | | | |__DeviceNumber
-| | | | | |__Count of devices at this level
-| | | | |__Connector/Port on Parent for this device
-| | | |__Parent DeviceNumber
-| | |__Level in topology for this bus
-| |__Bus number
-|__Topology info tag
-
-
-Bandwidth info:
-B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
-| | | |__Number if isochronous requests
-| | |__Number of interrupt requests
-| |__Total Bandwidth allocated to this bus
-|__Bandwidth info tag
-
-
-Device descriptor info & Product ID info:
-
-D: Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
-P: Vendor=xxxx ProdID=xxxx Rev=xx.xx
-
-where
-D: Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
-| | | | | | |__NumberConfigurations
-| | | | | |__MaxPacketSize of Default Endpoint
-| | | | |__DeviceProtocol
-| | | |__DeviceSubClass
-| | |__DeviceClass
-| |__Device USB version
-|__Device info tag #1
-
-where
-P: Vendor=xxxx ProdID=xxxx Rev=xx.xx
-| | | |__Product revision number
-| | |__Product ID code
-| |__Vendor ID code
-|__Device info tag #2
-
-
-String descriptor info:
-
-S: Manufacturer=ssss
-| |__Manufacturer of this device as read from the device.
-|__String info tag
-
-S: Product=ssss
-| |__Product description of this device as read from the device.
-|__String info tag
-
-
-Configuration descriptor info:
-
-C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
-| | | | |__MaxPower in mA
-| | | |__Attributes
-| | |__ConfiguratioNumber
-| |__NumberOfInterfaces
-|__Config info tag
-
-
-Interface descriptor info (can be multiple per Config):
-
-I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
-| | | | | | | |__Driver name
-| | | | | | |__InterfaceProtocol
-| | | | | |__InterfaceSubClass
-| | | | |__InterfaceClass
-| | | |__NumberOfEndpoints
-| | |__AlternateSettingNumber
-| |__InterfaceNumber
-|__Interface info tag
-
-
-Endpoint descriptor info (can be multiple per Interface):
-
-E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
-E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
-| | | | |__Interval
-| | | |__EndpointMaxPacketSize
-| | |__Attributes(EndpointType)
-| |__EndpointAddress(I=In,O=Out)
-|__Endpoint info tag
-
-=======================================================================
-
-
-If a user or script is interested only in Topology info, for
-example, use something like "grep ^T: /proc/bus/usb/devices"
-for only the Topology lines. A command like
-"grep -i ^[tdp]: /proc/bus/usb/devices" can be used to list
-only the lines that begin with the characters in square brackets,
-where the valid characters are TDPCIE. With a slightly more able
-script, it can display any selected lines (for example, only T, D,
-and P lines) and change their output format. (The "procusb"
-Perl script is the beginning of this idea. It will list only
-selected lines [selected from TDPCIE] or "All" lines from
-/proc/bus/usb/devices.)
-
-The Topology lines can be used to generate a graphic/pictorial
-of the USB devices on a system's root hub. (See more below
-on how to do this.)
-
-The Interface lines can be used to determine what driver is
-being used for each device.
-
-The Configuration lines could be used to list maximum power
-(in milliamps) that a system's USB devices are using.
-For example, "grep ^C: /proc/bus/usb/devices".
-
-
-Here's an example, from a system which has a UHCI root hub,
-an external hub connected to the root hub, and a mouse and
-a serial converter connected to the external hub.
-
-T: Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2
-B: Alloc= 28/900 us ( 3%), #Int= 2, #Iso= 0
-T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4
-D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
-P: Vendor=0451 ProdID=1446 Rev= 1.00
-C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
-I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
-E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms
-T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0
-D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
-P: Vendor=04b4 ProdID=0001 Rev= 0.00
-C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
-I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse
-E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms
-T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
-D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
-P: Vendor=0565 ProdID=0001 Rev= 1.08
-S: Manufacturer=Peracom Networks, Inc.
-S: Product=Peracom USB to Serial Converter
-C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
-I: If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
-E: Ad=81(I) Atr=02(Bulk) MxPS= 64 Ivl= 16ms
-E: Ad=01(O) Atr=02(Bulk) MxPS= 16 Ivl= 16ms
-E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl= 8ms
-
-
-Selecting only the "T:" and "I:" lines from this (for example, by using
-"procusb ti"), we have:
-
-T: Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2
-T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4
-I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
-T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0
-I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse
-T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
-I: If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
-
-
-Physically this looks like (or could be converted to):
-
- +------------------+
- | PC/root_hub (12)| Dev# = 1
- +------------------+ (nn) is Mbps.
- Level 0 | CN.0 | CN.1 | [CN = connector/port #]
- +------------------+
- /
- /
- +-----------------------+
- Level 1 | Dev#2: 4-port hub (12)|
- +-----------------------+
- |CN.0 |CN.1 |CN.2 |CN.3 |
- +-----------------------+
- \ \____________________
- \_____ \
- \ \
- +--------------------+ +--------------------+
- Level 2 | Dev# 3: mouse (1.5)| | Dev# 4: serial (12)|
- +--------------------+ +--------------------+
-
-
-
-Or, in a more tree-like structure (ports [Connectors] without
-connections could be omitted):
-
-PC: Dev# 1, root hub, 2 ports, 12 Mbps
-|_ CN.0: Dev# 2, hub, 4 ports, 12 Mbps
- |_ CN.0: Dev #3, mouse, 1.5 Mbps
- |_ CN.1:
- |_ CN.2: Dev #4, serial, 12 Mbps
- |_ CN.3:
-|_ CN.1:
-
-
- ### END ###
--- /dev/null
+Credits for the Simple Linux USB Driver:
+
+The following people have contributed to this code (in alphabetical
+order by last name). I'm sure this list should be longer, its
+difficult to maintain, add yourself with a patch if desired.
+
+ Alan Cox <alan@lxorguk.ukuu.org.uk>
+ Johannes Erdfelt <jerdfelt@sventech.com>
+ ham <ham@unsuave.com>
+ Bradley M Keryan <keryan@andrew.cmu.edu>
+ Paul Mackerras <paulus@cs.anu.edu.au>
+ David E. Nelson <dnelson@jump.net>
+ Vojtech Pavlik <vojtech@suse.cz>
+ Gregory P. Smith <greg@electricrain.com>
+ Linus Torvalds <torvalds@transmeta.com>
+ Roman Weissgaerber <weissg@vienna.at>
+ <Kazuki.Yasumatsu@fujixerox.co.jp>
+
+Special thanks to:
+
+ Inaky Perez Gonzalez <inaky@peloncho.fis.ucm.es> for starting the
+ Linux USB driver effort and writing much of the larger uusbd driver.
+ Much has been learned from that effort.
+
+ The NetBSD & FreeBSD USB developers. For being on the Linux USB list
+ and offering suggestions and sharing implementation experiences.
+
+Additional thanks to the following companies and people for donations
+of hardware, support, time and development (this is from the original
+THANKS file in Inaky's driver):
+
+ The following corporations have helped us in the development
+ of Linux USB / UUSBD:
+
+ - 3Com GmbH for donating a ISDN Pro TA and supporting me
+ in technical questions and with test equipment. I'd never
+ expect such a great help.
+
+ - USAR Systems provided us with one of their excellent USB
+ Evaluation Kits. It allows us to test the Linux-USB driver
+ for compilance with the latest USB specification. USAR
+ Systems recognized the importance of an up-to-date open
+ Operating System and supports this project with
+ Hardware. Thanks!.
+
+ - Thanks to Intel Corporation for their precious help.
+
+ - We teamed up with Cherry to make Linux the first OS with
+ built-in USB support. Cherry is one of the biggest keyboard
+ makers in the world.
+
+ - CMD Technology, Inc. sponsored us kindly donating a CSA-6700
+ PCI-to-USB Controller Board to test the OHCI implementation.
+
+ - Due to their support to us, Keytronic can be sure that they
+ will sell keyboards to some of the 3 million (at least)
+ Linux users.
+
+ - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
+ It was almost imposible to get a PC backplate USB connector
+ for the motherboard here at Europe (mine, home-made, was
+ quite lowsy :). Now I know where to adquire nice USB stuff!
+
+ - Genius Germany donated a USB mouse to test the mouse boot
+ protocol. They've also donated a F-23 digital joystick and a
+ NetMouse Pro. Thanks!
+
+ - AVM GmbH Berlin is supporting the development of the Linux
+ USB driver for the AVM ISDN Controller B1 USB. AVM is a
+ leading manufacturer for active and passive ISDN Controllers
+ and CAPI 2.0-based software. The active design of the AVM B1
+ is open for all OS platforms, including Linux.
+
+ - Thanks to Y-E Data, Inc. for donating their FlashBuster-U
+ USB Floppy Disk Drive, so we could test the bulk transfer
+ code.
+
+ - Many thanks to Logitech for contributing a three axis USB
+ mouse.
+
+ Logitech designs, manufactures and markets
+ Human Interface Devices, having a long history and
+ experience in making devices such as keyboards, mice,
+ trackballs, cameras, loudspeakers and control devices for
+ gaming and professional use.
+
+ Being a recognized vendor and seller for all these devices,
+ they have donated USB mice, a joystick and a scanner, as a
+ way to acknowledge the importance of Linux and to allow
+ Logitech customers to enjoy support in their favorite
+ operating systems and all Linux users to use Logitech and
+ other USB hardware.
+
+ Logitech is official sponsor of the Linux Conference on
+ Feb. 11th 1999 in Vienna, where we'll will present the
+ current state of the Linux USB effort.
+
+ - CATC has provided means to uncover dark corners of the UHCI
+ inner workings with a USB Inspector.
+
+ - Thanks to Entrega for providing PCI to USB cards, hubs and
+ converter products for development.
+
+
+ And thanks go to (hey! in no particular order :)
+
+ - Oren Tirosh <orenti@hishome.net>, for standing so patiently
+ all my doubts'bout USB and giving lots of cool ideas.
+
+ - Jochen Karrer <karrer@wpfd25.physik.uni-wuerzburg.de>, for
+ pointing out mortal bugs and giving advice.
+
+ - Edmund Humemberger <ed@atnet.at>, for it's great work on
+ public relationships and general management stuff for the
+ Linux-USB effort.
+
+ - Alberto Menegazzi <flash@flash.iol.it> is starting the
+ documentation for the UUSBD. Go for it!
+
+ - Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
+ introductory documents (compiting with Alberto's :).
+
+ - Christian Groessler <cpg@aladdin.de>, for it's help on those
+ itchy bits ... :)
+
+ - Paul MacKerras for polishing OHCI and pushing me harder for
+ the iMac support, giving improvements and enhancements.
+
+ - Fernando Herrera <fherrera@eurielec.etsit.upm.es> has taken
+ charge of composing, maintaining and feeding the
+ long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!!
+
+ - Rasca Gmelch <thron@gmx.de> has revived the raw driver and
+ pointed bugs, as well as started the uusbd-utils package.
+
+ - Peter Dettori <dettori@ozy.dec.com> is unconvering bugs like
+ crazy, as well as making cool suggestions, great :)
+
+ - All the Free Software and Linux community, the FSF & the GNU
+ project, the MIT X consortium, the TeX people ... everyone!
+ You know who you are!
+
+ - Big thanks to Richard Stallman for creating Emacs!
+
+ - The people at the linux-usb mailing list, for reading so
+ many messages :) Ok, no more kidding; for all your advices!
+
+ - All the people at the USB Implementors Forum for their
+ help and assistance.
+
+ - Nathan Myers <ncm@cantrip.org>, for his advice! (hope you
+ liked Cibeles' party).
+
+ - Linus Torvalds, for starting, developing and managing Linux.
+
+ - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank
+ for convincing me USB Standard hubs are not that standard
+ and that's good to allow for vendor specific quirks on the
+ standard hub driver.
+
--- /dev/null
+1. Specification of the API
+
+1.1. Basic concept or 'What is an URB?'
+
+The basic idea of the new driver is message passing, the message itself is
+called USB Request Block, or URB for short.
+
+- An URB consists of all relevant information to execute any USB transaction
+and deliver the data and status back.
+
+- Execution of an URB is an inherently asynchronous operation, i.e. the
+submit_urb(urb) call returns immediately after it has successfully queued
+the requested action.
+
+- Ongoing transfers for one URB (e.g. ISO) can simply be canceled with
+unlink_urb(urb) at any time.
+
+- Each URB has a completion handler, which is called after the action
+has been successfully completed or canceled (INT transfers behave a bit
+different, see below). The URB also contains a context-pointer for free
+usage and information passing to the completion handler.
+
+- URBs can be linked. After completing one URB, the next one can be
+automatically submitted. This is especially useful for ISO transfers:
+You only have read/write the data from/to the buffers in the completion
+handler, the continous streaming itself is transparently done by the
+URB-machinery.
+
+1.2. The URB structure
+
+typedef struct urb
+{
+// ignore, for host controller/URB machine internal use
+ void *hcpriv; // private data for host controller
+ struct list_head urb_list; // list pointer to all active urbs
+
+// This is used for urb linking
+ struct urb* next; // pointer to next URB
+ struct usb_device *dev; // pointer to associated USB device
+
+// pipe is assembled by the various well known pipe-macros in usb.h
+ unsigned int pipe; // pipe information
+
+// status after each completion
+ int status; // returned status
+ unsigned int transfer_flags; // ASAP, SP_OK, EARLY_COMPLETE
+
+// for data stage (CTRL), BULK, INT and ISO
+ void *transfer_buffer; // associated data buffer
+
+// expected length
+ int transfer_buffer_length; // data buffer length
+ int actual_length; // actual data buffer length
+
+// setup stage for CTRL (always 8 bytes!)
+ unsigned char* setup_packet; // setup packet (control only)
+
+// with ASAP, start_frame is set to the determined frame
+ int start_frame; // start frame (iso/irq)
+ int number_of_packets; // # of packets (iso/int)
+ int interval; // polling interval (irq only)
+ int error_count; // number of errors (iso only)
+ //
+ void *context; // context for completion routine
+ usb_complete_t complete; // pointer to completion routine
+ //
+// specification of the requested data offsets and length for ISO
+ iso_packet_descriptor_t iso_frame_desc[0];
+} urb_t, *purb_t;
+
+1.3. How to get an URB?
+
+URBs are allocated with the following call
+
+ purb_t alloc_urb(int isoframes)
+
+Return value is a pointer to the allocated URB, 0 if allocation failed.
+The parameter isoframes specifies the number of isochronous transfer frames
+you want to schedule. For CTRL/BULK/INT, use 0.
+
+To free an URB, use
+
+ void free_urb(purb_t purb)
+
+This call also may free internal (host controller specific) memory in the
+future.
+
+1.4. What has to be filled in?
+
+Depending on the type of transaction, there are some macros
+(FILL_CONTROL_URB, FILL_BULK_URB, and FILL_INT_URB, defined in uhci.h)
+that simplify the URB creation. In general, all macros need the usb
+device pointer, the pipe (usual format), the transfer buffer, the
+desired transfer length, the completion handler, and its context.
+Take a look at the uhci_control_msg-function that convert the old API
+into an URB.
+
+Flags:
+For ISO there are two startup behaviors: Specified start_frame or ASAP.
+For ASAP set USB_ISO_ASAP in transfer_flags.
+
+If short packets should NOT be tolerated, set USB_DISABLE_SPD in
+transfer_flags.
+
+Usually, (to reduce restart time) the completion handler is called
+AFTER the URB re-submission. You can get the other way by setting
+USB_URB_EARLY_COMPLETE in transfer_flags. This is implicite for
+INT transfers.
+
+1.5. How to submit an URB?
+
+Just call
+
+ int submit_urb(purb_t purb)
+
+It immediately returns, either with status 0 (request queued) or some
+error code, usually caused by the following:
+
+- Out of memory (-ENOMEM)
+- Wrong pipe handle (-ENXIO)
+- Unplugged device (-ENODEV)
+- Stalled endpoint (-EPIPE)
+- Too many queued ISO transfers (-EAGAIN)
+- Too many requested ISO frames (-EFBIG)
+- Invalid INT interval (-EINVAL)
+- More than one packet for INT (-EINVAL)
+
+After submission, urb->status is USB_ST_URB_PENDING.
+
+For isochronous endpoints, subsequent submitting of URBs to the same endpoint
+with the ASAP flag result in a seamless ISO streaming. Exception: The
+execution cannot be scheduled later than 900 frames from the 'now'-time.
+The same applies to INT transfers, but here the seamless continuation is
+independent of the transfer flags (implicitely ASAP).
+
+1.6. How to cancel an already running URB?
+
+Call
+ int unlink_urb(purb_t purb)
+
+It removes the urb from the internal list and frees all allocated
+HW descriptors. The status is changed to USB_ST_URB_KILLED. After
+unlink_urb() returns, you can safely free the URB with free_urb(urb)
+and all other possibly associated data (urb->context etc.)
+
+1.7. What about the completion handler?
+
+The completion handler is optional, but useful for fast data processing
+or wakeup of a sleeping process (as shown in the compatibility wrapper's
+completion handler).
+
+The handler is of the following type:
+
+ typedef void (*usb_complete_t)(struct urb *);
+
+i.e. it gets just the URB that caused the completion call.
+In the completion handler, you should have a look at urb->status to
+detect any USB errors. Since the context parameter is included in the URB,
+you can pass information to the completion handler.
+
+
+1.8. How to do isochronous (ISO) transfers?
+
+For ISO transfers you have to append the iso_packet_descriptor_t structure
+to the URB for each frame you want to schedule. When using alloc_urb(n)
+(recommended), the isoframe-parameter n can be used to allocate the
+structures for n frames.
+
+For each entry you have to specify the data offset for this frame (base is
+transfer_buffer), and the length you want to write/expect to read.
+After completion, actual_length contains the actual transfered length and
+status contains the resulting USB-status for the ISO transfer for this frame.
+It is allowed to specify a varying length from frame to frame (e.g. for
+audio synchronisation/adaptive transfer rates). You can also use the length
+0 to omit one or more frames (striping).
+
+As can be concluded from above, the UHCI-driver does not care for continous
+data in case of short packet ISO reads! There's no fixup_isoc() like in the
+old driver. There may be a common routine to do this in the future, but this
+has nothing to do with the UHCI-driver!
+
+For scheduling you can choose your own start frame or ASAP. As written above,
+queuing more than one ISO frame with ASAP to the same device&endpoint result
+in seamless ISO streaming. For continous streaming you have to use URB
+linking.
+
+1.9. How to start interrupt (INT) transfers?
+
+INT transfers are currently implemented with 8 different queues for intervals
+for 1, 2, 4,... 128ms. Only one TD is allocated for each interrupt. After
+calling the completion handler, the TD is recycled.
+With the submission of one URB, the interrupt is scheduled until it is
+canceled by unlink_urb.
+
+The submit_urb()-call modifies urb->interval to the rounded value.
+
--- /dev/null
+The ACM driver works with modems and ISDN TAs that use the USB Abstract
+Control Model standard.
+
+****************************
+Test it:
+Watch out, the driver is not stable and tested. Sync often, make backups,
+most importand: don't blame me...
+
+Create device files:
+mknod /dev/ttyACM0 c 166 0
+mknod /dev/ttyACM1 c 166 1
+mknod /dev/ttyACM2 c 166 2
+mknod /dev/ttyACM3 c 166 3
+Compile a kernel with support for your host controller (uhci only for now!)
+and support for ACM. Boot this kernel. If you connect your device to the
+USB bus you should see messages like the following:
+
+Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
+Jul 19 20:14:29 office kernel: Found 02:09
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office last message repeated 2 times
+Jul 19 20:14:29 office kernel: parsed = 39 len = 67
+Jul 19 20:14:29 office kernel: Expected descriptor 04/09, got 02/09 - skipping
+Jul 19 20:14:29 office kernel: 0 09
+Jul 19 20:14:29 office kernel: 1 02
+Jul 19 20:14:29 office kernel: 2 43
+Jul 19 20:14:29 office kernel: 3 00
+Jul 19 20:14:29 office kernel: 4 02
+Jul 19 20:14:29 office kernel: 5 02
+Jul 19 20:14:29 office kernel: 6 04
+Jul 19 20:14:29 office kernel: 7 60
+Jul 19 20:14:29 office kernel: 8 00
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 02:09
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office kernel: Found 04:09
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office kernel: Found 05:07
+Jul 19 20:14:29 office kernel: parsed = 67 len = 0
+Jul 19 20:14:29 office kernel: getstringtable
+Jul 19 20:14:29 office kernel: acm_probe
+Jul 19 20:14:29 office kernel: USB ACM found
+
+Watch out for the line:
+Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
+and the line:
+Jul 19 20:14:29 office kernel: USB ACM found
+These two lines show that the device was seen by the usb host controller and
+then recognized by the acm driver as a valid device.
+
+If you use a terminal emulation software like minicom with /dev/ttyACM0 you
+should be able to send AT commands to your device and get responses. I've
+been able to do zmodem downloads to another pc. However downloads from one
+ISDN TA to another ISDN TA connected to the same PC didn't work. Don't
+know why. Flow control is not finised after all and i'd guess there might
+be problems on heavily loades PCs. I also did some tests with ppp but i'm
+not finised with this. There might be a chance to get it working. However
+i'd like to know if your device is recognized as an ACM device. I'm also
+interested if the thing is stable or if it crashes.
+(should i say how it crases?)
+
+You should be able to add and remove devices from the bus. The driver will
+always try to fill up unused ttys. This means if you hotplug devices their
+order may have changed after reboot. This is not the behaviour Linus liked
+to see but it's ok for now. (I hope ;-)
+
+Please report your experiences to me:
+fuerst@in.tum.de
+
+***************************
+I've tested it with:
+3Com ISDN Pro TA.
+
+It should work with (That means i know these devices conform to ACM):
+3Com Office Connect Modem
+3Com Sportster USB (I think that's what it's called)
+
+***************************
+Many thanks to 3Com which did not only support me with hardware but also
+with technical support in USB questions. They also allowed me to do tests in
+their lab. Great!
+
+***************************
+Known bugs:
+Flow control not tested (likely not to work)
+Some tty function calls not implemented (putchar, etc...)
+Huge amounts of debug output (compile in [*] Magic SysRq key and press ALT+PRTSCR+0 )
+Not all mem is freed at close (need terminate irq in hcd)
+
+***************************
+Have fun,
+ Armin Fuerst
--- /dev/null
+13 November 1999
+david-b@pacbell.net
+
+This is an overview of how to use the "dc2xx" USB driver with certain
+digital still cameras from Kodak and other vendors.
+
+
+CAMERAS
+
+This driver will mostly be used with Kodak DC-2xx series digital still
+cameras, but it should be trivial to tell it about several non-Kodak
+USB-enabled cameras.
+
+You'll most likely want to hook it up to recent versions of "gPhoto"
+(www.gphoto.org), since version 0.4 and later know how to use it to talk
+to Kodak DC-240 and DC-280 cameras over USB.
+
+In addition the DC-260, DC-265, and DC-290 are currently recognized.
+However, like other cameras using the "Digita OS" (from www.flashpoint.com)
+there is no gPhoto support for this camera. At this writing the best
+known support for these cameras is a Python script that supports image
+downloading from those cameras. (See archives of the linux-usb mailing
+list.) The DC-220 should also work with this driver, given information
+about the USB product IDs. When it becomes available, the HP PhotoSmart
+C500 should also work ... it's another Digita OS camera with USB support.)
+
+It's likely that other digital still cameras can also use this USB driver,
+even if they're not from Kodak and don't use Digita. The reason is that
+most currently known USB still camera protocols treat USB like a faster
+packet-carrying connection than a serial line, which is exactly how this
+driver looks to an application.
+
+
+USB HARDWARE
+
+This has been shown to work on x86 OHCI and UHCI (Intel) chipsets. OHCI has
+been trouble free; not so with UHCI, which was first seen to be happy with
+2.3.24 kernels, and has not been as fast as OHCI.
+
+Note that in some cases changes in BIOS settings may be needed before
+your USB works. At least one user has reported a need for SMP-related
+settings as well.
+
+As yet, no reports have come from Linux users on non-Intel hardware.
+(You could color coordinate your iMac with a DC-240i ... :-)
+
+
+SETUP
+
+Configure in the DC2XX USB driver, and have it in your kernel. Recently I
+compile it right in, but I've done it as a module in the past.
+
+Create a device, perhaps like this (both read and write):
+
+ # mknod -m 0666 /dev/kodak c 10 170
+
+That "170" is not formally assigned, and this command may change. If you're
+using a non-Kodak camera, you may prefer another name.
+
+Don't plug in more than one compatible camera at this time. One of them
+will be ignored, but I'd not be sure which one!
+
+
+SANITY TESTING
+
+First: if you've got /proc support, make sure that the driver has hooked
+itself up correctly.
+
+ - you should see an entry in /proc/misc for the a Kodak DC-2xx
+ minor device number
+
+ - you should see an entry in /proc/bus/usb/drivers for "dc2xx",
+ if you also enabled USB /proc support.
+
+Second: when you connect your camera to the computer, does it get recognized
+by the driver?
+
+ - if you've got /proc/bus/usb/devices, you should see an entry
+ something like this. The "ProdID" may be different if you didn't
+ plug in a DC-240, but the "Driver=dc2xx" had better be there.
+
+ T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 MxCh= 0
+ D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
+ P: Vendor=040a ProdID=0120 Rev= 1.08
+ C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=100mA
+ I: If#= 0 Alt= 0 #EPs= 2 Cls=00(>ifc ) Sub=00 Prot=00 Driver=dc2xx
+ E: Ad=01(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
+ E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
+
+ - if you don't have /proc support for USB, see if "dmesg" output
+ tells you that you plugged in your camera.
+
+ USB new device connect, assigned device number 1
+ Manufacturer: Eastman Kodak Company
+ Product: KODAK DC240 Zoom Digital Camera
+ USB Camera is connected
+ usbcore: dc2xx driver claimed interface c3a68600
+ ohci-control thread sleeping
+
+Third: (optional) can you use gPhoto to talk to the camera?
+
+ - When you configure your camera, tell it to use "/dev/kodak" (or
+ whatever name you used). Right now, gPhoto emits a diagnostic
+ message (non-GUI) saying that it since it didn't act like a TTY,
+ it's assuming it's got a USB connection.
+
+ - With the camera turned on, get the "camera summary". It'll
+ talk to the camera -- and tell you you're using USB.
+
+If you got that far, you should be able to use everything fine.
--- /dev/null
+$Id: README.error-codes,v 1.1 1999/12/14 14:03:02 fliegl Exp $
+
+This is the documentation of (hopefully) all possible error codes (and
+their interpretation) that can be returned from the hostcontroller driver
+and from usbcore.
+
+NOTE:
+The USB_ST_* codes are deferred and are only listed for compatibility, new
+software should use only -E* instead!
+
+
+
+**************************************************************************
+* Error codes returned by usb_submit_urb *
+**************************************************************************
+
+Non-USB-specific:
+
+USB_ST_NOERROR
+0 URB submission went fine
+
+-ENOMEM no memory for allocation of internal structures
+
+USB-specific:
+
+-ENODEV specified USB-device or bus doesn't exist
+
+-ENXIO specified endpoint doesn't exist on the device
+
+USB_ST_URB_INVALID_ERROR
+-EINVAL a) Invalid transfer type specified (or not supported)
+ b) Invalid interrupt interval (0<=n<256)
+ c) more than one interrupt packet requested
+
+-EAGAIN a) specified ISO start frame too early
+ b) (using ISO-ASAP) too much scheduled for the future
+ wait some time and try again.
+
+-EFBIG too much ISO frames requested (currently uhci>900)
+
+-EPIPE specified pipe-handle is already stalled
+
+-EMSGSIZE endpoint message size is zero, do interface/alternate setting
+
+
+**************************************************************************
+* Error codes returned by in urb->status *
+* or in iso_frame_desc[n].status (for ISO) *
+**************************************************************************
+
+USB_ST_NOERROR
+0 Transfer completed successfully
+
+USB_ST_URB_KILLED
+-ENOENT URB was canceled by unlink_urb
+
+USB_ST_URB_PENDING
+-EINPROGRESS URB still pending, no results yet
+ (actually no error until now;-)
+
+USB_ST_BITSTUFF
+USB_ST_INTERNALERROR
+-EPROTO a) bitstuff error
+ b) unknown USB error
+
+USB_ST_CRC
+-EILSEQ CRC mismatch
+
+-EPIPE a) babble detect
+ b) endpoint stalled
+
+USB_ST_BUFFERUNDERRUN
+-ENOST buffer error
+
+USB_ST_NORESPONSE
+USB_ST_TIMEOUT
+-ETIMEDOUT transfer timed out, NAK
+
+USB_ST_REMOVED
+-ENODEV device was removed
+
+USB_ST_SHORT_PACKET
+-EREMOTEIO short packet detected
+
+USB_ST_PARTIAL_ERROR
+-EXDEV ISO transfer only partially completed
+ look at individual frame status for details
+
+USB_ST_URB_INVALID_ERROR
+-EINVAL ISO madness, if this happens: Log off and go home
+
+**************************************************************************
+* Error codes returned by usbcore-functions *
+* (expect also other submit and transfer status codes) *
+**************************************************************************
+
+usb_register():
+USB_ST_NOTSUPPORTED
+-EINVAL error during registering new driver
+
+usb_terminate_bulk():
+USB_ST_REMOVED
+-ENODEV urb already removed
+
+usb_get_*/usb_set_*():
+ All USB errors (submit/status) can occur
+
+
--- /dev/null
+ Linux HID driver v0.8
+ (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
+ (c) 1999 Andreas Gal <agal@uwsp.edu>
+ Sponsored by SuSE
+----------------------------------------------------------------------------
+
+0. Disclaimer
+~~~~~~~~~~~~~
+ This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your option)
+any later version.
+
+ This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+more details.
+
+ You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc., 59
+Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Should you need to contact me, the author, you can do so either by e-mail
+- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
+Ucitelska 1576, Prague 8, 182 00 Czech Republic
+
+ For your convenience, the GNU General Public License version 2 is included
+in the package: See the file COPYING.
+
+1. Introduction
+~~~~~~~~~~~~~~~
+ This is a driver for USB devices conforming to the USB HID (Human Input
+Device) standard. These devices include namely keyboards, mice and
+joysticks.
+
+ However many other devices (monitors, speakers, UPSs ...) also communicate
+through the same protocol, which makes its specification somewhat bloated.
+This isn't a problem, though, because the driver doesn't need to know about
+all the possible devices it can control, and can just parse the protocol and
+leave the rest of the job (for example understanding what the UPS wants to
+say) to the userland.
+
+ Because of this, the USB HID driver has two interfaces. One is via the
+proc filesystem, allowing userland applications send and read arbitrary
+reports to and from a connected USB device. The other is via a very simple
+yet generic input device driver, which dispatches input events (keystrokes,
+mouse or joystick movements) to specific, backward compatible userland
+interfaces. This way a PS/2 mouse, an AT keyboard or a Linux joystick driver
+interface are emulated, and allow applications to immediately work with USB
+mice, USB keyboards and USB joysticks without any changes.
+
+ The input driver is aimed for a little more than USB device handling in
+the future, though. It's generic enough so that it can be used for any
+mouse, keyboard or joystick (and more, of course). A PS/2 mouse driver, a
+serial mouse, Sun mouse, and most of the busmouse drivers were rewritten to
+use this as well as the AT keyboard and Sun keyboard drivers. This will
+hopefully allow conversion of all Linux keyboard and mouse and joystick
+drivers to this scheme.
+
+ This effort has it's home page at:
+
+ http://www.suse.cz/development/input/
+
+You'll find both the latest HID driver and the complete Input driver there.
+There is also a mailing list for this:
+
+ listproc@atrey.karlin.mff.cuni.cz
+
+Send "subscribe linux-joystick Your Name" to subscribe to it.
+
+2. Usage
+~~~~~~~~
+ Since the driver comes with recent 2.3 kernels, all that's needed to use
+it is to enable it either as a module or compiled-in into the kernel.
+
+ After that, after reboot (and possibly also inserting the USB and HID
+modules) the following will happen:
+
+* If you selected keyboard support, all USB keystrokes will be also routed
+ to the Linux keyboard driver as if being input through the ordinary system
+ keyboard.
+
+* If you selected mouse support, there will be (one or more) simulated PS/2
+ mouse devices on major 10, minor 32, 33 and more. These simulated mice can
+ in addition to a standard 3-button PS/2 mouse behave like MS Intellimice,
+ with a wheel. If you want to use the wheel, just specify '-t imps2' to gpm
+ and 'Protocol "ImPS/2"' to X, and it will work. A single emulated mouse
+ device can be open by any number of processes (unlike the /dev/psaux), and
+ for each of them the emulation is separate, each can use a different mode.
+ The mousedev driver, which emulates the mice, can also emulate a Genius
+ NewScroll 5 buttons-and-a-wheel mouse, if you set it to a Genius PS/2
+ mode ('-t netmouse' 'Protocol "NetMousePS/2"'). However, not gpm, nor X
+ can decode the 5 buttons yet, so this isn't very useful right now.
+
+* If you selected joystick support, the driver will take over major 15, the
+ joystick major number, and will emulate joysticks on it. This means the
+ normal joystick driver can't be used together with it (now, after the
+ normal joystick drivers are converted to the input scheme, all will work
+ nicely together). Also, you'll probably need to calibrate your joystick
+ manually ('man jscal') to be able to use it, because the USB
+ autocalibration is far from perfect yet.
+
+* If you selected event device support, there will be devices on major 10,
+ minors 64, 65 and more for each input device connected through this
+ driver. These devices output raw events the input driver dispatches. Each
+ has a timestamp. This hopefully will be THE way X will talk to keyboard
+ and mice, because it's hardware independent, and not limited by existing
+ de-facto standards.
+
+3. Verifying if it works
+~~~~~~~~~~~~~~~~~~~~~~~~
+ Typing a couple keys on the keyboard should be enough to check that a USB
+keyboard works and is correctly connected to the kernel keyboard driver.
+
+ Doing a cat /dev/hidmouse (c, 10, 32) will verify that a mouse is also
+emulated, characters should appear if you move it.
+
+ You can test the joystick emulation with the 'jstest' utility, available
+in the joystick package (see Documentation/joystick.txt).
+
+ You can test the event devics with the 'evtest' utitily available on the
+input driver homepage (see the URL above).
+
+4. FAQ
+~~~~~~
+Q: Why aren't any questions here yet?
+A: Because none were frequent enough yet.
+
+5. Event interface
+~~~~~~~~~~~~~~~~~~
+ Should you want to add event device support into any application (X, gpm,
+svgalib ...) I (vojtech@suse.cz) will be happy to provide you any help I
+can. Here goes a description of the current state of things, which is going
+to be extended, but not changed incompatibly as time goes:
+
+ You can use blocking and nonblocking reads, also select() on the
+/dev/inputX devices, and you'll always get a whole number of input events on
+a read. Their layout is:
+
+struct input_event {
+ struct timeval time;
+ unsigned short type;
+ unsigned short code;
+ unsigned int value;
+};
+
+ 'time' is the timestamp, it returns the time at which the event happened.
+Type is for example EV_REL for relative momement, REL_KEY for a keypress or
+release. More types are defined in include/linux/input.h.
+
+ 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
+list is in include/linux/input.h.
+
+ 'value' is the value the event carries. Either a relative change for
+EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
+release, 1 for keypress and 2 for autorepeat.
+
+6. Proc interface
+~~~~~~~~~~~~~~~~~
+ For HID-specific devices there is also the /proc interface. It isn't
+present in this release yet, though, so it's description will appear here
+together with the code in the driver.
--- /dev/null
+
+The OHCI HCD layer is a simple but nearly complete implementation of what the
+USB people would call a HCD for the OHCI.
+ (ISO comming soon, Bulk, INT u. CTRL transfers enabled)
+It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
+The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers.
+
+- Roman Weissgaerber <weissg@vienna.at>
+
+ * v4.0 1999/08/18 removed all dummy eds, unlink unused eds, code cleanup, bulk transfers
+ * v2.1 1999/05/09 ep_addr correction, code cleanup
+ * v0.2.0 1999/05/04
+ * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
+ * virtual root hub is now an option,
+ * memory allocation based on kmalloc and kfree now, simple Bus error handling,
+ * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
+ *
+ * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
+ * from Greg Smith (ohci.c): better reset ohci-controller handling, hub
+ *
+ * v0.1.0 1999/04/27 initial release
+
+to remove the module try:
+rmmod usb-ohci-hcd
+
+Features:
+- virtual root hub, all basic hub descriptors and commands (state: complete)
+ this is an option now (v0.2.0)
+ #define CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
+ default is with.
+ (at the moment: the Virtual Root Hub is included automatically)
+
+ files: ohci-root-hub.c, ohci-root-hub.h
+
+
+- Endpoint Descriptor (ED) handling more static approach
+ (EDs should be allocated in parallel to the SET CONFIGURATION command and they live
+ as long as the function (device) is alive or another configuration is choosen.
+ In the HCD layer the EDs has to be allocated manually either by calling a subroutine
+ or by sending a USB root hub vendor specific command to the virtual root hub.
+ At the alternate linux usb stack EDs will be added (allocated) at their first use.
+ ED will be unlinked from the HC chains if they are not bussy.
+
+ files: ohci-hcd.c ohci-hcd.h
+ routines: (do not use for drivers, use the top layer alternate usb commands instead)
+
+ int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1,
+ int interval, int load, f_handler handler, int ep_size, int speed)
+ adds an endpoint, (if the endpoint already exists some parameters will be updated)
+
+ int usb_ohci_rm_ep( )
+ removes an endpoint and all pending TDs of that EP
+
+ usb_ohci_rm_function( )
+ removes all Endpoints of a function (device)
+
+- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
+ The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
+ to take care of buffer allocation.
+ files: ohci-hcd.c ohci-hcd.h
+
+ There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
+
+ int ohci_trans_req(struct ohci * ohci, hcd_ed, int ctrl_len, void *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
+
+ CTRL: ctrl, ctrl_len ... cmd buffer
+ data, data_len ... data buffer (in or out)
+ INT, BULK: ctrl = NULL, ctrl_len=0,
+ data, data_len ... data buffer (in or out)
+ ISO: tbd
+
+ There is no buffer reinsertion done by the internal HCD function.
+ (The interface layer does this for a INT-pipe on request.)
+ If you want a transfer then you have to
+ provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
+ you can send as many as you like. They should come back by the callback f_handler in
+ the same order (for each endpoint, not globally) If an error occurs all
+ queued transfers of an endpoint will return unsent. They will be marked with an error status.
+
+ e.g double-buffering for int transfers:
+
+ ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+ ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+
+ and when a data0 packet returns by the callback f_handler requeue it:
+ ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+ and when a data1 packet returns by the callback f_handler requeue it:
+ ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+
+ lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
+ The alternate usb uses them for dev_id and usb_device_irq handler.
+
+
+- Done list handling: returns the requests (callback f_handler in ED) and does
+ some error handling, root-hub request dequeuing
+ (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
+
+
--- /dev/null
+-------------------------------------------------------------------------------
+Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC
+-------------------------------------------------------------------------------
+
+INTRODUCTION:
+
+This is a preliminary version of my OV511 Linux device driver. At the moment,
+it does not do much more than detect the chip and initialize it. As trivial
+as this sounds, it represents many hours of my work. Since OmniVision refused
+to release the full specs to me, I had to write code to probe out the register
+read/write commands. Some code is in place to allow a frame to be grabbed, but
+it is nowhere near complete.
+
+SUPPORTED CAMERAS:
+____________________________________________
+Manufacturer | Model | Custom ID
+-----------------+--------------+-----------
+D-Link | DSB-C300 | 3
+Creative Labs | WebCam 3 | 21
+--------------------------------------------
+
+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()
+
+WHAT YOU NEED:
+
+- If you want to help with the development, get the chip's specification docs at
+ http://www.ovt.com/omniusbp.html
+
+- A Video4Linux compatible frame grabber program (I recommend vidcat)
+ (see: http://www.exploits.org/v4l/ )
+
+WHAT NEEDS TO BE DONE:
+
+In short, a lot.
+
+UPDATE:
+Currently, the control messages are working fine ("vendor commands"; for
+reading and writing the OV511 registers.) The I2C bus commands for reading and
+writing the camera (OV7610) registers are implemented and working, with at least
+one person's camera. The isochronous-in endpoint for video data is finally
+producing data, but since ov511_parse_data() is not implemented you will not see
+a picture yet.
+
+Support for specific CCD's will have to be implemented as well (such as the
+OV7610.)
+
+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.
+
+HOW TO CONTACT ME:
+
+You can email me at mmcclelland@delphi.com . Please prefix the subject line
+with "OV511: " so that I am certain to notice your message.
+
+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 and ISOC
+working.
--- /dev/null
+/proc/bus/usb filesystem output
+===============================
+(version 19991218)
+
+
+The /proc filesystem for USB devices generates
+/proc/bus/usb/drivers and /proc/bus/usb/devices.
+
+/proc/bus/usb/drivers just lists the registered drivers,
+one per line. Not very interesting or pretty.
+
+In /proc/bus/usb/devices, each device's output has multiple
+lines (except for a root hub) of ASCII output.
+I made it ASCII instead of binary on purpose, so that someone
+can obtain some useful data from it without the use of an
+auxiliary program. However, with an auxiliary program, the numbers
+in the first 4 columns of each "T:" line (topology info:
+Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram.
+(I think. I haven't proved this, but I have tested it with 3
+different topo/connections and it looked possible.)
+
+Each line is tagged with a one-character ID for that line:
+
+T = Topology (etc.)
+B = Bandwidth
+D = Device descriptor info.
+P = Product ID info. (from Device descriptor, but they won't fit
+ together on one line)
+S = String info
+C = Configuration descriptor info. (* = active configuration)
+I = Interface descriptor info.
+E = Endpoint descriptor info.
+
+=======================================================================
+
+/proc/bus/usb/devices output format:
+
+Legend:
+ d = decimal number (may have leading spaces or 0's)
+ x = hexadecimal number (may have leading spaces or 0's)
+ s = string
+
+
+Topology info:
+
+T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
+| | | | | | | | |__MaxChildren
+| | | | | | | |__Device Speed in Mbps
+| | | | | | |__DeviceNumber
+| | | | | |__Count of devices at this level
+| | | | |__Connector/Port on Parent for this device
+| | | |__Parent DeviceNumber
+| | |__Level in topology for this bus
+| |__Bus number
+|__Topology info tag
+
+
+Bandwidth info:
+B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
+| | | |__Number if isochronous requests
+| | |__Number of interrupt requests
+| |__Total Bandwidth allocated to this bus
+|__Bandwidth info tag
+
+
+Device descriptor info & Product ID info:
+
+D: Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
+P: Vendor=xxxx ProdID=xxxx Rev=xx.xx
+
+where
+D: Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
+| | | | | | |__NumberConfigurations
+| | | | | |__MaxPacketSize of Default Endpoint
+| | | | |__DeviceProtocol
+| | | |__DeviceSubClass
+| | |__DeviceClass
+| |__Device USB version
+|__Device info tag #1
+
+where
+P: Vendor=xxxx ProdID=xxxx Rev=xx.xx
+| | | |__Product revision number
+| | |__Product ID code
+| |__Vendor ID code
+|__Device info tag #2
+
+
+String descriptor info:
+
+S: Manufacturer=ssss
+| |__Manufacturer of this device as read from the device.
+|__String info tag
+
+S: Product=ssss
+| |__Product description of this device as read from the device.
+|__String info tag
+
+
+Configuration descriptor info:
+
+C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
+| | | | |__MaxPower in mA
+| | | |__Attributes
+| | |__ConfiguratioNumber
+| |__NumberOfInterfaces
+|__Config info tag
+
+
+Interface descriptor info (can be multiple per Config):
+
+I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
+| | | | | | | |__Driver name
+| | | | | | |__InterfaceProtocol
+| | | | | |__InterfaceSubClass
+| | | | |__InterfaceClass
+| | | |__NumberOfEndpoints
+| | |__AlternateSettingNumber
+| |__InterfaceNumber
+|__Interface info tag
+
+
+Endpoint descriptor info (can be multiple per Interface):
+
+E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
+E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
+| | | | |__Interval
+| | | |__EndpointMaxPacketSize
+| | |__Attributes(EndpointType)
+| |__EndpointAddress(I=In,O=Out)
+|__Endpoint info tag
+
+=======================================================================
+
+
+If a user or script is interested only in Topology info, for
+example, use something like "grep ^T: /proc/bus/usb/devices"
+for only the Topology lines. A command like
+"grep -i ^[tdp]: /proc/bus/usb/devices" can be used to list
+only the lines that begin with the characters in square brackets,
+where the valid characters are TDPCIE. With a slightly more able
+script, it can display any selected lines (for example, only T, D,
+and P lines) and change their output format. (The "procusb"
+Perl script is the beginning of this idea. It will list only
+selected lines [selected from TDPCIE] or "All" lines from
+/proc/bus/usb/devices.)
+
+The Topology lines can be used to generate a graphic/pictorial
+of the USB devices on a system's root hub. (See more below
+on how to do this.)
+
+The Interface lines can be used to determine what driver is
+being used for each device.
+
+The Configuration lines could be used to list maximum power
+(in milliamps) that a system's USB devices are using.
+For example, "grep ^C: /proc/bus/usb/devices".
+
+
+Here's an example, from a system which has a UHCI root hub,
+an external hub connected to the root hub, and a mouse and
+a serial converter connected to the external hub.
+
+T: Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2
+B: Alloc= 28/900 us ( 3%), #Int= 2, #Iso= 0
+T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4
+D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
+P: Vendor=0451 ProdID=1446 Rev= 1.00
+C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
+I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
+E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms
+T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0
+D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
+P: Vendor=04b4 ProdID=0001 Rev= 0.00
+C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
+I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse
+E: Ad=81(I) Atr=03(Int.) MxPS= 3 Ivl= 10ms
+T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
+D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
+P: Vendor=0565 ProdID=0001 Rev= 1.08
+S: Manufacturer=Peracom Networks, Inc.
+S: Product=Peracom USB to Serial Converter
+C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
+I: If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
+E: Ad=81(I) Atr=02(Bulk) MxPS= 64 Ivl= 16ms
+E: Ad=01(O) Atr=02(Bulk) MxPS= 16 Ivl= 16ms
+E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl= 8ms
+
+
+Selecting only the "T:" and "I:" lines from this (for example, by using
+"procusb ti"), we have:
+
+T: Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2
+T: Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 4
+I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
+T: Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0
+I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=mouse
+T: Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
+I: If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
+
+
+Physically this looks like (or could be converted to):
+
+ +------------------+
+ | PC/root_hub (12)| Dev# = 1
+ +------------------+ (nn) is Mbps.
+ Level 0 | CN.0 | CN.1 | [CN = connector/port #]
+ +------------------+
+ /
+ /
+ +-----------------------+
+ Level 1 | Dev#2: 4-port hub (12)|
+ +-----------------------+
+ |CN.0 |CN.1 |CN.2 |CN.3 |
+ +-----------------------+
+ \ \____________________
+ \_____ \
+ \ \
+ +--------------------+ +--------------------+
+ Level 2 | Dev# 3: mouse (1.5)| | Dev# 4: serial (12)|
+ +--------------------+ +--------------------+
+
+
+
+Or, in a more tree-like structure (ports [Connectors] without
+connections could be omitted):
+
+PC: Dev# 1, root hub, 2 ports, 12 Mbps
+|_ CN.0: Dev# 2, hub, 4 ports, 12 Mbps
+ |_ CN.0: Dev #3, mouse, 1.5 Mbps
+ |_ CN.1:
+ |_ CN.2: Dev #4, serial, 12 Mbps
+ |_ CN.3:
+|_ CN.1:
+
+
+ ### END ###
--- /dev/null
+Oct. 19, 1999
+
+CHANGES
+
+- Ammended for Linux-2.3.22+
+
+
+INTRODUCTION
+
+This document will hopefully provide enough info on how to get SANE
+working with a Hewlett Packard USB capable scanner using the USB
+interface. The majority of HP Scanners support the Scanner Control
+Language (SCL) which is both published by HP and supported by SANE.
+The only HP Scanner that I'm aware of that does not support SCL is the
+4200C. All other HP scanners with USB interfaces should work (4100C,
+5200C, 6200C, and 6300C). Of course as HP releases new scanners this
+information may change.
+
+
+REQUIREMENTS
+
+In order to get this running you'll need USB support in your kernel in
+addition to USB Scanner support. Please refer to README.scanner
+for issues pertaining to Linux USB and USB Scanner support.
+
+An installed version of SANE which is available from
+http://www.mostang.com/sane/. Testing has been performed using
+version SANE-1.0.1. For instructions on building and installing SANE,
+refer to the various README files within the SANE distribution.
+
+
+OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW?
+
+NOTE: $INSTALL_DIR is the location where SANE was installed. It may
+be /usr/local, /usr, /opt or somewhere else. If you don't know, ask
+your system administrator.
+
+1) Make sure that you have the libsane-hp.* libraries under the
+$INSTALL_DIR/lib/sane/ directory. If you don't, then the HP backend
+was either not compiled or installed properly.
+
+2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
+files: dll.conf, hp.conf.
+
+ dll.conf: Make sure that the 'hp' entry is present and uncommented.
+
+ hp.conf: This should contain two lines:
+
+ /dev/usbscanner
+ option connect-device
+
+3) You should now be able to use SANE (xscanimage or scanimage).
+
+Don't forget to read any relevant man pages regarding the usage of
+SANE. If you have other entries uncommented in dll.conf, you may have
+to specify the device to (x)scanimage. Again, `man` is your friend.
+The xscanimage (1) man page has info on how to get 'The Gimp' to work
+with xscanimage. Note that Gimp support must be compiled into SANE
+for it work. If you are dealing with a RedHat system, this means that
+you'll also need to install the gimp-devel rpm package.
+
+NOTE: The issues regarding core dumping by (x)scanimage have (or seem
+to be thus far) been resolved with version 0.2+ of the USB scanner
+driver which should be available in linux-2.3.23. If you notice
+otherwise, please contact me.
+
+David /\/elson
+dnelson@jump.net
+http://www.jump.net/~dnelson
--- /dev/null
+Oct 19, 1999
+
+CHANGES
+
+- Ammended for linux-2.3.22+
+- Appended hp_scan.c to end of this README
+- Removed most references to HP
+
+
+OVERVIEW
+
+This README will address issues regarding how to configure the kernel
+to access a USB scanner. Although the driver was originally conceived
+for USB HP scanners, it's general enough so that it can be used with
+other scanners. Also, one can now pass the USB Vendor and
+Product ID's using module parameters for unknown scanners. Refer to
+the document README.scanner_hp_sane for guidance on how to configure
+SANE to use a USB HP Scanner.
+
+
+ADDITIONAL INFORMATION
+
+http://www.linux-usb.org/
+http://www.dynamine.net/linux-usb/HOWTO/
+
+
+REQUIREMENTS
+
+A host with a USB port. Ideally, either a UHCI (Intel) or OHCI
+(Compaq and others) hardware port should work. However, I've only
+been able to really use an OHCI controller. I did have access to a
+system with a UHCI controller but some very limited testing did not
+produce satisfactory results. Luke Ordelmans
+<postbus@ordelmans.demon.nl> has reported success using the UHCI host
+controller with kernel 2.3.18 and a ChainTech motherboard. Here
+lately I've been having better success with the ohci-hcd driver. But
+since Linux USB support is still in a state of constant development
+that may change at a later date. I am confident that eventually all
+the host contollers will perform without incident.
+
+A Linux kernel with USB support (preferably linux-2.3.18+)
+
+A Linux kernel with USB Scanner support.
+
+
+CONFIGURATION
+
+Using `make menuconfig` or your prefered method for configuring the
+kernel, select 'Support for USB', 'OHCI/OHCI-HCD/UHCI' depending on
+your hardware, 'USB hub support', and 'USB Scanner support'. Compile
+and install the modules (you may need to execute `depmod -a` to update
+the module dependencies). Testing was performed only as modules,
+YMMV.
+
+Add a device for the USB scanner:
+ linux-2.3.22 and above: `mknod /dev/usbscanner c 180 48`
+ linux-2.3.21 and below: `mknod /dev/usbscanner c 16 1`
+
+Set appropriate permissions for /dev/usbscanner (don't forget about
+group and world permissions). Both read and write permissions are
+required for proper operation.
+
+Load the appropriate modules (if compiled as modules):
+
+ OHCI:
+ modprobe usb-ohci
+ modprobe scanner
+
+ OHCI-HCD:
+ modprobe usb-ohci-hcd
+ modprobe hub
+ modprobe scanner
+
+ UHCI:
+ modprobe usb-uhci
+ modprobe hub (don't know if this is required or not)
+ modprobe scanner
+
+That's it. SANE should now be able to access the device.
+
+There is a small test program (hp_scan.c -- appended below) that can
+be used to test the scanner device if it's an HP scanner that supports
+SCL. Its purpose is to test the driver without having to
+retrieve/configure SANE. Hp_scan.c will scan the entire bed and put
+the output into a file called 'out.dat' in the current directory. The
+data in the file is raw data so it's not very useful for imaging.
+
+
+MODULE PARAMETERS
+
+If you have a device that wish to experiment with or try using this
+driver with, but the Vendor and Product ID's are not coded in, don't
+despair. If the driver was compiled as a module, you can pass options
+to the driver. Simply add 'options scanner vendor=0x####
+product=0x****' to the conf.modules/modules.conf file replacing the
+#'s and the *'s with the correct ID's. The ID's can be retrieved from
+the messages file or using `cat /proc/bus/usb/devices` if USB /proc
+support was selected during kernel configuration.
+
+
+BUGS
+
+If you encounter any problems feel free to drop me an email.
+
+David /\/elson
+dnelson@jump.net
+http://www.jump.net/~dnelson
+
+--------------- snip -- hp_scan.c -- snip ---------------
+/*
+
+This is a really crude attempt at writing a short test program. It's
+mostly only to be used to test connectivity with USB HP scanners that
+understand SCL. Currently, the supported models are 4100C, 5200C,
+6200C, and the 6300C. Note that the 4200C is *NOT* acceptable.
+
+Copyright (C) David E. Nelson <dnelson@jump.net>, 1999
+
+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.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <error.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/*
+ Gray Output produces about a 8945400 byte file.
+ Color Output produces a 26836200 byte file.
+
+ To compile: gcc -o hp_scan hp_scan.c
+*/
+
+// #define COLOR /* Undef to scan GrayScale */
+
+int send_cmd(int, const char *, int);
+int read_cmd(int, char *, int);
+
+int
+main(void) {
+
+ ssize_t cnt = 0, total_cnt = 0;
+
+ FILE *fpout;
+
+ int fp;
+ int data_size = 32768;
+
+ char *data;
+
+ static char reset_cmd[] = {'\x1b','E'};
+
+#ifdef COLOR
+ static char data_type_cmd[] = {'\x1b','*','a','5','T'}; /* Color */
+ static char data_width_cmd[] = {'\x1b','*','a','2','4','G'}; /* 24 Bit Color */
+#else
+ static char data_type_cmd[] = {'\x1b','*','a','4','T'}; /* Gray */
+ static char data_width_cmd[] = {'\x1b','*','a','8','G'}; /* 8 Bit Gray */
+#endif
+
+ static char query_cmd[] = {'\x1b', '*', 's', '2', '5', '7', 'E'};
+ static char start_scan_cmd[] = {'\x1b','*','f','0','S'};
+
+ if(!(data=malloc(data_size))) {
+ perror("malloc failed");
+ exit (1);
+ }
+
+ if((fp=open("/dev/usbscanner", O_RDWR)) < 0) {
+ perror("Unable to open scanner device");
+ exit (1);
+ }
+
+ if((fpout=fopen("out.dat", "w+")) == NULL) {
+ perror("Unable to open ouput file");
+ exit(1);
+ }
+
+ send_cmd(fp, reset_cmd, sizeof(reset_cmd));
+ send_cmd(fp, data_type_cmd, sizeof(data_type_cmd));
+ send_cmd(fp, data_width_cmd, sizeof(data_width_cmd));
+ send_cmd(fp, start_scan_cmd, sizeof(start_scan_cmd));
+
+ while ((cnt = read(fp, data, data_size)) > 0) {
+ printf("Read: %u\n", cnt);
+ if(fwrite(data, sizeof(char), cnt, fpout) < 0) {
+ perror("Write to output file failed");
+ exit (1);
+ }
+ total_cnt += cnt;
+ }
+ if (cnt < 0) {
+ perror("Read from scanner failed");
+ exit (1);
+ }
+
+ printf("\nRead %lu bytes.\n", total_cnt);
+
+ send_cmd(fp, reset_cmd, sizeof(reset_cmd));
+
+ close(fp);
+ fclose(fpout);
+ return (0);
+}
+
+int
+send_cmd(int fp, const char * cmd, int length) {
+
+ int result;
+ int x;
+
+ if((result = write(fp, cmd, length)) != length) {
+ printf ("Write warning: %d bytes requested, %d written\n");
+ } else if (result < 0) {
+ perror ("send_cmd failure");
+ exit (1);
+ }
+ return (result);
+}
+
+int
+read_cmd(int fp, char * response, int length) {
+
+ return read(fp, response, length);
+
+}
--- /dev/null
+Specification and Internals for the New UHCI Driver (Whitepaper...)
+
+ brought to you by
+
+ Georg Acher, acher@in.tum.de (executive slave) (base guitar)
+ Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
+ Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
+
+ $Id: README.uhci,v 1.1 1999/12/14 14:03:02 fliegl Exp $
+
+This document and the new uhci sources can be found on
+ http://hotswap.in.tum.de/usb
+
+1. General issues
+
+1.1 Why a new UHCI driver, we already have one?!?
+
+Correct, but its internal structure got more and more mixed up by the (still
+ongoing) efforts to get isochronous transfers (ISO) to work.
+Since there is an increasing need for reliable ISO-transfers (especially
+for USB-audio needed by TS and for a DAB-USB-Receiver build by GA and DF),
+this state was a bit unsatisfying in our opinion, so we've decided (based
+on knowledge and experiences with the old UHCI driver) to start
+from scratch with a new approach, much simpler but at the same time more
+powerful.
+It is inspired by the way Win98/Win2000 handles USB requests via URBs,
+but it's definitely 100% free of MS-code and doesn't crash while
+unplugging an used ISO-device like Win98 ;-)
+Some code for HW setup and root hub management was taken from the
+original UHCI driver, but heavily modified to fit into the new code.
+The invention of the basic concept, and major coding were completed in two
+days (and nights) on the 16th and 17th of October 1999, now known as the
+great USB-October-Revolution started by GA, DF, and TS ;-)
+
+Since the concept is in no way UHCI dependant, we hope that it will also be
+transfered to the OHCI-driver, so both drivers share a common API.
+
+1.2. Advantages and disadvantages
+
++ All USB transfer types work now!
++ Asynchronous operation
++ Simple, but powerful interface (only two calls for start and cancel)
++ Easy migration to the new API, simplified by a compatibility API
++ Simple usage of ISO transfers
++ Automatic linking of requests
++ ISO transfers allow variable length for each frame and striping
++ No CPU dependent and non-portable atomic memory access, no asm()-inlines
++ Tested on x86 and Alpha
+
+- Rewriting for ISO transfers needed
+
+1.3. Is there some compatibility to the old API?
+
+Yes, but only for control, bulk and interrupt transfers. We've implemented
+some wrapper calls for these transfer types. The usbcore works fine with
+these wrappers. For ISO there's no compatibility, because the old ISO-API
+and its semantics were unnecessary complicated in our opinion.
+
+1.4. What's really working?
+
+As said above, CTRL und BULK already work fine even with the wrappers,
+so legacy code wouldn't notice the change.
+Regarding to Thomas, ISO transfers now run stable with USB audio.
+INT transfers (e.g. mouse driver) work fine, too.
+
+1.5. Are there any bugs?
+
+No ;-)
+Hm...
+Well, of course this implementation needs extensive testing on all available
+hardware, but we believe that any fixes shouldn't harm the overall concept.
+
+1.6. What should be done next?
+
+A large part of the request handling seems to be identical for UHCI and
+OHCI, so it would be a good idea to extract the common parts and have only
+the HW specific stuff in uhci.c. Furthermore, all other USB device drivers
+should need URBification, if they use isochronous or interrupt transfers.
+One thing missing in the current implementation (and the old UHCI driver)
+is fair queueing for BULK transfers. Since this would need (in principle)
+the alteration of already constructed TD chains (to switch from depth to
+breadth execution), another way has to be found. Maybe some simple
+heuristics work with the same effect.
+
+---------------------------------------------------------------------------
+
+2. Internal structure and mechanisms
+
+To get quickly familiar with the internal structures, here's a short
+description how the new UHCI driver works. However, the ultimate source of
+truth is only uhci.c!
+
+2.1. Descriptor structure (QHs and TDs)
+
+During initialization, the following skeleton is allocated in init_skel:
+
+ framespecific | common chain
+
+framelist[]
+[ 0 ]-----> TD --> TD -------\
+[ 1 ]-----> TD --> TD --------> TD ----> QH -------> QH -------> QH ---> NULL
+ ... TD --> TD -------/
+[1023]-----> TD --> TD ------/
+
+ ^^ ^^ ^^ ^^ ^^ ^^
+ 1024 TDs for 7 TDs for 1 TD for Start of Start of End Chain
+ ISO INT (2-128ms) 1ms-INT CTRL Chain BULK Chain
+
+For each CTRL or BULK transfer a new QH is allocated and the containing data
+transfers are appended as (vertical) TDs. After building the whole QH with its
+dangling TDs, the QH is inserted before the BULK Chain QH (for CTRL) or
+before the End Chain QH (for BULK). Since only the QH->next pointers are
+affected, no atomic memory operation is required. The three QHs in the
+common chain are never equipped with TDs!
+
+For ISO or INT, the TD for each frame is simply inserted into the apropriate
+ISO/INT-TD-chain for the desired frame. The 7 skeleton INT-TDs are scattered
+among the 1024 frames similar to the old UHCI driver.
+
+For CTRL/BULK/ISO, the last TD in the transfer has the IOC-bit set. For INT,
+every TD (there is only one...) has the IOC-bit set.
+
+Besides the data for the UHCI controller (2 or 4 32bit words), the descriptors
+are double-linked through the .vertical and .horizontal elements in the
+SW data of the descriptor (using the double-linked list structures and
+operations), but SW-linking occurs only in closed domains, i.e. for each of
+the 1024 ISO-chains and the 8 INT-chains there is a closed cycle. This
+simplifies all insertions and unlinking operations and avoids costly
+bus_to_virt()-calls.
+
+2.2. URB structure and linking to QH/TDs
+
+During assembly of the QH and TDs of the requested action, these descriptors
+are stored in urb->urb_list, so the allocated QH/TD descriptors are bound to
+this URB.
+If the assembly was successful and the descriptors were added to the HW chain,
+the corresponding URB is inserted into a global URB list for this controller.
+This list stores all pending URBs.
+
+2.3. Interrupt processing
+
+Since UHCI provides no means to directly detect completed transactions, the
+following is done in each UHCI interrupt (uhci_interrupt()):
+
+For each URB in the pending queue (process_urb()), the ACTIVE-flag of the
+associated TDs are processed (depending on the transfer type
+process_{transfer|interrupt|iso}()). If the TDs are not active anymore,
+they indicate the completion of the transaction and the status is calculated.
+Inactive QH/TDs are removed from the HW chain (since the host controller
+already removed the TDs from the QH, no atomic access is needed) and
+eventually the URB is marked as completed (OK or errors) and removed from the
+pending queue. Then the next linked URB is submitted. After (or immediately
+before) that, the completion handler is called.
+
+2.4. Unlinking URBs
+
+First, all QH/TDs stored in the URB are unlinked from the HW chain.
+To ensure that the host controller really left a vertical TD chain, we
+wait for one frame. After that, the TDs are physically destroyed.
+
+2.5. URB linking and the consequences
+
+Since URBs can be linked and the corresponding submit_urb is called in
+the UHCI-interrupt, all work associated with URB/QH/TD assembly has to be
+interrupt save. This forces kmalloc to use GFP_ATOMIC in the interrupt.
--- /dev/null
+This serial driver currently only works with the Belkin and Peracom USB
+Serial devices. It should also work for the Etek converter, but I do
+not know the vendor id and device id of that device (if anyone does,
+please let me know.)
+
+If your device is not compatible with the above models, you can try
+out the "generic" interface. This interface does not provide any type
+of control messages sent to the device, and does not support any kind
+of device flow control. All that is required of your device is that
+it has at least one bulk in endpoint, or one bulk out endpoint.
+To enable the driver to recognize your device, build the driver as
+a module and load it by the following invocation:
+ insmod usb-serial.o vendor=0x#### product=0x####
+where the #### is replaced with the hex representation of your device's
+vendor id and product id.
+
+The driver can handle enumerating the device, and sending and receiving
+data from the converter. However, since I do not have a spec for the Belkin,
+Peracom, and eTek devices, and the raw dumps from the Win98 driver are
+confusing, and eTek keeps giving me the run around, no control signals are
+currently handled, and the data will most likely come through on a baud
+rate that you are not expecting. So if you have these devices, do not
+expect the correct data to show up at either end.
+
+The major number that the driver uses is 188 so to use the driver, create
+the following nodes:
+mknod /dev/ttyUSB0 c 188 0
+mknod /dev/ttyUSB1 c 188 1
+mknod /dev/ttyUSB2 c 188 2
+mknod /dev/ttyUSB3 c 188 3
+
+then plug in a device and use your friendly terminal program to see what
+happens.
+
+If anyone has any problems getting the device to enumerate, or data to
+flow through it, please contact me.
+
+
+
+greg k-h
+greg@kroah.com
+
CIRRUS LOGIC GENERIC FBDEV DRIVER
P: Jeff Garzik
-M: jgarzik@pobox.com
+M: jgarzik@mandrakesoft.com
L: linux-fbdev@vuser.vu.union.edu
S: Maintained
VIA 82Cxxx AUDIO DRIVER
P: Jeff Garzik
-M: jgarzik@pobox.com
+M: jgarzik@mandrakesoft.com
S: Maintained
VIDEO FOR LINUX
VERSION = 2
PATCHLEVEL = 3
-SUBLEVEL = 36
+SUBLEVEL = 37
EXTRAVERSION =
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
fs lib mm ipc kernel drivers net: dummy
$(MAKE) $(subst $@, _dir_$@, $@)
+TAGS: dummy
+ etags `find include/asm-$(ARCH) -name '*.h'`
+ find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs etags -a
+ find $(SUBDIRS) init -name '*.c' | xargs etags -a
+
+# Exuberant ctags works better with -I
+tags: dummy
+ CTAGSF=`ctags --version | grep -i exuberant >/dev/null && echo "-I __initdata,__initlocaldata,__exitdata,EXPORT_SYMBOL,EXPORT_SYMBOL_NOVERS"`; \
+ ctags $$CTAGSF `find include/asm-$(ARCH) -name '*.h'` && \
+ find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a && \
+ find $(SUBDIRS) init -name '*.c' | xargs ctags $$CTAGSF -a
+
MODFLAGS = -DMODULE
ifdef CONFIG_MODULES
ifdef CONFIG_MODVERSIONS
distclean: mrproper
rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
- -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS
+ -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS tags
backup: mrproper
cd .. && tar cf - linux/ | gzip -9 > backup.gz
#include <asm/hwrpb.h>
#include <asm/processor.h>
-extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
+extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
extern int do_pipe(int *);
-extern struct file_operations *get_blkfops(unsigned int);
-extern struct file_operations *get_chrfops(unsigned int);
-
-extern kdev_t get_unnamed_dev(void);
-extern void put_unnamed_dev(kdev_t);
-
extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);
extern asmlinkage unsigned long sys_brk(unsigned long);
uid_t exroot;
};
-static int getdev(const char *name, int rdonly, struct dentry **dp)
+static struct dentry *getdev(const char *name, int rdonly)
{
- kdev_t dev;
struct dentry *dentry;
struct inode *inode;
- struct file_operations *fops;
int retval;
dentry = namei(name);
retval = PTR_ERR(dentry);
if (IS_ERR(dentry))
- return retval;
+ return dentry;
retval = -ENOTBLK;
inode = dentry->d_inode;
retval = -EACCES;
if (IS_NODEV(inode))
goto out_dput;
-
- retval = -ENXIO;
- dev = inode->i_rdev;
- if (MAJOR(dev) >= MAX_BLKDEV)
- goto out_dput;
-
- retval = -ENODEV;
- fops = get_blkfops(MAJOR(dev));
- if (!fops)
- goto out_dput;
- if (fops->open) {
- struct file dummy;
- memset(&dummy, 0, sizeof(dummy));
- dummy.f_dentry = dentry;
- dummy.f_mode = rdonly ? 1 : 3;
- retval = fops->open(inode, &dummy);
- if (retval)
- goto out_dput;
- }
- *dp = dentry;
- retval = 0;
-out:
- return retval;
+ return dentry;
out_dput:
dput(dentry);
- goto out;
-}
-
-static void putdev(struct dentry *dentry)
-{
- struct file_operations *fops;
-
- fops = get_blkfops(MAJOR(dentry->d_inode->i_rdev));
- if (fops->release)
- fops->release(dentry->d_inode, NULL);
+ return ERR_PTR(retval);
}
/*
* We can't actually handle ufs yet, so we translate UFS mounts to
* ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS
* layout is so braindead it's a major headache doing it.
+ *
+ * Just how long ago was it written? OTOH our UFS driver may be still
+ * unhappy with OSF UFS. [CHECKME]
*/
static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags)
{
if (copy_from_user(&tmp, args, sizeof(tmp)))
goto out;
- retval = getdev(tmp.devname, 0, &dentry);
- if (retval)
+ dentry = getdev(tmp.devname, 0);
+ retval = PTR_ERR(dentry);
+ if (IS_ERR(dentry)
goto out;
- retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname,
+ retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname,
"ext2", flags, NULL);
- if (retval)
- putdev(dentry);
dput(dentry);
out:
return retval;
if (copy_from_user(&tmp, args, sizeof(tmp)))
goto out;
- retval = getdev(tmp.devname, 1, &dentry);
- if (retval)
+ dentry = getdev(tmp.devname, 1);
+ retval = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto out;
- retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname,
+ retval = do_mount(dentry->d_inode->i_bdev, tmp.devname, dirname,
"iso9660", flags, NULL);
- if (retval)
- putdev(dentry);
dput(dentry);
out:
return retval;
static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags)
{
- kdev_t dev;
int retval;
struct procfs_args tmp;
if (copy_from_user(&tmp, args, sizeof(tmp)))
return -EFAULT;
- dev = get_unnamed_dev();
- if (!dev)
- return -ENODEV;
- retval = do_mount(dev, "", dirname, "proc", flags, NULL);
- if (retval)
- put_unnamed_dev(dev);
- return retval;
+ return do_mount(NULL, "", dirname, "proc", flags, NULL);
}
asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data)
struct pci_dev *dev;
/* Iterate through the devices, collecting IRQ levels. */
- for (dev = pci_devices; dev; dev = dev->next) {
+ pci_for_each_dev(dev) {
if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) &&
(dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA))
continue;
{
struct pci_dev *dev;
- for (dev = pci_devices; dev; dev = dev->next) {
+ pci_for_each_dev(dev) {
u16 status;
pci_read_config_word(dev, PCI_STATUS, &status);
struct pci_dev *dev;
int idx;
- for (dev = pci_devices; dev; dev = dev->next)
+ pci_for_each_dev(dev) {
for (idx = 0; idx < PCI_NUM_RESOURCES; idx++)
if (dev->resource[idx].flags &&
dev->resource[idx].start)
pci_claim_resource(dev, idx);
+ }
}
void __init
xorb %bh, %bh
movb (497), %bl # get setup sect from bootsect
subw $4, %bx # LILO loads 4 sectors of setup
- shlw $7, %bx # convert to dwords (1sect=2^7 dwords)
+ shlw $8, %bx # convert to words (1sect=2^8 words)
movw %bx, %cx
- shrw $2, %bx # convert to segment
+ shrw $3, %bx # convert to segment
addw $SYSSEG, %bx
movw %bx, %cs:start_sys_seg
# Move rest of setup code/data to here
source drivers/parport/Config.in
bool 'ACPI support' CONFIG_ACPI
+if [ "$CONFIG_ACPI" != "n" ]; then
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' Enter S1 for sleep' CONFIG_ACPI_S1_SLEEP
+ fi
+fi
+
bool 'Advanced Power Management BIOS support' CONFIG_APM
if [ "$CONFIG_APM" != "n" ]; then
bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/string.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/time.h>
static int acpi_p_lvl2_tested = 0;
static int acpi_p_lvl3_tested = 0;
+static int acpi_disabled = 0;
+int acpi_active = 0;
+
// bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
static unsigned long acpi_slp_typ[] =
{
}
else
{
+#ifdef CONFIG_ACPI_S1_SLEEP
acpi_enter_sx(ACPI_S1);
acpi_enter_sx(ACPI_S0);
+#endif
}
file->f_pos += *len;
return 0;
{
int pid;
+ if (acpi_disabled)
+ return -ENODEV;
+
if (acpi_find_tables() && acpi_find_piix4()) {
// no ACPI tables and not PIIX4
return -ENODEV;
}
/*
- * Are the latencies in uS or in ticks in the tables?
- * Maybe this should do ACPI_uS_TO_TMR_TICKS?
- *
- * Whatever. Internally we always keep them in timer
+ * Internally we always keep latencies in timer
* ticks, which is simpler and more consistent (what is
* an uS to us?). Besides, that gives people more
* control in the /proc interfaces.
*/
if (acpi_facp->p_lvl2_lat
&& acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
- acpi_p_lvl2_lat = acpi_facp->p_lvl2_lat;
- acpi_enter_lvl2_lat = ACPI_TMR_HZ / 1000;
+ acpi_p_lvl2_lat = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl2_lat);
+ acpi_enter_lvl2_lat = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000);
}
if (acpi_facp->p_lvl3_lat
&& acpi_facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
- acpi_p_lvl3_lat = acpi_facp->p_lvl3_lat;
- acpi_enter_lvl3_lat = acpi_facp->p_lvl3_lat * 5;
+ acpi_p_lvl3_lat = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat);
+ acpi_enter_lvl3_lat
+ = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat * 5);
}
if (acpi_facp->sci_int
acpi_power_off = acpi_power_off_handler;
+ acpi_active = 1;
+
/*
* Set up the ACPI idle function. Note that we can't really
* do this with multiple CPU's, we'd need a per-CPU ACPI
acpi_destroy_tables();
}
+static int __init acpi_setup(char *str)
+{
+ while (str && *str) {
+ if (strncmp(str, "off", 3) == 0)
+ acpi_disabled = 1;
+ else if (strncmp(str, "on", 2) == 0)
+ acpi_disabled = 0;
+ str = strpbrk(str, ",");
+ if (str)
+ str += strspn(str, ",");
+ }
+ return 1;
+}
+
+__setup("acpi=", acpi_setup);
+
/*
* Register a device with the ACPI subsystem
*/
APM_INIT_ERROR_RETURN;
}
+#ifdef CONFIG_ACPI
+ if (acpi_active) {
+ printk(KERN_NOTICE "apm: overridden by ACPI.\n");
+ APM_INIT_ERROR_RETURN;
+ }
+#endif
+
/*
* Set up a segment that references the real mode segment 0x40
* that extends up to the end of page zero (that we have reserved).
EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
EXPORT_SYMBOL_NOVERS(__up_wakeup);
+EXPORT_SYMBOL_NOVERS(__down_write_failed);
+EXPORT_SYMBOL_NOVERS(__down_read_failed);
+EXPORT_SYMBOL_NOVERS(__rwsem_wake);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
EXPORT_SYMBOL(csum_partial_copy_generic);
}
spin_unlock_irqrestore(&irq_controller_lock,flags);
+#ifdef __SMP__
/* Wait to make sure it's not being used on another CPU */
while (irq_desc[irq].status & IRQ_INPROGRESS)
barrier();
+#endif
kfree(action);
return;
}
* Hannover, Germany
* hm@ix.de
*
- * Copyright 1997--1999 Martin Mares <mj@suse.cz>
+ * Copyright 1997--2000 Martin Mares <mj@suse.cz>
*
* For more information, please consult the following manuals (look at
* http://www.pcisig.com/ for how to get them):
* as well.
*/
-static void __init pcibios_allocate_bus_resources(struct pci_bus *bus)
+static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
{
+ struct list_head *ln;
+ struct pci_bus *bus;
struct pci_dev *dev;
int idx;
struct resource *r, *pr;
/* Depth-First Search on bus tree */
- while (bus) {
+ for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+ bus = pci_bus_b(ln);
if ((dev = bus->self)) {
for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
r = &dev->resource[idx];
printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
}
}
- if (bus->children)
- pcibios_allocate_bus_resources(bus->children);
- bus = bus->next;
+ pcibios_allocate_bus_resources(&bus->children);
}
}
u16 command;
struct resource *r, *pr;
- for(dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
pci_read_config_word(dev, PCI_COMMAND, &command);
for(idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
int idx;
struct resource *r;
- for(dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
int class = dev->class >> 8;
/* Don't touch classless devices and host bridges */
void __init pcibios_resource_survey(void)
{
- pcibios_allocate_bus_resources(pci_root);
+ DBG("PCI: Allocating resources\n");
+ pcibios_allocate_bus_resources(&pci_root_buses);
pcibios_allocate_resources(0);
pcibios_allocate_resources(1);
pcibios_assign_resources();
/*
* Low-Level PCI Support for PC
*
- * (c) 1999 Martin Mares <mj@suse.cz>
+ * (c) 1999--2000 Martin Mares <mj@suse.cz>
*/
#include <linux/config.h>
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
+static struct pci_bus *pci_root_bus;
+
/*
* IRQ routing table provided by the BIOS
*/
static void __init pcibios_sort(void)
{
- struct pci_dev *dev = pci_devices;
- struct pci_dev **last = &pci_devices;
- struct pci_dev *d, **dd, *e;
- int idx;
+ LIST_HEAD(sorted_devices);
+ struct list_head *ln;
+ struct pci_dev *dev, *d;
+ int idx, found;
unsigned char bus, devfn;
DBG("PCI: Sorting device list...\n");
- while ((e = dev)) {
- idx = 0;
- while (pci_bios_find_device(e->vendor, e->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
+ while (pci_devices.next != &pci_devices) {
+ ln = pci_devices.next;
+ list_del(ln);
+ dev = pci_dev_g(ln);
+ idx = found = 0;
+ while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) {
idx++;
- for(dd=&dev; (d = *dd); dd = &d->next) {
+ for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) {
+ d = pci_dev_g(ln);
if (d->bus->number == bus && d->devfn == devfn) {
- *dd = d->next;
- *last = d;
- last = &d->next;
+ list_del(&d->global_list);
+ list_add_tail(&d->global_list, &sorted_devices);
+ if (d == dev)
+ found = 1;
break;
}
}
- if (!d) {
+ if (ln == &pci_devices) {
printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
/*
* We must not continue scanning as several buggy BIOSes
break;
}
}
- if (e == dev) {
+ if (!found) {
printk("PCI: Device %02x:%02x not found by BIOS\n",
dev->bus->number, dev->devfn);
- d = dev;
- dev = dev->next;
- *last = d;
- last = &d->next;
+ list_del(&dev->global_list);
+ list_add_tail(&dev->global_list, &sorted_devices);
}
}
- *last = NULL;
+ list_splice(&sorted_devices, &pci_devices);
}
/*
static void __init pcibios_fixup_ghosts(struct pci_bus *b)
{
- struct pci_dev *d, *e, **z;
+ struct list_head *ln, *mn;
+ struct pci_dev *d, *e;
int mirror = PCI_DEVFN(16,0);
int seen_host_bridge = 0;
int i;
DBG("PCI: Scanning for ghost devices on bus %d\n", b->number);
- for(d=b->devices; d && d->devfn < mirror; d=d->sibling) {
+ for (ln=b->devices.next; ln != &b->devices; ln=ln->next) {
+ d = pci_dev_b(ln);
if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
seen_host_bridge++;
- for(e=d->next; e; e=e->sibling) {
+ for (mn=ln->next; mn != &b->devices; mn=mn->next) {
+ e = pci_dev_b(mn);
if (e->devfn != d->devfn + mirror ||
e->vendor != d->vendor ||
e->device != d->device ||
continue;
break;
}
- if (!e)
+ if (mn == &b->devices)
return;
}
if (!seen_host_bridge)
return;
printk("PCI: Ignoring ghost devices on bus %02x\n", b->number);
- for(e=b->devices; e->sibling != d; e=e->sibling);
- e->sibling = NULL;
- for(z=&pci_devices; (d=*z);)
- if (d->bus == b && d->devfn >= mirror) {
- *z = d->next;
- kfree_s(d, sizeof(*d));
+
+ ln = &b->devices;
+ while (ln->next != &b->devices) {
+ d = pci_dev_b(ln->next);
+ if (d->devfn >= mirror) {
+ list_del(&d->global_list);
+ list_del(&d->bus_list);
+ kfree(d);
} else
- z = &d->next;
+ ln = ln->next;
+ }
}
/*
*/
static void __init pcibios_fixup_peer_bridges(void)
{
- struct pci_bus *b = pci_root;
+ struct list_head *ln;
+ struct pci_bus *b = pci_root_bus;
int n, cnt=-1;
- struct pci_dev *d;
- struct pci_ops *ops = pci_root->ops;
+ struct pci_ops *ops = pci_root_bus->ops;
#ifdef CONFIG_PCI_DIRECT
/*
return;
#endif
- for(d=b->devices; d; d=d->sibling)
- if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+ DBG("PCI: Peer bridge fixup\n");
+
+ for(ln=b->devices.next; ln != &b->devices; ln=ln->next)
+ if ((pci_dev_b(ln)->class >> 8) == PCI_CLASS_BRIDGE_HOST)
cnt++;
n = b->subordinate + 1;
while (n <= 0xff) {
pci_read_config_byte(d, reg++, &subb);
DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
if (busno)
- pci_scan_bus(busno, pci_root->ops, NULL); /* Bus A */
+ pci_scan_bus(busno, pci_root_bus->ops, NULL); /* Bus A */
if (suba < subb)
- pci_scan_bus(suba+1, pci_root->ops, NULL); /* Bus B */
+ pci_scan_bus(suba+1, pci_root_bus->ops, NULL); /* Bus B */
}
}
u8 busno;
pci_read_config_byte(d, 0x44, &busno);
printk("PCI: RCC host bridge: secondary bus %02x\n", busno);
- pci_scan_bus(busno, pci_root->ops, NULL);
+ pci_scan_bus(busno, pci_root_bus->ops, NULL);
}
static void __init pci_fixup_compaq(struct pci_dev *d)
u8 busno;
pci_read_config_byte(d, 0xc8, &busno);
printk("PCI: Compaq host bridge: secondary bus %02x\n", busno);
- pci_scan_bus(busno, pci_root->ops, NULL);
+ pci_scan_bus(busno, pci_root_bus->ops, NULL);
}
static void __init pci_fixup_umc_ide(struct pci_dev *d)
* It might be a secondary bus, but in this case its parent is already
* known (ascending bus order) and therefore pci_scan_bus returns immediately.
*/
- if (busmap[i] && pci_scan_bus(i, pci_root->ops, NULL))
+ if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL))
printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i);
}
case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0):
case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0):
case ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0):
- case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533):
/* Intel PIIX: PIRQ holds configuration register address */
pci_read_config_byte(router, pirq, &x);
if (x < 16) {
}
DBG(" -> [PIIX] sink\n");
return NULL;
+ case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533):
default:
DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device);
if (newirq && mask == (1 << newirq)) {
struct pci_dev *dev;
u8 pin;
+ DBG("PCI: IRQ fixup\n");
rtable = pirq_table = pcibios_find_irq_routing_table();
#ifdef CONFIG_PCI_BIOS
if (!rtable && pci_bios_present)
if (rtable)
pcibios_irq_peer_trick(rtable);
- for(dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
#if defined(CONFIG_X86_IO_APIC)
/*
}
printk("PCI: Probing PCI hardware\n");
- pci_scan_bus(0, ops, NULL);
+ pci_root_bus = pci_scan_bus(0, ops, NULL);
pcibios_fixup_irqs();
if (pci_probe & PCI_PEER_FIXUP)
/*
* Low-Level PCI Support for SGI Visual Workstation
*
- * (c) 1999 Martin Mares <mj@suse.cz>
+ * (c) 1999--2000 Martin Mares <mj@suse.cz>
*/
#include <linux/config.h>
u8 pin;
int irq;
- for(dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
dev->irq = 0;
if (!pin)
#endif /* !PCI_MODIFY */
-/*
- * Given the vendor and device ids, find the n'th instance of that device
- * in the system.
- */
-
-int pcibios_find_device(unsigned short vendor, unsigned short device_id,
- unsigned short index, unsigned char *bus,
- unsigned char *devfn)
-{
- unsigned int curr = 0;
- struct pci_dev *dev;
-
- for (dev = pci_devices; dev; dev = dev->next)
- {
- if (dev->vendor == vendor && dev->device == device_id)
- {
- if (curr == index)
- {
- *devfn = dev->devfn;
- *bus = dev->bus->number;
- return PCIBIOS_SUCCESSFUL;
- }
- ++curr;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-/*
- * Given the class, find the n'th instance of that device
- * in the system.
- */
-
-int pcibios_find_class(unsigned int class_code, unsigned short index,
- unsigned char *bus, unsigned char *devfn)
-{
- unsigned int curr = 0;
- struct pci_dev *dev;
-
- for (dev = pci_devices; dev; dev = dev->next)
- {
- if (dev->class == class_code)
- {
- if (curr == index)
- {
- *devfn = dev->devfn;
- *bus = dev->bus->number;
- return PCIBIOS_SUCCESSFUL;
- }
- ++curr;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-int pcibios_present(void)
-{
- if (MACH_IS_HADES)
- return 1;
- else
- return 0;
-}
-
void __init pcibios_init(void)
{
printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
* Scan the tree, allocating PCI memory and I/O space.
*/
- layout_bus(&pci_root, orig_mem_base, orig_io_base);
+ layout_bus(pci_bus_b(pci_root.next), orig_mem_base, orig_io_base);
pci_mem_base = orig_mem_base;
pci_io_base = orig_io_base;
{
struct pci_dev *dev;
- for (dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
/*
* TODO: Take care of RM300 revision D boards for where the
* network slot became an ordinary PCI slot.
}
/* PCI interrupts are controlled by the OpenPIC */
- for( dev=pci_devices ; dev; dev=dev->next )
- {
+ pci_for_each_dev(dev) {
if ( dev->irq )
dev->irq = openpic_to_irq( dev->irq );
/* these need to be absolute addrs for OF and Matrox FB -- Cort */
return start;
}
-static void __init pcibios_claim_resources(struct pci_bus *bus)
+static void __init pcibios_claim_resources(struct list_head *bus_list)
{
+ struct list_head *ln, *dn;
+ struct pci_bus *bus;
struct pci_dev *dev;
int idx;
- while (bus)
- {
- for (dev=bus->devices; dev; dev=dev->sibling)
- {
+ for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+ bus = pci_bus_b(ln);
+ for (dn=bus->devices.next; dn != &bus->devices; dn=dn->next) {
+ dev = pci_dev_b(dn);
for (idx = 0; idx < PCI_NUM_RESOURCES; idx++)
{
struct resource *r = &dev->resource[idx];
}
}
}
- if (bus->children)
- pcibios_claim_resources(bus->children);
- bus = bus->next;
+ pcibios_claim_resources(&bus->children);
}
}
* honor the existence of multi-function devices where
* different functions have different interrupt pins. [mj]
*/
- for(dev=pci_devices; dev; dev=dev->next)
+ pci_for_each_dev(dev)
{
/*
* Open Firmware often doesn't initialize the,
printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
if (OpenPIC) {
/* PCI interrupts are controlled by the OpenPIC */
- for(dev=pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
if (dev->bus->number == 0) {
dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq);
return;
}
- for(dev=pci_devices; dev; dev=dev->next)
- {
+ pci_for_each_dev(dev) {
/*
* Use our old hard-coded kludge to figure out what
* irq this device uses. This is necessary on things
};
-extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
+extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
extern dev_t get_unnamed_dev(void);
extern void put_unnamed_dev(dev_t);
extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
char *the_name;
struct nfs_mount_data linux_nfs_mount;
struct sunos_nfs_mount_args *sunos_mount = data;
- dev_t dev;
/* Ok, here comes the fun part: Linux's nfs mount needs a
* socket connection to the server, but SunOS mount does not
linux_nfs_mount.hostname [255] = 0;
putname (the_name);
- dev = get_unnamed_dev ();
-
- ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
- if (ret)
- put_unnamed_dev(dev);
-
- return ret;
+ return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
}
asmlinkage int
char *netname; /* server's netname */
};
-extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
+extern int do_mount(struct block_device *, const char *, const char *, char *, int, void *);
extern dev_t get_unnamed_dev(void);
extern void put_unnamed_dev(dev_t);
extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
char *the_name;
struct nfs_mount_data linux_nfs_mount;
struct sunos_nfs_mount_args *sunos_mount = data;
- dev_t dev;
/* Ok, here comes the fun part: Linux's nfs mount needs a
* socket connection to the server, but SunOS mount does not
linux_nfs_mount.hostname [255] = 0;
putname (the_name);
- dev = get_unnamed_dev ();
-
- ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
- if (ret)
- put_unnamed_dev(dev);
-
- return ret;
+ return do_mount (NULL, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
}
/* XXXXXXXXXXXXXXXXXXXX */
static int fd_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long param)
{
-#define IOCTL_MODE_BIT 8
-#define OPEN_WRITE_BIT 16
-#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
-
int drive, device;
device = inode->i_rdev;
RO_IOCTLS(inode->i_rdev, param);
}
drive = MINOR(device);
- if (!IOCTL_ALLOWED)
- return -EPERM;
switch (cmd) {
case FDFMTBEG:
return 0;
if (old_dev && old_dev != inode->i_rdev)
invalidate_buffers(old_dev);
- /* Allow ioctls if we have write-permissions even if read-only open */
- if (filp->f_mode & 2 || permission(inode, 2) == 0)
- filp->f_mode |= IOCTL_MODE_BIT;
- if (filp->f_mode & 2)
- filp->f_mode |= OPEN_WRITE_BIT;
-
if (filp->f_flags & O_NDELAY)
return 0;
{
int drive;
- drive = inode->i_rdev & 3;
+ drive = MINOR(inode->i_rdev) & 3;
- if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
- /* if the file is mounted OR (writable now AND writable at open
- time) Linus: Does this cover all cases? */
- block_fsync(inode, filp);
+ block_fsync(inode, filp);
if (fd_ref[drive] < 0)
fd_ref[drive] = 0;
unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
{
- struct pci_dev *isa;
unsigned long fixdma_base = dev->resource[4].start;
byte tmpbyte;
unsigned long flags;
pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
- for (isa = pci_devices; isa; isa=isa->next) {
- /*
- * look for ISA bridge
- */
- if (isa->vendor == PCI_VENDOR_ID_AL &&
- isa->device == PCI_DEVICE_ID_AL_M1533) {
- isa_dev = isa;
- break;
- }
- }
+ isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) {
/*
static int fd_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long param)
{
-#define IOCTL_MODE_BIT 8
-#define OPEN_WRITE_BIT 16
-#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
-
int drive, type;
kdev_t device;
struct atari_format_descr fmt_desc;
return -EFAULT;
return 0;
}
- if (!IOCTL_ALLOWED)
- return -EPERM;
switch (cmd) {
case FDSETPRM:
case FDDEFPRM:
if (old_dev && old_dev != MINOR(inode->i_rdev))
invalidate_buffers(MKDEV(FLOPPY_MAJOR, old_dev));
- /* Allow ioctls if we have write-permissions even if read-only open */
- if (filp->f_mode & 2 || permission (inode, 2) == 0)
- filp->f_mode |= IOCTL_MODE_BIT;
- if (filp->f_mode & 2)
- filp->f_mode |= OPEN_WRITE_BIT;
-
if (filp->f_flags & O_NDELAY)
return 0;
drive = MINOR(inode->i_rdev) & 3;
- /*
- * If filp is NULL, we're being called from blkdev_release
- * or after a failed mount attempt. In the former case the
- * device has already been sync'ed, and in the latter no
- * sync is required. Otherwise, sync if filp is writable.
- */
- if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
- block_fsync (filp, filp->f_dentry);
+ block_fsync (filp, filp->f_dentry);
if (fd_ref[drive] < 0)
fd_ref[drive] = 0;
static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long param)
{
-#define IOCTL_MODE_BIT 8
-#define OPEN_WRITE_BIT 16
-#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT))
#define OUT(c,x) case c: outparam = (const char *) (x); break
#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
return -EINVAL;
/* permission checks */
- if (((cmd & 0x40) && !IOCTL_ALLOWED) ||
- ((cmd & 0x80) && !suser()))
+ if ((cmd & 0x80) && !suser())
return -EPERM;
/* copyin */
return fd_copyout((void *)param, outparam, size);
else
return 0;
-#undef IOCTL_ALLOWED
#undef OUT
#undef IN
}
printk("\n");
}
-static ssize_t floppy_read(struct file * filp, char *buf,
- size_t count, loff_t *ppos)
-{
- struct inode *inode = filp->f_dentry->d_inode;
- int drive = DRIVE(inode->i_rdev);
-
- check_disk_change(inode->i_rdev);
- if (UTESTF(FD_DISK_CHANGED))
- return -ENXIO;
- return block_read(filp, buf, count, ppos);
-}
-
-static ssize_t floppy_write(struct file * filp, const char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = filp->f_dentry->d_inode;
- int block;
- int ret;
- int drive = DRIVE(inode->i_rdev);
-
- if (!UDRS->maxblock)
- UDRS->maxblock=1;/* make change detectable */
- check_disk_change(inode->i_rdev);
- if (UTESTF(FD_DISK_CHANGED))
- return -ENXIO;
- if (!UTESTF(FD_DISK_WRITABLE))
- return -EROFS;
- block = (*ppos + count) >> 9;
- INFBOUND(UDRS->maxblock, block);
- ret= block_write(filp, buf, count, ppos);
- return ret;
-}
-
static int floppy_release(struct inode * inode, struct file * filp)
{
int drive;
drive = DRIVE(inode->i_rdev);
- /*
- * If filp is NULL, we're being called from blkdev_release
- * or after a failed mount attempt. In the former case the
- * device has already been sync'ed, and in the latter no
- * sync is required. Otherwise, sync if filp is writable.
- */
- if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
- block_fsync(filp, filp->f_dentry);
+ block_fsync(filp, filp->f_dentry);
if (UDRS->fd_ref < 0)
UDRS->fd_ref=0;
invalidate_buffers(MKDEV(FLOPPY_MAJOR,old_dev));
}
- /* Allow ioctls if we have write-permissions even if read-only open */
- if ((filp->f_mode & 2) || (permission(inode,2) == 0))
- filp->f_mode |= IOCTL_MODE_BIT;
- if (filp->f_mode & 2)
- filp->f_mode |= OPEN_WRITE_BIT;
-
if (UFDCS->rawcmd == 1)
UFDCS->rawcmd = 2;
static struct file_operations floppy_fops = {
NULL, /* lseek - default */
- floppy_read, /* read - general block-dev read */
- floppy_write, /* write - general block-dev write */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
NULL, /* readdir - bad */
NULL, /* poll */
fd_ioctl, /* ioctl */
if (PCI_FUNC(dev->devfn) & 1)
return;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
- for (findev=pci_devices; findev; findev=findev->next) {
+ pci_for_each_dev(findev) {
if ((findev->vendor == dev->vendor) &&
(findev->device == dev->device) &&
((findev->devfn - dev->devfn) == 1) &&
ide_pci_devid_t devid;
ide_pci_device_t *d;
- if (!pci_present())
- return;
- for(dev = pci_devices; dev; dev=dev->next) {
+ pci_for_each_dev(dev) {
devid.vid = dev->vendor;
devid.did = dev->device;
for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
}
if (S_ISBLK(inode->i_mode)) {
- error = blkdev_open(inode, file);
+ /* dentry will be wired, so... */
+ error = blkdev_get(inode->i_bdev, file->f_mode,
+ file->f_flags, BDEV_FILE);
+
lo->lo_device = inode->i_rdev;
lo->lo_flags = 0;
return -EBUSY;
if (S_ISBLK(dentry->d_inode->i_mode))
- blkdev_release (dentry->d_inode);
+ blkdev_put(dentry->d_inode->i_bdev, BDEV_FILE);
+
lo->lo_dentry = NULL;
if (lo->lo_backing_file != NULL) {
static int swim3_add_device(struct device_node *swims);
int swim3_init(void);
-#define IOCTL_MODE_BIT 8
-#define OPEN_WRITE_BIT 16
-
static void swim3_select(struct floppy_state *fs, int sel)
{
volatile struct swim3 *sw = fs->swim3;
if (devnum >= floppy_count)
return -ENODEV;
- if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) ||
- ((cmd & 0x80) && !suser()))
+ if ((cmd & 0x80) && !suser())
return -EPERM;
fs = &floppy_states[devnum];
else
++fs->ref_count;
- /* Allow ioctls if we have write-permissions even if read-only open */
- if ((filp->f_mode & 2) || (permission(inode, 2) == 0))
- filp->f_mode |= IOCTL_MODE_BIT;
- if (filp->f_mode & 2)
- filp->f_mode |= OPEN_WRITE_BIT;
-
return 0;
}
if (devnum >= floppy_count)
return -ENODEV;
- /*
- * If filp is NULL, we're being called from blkdev_release
- * or after a failed mount attempt. In the former case the
- * device has already been sync'ed, and in the latter no
- * sync is required. Otherwise, sync if filp is writable.
- */
- if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
- block_fsync (filp, filp->f_dentry);
+ block_fsync (filp, filp->f_dentry);
fs = &floppy_states[devnum];
sw = fs->swim3;
#define MAX_FLOPPIES 4
-#define IOCTL_MODE_BIT 8
-#define OPEN_WRITE_BIT 16
-
enum swim_state {
idle,
available,
if (devnum >= floppy_count)
return -ENODEV;
- if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) ||
- ((cmd & 0x80) && !suser()))
+ if ((cmd & 0x80) && !suser())
return -EPERM;
fs = &floppy_states[devnum];
else
++fs->ref_count;
- /* Allow ioctls if we have write-permissions even if read-only open */
- if ((filp->f_mode & 2) || (permission(inode, 2) == 0))
- filp->f_mode |= IOCTL_MODE_BIT;
- if (filp->f_mode & 2)
- filp->f_mode |= OPEN_WRITE_BIT;
-
return 0;
}
if (devnum >= floppy_count)
return -ENODEV;
- /*
- * If filp is NULL, we're being called from blkdev_release
- * or after a failed mount attempt. In the former case the
- * device has already been sync'ed, and in the latter no
- * sync is required. Otherwise, sync if filp is writable.
- */
- if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
- block_fsync (filp, filp->f_dentry);
+ block_fsync (filp, filp->f_dentry);
fs = &floppy_states[devnum];
if (fs->ref_count > 0) fs->ref_count--;
* linux/drivers/block/via82cxxx.c Version 0.06 Dec. 13, 1999
*
* Copyright (C) 1998-99 Michel Aubry, Maintainer
- * Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@pobox.com)
+ * Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@mandrakesoft.com)
* Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
*
void agp_frontend_cleanup(void)
{
+ misc_deregister(&agp_miscdev);
return;
}
static int find_bt848(void)
{
- struct pci_dev *dev = pci_devices;
+ struct pci_dev *dev;
int result=0;
bttv_num=0;
- while (dev)
- {
+ pci_for_each_dev(dev) {
if (dev->vendor == PCI_VENDOR_ID_BROOKTREE)
if ((dev->device == PCI_DEVICE_ID_BT848)||
(dev->device == PCI_DEVICE_ID_BT849)||
result=configure_bt848(dev,bttv_num++);
if (result)
return result;
- dev = dev->next;
}
if(bttv_num)
printk(KERN_INFO "bttv: %d Bt8xx card(s) found.\n", bttv_num);
/* Alternative: return sum of all words? */
}
-#if 0 /* May be needed for IPv6 */
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12])
{
#define REKEY_INTERVAL 300
#define HASH_BITS 24
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+__u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr,
+ __u16 sport, __u16 dport)
+{
+ static __u32 rekey_time = 0;
+ static __u32 count = 0;
+ static __u32 secret[12];
+ struct timeval tv;
+ __u32 seq;
+
+ /* The procedure is the same as for IPv4, but addresses are longer. */
+
+ do_gettimeofday(&tv); /* We need the usecs below... */
+
+ if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
+ rekey_time = tv.tv_sec;
+ /* First five words are overwritten below. */
+ get_random_bytes(&secret[5], sizeof(secret)-5*4);
+ count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
+ }
+
+ memcpy(secret, saddr, 16);
+ secret[4]=(sport << 16) + dport;
+
+ seq = (twothirdsMD4Transform(daddr, secret) &
+ ((1<<HASH_BITS)-1)) + count;
+
+ seq += tv.tv_usec + tv.tv_sec*1000000;
+ return seq;
+}
+
+__u32 secure_ipv6_id(__u32 *daddr)
+{
+ static time_t rekey_time = 0;
+ static __u32 secret[12];
+ time_t t;
+
+ /*
+ * Pick a random secret every REKEY_INTERVAL seconds.
+ */
+ t = CURRENT_TIME;
+ if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
+ rekey_time = t;
+ /* First word is overwritten below. */
+ get_random_bytes(secret, sizeof(secret));
+ }
+
+ return twothirdsMD4Transform(daddr, secret);
+}
+
+#endif
+
+
__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
__u16 sport, __u16 dport)
{
return seq;
}
+/* The code below is shamelessly stolen from secure_tcp_sequence_number().
+ * All blames to Andrey V. Savochkin <saw@msu.ru>.
+ */
+__u32 secure_ip_id(__u32 daddr)
+{
+ static time_t rekey_time = 0;
+ static __u32 secret[12];
+ time_t t;
+
+ /*
+ * Pick a random secret every REKEY_INTERVAL seconds.
+ */
+ t = CURRENT_TIME;
+ if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
+ rekey_time = t;
+ /* First word is overwritten below. */
+ get_random_bytes(secret+1, sizeof(secret)-4);
+ }
+
+ /*
+ * Pick a unique starting offset for each IP destination.
+ * Note that the words are placed into the first words to be
+ * mixed in with the halfMD4. This is because the starting
+ * vector is also a random secret (at secret+8), and further
+ * hashing fixed data into it isn't going to improve anything,
+ * so we should get started with the variable data.
+ */
+ secret[0]=daddr;
+
+ return halfMD4Transform(secret+8, secret);
+}
+
#ifdef CONFIG_SYN_COOKIES
/*
* Secure SYN cookie computation. This is the algorithm worked out by
#define dprintk(x...)
-static kdev_t raw_device_bindings[256] = {};
+static struct block_device *raw_device_bindings[256] = {};
static int raw_device_inuse[256] = {};
static int raw_device_sector_size[256] = {};
static int raw_device_sector_bits[256] = {};
-extern struct file_operations * get_blkfops(unsigned int major);
-
static ssize_t rw_raw_dev(int rw, struct file *, char *, size_t, loff_t *);
ssize_t raw_read(struct file *, char *, size_t, loff_t *);
NULL /* fsync */
};
-
-
void __init raw_init(void)
{
register_chrdev(RAW_MAJOR, "raw", &raw_fops);
}
-
-/*
- * The raw IO open and release code needs to fake appropriate
- * open/release calls to the underlying block devices.
- */
-
-static int bdev_open(kdev_t dev, int mode)
-{
- int err = 0;
- struct file dummy_file = {};
- struct dentry dummy_dentry = {};
- struct inode * inode = get_empty_inode();
-
- if (!inode)
- return -ENOMEM;
-
- dummy_file.f_op = get_blkfops(MAJOR(dev));
- if (!dummy_file.f_op) {
- err = -ENODEV;
- goto done;
- }
-
- if (dummy_file.f_op->open) {
- inode->i_rdev = dev;
- dummy_dentry.d_inode = inode;
- dummy_file.f_dentry = &dummy_dentry;
- dummy_file.f_mode = mode;
- err = dummy_file.f_op->open(inode, &dummy_file);
- }
-
- done:
- iput(inode);
- return err;
-}
-
-static int bdev_close(kdev_t dev)
-{
- int err;
- struct inode * inode = get_empty_inode();
-
- if (!inode)
- return -ENOMEM;
-
- inode->i_rdev = dev;
- err = blkdev_release(inode);
- iput(inode);
- return err;
-}
-
-
-
/*
* Open/close code for raw IO.
*/
int raw_open(struct inode *inode, struct file *filp)
{
int minor;
- kdev_t bdev;
+ struct block_device * bdev;
+ kdev_t rdev; /* it should eventually go away */
int err;
int sector_size;
int sector_bits;
*/
bdev = raw_device_bindings[minor];
- if (bdev == NODEV)
+ if (!bdev)
return -ENODEV;
- err = bdev_open(bdev, filp->f_mode);
+ rdev = to_kdev_t(bdev->bd_dev);
+ err = blkdev_get(bdev, filp->f_mode, 0, BDEV_RAW);
if (err)
return err;
*/
sector_size = 512;
- if (lookup_vfsmnt(bdev) != NULL) {
- if (blksize_size[MAJOR(bdev)])
- sector_size = blksize_size[MAJOR(bdev)][MINOR(bdev)];
+ if (lookup_vfsmnt(rdev) != NULL) {
+ if (blksize_size[MAJOR(rdev)])
+ sector_size = blksize_size[MAJOR(rdev)][MINOR(rdev)];
} else {
- if (hardsect_size[MAJOR(bdev)])
- sector_size = hardsect_size[MAJOR(bdev)][MINOR(bdev)];
+ if (hardsect_size[MAJOR(rdev)])
+ sector_size = hardsect_size[MAJOR(rdev)][MINOR(rdev)];
}
- set_blocksize(bdev, sector_size);
+ set_blocksize(rdev, sector_size);
raw_device_sector_size[minor] = sector_size;
for (sector_bits = 0; !(sector_size & 1); )
int raw_release(struct inode *inode, struct file *filp)
{
int minor;
- kdev_t bdev;
+ struct block_device *bdev;
minor = MINOR(inode->i_rdev);
bdev = raw_device_bindings[minor];
- bdev_close(bdev);
+ blkdev_put(bdev, BDEV_RAW);
raw_device_inuse[minor]--;
return 0;
}
err = -EBUSY;
break;
}
+ if (raw_device_bindings[minor])
+ bdput(raw_device_bindings[minor]);
raw_device_bindings[minor] =
- MKDEV(rq.block_major, rq.block_minor);
+ bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor)));
} else {
- rq.block_major = MAJOR(raw_device_bindings[minor]);
- rq.block_minor = MINOR(raw_device_bindings[minor]);
+ kdev_t dev=to_kdev_t(raw_device_bindings[minor]->bd_dev);
+ rq.block_major = MAJOR(dev);
+ rq.block_minor = MINOR(dev);
err = copy_to_user((void *) arg, &rq, sizeof(rq));
}
break;
*/
minor = MINOR(filp->f_dentry->d_inode->i_rdev);
- dev = raw_device_bindings[minor];
+ dev = to_kdev_t(raw_device_bindings[minor]->bd_dev);
sector_size = raw_device_sector_size[minor];
sector_bits = raw_device_sector_bits[minor];
sector_mask = sector_size- 1;
*/
static void probe_serial_pci(void)
{
- u16 subvendor, subdevice;
int k, line;
struct pci_dev *dev = NULL;
struct pci_board *board;
printk(KERN_DEBUG "Entered probe_serial_pci()\n");
#endif
- if (!pcibios_present()) {
-#ifdef SERIAL_DEBUG_PCI
- printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n");
-#endif
- return;
- }
-
- for(dev=pci_devices; dev; dev=dev->next) {
- pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID,
- &subvendor);
- pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subdevice);
-
+ pci_for_each_dev(dev) {
for (board = pci_boards; board->vendor; board++) {
if (board->vendor != (unsigned short) PCI_ANY_ID &&
dev->vendor != board->vendor)
dev->device != board->device)
continue;
if (board->subvendor != (unsigned short) PCI_ANY_ID &&
- subvendor != board->subvendor)
+ dev->subsystem_vendor != board->subvendor)
continue;
if (board->subdevice != (unsigned short) PCI_ANY_ID &&
- subdevice != board->subdevice)
+ dev->subsystem_device != board->subdevice)
continue;
break;
}
int init_stradis_cards(struct video_init *unused)
{
#endif
- struct pci_dev *dev = pci_devices;
+ struct pci_dev *dev = NULL;
int result = 0, i;
- u32 newcard;
saa_num = 0;
- while (dev) {
- if (dev->vendor == PCI_VENDOR_ID_PHILIPS)
- if (dev->device == PCI_DEVICE_ID_PHILIPS_SAA7146) {
- pci_read_config_dword(dev,
- PCI_SUBSYSTEM_VENDOR_ID, &newcard);
- if (!newcard)
- printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num);
- else
- printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num);
- result = configure_saa7146(dev, saa_num++);
- }
+ while ((dev = pci_find_device(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, dev))) {
+ if (!dev->subsystem_vendor_id)
+ printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num);
+ else
+ printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num);
+ result = configure_saa7146(dev, saa_num++);
if (result)
return result;
- dev = dev->next;
}
if (saa_num)
printk(KERN_INFO "stradis: %d card(s) found.\n", saa_num);
int count=0;
printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
-
- for(dev=pci_devices; dev!=NULL; dev=dev->next)
- {
+
+ pci_for_each_dev(dev) {
if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O)
continue;
if((dev->class&0xFF)>1)
struct pci_save *ps;
npci = 0;
- for (pd = pci_devices; pd != NULL; pd = pd->next)
+ pci_for_each_dev(pd) {
++npci;
+ }
n_pbook_pci_saves = npci;
if (npci == 0)
return;
if (ps == NULL)
return;
- for (pd = pci_devices; pd != NULL && npci != 0; pd = pd->next) {
+ pci_for_each_dev(pd) {
pci_read_config_word(pd, PCI_COMMAND, &ps->command);
pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address);
++ps;
- --npci;
}
}
pbook_pci_restore(void)
{
u16 cmd;
- struct pci_save *ps = pbook_pci_saves;
+ struct pci_save *ps = pbook_pci_saves - 1;
struct pci_dev *pd;
int j;
- for (pd = pci_devices; pd != NULL; pd = pd->next, ++ps) {
+ pci_for_each_dev(pd) {
+ ps++;
if (ps->command == 0)
continue;
pci_read_config_word(pd, PCI_COMMAND, &cmd);
* eg ifconfig
*/
int i;
- dev_link_t *link = dev_list;
- struct net_device *dev = (struct net_device *)link->priv;
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ dev_link_t *link;
+ struct net_device *dev;
+ ray_dev_t *local;
UCHAR *p;
struct freq_hop_element *pfh;
UCHAR c[33];
+ link = dev_list;
+ if (!link)
+ return 0;
+ dev = (struct net_device *)link->priv;
+ if (!dev)
+ return 0;
+ local = (ray_dev_t *)dev->priv;
+ if (!local)
+ return 0;
+
len = 0;
len += sprintf(buf + len, "Raylink Wireless LAN driver status\n");
}
return 0;
} /* End build_auth_frame */
+
/*===========================================================================*/
+
+static void raycs_write(const char *name, write_proc_t *w, void *data)
+{
+ struct proc_dir_entry * entry = create_proc_entry(name, S_IFREG | S_IWUSR, NULL);
+ if (entry) {
+ entry->write_proc = w;
+ entry->data = data;
+ }
+}
+
+static int write_essid(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ static char proc_essid[33];
+ int len = count;
+
+ if (len > 32)
+ len = 32;
+ memset(proc_essid, 0, 33);
+ if (copy_from_user(proc_essid, buffer, len))
+ return -EFAULT;
+ essid = proc_essid;
+ return count;
+}
+
+static int write_int(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ static char proc_number[10];
+ char *p;
+ int nr, len;
+
+ if (!count)
+ return 0;
+
+ if (count > 9)
+ return -EINVAL;
+ if (copy_from_user(proc_number, buffer, count))
+ return -EFAULT;
+ p = proc_number;
+ nr = 0;
+ len = count;
+ do {
+ unsigned int c = *p - '0';
+ if (c > 9)
+ return -EINVAL;
+ nr = nr*10 + c;
+ p++;
+ } while (--len);
+ *(int *)data = nr;
+ return count;
+}
+
static int __init init_ray_cs(void)
{
int rc;
DEBUG(1, "%s\n", rcsid);
rc = register_pcmcia_driver(&dev_info, &ray_attach, &ray_detach);
DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc);
-#ifdef CONFIG_PROC_FS
- /* [proc-namespace][fixme] It shouldn't be under root, damnit! */
- create_proc_info_entry("ray_cs", 0, &proc_root, ray_cs_proc_read);
-#endif
+
+ proc_mkdir("driver/ray_cs", 0);
+
+ create_proc_info_entry("driver/ray_cs/ray_cs", 0, NULL, ray_cs_proc_read);
+ raycs_write("driver/ray_cs/essid", write_essid, NULL);
+ raycs_write("driver/ray_cs/net_type", write_int, &net_type);
+ raycs_write("driver/ray_cs/translate", write_int, &translate);
if (translate != 0) translate = 1;
return 0;
} /* init_ray_cs */
-#ifndef MODULE
-
-static char init_ess_id[ESSID_SIZE];
-static int __init essid_setup(char *str)
-{
- strncpy(init_ess_id, str, ESSID_SIZE);
- essid = init_ess_id;
- return 1;
-}
-__setup("essid=", essid_setup);
-
-#endif
-
/*===========================================================================*/
static void __exit exit_ray_cs(void)
{
DEBUG(0, "ray_cs: cleanup_module\n");
+
+ remove_proc_entry("ray_cs", proc_root_driver);
unregister_pcmcia_driver(&dev_info);
while (dev_list != NULL) {
if (dev_list->state & DEV_CONFIG) ray_release((u_long)dev_list);
ray_detach(dev_list);
}
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("ray_cs", &proc_root);
-#endif
+ remove_proc_entry("driver/ray_cs/ray_cs", NULL);
+ remove_proc_entry("driver/ray_cs/essid", NULL);
+ remove_proc_entry("driver/ray_cs/net_type", NULL);
+ remove_proc_entry("driver/ray_cs/translate", NULL);
+ remove_proc_entry("driver/ray_cs", NULL);
} /* exit_ray_cs */
module_init(init_ray_cs);
if (*devp) {
struct net_device *dev = *devp;
struct tulip_private *tp = dev->priv;
+ *devp = *next;
unregister_netdev(dev);
kfree(dev);
kfree(tp);
- *devp = *next;
kfree(node);
MOD_DEC_USE_COUNT;
}
}
/* Look for parallel controllers that we don't know about. */
- for (pcidev = pci_devices; pcidev; pcidev = pcidev->next) {
+ pci_for_each_dev(pcidev) {
const int class_noprogif = pcidev->class & ~0xff;
if (class_noprogif != (PCI_CLASS_COMMUNICATION_PARALLEL << 8))
continue;
*
* PCI Bus Services -- Function For Backward Compatibility
*
- * Copyright 1998, 1999 Martin Mares <mj@suse.cz>
+ * Copyright 1998--2000 Martin Mares <mj@suse.cz>
*/
#include <linux/types.h>
int
pcibios_present(void)
{
- return !!pci_devices;
+ return pci_devices.next != &pci_devices;
}
int
*
* drivers/pci/helper.c
*
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
* This software is free. See the file COPYING for licensing details.
*
*/
* Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
* David Mosberger-Tang
*
- * Copyright 1997 -- 1999 Martin Mares <mj@suse.cz>
+ * Copyright 1997 -- 2000 Martin Mares <mj@suse.cz>
*/
#include <linux/types.h>
#define DBG(x...)
#endif
-struct pci_bus *pci_root;
-struct pci_dev *pci_devices = NULL;
-static struct pci_dev **pci_last_dev_p = &pci_devices;
+LIST_HEAD(pci_root_buses);
+LIST_HEAD(pci_devices);
struct pci_dev *
pci_find_slot(unsigned int bus, unsigned int devfn)
{
struct pci_dev *dev;
- for(dev=pci_devices; dev; dev=dev->next)
+ pci_for_each_dev(dev) {
if (dev->bus->number == bus && dev->devfn == devfn)
- break;
- return dev;
+ return dev;
+ }
+ return NULL;
}
unsigned int ss_vendor, unsigned int ss_device,
struct pci_dev *from)
{
- struct pci_dev *dev;
+ struct list_head *n = from ? from->global_list.next : pci_devices.next;
- if (from)
- dev = from->next;
- else
- dev = pci_devices;
-
- while (dev) {
+ while (n != &pci_devices) {
+ struct pci_dev *dev = pci_dev_g(n);
if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
(device == PCI_ANY_ID || dev->device == device) &&
(ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
(ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
return dev;
- dev = dev->next;
+ n = n->next;
}
return NULL;
}
struct pci_dev *
pci_find_class(unsigned int class, struct pci_dev *from)
{
- if (!from)
- from = pci_devices;
- else
- from = from->next;
- while (from && from->class != class)
- from = from->next;
- return from;
+ struct list_head *n = from ? from->global_list.next : pci_devices.next;
+
+ while (n != &pci_devices) {
+ struct pci_dev *dev = pci_dev_g(n);
+ if (dev->class == class)
+ return dev;
+ n = n->next;
+ }
+ return NULL;
}
}
}
+static struct pci_bus * __init pci_alloc_bus(void)
+{
+ struct pci_bus *b;
+
+ b = kmalloc(sizeof(*b), GFP_KERNEL);
+ if (b) {
+ memset(b, 0, sizeof(*b));
+ INIT_LIST_HEAD(&b->children);
+ INIT_LIST_HEAD(&b->devices);
+ }
+ return b;
+}
+
static struct pci_bus * __init pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
{
struct pci_bus *child;
/*
* Allocate a new bus, and inherit stuff from the parent..
*/
- child = kmalloc(sizeof(*child), GFP_KERNEL);
- memset(child, 0, sizeof(*child));
+ child = pci_alloc_bus();
- child->next = parent->children;
- parent->children = child;
+ list_add_tail(&child->node, &parent->children);
child->self = dev;
dev->subordinate = child;
child->parent = parent;
/*
* Insert it into the tree of buses.
*/
+ DBG("Scanning CardBus bridge %s\n", dev->slot_name);
child = pci_add_new_bus(bus, dev, ++busnr);
for (i = 0; i < 4; i++)
/*
* Insert it into the tree of buses.
*/
+ DBG("Scanning behind PCI bridge %s\n", dev->slot_name);
child = pci_add_new_bus(bus, dev, ++max);
sprintf(child->name, "PCI Bus #%02x", child->number);
dev->class = class;
class >>= 8;
+ DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);
+
switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
if (class == PCI_CLASS_BRIDGE_PCI)
first_dev = dev;
}
- DBG("PCI: %02x:%02x [%04x/%04x] %06x %02x\n", bus->number, dev->devfn, dev->vendor, dev->device, dev->class, hdr_type);
-
- /*
- * Put it into the global PCI device chain. It's used to
- * find devices once everything is set up.
- */
- *pci_last_dev_p = dev;
- pci_last_dev_p = &dev->next;
-
/*
- * Now insert it into the list of devices held
- * by the parent bus.
+ * Link the device to both the global PCI device chain and
+ * the per-bus list of devices.
*/
- *bus->last_dev_p = dev;
- bus->last_dev_p = &dev->sibling;
+ list_add_tail(&dev->global_list, &pci_devices);
+ list_add_tail(&dev->bus_list, &bus->devices);
/* Fix up broken headers */
pci_fixup_device(PCI_FIXUP_HEADER, dev);
static unsigned int __init pci_do_scan_bus(struct pci_bus *bus)
{
unsigned int devfn, max;
+ struct list_head *ln;
struct pci_dev *dev, dev0;
- DBG("pci_do_scan_bus for bus %d\n", bus->number);
- bus->last_dev_p = &bus->devices;
+ DBG("Scanning bus %02x\n", bus->number);
max = bus->secondary;
/* Create a device template */
* After performing arch-dependent fixup of the bus, look behind
* all PCI-to-PCI bridges on this bus.
*/
+ DBG("Fixups for bus %02x\n", bus->number);
pcibios_fixup_bus(bus);
- for (dev = bus->devices; dev; dev = dev->sibling) {
+ for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+ dev = pci_dev_b(ln);
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
max = pci_scan_bridge(bus, dev, max);
*
* Return how far we've got finding sub-buses.
*/
- DBG("PCI: pci_do_scan_bus returning with max=%02x\n", max);
+ DBG("Bus scan for %02x returning with max=%02x\n", bus->number, max);
return max;
}
-static int __init pci_bus_exists(struct pci_bus *b, int nr)
+static int __init pci_bus_exists(struct list_head *list, int nr)
{
- while (b) {
- if (b->number == nr)
- return 1;
- if (b->children && pci_bus_exists(b->children, nr))
+ struct list_head *l;
+
+ for(l=list->next; l != list; l = l->next) {
+ struct pci_bus *b = pci_bus_b(l);
+ if (b->number == nr || pci_bus_exists(&b->children, nr))
return 1;
- b = b->next;
}
return 0;
}
struct pci_bus * __init pci_alloc_primary_bus(int bus)
{
- struct pci_bus *b, **r;
+ struct pci_bus *b;
- if (pci_bus_exists(pci_root, bus)) {
+ if (pci_bus_exists(&pci_root_buses, bus)) {
/* If we already got to this bus through a different bridge, ignore it */
DBG("PCI: Bus %02x already known\n", bus);
return NULL;
}
- b = kmalloc(sizeof(*b), GFP_KERNEL);
- memset(b, 0, sizeof(*b));
-
- /* Put the new bus at the end of the chain of busses. */
- r = &pci_root;
- while (*r)
- r = &(*r)->next;
- *r = b;
+ b = pci_alloc_bus();
+ list_add_tail(&b->node, &pci_root_buses);
b->number = b->secondary = bus;
b->resource[0] = &ioport_resource;
pcibios_init();
- for(dev=pci_devices; dev; dev=dev->next)
+ pci_for_each_dev(dev) {
pci_fixup_device(PCI_FIXUP_FINAL, dev);
+ }
}
static int __init pci_setup(char *str)
# Maintained by Martin Mares <pci-ids@ucw.cz>
# If you have any new entries, send them to the maintainer.
#
-# $Id: pci.ids,v 1.43 1999/12/04 12:32:55 mj Exp $
+# $Id: pci.ids,v 1.46 2000/01/02 20:32:11 mj Exp $
#
# Vendors, devices and subsystems. Please keep sorted.
0002 PT80C524 [Nile]
0005 National PC87550 System Controller
8002 PT80C524 [Nile]
-1067 Mitsubishi Electronics
+1067 Mitsubishi Electric
+ 1002 VG500 [VolumePro Volume Rendering Accelerator]
1068 Diversified Technology
1069 Mylex Corporation
0001 DAC960P
0010 VME Bridge Model 618
3000 VME Bridge Model 2706
108c Oakleigh Systems Inc.
-108d Olicom
- 0001 OC-3136/3137
+108d Olicom
+ 0001 Token-Ring 16/4 PCI Adapter (3136/3137)
0002 16/4 Token Ring
- 0004 OC-3139/3140 RapidFire Token-Ring 16/4
- 0005 OC-3250 GoCard Token-Ring 16/4
+ 0004 RapidFire 3139 Token-Ring 16/4 PCI Adapter
+ 0005 GoCard 3250 Token-Ring 16/4 CardBus PC Card
0006 OC-3530 RapidFire Token-Ring 100
- 0007 OC-3141 RapidFire Token-Ring 16/4
+ 0007 RapidFire 3141 Token-Ring 16/4 PCI Fiber Adapter
+ 0008 RapidFire 3540 HSTR 100/16/4 PCI Adapter
0011 OC-2315
0012 OC-2325
0013 OC-2183/2185
9080 9080
10b5 9080 9080 [real subsystem ID not set]
10b6 Madge Networks
- 0001 Smart 16/4 Ringnode
- 0002 Smart 16/4 BM Mk2 Ringnode
- 0003 Smart 16/4 Ringnode
- 0e11 b0fd NC4621 4/16 Token-Ring Adapter + WOL
- 10b6 0003 Smart 16/4 Ringnode Mk3
- 10b6 0007 Presto Mk2
- 0004 Smart 16/4 Ringnode (BM)
+ 0001 Smart 16/4 PCI Ringnode
+ 0002 Smart 16/4 PCI Ringnode Mk2
+ 10b6 0002 Smart 16/4 PCI Ringnode Mk2
+ 10b6 0006 16/4 CardBus Adapter
+ 0003 Smart 16/4 PCI Ringnode Mk3
+ 0e11 b0fd Compaq NC4621 PCI, 4/16, WOL
+ 10b6 0003 Smart 16/4 PCI Ringnode Mk3
+ 10b6 0007 Presto PCI Plus Adapter
+ 0004 Smart 16/4 PCI Ringnode Mk1
0006 16/4 Cardbus Adapter
- 0007 Presto
- 1000 Collage 25 ATM adaptor
- 1001 Collage 155 Server
+ 10b6 0006 16/4 CardBus Adapter
+ 0007 Presto PCI Adapter
+ 0009 Smart 100/16/4 PCI-HS Ringnode
+ 000a Smart 100/16/4 PCI Ringnode
+ 000b 16/4 CardBus Adapter Mk2
+ 1000 Collage 25 ATM Adapter
+ 1001 Collage 155 ATM Server Adapter
10b7 3Com Corporation
0001 3c985 1000BaseSX
3390 Token Link Velocity
8888 Cinemaster C 3.0 DVD Decoder
1240 Marathon Technologies Corp.
1241 DSC Communications
+1242 Jaycor Networks, Inc.
+ 4643 FCI-1063 Fibre Channel Adapter
1243 Delphax
1244 AVM Audiovisuelles MKTG & Computer System GmbH
0700 B1 ISDN
12c4 Connect Tech Inc
12c5 Picture Elements Incorporated
0081 PCIVST [Grayscale Thresholding Engine]
- 0086 THR2 Thresholder
+ 0085 Video Simulator/Sender
+ 0086 THR2 Multi-scale Thresholder
12c6 Mitani Corporation
12c7 Dialogic Corp
12c8 G Force Co, Ltd
0e11 b123 NC1634 Gigabit Ethernet Adapter
1014 0119 Netfinity Gigabit Ethernet SX Adapter
8086 1000 EtherExpress PRO/1000 Gigabit Server Adapter
+ 1030 82559 InBusiness 10/100
1209 82559ER
1221 82092AA_0
1222 82092AA_1
EXPORT_SYMBOL(pci_write_config_word);
EXPORT_SYMBOL(pci_write_config_dword);
EXPORT_SYMBOL(pci_devices);
-EXPORT_SYMBOL(pci_root);
+EXPORT_SYMBOL(pci_root_buses);
EXPORT_SYMBOL(pci_enable_device);
EXPORT_SYMBOL(pci_find_class);
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_simple_probe);
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_assign_resource);
+EXPORT_SYMBOL(pci_setup_device);
#ifdef CONFIG_PROC_FS
EXPORT_SYMBOL(pci_proc_attach_device);
EXPORT_SYMBOL(pci_proc_detach_device);
static int
get_pci_dev_info(char *buf, char **start, off_t pos, int count)
{
- struct pci_dev *dev = pci_devices;
+ struct pci_dev *dev;
off_t at = 0;
int len, i, cnt;
cnt = 0;
- while (dev && count > cnt) {
+ pci_for_each_dev(dev) {
len = sprintf(buf, "%02x%02x\t%04x%04x\t%x",
dev->bus->number,
dev->devfn,
cnt += len;
buf += len;
}
- dev = dev->next;
}
return (count > cnt) ? cnt : count;
}
return 0;
}
-void __init proc_bus_pci_add(struct pci_bus *bus)
-{
- while (bus) {
- struct pci_dev *dev;
-
- for(dev = bus->devices; dev; dev = dev->sibling)
- pci_proc_attach_device(dev);
- if (bus->children)
- proc_bus_pci_add(bus->children);
- bus = bus->next;
- }
-}
/*
* Backward compatible /proc/pci interface.
int nprinted, len, begin = 0;
struct pci_dev *dev;
- len = sprintf(buf, "PCI devices found:\n");
+ len = sprintf(buf, "PCI devices found:\n");
- for (dev = pci_devices; dev; dev = dev->next) {
+ *eof = 1;
+ pci_for_each_dev(dev) {
nprinted = sprint_dev_config(dev, buf + len, count - len);
- if (nprinted < 0)
+ if (nprinted < 0) {
+ *eof = 0;
break;
+ }
len += nprinted;
if (len+begin < off) {
begin += len;
if (len+begin >= off+count)
break;
}
- if (!dev || len+begin < off)
- *eof = 1;
off -= begin;
*start = buf + off;
len -= off;
static int __init pci_proc_init(void)
{
if (pci_present()) {
+ struct pci_dev *dev;
proc_bus_pci_dir = proc_mkdir("pci", proc_bus);
create_proc_info_entry("devices", 0, proc_bus_pci_dir,
get_pci_dev_info);
- proc_bus_pci_add(pci_root);
+ pci_for_each_dev(dev) {
+ pci_proc_attach_device(dev);
+ }
create_proc_read_entry("pci", 0, NULL, pci_read_proc, NULL);
}
return 0;
pci_assign_unassigned_resources(u32 min_io, u32 min_mem)
{
struct pci_dev *dev;
- for (dev = pci_devices; dev; dev = dev->next)
+
+ pci_for_each_dev(dev) {
pdev_assign_unassigned_resources(dev, min_io, min_mem);
+ }
}
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
struct pbus_set_ranges_data inner;
struct pci_bus *child;
struct pci_dev *dev;
+ struct list_node *ln;
inner.found_vga = 0;
inner.mem_start = inner.io_start = ~0UL;
inner.mem_end = inner.io_end = 0;
/* Collect information about how our direct children are layed out. */
- for (dev = bus->devices; dev; dev = dev->sibling) {
+ for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
int i;
+ dev = pci_dev_b(ln);
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *res = &dev->resource[i];
if (res->flags & IORESOURCE_IO) {
}
/* And for all of the sub-busses. */
- for (child = bus->children; child; child = child->next)
- pbus_set_ranges(child, &inner);
+ for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
+ pbus_set_ranges(pci_bus_b(ln), &inner);
/* Align the values. */
inner.io_start = ROUND_DOWN(inner.io_start, 4*1024);
void __init
pci_set_bus_ranges(void)
{
- struct pci_bus *bus;
- for (bus = pci_root; bus; bus = bus->next)
- pbus_set_ranges(bus, NULL);
+ struct list_node *ln;
+
+ for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next)
+ pci_set_ranges(pci_bus_b(ln), NULL);
}
static void __init
int (*map_irq)(struct pci_dev *, u8, u8))
{
struct pci_dev *dev;
- for (dev = pci_devices; dev; dev = dev->next)
+ pci_for_each_dev(dev) {
pdev_fixup_irq(dev, swizzle, map_irq);
+ }
}
int
bus = s->cap.cb_dev->subordinate;
memset(&tmp, 0, sizeof(tmp));
tmp.bus = bus;
+ tmp.sysdata = bus->sysdata;
tmp.devfn = 0;
- printk("bus=%p, number=%d\n", bus, bus->number);
pci_readw(&tmp, PCI_VENDOR_ID, &vend);
pci_readw(&tmp, PCI_DEVICE_ID, &dev);
if (hdr & 0x80) {
do {
tmp.devfn = fn;
- pci_readw(&tmp, PCI_VENDOR_ID, &v);
- if (v != vend)
+ if (pci_readw(&tmp, PCI_VENDOR_ID, &v) || !v || v == 0xffff)
break;
fn++;
} while (fn < 8);
int r;
dev->bus = bus;
+ dev->sysdata = bus->sysdata;
dev->devfn = i;
- if (i < fn - 1) {
- dev->sibling = dev->next = &c[i + 1].dev;
- }
dev->vendor = vend;
pci_readw(dev, PCI_DEVICE_ID, &dev->device);
dev->hdr_type = hdr;
pci_setup_device(dev);
+ /* FIXME: Do we need to enable the expansion ROM? */
for (r = 0; r < 7; r++) {
struct resource *res = dev->resource + r;
if (res->flags) {
res->end,
res->flags);
}
- pci_enable_device(dev);
+ list_add_tail(&dev->bus_list, &bus->devices);
+ list_add_tail(&dev->global_list, &pci_devices);
#ifdef CONFIG_PROC_FS
pci_proc_attach_device(dev);
#endif
+
+ pci_enable_device(dev);
}
- /* Link into PCI device chain */
- bus->devices = &c[0].dev;
- c[fn - 1].dev.next = pci_devices;
- pci_devices = &c[0].dev;
s->cb_config = c;
-
return CS_SUCCESS;
}
void cb_free(socket_info_t * s)
{
cb_config_t *c = s->cb_config;
- struct pci_bus *bus = s->cap.cb_dev->subordinate;
+ int i;
if (c) {
- struct pci_dev **p;
- /* Unlink from PCI device chain */
- p = &pci_devices;
- while (*p) {
- struct pci_dev *dev = *p;
- if (dev->bus != bus) {
- p = &dev->next;
- continue;
- }
- *p = dev->next;
+ for(i=0; i<s->functions; i++) {
+ struct pci_dev *dev = &c[i].dev;
+ list_del(&dev->bus_list);
+ list_del(&dev->global_list);
free_resources(dev);
#ifdef CONFIG_PROC_FS
pci_proc_detach_device(dev);
#endif
}
- bus->devices = NULL;
kfree(s->cb_config);
s->cb_config = NULL;
printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cb_dev->subordinate->number);
/* Are we set up to route the IO irq to the PCI irq? */
bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL);
- if (!(bridge_ctrl & CB_BRIDGE_INTR)) {
- socket->io_irq = socket->cb_irq;
- if (socket->cb_irq && socket->cb_irq < 16)
- return 1 << socket->cb_irq;
+ if (socket->cb_irq) {
+ if (bridge_ctrl & CB_BRIDGE_INTR) {
+ bridge_ctrl &= ~CB_BRIDGE_INTR;
+ config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
+ }
+ printk("CardBus: using PCI interrupt %d\n", socket->cb_irq);
+ return 1 << socket->cb_irq;
+ }
- /* Uhhuh. Try falling back on ISA interrupts */
- printk("CardBus: Hmm.. Bad PCI irq routing (irq%d)\n", socket->cb_irq);
+ /* Uhhuh. No PCI interrupt: try falling back on ISA interrupts */
+ printk("CardBus: Hmm.. No PCI irq routing (irq%d).\n", socket->cb_irq);
+ if (!(bridge_ctrl & CB_BRIDGE_INTR)) {
bridge_ctrl |= CB_BRIDGE_INTR;
config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl);
}
offset = 0x1c + 8*nr;
bus = socket->dev->subordinate;
res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr;
- printk("dev=%p, bus=%p, parent=%p\n", socket->dev, bus, socket->dev->bus);
- printk("res = %p, bus->res = %p\n", res, bus->resource[nr]);
res->name = bus->name;
res->flags = type;
res->start = 0;
#include <asm/uaccess.h>
#include <linux/isapnp.h>
+LIST_HEAD(isapnp_cards);
+LIST_HEAD(isapnp_devices);
+
#ifdef CONFIG_PROC_FS
#include "isapnp_proc.c"
#endif
#define _LTAG_MEM32RANGE 0x85
#define _LTAG_FIXEDMEM32RANGE 0x86
-struct pci_bus *isapnp_cards = NULL; /* ISA PnP cards */
-struct pci_dev *isapnp_devices = NULL; /* ISA PnP devices */
-static struct pci_dev *isapnp_last_device = NULL;
static unsigned char isapnp_checksum_value;
static DECLARE_MUTEX(isapnp_cfg_mutex);
static int isapnp_detected = 0;
{
int number = 0, skip = 0, dependent = 0, compat = 0;
unsigned char type, tmp[17];
- struct pci_dev *dev, *prev_dev;
+ struct pci_dev *dev;
struct isapnp_resources *res = NULL;
if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
return 1;
- card->devices = dev;
- if (isapnp_last_device) {
- isapnp_last_device->next = dev;
- isapnp_last_device = dev;
- } else {
- isapnp_devices = isapnp_last_device = dev;
- }
+ list_add(&dev->bus_list, &card->devices);
+ list_add_tail(&dev->global_list, &isapnp_devices);
while (1) {
if (isapnp_read_tag(&type, &size)<0)
return 1;
switch (type) {
case _STAG_LOGDEVID:
if (size >= 5 && size <= 6) {
- prev_dev = dev;
isapnp_config_prepare(dev);
if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
return 1;
- prev_dev->sibling = dev;
- isapnp_last_device->next = dev;
- isapnp_last_device = dev;
+ list_add_tail(&dev->bus_list, &card->devices);
+ list_add_tail(&dev->global_list, &isapnp_devices);
size = 0;
skip = 0;
} else {
{
int csn;
unsigned char header[9], checksum;
- struct pci_bus *card, *prev = NULL;
+ struct pci_bus *card;
isapnp_wait();
isapnp_key();
if (isapnp_checksum_value != 0x00)
printk("isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value);
card->checksum = isapnp_checksum_value;
- if (!isapnp_cards)
- isapnp_cards = card;
- else
- prev->next = card;
- prev = card;
+
+ list_add_tail(&card->node, &isapnp_cards);
}
return 0;
}
int isapnp_present(void)
{
- if (isapnp_devices)
- return 1;
- return 0;
+ return !list_empty(&isapnp_devices);
}
int isapnp_cfg_begin(int csn, int logdev)
unsigned short device,
struct pci_bus *from)
{
- struct pci_bus *card;
+ struct list_head *list;
- if (from == NULL) {
- from = isapnp_cards;
- } else {
- from = from->next;
- }
- for (card = from; card; card = card->next) {
+ list = isapnp_cards.next;
+ if (from)
+ list = from->node.next;
+
+ while (list != &isapnp_cards) {
+ struct pci_bus *card = list_entry(list, struct pci_bus, node);
if (card->vendor == vendor && card->device == device)
return card;
+ list = list->next;
}
return NULL;
}
unsigned short function,
struct pci_dev *from)
{
- struct pci_dev *dev;
- int idx;
-
if (card == NULL) { /* look for a logical device from all cards */
- if (from == NULL) {
- from = isapnp_devices;
- } else {
- from = from->next;
- }
- for (dev = from; dev; dev = dev->next) {
+ struct list_head *list;
+
+ list = isapnp_devices.next;
+ if (from)
+ list = from->global_list.next;
+
+ while (list != &isapnp_devices) {
+ int idx;
+ struct pci_dev *dev = list_entry(list, struct pci_dev, global_list);
+
if (dev->vendor == vendor && dev->device == function)
return dev;
for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++)
if (dev->vendor_compatible[idx] == vendor &&
dev->device_compatible[idx] == function)
return dev;
+ list = list->next;
}
} else {
- if (from == NULL) {
- from = card->devices;
- } else {
- from = from->next;
- }
+ struct list_head *list;
+
+ list = card->devices.next;
+ if (from)
+ list = from->bus_list.next;
if (from->bus != card) /* something is wrong */
return NULL;
- for (dev = from; dev; dev = dev->sibling) {
+ while (list != &card->devices) {
+ int idx;
+ struct pci_dev *dev = list_entry(list, struct pci_dev, bus_list);
+
if (dev->vendor == vendor && dev->device == function)
return dev;
for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++)
if (dev->vendor_compatible[idx] == vendor &&
dev->device_compatible[idx] == function)
return dev;
- }
+ list = list->next;
+ }
}
return NULL;
}
{
int i, tmp, rport, rsize;
struct isapnp_port *xport;
- struct pci_dev *dev;
+ struct list_head *list;
if (check_region(port, size))
return 1;
if (port + size > rport && port + size < (rport + rsize) - 1)
return 1;
}
- for (dev = isapnp_devices; dev; dev = dev->next) {
+
+ for (list = isapnp_devices.next; list != &isapnp_devices ; list = list->next) {
+ struct pci_dev *dev = list_entry(list, struct pci_dev, global_list);
if (dev->active) {
for (tmp = 0; tmp < 8; tmp++) {
if (dev->resource[tmp].flags) {
static int isapnp_check_interrupt(struct isapnp_cfgtmp *cfg, int irq, int idx)
{
int i;
- struct pci_dev *dev;
+ struct list_head *list;
if (irq < 0 || irq > 15)
return 1;
if (isapnp_reserve_irq[i] == irq)
return 1;
}
- for (dev = isapnp_devices; dev; dev = dev->next) {
+ for (list = isapnp_devices.next; list != &isapnp_devices; list = list->next) {
+ struct pci_dev *dev = list_entry(list, struct pci_dev, global_list);
if (dev->active) {
if (dev->irq_resource[0].start == irq ||
dev->irq_resource[1].start == irq)
static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx)
{
int i;
- struct pci_dev *dev;
+ struct list_head *list;
if (dma < 0 || dma == 4 || dma > 7)
return 1;
if (isapnp_reserve_dma[i] == dma)
return 1;
}
- for (dev = isapnp_devices; dev; dev = dev->next) {
+ for (list = isapnp_devices.next; list != &isapnp_devices ; list = list->next) {
+ struct pci_dev *dev = list_entry(list, struct pci_dev, global_list);
if (dev->active) {
if (dev->dma_resource[0].start == dma || dev->dma_resource[1].start == dma)
return 1;
{
int i, tmp;
unsigned int raddr, rsize;
- struct pci_dev *dev;
struct isapnp_mem *xmem;
+ struct list_head *list;
for (i = 0; i < 8; i++) {
raddr = (unsigned int)isapnp_reserve_mem[i << 1];
if (__check_region(&iomem_resource, addr, size))
return 1;
}
- for (dev = isapnp_devices; dev; dev = dev->next) {
+ for (list = isapnp_devices.next; list != &isapnp_devices ; list = list->next) {
+ struct pci_dev *dev = list_entry(list, struct pci_dev, global_list);
if (dev->active) {
for (tmp = 0; tmp < 4; tmp++) {
if (dev->resource[tmp].flags) {
static void __init isapnp_pci_init(void)
{
- int devfn;
struct pci_dev *dev;
-
- for (devfn = 0; devfn < 255; devfn++) {
- dev = pci_find_slot(0, devfn);
- if (dev != NULL)
- break;
- }
- if (dev == NULL)
- return;
- while (dev) {
+
+ pci_for_each_dev(dev) {
#ifdef ISAPNP_DEBUG
printk("PCI: reserved IRQ: %i\n", dev->irq);
#endif
if (dev->irq > 0)
isapnp_do_reserve_irq(dev->irq);
- dev = dev->next;
}
}
int __init isapnp_init(void)
{
int cards;
- struct pci_bus *card;
- struct pci_dev *dev;
+ struct list_head *list;
if (isapnp_disable) {
isapnp_detected = 0;
}
isapnp_build_device_list();
cards = 0;
- for (card = isapnp_cards; card; card = card->next)
+
+ for (list = isapnp_cards.next; list != &isapnp_cards; list=list->next) {
+ struct pci_bus *card = list_entry(list, struct pci_bus, node);
+
cards++;
- if (isapnp_verbose) {
- for (card = isapnp_cards; card; card = card->next) {
+ if (isapnp_verbose) {
+ struct list_head *devlist;
printk( "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown");
if (isapnp_verbose < 2)
continue;
- for (dev = card->devices; dev; dev = dev->next)
+ for (devlist = card->devices.next; devlist != &card->devices; devlist = devlist->next) {
+ struct pci_dev *dev = list_entry(list, struct pci_dev, bus_list);
printk("isapnp: Device '%s'\n", dev->name[0]?card->name:"Unknown");
+ }
}
}
if (cards) {
*/
static void *isapnp_alloc(long size);
-struct pci_bus *isapnp_cards;
-struct pci_dev *isapnp_devices;
struct isapnp_info_buffer {
char *buffer; /* pointer to begin of buffer */
static void isapnp_info_read(isapnp_info_buffer_t *buffer)
{
- struct pci_bus *card;
- struct pci_dev *dev;
+ struct list_head *card_list;
- for (card = isapnp_cards; card; card = card->next) {
+ for (card_list = isapnp_cards.next; card_list != &isapnp_cards; card_list = card_list->next) {
+ struct pci_bus *card = list_entry(card_list, struct pci_bus, node);
+ struct list_head *dev_list;
+
isapnp_printf(buffer, "Card %i '", card->number);
isapnp_print_devid(buffer, card->vendor, card->device);
isapnp_printf(buffer, ":%s'", card->name[0]?card->name:"Unknown");
if (card->productver)
isapnp_printf(buffer, " Product version %x.%x", card->productver >> 4, card->productver & 0x0f);
isapnp_printf(buffer,"\n");
- for (dev = card->devices; dev; dev = dev->sibling)
+ for (dev_list = card->devices.next; dev_list != &card->devices; dev_list = dev_list->next) {
+ struct pci_dev *dev = list_entry(dev_list, struct pci_dev, bus_list);
isapnp_print_device(buffer, dev);
+ }
}
}
static int isapnp_select_csn(char *line)
{
int csn;
+ struct list_head *list;
char index[16], value[32];
isapnp_info_device = NULL;
isapnp_get_str(index, line, sizeof(index));
csn = simple_strtoul(index, NULL, 0);
- for (isapnp_info_card = isapnp_cards; isapnp_info_card; isapnp_info_card = isapnp_info_card->next)
+ for (list = isapnp_cards.next; list != &isapnp_cards; list = list->next) {
+ isapnp_info_card = list_entry(list, struct pci_bus, node);
if (isapnp_info_card->number == csn)
break;
+ }
if (isapnp_info_card == NULL) {
printk("isapnp: cannot find CSN %i\n", csn);
return 1;
{
mega_host_config *megaCfg;
struct Scsi_Host *host;
- u_char pciBus, pciDevFun, megaIrq;
+ u_char megaIrq;
u32 megaBase;
- u16 pciIdx = 0;
u16 numFound = 0;
- struct pci_dev *pdev = pci_devices;
+ struct pci_dev *pdev = NULL;
while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
- pciBus = pdev->bus->number;
- pciDevFun = pdev->devfn;
if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
u16 magic;
- pcibios_read_config_word (pciBus, pciDevFun,
- PCI_CONF_AMISIG,
- &magic);
- if (magic != AMI_SIGNATURE) {
- pciIdx++;
+ pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic);
+ if (magic != AMI_SIGNATURE)
continue; /* not an AMI board */
- }
}
- printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n",
+ printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x: in %s\n",
pciVendor,
pciDev,
- pciIdx, pciBus,
- PCI_SLOT (pciDevFun),
- PCI_FUNC (pciDevFun));
+ pdev->slot_name);
/* Read the base port and IRQ from PCI */
megaBase = pdev->resource[0].start;
megaIrq = pdev->irq;
- pciIdx++;
if (flag & BOARD_QUARTZ) {
megaCfg->host->irq = megaIrq;
megaCfg->host->io_port = megaBase;
megaCfg->host->n_io_port = 16;
- megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;
+ megaCfg->host->unique_id = (pdev->bus->number << 8) | pdev->devfn;
megaCtlrs[numCtlrs++] = megaCfg;
if (flag != BOARD_QUARTZ) {
/* Request our IO Range */
/*
* es1370.c -- Ensoniq ES1370/Asahi Kasei AK4531 audio driver.
*
- * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* 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
* there are several MIDI to PCM (WAV) packages, one of them is timidity.
*
* Revision history
- * 26.03.98 0.1 Initial release
- * 31.03.98 0.2 Fix bug in GETOSPACE
- * 04.04.98 0.3 Make it work (again) under 2.0.33
- * Fix mixer write operation not returning the actual
- * settings
- * 05.04.98 0.4 First attempt at using the new PCI stuff
- * 29.04.98 0.5 Fix hang when ^C is pressed on amp
- * 07.05.98 0.6 Don't double lock around stop_*() in *_release()
- * 10.05.98 0.7 First stab at a simple midi interface (no bells&whistles)
- * 14.05.98 0.8 Don't allow excessive interrupt rates
- * 08.06.98 0.9 First release using Alan Cox' soundcore instead of
- * miscdevice
- * 05.07.98 0.10 Fixed the driver to correctly maintin OSS style volume
- * settings (not sure if this should be standard)
- * Fixed many references: f_flags should be f_mode
- * -- Gerald Britton <gbritton@mit.edu>
- * 03.08.98 0.11 Now mixer behaviour can basically be selected between
- * "OSS documented" and "OSS actual" behaviour
- * Fixed mixer table thanks to Hakan.Lennestal@lu.erisoft.se
- * On module startup, set DAC2 to 11kSPS instead of 5.5kSPS,
- * as it produces an annoying ssssh in the lower sampling rate
- * Do not include modversions.h
- * 22.08.98 0.12 Mixer registers actually have 5 instead of 4 bits
- * pointed out by Itai Nahshon
- * 31.08.98 0.13 Fix realplayer problems - dac.count issues
- * 08.10.98 0.14 Joystick support fixed
- * -- Oliver Neukum <c188@org.chemie.uni-muenchen.de>
- * 10.12.98 0.15 Fix drain_dac trying to wait on not yet initialized DMA
- * 16.12.98 0.16 Don't wake up app until there are fragsize bytes to read/write
- * 06.01.99 0.17 remove the silly SA_INTERRUPT flag.
- * hopefully killed the egcs section type conflict
- * 12.03.99 0.18 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * 22.03.99 0.19 return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 07.04.99 0.20 implemented the following ioctl's: SOUND_PCM_READ_RATE,
- * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
- * Alpha fixes reported by Peter Jones <pjones@redhat.com>
- * Note: joystick address handling might still be wrong on archs
- * other than i386
- * 10.05.99 0.21 Added support for an electret mic for SB PCI64
- * to the Linux kernel sound driver. This mod also straighten
- * out the question marks around the mic impedance setting
- * (micz). From Kim.Berts@fisub.mail.abb.com
- * 11.05.99 0.22 Implemented the IMIX call to mute recording monitor.
- * Guenter Geiger <geiger@epy.co.at>
- * 15.06.99 0.23 Fix bad allocation bug.
- * Thanks to Deti Fliegl <fliegl@in.tum.de>
- * 28.06.99 0.24 Add pci_set_master
- * 02.08.99 0.25 Added workaround for the "phantom write" bug first
- * documented by Dave Sharpless from Anchor Games
- * 03.08.99 0.26 adapt to Linus' new __setup/__initcall
- * added kernel command line option "es1370=joystick[,lineout[,micbias]]"
- * removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
- * 12.08.99 0.27 module_init/__setup fixes
- * 19.08.99 0.28 SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
- * 31.08.99 0.29 add spin_lock_init
- * __initlocaldata to fix gcc 2.7.x problems
- * replaced current->state = x with set_current_state(x)
- * 03.09.99 0.30 change read semantics for MIDI to match
- * OSS more closely; remove possible wakeup race
- * 28.10.99 0.31 More waitqueue races fixed
+ * 26.03.1998 0.1 Initial release
+ * 31.03.1998 0.2 Fix bug in GETOSPACE
+ * 04.04.1998 0.3 Make it work (again) under 2.0.33
+ * Fix mixer write operation not returning the actual
+ * settings
+ * 05.04.1998 0.4 First attempt at using the new PCI stuff
+ * 29.04.1998 0.5 Fix hang when ^C is pressed on amp
+ * 07.05.1998 0.6 Don't double lock around stop_*() in *_release()
+ * 10.05.1998 0.7 First stab at a simple midi interface (no bells&whistles)
+ * 14.05.1998 0.8 Don't allow excessive interrupt rates
+ * 08.06.1998 0.9 First release using Alan Cox' soundcore instead of
+ * miscdevice
+ * 05.07.1998 0.10 Fixed the driver to correctly maintin OSS style volume
+ * settings (not sure if this should be standard)
+ * Fixed many references: f_flags should be f_mode
+ * -- Gerald Britton <gbritton@mit.edu>
+ * 03.08.1998 0.11 Now mixer behaviour can basically be selected between
+ * "OSS documented" and "OSS actual" behaviour
+ * Fixed mixer table thanks to Hakan.Lennestal@lu.erisoft.se
+ * On module startup, set DAC2 to 11kSPS instead of 5.5kSPS,
+ * as it produces an annoying ssssh in the lower sampling rate
+ * Do not include modversions.h
+ * 22.08.1998 0.12 Mixer registers actually have 5 instead of 4 bits
+ * pointed out by Itai Nahshon
+ * 31.08.1998 0.13 Fix realplayer problems - dac.count issues
+ * 08.10.1998 0.14 Joystick support fixed
+ * -- Oliver Neukum <c188@org.chemie.uni-muenchen.de>
+ * 10.12.1998 0.15 Fix drain_dac trying to wait on not yet initialized DMA
+ * 16.12.1998 0.16 Don't wake up app until there are fragsize bytes to read/write
+ * 06.01.1999 0.17 remove the silly SA_INTERRUPT flag.
+ * hopefully killed the egcs section type conflict
+ * 12.03.1999 0.18 cinfo.blocks should be reset after GETxPTR ioctl.
+ * reported by Johan Maes <joma@telindus.be>
+ * 22.03.1999 0.19 return EAGAIN instead of EBUSY when O_NONBLOCK
+ * read/write cannot be executed
+ * 07.04.1999 0.20 implemented the following ioctl's: SOUND_PCM_READ_RATE,
+ * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
+ * Alpha fixes reported by Peter Jones <pjones@redhat.com>
+ * Note: joystick address handling might still be wrong on archs
+ * other than i386
+ * 10.05.1999 0.21 Added support for an electret mic for SB PCI64
+ * to the Linux kernel sound driver. This mod also straighten
+ * out the question marks around the mic impedance setting
+ * (micz). From Kim.Berts@fisub.mail.abb.com
+ * 11.05.1999 0.22 Implemented the IMIX call to mute recording monitor.
+ * Guenter Geiger <geiger@epy.co.at>
+ * 15.06.1999 0.23 Fix bad allocation bug.
+ * Thanks to Deti Fliegl <fliegl@in.tum.de>
+ * 28.06.1999 0.24 Add pci_set_master
+ * 02.08.1999 0.25 Added workaround for the "phantom write" bug first
+ * documented by Dave Sharpless from Anchor Games
+ * 03.08.1999 0.26 adapt to Linus' new __setup/__initcall
+ * added kernel command line option "es1370=joystick[,lineout[,micbias]]"
+ * removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
+ * 12.08.1999 0.27 module_init/__setup fixes
+ * 19.08.1999 0.28 SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
+ * 31.08.1999 0.29 add spin_lock_init
+ * __initlocaldata to fix gcc 2.7.x problems
+ * replaced current->state = x with set_current_state(x)
+ * 03.09.1999 0.30 change read semantics for MIDI to match
+ * OSS more closely; remove possible wakeup race
+ * 28.10.1999 0.31 More waitqueue races fixed
*
* some important things missing in Ensoniq documentation:
*
/*
* es1371.c -- Creative Ensoniq ES1371.
*
- * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* 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
* there are several MIDI to PCM (WAV) packages, one of them is timidity.
*
* Revision history
- * 04.06.98 0.1 Initial release
- * Mixer stuff should be overhauled; especially optional AC97 mixer bits
- * should be detected. This results in strange behaviour of some mixer
- * settings, like master volume and mic.
- * 08.06.98 0.2 First release using Alan Cox' soundcore instead of miscdevice
- * 03.08.98 0.3 Do not include modversions.h
- * Now mixer behaviour can basically be selected between
- * "OSS documented" and "OSS actual" behaviour
- * 31.08.98 0.4 Fix realplayer problems - dac.count issues
- * 27.10.98 0.5 Fix joystick support
- * -- Oliver Neukum (c188@org.chemie.uni-muenchen.de)
- * 10.12.98 0.6 Fix drain_dac trying to wait on not yet initialized DMA
- * 23.12.98 0.7 Fix a few f_file & FMODE_ bugs
- * Don't wake up app until there are fragsize bytes to read/write
- * 06.01.99 0.8 remove the silly SA_INTERRUPT flag.
- * hopefully killed the egcs section type conflict
- * 12.03.99 0.9 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * 22.03.99 0.10 return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 07.04.99 0.11 implemented the following ioctl's: SOUND_PCM_READ_RATE,
- * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
- * Alpha fixes reported by Peter Jones <pjones@redhat.com>
- * Another Alpha fix (wait_src_ready in init routine)
- * reported by "Ivan N. Kokshaysky" <ink@jurassic.park.msu.ru>
- * Note: joystick address handling might still be wrong on archs
- * other than i386
- * 15.06.99 0.12 Fix bad allocation bug.
- * Thanks to Deti Fliegl <fliegl@in.tum.de>
- * 28.06.99 0.13 Add pci_set_master
- * 03.08.99 0.14 adapt to Linus' new __setup/__initcall
- * added kernel command line option "es1371=joystickaddr"
- * removed CONFIG_SOUND_ES1371_JOYPORT_BOOT kludge
- * 10.08.99 0.15 (Re)added S/PDIF module option for cards revision >= 4.
- * Initial version by Dave Platt <dplatt@snulbug.mtview.ca.us>.
- * module_init/__setup fixes
- * 08.16.99 0.16 Joe Cotellese <joec@ensoniq.com>
- * Added detection for ES1371 revision ID so that we can
- * detect the ES1373 and later parts.
- * added AC97 #defines for readability
- * added a /proc file system for dumping hardware state
- * updated SRC and CODEC w/r functions to accomodate bugs
- * in some versions of the ES137x chips.
- * 31.08.99 0.17 add spin_lock_init
- * __initlocaldata to fix gcc 2.7.x problems
- * replaced current->state = x with set_current_state(x)
- * 03.09.99 0.18 change read semantics for MIDI to match
- * OSS more closely; remove possible wakeup race
- * 21.10.99 0.19 Round sampling rates, requested by
- * Kasamatsu Kenichi <t29w0267@ip.media.kyoto-u.ac.jp>
- * 27.10.99 0.20 Added SigmaTel 3D enhancement string
- * Codec ID printing changes
- * 28.10.99 0.21 More waitqueue races fixed
- * Joe Cotellese <joec@ensoniq.com>
- * Changed PCI detection routine so we can more easily
- * detect ES137x chip and derivatives.
+ * 04.06.1998 0.1 Initial release
+ * Mixer stuff should be overhauled; especially optional AC97 mixer bits
+ * should be detected. This results in strange behaviour of some mixer
+ * settings, like master volume and mic.
+ * 08.06.1998 0.2 First release using Alan Cox' soundcore instead of miscdevice
+ * 03.08.1998 0.3 Do not include modversions.h
+ * Now mixer behaviour can basically be selected between
+ * "OSS documented" and "OSS actual" behaviour
+ * 31.08.1998 0.4 Fix realplayer problems - dac.count issues
+ * 27.10.1998 0.5 Fix joystick support
+ * -- Oliver Neukum (c188@org.chemie.uni-muenchen.de)
+ * 10.12.1998 0.6 Fix drain_dac trying to wait on not yet initialized DMA
+ * 23.12.1998 0.7 Fix a few f_file & FMODE_ bugs
+ * Don't wake up app until there are fragsize bytes to read/write
+ * 06.01.1999 0.8 remove the silly SA_INTERRUPT flag.
+ * hopefully killed the egcs section type conflict
+ * 12.03.1999 0.9 cinfo.blocks should be reset after GETxPTR ioctl.
+ * reported by Johan Maes <joma@telindus.be>
+ * 22.03.1999 0.10 return EAGAIN instead of EBUSY when O_NONBLOCK
+ * read/write cannot be executed
+ * 07.04.1999 0.11 implemented the following ioctl's: SOUND_PCM_READ_RATE,
+ * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
+ * Alpha fixes reported by Peter Jones <pjones@redhat.com>
+ * Another Alpha fix (wait_src_ready in init routine)
+ * reported by "Ivan N. Kokshaysky" <ink@jurassic.park.msu.ru>
+ * Note: joystick address handling might still be wrong on archs
+ * other than i386
+ * 15.06.1999 0.12 Fix bad allocation bug.
+ * Thanks to Deti Fliegl <fliegl@in.tum.de>
+ * 28.06.1999 0.13 Add pci_set_master
+ * 03.08.1999 0.14 adapt to Linus' new __setup/__initcall
+ * added kernel command line option "es1371=joystickaddr"
+ * removed CONFIG_SOUND_ES1371_JOYPORT_BOOT kludge
+ * 10.08.1999 0.15 (Re)added S/PDIF module option for cards revision >= 4.
+ * Initial version by Dave Platt <dplatt@snulbug.mtview.ca.us>.
+ * module_init/__setup fixes
+ * 08.16.1999 0.16 Joe Cotellese <joec@ensoniq.com>
+ * Added detection for ES1371 revision ID so that we can
+ * detect the ES1373 and later parts.
+ * added AC97 #defines for readability
+ * added a /proc file system for dumping hardware state
+ * updated SRC and CODEC w/r functions to accomodate bugs
+ * in some versions of the ES137x chips.
+ * 31.08.1999 0.17 add spin_lock_init
+ * __initlocaldata to fix gcc 2.7.x problems
+ * replaced current->state = x with set_current_state(x)
+ * 03.09.1999 0.18 change read semantics for MIDI to match
+ * OSS more closely; remove possible wakeup race
+ * 21.10.1999 0.19 Round sampling rates, requested by
+ * Kasamatsu Kenichi <t29w0267@ip.media.kyoto-u.ac.jp>
+ * 27.10.1999 0.20 Added SigmaTel 3D enhancement string
+ * Codec ID printing changes
+ * 28.10.1999 0.21 More waitqueue races fixed
+ * Joe Cotellese <joec@ensoniq.com>
+ * Changed PCI detection routine so we can more easily
+ * detect ES137x chip and derivatives.
+ * 05.01.2000 0.22 Should now work with rev7 boards; patch by
+ * Eric Lemar, elemar@cs.washington.edu
*/
/*****************************************************************************/
case SOUND_MIXER_SPEAKER:
j = rdcodec(s, AC97_PCBEEP_VOL);
- if (j & AC97_MUTE
+ if (j & AC97_MUTE)
return put_user(0, (int *)arg);
return put_user(0x6464 - ((j >> 1) & 0xf) * 0x606, (int *)arg);
pci_set_master(pcidev); /* enable bus mastering */
/* if we are a 5880 turn on the AC97 */
if (s->vendor == PCI_VENDOR_ID_ENSONIQ &&
- s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 &&
- s->rev == CT5880REV_CT5880_C) {
+ ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev == CT5880REV_CT5880_C) ||
+ (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_CT5880_A))) {
cssr |= CSTAT_5880_AC97_RST;
outl(cssr, s->io+ES1371_REG_STATUS);
/* need to delay around 20ms(bleech) to give
* 07.10.99 0.9 Fix initialization; complain if sequencer writes time out
* Revised resource grabbing for the FM synthesizer
* 28.10.99 0.10 More waitqueue races fixed
+ * 09.12.99 0.11 Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M)
+ * Disabling recording on Alpha
*
*/
break;
if (!db->rawbuf)
return -ENOMEM;
+ /* work around a problem of the alpha port */
+ if ((gfp_mask & GFP_DMA) && (virt_to_bus(db->rawbuf) & (~0xffffffUL))) {
+ printk(KERN_ERR "solo1: requested DMA buffer below 16M but got 0x%lx, Alpha bug?\n",
+ (unsigned long)virt_to_bus(db->rawbuf));
+ kfree(db->rawbuf);
+ db->rawbuf = NULL;
+ return -ENOMEM;
+ }
db->buforder = order;
/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
if (s->dma_dac.mapped)
s->dma_dac.count &= s->dma_dac.fragsize-1;
spin_unlock_irqrestore(&s->lock, flags);
+#if 0
+ printk(KERN_DEBUG "esssolo1: GETOPTR: bytes %u blocks %u ptr %u, buforder %u numfrag %u fragshift %u\n"
+ KERN_DEBUG "esssolo1: swptr %u count %u fragsize %u dmasize %u fragsamples %u\n",
+ cinfo.bytes, cinfo.blocks, cinfo.ptr, s->dma_dac.buforder, s->dma_dac.numfrag, s->dma_dac.fragshift,
+ s->dma_dac.swptr, s->dma_dac.count, s->dma_dac.fragsize, s->dma_dac.dmasize, s->dma_dac.fragsamples);
+#endif
return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
case SNDCTL_DSP_GETBLKSIZE:
s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
up(&s->open_sem);
MOD_INC_USE_COUNT;
- if (prog_dmabuf_dac(s) || prog_dmabuf_adc(s)) {
- solo1_release(inode, file);
- return -ENOMEM;
- }
prog_codec(s);
return 0;
}
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "solo1: version v0.10 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "solo1: version v0.11 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
if (!RSRCISIOREGION(pcidev, 0) ||
#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
-/* eeeew. */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-#else
-#define RSRCADDRESS(dev,num) ((dev)->base_address[(num)] \
- & PCI_BASE_ADDRESS_MEM_MASK)
-
-#endif
/* List of cards. */
static struct nm256_info *nmcard_list;
/*
* sonicvibes.c -- S3 Sonic Vibes audio driver.
*
- * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Copyright (C) 1998-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
*
* 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
* out first how to drive them...
*
* Revision history
- * 06.05.98 0.1 Initial release
- * 10.05.98 0.2 Fixed many bugs, esp. ADC rate calculation
- * First stab at a simple midi interface (no bells&whistles)
- * 13.05.98 0.3 Fix stupid cut&paste error: set_adc_rate was called instead of
- * set_dac_rate in the FMODE_WRITE case in sv_open
- * Fix hwptr out of bounds (now mpg123 works)
- * 14.05.98 0.4 Don't allow excessive interrupt rates
- * 08.06.98 0.5 First release using Alan Cox' soundcore instead of miscdevice
- * 03.08.98 0.6 Do not include modversions.h
- * Now mixer behaviour can basically be selected between
- * "OSS documented" and "OSS actual" behaviour
- * 31.08.98 0.7 Fix realplayer problems - dac.count issues
- * 10.12.98 0.8 Fix drain_dac trying to wait on not yet initialized DMA
- * 16.12.98 0.9 Fix a few f_file & FMODE_ bugs
- * 06.01.99 0.10 remove the silly SA_INTERRUPT flag.
- * hopefully killed the egcs section type conflict
- * 12.03.99 0.11 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * 22.03.99 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 05.04.99 0.13 added code to sv_read and sv_write which should detect
- * lockups of the sound chip and revive it. This is basically
- * an ugly hack, but at least applications using this driver
- * won't hang forever. I don't know why these lockups happen,
- * it might well be the motherboard chipset (an early 486 PCI
- * board with ALI chipset), since every busmastering 100MB
- * ethernet card I've tried (Realtek 8139 and Macronix tulip clone)
- * exhibit similar behaviour (they work for a couple of packets
- * and then lock up and can be revived by ifconfig down/up).
- * 07.04.99 0.14 implemented the following ioctl's: SOUND_PCM_READ_RATE,
- * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
- * Alpha fixes reported by Peter Jones <pjones@redhat.com>
- * Note: dmaio hack might still be wrong on archs other than i386
- * 15.06.99 0.15 Fix bad allocation bug.
- * Thanks to Deti Fliegl <fliegl@in.tum.de>
- * 28.06.99 0.16 Add pci_set_master
- * 03.08.99 0.17 adapt to Linus' new __setup/__initcall
- * added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
- * 12.08.99 0.18 module_init/__setup fixes
- * 24.08.99 0.19 get rid of the dmaio kludge, replace with allocate_resource
- * 31.08.99 0.20 add spin_lock_init
- * __initlocaldata to fix gcc 2.7.x problems
- * use new resource allocation to allocate DDMA IO space
- * replaced current->state = x with set_current_state(x)
- * 03.09.99 0.21 change read semantics for MIDI to match
- * OSS more closely; remove possible wakeup race
- * 28.10.99 0.22 More waitqueue races fixed
- * 01.12.99 0.23 New argument to allocate_resource
- * 07.12.99 0.24 More allocate_resource semantics change
+ * 06.05.1998 0.1 Initial release
+ * 10.05.1998 0.2 Fixed many bugs, esp. ADC rate calculation
+ * First stab at a simple midi interface (no bells&whistles)
+ * 13.05.1998 0.3 Fix stupid cut&paste error: set_adc_rate was called instead of
+ * set_dac_rate in the FMODE_WRITE case in sv_open
+ * Fix hwptr out of bounds (now mpg123 works)
+ * 14.05.1998 0.4 Don't allow excessive interrupt rates
+ * 08.06.1998 0.5 First release using Alan Cox' soundcore instead of miscdevice
+ * 03.08.1998 0.6 Do not include modversions.h
+ * Now mixer behaviour can basically be selected between
+ * "OSS documented" and "OSS actual" behaviour
+ * 31.08.1998 0.7 Fix realplayer problems - dac.count issues
+ * 10.12.1998 0.8 Fix drain_dac trying to wait on not yet initialized DMA
+ * 16.12.1998 0.9 Fix a few f_file & FMODE_ bugs
+ * 06.01.1999 0.10 remove the silly SA_INTERRUPT flag.
+ * hopefully killed the egcs section type conflict
+ * 12.03.1999 0.11 cinfo.blocks should be reset after GETxPTR ioctl.
+ * reported by Johan Maes <joma@telindus.be>
+ * 22.03.1999 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK
+ * read/write cannot be executed
+ * 05.04.1999 0.13 added code to sv_read and sv_write which should detect
+ * lockups of the sound chip and revive it. This is basically
+ * an ugly hack, but at least applications using this driver
+ * won't hang forever. I don't know why these lockups happen,
+ * it might well be the motherboard chipset (an early 486 PCI
+ * board with ALI chipset), since every busmastering 100MB
+ * ethernet card I've tried (Realtek 8139 and Macronix tulip clone)
+ * exhibit similar behaviour (they work for a couple of packets
+ * and then lock up and can be revived by ifconfig down/up).
+ * 07.04.1999 0.14 implemented the following ioctl's: SOUND_PCM_READ_RATE,
+ * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
+ * Alpha fixes reported by Peter Jones <pjones@redhat.com>
+ * Note: dmaio hack might still be wrong on archs other than i386
+ * 15.06.1999 0.15 Fix bad allocation bug.
+ * Thanks to Deti Fliegl <fliegl@in.tum.de>
+ * 28.06.1999 0.16 Add pci_set_master
+ * 03.08.1999 0.17 adapt to Linus' new __setup/__initcall
+ * added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
+ * 12.08.1999 0.18 module_init/__setup fixes
+ * 24.08.1999 0.19 get rid of the dmaio kludge, replace with allocate_resource
+ * 31.08.1999 0.20 add spin_lock_init
+ * __initlocaldata to fix gcc 2.7.x problems
+ * use new resource allocation to allocate DDMA IO space
+ * replaced current->state = x with set_current_state(x)
+ * 03.09.1999 0.21 change read semantics for MIDI to match
+ * OSS more closely; remove possible wakeup race
+ * 28.10.1999 0.22 More waitqueue races fixed
+ * 01.12.1999 0.23 New argument to allocate_resource
+ * 07.12.1999 0.24 More allocate_resource semantics change
*
*/
+++ /dev/null
-Credits for the Simple Linux USB Driver:
-
-The following people have contributed to this code (in alphabetical
-order by last name). I'm sure this list should be longer, its
-difficult to maintain, add yourself with a patch if desired.
-
- Alan Cox <alan@lxorguk.ukuu.org.uk>
- Johannes Erdfelt <jerdfelt@sventech.com>
- ham <ham@unsuave.com>
- Bradley M Keryan <keryan@andrew.cmu.edu>
- Paul Mackerras <paulus@cs.anu.edu.au>
- David E. Nelson <dnelson@jump.net>
- Vojtech Pavlik <vojtech@suse.cz>
- Gregory P. Smith <greg@electricrain.com>
- Linus Torvalds <torvalds@transmeta.com>
- Roman Weissgaerber <weissg@vienna.at>
- <Kazuki.Yasumatsu@fujixerox.co.jp>
-
-Special thanks to:
-
- Inaky Perez Gonzalez <inaky@peloncho.fis.ucm.es> for starting the
- Linux USB driver effort and writing much of the larger uusbd driver.
- Much has been learned from that effort.
-
- The NetBSD & FreeBSD USB developers. For being on the Linux USB list
- and offering suggestions and sharing implementation experiences.
-
-Additional thanks to the following companies and people for donations
-of hardware, support, time and development (this is from the original
-THANKS file in Inaky's driver):
-
- The following corporations have helped us in the development
- of Linux USB / UUSBD:
-
- - 3Com GmbH for donating a ISDN Pro TA and supporting me
- in technical questions and with test equipment. I'd never
- expect such a great help.
-
- - USAR Systems provided us with one of their excellent USB
- Evaluation Kits. It allows us to test the Linux-USB driver
- for compilance with the latest USB specification. USAR
- Systems recognized the importance of an up-to-date open
- Operating System and supports this project with
- Hardware. Thanks!.
-
- - Thanks to Intel Corporation for their precious help.
-
- - We teamed up with Cherry to make Linux the first OS with
- built-in USB support. Cherry is one of the biggest keyboard
- makers in the world.
-
- - CMD Technology, Inc. sponsored us kindly donating a CSA-6700
- PCI-to-USB Controller Board to test the OHCI implementation.
-
- - Due to their support to us, Keytronic can be sure that they
- will sell keyboards to some of the 3 million (at least)
- Linux users.
-
- - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
- It was almost imposible to get a PC backplate USB connector
- for the motherboard here at Europe (mine, home-made, was
- quite lowsy :). Now I know where to adquire nice USB stuff!
-
- - Genius Germany donated a USB mouse to test the mouse boot
- protocol. They've also donated a F-23 digital joystick and a
- NetMouse Pro. Thanks!
-
- - AVM GmbH Berlin is supporting the development of the Linux
- USB driver for the AVM ISDN Controller B1 USB. AVM is a
- leading manufacturer for active and passive ISDN Controllers
- and CAPI 2.0-based software. The active design of the AVM B1
- is open for all OS platforms, including Linux.
-
- - Thanks to Y-E Data, Inc. for donating their FlashBuster-U
- USB Floppy Disk Drive, so we could test the bulk transfer
- code.
-
- - Many thanks to Logitech for contributing a three axis USB
- mouse.
-
- Logitech designs, manufactures and markets
- Human Interface Devices, having a long history and
- experience in making devices such as keyboards, mice,
- trackballs, cameras, loudspeakers and control devices for
- gaming and professional use.
-
- Being a recognized vendor and seller for all these devices,
- they have donated USB mice, a joystick and a scanner, as a
- way to acknowledge the importance of Linux and to allow
- Logitech customers to enjoy support in their favorite
- operating systems and all Linux users to use Logitech and
- other USB hardware.
-
- Logitech is official sponsor of the Linux Conference on
- Feb. 11th 1999 in Vienna, where we'll will present the
- current state of the Linux USB effort.
-
- - CATC has provided means to uncover dark corners of the UHCI
- inner workings with a USB Inspector.
-
- - Thanks to Entrega for providing PCI to USB cards, hubs and
- converter products for development.
-
-
- And thanks go to (hey! in no particular order :)
-
- - Oren Tirosh <orenti@hishome.net>, for standing so patiently
- all my doubts'bout USB and giving lots of cool ideas.
-
- - Jochen Karrer <karrer@wpfd25.physik.uni-wuerzburg.de>, for
- pointing out mortal bugs and giving advice.
-
- - Edmund Humemberger <ed@atnet.at>, for it's great work on
- public relationships and general management stuff for the
- Linux-USB effort.
-
- - Alberto Menegazzi <flash@flash.iol.it> is starting the
- documentation for the UUSBD. Go for it!
-
- - Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
- introductory documents (compiting with Alberto's :).
-
- - Christian Groessler <cpg@aladdin.de>, for it's help on those
- itchy bits ... :)
-
- - Paul MacKerras for polishing OHCI and pushing me harder for
- the iMac support, giving improvements and enhancements.
-
- - Fernando Herrera <fherrera@eurielec.etsit.upm.es> has taken
- charge of composing, maintaining and feeding the
- long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!!
-
- - Rasca Gmelch <thron@gmx.de> has revived the raw driver and
- pointed bugs, as well as started the uusbd-utils package.
-
- - Peter Dettori <dettori@ozy.dec.com> is unconvering bugs like
- crazy, as well as making cool suggestions, great :)
-
- - All the Free Software and Linux community, the FSF & the GNU
- project, the MIT X consortium, the TeX people ... everyone!
- You know who you are!
-
- - Big thanks to Richard Stallman for creating Emacs!
-
- - The people at the linux-usb mailing list, for reading so
- many messages :) Ok, no more kidding; for all your advices!
-
- - All the people at the USB Implementors Forum for their
- help and assistance.
-
- - Nathan Myers <ncm@cantrip.org>, for his advice! (hope you
- liked Cibeles' party).
-
- - Linus Torvalds, for starting, developing and managing Linux.
-
- - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank
- for convincing me USB Standard hubs are not that standard
- and that's good to allow for vendor specific quirks on the
- standard hub driver.
-
+++ /dev/null
-1. Specification of the API
-
-1.1. Basic concept or 'What is an URB?'
-
-The basic idea of the new driver is message passing, the message itself is
-called USB Request Block, or URB for short.
-
-- An URB consists of all relevant information to execute any USB transaction
-and deliver the data and status back.
-
-- Execution of an URB is an inherently asynchronous operation, i.e. the
-submit_urb(urb) call returns immediately after it has successfully queued
-the requested action.
-
-- Ongoing transfers for one URB (e.g. ISO) can simply be canceled with
-unlink_urb(urb) at any time.
-
-- Each URB has a completion handler, which is called after the action
-has been successfully completed or canceled (INT transfers behave a bit
-different, see below). The URB also contains a context-pointer for free
-usage and information passing to the completion handler.
-
-- URBs can be linked. After completing one URB, the next one can be
-automatically submitted. This is especially useful for ISO transfers:
-You only have read/write the data from/to the buffers in the completion
-handler, the continous streaming itself is transparently done by the
-URB-machinery.
-
-1.2. The URB structure
-
-typedef struct urb
-{
-// ignore, for host controller/URB machine internal use
- void *hcpriv; // private data for host controller
- struct list_head urb_list; // list pointer to all active urbs
-
-// This is used for urb linking
- struct urb* next; // pointer to next URB
- struct usb_device *dev; // pointer to associated USB device
-
-// pipe is assembled by the various well known pipe-macros in usb.h
- unsigned int pipe; // pipe information
-
-// status after each completion
- int status; // returned status
- unsigned int transfer_flags; // ASAP, SP_OK, EARLY_COMPLETE
-
-// for data stage (CTRL), BULK, INT and ISO
- void *transfer_buffer; // associated data buffer
-
-// expected length
- int transfer_buffer_length; // data buffer length
- int actual_length; // actual data buffer length
-
-// setup stage for CTRL (always 8 bytes!)
- unsigned char* setup_packet; // setup packet (control only)
-
-// with ASAP, start_frame is set to the determined frame
- int start_frame; // start frame (iso/irq)
- int number_of_packets; // # of packets (iso/int)
- int interval; // polling interval (irq only)
- int error_count; // number of errors (iso only)
- //
- void *context; // context for completion routine
- usb_complete_t complete; // pointer to completion routine
- //
-// specification of the requested data offsets and length for ISO
- iso_packet_descriptor_t iso_frame_desc[0];
-} urb_t, *purb_t;
-
-1.3. How to get an URB?
-
-URBs are allocated with the following call
-
- purb_t alloc_urb(int isoframes)
-
-Return value is a pointer to the allocated URB, 0 if allocation failed.
-The parameter isoframes specifies the number of isochronous transfer frames
-you want to schedule. For CTRL/BULK/INT, use 0.
-
-To free an URB, use
-
- void free_urb(purb_t purb)
-
-This call also may free internal (host controller specific) memory in the
-future.
-
-1.4. What has to be filled in?
-
-Depending on the type of transaction, there are some macros
-(FILL_CONTROL_URB, FILL_BULK_URB, and FILL_INT_URB, defined in uhci.h)
-that simplify the URB creation. In general, all macros need the usb
-device pointer, the pipe (usual format), the transfer buffer, the
-desired transfer length, the completion handler, and its context.
-Take a look at the uhci_control_msg-function that convert the old API
-into an URB.
-
-Flags:
-For ISO there are two startup behaviors: Specified start_frame or ASAP.
-For ASAP set USB_ISO_ASAP in transfer_flags.
-
-If short packets should NOT be tolerated, set USB_DISABLE_SPD in
-transfer_flags.
-
-Usually, (to reduce restart time) the completion handler is called
-AFTER the URB re-submission. You can get the other way by setting
-USB_URB_EARLY_COMPLETE in transfer_flags. This is implicite for
-INT transfers.
-
-1.5. How to submit an URB?
-
-Just call
-
- int submit_urb(purb_t purb)
-
-It immediately returns, either with status 0 (request queued) or some
-error code, usually caused by the following:
-
-- Out of memory (-ENOMEM)
-- Wrong pipe handle (-ENXIO)
-- Unplugged device (-ENODEV)
-- Stalled endpoint (-EPIPE)
-- Too many queued ISO transfers (-EAGAIN)
-- Too many requested ISO frames (-EFBIG)
-- Invalid INT interval (-EINVAL)
-- More than one packet for INT (-EINVAL)
-
-After submission, urb->status is USB_ST_URB_PENDING.
-
-For isochronous endpoints, subsequent submitting of URBs to the same endpoint
-with the ASAP flag result in a seamless ISO streaming. Exception: The
-execution cannot be scheduled later than 900 frames from the 'now'-time.
-The same applies to INT transfers, but here the seamless continuation is
-independent of the transfer flags (implicitely ASAP).
-
-1.6. How to cancel an already running URB?
-
-Call
- int unlink_urb(purb_t purb)
-
-It removes the urb from the internal list and frees all allocated
-HW descriptors. The status is changed to USB_ST_URB_KILLED. After
-unlink_urb() returns, you can safely free the URB with free_urb(urb)
-and all other possibly associated data (urb->context etc.)
-
-1.7. What about the completion handler?
-
-The completion handler is optional, but useful for fast data processing
-or wakeup of a sleeping process (as shown in the compatibility wrapper's
-completion handler).
-
-The handler is of the following type:
-
- typedef void (*usb_complete_t)(struct urb *);
-
-i.e. it gets just the URB that caused the completion call.
-In the completion handler, you should have a look at urb->status to
-detect any USB errors. Since the context parameter is included in the URB,
-you can pass information to the completion handler.
-
-
-1.8. How to do isochronous (ISO) transfers?
-
-For ISO transfers you have to append the iso_packet_descriptor_t structure
-to the URB for each frame you want to schedule. When using alloc_urb(n)
-(recommended), the isoframe-parameter n can be used to allocate the
-structures for n frames.
-
-For each entry you have to specify the data offset for this frame (base is
-transfer_buffer), and the length you want to write/expect to read.
-After completion, actual_length contains the actual transfered length and
-status contains the resulting USB-status for the ISO transfer for this frame.
-It is allowed to specify a varying length from frame to frame (e.g. for
-audio synchronisation/adaptive transfer rates). You can also use the length
-0 to omit one or more frames (striping).
-
-As can be concluded from above, the UHCI-driver does not care for continous
-data in case of short packet ISO reads! There's no fixup_isoc() like in the
-old driver. There may be a common routine to do this in the future, but this
-has nothing to do with the UHCI-driver!
-
-For scheduling you can choose your own start frame or ASAP. As written above,
-queuing more than one ISO frame with ASAP to the same device&endpoint result
-in seamless ISO streaming. For continous streaming you have to use URB
-linking.
-
-1.9. How to start interrupt (INT) transfers?
-
-INT transfers are currently implemented with 8 different queues for intervals
-for 1, 2, 4,... 128ms. Only one TD is allocated for each interrupt. After
-calling the completion handler, the TD is recycled.
-With the submission of one URB, the interrupt is scheduled until it is
-canceled by unlink_urb.
-
-The submit_urb()-call modifies urb->interval to the rounded value.
-
+++ /dev/null
-The ACM driver works with modems and ISDN TAs that use the USB Abstract
-Control Model standard.
-
-****************************
-Test it:
-Watch out, the driver is not stable and tested. Sync often, make backups,
-most importand: don't blame me...
-
-Create device files:
-mknod /dev/ttyACM0 c 166 0
-mknod /dev/ttyACM1 c 166 1
-mknod /dev/ttyACM2 c 166 2
-mknod /dev/ttyACM3 c 166 3
-Compile a kernel with support for your host controller (uhci only for now!)
-and support for ACM. Boot this kernel. If you connect your device to the
-USB bus you should see messages like the following:
-
-Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
-Jul 19 20:14:29 office kernel: Found 02:09
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office last message repeated 2 times
-Jul 19 20:14:29 office kernel: parsed = 39 len = 67
-Jul 19 20:14:29 office kernel: Expected descriptor 04/09, got 02/09 - skipping
-Jul 19 20:14:29 office kernel: 0 09
-Jul 19 20:14:29 office kernel: 1 02
-Jul 19 20:14:29 office kernel: 2 43
-Jul 19 20:14:29 office kernel: 3 00
-Jul 19 20:14:29 office kernel: 4 02
-Jul 19 20:14:29 office kernel: 5 02
-Jul 19 20:14:29 office kernel: 6 04
-Jul 19 20:14:29 office kernel: 7 60
-Jul 19 20:14:29 office kernel: 8 00
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 02:09
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: Found 04:09
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: Found 05:07
-Jul 19 20:14:29 office kernel: parsed = 67 len = 0
-Jul 19 20:14:29 office kernel: getstringtable
-Jul 19 20:14:29 office kernel: acm_probe
-Jul 19 20:14:29 office kernel: USB ACM found
-
-Watch out for the line:
-Jul 19 20:14:29 office kernel: USB new device connect, assigned device number 1
-and the line:
-Jul 19 20:14:29 office kernel: USB ACM found
-These two lines show that the device was seen by the usb host controller and
-then recognized by the acm driver as a valid device.
-
-If you use a terminal emulation software like minicom with /dev/ttyACM0 you
-should be able to send AT commands to your device and get responses. I've
-been able to do zmodem downloads to another pc. However downloads from one
-ISDN TA to another ISDN TA connected to the same PC didn't work. Don't
-know why. Flow control is not finised after all and i'd guess there might
-be problems on heavily loades PCs. I also did some tests with ppp but i'm
-not finised with this. There might be a chance to get it working. However
-i'd like to know if your device is recognized as an ACM device. I'm also
-interested if the thing is stable or if it crashes.
-(should i say how it crases?)
-
-You should be able to add and remove devices from the bus. The driver will
-always try to fill up unused ttys. This means if you hotplug devices their
-order may have changed after reboot. This is not the behaviour Linus liked
-to see but it's ok for now. (I hope ;-)
-
-Please report your experiences to me:
-fuerst@in.tum.de
-
-***************************
-I've tested it with:
-3Com ISDN Pro TA.
-
-It should work with (That means i know these devices conform to ACM):
-3Com Office Connect Modem
-3Com Sportster USB (I think that's what it's called)
-
-***************************
-Many thanks to 3Com which did not only support me with hardware but also
-with technical support in USB questions. They also allowed me to do tests in
-their lab. Great!
-
-***************************
-Known bugs:
-Flow control not tested (likely not to work)
-Some tty function calls not implemented (putchar, etc...)
-Huge amounts of debug output (compile in [*] Magic SysRq key and press ALT+PRTSCR+0 )
-Not all mem is freed at close (need terminate irq in hcd)
-
-***************************
-Have fun,
- Armin Fuerst
+++ /dev/null
-13 November 1999
-david-b@pacbell.net
-
-This is an overview of how to use the "dc2xx" USB driver with certain
-digital still cameras from Kodak and other vendors.
-
-
-CAMERAS
-
-This driver will mostly be used with Kodak DC-2xx series digital still
-cameras, but it should be trivial to tell it about several non-Kodak
-USB-enabled cameras.
-
-You'll most likely want to hook it up to recent versions of "gPhoto"
-(www.gphoto.org), since version 0.4 and later know how to use it to talk
-to Kodak DC-240 and DC-280 cameras over USB.
-
-In addition the DC-260, DC-265, and DC-290 are currently recognized.
-However, like other cameras using the "Digita OS" (from www.flashpoint.com)
-there is no gPhoto support for this camera. At this writing the best
-known support for these cameras is a Python script that supports image
-downloading from those cameras. (See archives of the linux-usb mailing
-list.) The DC-220 should also work with this driver, given information
-about the USB product IDs. When it becomes available, the HP PhotoSmart
-C500 should also work ... it's another Digita OS camera with USB support.)
-
-It's likely that other digital still cameras can also use this USB driver,
-even if they're not from Kodak and don't use Digita. The reason is that
-most currently known USB still camera protocols treat USB like a faster
-packet-carrying connection than a serial line, which is exactly how this
-driver looks to an application.
-
-
-USB HARDWARE
-
-This has been shown to work on x86 OHCI and UHCI (Intel) chipsets. OHCI has
-been trouble free; not so with UHCI, which was first seen to be happy with
-2.3.24 kernels, and has not been as fast as OHCI.
-
-Note that in some cases changes in BIOS settings may be needed before
-your USB works. At least one user has reported a need for SMP-related
-settings as well.
-
-As yet, no reports have come from Linux users on non-Intel hardware.
-(You could color coordinate your iMac with a DC-240i ... :-)
-
-
-SETUP
-
-Configure in the DC2XX USB driver, and have it in your kernel. Recently I
-compile it right in, but I've done it as a module in the past.
-
-Create a device, perhaps like this (both read and write):
-
- # mknod -m 0666 /dev/kodak c 10 170
-
-That "170" is not formally assigned, and this command may change. If you're
-using a non-Kodak camera, you may prefer another name.
-
-Don't plug in more than one compatible camera at this time. One of them
-will be ignored, but I'd not be sure which one!
-
-
-SANITY TESTING
-
-First: if you've got /proc support, make sure that the driver has hooked
-itself up correctly.
-
- - you should see an entry in /proc/misc for the a Kodak DC-2xx
- minor device number
-
- - you should see an entry in /proc/bus/usb/drivers for "dc2xx",
- if you also enabled USB /proc support.
-
-Second: when you connect your camera to the computer, does it get recognized
-by the driver?
-
- - if you've got /proc/bus/usb/devices, you should see an entry
- something like this. The "ProdID" may be different if you didn't
- plug in a DC-240, but the "Driver=dc2xx" had better be there.
-
- T: Lev=01 Prnt=00 Port=00 Cnt=01 Dev#= 1 Spd=12 MxCh= 0
- D: Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
- P: Vendor=040a ProdID=0120 Rev= 1.08
- C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=100mA
- I: If#= 0 Alt= 0 #EPs= 2 Cls=00(>ifc ) Sub=00 Prot=00 Driver=dc2xx
- E: Ad=01(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
- E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
-
- - if you don't have /proc support for USB, see if "dmesg" output
- tells you that you plugged in your camera.
-
- USB new device connect, assigned device number 1
- Manufacturer: Eastman Kodak Company
- Product: KODAK DC240 Zoom Digital Camera
- USB Camera is connected
- usbcore: dc2xx driver claimed interface c3a68600
- ohci-control thread sleeping
-
-Third: (optional) can you use gPhoto to talk to the camera?
-
- - When you configure your camera, tell it to use "/dev/kodak" (or
- whatever name you used). Right now, gPhoto emits a diagnostic
- message (non-GUI) saying that it since it didn't act like a TTY,
- it's assuming it's got a USB connection.
-
- - With the camera turned on, get the "camera summary". It'll
- talk to the camera -- and tell you you're using USB.
-
-If you got that far, you should be able to use everything fine.
+++ /dev/null
-$Id: README.error-codes,v 1.1 1999/12/14 14:03:02 fliegl Exp $
-
-This is the documentation of (hopefully) all possible error codes (and
-their interpretation) that can be returned from the hostcontroller driver
-and from usbcore.
-
-NOTE:
-The USB_ST_* codes are deferred and are only listed for compatibility, new
-software should use only -E* instead!
-
-
-
-**************************************************************************
-* Error codes returned by usb_submit_urb *
-**************************************************************************
-
-Non-USB-specific:
-
-USB_ST_NOERROR
-0 URB submission went fine
-
--ENOMEM no memory for allocation of internal structures
-
-USB-specific:
-
--ENODEV specified USB-device or bus doesn't exist
-
--ENXIO specified endpoint doesn't exist on the device
-
-USB_ST_URB_INVALID_ERROR
--EINVAL a) Invalid transfer type specified (or not supported)
- b) Invalid interrupt interval (0<=n<256)
- c) more than one interrupt packet requested
-
--EAGAIN a) specified ISO start frame too early
- b) (using ISO-ASAP) too much scheduled for the future
- wait some time and try again.
-
--EFBIG too much ISO frames requested (currently uhci>900)
-
--EPIPE specified pipe-handle is already stalled
-
--EMSGSIZE endpoint message size is zero, do interface/alternate setting
-
-
-**************************************************************************
-* Error codes returned by in urb->status *
-* or in iso_frame_desc[n].status (for ISO) *
-**************************************************************************
-
-USB_ST_NOERROR
-0 Transfer completed successfully
-
-USB_ST_URB_KILLED
--ENOENT URB was canceled by unlink_urb
-
-USB_ST_URB_PENDING
--EINPROGRESS URB still pending, no results yet
- (actually no error until now;-)
-
-USB_ST_BITSTUFF
-USB_ST_INTERNALERROR
--EPROTO a) bitstuff error
- b) unknown USB error
-
-USB_ST_CRC
--EILSEQ CRC mismatch
-
--EPIPE a) babble detect
- b) endpoint stalled
-
-USB_ST_BUFFERUNDERRUN
--ENOST buffer error
-
-USB_ST_NORESPONSE
-USB_ST_TIMEOUT
--ETIMEDOUT transfer timed out, NAK
-
-USB_ST_REMOVED
--ENODEV device was removed
-
-USB_ST_SHORT_PACKET
--EREMOTEIO short packet detected
-
-USB_ST_PARTIAL_ERROR
--EXDEV ISO transfer only partially completed
- look at individual frame status for details
-
-USB_ST_URB_INVALID_ERROR
--EINVAL ISO madness, if this happens: Log off and go home
-
-**************************************************************************
-* Error codes returned by usbcore-functions *
-* (expect also other submit and transfer status codes) *
-**************************************************************************
-
-usb_register():
-USB_ST_NOTSUPPORTED
--EINVAL error during registering new driver
-
-usb_terminate_bulk():
-USB_ST_REMOVED
--ENODEV urb already removed
-
-usb_get_*/usb_set_*():
- All USB errors (submit/status) can occur
-
-
+++ /dev/null
- Linux HID driver v0.8
- (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
- (c) 1999 Andreas Gal <agal@uwsp.edu>
- Sponsored by SuSE
-----------------------------------------------------------------------------
-
-0. Disclaimer
-~~~~~~~~~~~~~
- This program is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2 of the License, or (at your option)
-any later version.
-
- This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-more details.
-
- You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc., 59
-Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- Should you need to contact me, the author, you can do so either by e-mail
-- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
-Ucitelska 1576, Prague 8, 182 00 Czech Republic
-
- For your convenience, the GNU General Public License version 2 is included
-in the package: See the file COPYING.
-
-1. Introduction
-~~~~~~~~~~~~~~~
- This is a driver for USB devices conforming to the USB HID (Human Input
-Device) standard. These devices include namely keyboards, mice and
-joysticks.
-
- However many other devices (monitors, speakers, UPSs ...) also communicate
-through the same protocol, which makes its specification somewhat bloated.
-This isn't a problem, though, because the driver doesn't need to know about
-all the possible devices it can control, and can just parse the protocol and
-leave the rest of the job (for example understanding what the UPS wants to
-say) to the userland.
-
- Because of this, the USB HID driver has two interfaces. One is via the
-proc filesystem, allowing userland applications send and read arbitrary
-reports to and from a connected USB device. The other is via a very simple
-yet generic input device driver, which dispatches input events (keystrokes,
-mouse or joystick movements) to specific, backward compatible userland
-interfaces. This way a PS/2 mouse, an AT keyboard or a Linux joystick driver
-interface are emulated, and allow applications to immediately work with USB
-mice, USB keyboards and USB joysticks without any changes.
-
- The input driver is aimed for a little more than USB device handling in
-the future, though. It's generic enough so that it can be used for any
-mouse, keyboard or joystick (and more, of course). A PS/2 mouse driver, a
-serial mouse, Sun mouse, and most of the busmouse drivers were rewritten to
-use this as well as the AT keyboard and Sun keyboard drivers. This will
-hopefully allow conversion of all Linux keyboard and mouse and joystick
-drivers to this scheme.
-
- This effort has it's home page at:
-
- http://www.suse.cz/development/input/
-
-You'll find both the latest HID driver and the complete Input driver there.
-There is also a mailing list for this:
-
- listproc@atrey.karlin.mff.cuni.cz
-
-Send "subscribe linux-joystick Your Name" to subscribe to it.
-
-2. Usage
-~~~~~~~~
- Since the driver comes with recent 2.3 kernels, all that's needed to use
-it is to enable it either as a module or compiled-in into the kernel.
-
- After that, after reboot (and possibly also inserting the USB and HID
-modules) the following will happen:
-
-* If you selected keyboard support, all USB keystrokes will be also routed
- to the Linux keyboard driver as if being input through the ordinary system
- keyboard.
-
-* If you selected mouse support, there will be (one or more) simulated PS/2
- mouse devices on major 10, minor 32, 33 and more. These simulated mice can
- in addition to a standard 3-button PS/2 mouse behave like MS Intellimice,
- with a wheel. If you want to use the wheel, just specify '-t imps2' to gpm
- and 'Protocol "ImPS/2"' to X, and it will work. A single emulated mouse
- device can be open by any number of processes (unlike the /dev/psaux), and
- for each of them the emulation is separate, each can use a different mode.
- The mousedev driver, which emulates the mice, can also emulate a Genius
- NewScroll 5 buttons-and-a-wheel mouse, if you set it to a Genius PS/2
- mode ('-t netmouse' 'Protocol "NetMousePS/2"'). However, not gpm, nor X
- can decode the 5 buttons yet, so this isn't very useful right now.
-
-* If you selected joystick support, the driver will take over major 15, the
- joystick major number, and will emulate joysticks on it. This means the
- normal joystick driver can't be used together with it (now, after the
- normal joystick drivers are converted to the input scheme, all will work
- nicely together). Also, you'll probably need to calibrate your joystick
- manually ('man jscal') to be able to use it, because the USB
- autocalibration is far from perfect yet.
-
-* If you selected event device support, there will be devices on major 10,
- minors 64, 65 and more for each input device connected through this
- driver. These devices output raw events the input driver dispatches. Each
- has a timestamp. This hopefully will be THE way X will talk to keyboard
- and mice, because it's hardware independent, and not limited by existing
- de-facto standards.
-
-3. Verifying if it works
-~~~~~~~~~~~~~~~~~~~~~~~~
- Typing a couple keys on the keyboard should be enough to check that a USB
-keyboard works and is correctly connected to the kernel keyboard driver.
-
- Doing a cat /dev/hidmouse (c, 10, 32) will verify that a mouse is also
-emulated, characters should appear if you move it.
-
- You can test the joystick emulation with the 'jstest' utility, available
-in the joystick package (see Documentation/joystick.txt).
-
- You can test the event devics with the 'evtest' utitily available on the
-input driver homepage (see the URL above).
-
-4. FAQ
-~~~~~~
-Q: Why aren't any questions here yet?
-A: Because none were frequent enough yet.
-
-5. Event interface
-~~~~~~~~~~~~~~~~~~
- Should you want to add event device support into any application (X, gpm,
-svgalib ...) I (vojtech@suse.cz) will be happy to provide you any help I
-can. Here goes a description of the current state of things, which is going
-to be extended, but not changed incompatibly as time goes:
-
- You can use blocking and nonblocking reads, also select() on the
-/dev/inputX devices, and you'll always get a whole number of input events on
-a read. Their layout is:
-
-struct input_event {
- struct timeval time;
- unsigned short type;
- unsigned short code;
- unsigned int value;
-};
-
- 'time' is the timestamp, it returns the time at which the event happened.
-Type is for example EV_REL for relative momement, REL_KEY for a keypress or
-release. More types are defined in include/linux/input.h.
-
- 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
-list is in include/linux/input.h.
-
- 'value' is the value the event carries. Either a relative change for
-EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
-release, 1 for keypress and 2 for autorepeat.
-
-6. Proc interface
-~~~~~~~~~~~~~~~~~
- For HID-specific devices there is also the /proc interface. It isn't
-present in this release yet, though, so it's description will appear here
-together with the code in the driver.
+++ /dev/null
-
-The OHCI HCD layer is a simple but nearly complete implementation of what the
-USB people would call a HCD for the OHCI.
- (ISO comming soon, Bulk, INT u. CTRL transfers enabled)
-It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
-The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers.
-
-- Roman Weissgaerber <weissg@vienna.at>
-
- * v4.0 1999/08/18 removed all dummy eds, unlink unused eds, code cleanup, bulk transfers
- * v2.1 1999/05/09 ep_addr correction, code cleanup
- * v0.2.0 1999/05/04
- * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
- * virtual root hub is now an option,
- * memory allocation based on kmalloc and kfree now, simple Bus error handling,
- * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
- *
- * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
- * from Greg Smith (ohci.c): better reset ohci-controller handling, hub
- *
- * v0.1.0 1999/04/27 initial release
-
-to remove the module try:
-rmmod usb-ohci-hcd
-
-Features:
-- virtual root hub, all basic hub descriptors and commands (state: complete)
- this is an option now (v0.2.0)
- #define CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
- default is with.
- (at the moment: the Virtual Root Hub is included automatically)
-
- files: ohci-root-hub.c, ohci-root-hub.h
-
-
-- Endpoint Descriptor (ED) handling more static approach
- (EDs should be allocated in parallel to the SET CONFIGURATION command and they live
- as long as the function (device) is alive or another configuration is choosen.
- In the HCD layer the EDs has to be allocated manually either by calling a subroutine
- or by sending a USB root hub vendor specific command to the virtual root hub.
- At the alternate linux usb stack EDs will be added (allocated) at their first use.
- ED will be unlinked from the HC chains if they are not bussy.
-
- files: ohci-hcd.c ohci-hcd.h
- routines: (do not use for drivers, use the top layer alternate usb commands instead)
-
- int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1,
- int interval, int load, f_handler handler, int ep_size, int speed)
- adds an endpoint, (if the endpoint already exists some parameters will be updated)
-
- int usb_ohci_rm_ep( )
- removes an endpoint and all pending TDs of that EP
-
- usb_ohci_rm_function( )
- removes all Endpoints of a function (device)
-
-- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
- The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
- to take care of buffer allocation.
- files: ohci-hcd.c ohci-hcd.h
-
- There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
-
- int ohci_trans_req(struct ohci * ohci, hcd_ed, int ctrl_len, void *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
-
- CTRL: ctrl, ctrl_len ... cmd buffer
- data, data_len ... data buffer (in or out)
- INT, BULK: ctrl = NULL, ctrl_len=0,
- data, data_len ... data buffer (in or out)
- ISO: tbd
-
- There is no buffer reinsertion done by the internal HCD function.
- (The interface layer does this for a INT-pipe on request.)
- If you want a transfer then you have to
- provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
- you can send as many as you like. They should come back by the callback f_handler in
- the same order (for each endpoint, not globally) If an error occurs all
- queued transfers of an endpoint will return unsent. They will be marked with an error status.
-
- e.g double-buffering for int transfers:
-
- ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
- ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
-
- and when a data0 packet returns by the callback f_handler requeue it:
- ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
- and when a data1 packet returns by the callback f_handler requeue it:
- ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
-
- lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
- The alternate usb uses them for dev_id and usb_device_irq handler.
-
-
-- Done list handling: returns the requests (callback f_handler in ED) and does
- some error handling, root-hub request dequeuing
- (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
-
-
+++ /dev/null
--------------------------------------------------------------------------------
-Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC
--------------------------------------------------------------------------------
-
-INTRODUCTION:
-
-This is a preliminary version of my OV511 Linux device driver. At the moment,
-it does not do much more than detect the chip and initialize it. As trivial
-as this sounds, it represents many hours of my work. Since OmniVision refused
-to release the full specs to me, I had to write code to probe out the register
-read/write commands. Some code is in place to allow a frame to be grabbed, but
-it is nowhere near complete.
-
-SUPPORTED CAMERAS:
-____________________________________________
-Manufacturer | Model | Custom ID
------------------+--------------+-----------
-D-Link | DSB-C300 | 3
-Creative Labs | WebCam 3 | 21
---------------------------------------------
-
-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()
-
-WHAT YOU NEED:
-
-- If you want to help with the development, get the chip's specification docs at
- http://www.ovt.com/omniusbp.html
-
-- A Video4Linux compatible frame grabber program (I recommend vidcat)
- (see: http://www.exploits.org/v4l/ )
-
-WHAT NEEDS TO BE DONE:
-
-In short, a lot.
-
-UPDATE:
-Currently, the control messages are working fine ("vendor commands"; for
-reading and writing the OV511 registers.) The I2C bus commands for reading and
-writing the camera (OV7610) registers are implemented and working, with at least
-one person's camera. The isochronous-in endpoint for video data is finally
-producing data, but since ov511_parse_data() is not implemented you will not see
-a picture yet.
-
-Support for specific CCD's will have to be implemented as well (such as the
-OV7610.)
-
-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.
-
-HOW TO CONTACT ME:
-
-You can email me at mmcclelland@delphi.com . Please prefix the subject line
-with "OV511: " so that I am certain to notice your message.
-
-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 and ISOC
-working.
+++ /dev/null
-Oct 19, 1999
-
-CHANGES
-
-- Ammended for linux-2.3.22+
-- Appended hp_scan.c to end of this README
-- Removed most references to HP
-
-
-OVERVIEW
-
-This README will address issues regarding how to configure the kernel
-to access a USB scanner. Although the driver was originally conceived
-for USB HP scanners, it's general enough so that it can be used with
-other scanners. Also, one can now pass the USB Vendor and
-Product ID's using module parameters for unknown scanners. Refer to
-the document README.scanner_hp_sane for guidance on how to configure
-SANE to use a USB HP Scanner.
-
-
-ADDITIONAL INFORMATION
-
-http://www.linux-usb.org/
-http://www.dynamine.net/linux-usb/HOWTO/
-
-
-REQUIREMENTS
-
-A host with a USB port. Ideally, either a UHCI (Intel) or OHCI
-(Compaq and others) hardware port should work. However, I've only
-been able to really use an OHCI controller. I did have access to a
-system with a UHCI controller but some very limited testing did not
-produce satisfactory results. Luke Ordelmans
-<postbus@ordelmans.demon.nl> has reported success using the UHCI host
-controller with kernel 2.3.18 and a ChainTech motherboard. Here
-lately I've been having better success with the ohci-hcd driver. But
-since Linux USB support is still in a state of constant development
-that may change at a later date. I am confident that eventually all
-the host contollers will perform without incident.
-
-A Linux kernel with USB support (preferably linux-2.3.18+)
-
-A Linux kernel with USB Scanner support.
-
-
-CONFIGURATION
-
-Using `make menuconfig` or your prefered method for configuring the
-kernel, select 'Support for USB', 'OHCI/OHCI-HCD/UHCI' depending on
-your hardware, 'USB hub support', and 'USB Scanner support'. Compile
-and install the modules (you may need to execute `depmod -a` to update
-the module dependencies). Testing was performed only as modules,
-YMMV.
-
-Add a device for the USB scanner:
- linux-2.3.22 and above: `mknod /dev/usbscanner c 180 48`
- linux-2.3.21 and below: `mknod /dev/usbscanner c 16 1`
-
-Set appropriate permissions for /dev/usbscanner (don't forget about
-group and world permissions). Both read and write permissions are
-required for proper operation.
-
-Load the appropriate modules (if compiled as modules):
-
- OHCI:
- modprobe usb-ohci
- modprobe scanner
-
- OHCI-HCD:
- modprobe usb-ohci-hcd
- modprobe hub
- modprobe scanner
-
- UHCI:
- modprobe usb-uhci
- modprobe hub (don't know if this is required or not)
- modprobe scanner
-
-That's it. SANE should now be able to access the device.
-
-There is a small test program (hp_scan.c -- appended below) that can
-be used to test the scanner device if it's an HP scanner that supports
-SCL. Its purpose is to test the driver without having to
-retrieve/configure SANE. Hp_scan.c will scan the entire bed and put
-the output into a file called 'out.dat' in the current directory. The
-data in the file is raw data so it's not very useful for imaging.
-
-
-MODULE PARAMETERS
-
-If you have a device that wish to experiment with or try using this
-driver with, but the Vendor and Product ID's are not coded in, don't
-despair. If the driver was compiled as a module, you can pass options
-to the driver. Simply add 'options scanner vendor=0x####
-product=0x****' to the conf.modules/modules.conf file replacing the
-#'s and the *'s with the correct ID's. The ID's can be retrieved from
-the messages file or using `cat /proc/bus/usb/devices` if USB /proc
-support was selected during kernel configuration.
-
-
-BUGS
-
-If you encounter any problems feel free to drop me an email.
-
-David /\/elson
-dnelson@jump.net
-http://www.jump.net/~dnelson
-
---------------- snip -- hp_scan.c -- snip ---------------
-/*
-
-This is a really crude attempt at writing a short test program. It's
-mostly only to be used to test connectivity with USB HP scanners that
-understand SCL. Currently, the supported models are 4100C, 5200C,
-6200C, and the 6300C. Note that the 4200C is *NOT* acceptable.
-
-Copyright (C) David E. Nelson <dnelson@jump.net>, 1999
-
-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.
-
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <error.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-/*
- Gray Output produces about a 8945400 byte file.
- Color Output produces a 26836200 byte file.
-
- To compile: gcc -o hp_scan hp_scan.c
-*/
-
-// #define COLOR /* Undef to scan GrayScale */
-
-int send_cmd(int, const char *, int);
-int read_cmd(int, char *, int);
-
-int
-main(void) {
-
- ssize_t cnt = 0, total_cnt = 0;
-
- FILE *fpout;
-
- int fp;
- int data_size = 32768;
-
- char *data;
-
- static char reset_cmd[] = {'\x1b','E'};
-
-#ifdef COLOR
- static char data_type_cmd[] = {'\x1b','*','a','5','T'}; /* Color */
- static char data_width_cmd[] = {'\x1b','*','a','2','4','G'}; /* 24 Bit Color */
-#else
- static char data_type_cmd[] = {'\x1b','*','a','4','T'}; /* Gray */
- static char data_width_cmd[] = {'\x1b','*','a','8','G'}; /* 8 Bit Gray */
-#endif
-
- static char query_cmd[] = {'\x1b', '*', 's', '2', '5', '7', 'E'};
- static char start_scan_cmd[] = {'\x1b','*','f','0','S'};
-
- if(!(data=malloc(data_size))) {
- perror("malloc failed");
- exit (1);
- }
-
- if((fp=open("/dev/usbscanner", O_RDWR)) < 0) {
- perror("Unable to open scanner device");
- exit (1);
- }
-
- if((fpout=fopen("out.dat", "w+")) == NULL) {
- perror("Unable to open ouput file");
- exit(1);
- }
-
- send_cmd(fp, reset_cmd, sizeof(reset_cmd));
- send_cmd(fp, data_type_cmd, sizeof(data_type_cmd));
- send_cmd(fp, data_width_cmd, sizeof(data_width_cmd));
- send_cmd(fp, start_scan_cmd, sizeof(start_scan_cmd));
-
- while ((cnt = read(fp, data, data_size)) > 0) {
- printf("Read: %u\n", cnt);
- if(fwrite(data, sizeof(char), cnt, fpout) < 0) {
- perror("Write to output file failed");
- exit (1);
- }
- total_cnt += cnt;
- }
- if (cnt < 0) {
- perror("Read from scanner failed");
- exit (1);
- }
-
- printf("\nRead %lu bytes.\n", total_cnt);
-
- send_cmd(fp, reset_cmd, sizeof(reset_cmd));
-
- close(fp);
- fclose(fpout);
- return (0);
-}
-
-int
-send_cmd(int fp, const char * cmd, int length) {
-
- int result;
- int x;
-
- if((result = write(fp, cmd, length)) != length) {
- printf ("Write warning: %d bytes requested, %d written\n");
- } else if (result < 0) {
- perror ("send_cmd failure");
- exit (1);
- }
- return (result);
-}
-
-int
-read_cmd(int fp, char * response, int length) {
-
- return read(fp, response, length);
-
-}
+++ /dev/null
-Oct. 19, 1999
-
-CHANGES
-
-- Ammended for Linux-2.3.22+
-
-
-INTRODUCTION
-
-This document will hopefully provide enough info on how to get SANE
-working with a Hewlett Packard USB capable scanner using the USB
-interface. The majority of HP Scanners support the Scanner Control
-Language (SCL) which is both published by HP and supported by SANE.
-The only HP Scanner that I'm aware of that does not support SCL is the
-4200C. All other HP scanners with USB interfaces should work (4100C,
-5200C, 6200C, and 6300C). Of course as HP releases new scanners this
-information may change.
-
-
-REQUIREMENTS
-
-In order to get this running you'll need USB support in your kernel in
-addition to USB Scanner support. Please refer to README.scanner
-for issues pertaining to Linux USB and USB Scanner support.
-
-An installed version of SANE which is available from
-http://www.mostang.com/sane/. Testing has been performed using
-version SANE-1.0.1. For instructions on building and installing SANE,
-refer to the various README files within the SANE distribution.
-
-
-OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW?
-
-NOTE: $INSTALL_DIR is the location where SANE was installed. It may
-be /usr/local, /usr, /opt or somewhere else. If you don't know, ask
-your system administrator.
-
-1) Make sure that you have the libsane-hp.* libraries under the
-$INSTALL_DIR/lib/sane/ directory. If you don't, then the HP backend
-was either not compiled or installed properly.
-
-2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
-files: dll.conf, hp.conf.
-
- dll.conf: Make sure that the 'hp' entry is present and uncommented.
-
- hp.conf: This should contain two lines:
-
- /dev/usbscanner
- option connect-device
-
-3) You should now be able to use SANE (xscanimage or scanimage).
-
-Don't forget to read any relevant man pages regarding the usage of
-SANE. If you have other entries uncommented in dll.conf, you may have
-to specify the device to (x)scanimage. Again, `man` is your friend.
-The xscanimage (1) man page has info on how to get 'The Gimp' to work
-with xscanimage. Note that Gimp support must be compiled into SANE
-for it work. If you are dealing with a RedHat system, this means that
-you'll also need to install the gimp-devel rpm package.
-
-NOTE: The issues regarding core dumping by (x)scanimage have (or seem
-to be thus far) been resolved with version 0.2+ of the USB scanner
-driver which should be available in linux-2.3.23. If you notice
-otherwise, please contact me.
-
-David /\/elson
-dnelson@jump.net
-http://www.jump.net/~dnelson
+++ /dev/null
-This serial driver currently only works with the Belkin and Peracom USB
-Serial devices. It should also work for the Etek converter, but I do
-not know the vendor id and device id of that device (if anyone does,
-please let me know.)
-
-If your device is not compatible with the above models, you can try
-out the "generic" interface. This interface does not provide any type
-of control messages sent to the device, and does not support any kind
-of device flow control. All that is required of your device is that
-it has at least one bulk in endpoint, or one bulk out endpoint.
-To enable the driver to recognize your device, build the driver as
-a module and load it by the following invocation:
- insmod usb-serial.o vendor=0x#### product=0x####
-where the #### is replaced with the hex representation of your device's
-vendor id and product id.
-
-The driver can handle enumerating the device, and sending and receiving
-data from the converter. However, since I do not have a spec for the Belkin,
-Peracom, and eTek devices, and the raw dumps from the Win98 driver are
-confusing, and eTek keeps giving me the run around, no control signals are
-currently handled, and the data will most likely come through on a baud
-rate that you are not expecting. So if you have these devices, do not
-expect the correct data to show up at either end.
-
-The major number that the driver uses is 188 so to use the driver, create
-the following nodes:
-mknod /dev/ttyUSB0 c 188 0
-mknod /dev/ttyUSB1 c 188 1
-mknod /dev/ttyUSB2 c 188 2
-mknod /dev/ttyUSB3 c 188 3
-
-then plug in a device and use your friendly terminal program to see what
-happens.
-
-If anyone has any problems getting the device to enumerate, or data to
-flow through it, please contact me.
-
-
-
-greg k-h
-greg@kroah.com
-
+++ /dev/null
-Specification and Internals for the New UHCI Driver (Whitepaper...)
-
- brought to you by
-
- Georg Acher, acher@in.tum.de (executive slave) (base guitar)
- Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
- Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
-
- $Id: README.uhci,v 1.1 1999/12/14 14:03:02 fliegl Exp $
-
-This document and the new uhci sources can be found on
- http://hotswap.in.tum.de/usb
-
-1. General issues
-
-1.1 Why a new UHCI driver, we already have one?!?
-
-Correct, but its internal structure got more and more mixed up by the (still
-ongoing) efforts to get isochronous transfers (ISO) to work.
-Since there is an increasing need for reliable ISO-transfers (especially
-for USB-audio needed by TS and for a DAB-USB-Receiver build by GA and DF),
-this state was a bit unsatisfying in our opinion, so we've decided (based
-on knowledge and experiences with the old UHCI driver) to start
-from scratch with a new approach, much simpler but at the same time more
-powerful.
-It is inspired by the way Win98/Win2000 handles USB requests via URBs,
-but it's definitely 100% free of MS-code and doesn't crash while
-unplugging an used ISO-device like Win98 ;-)
-Some code for HW setup and root hub management was taken from the
-original UHCI driver, but heavily modified to fit into the new code.
-The invention of the basic concept, and major coding were completed in two
-days (and nights) on the 16th and 17th of October 1999, now known as the
-great USB-October-Revolution started by GA, DF, and TS ;-)
-
-Since the concept is in no way UHCI dependant, we hope that it will also be
-transfered to the OHCI-driver, so both drivers share a common API.
-
-1.2. Advantages and disadvantages
-
-+ All USB transfer types work now!
-+ Asynchronous operation
-+ Simple, but powerful interface (only two calls for start and cancel)
-+ Easy migration to the new API, simplified by a compatibility API
-+ Simple usage of ISO transfers
-+ Automatic linking of requests
-+ ISO transfers allow variable length for each frame and striping
-+ No CPU dependent and non-portable atomic memory access, no asm()-inlines
-+ Tested on x86 and Alpha
-
-- Rewriting for ISO transfers needed
-
-1.3. Is there some compatibility to the old API?
-
-Yes, but only for control, bulk and interrupt transfers. We've implemented
-some wrapper calls for these transfer types. The usbcore works fine with
-these wrappers. For ISO there's no compatibility, because the old ISO-API
-and its semantics were unnecessary complicated in our opinion.
-
-1.4. What's really working?
-
-As said above, CTRL und BULK already work fine even with the wrappers,
-so legacy code wouldn't notice the change.
-Regarding to Thomas, ISO transfers now run stable with USB audio.
-INT transfers (e.g. mouse driver) work fine, too.
-
-1.5. Are there any bugs?
-
-No ;-)
-Hm...
-Well, of course this implementation needs extensive testing on all available
-hardware, but we believe that any fixes shouldn't harm the overall concept.
-
-1.6. What should be done next?
-
-A large part of the request handling seems to be identical for UHCI and
-OHCI, so it would be a good idea to extract the common parts and have only
-the HW specific stuff in uhci.c. Furthermore, all other USB device drivers
-should need URBification, if they use isochronous or interrupt transfers.
-One thing missing in the current implementation (and the old UHCI driver)
-is fair queueing for BULK transfers. Since this would need (in principle)
-the alteration of already constructed TD chains (to switch from depth to
-breadth execution), another way has to be found. Maybe some simple
-heuristics work with the same effect.
-
----------------------------------------------------------------------------
-
-2. Internal structure and mechanisms
-
-To get quickly familiar with the internal structures, here's a short
-description how the new UHCI driver works. However, the ultimate source of
-truth is only uhci.c!
-
-2.1. Descriptor structure (QHs and TDs)
-
-During initialization, the following skeleton is allocated in init_skel:
-
- framespecific | common chain
-
-framelist[]
-[ 0 ]-----> TD --> TD -------\
-[ 1 ]-----> TD --> TD --------> TD ----> QH -------> QH -------> QH ---> NULL
- ... TD --> TD -------/
-[1023]-----> TD --> TD ------/
-
- ^^ ^^ ^^ ^^ ^^ ^^
- 1024 TDs for 7 TDs for 1 TD for Start of Start of End Chain
- ISO INT (2-128ms) 1ms-INT CTRL Chain BULK Chain
-
-For each CTRL or BULK transfer a new QH is allocated and the containing data
-transfers are appended as (vertical) TDs. After building the whole QH with its
-dangling TDs, the QH is inserted before the BULK Chain QH (for CTRL) or
-before the End Chain QH (for BULK). Since only the QH->next pointers are
-affected, no atomic memory operation is required. The three QHs in the
-common chain are never equipped with TDs!
-
-For ISO or INT, the TD for each frame is simply inserted into the apropriate
-ISO/INT-TD-chain for the desired frame. The 7 skeleton INT-TDs are scattered
-among the 1024 frames similar to the old UHCI driver.
-
-For CTRL/BULK/ISO, the last TD in the transfer has the IOC-bit set. For INT,
-every TD (there is only one...) has the IOC-bit set.
-
-Besides the data for the UHCI controller (2 or 4 32bit words), the descriptors
-are double-linked through the .vertical and .horizontal elements in the
-SW data of the descriptor (using the double-linked list structures and
-operations), but SW-linking occurs only in closed domains, i.e. for each of
-the 1024 ISO-chains and the 8 INT-chains there is a closed cycle. This
-simplifies all insertions and unlinking operations and avoids costly
-bus_to_virt()-calls.
-
-2.2. URB structure and linking to QH/TDs
-
-During assembly of the QH and TDs of the requested action, these descriptors
-are stored in urb->urb_list, so the allocated QH/TD descriptors are bound to
-this URB.
-If the assembly was successful and the descriptors were added to the HW chain,
-the corresponding URB is inserted into a global URB list for this controller.
-This list stores all pending URBs.
-
-2.3. Interrupt processing
-
-Since UHCI provides no means to directly detect completed transactions, the
-following is done in each UHCI interrupt (uhci_interrupt()):
-
-For each URB in the pending queue (process_urb()), the ACTIVE-flag of the
-associated TDs are processed (depending on the transfer type
-process_{transfer|interrupt|iso}()). If the TDs are not active anymore,
-they indicate the completion of the transaction and the status is calculated.
-Inactive QH/TDs are removed from the HW chain (since the host controller
-already removed the TDs from the QH, no atomic access is needed) and
-eventually the URB is marked as completed (OK or errors) and removed from the
-pending queue. Then the next linked URB is submitted. After (or immediately
-before) that, the completion handler is called.
-
-2.4. Unlinking URBs
-
-First, all QH/TDs stored in the URB are unlinked from the HW chain.
-To ensure that the host controller really left a vertical TD chain, we
-wait for one frame. After that, the TDs are physically destroyed.
-
-2.5. URB linking and the consequences
-
-Since URBs can be linked and the corresponding submit_urb is called in
-the UHCI-interrupt, all work associated with URB/QH/TD assembly has to be
-interrupt save. This forces kmalloc to use GFP_ATOMIC in the interrupt.
/* for ISOC transfers calculate start frame index */
if (urb->transfer_flags & USB_ISO_ASAP) {
urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1):
- (ohci->hcca.frame_no + 10)) & 0xffff;
+ (le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff;
}
td_submit_urb (urb); /* fill the TDs and link it to the ed */
spin_unlock_irqrestore (&usb_ed_lock, flags);
current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout (HZ / 10); /* wait until all TDs are deleted */
- remove_wait_queue (&op_wakeup, &wait);
+ if(schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
+ remove_wait_queue (&op_wakeup, &wait);
+ else
+ printk (KERN_ERR MODSTR "unlink URB timeout!\n");
} else
urb_rm_priv (urb);
usb_dec_dev_use (urb->dev);
{
ohci_t * ohci = usb_dev->bus->hcpriv;
- return ohci->hcca.frame_no;
+ return le16_to_cpu (ohci->hcca.frame_no);
}
/*-------------------------------------------------------------------------*/
writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
writel (OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */
- frame = ohci->hcca.frame_no & 0x1;
+ frame = le16_to_cpu (ohci->hcca.frame_no) & 0x1;
ed->ed_rm_list = ohci->ed_rm_list[frame];
ohci->ed_rm_list[frame] = ed;
writel (0, &ohci->regs->ed_controlhead);
writel (0, &ohci->regs->ed_bulkhead);
- writel (virt_to_bus(&ohci->hcca), &ohci->regs->hcca); /* a reset clears this */
+ writel (virt_to_bus (&ohci->hcca), &ohci->regs->hcca); /* a reset clears this */
fminterval = 0x2edf;
writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
struct ohci_regs * regs = ohci->regs;
int ints;
- if ((ohci->hcca.done_head != 0) && !(ohci->hcca.done_head & 0x01)) {
+ if ((ohci->hcca.done_head != 0) && !(le32_to_cpu (ohci->hcca.done_head) & 0x01)) {
ints = OHCI_INTR_WDH;
} else {
if ((ints = (readl (®s->intrstatus) & readl (®s->intrenable))) == 0)
return;
}
- dbg (KERN_DEBUG MODSTR "Interrupt: %x frame: %x \n", ints, ohci->hcca.frame_no);
+ dbg (KERN_DEBUG MODSTR "Interrupt: %x frame: %x \n", ints, le16_to_cpu (ohci->hcca.frame_no));
if (ints & OHCI_INTR_WDH) {
writel (OHCI_INTR_WDH, ®s->intrdisable);
}
if (ints & OHCI_INTR_SF) {
- unsigned int frame = (ohci->hcca.frame_no) & 1;
+ unsigned int frame = le16_to_cpu (ohci->hcca.frame_no) & 1;
writel (OHCI_INTR_SF, ®s->intrdisable);
if (ohci->ed_rm_list[!frame] != NULL) {
dl_del_list (ohci, !frame);
* Version History:
* Version 1.00 - Initial version
*/
-
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
#define __NO_VERSION__
#include "usb.h"
#include "ov511.h"
+#define OV511_I2C_RETRIES 3
+
/* Video Size 384 x 288 x 3 bytes for RGB */
-#define MAX_FRAME_SIZE (384 * 288 * 3)
+#define MAX_FRAME_SIZE (320 * 240 * 3)
// FIXME - Force CIF to make some apps happy for the moment. Should find a
// better way to do this.
-#define DEFAULT_WIDTH 384
-#define DEFAULT_HEIGHT 288
+#define DEFAULT_WIDTH 320
+#define DEFAULT_HEIGHT 240
char kernel_version[] = UTS_RELEASE;
vfree(mem);
}
-int usb_ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value)
+int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value)
{
int rc;
USB_TYPE_CLASS | USB_RECIP_DEVICE,
0, (__u16)reg, &value, 1, HZ);
- PDEBUG("reg write: 0x%X:0x%X\n", reg, value);
+ PDEBUG("reg write: 0x%02X:0x%02X\n", reg, value);
return rc;
}
/* returns: negative is error, pos or zero is data */
-int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg)
+int ov511_reg_read(struct usb_device *dev, unsigned char reg)
{
int rc;
unsigned char buffer[1];
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE,
0, (__u16)reg, buffer, 1, HZ);
- PDEBUG("reg read: 0x%X:0x%X\n", reg, buffer[0]);
+ PDEBUG("reg read: 0x%02X:0x%02X\n", reg, buffer[0]);
if(rc < 0)
return rc;
return buffer[0];
}
-int usb_ov511_cam_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value)
+int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char value)
{
- int rc;
-
- // Three byte write cycle
-
- // Set slave ID (This might only need to be done once)
- // (CAMERA SPECIFIC (OV7610/OV7110))
- rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
- OV7610_I2C_WRITE_ID);
- if (rc < 0) return rc;
-
- // Select camera register (I2C sub-address)
- rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);
- if (rc < 0) return rc;
+ int rc, retries;
- // Write "value" to I2C data port of OV511
- rc = usb_ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value);
- if (rc < 0) return rc;
-
- // FIXME - should ensure bus is idle before continuing
-
- // Initiate 3-byte write cycle
- rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01);
+ PDEBUG("i2c write: 0x%02X:0x%02X\n", reg, value);
+ /* Three byte write cycle */
+ for(retries = OV511_I2C_RETRIES;;) {
+ /* Select camera register */
+ rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);
+ if (rc < 0) return rc;
- return rc;
+ /* Write "value" to I2C data port of OV511 */
+ rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value);
+ if (rc < 0) return rc;
+
+ /* Initiate 3-byte write cycle */
+ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01);
+ if (rc < 0) return rc;
+
+ do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+ while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+ if (rc < 0) return rc;
+
+ if((rc&2) == 0) /* Ack? */
+ break;
+
+ /* I2C abort */
+ ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+
+ if (--retries < 0) return -1;
+ }
+
+ return 0;
}
/* returns: negative is error, pos or zero is data */
-int usb_ov511_cam_reg_read(struct usb_device *dev, unsigned char reg)
+int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
{
- int rc;
+ int rc, value, retries;
- // Two byte write cycle
-
- // Set slave ID (This might only need to be done once)
- // (CAMERA SPECIFIC (OV7610/OV7110))
- rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, OV7610_I2C_WRITE_ID);
- if (rc < 0) return rc;
-
- // Select camera register (I2C sub-address)
- rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
- if (rc < 0) return rc;
-
- // Initiate 2-byte write cycle
- rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);
- if (rc < 0) return rc;
-
- // Two byte read cycle
-
- // Set slave ID (This might only need to be done once)
- // (CAMERA SPECIFIC (OV7610/OV7110))
- rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
- OV7610_I2C_READ_ID);
- if (rc < 0) return rc;
-
- // Initiate 2-byte read cycle
- rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
+ /* Two byte write cycle */
+ for(retries = OV511_I2C_RETRIES;;) {
+ /* Select camera register */
+ rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
+ if (rc < 0) return rc;
+
+ /* Initiate 2-byte write cycle */
+ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);
+ if (rc < 0) return rc;
+
+ do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+ while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+ if (rc < 0) return rc;
+
+ if((rc&2) == 0) /* Ack? */
+ break;
+
+ /* I2C abort */
+ ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+
+ if (--retries < 0) return -1;
+ }
+
+ /* Two byte read cycle */
+ for(retries = OV511_I2C_RETRIES;;) {
+ /* Initiate 2-byte read cycle */
+ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
+ if (rc < 0) return rc;
+
+ do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+ while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+ if (rc < 0) return rc;
+
+ if((rc&2) == 0) /* Ack? */
+ break;
+
+ /* I2C abort */
+ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+ if (rc < 0) return rc;
+
+ if (--retries < 0) return -1;
+ }
+
+ value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
+ PDEBUG("i2c read: 0x%02X:0x%02X\n", reg, value);
+
+ /* This is needed to make ov511_i2c_write() work */
+ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
if (rc < 0) return rc;
- // FIXME - should check I2C bus status here before reading data!
-
- // Write "value" to I2C data port of OV511
- return usb_ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
+ return (value);
}
-int usb_ov511_reset(struct usb_device *dev, unsigned char reset_type)
+int ov511_reset(struct usb_device *dev, unsigned char reset_type)
{
int rc;
PDEBUG("Reset: type=0x%X\n", reset_type);
- rc = usb_ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
+ rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
if (rc < 0)
printk(KERN_ERR "ov511: reset: command failed\n");
- rc = usb_ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
+ rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
if (rc < 0)
printk(KERN_ERR "ov511: reset: command failed\n");
return rc;
}
-int usb_ov511_set_packet_size(struct usb_ov511 *ov511, int size)
+int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
{
int alt, multiplier, err;
break;
case 993:
alt = 1;
- multiplier = 32;
+ multiplier = 31;
break;
case 768:
alt = 2;
break;
case 769:
alt = 3;
- multiplier = 25;
+ multiplier = 24;
break;
case 512:
alt = 4;
break;
case 513:
alt = 5;
- multiplier = 17;
+ multiplier = 16;
break;
case 257:
alt = 6;
- multiplier = 9;
+ multiplier = 8;
break;
case 0:
alt = 7;
return -EINVAL;
}
- err = usb_ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
+ err = ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
multiplier);
if (err < 0) {
printk(KERN_ERR "ov511: Set packet size: Set FIFO size ret %d\n",
}
// FIXME - Should we only reset the FIFO?
- if (usb_ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0)
+ if (ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0)
return -ENOMEM;
return 0;
/* How much data is left in the scratch buf? */
#define scratch_left(x) (ov511->scratchlen - (int)((char *)x - (char *)ov511->scratch))
-// FIXME - Useless stub
-static void ov511_parse_data(struct usb_ov511 *ov511)
-{
- PDEBUG("ov511_parse_data not implemented\n"); // TEMPORARY CODE
-}
-
-static int ov511_compress_isochronous(struct usb_ov511 *ov511, urb_t *urb)
+static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
{
- unsigned char *cdata, *data;
+ unsigned char *cdata;
int i, totlen = 0;
+ int aPackNum[10];
+ struct ov511_frame *frame;
+
+ if (ov511->curframe == -1) {
+ return 0;
+ }
- data = ov511->scratch + ov511->scratchlen;
for (i = 0; i < urb->number_of_packets; i++) {
int n = urb->iso_frame_desc[i].actual_length;
int st = urb->iso_frame_desc[i].status;
cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- if (st) {
+ if (!n) continue;
+
+ aPackNum[i] = n ? cdata[512] : -1;
+
+ if (st){
// Macro - must be in braces!
PDEBUG("data error: [%d] len=%d, status=%d\n",
i, n, st);
- }
+ }
+
+ frame = &ov511->frame[ov511->curframe];
+
+ /* Can we find a frame end */
+ if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] |
+ cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
+ (cdata[8] & 8) && (cdata[8] & 0x80)) {
+
+ PDEBUG("Found Frame End!, packnum = %d\n", (int)(cdata[512]));
+ PDEBUG("Current frame = %d\n", ov511->curframe);
+
+ if (frame->scanstate == STATE_LINES) {
+ if (waitqueue_active(&frame->wq)) {
+ PDEBUG("About to wake up waiting processes\n");
+ frame->grabstate = FRAME_DONE;
+ wake_up_interruptible(&frame->wq);
+ }
+ }
+ }
- if ((ov511->scratchlen + n) > SCRATCH_BUF_SIZE) {
- PDEBUG("scratch buf overflow!scr_len: %d, n: %d\n", ov511->scratchlen, n );
- return totlen;
+ /* Can we find a frame start */
+ else if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] |
+ cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
+ (cdata[8] & 8)) {
+ PDEBUG("ov511: Found Frame Start!, packnum = %d\n", (int)(cdata[512]));
+ frame->scanstate = STATE_LINES;
+ frame->curpix = 0;
}
- if (n) {
- memmove(data, cdata, n);
- data += n;
- totlen += n;
- ov511->scratchlen += n;
+ /* Are we in a frame? */
+ else if (frame->scanstate == STATE_LINES) {
+ unsigned char *f = frame->data + 3 * frame->curpix;
+ int i;
+ if (frame->curpix <= 320 * 240 - 256) {
+ for (i=0; i<256; i++) {
+ *f++ = *cdata;
+ *f++ = *cdata;
+ *f++ = *cdata++;
+ *f++ = *cdata;
+ *f++ = *cdata;
+ *f++ = *cdata++;
+ }
+ frame->curpix += 512;
+ } else {
+ PDEBUG("Too many pixels!\n");
+ }
}
+
}
+ PDEBUG("pn: %d %d %d %d %d %d %d %d %d %d\n",
+ aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
+ aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
return totlen;
}
struct ov511_sbuf *sbuf;
int i;
- PDEBUG("ov511_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length);
+#if 0
+ static int last_status, last_error_count, last_actual_length;
+ if (last_status != urb->status ||
+ last_error_count != urb->error_count ||
+ last_actual_length != urb->actual_length) {
+ PDEBUG("ov511_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length);
+ last_status = urb->status;
+ last_error_count = urb->error_count;
+ last_actual_length = urb->actual_length;
+ }
+#endif
if (!ov511->streaming) {
PDEBUG("hmmm... not streaming, but got interrupt\n");
}
sbuf = &ov511->sbuf[ov511->cursbuf];
-// usb_kill_isoc(sbuf->isodesc);
/* Copy the data received into our scratch buffer */
- len = ov511_compress_isochronous(ov511, urb);
-
+ len = ov511_move_data(ov511, urb);
+#if 0
/* If we don't have a frame we're current working on, complain */
if (ov511->scratchlen) {
if (ov511->curframe < 0) {
} else
ov511_parse_data(ov511);
}
-
+#endif
for (i = 0; i < FRAMES_PER_DESC; i++) {
sbuf->urb->iso_frame_desc[i].status = 0;
sbuf->urb->iso_frame_desc[i].actual_length = 0;
/* Move to the next sbuf */
ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF;
- /* Reschedule this block of Isochronous desc */
-// usb_run_isoc(sbuf->isodesc, ov511->sbuf[ov511->cursbuf].isodesc);
-
return;
}
ov511->cursbuf = 0;
ov511->scratchlen = 0;
- // FIXME - is this the proper size?
- usb_ov511_set_packet_size(ov511, 512);
+ ov511_set_packet_size(ov511, 512);
+#define OV511_COLOR_BAR_TEST
+#ifdef OV511_COLOR_BAR_TEST
+ {
+ int rc;
+ rc = ov511_i2c_read(ov511->dev, 0x12);
+ rc = ov511_i2c_write(ov511->dev, 0x12, 0x3f);
+ rc = ov511_i2c_read(ov511->dev, 0x12);
+ rc = ov511_i2c_read(ov511->dev, 0x13);
+ rc = ov511_i2c_write(ov511->dev, 0x14, 0x4);
+ rc = ov511_i2c_read(ov511->dev, 0x14);
+ rc = ov511_i2c_write(ov511->dev, 0x28, 0x60);
+ rc = ov511_i2c_read(ov511->dev, 0x28);
+ ov511_reg_write(ov511->dev, OV511_REG_CAMERA_DATA_INPUT_SELECT,
+ 0);
+ }
+#endif
+
/* We double buffer the Iso lists */
urb = usb_alloc_urb(FRAMES_PER_DESC);
urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
}
-
+
ov511->sbuf[1].urb->next = ov511->sbuf[0].urb;
ov511->sbuf[0].urb->next = ov511->sbuf[1].urb;
ov511->streaming = 1;
- return 0;
+ return 0;
}
if (!ov511->streaming)
return;
-// FIXME - Figure out how to do this with the ov511 (Does the below do it?)
-// /* Turn off continuous grab */
-// if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) {
-// printk(KERN_ERR "cpia_set_grab_mode error\n");
-// return /* -EBUSY */;
-// }
-
- usb_ov511_set_packet_size(ov511, 0);
+ ov511_set_packet_size(ov511, 0);
/* Unschedule all of the iso td's */
usb_unlink_urb(ov511->sbuf[1].urb);
height = DEFAULT_HEIGHT;
height = (height / 4) * 4; /* Multiple of 4 */
-// FIXME - Don't know how to implement the equivalent of this for the ov511
-// /* Set the ROI they want */
-// if (usb_cpia_set_roi(cpia->dev, 0, width / 8, 0, height / 4) < 0)
-// return -EBUSY;
-
-// if (usb_cpia_set_compression(cpia->dev, cpia->compress ?
-// COMP_AUTO : COMP_DISABLED, DONT_DECIMATE) < 0) {
-// printk(KERN_ERR "cpia_set_compression error\n");
-// return -EBUSY;
-// }
-
- /* We want a fresh frame every 30 we get */
- ov511->compress = (ov511->compress + 1) % 30;
-
-// /* Grab the frame */
-// if (usb_cpia_upload_frame(cpia->dev, WAIT_FOR_NEXT_FRAME) < 0) {
-// printk(KERN_ERR "cpia_upload_frame error\n");
-// return -EBUSY;
-// }
+// /* We want a fresh frame every 30 we get */
+// ov511->compress = (ov511->compress + 1) % 30;
return 0;
}
0
};
-static int usb_ov511_configure(struct usb_ov511 *ov511)
+static int ov511_configure(struct usb_ov511 *ov511)
{
struct usb_device *dev = ov511->dev;
int temprc; // DEBUG CODE
-
+
/* Set altsetting 0 */
if (usb_set_interface(dev, ov511->iface, 0) < 0) {
printk(KERN_ERR "ov511: usb_set_interface error\n");
return -EBUSY;
}
-
+
memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template));
init_waitqueue_head(&ov511->frame[0].wq);
init_waitqueue_head(&ov511->frame[1].wq);
-
+
if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) == -1) {
printk(KERN_ERR "ov511: video_register_device failed\n");
return -EBUSY;
}
- // Disable compression
- if (usb_ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) {
- printk(KERN_ERR "ov511: disable compression: command failed\n");
+ /* Reset in case driver was unloaded and reloaded without unplug */
+ if (ov511_reset(dev, OV511_RESET_ALL) < 0)
goto error;
- }
-
- // Initialize system
- // FIXME - This should be moved to a function
- if (usb_ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) {
+
+ /* Initialize system */
+ if (ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) {
printk(KERN_ERR "ov511: enable system: command failed\n");
goto error;
}
+
+ /* This seems to be necessary */
+ if (ov511_reset(dev, OV511_RESET_ALL) < 0)
+ goto error;
+
+ /* Disable compression */
+ if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) {
+ printk(KERN_ERR "ov511: disable compression: command failed\n");
+ goto error;
+ }
+
+// FIXME - error checking needed
+ ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
+ OV7610_I2C_WRITE_ID);
+ ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
+ OV7610_I2C_READ_ID);
+
+// DEBUG CODE
+// usb_ov511_reg_write(dev, OV511_REG_I2C_CLOCK_PRESCALER,
+// OV511_I2C_CLOCK_PRESCALER);
- if (usb_ov511_reset(dev, OV511_RESET_NOREGS) < 0)
+ if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
goto error;
+ /* Dummy read to sync I2C */
+ ov511_i2c_read(dev, 0x1C);
+
// DEBUG - TEST CODE FOR CAMERA REG READ
- temprc = usb_ov511_cam_reg_read(dev, 0x1D);
- PDEBUG("Camera reg 0x1D: 0x%X\n", temprc);
-// END DEBUG CODE
+ temprc = ov511_i2c_read(dev, 0x1C);
+ temprc = ov511_i2c_read(dev, 0x1D);
+// END DEBUG CODE
+
ov511->compress = 0;
return 0;
ov511->dev = dev;
ov511->iface = interface->bInterfaceNumber;
- rc = usb_ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
+ rc = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
if (rc < 0) {
printk("ov511: Unable to read camera bridge registers\n");
return NULL;
- } else if (rc == 3) { // D-Link DSB-C300
+ } else if (rc == 3) { /* D-Link DSB-C300 */
printk("ov511: Camera is a D-Link DSB-C300\n");
ov511->customid = 3;
- } else if (rc == 21) { // Creative Labs WebCam 3
+ } else if (rc == 21) { /* Creative Labs WebCam 3 */
printk("ov511: Camera is a Creative Labs WebCam 3\n");
ov511->customid = 21;
} else {
return NULL;
}
- // Reset in case driver was unloaded and reloaded without unplug
- if (usb_ov511_reset(dev, OV511_RESET_ALL) < 0)
- return NULL;
-
- if (!usb_ov511_configure(ov511)) {
+ if (!ov511_configure(ov511)) {
ov511->user=0;
init_MUTEX(&ov511->lock); /* to 1 == available */
return ov511;
/* System control register numbers */
#define OV511_REG_SYSTEM_RESET 0x50
#define OV511_RESET_UDC 0x01
-#define OV511_RESET_I2O 0x02
+#define OV511_RESET_I2C 0x02
#define OV511_RESET_FIFO 0x04
#define OV511_RESET_OMNICE 0x08
#define OV511_RESET_DRAM_INTF 0x10
#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
#define FRAMES_PER_DESC 10 /* FIXME - What should this be? */
-#define FRAME_SIZE_PER_DESC 960 /* FIXME - Shouldn't be hardcoded */
+#define FRAME_SIZE_PER_DESC 512 /* FIXME - Shouldn't be hardcoded */
// FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
#define OV511_ENDPOINT_ADDRESS 0x81 /* Address of isoc endpoint */
// FIXME - these can vary between specific models
#define OV7610_I2C_WRITE_ID 0x42
#define OV7610_I2C_READ_ID 0x43
+#define OV511_I2C_CLOCK_PRESCALER 0x03
/* Prototypes */
int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg);
int scanstate; /* State of scanning */
int curline; /* Line of frame we're working on */
+ int curpix;
long scanlength; /* uncompressed, raw data length of frame */
long bytes_read; /* amount of scanlength that has been read from *data */
-/* Driver for USB SCSI-like devices
+/* Driver for USB Mass Storage compliant devices
*
* (c) 1999 Michael Gee (michael@linuxspecific.com)
- * (c) 1999 Matthew Dharm (mdharm@one-eyed-alien.net)
- *
- * This driver is schizoid - it makes a USB device appear as both a SCSI
- * device and a character device. The latter is only available if the device
- * has an interrupt endpoint, and is used specifically to receive interrupt
- * events.
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* In order to support various 'strange' devices, this module supports plug-in
* device-specific filter modules, which can do their own thing when required.
*
- * Further reference.
+ * Further reference:
* This driver is based on the 'USB Mass Storage Class' document. This
- * describes in detail the transformation of SCSI command blocks to the
- * equivalent USB control and data transfer required.
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI commands in mind when they
+ * created this document. The commands are all similar to commands
+ * in the SCSI-II specification.
+ *
* It is important to note that in a number of cases this class exhibits
* class-specific exemptions from the USB specification. Notably the
* usage of NAK, STALL and ACK differs from the norm, in that they are
- * used to communicate wait, failed and OK on SCSI commands.
+ * used to communicate wait, failed and OK on commands.
* Also, for certain devices, the interrupt endpoint is used to convey
* status of a command.
*
#include "usb.h"
#include "usb_scsi.h"
-/* direction table (what a pain) */
-
+/* direction table -- this indicates the direction of the data
+ * transfer for each command code -- a 1 indicates input
+ */
unsigned char us_direction[256/8] = {
-
-#include "usb_scsi_dt.c"
-
+ 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
+ 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#ifdef REWRITE_PROJECT
+++ /dev/null
-0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
-0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
void
aty128pci_probe(void)
{
- struct pci_dev *pdev;
+ struct pci_dev *pdev = NULL;
struct fb_info_aty128 *info;
unsigned long fb_addr, reg_addr;
u16 tmp;
- for (pdev = pci_devices; pdev; pdev = pdev->next) {
- if (((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
- (pdev->vendor == PCI_VENDOR_ID_ATI)) {
+ while ((pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) {
+ if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
struct resource *rp;
/* FIXME add other known R128 device ID's */
-/* $Id: atyfb.c,v 1.133 1999/12/09 10:23:13 davem Exp $
+/* $Id: atyfb.c,v 1.134 1999/12/23 21:32:09 geert Exp $
* linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
*
* Copyright (C) 1997-1998 Geert Uytterhoeven
*/
int atyfb_init(void);
-#ifdef CONFIG_FB_OF
-void atyfb_of_init(struct device_node *dp);
-#endif
#ifndef MODULE
int atyfb_setup(char*);
#endif
int __init atyfb_init(void)
{
-#if defined(CONFIG_FB_OF)
- /* We don't want to be called like this. */
- /* We rely on Open Firmware (offb) instead. */
-#elif defined(CONFIG_PCI)
- struct pci_dev *pdev;
+#if defined(CONFIG_PCI)
+ struct pci_dev *pdev = NULL;
struct fb_info_aty *info;
- unsigned long addr;
+ unsigned long addr, res_start, res_size;
#ifdef __sparc__
extern void (*prom_palette) (int);
extern int con_is_present(void);
u16 tmp;
#endif
- for (pdev = pci_devices; pdev; pdev = pdev->next) {
- if (((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
- (pdev->vendor == PCI_VENDOR_ID_ATI)) {
+ while ((pdev = pci_find_device(PCI_VENDOR_ID_ATY, PCI_ANY_ID, pdev))) {
+ if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
struct resource *rp;
info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
if (!addr)
continue;
+ res_start = rp->start;
+ res_size = rp->end-rp->start+1;
+ if (!request_mem_region(res_start, res_size, "atyfb"))
+ continue;
+
#ifdef __sparc__
/*
* Map memory-mapped registers.
if (!info->mmap_map) {
printk("atyfb_init: can't alloc mmap_map\n");
kfree(info);
+ release_mem_region(res_start, res_size);
return -ENXIO;
}
memset(info->mmap_map, 0, j * sizeof(*info->mmap_map));
if(!info->ati_regbase) {
kfree(info);
+ release_mem_region(res_start, res_size);
return -ENOMEM;
}
if(!info->frame_buffer) {
kfree(info);
+ release_mem_region(res_start, res_size);
return -ENXIO;
}
if (info->mmap_map)
kfree(info->mmap_map);
kfree(info);
+ release_mem_region(res_start, res_size);
return -ENXIO;
}
info->mmap_map[1].prot_mask = _PAGE_CACHE;
info->mmap_map[1].prot_flag = _PAGE_E;
#endif /* __sparc__ */
+
+#ifdef CONFIG_PMAC_PBOOK
+ if (first_display == NULL)
+ pmu_register_sleep_notifier(&aty_sleep_notifier);
+ info->next = first_display;
+ first_display = info;
+#endif
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ if (!console_fb_info)
+ console_fb_info = &info->fb_info;
+#endif /* CONFIG_FB_COMPAT_XPMAC */
}
}
return 0;
}
-#ifdef CONFIG_FB_OF
-void __init atyfb_of_init(struct device_node *dp)
-{
- unsigned long addr;
- u8 bus, devfn;
- u16 cmd;
- struct fb_info_aty *info;
- int i;
-
- if (device_is_compatible(dp, "ATY,264LTPro")) {
- /* XXX kludge for now */
- if (dp->name == 0 || strcmp(dp->name, "ATY,264LTProA") != 0
- || dp->parent == 0)
- return;
- dp = dp->parent;
- }
- switch (dp->n_addrs) {
- case 1:
- case 2:
- case 3:
- addr = dp->addrs[0].address;
- break;
- case 4:
- addr = dp->addrs[1].address;
- break;
- default:
- printk("Warning: got %d adresses for ATY:\n", dp->n_addrs);
- for (i = 0; i < dp->n_addrs; i++)
- printk(" %08x-%08x", dp->addrs[i].address,
- dp->addrs[i].address+dp->addrs[i].size-1);
- if (dp->n_addrs)
- printk("\n");
- return;
- }
-
- info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
- if (!info) {
- printk("atyfb_of_init: can't alloc fb_info_aty\n");
- return;
- }
- memset(info, 0, sizeof(struct fb_info_aty));
-
- info->ati_regbase_phys = 0x7ff000+addr;
- info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
- 0x1000);
-
- if(! info->ati_regbase) {
- printk("atyfb_of_init: ioremap() returned NULL\n");
- kfree(info);
- return;
- }
-
- info->ati_regbase_phys += 0xc00;
- info->ati_regbase += 0xc00;
-
- /* enable memory-space accesses using config-space command register */
- if (pci_device_loc(dp, &bus, &devfn) == 0) {
- pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
- if (cmd != 0xffff) {
- cmd |= PCI_COMMAND_MEMORY;
- pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
- }
- }
-
-#ifdef __BIG_ENDIAN
- /* Use the big-endian aperture */
- addr += 0x800000;
-#endif
-
- /* Map in frame buffer */
- info->frame_buffer_phys = addr;
- info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
-
- if(! info->frame_buffer) {
- printk("atyfb_of_init: ioremap() returned NULL\n");
- kfree(info);
- return;
- }
-
- if (!aty_init(info, dp->full_name)) {
- kfree(info);
- return;
- }
-
-#ifdef CONFIG_PMAC_PBOOK
- if (first_display == NULL)
- pmu_register_sleep_notifier(&aty_sleep_notifier);
- info->next = first_display;
- first_display = info;
-#endif
-
-
-#ifdef CONFIG_PMAC_PBOOK
- if (first_display == NULL)
- pmu_register_sleep_notifier(&aty_sleep_notifier);
- info->next = first_display;
- first_display = info;
-#endif
-
-
-#ifdef CONFIG_FB_COMPAT_XPMAC
- if (!console_fb_info)
- console_fb_info = &info->fb_info;
-#endif /* CONFIG_FB_COMPAT_XPMAC */
-}
-#endif /* CONFIG_FB_OF */
-
-
#ifndef MODULE
int __init atyfb_setup(char *options)
{
/*
* drivers/video/clgenfb.c - driver for Cirrus Logic chipsets
*
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
*
* Contributors (thanks, all!)
*
{
iounmap (info->fbmem);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)
- __release_region (&iomem_resource, info->fbmem_phys, info->size);
- __release_region (&iomem_resource, 0xA0000, 65535);
+ release_mem_region(info->fbmem_phys, info->size);
+ release_mem_region(0xA0000, 65535);
if (release_io_ports)
- __release_region (&ioport_resource, 0x3C0, 32);
+ release_region(0x3C0, 32);
#endif
}
#endif /* MODULE */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)
- if (!__request_region (&iomem_resource, board_addr,
- board_size, "clgenfb")) {
+ if (!request_mem_region(board_addr, board_size, "clgenfb")) {
pci_write_config_word (pdev, PCI_COMMAND, tmp16);
printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n",
board_addr);
return -1;
}
- if (!__request_region (&iomem_resource, 0xA0000, 65535, "clgenfb")) {
+ if (!request_mem_region(0xA0000, 65535, "clgenfb")) {
pci_write_config_word (pdev, PCI_COMMAND, tmp16);
printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n",
0xA0000L);
- __release_region(&iomem_resource, board_addr, board_size);
+ release_mem_region(board_addr, board_size);
return -1;
}
- if (__request_region(&ioport_resource, 0x3C0, 32, "clgenfb"))
+ if (request_region(0x3C0, 32, "clgenfb"))
release_io_ports = 1;
#endif /* kernel > 2.3.13 */
static void clgen_zorro_unmap (struct clgenfb_info *info)
{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)
- __release_region(&iomem_resource, info->board_addr, info->board_size);
+ release_mem_region(info->board_addr, info->board_size);
#endif
if (info->btype == BT_PICASSO4) {
iounmap (info->board_addr);
info->board_addr = board_addr = (unsigned long) cd->cd_BoardAddr;
info->board_size = board_size = (unsigned long) cd->cd_BoardSize;
- if (!__request_region(&iomem_resource, board_addr,
- board_size, "clgenfb")) {
+ if (!request_mem_region(board_addr, board_size, "clgenfb")) {
printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n",
board_addr);
return -1;
*/
#ifdef MODULE
-MODULE_AUTHOR("Copyright 1999 Jeff Garzik <jgarzik@pobox.com>");
+MODULE_AUTHOR("Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>");
MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
int init_module (void)
/*
* drivers/video/clgenfb.h - Cirrus Logic chipset constants
*
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
*
* Original clgenfb author: Frank Neumann
*
#ifdef CONFIG_FB_CLGEN
{ "clgen", clgenfb_init, clgenfb_setup },
#endif
+#ifdef CONFIG_FB_ATY
+ { "atyfb", atyfb_init, atyfb_setup },
+#endif
#ifdef CONFIG_FB_OF
+ /*
+ * Offb must be initialized _after_ all other frame buffer devices
+ * that use PCI probing and PCI resources! [ Geert ]
+ */
{ "offb", offb_init, offb_setup },
#endif
#ifdef CONFIG_FB_SBUS
{ "sbus", sbusfb_init, sbusfb_setup },
#endif
-#ifdef CONFIG_FB_ATY
- { "atyfb", atyfb_init, atyfb_setup },
-#endif
#ifdef CONFIG_FB_ATY128
{ "aty128fb", aty128fb_init, aty128fb_setup },
#endif
/* We don't want to be called like this. */
/* We rely on Open Firmware (offb) instead. */
#elif defined(CONFIG_PCI)
- struct pci_dev *pdev;
+ struct pci_dev *pdev = NULL;
struct fb_info_imstt *p;
__u32 addr;
__u16 cmd;
- for (pdev = pci_devices; pdev; pdev = pdev->next) {
- if (!(((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
- && (pdev->vendor == PCI_VENDOR_ID_IMS)))
+ while ((pdev = pci_find_device(PCI_VENDOR_ID_IMS, PCI_ANY_ID, pdev))) {
+ if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
continue;
-
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- if (!(cmd & PCI_COMMAND_MEMORY)) {
- cmd |= PCI_COMMAND_MEMORY;
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
- }
+ pci_enable_device(pdev);
addr = pdev->resource[0].start;
if (!addr)
};
#endif
-static struct pci_dev* pci_find(struct pci_dev* p) {
-
- DBG("pci_find")
-
- if (p) return p->next;
- return pci_devices;
-}
-
static void initMatrox(WPMINFO struct display* p) {
struct display_switch *swtmp;
if (disabled)
return -ENXIO;
- while ((pdev = pci_find(pdev)) != NULL) {
+ while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) {
struct board* b;
u_int8_t rev;
u_int16_t svid;
u_int16_t sid;
pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
- pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
- pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sid);
+ svid = dev->subsystem_vendor;
+ sid = dev->subsystem_device;
for (b = dev_list; b->vendor; b++) {
if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue;
if (b->svid)
#include <linux/fb.h>
#include <linux/selection.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#ifdef CONFIG_FB_COMPAT_XPMAC
#include <asm/vc_ioctl.h>
#endif
}
-#ifdef CONFIG_FB_ATY
-extern void atyfb_of_init(struct device_node *dp);
-#endif /* CONFIG_FB_ATY */
#ifdef CONFIG_FB_ATY128
extern void aty128fb_of_init(struct device_node *dp);
#endif /* CONFIG_FB_ATY */
return 0;
}
+
+ /*
+ * This function is intended to go away as soon as all OF-aware frame
+ * buffer device drivers have been converted to use PCI probing and PCI
+ * resources. [ Geert ]
+ */
+
static int __init offb_init_driver(struct device_node *dp)
{
#ifdef CONFIG_FB_ATY128
return 1;
}
#endif
-#ifdef CONFIG_FB_ATY
- if (!strncmp(dp->name, "ATY", 3)) {
- atyfb_of_init(dp);
- return 1;
- }
-#endif /* CONFIG_FB_ATY */
#ifdef CONFIG_FB_S3TRIO
if (!strncmp(dp->name, "S3Trio", 6)) {
s3triofb_init_of(dp);
address = (u_long)*up;
else {
for (i = 0; i < dp->n_addrs; ++i)
- if (dp->addrs[i].size >= len)
+ if (dp->addrs[i].size >= pitch*height*depth/8)
break;
if (i >= dp->n_addrs) {
printk(KERN_ERR "no framebuffer address found for %s\n", dp->full_name);
struct fb_var_screeninfo *var;
struct display *disp;
struct fb_info_offb *info;
+ unsigned long res_start = address;
+ unsigned long res_size = pitch*height*depth/8;
+
+ if (!request_mem_region(res_start, res_size, "offb"))
+ return;
printk(KERN_INFO "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
width, height, name, address, depth, pitch);
if (depth != 8 && depth != 16 && depth != 32) {
printk(KERN_ERR "%s: can't use depth = %d\n", full_name, depth);
+ release_mem_region(res_start, res_size);
return;
}
info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
- if (info == 0)
+ if (info == 0) {
+ release_mem_region(res_start, res_size);
return;
+ }
memset(info, 0, sizeof(*info));
fix = &info->fix;
if (register_framebuffer(&info->info) < 0) {
kfree(info);
+ release_mem_region(res_start, res_size);
return;
}
DPRINTK("found board: %s\n", board_table[p->board].name);
p->regions.p_fb=p->regions.fb_base;
- if (!__request_region(&iomem_resource, p->regions.p_fb,
- p->regions.fb_size, "pm2fb")) {
+ if (!request_mem_region(p->regions.p_fb, p->regions.fb_size,
+ "pm2fb")) {
printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort\n");
return 0;
}
#else
p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE;
#endif
- if (!__request_region(&iomem_resource, p->regions.p_regs,
- PM2_REGS_SIZE, "pm2fb")) {
+ if (!request_mem_region(p->regions.p_regs, PM2_REGS_SIZE, "pm2fb")) {
printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort\n");
UNMAP(p->regions.v_fb, p->regions.fb_size);
return 0;
}
DPRINTK("scanning PCI bus for known chipsets...\n");
- for (dev = pci_devices; !pci->dev && dev; dev = dev->next) {
+ pci_for_each_dev(dev) {
for (i = 0; pm2pci_cards[i].vendor; i++)
if (pm2pci_cards[i].vendor == dev->vendor &&
pm2pci_cards[i].device == dev->device) {
DPRINTK("... found %s\n", pm2pci_cards[i].name);
break;
}
+ if (pci->dev)
+ break;
}
if (!pci->dev) {
DPRINTK("no PCI board found.\n");
pm2fb_reset(i);
UNMAP(i->regions.v_fb, i->regions.fb_size);
- __release_region(&iomem_resource, i->regions.p_fb, i->regions.fb_size);
+ release_mem_region(i->regions.p_fb, i->regions.fb_size);
UNMAP(i->regions.v_regs, PM2_REGS_SIZE);
- __release_region(&iomem_resource, i->regions.p_regs, PM2_REGS_SIZE);
+ release_mem_region(i->regions.p_regs, PM2_REGS_SIZE);
if (board_table[i->board].cleanup)
board_table[i->board].cleanup(i);
/*
* linux/drivers/video/rivafb.c - nVidia RIVA 128/TNT/TNT2 fb driver
*
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
*
* Contributors:
*
rinfo->ctrl_base_phys = rinfo->pd->resource[0].start;
rinfo->fb_base_phys = rinfo->pd->resource[1].start;
- __request_region(&ioport_resource, 0x3C0, 32, "rivafb");
+ request_region(0x3C0, 32, "rivafb");
- if (!__request_region (&iomem_resource, rinfo->ctrl_base_phys,
- rinfo->base0_region_size, "rivafb") ||
- !__request_region (&iomem_resource, rinfo->fb_base_phys,
- rinfo->base1_region_size, "rivafb")) {
+ if (!request_mem_region(rinfo->ctrl_base_phys,
+ rinfo->base0_region_size, "rivafb") ||
+ !request_mem_region(rinfo->fb_base_phys, rinfo->base1_region_size,
+ "rivafb")) {
printk (KERN_ERR PFX "cannot reserve MMIO region\n");
return -ENXIO;
}
if(!pcibios_present()) return -ENXIO;
#endif
- for(pdev = pci_devices; pdev; pdev = pdev->next) {
+ while ((pdev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_ANY_ID, pdev))) {
if(((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
- (pdev->vendor == PCI_VENDOR_ID_3DFX) &&
((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
(pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3))) {
char* name = pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE
video_visual = (video_bpp == 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
- if (!__request_region(&iomem_resource, video_base, video_size,
- "vesafb")) {
+ if (!request_mem_region(video_base, video_size, "vesafb")) {
printk(KERN_ERR
"vesafb: abort, cannot reserve video memory at 0x%lu\n",
video_base);
/* request failure does not faze us, as vgacon probably has this
* region already (FIXME) */
- __request_region(&ioport_resource, 0x3c0, 32, "vesafb");
+ request_region(0x3c0, 32, "vesafb");
if (mtrr)
mtrr_add(video_base, video_size, MTRR_TYPE_WRCOMB, 1);
/*
* linux/include/video/vga.h -- standard VGA chipset interaction
*
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
*
* Copyright history from vga16fb.c:
* Copyright 1999 Ben Pfaff and Petr Vandrovec
printk(KERN_DEBUG "vga16fb: initializing\n");
- if (!__request_region(&iomem_resource, VGA_FB_PHYS, VGA_FB_PHYS_LEN,
- "vga16fb")) {
+ if (!request_mem_region(VGA_FB_PHYS, VGA_FB_PHYS_LEN, "vga16fb")) {
printk (KERN_ERR "vga16fb: unable to reserve VGA memory, exiting\n");
return -1;
}
/* note - does not cause failure, b/c vgacon probably still owns this
* region (FIXME) */
- if (__request_region(&ioport_resource, 0x3C0, 32, "vga16fb"))
+ if (request_region(0x3C0, 32, "vga16fb"))
release_io_ports = 1;
disp.var = vga16fb_defined;
{
unregister_framebuffer(&vga16fb.fb_info);
iounmap(vga16fb.video_vbase);
- __release_region(&iomem_resource, VGA_FB_PHYS, VGA_FB_PHYS_LEN);
+ release_mem_region(VGA_FB_PHYS, VGA_FB_PHYS_LEN);
if (release_io_ports)
- __release_region(&ioport_resource, 0x3c0, 32);
+ release_region(0x3c0, 32);
}
#endif
#include <linux/mm.h>
#include <linux/locks.h>
#include <linux/fcntl.h>
+#include <linux/malloc.h>
+#include <linux/kmod.h>
#include <asm/uaccess.h>
{
return fsync_dev(dentry->d_inode->i_rdev);
}
+
+/*
+ * bdev cache handling - shamelessly stolen from inode.c
+ * We use smaller hashtable, though.
+ */
+
+#define HASH_BITS 6
+#define HASH_SIZE (1UL << HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+static struct list_head bdev_hashtable[HASH_SIZE];
+static spinlock_t bdev_lock = SPIN_LOCK_UNLOCKED;
+static kmem_cache_t * bdev_cachep;
+
+#define alloc_bdev() \
+ ((struct block_device *) kmem_cache_alloc(bdev_cachep, SLAB_KERNEL))
+#define destroy_bdev(bdev) kmem_cache_free(bdev_cachep, (bdev))
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct block_device * bdev = (struct block_device *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ {
+ memset(bdev, 0, sizeof(*bdev));
+ sema_init(&bdev->bd_sem, 1);
+ }
+}
+
+void bdev_init(void)
+{
+ int i;
+ struct list_head *head = bdev_hashtable;
+
+ i = HASH_SIZE;
+ do {
+ INIT_LIST_HEAD(head);
+ head++;
+ i--;
+ } while (i);
+
+ bdev_cachep = kmem_cache_create("bdev_cache",
+ sizeof(struct block_device),
+ 0, SLAB_HWCACHE_ALIGN, init_once,
+ NULL);
+ if (!bdev_cachep)
+ panic("cannot create bdev slab cache");
+}
+
+/*
+ * Most likely _very_ bad one - but then it's hardly critical for small
+ * /dev and can be fixed when somebody will need really large one.
+ */
+static inline unsigned long hash(dev_t dev)
+{
+ unsigned long tmp = dev;
+ tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
+ return tmp & HASH_MASK;
+}
+
+static struct block_device *bdfind(dev_t dev, struct list_head *head)
+{
+ struct list_head *p;
+ struct block_device *bdev;
+ for (p=head->next; p!=head; p=p->next) {
+ bdev = list_entry(p, struct block_device, bd_hash);
+ if (bdev->bd_dev != dev)
+ continue;
+ atomic_inc(&bdev->bd_count);
+ return bdev;
+ }
+ return NULL;
+}
+
+struct block_device *bdget(dev_t dev)
+{
+ struct list_head * head = bdev_hashtable + hash(dev);
+ struct block_device *bdev, *new_bdev;
+ spin_lock(&bdev_lock);
+ bdev = bdfind(dev, head);
+ spin_unlock(&bdev_lock);
+ if (bdev)
+ return bdev;
+ new_bdev = alloc_bdev();
+ if (!new_bdev)
+ return NULL;
+ atomic_set(&new_bdev->bd_count,1);
+ new_bdev->bd_dev = dev;
+ spin_lock(&bdev_lock);
+ bdev = bdfind(dev, head);
+ if (!bdev) {
+ list_add(&new_bdev->bd_hash, head);
+ spin_unlock(&bdev_lock);
+ return new_bdev;
+ }
+ spin_unlock(&bdev_lock);
+ destroy_bdev(new_bdev);
+ return bdev;
+}
+
+void bdput(struct block_device *bdev)
+{
+ if (atomic_dec_and_test(&bdev->bd_count)) {
+ spin_lock(&bdev_lock);
+ if (atomic_read(&bdev->bd_openers))
+ BUG();
+ list_del(&bdev->bd_hash);
+ spin_unlock(&bdev_lock);
+ destroy_bdev(bdev);
+ }
+}
+
+static struct {
+ const char *name;
+ struct file_operations *bdops;
+} blkdevs[MAX_BLKDEV] = {
+ { NULL, NULL },
+};
+
+int get_blkdev_list(char * p)
+{
+ int i;
+ int len;
+
+ len = sprintf(p, "\nBlock devices:\n");
+ for (i = 0; i < MAX_BLKDEV ; i++) {
+ if (blkdevs[i].bdops) {
+ len += sprintf(p+len, "%3d %s\n", i, blkdevs[i].name);
+ }
+ }
+ return len;
+}
+
+/*
+ Return the function table of a device.
+ Load the driver if needed.
+*/
+struct file_operations * get_blkfops(unsigned int major)
+{
+ const struct file_operations *ret = NULL;
+
+ /* major 0 is used for non-device mounts */
+ if (major && major < MAX_BLKDEV) {
+#ifdef CONFIG_KMOD
+ if (!blkdevs[major].bdops) {
+ char name[20];
+ sprintf(name, "block-major-%d", major);
+ request_module(name);
+ }
+#endif
+ ret = blkdevs[major].bdops;
+ }
+ return ret;
+}
+
+int register_blkdev(unsigned int major, const char * name, struct file_operations *bdops)
+{
+ if (major == 0) {
+ for (major = MAX_BLKDEV-1; major > 0; major--) {
+ if (blkdevs[major].bdops == NULL) {
+ blkdevs[major].name = name;
+ blkdevs[major].bdops = bdops;
+ return major;
+ }
+ }
+ return -EBUSY;
+ }
+ if (major >= MAX_BLKDEV)
+ return -EINVAL;
+ if (blkdevs[major].bdops && blkdevs[major].bdops != bdops)
+ return -EBUSY;
+ blkdevs[major].name = name;
+ blkdevs[major].bdops = bdops;
+ return 0;
+}
+
+int unregister_blkdev(unsigned int major, const char * name)
+{
+ if (major >= MAX_BLKDEV)
+ return -EINVAL;
+ if (!blkdevs[major].bdops)
+ return -EINVAL;
+ if (strcmp(blkdevs[major].name, name))
+ return -EINVAL;
+ blkdevs[major].name = NULL;
+ blkdevs[major].bdops = NULL;
+ return 0;
+}
+
+/*
+ * This routine checks whether a removable media has been changed,
+ * and invalidates all buffer-cache-entries in that case. This
+ * is a relatively slow routine, so we have to try to minimize using
+ * it. Thus it is called only upon a 'mount' or 'open'. This
+ * is the best way of combining speed and utility, I think.
+ * People changing diskettes in the middle of an operation deserve
+ * to lose :-)
+ */
+int check_disk_change(kdev_t dev)
+{
+ int i;
+ const struct file_operations * bdops;
+ struct super_block * sb;
+
+ i = MAJOR(dev);
+ if (i >= MAX_BLKDEV || (bdops = blkdevs[i].bdops) == NULL)
+ return 0;
+ if (bdops->check_media_change == NULL)
+ return 0;
+ if (!bdops->check_media_change(dev))
+ return 0;
+
+ printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
+ bdevname(dev));
+
+ sb = get_super(dev);
+ if (sb && invalidate_inodes(sb))
+ printk("VFS: busy inodes on changed media.\n");
+
+ invalidate_buffers(dev);
+
+ if (bdops->revalidate)
+ bdops->revalidate(dev);
+ return 1;
+}
+
+int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
+{
+ kdev_t rdev = to_kdev_t(bdev->bd_dev);
+ struct file_operations *fops = get_blkfops(MAJOR(rdev));
+ struct inode inode_fake;
+ int res;
+ mm_segment_t old_fs = get_fs();
+
+ if (!fops || !fops->ioctl)
+ return -EINVAL;
+ inode_fake.i_rdev=rdev;
+ init_waitqueue_head(&inode_fake.i_wait);
+ set_fs(KERNEL_DS);
+ res = fops->ioctl(&inode_fake, NULL, cmd, arg);
+ set_fs(old_fs);
+ return res;
+}
+
+int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind)
+{
+ int ret = -ENODEV;
+ kdev_t rdev = to_kdev_t(bdev->bd_dev); /* this should become bdev */
+ struct file_operations *fops = get_blkfops(MAJOR(rdev));
+ down(&bdev->bd_sem);
+ if (fops) {
+ /*
+ * This crockload is due to bad choice of ->open() type.
+ * It will go away.
+ */
+ struct file fake_file = {};
+ struct dentry fake_dentry = {};
+ struct inode *fake_inode = get_empty_inode();
+ ret = -ENOMEM;
+ if (fake_inode) {
+ fake_file.f_mode = mode;
+ fake_file.f_flags = flags;
+ fake_file.f_dentry = &fake_dentry;
+ fake_dentry.d_inode = fake_inode;
+ fake_inode->i_rdev = rdev;
+ ret = 0;
+ if (fops->open)
+ ret = fops->open(fake_inode, &fake_file);
+ if (!ret)
+ atomic_inc(&bdev->bd_openers);
+ iput(fake_inode);
+ }
+ }
+ up(&bdev->bd_sem);
+ return ret;
+}
+
+int blkdev_put(struct block_device *bdev, int kind)
+{
+ int ret = 0;
+ kdev_t rdev = to_kdev_t(bdev->bd_dev); /* this should become bdev */
+ struct file_operations *fops = get_blkfops(MAJOR(rdev));
+ down(&bdev->bd_sem);
+ /* syncing will go here */
+ if (atomic_dec_and_test(&bdev->bd_openers)) {
+ /* invalidating buffers will go here */
+ }
+ if (fops->release) {
+ struct inode * fake_inode = get_empty_inode();
+ ret = -ENOMEM;
+ if (fake_inode) {
+ fake_inode->i_rdev = rdev;
+ ret = fops->release(fake_inode, NULL);
+ iput(fake_inode);
+ }
+ }
+ up(&bdev->bd_sem);
+ return ret;
+}
+
+char * bdevname(kdev_t dev)
+{
+ static char buffer[32];
+ const char * name = blkdevs[MAJOR(dev)].name;
+
+ if (!name)
+ name = "unknown-block";
+
+ sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
+ return buffer;
+}
+
+/*
+ * Called every time a block special file is opened
+ */
+int blkdev_open(struct inode * inode, struct file * filp)
+{
+ int ret = -ENODEV;
+ filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
+ if (filp->f_op != NULL){
+ ret = 0;
+ if (filp->f_op->open != NULL)
+ ret = filp->f_op->open(inode,filp);
+ }
+ return ret;
+}
+
+/*
+ * Dummy default file-operations: the only thing this does
+ * is contain the open that then fills in the correct operations
+ * depending on the special file...
+ */
+struct file_operations def_blk_fops = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ blkdev_open, /* open */
+ NULL, /* flush */
+ NULL, /* release */
+};
+
+struct inode_operations blkdev_inode_operations = {
+ &def_blk_fops, /* default file operations */
+};
{ NULL, NULL },
};
-static struct device_struct blkdevs[MAX_BLKDEV] = {
- { NULL, NULL },
-};
+extern int get_blkdev_list(char *);
int get_device_list(char * page)
{
len += sprintf(page+len, "%3d %s\n", i, chrdevs[i].name);
}
}
- len += sprintf(page+len, "\nBlock devices:\n");
- for (i = 0; i < MAX_BLKDEV ; i++) {
- if (blkdevs[i].fops) {
- len += sprintf(page+len, "%3d %s\n", i, blkdevs[i].name);
- }
- }
+ len += get_blkdev_list(page+len);
return len;
}
return ret;
}
-
-/*
- Return the function table of a device.
- Load the driver if needed.
-*/
-struct file_operations * get_blkfops(unsigned int major)
-{
- return get_fops (major,0,MAX_BLKDEV,"block-major-%d",blkdevs);
-}
-
struct file_operations * get_chrfops(unsigned int major, unsigned int minor)
{
return get_fops (major,minor,MAX_CHRDEV,"char-major-%d",chrdevs);
return 0;
}
-int register_blkdev(unsigned int major, const char * name, struct file_operations *fops)
-{
- if (major == 0) {
- for (major = MAX_BLKDEV-1; major > 0; major--) {
- if (blkdevs[major].fops == NULL) {
- blkdevs[major].name = name;
- blkdevs[major].fops = fops;
- return major;
- }
- }
- return -EBUSY;
- }
- if (major >= MAX_BLKDEV)
- return -EINVAL;
- if (blkdevs[major].fops && blkdevs[major].fops != fops)
- return -EBUSY;
- blkdevs[major].name = name;
- blkdevs[major].fops = fops;
- return 0;
-}
-
int unregister_chrdev(unsigned int major, const char * name)
{
if (major >= MAX_CHRDEV)
return 0;
}
-int unregister_blkdev(unsigned int major, const char * name)
-{
- if (major >= MAX_BLKDEV)
- return -EINVAL;
- if (!blkdevs[major].fops)
- return -EINVAL;
- if (strcmp(blkdevs[major].name, name))
- return -EINVAL;
- blkdevs[major].name = NULL;
- blkdevs[major].fops = NULL;
- return 0;
-}
-
-/*
- * This routine checks whether a removable media has been changed,
- * and invalidates all buffer-cache-entries in that case. This
- * is a relatively slow routine, so we have to try to minimize using
- * it. Thus it is called only upon a 'mount' or 'open'. This
- * is the best way of combining speed and utility, I think.
- * People changing diskettes in the middle of an operation deserve
- * to lose :-)
- */
-int check_disk_change(kdev_t dev)
-{
- int i;
- struct file_operations * fops;
- struct super_block * sb;
-
- i = MAJOR(dev);
- if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
- return 0;
- if (fops->check_media_change == NULL)
- return 0;
- if (!fops->check_media_change(dev))
- return 0;
-
- printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
- bdevname(dev));
-
- sb = get_super(dev);
- if (sb && invalidate_inodes(sb))
- printk("VFS: busy inodes on changed media.\n");
-
- invalidate_buffers(dev);
-
- if (fops->revalidate)
- fops->revalidate(dev);
- return 1;
-}
-
-/*
- * Called every time a block special file is opened
- */
-int blkdev_open(struct inode * inode, struct file * filp)
-{
- int ret = -ENODEV;
- filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
- if (filp->f_op != NULL){
- ret = 0;
- if (filp->f_op->open != NULL)
- ret = filp->f_op->open(inode,filp);
- }
- return ret;
-}
-
-int blkdev_release(struct inode * inode)
-{
- struct file_operations *fops = get_blkfops(MAJOR(inode->i_rdev));
- if (fops && fops->release)
- return fops->release(inode,NULL);
- return 0;
-}
-
-
-/*
- * Dummy default file-operations: the only thing this does
- * is contain the open that then fills in the correct operations
- * depending on the special file...
- */
-struct file_operations def_blk_fops = {
- NULL, /* lseek */
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- blkdev_open, /* open */
- NULL, /* flush */
- NULL, /* release */
-};
-
-static struct inode_operations blkdev_inode_operations = {
- &def_blk_fops, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
-};
-
/*
* Called every time a character special file is opened
*/
* is contain the open that then fills in the correct operations
* depending on the special file...
*/
-struct file_operations def_chr_fops = {
- NULL, /* lseek */
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- chrdev_open, /* open */
- NULL, /* flush */
- NULL, /* release */
+static struct file_operations def_chr_fops = {
+ open: chrdev_open
};
static struct inode_operations chrdev_inode_operations = {
- &def_chr_fops, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
+ &def_chr_fops /* default file operations */
};
/*
return buffer;
}
-char * bdevname(kdev_t dev)
-{
- static char buffer[32];
- const char * name = blkdevs[MAJOR(dev)].name;
-
- if (!name)
- name = "unknown-block";
-
- sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
- return buffer;
-}
-
char * cdevname(kdev_t dev)
{
static char buffer[32];
} else if (S_ISBLK(mode)) {
inode->i_op = &blkdev_inode_operations;
inode->i_rdev = to_kdev_t(rdev);
+ inode->i_bdev = bdget(rdev);
} else if (S_ISFIFO(mode))
- init_fifo(inode);
+ inode->i_op = &fifo_inode_operations;
else if (S_ISSOCK(mode))
;
else
struct inode_operations fifo_inode_operations = {
&def_fifo_fops, /* default file operations */
};
-
-
-/* Goner. Filesystems do not use it anymore. */
-
-void init_fifo(struct inode * inode)
-{
- inode->i_op = &fifo_inode_operations;
-}
DQUOT_DROP(inode);
if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->clear_inode)
inode->i_sb->s_op->clear_inode(inode);
-
+ if (inode->i_bdev) {
+ bdput(inode->i_bdev);
+ inode->i_bdev = NULL;
+ }
inode->i_state = 0;
}
inode->i_generation = 0;
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
inode->i_pipe = NULL;
+ inode->i_bdev = NULL;
}
/*
*/
#define WE_OBEY_THE_WRITTEN_STANDARDS 1
-static unsigned int isofs_get_last_session(kdev_t dev,s32 session )
+static unsigned int isofs_get_last_session(struct super_block *sb,s32 session )
{
- struct cdrom_multisession ms_info;
- unsigned int vol_desc_start;
- struct inode inode_fake;
- struct file_operations *fops;
- extern struct file_operations * get_blkfops(unsigned int);
- int i;
-
- vol_desc_start=0;
- fops = get_blkfops(MAJOR(dev));
- if (fops && fops->ioctl)
- {
- /* Whoops. We must save the old FS, since otherwise
- * we would destroy the kernels idea about FS on root
- * mount in read_super... [chexum]
- */
- mm_segment_t old_fs=get_fs();
- inode_fake.i_rdev=dev;
- init_waitqueue_head(&inode_fake.i_wait);
- ms_info.addr_format=CDROM_LBA;
- /* If a minor device was explicitly opened, set session to the
- * minor number. For instance, if /dev/hdc1 is mounted, session
- * 1 on the CD-ROM is selected. CD_PART_MAX gives access to
- * a max of 64 sessions on IDE. SCSI drives must still use
- * the session option to mount.
- */
- if ((MINOR(dev) % CD_PART_MAX) && (MAJOR(dev) != SCSI_CDROM_MAJOR))
+ struct cdrom_multisession ms_info;
+ unsigned int vol_desc_start;
+ struct block_device *bdev = sb->s_bdev;
+ kdev_t dev = sb->s_dev;
+ int i;
+
+ vol_desc_start=0;
+ ms_info.addr_format=CDROM_LBA;
+ /* If a minor device was explicitly opened, set session to the
+ * minor number. For instance, if /dev/hdc1 is mounted, session
+ * 1 on the CD-ROM is selected. CD_PART_MAX gives access to
+ * a max of 64 sessions on IDE. SCSI drives must still use
+ * the session option to mount.
+ */
+ if ((MINOR(dev) % CD_PART_MAX) && (MAJOR(dev) != SCSI_CDROM_MAJOR))
session = MINOR(dev) % CD_PART_MAX;
- set_fs(KERNEL_DS);
- if(session >= 0 && session <= 99) {
- struct cdrom_tocentry Te;
- Te.cdte_track=session;
- Te.cdte_format=CDROM_LBA;
- i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
- NULL,
- CDROMREADTOCENTRY,
- (unsigned long) &Te);
- set_fs(old_fs);
- if(!i) printk(KERN_ERR"Session %d start %d type %d\n",session,Te.cdte_addr.lba,Te.cdte_ctrl&CDROM_DATA_TRACK);
- if(i || (Te.cdte_ctrl&CDROM_DATA_TRACK) != 4)
- printk(KERN_ERR"Invalid session number or type of track\n");
- else return Te.cdte_addr.lba;
- }
- i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
- NULL,
- CDROMMULTISESSION,
- (unsigned long) &ms_info);
- set_fs(old_fs);
- if(session > 0) printk(KERN_ERR"Invalid session number\n");
+ if(session >= 0 && session <= 99) {
+ struct cdrom_tocentry Te;
+ Te.cdte_track=session;
+ Te.cdte_format=CDROM_LBA;
+ i = ioctl_by_bdev(bdev, CDROMREADTOCENTRY, (unsigned long) &Te);
+ if (!i) {
+ printk(KERN_DEBUG "Session %d start %d type %d\n",
+ session, Te.cdte_addr.lba,
+ Te.cdte_ctrl&CDROM_DATA_TRACK);
+ if ((Te.cdte_ctrl&CDROM_DATA_TRACK) == 4)
+ return Te.cdte_addr.lba;
+ }
+
+ printk(KERN_ERR "Invalid session number or type of track\n");
+ }
+ i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
+ if(session > 0) printk(KERN_ERR "Invalid session number\n");
#if 0
- printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
- if (i==0)
- {
- printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no");
- printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
+ printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
+ if (i==0) {
+ printk("isofs.inode: XA disk: %s\n",ms_info.xa_flag?"yes":"no");
+ printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
}
#endif
- if (i==0)
+ if (i==0)
#if WE_OBEY_THE_WRITTEN_STANDARDS
if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
#endif
- vol_desc_start=ms_info.addr.lba;
- }
- return vol_desc_start;
+ vol_desc_start=ms_info.addr.lba;
+ return vol_desc_start;
}
/*
s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */
vol_desc_start = (opt.sbsector != -1) ?
- opt.sbsector : isofs_get_last_session(dev,opt.session);
+ opt.sbsector : isofs_get_last_session(s,opt.session);
for (iso_blknum = vol_desc_start+16;
iso_blknum < vol_desc_start+100; iso_blknum++)
static DECLARE_MUTEX(mount_sem);
extern void wait_for_keypress(void);
-extern struct file_operations * get_blkfops(unsigned int major);
extern int root_mountflags;
return s;
}
-static struct super_block * read_super(kdev_t dev,const char *name,int flags,
+static struct super_block * read_super(kdev_t dev, struct block_device *bdev,
+ const char *name, int flags,
void *data, int silent)
{
struct super_block * s;
check_disk_change(dev);
s = get_super(dev);
if (s)
- goto out;
+ goto found; /* ought to set ->s_bdev */
type = get_fs_type(name);
if (!type) {
if (!s)
goto out;
s->s_dev = dev;
+ s->s_bdev = bdev;
s->s_flags = flags;
s->s_dirt = 0;
sema_init(&s->s_vfs_rename_sem,1);
/* N.B. Should lock superblock now ... */
if (!type->read_super(s, data, silent))
goto out_fail;
- s->s_dev = dev; /* N.B. why do this again?? */
s->s_type = type;
+bd_get:
+ /* tell bdcache that we are going to keep this one */
+ if (bdev)
+ atomic_inc(&bdev->bd_count);
out:
return s;
- /* N.B. s_dev should be cleared in type->read_super */
out_fail:
s->s_dev = 0;
+ s->s_bdev = 0;
out_null:
s = NULL;
goto out;
+found:
+ s->s_bdev = bdev;
+ goto bd_get;
}
/*
dentry->d_covers = covered;
}
-static int do_umount(kdev_t dev, int unmount_root, int flags)
+static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags)
{
struct super_block * sb;
+ struct block_device *bdev;
int retval;
retval = -ENOENT;
retval = 0;
if (!(sb->s_flags & MS_RDONLY))
retval = do_remount_sb(sb, MS_RDONLY, 0);
- return retval;
+ return ERR_PTR(retval);
}
retval = d_umount(sb);
}
sb->s_dev = 0; /* Free the superblock */
+ bdev = sb->s_bdev;
+ sb->s_bdev = NULL;
unlock_super(sb);
remove_vfsmnt(dev);
+
+ return bdev;
+
out:
- return retval;
+ return ERR_PTR(retval);
}
static int umount_dev(kdev_t dev, int flags)
{
int retval;
- struct inode * inode = get_empty_inode();
-
- retval = -ENOMEM;
- if (!inode)
- goto out;
+ struct block_device *bdev;
- inode->i_rdev = dev;
retval = -ENXIO;
if (MAJOR(dev) >= MAX_BLKDEV)
- goto out_iput;
+ goto out;
fsync_dev(dev);
down(&mount_sem);
- retval = do_umount(dev, 0, flags);
- if (!retval) {
- fsync_dev(dev);
- if (dev != ROOT_DEV) {
- blkdev_release(inode);
+ bdev = do_umount(dev, 0, flags);
+ if (IS_ERR(bdev))
+ retval = PTR_ERR(bdev);
+ else {
+ retval = 0;
+ if (bdev) {
+ blkdev_put(bdev, BDEV_FS);
+ bdput(bdev);
+ } else {
put_unnamed_dev(dev);
}
}
-
up(&mount_sem);
-out_iput:
- iput(inode);
out:
return retval;
}
* Now umount can handle mount points as well as block devices.
* This is important for filesystems which use unnamed block devices.
*
- * There is a little kludge here with the dummy_inode. The current
- * vfs release functions only use the r_dev field in the inode so
- * we give them the info they need without using a real inode.
- * If any other fields are ever needed by any block device release
- * functions, they should be faked here. -- jrs
- *
* We now support a flag for forced unmount like the other 'big iron'
* unixes. Our API is identical to OSF/1 to avoid making a mess of AMD
*/
* Anyone using this new feature must know what he/she is doing.
*/
-int do_mount(kdev_t dev, const char * dev_name, const char * dir_name,
- const char * type, int flags, void * data)
+int do_mount(struct block_device *bdev, const char *dev_name,
+ const char *dir_name, const char * type, int flags, void * data)
{
+ kdev_t dev;
struct dentry * dir_d;
struct super_block * sb;
struct vfsmount *vfsmnt;
int error;
+ if (bdev) {
+ mode_t mode = FMODE_READ; /* we always need it ;-) */
+ if (!(flags & MS_RDONLY))
+ mode |= FMODE_WRITE;
+ dev = to_kdev_t(bdev->bd_dev);
+ error = blkdev_get(bdev, mode, 0, BDEV_FS);
+ if (error)
+ return error;
+ } else {
+ dev = get_unnamed_dev();
+ if (!dev)
+ return -EMFILE; /* huh? */
+ }
+
error = -EACCES;
if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
goto out;
* read_super just does a get_super().
*/
error = -EINVAL;
- sb = read_super(dev, type, flags, data, 0);
+ sb = read_super(dev, bdev, type, flags, data, 0);
if (!sb)
goto dput_and_out;
*/
error = -EBUSY;
if (!fs_may_mount(dev))
- goto dput_and_out;
+ goto bdput_and_out;
error = -ENOMEM;
vfsmnt = add_vfsmnt(sb, dev_name, dir_name);
if (vfsmnt) {
d_mount(dget(dir_d), sb->s_root);
- error = 0;
+ dput(dir_d);
+ up(&mount_sem);
+ return 0;
}
+bdput_and_out:
+ sb->s_bdev = NULL;
+ if (bdev)
+ bdput(bdev);
dput_and_out:
dput(dir_d);
up(&mount_sem);
out:
- return error;
+ if (bdev)
+ blkdev_put(bdev, BDEV_FS);
+ else
+ put_unnamed_dev(dev);
+ return error;
}
struct file_system_type * fstype;
struct dentry * dentry = NULL;
struct inode * inode = NULL;
- kdev_t dev;
+ struct block_device *bdev = NULL;
int retval;
unsigned long flags = 0;
unsigned long page = 0;
- struct file dummy; /* allows read-write or read-only flag */
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (!fstype)
goto out;
- memset(&dummy, 0, sizeof(dummy));
if (fstype->fs_flags & FS_REQUIRES_DEV) {
dentry = namei(dev_name);
retval = PTR_ERR(dentry);
if (IS_NODEV(inode))
goto dput_and_out;
- dev = inode->i_rdev;
- retval = -ENXIO;
- if (MAJOR(dev) >= MAX_BLKDEV)
- goto dput_and_out;
-
- retval = -ENOTBLK;
- dummy.f_op = get_blkfops(MAJOR(dev));
- if (!dummy.f_op)
- goto dput_and_out;
-
- if (dummy.f_op->open) {
- dummy.f_dentry = dentry;
- dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
- retval = dummy.f_op->open(inode, &dummy);
- if (retval)
- goto dput_and_out;
- }
-
- } else {
- retval = -EMFILE;
- if (!(dev = get_unnamed_dev()))
- goto out;
+ bdev = inode->i_bdev;
}
page = 0;
flags = new_flags & ~MS_MGC_MSK;
retval = copy_mount_options(data, &page);
if (retval < 0)
- goto clean_up;
+ goto dput_and_out;
}
- retval = do_mount(dev, dev_name, dir_name, fstype->name, flags,
+ retval = do_mount(bdev, dev_name, dir_name, fstype->name, flags,
(void *) page);
free_page(page);
- if (retval)
- goto clean_up;
dput_and_out:
dput(dentry);
out:
unlock_kernel();
return retval;
-
-clean_up:
- if (dummy.f_op) {
- if (dummy.f_op->release)
- dummy.f_op->release(inode, NULL);
- } else
- put_unnamed_dev(dev);
- goto dput_and_out;
}
void __init mount_root(void)
struct file_system_type * fs_type;
struct super_block * sb;
struct vfsmount *vfsmnt;
- struct inode * d_inode = NULL;
- struct file filp;
+ struct block_device *bdev = NULL;
+ mode_t mode;
int retval;
#ifdef CONFIG_ROOT_NFS
if ((fs_type = get_fs_type("nfs"))) {
sb = get_empty_super(); /* "can't fail" */
sb->s_dev = get_unnamed_dev();
+ sb->s_bdev = NULL;
sb->s_flags = root_mountflags;
sema_init(&sb->s_vfs_rename_sem,1);
vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
}
#endif
- memset(&filp, 0, sizeof(filp));
- d_inode = get_empty_inode();
- if (!d_inode)
- panic(__FUNCTION__ ": unable to allocate root inode");
- d_inode->i_rdev = ROOT_DEV;
- filp.f_dentry = NULL;
- if ( root_mountflags & MS_RDONLY)
- filp.f_mode = 1; /* read only */
- else
- filp.f_mode = 3; /* read write */
- retval = blkdev_open(d_inode, &filp);
+ bdev = bdget(kdev_t_to_nr(ROOT_DEV));
+ if (!bdget)
+ panic(__FUNCTION__ ": unable to allocate root device");
+ mode = FMODE_READ;
+ if (!(root_mountflags & MS_RDONLY))
+ mode |= FMODE_WRITE;
+ retval = blkdev_get(bdev, mode, 0, BDEV_FS);
if (retval == -EROFS) {
root_mountflags |= MS_RDONLY;
- filp.f_mode = 1;
- retval = blkdev_open(d_inode, &filp);
+ retval = blkdev_get(bdev, FMODE_READ, 0, BDEV_FS);
}
- iput(d_inode);
if (retval)
/*
* Allow the user to distinguish between failed open
else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
if (!(fs_type->fs_flags & FS_REQUIRES_DEV))
continue;
- sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
+ sb = read_super(ROOT_DEV,bdev,fs_type->name,root_mountflags,NULL,1);
if (sb) {
sb->s_flags = root_mountflags;
current->fs->root = dget(sb->s_root);
fs_type->name,
(sb->s_flags & MS_RDONLY) ? " readonly" : "");
vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
- if (vfsmnt)
+ if (vfsmnt) {
+ bdput(bdev); /* sb holds a reference */
return;
+ }
panic("VFS: add_vfsmnt failed for root fs");
}
}
error = -ENOTDIR;
}
if (error) {
- int umount_error;
+ struct block_device *bdev;
printk(KERN_NOTICE "Trying to unmount old root ... ");
- umount_error = do_umount(old_root_dev,1, 0);
- if (!umount_error) {
+ bdev = do_umount(old_root_dev,1, 0);
+ if (!IS_ERR(bdev)) {
printk("okay\n");
invalidate_buffers(old_root_dev);
+ if (bdev) {
+ blkdev_put(bdev, BDEV_FS);
+ bdput(bdev);
+ }
return 0;
}
- printk(KERN_ERR "error %d\n",umount_error);
+ printk(KERN_ERR "error %d\n",PTR_ERR(bdev));
return error;
}
remove_vfsmnt(old_root_dev);
}
case FILE_TYPE_FIFO:
{
- init_special_inode(inode, inode->i_mode|S_FIFO, 0);
+ init_special_inode(inode, inode->i_mode | S_IFIFO, 0);
break;
}
case FILE_TYPE_SYMLINK:
#include "udf_sb.h"
unsigned int
-udf_get_last_session(kdev_t dev)
+udf_get_last_session(struct super_block *sb)
{
struct cdrom_multisession ms_info;
unsigned int vol_desc_start;
- struct inode inode_fake;
- extern struct file_operations * get_blkfops(unsigned int);
+ struct block_device *bdev = sb->s_bdev;
int i;
vol_desc_start=0;
- if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
- {
- /* Whoops. We must save the old FS, since otherwise
- * we would destroy the kernels idea about FS on root
- * mount in read_super... [chexum]
- */
- mm_segment_t old_fs=get_fs();
- inode_fake.i_rdev=dev;
- ms_info.addr_format=CDROM_LBA;
- set_fs(KERNEL_DS);
- i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
- NULL,
- CDROMMULTISESSION,
- (unsigned long) &ms_info);
- set_fs(old_fs);
-
+ ms_info.addr_format=CDROM_LBA;
+ i=ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
#define WE_OBEY_THE_WRITTEN_STANDARDS 1
-
- if (i == 0)
- {
- udf_debug("XA disk: %s, vol_desc_start=%d\n",
- (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
+ if (i == 0) {
+ udf_debug("XA disk: %s, vol_desc_start=%d\n",
+ (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
#if WE_OBEY_THE_WRITTEN_STANDARDS
- if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
+ if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
#endif
- vol_desc_start = ms_info.addr.lba;
- }
- else
- {
- udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
- }
- }
- else
- {
- udf_debug("Device doesn't know how to ioctl?\n");
+ vol_desc_start = ms_info.addr.lba;
+ } else {
+ udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
}
return vol_desc_start;
}
unsigned int
-udf_get_last_block(kdev_t dev, int *flags)
+udf_get_last_block(struct super_block *sb, int *flags)
{
extern int *blksize_size[];
- struct inode inode_fake;
- extern struct file_operations * get_blkfops(unsigned int);
+ kdev_t dev = sb->s_dev;
+ struct block_device *bdev = sb->s_bdev;
int ret;
unsigned long lblock;
unsigned int hbsize = get_hardblocksize(dev);
else if (hbsize > secsize)
div = hbsize / secsize;
- if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
- {
- /* Whoops. We must save the old FS, since otherwise
- * we would destroy the kernels idea about FS on root
- * mount in read_super... [chexum]
- */
- mm_segment_t old_fs=get_fs();
- inode_fake.i_rdev=dev;
- set_fs(KERNEL_DS);
-
- lblock = 0;
- ret = get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
- NULL,
- BLKGETSIZE,
- (unsigned long) &lblock);
-
- if (!ret && lblock != 0x7FFFFFFF) /* Hard Disk */
- {
- if (mult)
- lblock *= mult;
- else if (div)
- lblock /= div;
- }
- else /* CDROM */
- {
- ret = get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
- NULL,
- CDROM_LAST_WRITTEN,
- (unsigned long) &lblock);
- }
-
- set_fs(old_fs);
- if (!ret && lblock)
- return lblock - 1;
- }
- else
- {
- udf_debug("Device doesn't know how to ioctl?\n");
+ lblock = 0;
+ ret = ioctl_by_bdev(bdev, BLKGETSIZE, (unsigned long) &lblock);
+
+ if (!ret && lblock != 0x7FFFFFFF) {
+ /* Hard Disk */
+ if (mult)
+ lblock *= mult;
+ else if (div)
+ lblock /= div;
+ } else {
+ /* CDROM */
+ ret = ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock);
}
+ if (!ret && lblock)
+ return lblock - 1;
return 0;
}
goto error_out;
if ( uopt.session == 0xFFFFFFFF )
- UDF_SB_SESSION(sb) = udf_get_last_session(sb->s_dev);
+ UDF_SB_SESSION(sb) = udf_get_last_session(sb);
else
UDF_SB_SESSION(sb) = uopt.session;
udf_debug("Multi-session=%d\n", UDF_SB_SESSION(sb));
if ( uopt.lastblock == 0xFFFFFFFF )
- UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb->s_dev, &(UDF_SB(sb)->s_flags));
+ UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb, &(UDF_SB(sb)->s_flags));
else
UDF_SB_LASTBLOCK(sb) = uopt.lastblock;
extern void udf_release_data(struct buffer_head *);
/* lowlevel.c */
-extern unsigned int udf_get_last_session(kdev_t);
-extern unsigned int udf_get_last_block(kdev_t, int *);
+extern unsigned int udf_get_last_session(struct super_block *);
+extern unsigned int udf_get_last_block(struct super_block *, int *);
/* partition.c */
extern Uint32 udf_get_pblock(struct super_block *, Uint32, Uint16, Uint32);
}
/* we use FASTCALL convention for the helpers */
-extern struct rw_semaphore *FASTCALL(down_read_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(down_write_failed(struct rw_semaphore *sem));
-extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(__down_read_failed(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem));
+extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem));
extern inline void down_read(struct rw_semaphore *sem)
{
}
}
+extern int acpi_active;
+
#else /* CONFIG_ACPI */
extern inline struct acpi_dev*
unsigned long nrpages;
};
+struct block_device {
+ struct list_head bd_hash;
+ atomic_t bd_count;
+/* struct address_space bd_data; */
+ dev_t bd_dev; /* not a kdev_t - it's a search key */
+ atomic_t bd_openers;
+/* struct bdev_operations *bd_op; */
+ struct semaphore bd_sem; /* open/close mutex */
+};
+
struct inode {
struct list_head i_hash;
struct list_head i_list;
spinlock_t i_shared_lock;
struct dquot *i_dquot[MAXQUOTAS];
struct pipe_inode_info *i_pipe;
+ struct block_device *i_bdev;
unsigned long i_state;
struct list_head s_dirty; /* dirty inodes */
struct list_head s_files;
+ struct block_device *s_bdev;
+
union {
struct minix_sb_info minix_sb;
struct ext2_sb_info ext2_sb;
#define __getname() ((char *) __get_free_page(GFP_KERNEL))
#define putname(name) free_page((unsigned long)(name))
+enum {BDEV_FILE, BDEV_SWAP, BDEV_FS, BDEV_RAW};
extern void kill_fasync(struct fasync_struct *, int, int);
extern int register_blkdev(unsigned int, const char *, struct file_operations *);
extern int unregister_blkdev(unsigned int, const char *);
+extern struct block_device *bdget(dev_t);
+extern void bdput(struct block_device *);
extern int blkdev_open(struct inode *, struct file *);
-extern int blkdev_release (struct inode *);
extern struct file_operations def_blk_fops;
+extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
+extern int blkdev_get(struct block_device *, mode_t, unsigned, int);
+extern int blkdev_put(struct block_device *, int);
/* fs/devices.c */
extern int register_chrdev(unsigned int, const char *, struct file_operations *);
extern char * kdevname(kdev_t);
extern void init_special_inode(struct inode *, umode_t, int);
-extern void init_fifo(struct inode *);
extern struct inode_operations fifo_inode_operations;
+extern struct inode_operations blkdev_inode_operations;
/* Invalid inode operations -- fs/bad_inode.c */
extern void make_bad_inode(struct inode *);
#include <linux/types.h>
#include <linux/config.h>
#include <linux/ioport.h>
+#include <linux/list.h>
#include <asm/pci.h>
* The pci_dev structure is used to describe both PCI and ISAPnP devices.
*/
struct pci_dev {
- int active; /* device is active */
- int ro; /* Read/Only */
-
+ struct list_head global_list; /* node in list of all PCI devices */
+ struct list_head bus_list; /* node in per-bus list */
struct pci_bus *bus; /* bus this device is on */
struct pci_bus *subordinate; /* bus this device bridges to */
- struct pci_dev *sibling; /* next device on this bus */
- struct pci_dev *next; /* chain of all devices */
void *sysdata; /* hook for sys-specific extension */
struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */
char name[48]; /* Device name */
char slot_name[8]; /* Slot name */
+ int active; /* device is active */
+ int ro; /* Read/Only */
int (*prepare)(struct pci_dev *dev);
int (*activate)(struct pci_dev *dev);
int (*deactivate)(struct pci_dev *dev);
};
+#define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
+#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list)
+
/*
* For PCI devices, the region numbers are assigned this way:
*
#define PCI_REGION_FLAG_MASK 0x0f /* These bits of resource flags tell us the PCI region flags */
struct pci_bus {
+ struct list_head node; /* node in list of buses */
struct pci_bus *parent; /* parent bus this bridge is on */
- struct pci_bus *children; /* chain of P2P bridges on this bus */
- struct pci_bus *next; /* chain of all PCI buses */
- struct pci_ops *ops; /* configuration access functions */
-
+ struct list_head children; /* list of child buses */
+ struct list_head devices; /* list of devices on this bus */
struct pci_dev *self; /* bridge device as seen by parent */
- struct pci_dev *devices; /* devices behind this bridge */
- struct pci_dev **last_dev_p; /* where should next device be linked to */
struct resource *resource[4]; /* address space routed to this bus */
+ struct pci_ops *ops; /* configuration access functions */
void *sysdata; /* hook for sys-specific extension */
struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */
unsigned char pad1;
};
-extern struct pci_bus *pci_root; /* root bus */
-extern struct pci_dev *pci_devices; /* list of all devices */
+#define pci_bus_b(n) list_entry(n, struct pci_bus, node)
+
+extern struct list_head pci_root_buses; /* list of all known PCI buses */
+extern struct list_head pci_devices; /* list of all devices */
/*
* Error values that may be returned by PCI functions.
char *pci_class_name(u32 class);
void pci_read_bridge_bases(struct pci_bus *child);
struct resource *pci_find_parent_resource(struct pci_dev *dev, struct resource *res);
+int pci_setup_device(struct pci_dev * dev);
/* Generic PCI functions exported to card drivers */
int pci_write_config_word(struct pci_dev *dev, int where, u16 val);
int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);
-int pci_setup_device(struct pci_dev * dev);
int pci_enable_device(struct pci_dev *dev);
void pci_set_master(struct pci_dev *dev);
int pci_set_power_state(struct pci_dev *dev, int state);
int pci_assign_resource(struct pci_dev *dev, int i);
+#define __pcidev(entry) list_entry(entry, struct pci_dev, global_list)
+
+#define pci_for_each_dev(dev) \
+ for(dev = __pcidev(pci_devices.next); dev != __pcidev(&pci_devices); dev = __pcidev(dev->global_list.next))
+
/* Helper functions for low-level code (drivers/pci/setup.c) */
int pci_claim_resource(struct pci_dev *, int);
extern void get_random_bytes(void *buf, int nbytes);
void generate_random_uuid(unsigned char uuid_out[16]);
+extern __u32 secure_ip_id(__u32 daddr);
extern __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
__u16 sport, __u16 dport);
extern __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr,
__u32 daddr, __u16 sport,
__u16 dport, __u32 sseq,
__u32 count, __u32 maxdiff);
+extern __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr,
+ __u16 sport, __u16 dport);
+
+extern __u32 secure_ipv6_id(__u32 *daddr);
#ifndef MODULE
extern struct file_operations random_fops, urandom_fops;
__s32 rta_expires;
__u32 rta_error;
__u32 rta_used;
+
+#define RTNETLINK_HAVE_PEERINFO 1
+ __u32 rta_id;
+ __u32 rta_ts;
+ __u32 rta_tsage;
};
/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */
NET_TCP_TW_RECYCLE=66,
NET_IPV4_ALWAYS_DEFRAG=67,
NET_IPV4_TCP_KEEPALIVE_INTVL=68,
+ NET_IPV4_INET_PEER_THRESHOLD=69,
+ NET_IPV4_INET_PEER_MINTTL=70,
+ NET_IPV4_INET_PEER_MAXTTL=71,
+ NET_IPV4_INET_PEER_GC_MINTIME=72,
+ NET_IPV4_INET_PEER_GC_MAXTIME=73
};
enum {
--- /dev/null
+/*
+ * INETPEER - A storage for permanent information about peers
+ *
+ * Version: $Id: inetpeer.h,v 1.1 2000/01/06 00:41:51 davem Exp $
+ *
+ * Authors: Andrey V. Savochkin <saw@msu.ru>
+ */
+
+#ifndef _NET_INETPEER_H
+#define _NET_INETPEER_H
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+struct inet_peer
+{
+ struct inet_peer *avl_left, *avl_right;
+ struct inet_peer *unused_next, **unused_prevp;
+ atomic_t refcnt;
+ unsigned long dtime; /* the time of last use of not
+ * referenced entries */
+ __u32 v4daddr; /* peer's address */
+ __u16 avl_height;
+ __u16 ip_id_count; /* IP ID for the next packet */
+ __u32 tcp_ts;
+ unsigned long tcp_ts_stamp;
+};
+
+void inet_initpeers(void) __init;
+
+/* can be called with or without local BH being disabled */
+struct inet_peer *inet_getpeer(__u32 daddr, int create);
+
+extern spinlock_t inet_peer_unused_lock;
+extern struct inet_peer *inet_peer_unused_head;
+extern struct inet_peer **inet_peer_unused_tailp;
+/* can be called from BH context or outside */
+extern inline void inet_putpeer(struct inet_peer *p)
+{
+ spin_lock_bh(&inet_peer_unused_lock);
+ if (atomic_dec_and_test(&p->refcnt)) {
+ p->unused_prevp = inet_peer_unused_tailp;
+ p->unused_next = NULL;
+ *inet_peer_unused_tailp = p;
+ inet_peer_unused_tailp = &p->unused_next;
+ p->dtime = jiffies;
+ }
+ spin_unlock_bh(&inet_peer_unused_lock);
+}
+
+extern spinlock_t inet_peer_idlock;
+/* can be called with or without local BH being disabled */
+extern inline __u16 inet_getid(struct inet_peer *p)
+{
+ __u16 id;
+
+ spin_lock_bh(&inet_peer_idlock);
+ id = p->ip_id_count++;
+ spin_unlock_bh(&inet_peer_idlock);
+ return id;
+}
+
+#endif /* _NET_INETPEER_H */
extern int ip_fragment(struct sk_buff *skb, int (*out)(struct sk_buff*));
extern int ip_do_nat(struct sk_buff *skb);
extern void ip_send_check(struct iphdr *ip);
-extern int ip_id_count;
extern int ip_queue_xmit(struct sk_buff *skb);
extern void ip_init(void);
extern int ip_build_xmit(struct sock *sk,
!(dst->mxlock&(1<<RTAX_MTU))));
}
+extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst);
+
+extern __inline__ void ip_select_ident(struct iphdr *iph, struct dst_entry *dst)
+{
+ if (iph->frag_off&__constant_htons(IP_DF))
+ iph->id = 0;
+ else
+ __ip_select_ident(iph, dst);
+}
+
/*
* Map a multicast IP onto multicast MAC for type ethernet.
*/
#include <linux/config.h>
#include <net/dst.h>
+#include <net/inetpeer.h>
#include <linux/in_route.h>
#include <linux/rtnetlink.h>
#include <linux/route.h>
__u8 scope;
};
+struct inet_peer;
struct rtable
{
union
/* Miscellaneous cached information */
__u32 rt_spec_dst; /* RFC1122 specific destination */
+ struct inet_peer *peer; /* long-living peer info */
#ifdef CONFIG_IP_ROUTE_NAT
__u32 rt_src_map;
return ip_route_output(rp, dst, src, tos, oif);
}
+extern void rt_bind_peer(struct rtable *rt, int create);
+
+extern __inline__ struct inet_peer *rt_get_peer(struct rtable *rt)
+{
+ if (rt->peer)
+ return rt->peer;
+
+ rt_bind_peer(rt, 0);
+ return rt->peer;
+}
+
#endif /* _ROUTE_H */
page_cache_init(mempages);
kiobuf_init();
signals_init();
+ bdev_init();
inode_init();
file_table_init();
#if defined(CONFIG_SYSVIPC)
extern int console_loglevel;
extern void set_device_ro(kdev_t dev,int flag);
-extern struct file_operations * get_blkfops(unsigned int);
-extern int blkdev_release(struct inode * inode);
#if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
extern int (*do_nfsservctl)(int, void *, void *);
#endif
EXPORT_SYMBOL(set_device_ro);
EXPORT_SYMBOL(bmap);
EXPORT_SYMBOL(sync_dev);
-EXPORT_SYMBOL(get_blkfops);
EXPORT_SYMBOL(blkdev_open);
-EXPORT_SYMBOL(blkdev_release);
+EXPORT_SYMBOL(blkdev_get);
+EXPORT_SYMBOL(blkdev_put);
+EXPORT_SYMBOL(ioctl_by_bdev);
EXPORT_SYMBOL(gendisk_head);
EXPORT_SYMBOL(resetup_one_dev);
EXPORT_SYMBOL(unplug_device);
EXPORT_SYMBOL(nr_async_pages);
EXPORT_SYMBOL(___strtok);
EXPORT_SYMBOL(init_special_inode);
-EXPORT_SYMBOL(fifo_inode_operations);
EXPORT_SYMBOL(read_ahead);
EXPORT_SYMBOL(get_hash_table);
EXPORT_SYMBOL(get_empty_inode);
{
struct swap_info_struct * p = NULL;
struct dentry * dentry;
- struct file filp;
int i, type, prev;
int err = -EPERM;
p->flags = SWP_WRITEOK;
goto out_dput;
}
- if(p->swap_device){
- memset(&filp, 0, sizeof(filp));
- filp.f_dentry = dentry;
- filp.f_mode = 3; /* read write */
- /* open it again to get fops */
- if( !blkdev_open(dentry->d_inode, &filp) &&
- filp.f_op && filp.f_op->release){
- filp.f_op->release(dentry->d_inode,&filp);
- filp.f_op->release(dentry->d_inode,&filp);
- }
- }
+ if (p->swap_device)
+ blkdev_put(dentry->d_inode->i_bdev, BDEV_SWAP);
dput(dentry);
dentry = p->swap_file;
unsigned int type;
int i, j, prev;
int error = -EPERM;
- struct file filp;
static int least_priority = 0;
union swap_header *swap_header = 0;
int swap_header_version;
int nr_good_pages = 0;
unsigned long maxpages;
int swapfilesize;
+ struct block_device *bdev = NULL;
lock_kernel();
if (!capable(CAP_SYS_ADMIN))
goto out;
- memset(&filp, 0, sizeof(filp));
p = swap_info;
for (type = 0 ; type < nr_swapfiles ; type++,p++)
if (!(p->flags & SWP_USED))
p->swap_device = dev;
set_blocksize(dev, PAGE_SIZE);
- filp.f_dentry = swap_dentry;
- filp.f_mode = 3; /* read write */
- error = blkdev_open(swap_dentry->d_inode, &filp);
+ bdev = swap_dentry->d_inode->i_bdev;
+
+ error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_SWAP);
if (error)
goto bad_swap_2;
set_blocksize(dev, PAGE_SIZE);
error = 0;
goto out;
bad_swap:
- if(filp.f_op && filp.f_op->release)
- filp.f_op->release(filp.f_dentry->d_inode,&filp);
+ if (bdev)
+ blkdev_put(bdev, BDEV_SWAP);
bad_swap_2:
if (p->swap_map)
vfree(p->swap_map);
define_bool CONFIG_NETLINK y
bool ' IP: policy routing' CONFIG_IP_MULTIPLE_TABLES
if [ "$CONFIG_IP_MULTIPLE_TABLES" = "y" ]; then
- bool ' IP: use FWMARK value as routing key' CONFIG_IP_ROUTE_FWMARK
+ if [ "$CONFIG_NETFILTER" = "y" ]; then
+ bool ' IP: use FWMARK value as routing key' CONFIG_IP_ROUTE_FWMARK
+ fi
bool ' IP: fast network address translation' CONFIG_IP_ROUTE_NAT
fi
bool ' IP: equal cost multipath' CONFIG_IP_ROUTE_MULTIPATH
# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := ipv4.o
-IPV4_OBJS := utils.o route.o proc.o protocol.o \
+IPV4_OBJS := utils.o route.o inetpeer.o proc.o protocol.o \
ip_input.o ip_fragment.o ip_forward.o ip_options.o \
ip_output.o ip_sockglue.o \
tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o\
* the older version didn't come out right using gcc 2.5.8, the newer one
* seems to fall out with gcc 2.6.2.
*
- * Version: $Id: igmp.c,v 1.35 1999/12/15 22:39:10 davem Exp $
+ * Version: $Id: igmp.c,v 1.36 2000/01/06 00:41:54 davem Exp $
*
* Authors:
* Alan Cox <Alan.Cox@linux.org>
iph->version = 4;
iph->ihl = (sizeof(struct iphdr)+4)>>2;
iph->tos = 0;
- iph->frag_off = 0;
+ iph->frag_off = __constant_htons(IP_DF);
iph->ttl = 1;
iph->daddr = dst;
iph->saddr = rt->rt_src;
iph->protocol = IPPROTO_IGMP;
iph->tot_len = htons(IGMP_SIZE);
- iph->id = htons(ip_id_count++);
+ ip_select_ident(iph, &rt->u.dst);
((u8*)&iph[1])[0] = IPOPT_RA;
((u8*)&iph[1])[1] = 4;
((u8*)&iph[1])[2] = 0;
--- /dev/null
+/*
+ * INETPEER - A storage for permanent information about peers
+ *
+ * This source is covered by the GNU GPL, the same as all kernel sources.
+ *
+ * Version: $Id: inetpeer.c,v 1.1 2000/01/06 00:41:55 davem Exp $
+ *
+ * Authors: Andrey V. Savochkin <saw@msu.ru>
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <net/inetpeer.h>
+
+/*
+ * Theory of operations.
+ * We keep one entry for each peer IP address. The nodes contains long-living
+ * information about the peer which doesn't depend on routes.
+ * At this moment this information consists only of ID field for the next
+ * outgoing IP packet. This field is incremented with each packet as encoded
+ * in inet_getid() function (include/net/inetpeer.h).
+ * At the moment of writing this notes identifier of IP packets is generated
+ * to be unpredictable using this code only for packets subjected
+ * (actually or potentially) to defragmentation. I.e. DF packets less than
+ * PMTU in size uses a constant ID and do not use this code (see
+ * ip_select_ident() in include/net/ip.h).
+ *
+ * Route cache entries hold references to our nodes.
+ * New cache entries get references via lookup by destination IP address in
+ * the avl tree. The reference is grabbed only when it's needed i.e. only
+ * when we try to output IP packet which needs an unpredictable ID (see
+ * __ip_select_ident() in net/ipv4/route.c).
+ * Nodes are removed only when reference counter goes to 0.
+ * When it's happened the node may be removed when a sufficient amount of
+ * time has been passed since its last use. The less-recently-used entry can
+ * also be removed if the pool is overloaded i.e. if the total amount of
+ * entries is greater-or-equal than the threshold.
+ *
+ * Node pool is organised as an AVL tree.
+ * Such an implementation has been chosen not just for fun. It's a way to
+ * prevent easy and efficient DoS attacks by creating hash collisions. A huge
+ * amount of long living nodes in a single hash slot would significantly delay
+ * lookups performed with disabled BHs.
+ *
+ * Serialisation issues.
+ * 1. Nodes may appear in the tree only with the pool write lock held.
+ * 2. Nodes may disappear from the tree only with the pool write lock held
+ * AND reference count being 0.
+ * 3. Nodes appears and disappears from unused node list only under
+ * "inet_peer_unused_lock".
+ * 4. Global variable peer_total is modified under the pool lock.
+ * 5. struct inet_peer fields modification:
+ * avl_left, avl_right, avl_parent, avl_height: pool lock
+ * unused_next, unused_prevp: unused node list lock
+ * refcnt: atomically against modifications on other CPU;
+ * usually under some other lock to prevent node disappearing
+ * dtime: unused node list lock
+ * v4daddr: unchangeable
+ * ip_id_count: idlock
+ */
+
+spinlock_t inet_peer_idlock = SPIN_LOCK_UNLOCKED;
+
+static kmem_cache_t *peer_cachep;
+
+#define node_height(x) x->avl_height
+static struct inet_peer peer_fake_node = {
+ avl_left : &peer_fake_node,
+ avl_right : &peer_fake_node,
+ avl_height : 0
+};
+#define peer_avl_empty (&peer_fake_node)
+static struct inet_peer *peer_root = peer_avl_empty;
+static rwlock_t peer_pool_lock = RW_LOCK_UNLOCKED;
+#define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */
+
+static volatile int peer_total = 0;
+int inet_peer_threshold = 65536 + 128; /* start to throw entries more
+ * aggressively at this stage */
+int inet_peer_minttl = 120 * HZ; /* TTL under high load: 120 sec */
+int inet_peer_maxttl = 10 * 60 * HZ; /* usual time to live: 10 min */
+struct inet_peer *inet_peer_unused_head = NULL,
+ **inet_peer_unused_tailp = &inet_peer_unused_head;
+spinlock_t inet_peer_unused_lock = SPIN_LOCK_UNLOCKED;
+#define PEER_MAX_CLEANUP_WORK 30
+
+static void peer_check_expire(unsigned long dummy);
+static struct timer_list peer_periodic_timer =
+ { NULL, NULL, 0, 0, &peer_check_expire };
+int inet_peer_gc_mintime = 10 * HZ,
+ inet_peer_gc_maxtime = 120 * HZ;
+
+
+void __init inet_initpeers(void)
+{
+ struct sysinfo si;
+
+ /* Use the straight interface to information about memory. */
+ si_meminfo(&si);
+ /* The values below were suggested by Alexey Kuznetsov
+ * <kuznet@ms2.inr.ac.ru>. I don't have any opinion about the values
+ * myself. --SAW
+ */
+ if (si.totalram <= 32768*1024)
+ inet_peer_threshold >>= 1; /* max pool size about 1MB on IA32 */
+ if (si.totalram <= 16384*1024)
+ inet_peer_threshold >>= 1; /* about 512KB */
+ if (si.totalram <= 8192*1024)
+ inet_peer_threshold >>= 2; /* about 128KB */
+
+ peer_cachep = kmem_cache_create("inet_peer_cache",
+ sizeof(struct inet_peer),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+
+ /* All the timers, started at system startup tend
+ to synchronize. Perturb it a bit.
+ */
+ peer_periodic_timer.expires = jiffies
+ + net_random() % inet_peer_gc_maxtime
+ + inet_peer_gc_maxtime;
+ add_timer(&peer_periodic_timer);
+}
+
+/* Called with or without local BH being disabled. */
+static void unlink_from_unused(struct inet_peer *p)
+{
+ spin_lock_bh(&inet_peer_unused_lock);
+ if (p->unused_prevp != NULL) {
+ /* On unused list. */
+ *p->unused_prevp = p->unused_next;
+ if (p->unused_next != NULL)
+ p->unused_next->unused_prevp = p->unused_prevp;
+ else
+ inet_peer_unused_tailp = p->unused_prevp;
+ p->unused_prevp = NULL; /* mark it as removed */
+ }
+ spin_unlock_bh(&inet_peer_unused_lock);
+}
+
+/* Called with local BH disabled and the pool lock held. */
+#define lookup(daddr) \
+({ \
+ struct inet_peer *u, **v; \
+ stackptr = stack; \
+ *stackptr++ = &peer_root; \
+ for (u = peer_root; u != peer_avl_empty; ) { \
+ if (daddr == u->v4daddr) \
+ break; \
+ if (daddr < u->v4daddr) \
+ v = &u->avl_left; \
+ else \
+ v = &u->avl_right; \
+ *stackptr++ = v; \
+ u = *v; \
+ } \
+ u; \
+})
+
+/* Called with local BH disabled and the pool write lock held. */
+#define lookup_rightempty(start) \
+({ \
+ struct inet_peer *u, **v; \
+ *stackptr++ = &start->avl_left; \
+ v = &start->avl_left; \
+ for (u = *v; u->avl_right != peer_avl_empty; ) { \
+ v = &u->avl_right; \
+ *stackptr++ = v; \
+ u = *v; \
+ } \
+ u; \
+})
+
+/* Called with local BH disabled and the pool write lock held.
+ * Variable names are the proof of operation correctness.
+ * Look into mm/map_avl.c for more detail description of the ideas. */
+static void peer_avl_rebalance(struct inet_peer **stack[],
+ struct inet_peer ***stackend)
+{
+ struct inet_peer **nodep, *node, *l, *r;
+ int lh, rh;
+
+ while (stackend > stack) {
+ nodep = *--stackend;
+ node = *nodep;
+ l = node->avl_left;
+ r = node->avl_right;
+ lh = node_height(l);
+ rh = node_height(r);
+ if (lh > rh + 1) { /* l: RH+2 */
+ struct inet_peer *ll, *lr, *lrl, *lrr;
+ int lrh;
+ ll = l->avl_left;
+ lr = l->avl_right;
+ lrh = node_height(lr);
+ if (lrh <= node_height(ll)) { /* ll: RH+1 */
+ node->avl_left = lr; /* lr: RH or RH+1 */
+ node->avl_right = r; /* r: RH */
+ node->avl_height = lrh + 1; /* RH+1 or RH+2 */
+ l->avl_left = ll; /* ll: RH+1 */
+ l->avl_right = node; /* node: RH+1 or RH+2 */
+ l->avl_height = node->avl_height + 1;
+ *nodep = l;
+ } else { /* ll: RH, lr: RH+1 */
+ lrl = lr->avl_left; /* lrl: RH or RH-1 */
+ lrr = lr->avl_right; /* lrr: RH or RH-1 */
+ node->avl_left = lrr; /* lrr: RH or RH-1 */
+ node->avl_right = r; /* r: RH */
+ node->avl_height = rh + 1; /* node: RH+1 */
+ l->avl_left = ll; /* ll: RH */
+ l->avl_right = lrl; /* lrl: RH or RH-1 */
+ l->avl_height = rh + 1; /* l: RH+1 */
+ lr->avl_left = l; /* l: RH+1 */
+ lr->avl_right = node; /* node: RH+1 */
+ lr->avl_height = rh + 2;
+ *nodep = lr;
+ }
+ } else if (rh > lh + 1) { /* r: LH+2 */
+ struct inet_peer *rr, *rl, *rlr, *rll;
+ int rlh;
+ rr = r->avl_right;
+ rl = r->avl_left;
+ rlh = node_height(rl);
+ if (rlh <= node_height(rr)) { /* rr: LH+1 */
+ node->avl_right = rl; /* rl: LH or LH+1 */
+ node->avl_left = l; /* l: LH */
+ node->avl_height = rlh + 1; /* LH+1 or LH+2 */
+ r->avl_right = rr; /* rr: LH+1 */
+ r->avl_left = node; /* node: LH+1 or LH+2 */
+ r->avl_height = node->avl_height + 1;
+ *nodep = r;
+ } else { /* rr: RH, rl: RH+1 */
+ rlr = rl->avl_right; /* rlr: LH or LH-1 */
+ rll = rl->avl_left; /* rll: LH or LH-1 */
+ node->avl_right = rll; /* rll: LH or LH-1 */
+ node->avl_left = l; /* l: LH */
+ node->avl_height = lh + 1; /* node: LH+1 */
+ r->avl_right = rr; /* rr: LH */
+ r->avl_left = rlr; /* rlr: LH or LH-1 */
+ r->avl_height = lh + 1; /* r: LH+1 */
+ rl->avl_right = r; /* r: LH+1 */
+ rl->avl_left = node; /* node: LH+1 */
+ rl->avl_height = lh + 2;
+ *nodep = rl;
+ }
+ } else {
+ node->avl_height = (lh > rh ? lh : rh) + 1;
+ }
+ }
+}
+
+/* Called with local BH disabled and the pool write lock held. */
+#define link_to_pool(n) \
+do { \
+ n->avl_height = 1; \
+ n->avl_left = peer_avl_empty; \
+ n->avl_right = peer_avl_empty; \
+ **--stackptr = n; \
+ peer_avl_rebalance(stack, stackptr); \
+} while(0)
+
+/* May be called with local BH enabled. */
+static void unlink_from_pool(struct inet_peer *p)
+{
+ int do_free;
+
+ do_free = 0;
+
+ write_lock_bh(&peer_pool_lock);
+ /* Check the reference counter. It was artificially incremented by 1
+ * in cleanup() function to prevent sudden disappearing. If the
+ * reference count is still 1 then the node is referenced only as `p'
+ * here and from the pool. So under the exclusive pool lock it's safe
+ * to remove the node and free it later. */
+ if (atomic_read(&p->refcnt) == 1) {
+ struct inet_peer **stack[PEER_MAXDEPTH];
+ struct inet_peer ***stackptr, ***delp;
+ if (lookup(p->v4daddr) != p)
+ BUG();
+ delp = stackptr - 1; /* *delp[0] == p */
+ if (p->avl_left == peer_avl_empty) {
+ *delp[0] = p->avl_right;
+ --stackptr;
+ } else {
+ /* look for a node to insert instead of p */
+ struct inet_peer *t;
+ t = lookup_rightempty(p);
+ if (*stackptr[-1] != t)
+ BUG();
+ **--stackptr = t->avl_left;
+ /* t is removed, t->v4daddr > x->v4daddr for any
+ * x in p->avl_left subtree.
+ * Put t in the old place of p. */
+ *delp[0] = t;
+ t->avl_left = p->avl_left;
+ t->avl_right = p->avl_right;
+ t->avl_height = p->avl_height;
+ if (delp[1] != &p->avl_left)
+ BUG();
+ delp[1] = &t->avl_left; /* was &p->avl_left */
+ }
+ peer_avl_rebalance(stack, stackptr);
+ peer_total--;
+ do_free = 1;
+ }
+ write_unlock_bh(&peer_pool_lock);
+
+ if (do_free)
+ kmem_cache_free(peer_cachep, p);
+ else
+ /* The node is used again. Decrease the reference counter
+ * back. The loop "cleanup -> unlink_from_unused
+ * -> unlink_from_pool -> putpeer -> link_to_unused
+ * -> cleanup (for the same node)"
+ * doesn't really exist because the entry will have a
+ * recent deletion time and will not be cleaned again soon. */
+ inet_putpeer(p);
+}
+
+/* May be called with local BH enabled. */
+static int cleanup_once(unsigned long ttl)
+{
+ struct inet_peer *p;
+
+ /* Remove the first entry from the list of unused nodes. */
+ spin_lock_bh(&inet_peer_unused_lock);
+ p = inet_peer_unused_head;
+ if (p != NULL) {
+ if (time_after(p->dtime + ttl, jiffies)) {
+ /* Do not prune fresh entries. */
+ spin_unlock_bh(&inet_peer_unused_lock);
+ return -1;
+ }
+ inet_peer_unused_head = p->unused_next;
+ if (p->unused_next != NULL)
+ p->unused_next->unused_prevp = p->unused_prevp;
+ else
+ inet_peer_unused_tailp = p->unused_prevp;
+ p->unused_prevp = NULL; /* mark as not on the list */
+ /* Grab an extra reference to prevent node disappearing
+ * before unlink_from_pool() call. */
+ atomic_inc(&p->refcnt);
+ }
+ spin_unlock_bh(&inet_peer_unused_lock);
+
+ if (p == NULL)
+ /* It means that the total number of USED entries has
+ * grown over inet_peer_threshold. It shouldn't really
+ * happen because of entry limits in route cache. */
+ return -1;
+
+ unlink_from_pool(p);
+ return 0;
+}
+
+/* Called with or without local BH being disabled. */
+struct inet_peer *inet_getpeer(__u32 daddr, int create)
+{
+ struct inet_peer *p, *n;
+ struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;
+
+ /* Look up for the address quickly. */
+ read_lock_bh(&peer_pool_lock);
+ p = lookup(daddr);
+ if (p != peer_avl_empty)
+ atomic_inc(&p->refcnt);
+ read_unlock_bh(&peer_pool_lock);
+
+ if (p != peer_avl_empty) {
+ /* The existing node has been found. */
+ /* Remove the entry from unused list if it was there. */
+ unlink_from_unused(p);
+ return p;
+ }
+
+ if (!create)
+ return NULL;
+
+ /* Allocate the space outside the locked region. */
+ n = kmem_cache_alloc(peer_cachep, GFP_ATOMIC);
+ if (n == NULL)
+ return NULL;
+ n->v4daddr = daddr;
+ atomic_set(&n->refcnt, 1);
+ n->ip_id_count = secure_ip_id(daddr);
+ n->tcp_ts_stamp = 0;
+
+ write_lock_bh(&peer_pool_lock);
+ /* Check if an entry has suddenly appeared. */
+ p = lookup(daddr);
+ if (p != peer_avl_empty)
+ goto out_free;
+
+ /* Link the node. */
+ link_to_pool(n);
+ n->unused_prevp = NULL; /* not on the list */
+ peer_total++;
+ write_unlock_bh(&peer_pool_lock);
+
+ if (peer_total >= inet_peer_threshold)
+ /* Remove one less-recently-used entry. */
+ cleanup_once(0);
+
+ return n;
+
+out_free:
+ /* The appropriate node is already in the pool. */
+ atomic_inc(&p->refcnt);
+ write_unlock_bh(&peer_pool_lock);
+ /* Remove the entry from unused list if it was there. */
+ unlink_from_unused(p);
+ /* Free preallocated the preallocated node. */
+ kmem_cache_free(peer_cachep, n);
+ return p;
+}
+
+/* Called with local BH disabled. */
+static void peer_check_expire(unsigned long dummy)
+{
+ int i;
+ int ttl;
+
+ if (peer_total >= inet_peer_threshold)
+ ttl = inet_peer_minttl;
+ else
+ ttl = inet_peer_maxttl
+ - (inet_peer_maxttl - inet_peer_minttl) / HZ *
+ peer_total / inet_peer_threshold * HZ;
+ for (i = 0; i < PEER_MAX_CLEANUP_WORK && !cleanup_once(ttl); i++);
+
+ /* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime
+ * interval depending on the total number of entries (more entries,
+ * less interval). */
+ peer_periodic_timer.expires = jiffies
+ + inet_peer_gc_maxtime
+ - (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ *
+ peer_total / inet_peer_threshold * HZ;
+ add_timer(&peer_periodic_timer);
+}
}
iph->tot_len = htons(skb->len);
- iph->id = htons(ip_id_count++);
+ ip_select_ident(iph, &rt->u.dst);
ip_send_check(iph);
stats->tx_bytes += skb->len;
*
* The Internet Protocol (IP) output module.
*
- * Version: $Id: ip_output.c,v 1.75 1999/12/21 04:05:04 davem Exp $
+ * Version: $Id: ip_output.c,v 1.76 2000/01/06 00:41:57 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
#include <net/icmp.h>
#include <net/raw.h>
#include <net/checksum.h>
+#include <net/inetpeer.h>
#include <linux/igmp.h>
#include <linux/netfilter_ipv4.h>
#include <linux/mroute.h>
int sysctl_ip_dynaddr = 0;
-int ip_id_count = 0;
-
/* Generate a checksum for an outgoing IP datagram. */
__inline__ void ip_send_check(struct iphdr *iph)
{
{
struct rtable *rt = (struct rtable *)skb->dst;
struct iphdr *iph;
-
+
/* Build the IP header. */
if (opt)
iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr) + opt->optlen);
iph->saddr = rt->rt_src;
iph->protocol = sk->protocol;
iph->tot_len = htons(skb->len);
- iph->id = htons(ip_id_count++);
+ ip_select_ident(iph, &rt->u.dst);
skb->nh.iph = iph;
if (opt && opt->optlen) {
if (ip_dont_fragment(sk, &rt->u.dst))
iph->frag_off |= __constant_htons(IP_DF);
+ ip_select_ident(iph, &rt->u.dst);
+
/* Add an IP checksum. */
ip_send_check(iph);
kfree_skb(skb);
return -EMSGSIZE;
}
+ ip_select_ident(iph, &rt->u.dst);
return ip_fragment(skb, skb->dst->output);
}
}
iph->tot_len = htons(skb->len);
- iph->id = htons(ip_id_count++);
return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
ip_queue_xmit2);
int err;
int offset, mf;
int mtu;
- unsigned short id;
+ u16 id = 0;
int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
int nfrags=0;
mtu = rt->u.dst.pmtu;
if (ip_dont_fragment(sk, &rt->u.dst))
df = htons(IP_DF);
-
+
length -= sizeof(struct iphdr);
if (opt) {
maxfraglen = ((mtu-sizeof(struct iphdr)-opt->optlen) & ~7) + fragheaderlen;
} else {
fragheaderlen = sizeof(struct iphdr);
-
+
/*
* Fragheaderlen is the size of 'overhead' on each buffer. Now work
* out the size of the frames to send.
*/
-
+
maxfraglen = ((mtu-sizeof(struct iphdr)) & ~7) + fragheaderlen;
}
/*
* Start at the end of the frame by handling the remainder.
*/
-
+
offset = length - (length % (maxfraglen - fragheaderlen));
-
+
/*
* Amount of memory to allocate for final fragment.
*/
-
+
fraglen = length - offset + fragheaderlen;
-
+
if (length-offset==0) {
fraglen = maxfraglen;
offset -= maxfraglen-fragheaderlen;
/*
* The last fragment will not have MF (more fragments) set.
*/
-
+
mf = 0;
/*
* Don't fragment packets for path mtu discovery.
*/
-
- if (offset > 0 && df) {
+
+ if (offset > 0 && sk->protinfo.af_inet.pmtudisc==IP_PMTUDISC_DO) {
ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu);
return -EMSGSIZE;
}
if (flags&MSG_PROBE)
goto out;
- /*
- * Get an identifier
- */
-
- id = htons(ip_id_count++);
-
/*
* Begin outputting the bytes.
*/
-
+
do {
char *data;
struct sk_buff * skb;
/*
* Fill in the control structures
*/
-
+
skb->priority = sk->priority;
skb->dst = dst_clone(&rt->u.dst);
skb_reserve(skb, hh_len);
/*
* Find where to start putting bytes.
*/
-
+
data = skb_put(skb, fraglen);
skb->nh.iph = (struct iphdr *)data;
/*
* Only write IP header onto non-raw packets
*/
-
+
{
struct iphdr *iph = (struct iphdr *)data;
}
iph->tos = sk->protinfo.af_inet.tos;
iph->tot_len = htons(fraglen - fragheaderlen + iph->ihl*4);
+ iph->frag_off = htons(offset>>3)|mf|df;
iph->id = id;
- iph->frag_off = htons(offset>>3);
- iph->frag_off |= mf|df;
+ if (!mf) {
+ if (offset || !df) {
+ /* Select an unpredictable ident only
+ * for packets without DF or having
+ * been fragmented.
+ */
+ __ip_select_ident(iph, &rt->u.dst);
+ id = iph->id;
+ }
+
+ /*
+ * Any further fragments will have MF set.
+ */
+ mf = htons(IP_MF);
+ }
if (rt->rt_type == RTN_MULTICAST)
iph->ttl = sk->protinfo.af_inet.mc_ttl;
else
iph->daddr = rt->rt_dst;
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
data += iph->ihl*4;
-
- /*
- * Any further fragments will have MF set.
- */
-
- mf = htons(IP_MF);
}
-
+
/*
* User data callback
*/
goto error;
skb_reserve(skb, hh_len);
}
-
+
skb->priority = sk->priority;
skb->dst = dst_clone(&rt->u.dst);
skb->nh.iph = iph = (struct iphdr *)skb_put(skb, length);
-
+
if(!sk->protinfo.af_inet.hdrincl) {
iph->version=4;
iph->ihl=5;
iph->tos=sk->protinfo.af_inet.tos;
iph->tot_len = htons(length);
- iph->id=htons(ip_id_count++);
iph->frag_off = df;
iph->ttl=sk->protinfo.af_inet.mc_ttl;
+ ip_select_ident(iph, &rt->u.dst);
if (rt->rt_type != RTN_MULTICAST)
iph->ttl=sk->protinfo.af_inet.ttl;
iph->protocol=sk->protocol;
ip_statistics.IpOutDiscards++;
return err;
}
-
-
/*
* This IP datagram is too large to be sent in one piece. Break it up into
kfree_skb(skb);
ip_statistics.IpFragOKs++;
return err;
-
+
fail:
kfree_skb(skb);
ip_statistics.IpFragFails++;
NULL,
};
-
/*
* IP registers the packet type and then calls the subprotocol initialisers
*/
dev_add_pack(&ip_packet_type);
ip_rt_init();
+ inet_initpeers();
#ifdef CONFIG_IP_MULTICAST
proc_net_create("igmp", 0, ip_mc_procinfo);
#endif
}
-
/*
* Linux NET3: IP/IP protocol decoder.
*
- * Version: $Id: ipip.c,v 1.29 1999/08/31 07:03:42 davem Exp $
+ * Version: $Id: ipip.c,v 1.30 2000/01/06 00:41:55 davem Exp $
*
* Authors:
* Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
iph->ttl = old_iph->ttl;
iph->tot_len = htons(skb->len);
- iph->id = htons(ip_id_count++);
+ ip_select_ident(iph, &rt->u.dst);
ip_send_check(iph);
stats->tx_bytes += skb->len;
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version: $Id: ipmr.c,v 1.48 1999/12/15 22:39:16 davem Exp $
+ * Version: $Id: ipmr.c,v 1.49 2000/01/06 00:41:56 davem Exp $
*
* Fixes:
* Michael Chastain : Incorrect size of copying.
iph->protocol = IPPROTO_IPIP;
iph->ihl = 5;
iph->tot_len = htons(skb->len);
- iph->id = htons(ip_id_count++);
+ ip_select_ident(iph, skb->dst);
ip_send_check(iph);
skb->h.ipiph = skb->nh.iph;
*
* RAW - implementation of IP "raw" sockets.
*
- * Version: $Id: raw.c,v 1.44 1999/12/15 22:39:21 davem Exp $
+ * Version: $Id: raw.c,v 1.45 2000/01/06 00:41:58 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
{
struct iovec *iov;
u32 saddr;
+ struct dst_entry *dst;
};
/*
* ip_build_xmit clean (well less messy).
*/
if (!iph->id)
- iph->id = htons(ip_id_count++);
+ ip_select_ident(iph, rfh->dst);
iph->check=ip_fast_csum((unsigned char *)iph, iph->ihl);
}
return 0;
rfh.iov = msg->msg_iov;
rfh.saddr = rt->rt_src;
+ rfh.dst = &rt->u.dst;
if (!ipc.addr)
ipc.addr = rt->rt_dst;
err=ip_build_xmit(sk, sk->protinfo.af_inet.hdrincl ? raw_getrawfrag : raw_getfrag,
#include <linux/pkt_sched.h>
#include <linux/mroute.h>
#include <linux/netfilter_ipv4.h>
+#include <linux/random.h>
#include <net/protocol.h>
#include <net/ip.h>
#include <net/route.h>
+#include <net/inetpeer.h>
#include <net/sock.h>
#include <net/ip_fib.h>
#include <net/arp.h>
static struct dst_entry * ipv4_dst_check(struct dst_entry * dst, u32);
static struct dst_entry * ipv4_dst_reroute(struct dst_entry * dst,
struct sk_buff *);
+static void ipv4_dst_destroy(struct dst_entry * dst);
static struct dst_entry * ipv4_negative_advice(struct dst_entry *);
static void ipv4_link_failure(struct sk_buff *skb);
static int rt_garbage_collect(void);
rt_garbage_collect,
ipv4_dst_check,
ipv4_dst_reroute,
- NULL,
+ ipv4_dst_destroy,
ipv4_negative_advice,
ipv4_link_failure,
sizeof(struct rtable),
return 0;
}
+void rt_bind_peer(struct rtable *rt, int create)
+{
+ static spinlock_t rt_peer_lock = SPIN_LOCK_UNLOCKED;
+ struct inet_peer *peer;
+
+ peer = inet_getpeer(rt->rt_dst, create);
+
+ spin_lock_bh(&rt_peer_lock);
+ if (rt->peer == NULL) {
+ rt->peer = peer;
+ peer = NULL;
+ }
+ spin_unlock_bh(&rt_peer_lock);
+ if (peer)
+ inet_putpeer(peer);
+}
+
+/*
+ * Peer allocation may fail only in serious out-of-memory conditions. However
+ * we still can generate some output.
+ * Random ID selection looks a bit dangerous because we have no chances to
+ * select ID being unique in a reasonable period of time.
+ * But broken packet identifier may be better than no packet at all.
+ */
+static void ip_select_fb_ident(struct iphdr *iph)
+{
+ static spinlock_t ip_fb_id_lock = SPIN_LOCK_UNLOCKED;
+ static u32 ip_fallback_id;
+ u32 salt;
+
+ spin_lock_bh(&ip_fb_id_lock);
+ salt = secure_ip_id(ip_fallback_id ^ iph->daddr);
+ iph->id = salt & 0xFFFF;
+ ip_fallback_id = salt;
+ spin_unlock_bh(&ip_fb_id_lock);
+}
+
+void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst)
+{
+ struct rtable *rt = (struct rtable *) dst;
+
+ if (rt) {
+ if (rt->peer == NULL)
+ rt_bind_peer(rt, 1);
+
+ /* If peer is attached to destination, it is never detached,
+ so that we need not to grab a lock to dereference it.
+ */
+ if (rt->peer) {
+ iph->id = inet_getid(rt->peer);
+ return;
+ }
+ } else {
+ printk(KERN_DEBUG "rt_bind_peer(0) @%p\n", NET_CALLER(iph));
+ }
+
+ ip_select_fb_ident(iph);
+}
+
static void rt_del(unsigned hash, struct rtable *rt)
{
struct rtable **rthp;
/* Redirect received -> path was valid */
dst_confirm(&rth->u.dst);
+ if (rt->peer)
+ atomic_inc(&rt->peer->refcnt);
+
if (!arp_bind_neighbour(&rt->u.dst) ||
!(rt->u.dst.neighbour->nud_state&NUD_VALID)) {
if (rt->u.dst.neighbour)
return NULL;
}
+static void ipv4_dst_destroy(struct dst_entry * dst)
+{
+ struct rtable *rt = (struct rtable *) dst;
+ struct inet_peer *peer = rt->peer;
+
+ if (peer) {
+ rt->peer = NULL;
+ inet_putpeer(peer);
+ }
+}
+
static void ipv4_link_failure(struct sk_buff *skb)
{
struct rtable *rt;
else
ci.rta_expires = 0;
ci.rta_error = rt->u.dst.error;
+ ci.rta_id = 0;
+ ci.rta_ts = 0;
+ ci.rta_tsage = 0;
+ if (rt->peer) {
+ ci.rta_id = rt->peer->ip_id_count;
+ if (rt->peer->tcp_ts_stamp) {
+ ci.rta_ts = rt->peer->tcp_ts;
+ ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp;
+ }
+ }
#ifdef CONFIG_IP_MROUTE
eptr = (struct rtattr*)skb->tail;
#endif
/*
* sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
*
- * $Id: sysctl_net_ipv4.c,v 1.40 1999/09/07 02:31:17 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.41 2000/01/06 00:42:03 davem Exp $
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
/* From igmp.c */
extern int sysctl_igmp_max_memberships;
+/* From inetpeer.c */
+extern int inet_peer_threshold;
+extern int inet_peer_minttl;
+extern int inet_peer_maxttl;
+extern int inet_peer_gc_mintime;
+extern int inet_peer_gc_maxtime;
+
int tcp_retr1_max = 255;
struct ipv4_config ipv4_config;
{NET_IPV4_IGMP_MAX_MEMBERSHIPS, "igmp_max_memberships",
&sysctl_igmp_max_memberships, sizeof(int), 0644, NULL, &proc_dointvec},
#endif
+ {NET_IPV4_INET_PEER_THRESHOLD, "inet_peer_threshold",
+ &inet_peer_threshold, sizeof(int), 0644, NULL, &proc_dointvec},
+ {NET_IPV4_INET_PEER_MINTTL, "inet_peer_minttl",
+ &inet_peer_minttl, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
+ {NET_IPV4_INET_PEER_MAXTTL, "inet_peer_maxttl",
+ &inet_peer_maxttl, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
+ {NET_IPV4_INET_PEER_GC_MINTIME, "inet_peer_gc_mintime",
+ &inet_peer_gc_mintime, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
+ {NET_IPV4_INET_PEER_GC_MAXTIME, "inet_peer_gc_maxtime",
+ &inet_peer_gc_maxtime, sizeof(int), 0644, NULL,
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{0}
};
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.192 1999/12/23 02:04:50 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.193 2000/01/06 00:42:01 davem Exp $
*
* IPv4 specific functions
*
static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
{
- return secure_tcp_sequence_number(sk->saddr, sk->daddr,
+ return secure_tcp_sequence_number(skb->nh.iph->daddr,
+ skb->nh.iph->saddr,
skb->h.th->dest,
skb->h.th->source);
}
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_output.c,v 1.22 1999/08/20 11:06:21 davem Exp $
+ * $Id: ip6_output.c,v 1.23 2000/01/06 00:42:07 davem Exp $
*
* Based on linux/net/ipv4/ip_output.c
*
#include <net/rawv6.h>
#include <net/icmp.h>
-static u32 ipv6_fragmentation_id = 1;
+static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
+{
+ static u32 ipv6_fragmentation_id = 1;
+ static spinlock_t ip6_id_lock = SPIN_LOCK_UNLOCKED;
+
+ spin_lock_bh(&ip6_id_lock);
+ fhdr->identification = ipv6_fragmentation_id;
+ if (++ipv6_fragmentation_id == 0)
+ ipv6_fragmentation_id = 1;
+ spin_unlock_bh(&ip6_id_lock);
+}
int ip6_output(struct sk_buff *skb)
{
fhdr->reserved = 0;
fhdr->frag_off = htons(offset);
- fhdr->identification = ipv6_fragmentation_id++;
+ ipv6_select_ident(skb, fhdr);
return &fhdr->nexthdr;
}
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: route.c,v 1.42 1999/12/15 22:39:53 davem Exp $
+ * $Id: route.c,v 1.43 2000/01/06 00:42:08 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
ci.rta_used = rt->u.dst.__use;
ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt);
ci.rta_error = rt->u.dst.error;
+ ci.rta_id = 0;
+ ci.rta_ts = 0;
+ ci.rta_tsage = 0;
RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
nlh->nlmsg_len = skb->tail - b;
return skb->len;
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: sit.c,v 1.34 1999/08/31 07:04:16 davem Exp $
+ * $Id: sit.c,v 1.35 2000/01/06 00:42:08 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
iph->ttl = iph6->hop_limit;
iph->tot_len = htons(skb->len);
- iph->id = htons(ip_id_count++);
+ ip_select_ident(iph, &rt->u.dst);
ip_send_check(iph);
stats->tx_bytes += skb->len;
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.114 2000/01/03 17:19:17 davem Exp $
+ * $Id: tcp_ipv6.c,v 1.115 2000/01/06 00:42:09 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
{
- __u32 si;
- __u32 di;
-
if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
- si = skb->nh.ipv6h->saddr.s6_addr32[3];
- di = skb->nh.ipv6h->daddr.s6_addr32[3];
+ return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
+ skb->nh.ipv6h->saddr.s6_addr32,
+ skb->h.th->dest,
+ skb->h.th->source);
} else {
- si = skb->nh.iph->saddr;
- di = skb->nh.iph->daddr;
+ return secure_tcp_sequence_number(skb->nh.iph->daddr,
+ skb->nh.iph->saddr,
+ skb->h.th->dest,
+ skb->h.th->source);
}
-
- return secure_tcp_sequence_number(di, si,
- skb->h.th->dest,
- skb->h.th->source);
}
static int tcp_v6_check_established(struct sock *sk)
*/
if (!tp->write_seq)
- tp->write_seq = secure_tcp_sequence_number(np->saddr.s6_addr32[3],
- np->daddr.s6_addr32[3],
- sk->sport, sk->dport);
+ tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
+ np->daddr.s6_addr32,
+ sk->sport, sk->dport);
err = tcp_connect(sk, buff);
if (err == 0)
#endif
#include <net/pkt_sched.h>
#include <net/scm.h>
+#include <linux/random.h>
#ifdef CONFIG_BRIDGE
#include <net/br.h>
EXPORT_SYMBOL(ip_options_undo);
EXPORT_SYMBOL(arp_send);
EXPORT_SYMBOL(arp_broken_ops);
-EXPORT_SYMBOL(ip_id_count);
+EXPORT_SYMBOL(__ip_select_ident);
EXPORT_SYMBOL(ip_send_check);
EXPORT_SYMBOL(ip_fragment);
EXPORT_SYMBOL(inet_family_ops);
#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(sysctl_max_syn_backlog);
#endif
+
+#if defined (CONFIG_IPV6_MODULE)
+EXPORT_SYMBOL(secure_tcpv6_sequence_number);
+EXPORT_SYMBOL(secure_ipv6_id);
+#endif
+
#endif
#ifdef CONFIG_NETLINK