From: Linus Torvalds Date: Fri, 23 Nov 2007 20:34:52 +0000 (-0500) Subject: Import 2.3.99pre9-2 X-Git-Tag: 2.3.99pre9-2 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=03e55876fca8bd17e560898fb78a7f3fa72d3df6;p=history.git Import 2.3.99pre9-2 --- diff --git a/CREDITS b/CREDITS index f881963d7cf6..eda1077d7736 100644 --- a/CREDITS +++ b/CREDITS @@ -942,14 +942,20 @@ D: Selection mechanism N: Andre Hedrick E: andre@linux-ide.org +E: ahedrick@atipa.com E: andre@suse.com +W: http://www.linux-ide.org/ D: Random SMP kernel hacker... D: Uniform Multi-Platform E-IDE driver D: Active-ATA-Chipset maddness.......... D: Ultra DMA 66/33 D: ATA-Smart Kernel Daemon -S: 580 Second Street, Suite 2 -S: Oakland, CA +S: Linux ATA Development (LAD) +S: Concord, CA +S: Atipa Linux Solutions +S: 6000 Connecticut Kansas City, MO 64120 +S: SuSE Linux, Inc. +S: 580 Second Street, Suite 210 Oakland, CA 94607 S: USA N: Jochen Hein diff --git a/Documentation/Configure.help b/Documentation/Configure.help index f65e265dc87e..c2afcf32675a 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -1496,7 +1496,7 @@ CONFIG_MD_RAID0 If unsure, say Y. -DANGEROUS! RAID-1/RAID-5 code +RAID-1/RAID-5 code (DANGEROUS) CONFIG_RAID15_DANGEROUS This new RAID1/RAID5 code has been freshly merged, and has not seen enough testing yet. While there are no known bugs in it, it might @@ -10430,7 +10430,7 @@ CONFIG_NFSD Provide NFSv3 server support CONFIG_NFSD_V3 If you would like to include the NFSv3 server as well as the NFSv2 - server, say Y here. In unsure, say Y. + server, say Y here. If unsure, say Y. OS/2 HPFS file system support CONFIG_HPFS_FS diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index d785534f6178..b6cdf0567d9d 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -18,6 +18,9 @@ db2ps db2pdf: (echo "*** You need to install DocBook stylesheets ***"; \ exit 1) +%.eps: %.fig + -fig2dev -Leps $< $@ + $(TOPDIR)/scripts/docproc: $(MAKE) -C $(TOPDIR)/scripts docproc @@ -67,12 +70,15 @@ TEX := $(patsubst %.sgml, %.tex, $(BOOKS)) LOG := $(patsubst %.sgml, %.log, $(BOOKS)) clean: - $(RM) core *~ - $(RM) $(BOOKS) - $(RM) $(DVI) $(AUX) $(TEX) $(LOG) + -$(RM) core *~ + -$(RM) $(BOOKS) + -$(RM) $(DVI) $(AUX) $(TEX) $(LOG) + -$(RM) parport-share.eps parport-multi.eps parport-structure.eps mrproper: clean - $(RM) $(PS) $(PDF) + -$(RM) $(PS) $(PDF) + +parportbook.ps: parport-share.eps parport-multi.eps parport-structure.eps %.ps : %.sgml db2ps db2ps $< diff --git a/Documentation/DocBook/parportbook.tmpl b/Documentation/DocBook/parportbook.tmpl index 1644748adddc..a6ac266d1419 100644 --- a/Documentation/DocBook/parportbook.tmpl +++ b/Documentation/DocBook/parportbook.tmpl @@ -1,8 +1,9 @@ + - The Parallel Port Subsystem + The Linux 2.4 Parallel Port Subsystem @@ -51,90 +52,97 @@ - + - -Design goals + + Design goals - -The problems + + The problems - - + + The first parallel port support for Linux came with the line + printer driver, lp. The printer driver is a + character special device, and (in Linux 2.0) had support for + writing, via write, and configuration and + statistics reporting via ioctl. + - + + The printer driver could be used on any computer that had an IBM + PC-compatible parallel port. Because some architectures have + parallel ports that aren't really the same as PC-style ports, + other variants of the printer driver were written in order to + support Amiga and Atari parallel ports. + + + + When the Iomega Zip drive was released, and a driver written for + it, a problem became apparent. The Zip drive is a parallel port + device that provides a parallel port of its own---it is designed + to sit between a computer and an attached printer, with the + printer plugged into the Zip drive, and the Zip drive plugged into + the computer. + -The first parallel port support for Linux came with the line -printer driver, lp. The printer driver is a -character special device, and (in Linux 2.0) had support for writing, -via write, and configuration and statistics -reporting via ioctl. - -The printer driver could be used on any computer that had an IBM -PC-compatible parallel port. Because some architectures have parallel -ports that aren't really the same as PC-style ports, other variants of -the printer driver were written in order to support Amiga and Atari -parallel ports. - -When the Iomega Zip drive was released, and a driver written for -it, a problem became apparent. The Zip drive is a parallel port -device that provides a parallel port of its own---it is designed to -sit between a computer and an attached printer, with the printer -plugged into the Zip drive, and the Zip drive plugged into the -computer. - -The problem was that, although printers and Zip drives were both -supported, for any given port only one could be used at a time. Only -one of the two drivers could be present in the kernel at once. This -was because of the fact that both drivers wanted to drive the same -hardware---the parallel port. When the printer driver initialised, it -would call the check_region function to make sure -that the IO region associated with the parallel port was free, and -then it would call request_region to allocate it. -The Zip drive used the same mechanism. Whichever driver initialised -first would gain exclusive control of the parallel port. - -The only way around this problem at the time was to make sure -that both drivers were available as loadable kernel modules. To use -the printer, load the printer driver module; then for the Zip drive, -unload the printer driver module and load the Zip driver -module. - -The net effect was that printing a document that was stored on a Zip -drive was a bit of an ordeal, at least if the Zip drive and printer -shared a parallel port. A better solution was needed. - -Zip drives are not the only devices that presented problems for -Linux. There are other devices with pass-through ports, for example -parallel port CD-ROM drives. There are also printers that report -their status textually rather than using simple error pins: sending a -command to the printer can cause it to report the number of pages that -it has ever printed, or how much free memory it has, or whether it is -running out of toner, and so on. The printer driver didn't originally -offer any facility for reading back this information (although Carsten -Gross added nibble mode readback support for kernel 2.2). - - - -The IEEE has issued a standards document called IEEE 1284, which -documents existing practice for parallel port communications in a -variety of modes. Those modes are: compatibility, -reverse nibble, reverse byte, ECP and EPP. Newer devices often use -the more advanced modes of transfer (ECP and EPP). In Linux 2.0, the -printer driver only supported compatibility mode -(i.e. normal printer protocol) and reverse nibble mode. - - - - -The solutions + + The problem was that, although printers and Zip drives were both + supported, for any given port only one could be used at a time. + Only one of the two drivers could be present in the kernel at + once. This was because of the fact that both drivers wanted to + drive the same hardware---the parallel port. When the printer + driver initialised, it would call the + check_region function to make sure that the + IO region associated with the parallel port was free, and then it + would call request_region to allocate it. + The Zip drive used the same mechanism. Whichever driver + initialised first would gain exclusive control of the parallel + port. + + + + The only way around this problem at the time was to make sure that + both drivers were available as loadable kernel modules. To use + the printer, load the printer driver module; then for the Zip + drive, unload the printer driver module and load the Zip driver + module. + + + + The net effect was that printing a document that was stored on a + Zip drive was a bit of an ordeal, at least if the Zip drive and + printer shared a parallel port. A better solution was + needed. + + + + Zip drives are not the only devices that presented problems for + Linux. There are other devices with pass-through ports, for + example parallel port CD-ROM drives. There are also printers that + report their status textually rather than using simple error pins: + sending a command to the printer can cause it to report the number + of pages that it has ever printed, or how much free memory it has, + or whether it is running out of toner, and so on. The printer + driver didn't originally offer any facility for reading back this + information (although Carsten Gross added nibble mode readback + support for kernel 2.2). + + + + The IEEE has issued a standards document called IEEE 1284, which + documents existing practice for parallel port communications in a + variety of modes. Those modes are: compatibility, + reverse nibble, reverse byte, ECP and EPP. Newer devices often + use the more advanced modes of transfer (ECP and EPP). In Linux + 2.0, the printer driver only supported compatibility + mode (i.e. normal printer protocol) and reverse nibble + mode. + + + + + + The solutions -The parport code in Linux 2.2 was designed -to meet these problems of architectural differences in parallel ports, -of port-sharing between devices with pass-through ports, and of lack -of support for IEEE 1284 transfer modes. - - - -There are two layers to the -parport subsystem, only one of which deals -directly with the hardware. The other layer deals with sharing and -IEEE 1284 transfer modes. In this way, parallel support for a -particular architecture comes in the form of a module which registers -itself with the generic sharing layer. - - - -The sharing model provided by the parport -subsystem is one of exclusive access. A device driver, such as the -printer driver, must ask the parport layer for -access to the port, and can only use the port once access has been -granted. When it has finished a transaction, it can -tell the parport layer that it may release the -port for other device drivers to use. - - - -Devices with pass-through ports all manage to share a parallel -port with other devices in generally the same way. The device has a -latch for each of the pins on its pass-through port. The normal state -of affairs is pass-through mode, with the device copying the signal -lines between its host port and its pass-through port. When the -device sees a special signal from the host port, it latches the -pass-through port so that devices further downstream don't get -confused by the pass-through device's conversation with the host -parallel port: the device connected to the pass-through port (and any -devices connected in turn to it) are effectively cut off from the -computer. When the pass-through device has completed its transaction -with the computer, it enables the pass-through port again. - - - - - - - -This technique relies on certain special signals -being invisible to devices that aren't watching for them. This tends -to mean only changing the data signals and leaving the control signals -alone. IEEE 1284.3 documents a standard protocol for daisy-chaining -devices together with parallel ports. - - - -Support for standard transfer modes are provided as operations -that can be performed on a port, along with operations for setting the -data lines, or the control lines, or reading the status lines. These -operations appear to the device driver as function pointers; more -later. - - - - - - -Standard transfer modes - - - - -The standard transfer modes in use over the -parallel port are defined by a document called IEEE -1284. It really just codifies existing practice and documents -protocols (and variations on protocols) that have been in common use -for quite some time. - -The original definitions of which pin did what were set out by -Centronics Data Computer Corporation, but only the printer-side -interface signals were specified. - -By the early 1980s, IBM's host-side implementation had become -the most widely used. New printers emerged that claimed Centronics -compatibility, but although compatible with Centronics they differed -from one another in a number of ways. - -As a result of this, when IEEE 1284 was published in 1994, all -that it could really do was document the various protocols that are -used for printers (there are about six variations on a theme). - -In addition to the protocol used to talk to -Centronics-compatible printers, IEEE 1284 defined other protocols that -are used for unidirectional peripheral-to-host transfers (reverse -nibble and reverse byte) and for fast bidirectional transfers (ECP and -EPP). - - - - -Structure + + The parport code in Linux 2.2 was designed to + meet these problems of architectural differences in parallel + ports, of port-sharing between devices with pass-through ports, + and of lack of support for IEEE 1284 transfer modes. + + + + + + There are two layers to the parport + subsystem, only one of which deals directly with the hardware. + The other layer deals with sharing and IEEE 1284 transfer modes. + In this way, parallel support for a particular architecture comes + in the form of a module which registers itself with the generic + sharing layer. + + + + + + The sharing model provided by the parport + subsystem is one of exclusive access. A device driver, such as + the printer driver, must ask the parport + layer for access to the port, and can only use the port once + access has been granted. When it has finished a + transaction, it can tell the + parport layer that it may release the port + for other device drivers to use. + + + + + + Devices with pass-through ports all manage to share a parallel + port with other devices in generally the same way. The device has + a latch for each of the pins on its pass-through port. The normal + state of affairs is pass-through mode, with the device copying the + signal lines between its host port and its pass-through port. + When the device sees a special signal from the host port, it + latches the pass-through port so that devices further downstream + don't get confused by the pass-through device's conversation with + the host parallel port: the device connected to the pass-through + port (and any devices connected in turn to it) are effectively cut + off from the computer. When the pass-through device has completed + its transaction with the computer, it enables the pass-through + port again. + + + + + + + + + + + + + This technique relies on certain special signals + being invisible to devices that aren't watching for them. This + tends to mean only changing the data signals and leaving the + control signals alone. IEEE 1284.3 documents a standard protocol + for daisy-chaining devices together with parallel ports. + + + + + + Support for standard transfer modes are provided as operations + that can be performed on a port, along with operations for setting + the data lines, or the control lines, or reading the status lines. + These operations appear to the device driver as function pointers; + more later. + + + + + + + + Standard transfer modes + + + + + + The standard transfer modes in use over the parallel + port are defined by a document called IEEE 1284. It + really just codifies existing practice and documents protocols (and + variations on protocols) that have been in common use for quite + some time. + + + + The original definitions of which pin did what were set out by + Centronics Data Computer Corporation, but only the printer-side + interface signals were specified. + + + + By the early 1980s, IBM's host-side implementation had become the + most widely used. New printers emerged that claimed Centronics + compatibility, but although compatible with Centronics they + differed from one another in a number of ways. + + + + As a result of this, when IEEE 1284 was published in 1994, all that + it could really do was document the various protocols that are used + for printers (there are about six variations on a theme). + + + + In addition to the protocol used to talk to Centronics-compatible + printers, IEEE 1284 defined other protocols that are used for + unidirectional peripheral-to-host transfers (reverse nibble and + reverse byte) and for fast bidirectional transfers (ECP and + EPP). + + + + + + Structure - - - - - - - - - -Sharing core - - - -At the core of the parport subsystem is the -sharing mechanism (see drivers/parport/share.c). -This module, parport, is responsible for -keeping track of which ports there are in the system, which device -drivers might be interested in new ports, and whether or not each port -is available for use (or if not, which driver is currently using -it). - - - - -Parports and their overrides - - -The generic parport sharing code doesn't -directly handle the parallel port hardware. That is done instead by -low-level parport drivers. The -function of a low-level parport driver is to -detect parallel ports, register them with the sharing code, and -provide a list of access functions for each port. - -The most basic access functions that must be provided are ones -for examining the status lines, for setting the control lines, and for -setting the data lines. There are also access functions for setting -the direction of the data lines; normally they are in the -forward direction (that is, the computer drives them), -but some ports allow switching to reverse mode (driven -by the peripheral). There is an access function for examining the -data lines once in reverse mode. - - - - -IEEE 1284 transfer modes - - -Stacked on top of the sharing mechanism, but still in the -parport module, are functions for transferring -data. They are provided for the device drivers to use, and are very -much like library routines. Since these transfer functions are -provided by the generic parport core they must -use the lowest common denominator set of access -functions: they can set the control lines, examine the status lines, -and use the data lines. With some parallel ports the data lines can -only be set and not examined, and with other ports accessing the data -register causes control line activity; with these types of situations, -the IEEE 1284 transfer functions make a best effort attempt to do the -right thing. In some cases, it is not physically possible to use -particular IEEE 1284 transfer modes. - -The low-level parport drivers also provide -IEEE 1284 transfer functions, as names in the access function list. -The low-level driver can just name the generic IEEE 1284 transfer -functions for this. Some parallel ports can do IEEE 1284 transfers in -hardware; for those ports, the low-level driver can provide functions -to utilise that feature. - - - - - - - - -Pardevices and parport_drivers - -When a parallel port device driver (such as -lp) initialises it tells the sharing layer about -itself using parport_register_driver. The -information is put into a struct -parport_driver, which is put into a linked list. The -information in a struct parport_driver really -just amounts to some function pointers to callbacks in the parallel -port device driver. - -During its initialisation, a low-level port driver tells the -sharing layer about all the ports that it has found (using -parport_register_port), and the sharing layer -creates a struct parport for each of them. -Each struct parport contains (among other -things) a pointer to a struct -parport_operations, which is a list of function pointers -for the various operations that can be performed on a port. You can -think of a struct parport as a parallel port -object, if object-orientated programming -is your thing. The parport structures are -chained in a linked list, whose head is portlist -(in drivers/parport/share.c). - -Once the port has been registered, the low-level port driver -announces it. The parport_announce_port function -walks down the list of parallel port device drivers -(struct parport_drivers) calling the -attach function of each. - -Similarly, a low-level port driver can undo the effect of -registering a port with the -parport_unregister_port function, and device -drivers are notified using the detach -callback. - -Device drivers can undo the effect of registering themselves -with the parport_unregister_driver -function. - - - - - - -The IEEE 1284.3 API - -The ability to daisy-chain devices is very useful, but if every -device does it in a different way it could lead to lots of -complications for device driver writers. Fortunately, the IEEE are -standardising it in IEEE 1284.3, which covers daisy-chain devices and -port multiplexors. - -At the time of writing, IEEE 1284.3 has not been published, but -the draft specifies the on-the-wire protocol for daisy-chaining and -multiplexing, and also suggests a programming interface for using it. -That interface (or most of it) has been implemented in the -parport code in Linux. - -At initialisation of the parallel port bus, daisy-chained -devices are assigned addresses starting from zero. There can only be -four devices with daisy-chain addresses, plus one device on the end -that doesn't know about daisy-chaining and thinks it's connected -directly to a computer. - -Another way of connecting more parallel port devices is to use a -multiplexor. The idea is to have a device that is connected directly -to a parallel port on a computer, but has a number of parallel ports -on the other side for other peripherals to connect to (two or four -ports are allowed). The multiplexor switches control to different -ports under software control---it is, in effect, a programmable -printer switch. - -Combining the ability of daisy-chaining five devices together -with the ability to multiplex one parallel port between four gives the -potential to have twenty peripherals connected to the same parallel -port! - -In addition, of course, a single computer can have multiple -parallel ports. So, each parallel port peripheral in the system can -be identified with three numbers, or co-ordinates: the parallel port, -the multiplexed port, and the daisy-chain address. - - - - - - - - - - - - - - - -Each device in the system is numbered at initialisation (by -parport_daisy_init). You can convert between -this device number and its co-ordinates with -parport_device_num and -parport_device_coords. - - - int parport_device_num - int parport - int mux - int daisy - - - - int parport_device_coords - int devnum - int *parport - int *mux - int *daisy - - -Any parallel port peripheral will be connected directly or -indirectly to a parallel port on the system, but it won't have a -daisy-chain address if it does not know about daisy-chaining, and it -won't be connected through a multiplexor port if there is no -multiplexor. The special co-ordinate value -1 is -used to indicate these cases. - -Two functions are provided for finding devices based on their -IEEE 1284 Device ID: parport_find_device and -parport_find_class. - - - int parport_find_device - const char *mfg - const char *mdl - int from - - - - int parport_find_class - parport_device_class cls - int from - - -These functions take a device number (in addition to some other -things), and return another device number. They walk through the list -of detected devices until they find one that matches the requirements, -and then return that device number (or -1 if -there are no more such devices). They start their search at the -device after the one in the list with the number given (at -from+1, in other words). - - - - - - -Device driver's view + + + + + + + + + + + Sharing core + + + At the core of the parport subsystem is the + sharing mechanism (see + drivers/parport/share.c). This module, + parport, is responsible for keeping track of + which ports there are in the system, which device drivers might be + interested in new ports, and whether or not each port is available + for use (or if not, which driver is currently using it). + + + + + + Parports and their overrides + + + The generic parport sharing code doesn't + directly handle the parallel port hardware. That is done instead + by low-level parport drivers. + The function of a low-level parport driver is + to detect parallel ports, register them with the sharing code, and + provide a list of access functions for each port. + + + + The most basic access functions that must be provided are ones for + examining the status lines, for setting the control lines, and for + setting the data lines. There are also access functions for + setting the direction of the data lines; normally they are in the + forward direction (that is, the computer drives + them), but some ports allow switching to reverse + mode (driven by the peripheral). There is an access function for + examining the data lines once in reverse mode. + + + + + + IEEE 1284 transfer modes + + + Stacked on top of the sharing mechanism, but still in the + parport module, are functions for + transferring data. They are provided for the device drivers to + use, and are very much like library routines. Since these + transfer functions are provided by the generic + parport core they must use the lowest + common denominator set of access functions: they can set + the control lines, examine the status lines, and use the data + lines. With some parallel ports the data lines can only be set + and not examined, and with other ports accessing the data register + causes control line activity; with these types of situations, the + IEEE 1284 transfer functions make a best effort attempt to do the + right thing. In some cases, it is not physically possible to use + particular IEEE 1284 transfer modes. + + + + The low-level parport drivers also provide + IEEE 1284 transfer functions, as names in the access function + list. The low-level driver can just name the generic IEEE 1284 + transfer functions for this. Some parallel ports can do IEEE 1284 + transfers in hardware; for those ports, the low-level driver can + provide functions to utilise that feature. + + + + + + + + Pardevices and parport_drivers + + + When a parallel port device driver (such as + lp) initialises it tells the sharing layer + about itself using parport_register_driver. + The information is put into a struct + parport_driver, which is put into a linked list. The + information in a struct parport_driver + really just amounts to some function pointers to callbacks in the + parallel port device driver. + + + + During its initialisation, a low-level port driver tells the + sharing layer about all the ports that it has found (using + parport_register_port), and the sharing layer + creates a struct parport for each of + them. Each struct parport contains + (among other things) a pointer to a struct + parport_operations, which is a list of function + pointers for the various operations that can be performed on a + port. You can think of a struct parport + as a parallel port object, if + object-orientated programming is your thing. The + parport structures are chained in a + linked list, whose head is portlist (in + drivers/parport/share.c). + + + + Once the port has been registered, the low-level port driver + announces it. The parport_announce_port + function walks down the list of parallel port device drivers + (struct parport_drivers) calling the + attach function of each. + + + + Similarly, a low-level port driver can undo the effect of + registering a port with the + parport_unregister_port function, and device + drivers are notified using the detach + callback. + + + + Device drivers can undo the effect of registering themselves with + the parport_unregister_driver + function. + + + + + + + + The IEEE 1284.3 API + + + The ability to daisy-chain devices is very useful, but if every + device does it in a different way it could lead to lots of + complications for device driver writers. Fortunately, the IEEE + are standardising it in IEEE 1284.3, which covers daisy-chain + devices and port multiplexors. + + + + At the time of writing, IEEE 1284.3 has not been published, but + the draft specifies the on-the-wire protocol for daisy-chaining + and multiplexing, and also suggests a programming interface for + using it. That interface (or most of it) has been implemented in + the parport code in Linux. + + + + At initialisation of the parallel port bus, + daisy-chained devices are assigned addresses starting from zero. + There can only be four devices with daisy-chain addresses, plus + one device on the end that doesn't know about daisy-chaining and + thinks it's connected directly to a computer. + + + + Another way of connecting more parallel port devices is to use a + multiplexor. The idea is to have a device that is connected + directly to a parallel port on a computer, but has a number of + parallel ports on the other side for other peripherals to connect + to (two or four ports are allowed). The multiplexor switches + control to different ports under software control---it is, in + effect, a programmable printer switch. + + + + Combining the ability of daisy-chaining five devices together with + the ability to multiplex one parallel port between four gives the + potential to have twenty peripherals connected to the same + parallel port! + + + + In addition, of course, a single computer can have multiple + parallel ports. So, each parallel port peripheral in the system + can be identified with three numbers, or co-ordinates: the + parallel port, the multiplexed port, and the daisy-chain + address. + + + + + + + + + + + + + Each device in the system is numbered at initialisation (by + parport_daisy_init). You can convert between + this device number and its co-ordinates with + parport_device_num and + parport_device_coords. + + + + int parport_device_num + int parport + int mux + int daisy + + + + int parport_device_coords + int devnum + int *parport + int *mux + int *daisy + + + + Any parallel port peripheral will be connected directly or + indirectly to a parallel port on the system, but it won't have a + daisy-chain address if it does not know about daisy-chaining, and + it won't be connected through a multiplexor port if there is no + multiplexor. The special co-ordinate value + -1 is used to indicate these cases. + + + + Two functions are provided for finding devices based on their IEEE + 1284 Device ID: parport_find_device and + parport_find_class. + + + + int parport_find_device + const char *mfg + const char *mdl + int from + + + + int parport_find_class + parport_device_class cls + int from + + + + These functions take a device number (in addition to some other + things), and return another device number. They walk through the + list of detected devices until they find one that matches the + requirements, and then return that device number (or + -1 if there are no more such devices). They + start their search at the device after the one in the list with + the number given (at from+1, in other + words). + + + + + + + + Device driver's view -This section is written from the point of view of the device -driver programmer, who might be writing a driver for a printer or a -scanner or else anything that plugs into the parallel port. It -explains how to use the parport interface to find -parallel ports, use them, and share them with other device -drivers. - -We'll start out with a description of the various functions that -can be called, and then look at a reasonably simple example of their -use: the printer driver. - -The interactions between the device driver and the -parport layer are as follows. First, the device -driver registers its existence with parport, in -order to get told about any parallel ports that have been (or will be) -detected. When it gets told about a parallel port, it then tells -parport that it wants to drive a device on that -port. Thereafter it can claim exclusive access to the port in order -to talk to its device. - -So, the first thing for the device driver to do is tell -parport that it wants to know what parallel ports -are on the system. To do this, it uses the -parport_register_device function: - - - + This section is written from the point of view of the device driver + programmer, who might be writing a driver for a printer or a + scanner or else anything that plugs into the parallel port. It + explains how to use the parport interface to + find parallel ports, use them, and share them with other device + drivers. + + + + We'll start out with a description of the various functions that + can be called, and then look at a reasonably simple example of + their use: the printer driver. + + + + The interactions between the device driver and the + parport layer are as follows. First, the + device driver registers its existence with + parport, in order to get told about any + parallel ports that have been (or will be) detected. When it gets + told about a parallel port, it then tells + parport that it wants to drive a device on + that port. Thereafter it can claim exclusive access to the port in + order to talk to its device. + + + + So, the first thing for the device driver to do is tell + parport that it wants to know what parallel + ports are on the system. To do this, it uses the + parport_register_device function: + + + + - - - int parport_register_driver - struct parport_driver *driver - - -In other words, the device driver passes pointers to a couple of -functions to parport, and -parport calls attach for -each port that's detected (and detach for each -port that disappears -- yes, this can happen). - -The next thing that happens is that the device driver tells -parport that it thinks there's a device on the -port that it can drive. This typically will happen in the driver's -attach function, and is done with -parport_register_device: - - - struct pardevice *parport_register_device - struct parport *port - const char *name - int (*pf) - void * - void (*kf) - void * - void (*irq_func) - int, void *, struct pt_regs * - int flags - void *handle - - -The port comes from the parameter supplied -to the attach function when it is called, or -alternatively can be found from the list of detected parallel ports -directly with the (now deprecated) -parport_enumerate function. - -The next three parameters, pf, -kf, and irq_func, are -more function pointers. These callback functions get called under -various circumstances, and are always given the -handle as one of their parameters. - -The preemption callback, pf, is called -when the driver has claimed access to the port but another device -driver wants access. If the driver is willing to let the port go, it -should return zero and the port will be released on its behalf. There -is no need to call parport_release. If -pf gets called at a bad time for letting the -port go, it should return non-zero and no action will be taken. It is -good manners for the driver to try to release the port at the earliest -opportunity after its preemption callback is called. - -The kick callback, kf, is -called when the port can be claimed for exclusive access; that is, -parport_claim is guaranteed to succeed inside the -kick callback. If the driver wants to claim the port -it should do so; otherwise, it need not take any action. - -The irq_func callback is called, -predictably, when a parallel port interrupt is generated. But it is -not the only code that hooks on the interrupt. The sequence is this: -the lowlevel driver is the one that has done -request_irq; it then does whatever -hardware-specific things it needs to do to the parallel port hardware -(for PC-style ports, there is nothing special to do); it then tells -the IEEE 1284 code about the interrupt, which may involve reacting to -an IEEE 1284 event, depending on the current IEEE 1284 phase; and -finally the irq_func function is called. - -None of the callback functions are allowed to block. - -The flags are for telling -parport any requirements or hints that are -useful. The only useful value here (other than -0, which is the usual value) is -PARPORT_DEV_EXCL. The point of that flag is to -request exclusive access at all times---once a driver has successfully -called parport_register_device with that flag, no -other device drivers will be able to register devices on that port -(until the successful driver deregisters its device, of -course). - -The PARPORT_DEV_EXCL flag is for preventing -port sharing, and so should only be used when sharing the port with -other device drivers is impossible and would lead to incorrect -behaviour. Use it sparingly! - -Devices can also be registered by device drivers based on their -device numbers (the same device numbers as in the previous -section). - -The parport_open function is similar to -parport_register_device, and -parport_close is the equivalent of -parport_unregister_device. The difference is -that parport_open takes a device number rather -than a pointer to a struct parport. - - - struct pardevice *parport_open - int devnum - int (*pf) - void * - int (*kf) - void * - int (*irqf) - int, void *, struct pt_regs * - int flags - void *handle - - - - void parport_close - struct pardevice *dev - - - - struct pardevice *parport_register_device - struct parport *port - const char *name - int (*pf) - void * - int (*kf) - void * - int (*irqf) - int, void *, struct pt_regs * - int flags - void *handle - - - - void parport_unregister_device - struct pardevice *dev - - -The intended use of these functions is during driver -initialisation while the driver looks for devices that it supports, as -demonstrated by the following code fragment: - - - + + + int parport_register_driver + struct parport_driver *driver + + + + In other words, the device driver passes pointers to a couple of + functions to parport, and + parport calls attach for + each port that's detected (and detach for each + port that disappears---yes, this can happen). + + + + The next thing that happens is that the device driver tells + parport that it thinks there's a device on the + port that it can drive. This typically will happen in the driver's + attach function, and is done with + parport_register_device: + + + + struct pardevice *parport_register_device + struct parport *port + const char *name + int (*pf) + void * + void (*kf) + void * + void (*irq_func) + int, void *, struct pt_regs * + int flags + void *handle + + + + The port comes from the parameter supplied + to the attach function when it is called, or + alternatively can be found from the list of detected parallel ports + directly with the (now deprecated) + parport_enumerate function. + + + + The next three parameters, pf, + kf, and irq_func, are + more function pointers. These callback functions get called under + various circumstances, and are always given the + handle as one of their parameters. + + + + The preemption callback, pf, is called when + the driver has claimed access to the port but another device driver + wants access. If the driver is willing to let the port go, it + should return zero and the port will be released on its behalf. + There is no need to call parport_release. If + pf gets called at a bad time for letting the + port go, it should return non-zero and no action will be taken. It + is good manners for the driver to try to release the port at the + earliest opportunity after its preemption callback is + called. + + + + The kick callback, kf, is + called when the port can be claimed for exclusive access; that is, + parport_claim is guaranteed to succeed inside + the kick callback. If the driver wants to claim the + port it should do so; otherwise, it need not take any + action. + + + + The irq_func callback is called, + predictably, when a parallel port interrupt is generated. But it + is not the only code that hooks on the interrupt. The sequence is + this: the lowlevel driver is the one that has done + request_irq; it then does whatever + hardware-specific things it needs to do to the parallel port + hardware (for PC-style ports, there is nothing special to do); it + then tells the IEEE 1284 code about the interrupt, which may + involve reacting to an IEEE 1284 event, depending on the current + IEEE 1284 phase; and finally the irq_func + function is called. + + + + None of the callback functions are allowed to block. + + + + The flags are for telling + parport any requirements or hints that are + useful. The only useful value here (other than + 0, which is the usual value) is + PARPORT_DEV_EXCL. The point of that flag is + to request exclusive access at all times---once a driver has + successfully called parport_register_device + with that flag, no other device drivers will be able to register + devices on that port (until the successful driver deregisters its + device, of course). + + + + The PARPORT_DEV_EXCL flag is for preventing + port sharing, and so should only be used when sharing the port with + other device drivers is impossible and would lead to incorrect + behaviour. Use it sparingly! + + + + Devices can also be registered by device drivers based on their + device numbers (the same device numbers as in the previous + section). + + + + The parport_open function is similar to + parport_register_device, and + parport_close is the equivalent of + parport_unregister_device. The difference is + that parport_open takes a device number rather + than a pointer to a struct parport. + + + + struct pardevice *parport_open + int devnum + int (*pf) + void * + int (*kf) + void * + int (*irqf) + int, void *, struct pt_regs * + int flags + void *handle + + + + void parport_close + struct pardevice *dev + + + + struct pardevice *parport_register_device + struct parport *port + const char *name + int (*pf) + void * + int (*kf) + void * + int (*irqf) + int, void *, struct pt_regs * + int flags + void *handle + + + + void parport_unregister_device + struct pardevice *dev + + + + The intended use of these functions is during driver initialisation + while the driver looks for devices that it supports, as + demonstrated by the following code fragment: + + + + - -Once your device driver has registered its device and been -handed a pointer to a struct pardevice, the -next thing you are likely to want to do is communicate with the device -you think is there. To do that you'll need to claim access to the -port. - - - int parport_claim - struct pardevice *dev - - - - int parport_claim_or_block - struct pardevice *dev - - - - void parport_release - struct pardevice *dev - - -To claim access to the port, use -parport_claim or -parport_claim_or_block. The first of these will -not block, and so can be used from interrupt context. If -parport_claim succeeds it will return zero and -the port is available to use. It may fail (returning non-zero) if the -port is in use by another driver and that driver is not willing to -relinquish control of the port. - -The other function, parport_claim_or_block, -will block if necessary to wait for the port to be free. If it slept, -it returns 1; if it succeeded without needing to -sleep it returns 0. If it fails it will return a -negative error code. - -When you have finished communicating with the device, you can -give up access to the port so that other drivers can communicate with -their devices. The parport_release function -cannot fail, but it should not be called without the port claimed. -Similarly, you should not try to claim the port if you already have it -claimed. - -You may find that although there are convenient points for your -driver to relinquish the parallel port and allow other drivers to talk -to their devices, it would be preferable to keep hold of the port. -The printer driver only needs the port when there is data to print, -for example, but a network driver (such as PLIP) could be sent a -remote packet at any time. With PLIP, it is no huge catastrophe if a -network packet is dropped, since it will likely be sent again, so it -is possible for that kind of driver to share the port with other -(pass-through) devices. - -The parport_yield and -parport_yield_blocking functions are for marking -points in the driver at which other drivers may claim the port and use -their devices. Yielding the port is similar to releasing it and -reclaiming it, but it more efficient because nothing is done if there -are no other devices needing the port. In fact, nothing is done even -if there are other devices waiting but the current device is still -within its timeslice. The default timeslice is half a -second, but it can be adjusted via a /proc -entry. - - - int parport_yield - struct pardevice *dev - - - - int parport_yield_blocking - struct pardevice *dev - - -The first of these, parport_yield, will not -block but as a result may fail. The return value for -parport_yield is the same as for -parport_claim. The blocking version, -parport_yield_blocking, has the same return code -as parport_claim_or_block. - -Once the port has been claimed, the device driver can use the -functions in the struct parport_operations -pointer in the struct parport it has a -pointer to. For example: - - - + + + Once your device driver has registered its device and been handed a + pointer to a struct pardevice, the next + thing you are likely to want to do is communicate with the device + you think is there. To do that you'll need to claim access to the + port. + + + + int parport_claim + struct pardevice *dev + + + + int parport_claim_or_block + struct pardevice *dev + + + + void parport_release + struct pardevice *dev + + + + To claim access to the port, use parport_claim + or parport_claim_or_block. The first of these + will not block, and so can be used from interrupt context. If + parport_claim succeeds it will return zero and + the port is available to use. It may fail (returning non-zero) if + the port is in use by another driver and that driver is not willing + to relinquish control of the port. + + + + The other function, parport_claim_or_block, + will block if necessary to wait for the port to be free. If it + slept, it returns 1; if it succeeded without + needing to sleep it returns 0. If it fails it + will return a negative error code. + + + + When you have finished communicating with the device, you can give + up access to the port so that other drivers can communicate with + their devices. The parport_release function + cannot fail, but it should not be called without the port claimed. + Similarly, you should not try to claim the port if you already have + it claimed. + + + + You may find that although there are convenient points for your + driver to relinquish the parallel port and allow other drivers to + talk to their devices, it would be preferable to keep hold of the + port. The printer driver only needs the port when there is data to + print, for example, but a network driver (such as PLIP) could be + sent a remote packet at any time. With PLIP, it is no huge + catastrophe if a network packet is dropped, since it will likely be + sent again, so it is possible for that kind of driver to share the + port with other (pass-through) devices. + + + + The parport_yield and + parport_yield_blocking functions are for + marking points in the driver at which other drivers may claim the + port and use their devices. Yielding the port is similar to + releasing it and reclaiming it, but is more efficient because + nothing is done if there are no other devices needing the port. In + fact, nothing is done even if there are other devices waiting but + the current device is still within its timeslice. + The default timeslice is half a second, but it can be adjusted via + a /proc entry. + + + + int parport_yield + struct pardevice *dev + + + + int parport_yield_blocking + struct pardevice *dev + + + + The first of these, parport_yield, will not + block but as a result may fail. The return value for + parport_yield is the same as for + parport_claim. The blocking version, + parport_yield_blocking, has the same return + code as parport_claim_or_block. + + + + Once the port has been claimed, the device driver can use the + functions in the struct parport_operations + pointer in the struct parport it has a + pointer to. For example: + + + + ops->write_data (port, d); -]]> - -Some of these operations have shortcuts. For -instance, parport_write_data is equivalent to the -above, but may be a little bit faster (it's a macro that in some cases -can avoid needing to indirect through port and -ops). - - - - -Port drivers - - - -To recap, then: - - - - - -The device driver registers itself with parport. - - - - - -A low-level driver finds a parallel port and registers it with -parport (these first two things can happen in -either order). This registration creates a struct -parport which is linked onto a list of known ports. - - - - - -parport calls the attach -function of each registered device driver, passing it the pointer to -the new struct parport. - - - - - -The device driver gets a handle from parport, for -use with -parport_claim/release. This -handle takes the form of a pointer to a struct -pardevice, representing a particular device on the -parallel port, and is acquired using -parport_register_device. - - - - - -The device driver claims the port using -parport_claim (or -function_claim_or_block). - - - - - -Then it goes ahead and uses the port. When finished it releases the -port. - - - - - -The purpose of the low-level drivers, then, is to detect -parallel ports and provide methods of accessing them -(i.e. implementing the operations in struct -parport_operations). - - - - - - -A more complete description of which operation is supposed to do -what is available in -Documentation/parport-lowlevel.txt. - - - - -The printer driver - - - - -The printer driver, lp is a character -special device driver and a parport client. As a -character special device driver it registers a struct -file_operations using -register_chrdev, with pointers filled in for -write, ioctl, -open and -release. As a client of -parport, it registers a struct -parport_driver using -parport_register_driver, so that -parport knows to call -lp_attach when a new parallel port is discovered -(and lp_detach when it goes away). - -The parallel port console functionality is also implemented in -lp.c, but that won't be covered here (it's quite -simple though). - -The initialisation of the driver is quite easy to understand -(see lp_init). The lp_table -is an array of structures that contain information about a specific -device (the struct pardevice associated with -it, for example). That array is initialised to sensible values first -of all. - -Next, the printer driver calls -register_chrdev passing it a pointer to -lp_fops, which contains function pointers for the -printer driver's implementation of open, -write, and so on. This part is the same as for -any character special device driver. - -After successfully registering itself as a character special -device driver, the printer driver registers itself as a -parport client using -parport_register_driver. It passes a pointer to -this structure: - - - + + + Some of these operations have shortcuts. For + instance, parport_write_data is equivalent to + the above, but may be a little bit faster (it's a macro that in + some cases can avoid needing to indirect through + port and ops). + + + + + + Port drivers + + + + + To recap, then: + + + + + + The device driver registers itself with parport. + + + + + + A low-level driver finds a parallel port and registers it with + parport (these first two things can happen + in either order). This registration creates a struct + parport which is linked onto a list of known ports. + + + + + + parport calls the + attach function of each registered device + driver, passing it the pointer to the new struct + parport. + + + + + + The device driver gets a handle from + parport, for use with + parport_claim/release. + This handle takes the form of a pointer to a struct + pardevice, representing a particular device on the + parallel port, and is acquired using + parport_register_device. + + + + + + The device driver claims the port using + parport_claim (or + function_claim_or_block). + + + + + + Then it goes ahead and uses the port. When finished it releases + the port. + + + + + + + The purpose of the low-level drivers, then, is to detect parallel + ports and provide methods of accessing them (i.e. implementing the + operations in struct + parport_operations). + + + + + A more complete description of which operation is supposed to do + what is available in + Documentation/parport-lowlevel.txt. + + + + + + The printer driver + + + + + + The printer driver, lp is a character special + device driver and a parport client. As a + character special device driver it registers a struct + file_operations using + register_chrdev, with pointers filled in for + write, ioctl, + open and + release. As a client of + parport, it registers a struct + parport_driver using + parport_register_driver, so that + parport knows to call + lp_attach when a new parallel port is + discovered (and lp_detach when it goes + away). + + + + The parallel port console functionality is also implemented in + lp.c, but that won't be covered here (it's + quite simple though). + + + + The initialisation of the driver is quite easy to understand (see + lp_init). The lp_table is + an array of structures that contain information about a specific + device (the struct pardevice associated + with it, for example). That array is initialised to sensible + values first of all. + + + + Next, the printer driver calls register_chrdev + passing it a pointer to lp_fops, which contains + function pointers for the printer driver's implementation of + open, write, and so on. + This part is the same as for any character special device + driver. + + + + After successfully registering itself as a character special device + driver, the printer driver registers itself as a + parport client using + parport_register_driver. It passes a pointer + to this structure: + + + + - -The lp_detach function is not very -interesting (it does nothing); the interesting bit is -lp_attach. What goes on here depends on whether -the user supplied any parameters. The possibilities are: no -parameters supplied, in which case the printer driver uses every port -that is detected; the user supplied the parameter auto, -in which case only ports on which the device ID string indicates a -printer is present are used; or the user supplied a list of parallel -port numbers to try, in which case only those are used. - -For each port that the printer driver wants to use (see -lp_register), it calls -parport_register_device and stores the resulting -struct pardevice pointer in the -lp_table. If the user told it to do so, it then -resets the printer. - -The other interesting piece of the printer driver, from the -point of view of parport, is -lp_write. In this function, the user space -process has data that it wants printed, and the printer driver hands -it off to the parport code to deal with. - -The parport functions it uses that we have -not seen yet are parport_negotiate, -parport_set_timeout, and -parport_write. These functions are part of the -IEEE 1284 implementation. - -The way the IEEE 1284 protocol works is that the host tells the -peripheral what transfer mode it would like to use, and the peripheral -either accepts that mode or rejects it; if the mode is rejected, the -host can try again with a different mode. This is the negotation -phase. Once the peripheral has accepted a particular transfer mode, -data transfer can begin that mode. - -The particular transfer mode that the printer driver wants to -use is named in IEEE 1284 as compatibility mode, and -the function to request a particular mode is called -parport_negotiate. - - - int parport_negotiate - struct parport *port - int mode - - -The modes parameter is a symbolic -constant representing an IEEE 1284 mode; in this instance, it is -IEEE1284_MODE_COMPAT. (Compatibility mode is -slightly different to the other modes---rather than being specifically -requested, it is the default until another mode is selected.) - -Back to lp_write then. First, access to -the parallel port is secured with -parport_claim_or_block. At this point the driver -might sleep, waiting for another driver (perhaps a Zip drive driver, -for instance) to let the port go. Next, it goes to compatibility mode -using parport_negotiate. - -The main work is done in the write-loop. In particular, the -line that hands the data over to parport -reads: + ]]> + + + The lp_detach function is not very interesting + (it does nothing); the interesting bit is + lp_attach. What goes on here depends on + whether the user supplied any parameters. The possibilities are: + no parameters supplied, in which case the printer driver uses every + port that is detected; the user supplied the parameter + auto, in which case only ports on which the device + ID string indicates a printer is present are used; or the user + supplied a list of parallel port numbers to try, in which case only + those are used. + + + + For each port that the printer driver wants to use (see + lp_register), it calls + parport_register_device and stores the + resulting struct pardevice pointer in the + lp_table. If the user told it to do so, it then + resets the printer. + + + + The other interesting piece of the printer driver, from the point + of view of parport, is + lp_write. In this function, the user space + process has data that it wants printed, and the printer driver + hands it off to the parport code to deal with. + + + + The parport functions it uses that we have not + seen yet are parport_negotiate, + parport_set_timeout, and + parport_write. These functions are part of + the IEEE 1284 implementation. + + + + The way the IEEE 1284 protocol works is that the host tells the + peripheral what transfer mode it would like to use, and the + peripheral either accepts that mode or rejects it; if the mode is + rejected, the host can try again with a different mode. This is + the negotation phase. Once the peripheral has accepted a + particular transfer mode, data transfer can begin that mode. + + + + The particular transfer mode that the printer driver wants to use + is named in IEEE 1284 as compatibility mode, and the + function to request a particular mode is called + parport_negotiate. + + + + int parport_negotiate + struct parport *port + int mode + + + + The modes parameter is a symbolic constant + representing an IEEE 1284 mode; in this instance, it is + IEEE1284_MODE_COMPAT. (Compatibility mode is + slightly different to the other modes---rather than being + specifically requested, it is the default until another mode is + selected.) + + + + Back to lp_write then. First, access to the + parallel port is secured with + parport_claim_or_block. At this point the + driver might sleep, waiting for another driver (perhaps a Zip drive + driver, for instance) to let the port go. Next, it goes to + compatibility mode using parport_negotiate. + + + + The main work is done in the write-loop. In particular, the line + that hands the data over to parport reads: + -The parport_write function writes data to -the peripheral using the currently selected transfer mode -(compatibility mode, in this case). It returns the number of bytes -successfully written: - - - ssize_t parport_write - struct parport *port - const void *buf - size_t len - - - - ssize_t parport_read - struct parport *port - void *buf - size_t len - - -(parport_read does what it sounds like, but -only works for modes in which reverse transfer is possible. Of -course, parport_write only works in modes in -which forward transfer is possible, too.) - -The buf pointer should be to kernel space -memory, and obviously the len parameter -specifies the amount of data to transfer. - -In fact what parport_write does is call the -appropriate block transfer function from the struct -parport_operations: - - - + The parport_write function writes data to the + peripheral using the currently selected transfer mode + (compatibility mode, in this case). It returns the number of bytes + successfully written: + + + + ssize_t parport_write + struct parport *port + const void *buf + size_t len + + + + ssize_t parport_read + struct parport *port + void *buf + size_t len + + + + (parport_read does what it sounds like, but + only works for modes in which reverse transfer is possible. Of + course, parport_write only works in modes in + which forward transfer is possible, too.) + + + + The buf pointer should be to kernel space + memory, and obviously the len parameter + specifies the amount of data to transfer. + + + + In fact what parport_write does is call the + appropriate block transfer function from the struct + parport_operations: + + + + - -The transfer code in parport will tolerate -a data transfer stall only for so long, and this timeout can be -specified with parport_set_timeout, which returns -the previous timeout: - - - long parport_set_timeout - struct pardevice *dev - long inactivity - - -This timeout is specific to the device, and is restored on -parport_claim. - - - - -User-level device drivers - - - -Introduction to ppdev - -The printer is accessible through /dev/lp0; -in the same way, the parallel port itself is accessible through -/dev/parport0. The difference is in the level of -control that you have over the wires in the parallel port -cable. - -With the printer driver, a user-space program (such as the -printer spooler) can send bytes in printer protocol. -Briefly, this means that for each byte, the eight data lines are set -up, then a strobe line tells the printer to look at the -data lines, and the printer sets an acknowledgement -line to say that it got the byte. The printer driver also allows the -user-space program to read bytes in nibble mode, which -is a way of transferring data from the peripheral to the computer half -a byte at a time (and so it's quite slow). - -In contrast, the ppdev driver (accessed via -/dev/parport0) allows you to: - - - - - -examine status lines, - - - - - -set control lines, - - - - - -set/examine data lines (and control the direction of the data lines), - - - - - -wait for an interrupt (triggered by one of the status lines), - - - - - -find out how many new interrupts have occurred, - - - - - -set up a response to an interrupt, - - - - - -use IEEE 1284 negotiation (for telling peripheral which transfer mode, -to use) - - - - - -transfer data using a specified IEEE 1284 mode. - - - - - - - - -User-level or kernel-level driver? - -The decision of whether to choose to write a kernel-level device -driver or a user-level device driver depends on several factors. One -of the main ones from a practical point of view is speed: kernel-level -device drivers get to run faster because they are not preemptable, -unlike user-level applications. - -Another factor is ease of development. It is in general easier -to write a user-level driver because (a) one wrong move does not -result in a crashed machine, (b) you have access to user libraries -(such as the C library), and (c) debugging is easier. - - - - -Programming interface - -The ppdev interface is largely the same as -that of other character special devices, in that it supports -open, close, -read, write, and -ioctl. - - -Starting and stopping: <function>open</function> and -<function>close</function> - -The device node /dev/parport0 represents -any device that is connected to parport0, the -first parallel port in the system. Each time the device node is -opened, it represents (to the process doing the opening) a different -device. It can be opened more than once, but only one instance can -actually be in control of the parallel port at any time. A process -that has opened /dev/parport0 shares the parallel -port in the same way as any other device driver. A user-land driver -may be sharing the parallel port with in-kernel device drivers as well -as other user-land drivers. - - - -Control: <function>ioctl</function> - -Most of the control is done, naturally enough, via the -ioctl call. Using ioctl, -the user-land driver can control both the ppdev -driver in the kernel and the physical parallel port itself. The -ioctl call takes as parameters a file descriptor -(the one returned from opening the device node), a command, and -optionally (a pointer to) some data. - - -PPCLAIM - - -Claims access to the port. As a user-land device driver writer, -you will need to do this before you are able to actually change the -state of the parallel port in any way. Note that some operations only -affect the ppdev driver and not the port, such as -PPSETMODE; they can be performed while access to -the port is not claimed. - - - -PPEXCL - - -Instructs the kernel driver to forbid any sharing of the port -with other drivers, i.e. it requests exclusivity. The -PPEXCL command is only valid when the port is not -already claimed for use, and it may mean that the next -PPCLAIM ioctl will fail: -some other driver may already have registered itself on that -port. - -Most device drivers don't need exclusive access to the port. -It's only provided in case it is really needed, for example for -devices where access to the port is required for extensive periods of -time (many seconds). - -Note that the PPEXCL -ioctl doesn't actually claim the port there and -then---action is deferred until the PPCLAIM -ioctl is performed. - - - -PPRELEASE - - -Releases the port. Releasing the port undoes the effect of -claiming the port. It allows other device drivers to talk to their -devices (assuming that there are any). - - - -PPYIELD - - -Yields the port to another driver. This -ioctl is a kind of short-hand for releasing the -port and immediately reclaiming it. It gives other drivers a chance -to talk to their devices, but afterwards claims the port back. An -example of using this would be in a user-land printer driver: once a -few characters have been written we could give the port to another -device driver for a while, but if we still have characters to send to -the printer we would want the port back as soon as possible. - -It is important not to claim the parallel port for too long, as -other device drivers will have no time to service their devices. If -your device does not allow for parallel port sharing at all, it is -better to claim the parallel port exclusively (see -PPEXCL). - - - -PPNEGOT - - -Performs IEEE 1284 negotiation into a particular mode. Briefly, -negotiation is the method by which the host and the peripheral decide -on a protocol to use when transferring data. - -An IEEE 1284 compliant device will start out in compatibility -mode, and then the host can negotiate to another mode (such as -ECP). - -The ioctl parameter should be a pointer to -an int; values for this are in -parport.h and include: - - -IEEE1284_MODE_COMPAT -IEEE1284_MODE_NIBBLE -IEEE1284_MODE_BYTE -IEEE1284_MODE_EPP -IEEE1284_MODE_ECP - - -The PPNEGOT ioctl -actually does two things: it performs the on-the-wire negotiation, and -it sets the behaviour of subsequent -read/write calls so that -they use that mode (but see PPSETMODE). - - - -PPSETMODE - - -Sets which IEEE 1284 protocol to use for the -read and write calls. + ]]> -The ioctl parameter should be a pointer to -an int. - - + + The transfer code in parport will tolerate a + data transfer stall only for so long, and this timeout can be + specified with parport_set_timeout, which + returns the previous timeout: + -PPGETTIME - + + long parport_set_timeout + struct pardevice *dev + long inactivity + -Retrieves the time-out value. The read and -write calls will time out if the peripheral -doesn't respond quickly enough. The PPGETTIME -ioctl retrieves the length of time that the -peripheral is allowed to have before giving up. + + This timeout is specific to the device, and is restored on + parport_claim. + -The ioctl parameter should be a pointer to -a struct timeval. + - + + User-level device drivers -PPSETTIME - + + + Introduction to ppdev -Sets the time-out. The ioctl parameter -should be a pointer to a struct -timeval. - - - -PPWCONTROL - - -Sets the control lines. The ioctl -parameter is a pointer to an unsigned char, the bitwise -OR of the control line values in -parport.h. - - + + The printer is accessible through /dev/lp0; + in the same way, the parallel port itself is accessible through + /dev/parport0. The difference is in the + level of control that you have over the wires in the parallel port + cable. + -PPRCONTROL - + + With the printer driver, a user-space program (such as the printer + spooler) can send bytes in printer protocol. + Briefly, this means that for each byte, the eight data lines are + set up, then a strobe line tells the printer to + look at the data lines, and the printer sets an + acknowledgement line to say that it got the byte. + The printer driver also allows the user-space program to read + bytes in nibble mode, which is a way of + transferring data from the peripheral to the computer half a byte + at a time (and so it's quite slow). + -Returns the last value written to the control register, in the -form of an unsigned char: each bit corresponds to a -control line (although some are unused). The -ioctl parameter should be a pointer to an -unsigned char. - -This doesn't actually touch the hardware; the last value written -is remembered in software. This is because some parallel port -hardware does not offer read access to the control register. + + In contrast, the ppdev driver (accessed via + /dev/parport0) allows you to: + -The control lines bits are defined in -parport.h: + + + + + examine status lines, + + + + + + set control lines, + + + + + + set/examine data lines (and control the direction of the data + lines), + + + + + + wait for an interrupt (triggered by one of the status lines), + + + + + + find out how many new interrupts have occurred, + + + + + + set up a response to an interrupt, + + + + + + use IEEE 1284 negotiation (for telling peripheral which transfer + mode, to use) + + + + + + transfer data using a specified IEEE 1284 mode. + + + + + + + + + User-level or kernel-level driver? - -PARPORT_CONTROL_STROBE -PARPORT_CONTROL_AUTOFD -PARPORT_CONTROL_SELECT -PARPORT_CONTROL_INIT - + + The decision of whether to choose to write a kernel-level device + driver or a user-level device driver depends on several factors. + One of the main ones from a practical point of view is speed: + kernel-level device drivers get to run faster because they are not + preemptable, unlike user-level applications. + - + + Another factor is ease of development. It is in general easier to + write a user-level driver because (a) one wrong move does not + result in a crashed machine, (b) you have access to user libraries + (such as the C library), and (c) debugging is easier. + -PPFCONTROL - + -Frobs the control lines. Since a common operation is to change -one of the control signals while leaving the others alone, it would be -quite inefficient for the user-land driver to have to use -PPRCONTROL, make the change, and then use -PPWCONTROL. Of course, each driver could -remember what state the control lines are supposed to be in (they are -never changed by anything else), but in order to provide -PPRCONTROL, ppdev must -remember the state of the control lines anyway. + + Programming interface -The PPFCONTROL ioctl -is for frobbing control lines, and is like -PPWCONTROL but acts on a restricted set of -control lines. The ioctl parameter is a pointer -to a struct ppdev_frob_struct: + + The ppdev interface is largely the same as + that of other character special devices, in that it supports + open, close, + read, write, and + ioctl. + - - + + Starting and stopping: <function>open</function> and + <function>close</function> + + + + The device node /dev/parport0 represents any + device that is connected to parport0, the + first parallel port in the system. Each time the device node is + opened, it represents (to the process doing the opening) a + different device. It can be opened more than once, but only one + instance can actually be in control of the parallel port at any + time. A process that has opened + /dev/parport0 shares the parallel port in + the same way as any other device driver. A user-land driver may + be sharing the parallel port with in-kernel device drivers as + well as other user-land drivers. + + + + + Control: <function>ioctl</function> + + + Most of the control is done, naturally enough, via the + ioctl call. Using + ioctl, the user-land driver can control both + the ppdev driver in the kernel and the + physical parallel port itself. The ioctl + call takes as parameters a file descriptor (the one returned from + opening the device node), a command, and optionally (a pointer + to) some data. + + + + PPCLAIM + + + + Claims access to the port. As a user-land device driver + writer, you will need to do this before you are able to + actually change the state of the parallel port in any way. + Note that some operations only affect the + ppdev driver and not the port, such as + PPSETMODE; they can be performed while + access to the port is not claimed. + + + + + PPEXCL + + + + Instructs the kernel driver to forbid any sharing of the port + with other drivers, i.e. it requests exclusivity. The + PPEXCL command is only valid when the + port is not already claimed for use, and it may mean that the + next PPCLAIM ioctl + will fail: some other driver may already have registered + itself on that port. + + + + Most device drivers don't need exclusive access to the port. + It's only provided in case it is really needed, for example + for devices where access to the port is required for extensive + periods of time (many seconds). + + + + Note that the PPEXCL + ioctl doesn't actually claim the port + there and then---action is deferred until the + PPCLAIM ioctl is + performed. + + + + + PPRELEASE + + + + Releases the port. Releasing the port undoes the effect of + claiming the port. It allows other device drivers to talk to + their devices (assuming that there are any). + + + + + PPYIELD + + + + Yields the port to another driver. This + ioctl is a kind of short-hand for + releasing the port and immediately reclaiming it. It gives + other drivers a chance to talk to their devices, but + afterwards claims the port back. An example of using this + would be in a user-land printer driver: once a few characters + have been written we could give the port to another device + driver for a while, but if we still have characters to send to + the printer we would want the port back as soon as possible. + + + + It is important not to claim the parallel port for too long, + as other device drivers will have no time to service their + devices. If your device does not allow for parallel port + sharing at all, it is better to claim the parallel port + exclusively (see PPEXCL). + + + + + PPNEGOT + + + + Performs IEEE 1284 negotiation into a particular mode. + Briefly, negotiation is the method by which the host and the + peripheral decide on a protocol to use when transferring data. + + + + An IEEE 1284 compliant device will start out in compatibility + mode, and then the host can negotiate to another mode (such as + ECP). + + + + The ioctl parameter should be a pointer + to an int; values for this are in + parport.h and include: + + + + + IEEE1284_MODE_COMPAT + + IEEE1284_MODE_NIBBLE + + IEEE1284_MODE_BYTE + + IEEE1284_MODE_EPP + + IEEE1284_MODE_ECP + + + + The PPNEGOT ioctl + actually does two things: it performs the on-the-wire + negotiation, and it sets the behaviour of subsequent + read/write calls so + that they use that mode (but see + PPSETMODE). + + + + + PPSETMODE + + + + Sets which IEEE 1284 protocol to use for the + read and write + calls. + + + + The ioctl parameter should be a pointer + to an int. + + + + + PPGETTIME + + + + Retrieves the time-out value. The read + and write calls will time out if the + peripheral doesn't respond quickly enough. The + PPGETTIME ioctl + retrieves the length of time that the peripheral is allowed to + have before giving up. + + + + The ioctl parameter should be a pointer + to a struct timeval. + + + + + PPSETTIME + + + + Sets the time-out. The ioctl parameter + should be a pointer to a struct + timeval. + + + + + PPWCONTROL + + + + Sets the control lines. The ioctl + parameter is a pointer to an unsigned char, the + bitwise OR of the control line values in + parport.h. + + + + + PPRCONTROL + + + + Returns the last value written to the control register, in the + form of an unsigned char: each bit corresponds to + a control line (although some are unused). The + ioctl parameter should be a pointer to an + unsigned char. + + + + This doesn't actually touch the hardware; the last value + written is remembered in software. This is because some + parallel port hardware does not offer read access to the + control register. + + + + The control lines bits are defined in + parport.h: + + + + + PARPORT_CONTROL_STROBE + + PARPORT_CONTROL_AUTOFD + + PARPORT_CONTROL_SELECT + + PARPORT_CONTROL_INIT + + + + + PPFCONTROL + + + + Frobs the control lines. Since a common operation is to + change one of the control signals while leaving the others + alone, it would be quite inefficient for the user-land driver + to have to use PPRCONTROL, make the + change, and then use PPWCONTROL. Of + course, each driver could remember what state the control + lines are supposed to be in (they are never changed by + anything else), but in order to provide + PPRCONTROL, ppdev + must remember the state of the control lines anyway. + + + + The PPFCONTROL ioctl + is for frobbing control lines, and is like + PPWCONTROL but acts on a restricted set + of control lines. The ioctl parameter is + a pointer to a struct + ppdev_frob_struct: + + + + - - -The mask and -val fields are bitwise ORs of control line -names (such as in PPWCONTROL). The operation -performed by PPFCONTROL is: - - - - - -In other words, the signals named in -mask are set to the values in -val. + ]]> + + + + The mask and + val fields are bitwise ORs of + control line names (such as in + PPWCONTROL). The operation performed by + PPFCONTROL is: + + + + + + + + In other words, the signals named in + mask are set to the values in + val. + + + + + PPRSTATUS + + + + Returns an unsigned char containing bits set for + each status line that is set (for instance, + PARPORT_STATUS_BUSY). The + ioctl parameter should be a pointer to an + unsigned char. + + + + + PPDATADIR + + + + Controls the data line drivers. Normally the computer's + parallel port will drive the data lines, but for byte-wide + transfers from the peripheral to the host it is useful to turn + off those drivers and let the peripheral drive the + signals. (If the drivers on the computer's parallel port are + left on when this happens, the port might be damaged.) + + + + This is only needed in conjunction with + PPWDATA or + PPRDATA. + + + + The ioctl parameter is a pointer to an + int. If the int is zero, the + drivers are turned on (forward direction); if non-zero, the + drivers are turned off (reverse direction). + + + + + PPWDATA + + + + Sets the data lines (if in forward mode). The + ioctl parameter is a pointer to an + unsigned char. + + + + + PPRDATA + + + + Reads the data lines (if in reverse mode). The + ioctl parameter is a pointer to an + unsigned char. + + + + + PPCLRIRQ + + + + Clears the interrupt count. The ppdev + driver keeps a count of interrupts as they are triggered. + PPCLRIRQ stores this count in an + int, a pointer to which is passed in as the + ioctl parameter. + + + + In addition, the interrupt count is reset to zero. + + + + + PPWCTLONIRQ + + + + Set a trigger response. Afterwards when an interrupt is + triggered, the interrupt handler will set the control lines as + requested. The ioctl parameter is a + pointer to an unsigned char, which is interpreted + in the same way as for PPWCONTROL. + + + + The reason for this ioctl is simply + speed. Without this ioctl, responding to + an interrupt would start in the interrupt handler, switch + context to the user-land driver via poll + or select, and then switch context back + to the kernel in order to handle + PPWCONTROL. Doing the whole lot in the + interrupt handler is a lot faster. + + + + + + + + + + + + Transferring data: <function>read</function> and + <function>write</function> + + + Transferring data using read and + write is straightforward. The data is + transferring using the current IEEE 1284 mode (see the + PPSETMODE ioctl). For + modes which can only transfer data in one direction, only the + appropriate function will work, of course. + + + + + Waiting for events: <function>poll</function> and + <function>select</function> + + + The ppdev driver provides user-land device + drivers with the ability to wait for interrupts, and this is done + using poll (and select, + which is implemented in terms of poll). + + + + When a user-land device driver wants to wait for an interrupt, it + sleeps with poll. When the interrupt + arrives, ppdev wakes it up (with a + read event, although strictly speaking there is + nothing to actually read). + + + + + + + + Examples - - -PPRSTATUS - - -Returns an unsigned char containing bits set for -each status line that is set (for instance, -PARPORT_STATUS_BUSY). The -ioctl parameter should be a pointer to an -unsigned char. - - - -PPDATADIR - - -Controls the data line drivers. Normally the computer's -parallel port will drive the data lines, but for byte-wide transfers -from the peripheral to the host it is useful to turn off those drivers -and let the peripheral drive the signals. (If the drivers on the -computer's parallel port are left on when this happens, the port might -be damaged.) - -This is only needed in conjunction with -PPWDATA or PPRDATA. - -The ioctl parameter is a pointer to an -int. If the int is zero, the drivers are -turned on (forward direction); if non-zero, the drivers are turned off -(reverse direction). - - - -PPWDATA - - -Sets the data lines (if in forward mode). The -ioctl parameter is a pointer to an unsigned -char. - - - -PPRDATA - - -Reads the data lines (if in reverse mode). The -ioctl parameter is a pointer to an unsigned -char. - - - -PPCLRIRQ - - -Clears the interrupt count. The ppdev -driver keeps a count of interrupts as they are triggered. -PPCLRIRQ stores this count in an -int, a pointer to which is passed in as the -ioctl parameter. - -In addition, the interrupt count is reset to zero. - - - -PPWCTLONIRQ - - -Set a trigger response. Afterwards when an interrupt is -triggered, the interrupt handler will set the control lines as -requested. The ioctl parameter is a pointer to -an unsigned char, which is interpreted in the same way as -for PPWCONTROL. - -The reason for this ioctl is simply speed. -Without this ioctl, responding to an interrupt -would start in the interrupt handler, switch context to the user-land -driver via poll or select, -and then switch context back to the kernel in order to handle -PPWCONTROL. Doing the whole lot in the interrupt -handler is a lot faster. - - - - - - - - - - -Transferring data: <function>read</function> and -<function>write</function> - -Transferring data using read and -write is straightforward. The data is -transferring using the current IEEE 1284 mode (see the -PPSETMODE ioctl). For modes -which can only transfer data in one direction, only the appropriate -function will work, of course. - - - -Waiting for events: <function>poll</function> and -<function>select</function> - -The ppdev driver provides user-land device -drivers with the ability to wait for interrupts, and this is done -using poll (and select, -which is implemented in terms of poll). - -When a user-land device driver wants to wait for an interrupt, -it sleeps with poll. When the interrupt arrives, -ppdev wakes it up (with a read -event, although strictly speaking there is nothing to actually -read). - - - - - - -Examples - -Presented here are two demonstrations of how to write a simple -printer driver for ppdev. Firstly we will use -the write function, and after that we will drive -the control and data lines directly. + + Presented here are two demonstrations of how to write a simple + printer driver for ppdev. Firstly we will + use the write function, and after that we + will drive the control and data lines directly. + -The first thing to do is to actually open the device. + + The first thing to do is to actually open the device. + - + ]]> -Here name should be something along the lines -of "/dev/parport0". (If you don't have any -/dev/parport files, you can make them with -mknod; they are character special device nodes with -major 99.) + + Here name should be something along the lines + of "/dev/parport0". (If you don't have any + /dev/parport files, you can make them with + mknod; they are character special device nodes + with major 99.) + -In order to do anything with the port we need to claim access to -it. + + In order to do anything with the port we need to claim access to + it. + - + ]]> -Our printer driver will copy its input (from -stdin) to the printer, and it can do that it one of -two ways. The first way is to hand it all off to the kernel driver, -with the knowledge that the protocol that the printer speaks is IEEE -1284's compatibility mode. + + Our printer driver will copy its input (from + stdin) to the printer, and it can do that it + one of two ways. The first way is to hand it all off to the + kernel driver, with the knowledge that the protocol that the + printer speaks is IEEE 1284's compatibility + mode. + - + ]]> -The write_printer function is not pictured -above. This is because the main loop that is shown can be used for -both methods of driving the printer. Here is one implementation of -write_printer: + + The write_printer function is not pictured + above. This is because the main loop that is shown can be used + for both methods of driving the printer. Here is one + implementation of write_printer: + - + ]]> -We hand the data to the kernel-level driver (using -write) and it handles the printer -protocol. + + We hand the data to the kernel-level driver (using + write) and it handles the printer + protocol. + -Now let's do it the hard way! In this particular example there -is no practical reason to do anything other than just call -write, because we know that the printer talks an -IEEE 1284 protocol. On the other hand, this particular example does -not even need a user-land driver since there is already a kernel-level -one; for the purpose of this discussion, try to imagine that the -printer speaks a protocol that is not already implemented under -Linux. + + Now let's do it the hard way! In this particular example there is + no practical reason to do anything other than just call + write, because we know that the printer talks + an IEEE 1284 protocol. On the other hand, this particular example + does not even need a user-land driver since there is already a + kernel-level one; for the purpose of this discussion, try to + imagine that the printer speaks a protocol that is not already + implemented under Linux. + -So, here is the alternative implementation of -write_printer (for brevity, error checking has -been omitted): + + So, here is the alternative implementation of + write_printer (for brevity, error checking + has been omitted): + - + ]]> -To show a bit more of the ppdev interface, -here is a small piece of code that is intended to mimic the printer's -side of printer protocol. + + To show a bit more of the ppdev interface, + here is a small piece of code that is intended to mimic the + printer's side of printer protocol. + - putchar (ch); } -]]> - - + ]]> + + + + + + + + API reference + + +!Fdrivers/parport/daisy.c parport_device_num +!Fdrivers/parport/daisy.c parport_device_coords +!Fdrivers/parport/daisy.c parport_find_device +!Fdrivers/parport/daisy.c parport_find_class +!Fdrivers/parport/share.c parport_register_driver +!Fdrivers/parport/share.c parport_unregister_driver +!Fdrivers/parport/share.c parport_register_device +!Fdrivers/parport/share.c parport_unregister_device +!Fdrivers/parport/daisy.c parport_open +!Fdrivers/parport/daisy.c parport_close +!Fdrivers/parport/share.c parport_claim +!Fdrivers/parport/share.c parport_claim_or_block +!Fdrivers/parport/share.c parport_release +!Finclude/linux/parport.h parport_yield +!Finclude/linux/parport.h parport_yield_blocking +!Fdrivers/parport/ieee1284.c parport_negotiate +!Fdrivers/parport/ieee1284.c parport_write +!Fdrivers/parport/ieee1284.c parport_read +!Fdrivers/parport/ieee1284.c parport_set_timeout + + + + + + + + - - \ No newline at end of file diff --git a/Documentation/pci.txt b/Documentation/pci.txt index b676d2b32c96..b96f6c48fec5 100644 --- a/Documentation/pci.txt +++ b/Documentation/pci.txt @@ -96,6 +96,9 @@ Tips: The ID table array should be marked __devinitdata. The probe() and remove() functions (and all initialization functions called only from these) should be marked __devinit/exit. + If you are sure the driver is not a hotplug driver then use only + __init/exit __initdata/exitdata. + 2. How to find PCI devices manually (the old style) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/video4linux/bttv/CARDLIST b/Documentation/video4linux/bttv/CARDLIST index e41e60edfb7c..02ec58baac56 100644 --- a/Documentation/video4linux/bttv/CARDLIST +++ b/Documentation/video4linux/bttv/CARDLIST @@ -38,6 +38,10 @@ bttv.o card=36 - Typhoon TView TV/FM Tuner card=37 - PixelView PlayTV pro card=38 - TView99 CPH063 + card=39 - Pinnacle PCTV Rave + card=40 - STB2 + card=41 - AVerMedia TVPhone 98 + card=42 - ProVideo PV951 tuner.o type=0 - Temic PAL diff --git a/MAINTAINERS b/MAINTAINERS index 56f7268549de..1776ea8a77c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -482,6 +482,7 @@ S: Supported IDE DRIVER [GENERAL] P: Andre Hedrick M: andre@linux-ide.org +M: ahedrick@atipa.com M: andre@suse.com L: linux-kernel@vger.rutgers.edu W: http://www.kernel.org/pub/linux/kernel/people/hedrick/ diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 3988131acb04..b49cebfded6b 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -182,7 +182,7 @@ ifeq ($(CONFIG_ARCH_ACORN),y) SUBDIRS += drivers/acorn DRIVERS += drivers/acorn/block/acorn-block.a DRIVERS += drivers/acorn/char/acorn-char.o -DRIVERS += drivers/acorn/net/acorn-net.a +DRIVERS += drivers/acorn/net/acorn-net.o DRIVERS += drivers/acorn/scsi/acorn-scsi.a endif diff --git a/arch/arm/def-configs/ebsa110 b/arch/arm/def-configs/ebsa110 index 417ad00ffff3..42529e789a41 100644 --- a/arch/arm/def-configs/ebsa110 +++ b/arch/arm/def-configs/ebsa110 @@ -10,7 +10,7 @@ CONFIG_UID16=y CONFIG_EXPERIMENTAL=y # -# System and processor type +# System and Processor Type # # CONFIG_ARCH_ARC is not set # CONFIG_ARCH_A5K is not set @@ -25,6 +25,8 @@ CONFIG_CPU_SA110=y # CONFIG_PCI is not set # CONFIG_ISA is not set # CONFIG_ISA_DMA is not set +# CONFIG_SBUS is not set +# CONFIG_PCMCIA is not set # # Loadable module support @@ -69,7 +71,6 @@ CONFIG_LEDS=y # I2O device support # # CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set # CONFIG_I2O_BLOCK is not set # CONFIG_I2O_LAN is not set # CONFIG_I2O_SCSI is not set @@ -87,13 +88,19 @@ CONFIG_LEDS=y # CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set # # Additional Block Devices # # CONFIG_BLK_DEV_LOOP is not set CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_RAID15_DANGEROUS is not set CONFIG_BLK_DEV_RAM=y # CONFIG_BLK_DEV_INITRD is not set @@ -124,7 +131,7 @@ CONFIG_PRINTER=m # Mice # # CONFIG_BUSMOUSE is not set -CONFIG_MOUSE=y +# CONFIG_MOUSE is not set # CONFIG_PSMOUSE is not set # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set @@ -141,6 +148,7 @@ CONFIG_MOUSE=y CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set # CONFIG_WDT is not set +# CONFIG_WDTPCI is not set CONFIG_SOFT_WATCHDOG=y # CONFIG_PCWATCHDOG is not set # CONFIG_ACQUIRE_WDT is not set @@ -173,6 +181,7 @@ CONFIG_NETLINK=y CONFIG_RTNETLINK=y # CONFIG_NETLINK_DEV is not set CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -222,6 +231,7 @@ CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y # CONFIG_IP_NF_TARGET_MIRROR is not set CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=y CONFIG_IP_NF_TARGET_REDIRECT=y CONFIG_IP_NF_MANGLE=y @@ -302,10 +312,12 @@ CONFIG_ARM_AM79C961A=y # CONFIG_HIPPI is not set # CONFIG_PLIP is not set CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set CONFIG_PPP_ASYNC=y # CONFIG_PPP_SYNC_TTY is not set CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m # CONFIG_SLIP is not set # @@ -342,9 +354,10 @@ CONFIG_PPP_BSDCOMP=m # File systems # # CONFIG_QUOTA is not set -CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS_FS is not set CONFIG_AUTOFS4_FS=y # CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set @@ -354,10 +367,12 @@ CONFIG_AUTOFS4_FS=y # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set -CONFIG_MINIX_FS=y +# CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set @@ -365,23 +380,39 @@ CONFIG_PROC_FS=y # CONFIG_DEVFS_DEBUG is not set # CONFIG_DEVPTS_FS is not set # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set # CONFIG_EXT2_FS is not set # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types diff --git a/arch/arm/def-configs/footbridge b/arch/arm/def-configs/footbridge index acfd9de1758a..ffe655f5db29 100644 --- a/arch/arm/def-configs/footbridge +++ b/arch/arm/def-configs/footbridge @@ -10,7 +10,7 @@ CONFIG_UID16=y CONFIG_EXPERIMENTAL=y # -# System and processor type +# System and Processor Type # # CONFIG_ARCH_ARC is not set # CONFIG_ARCH_A5K is not set @@ -19,6 +19,10 @@ CONFIG_EXPERIMENTAL=y CONFIG_FOOTBRIDGE=y CONFIG_HOST_FOOTBRIDGE=y # CONFIG_ADDIN_FOOTBRIDGE is not set + +# +# Footbridge Implementations +# CONFIG_ARCH_EBSA285=y # CONFIG_ARCH_CATS is not set CONFIG_ARCH_NETWINDER=y @@ -30,7 +34,10 @@ CONFIG_CPU_32v4=y CONFIG_CPU_SA110=y CONFIG_PCI=y CONFIG_PCI_NAMES=y +CONFIG_ISA=y CONFIG_ISA_DMA=y +# CONFIG_SBUS is not set +# CONFIG_PCMCIA is not set CONFIG_ALIGNMENT_TRAP=y # @@ -137,7 +144,11 @@ CONFIG_PARIDE_ON26=m # CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_RAID15_DANGEROUS is not set CONFIG_BLK_DEV_RAM=y # CONFIG_BLK_DEV_INITRD is not set @@ -202,6 +213,7 @@ CONFIG_PSMOUSE=y CONFIG_WATCHDOG=y # CONFIG_WATCHDOG_NOWAYOUT is not set # CONFIG_WDT is not set +# CONFIG_WDTPCI is not set CONFIG_SOFT_WATCHDOG=y # CONFIG_PCWATCHDOG is not set # CONFIG_ACQUIRE_WDT is not set @@ -242,6 +254,7 @@ CONFIG_VIDEO_DEV=y # CONFIG_VIDEO_PMS is not set # CONFIG_VIDEO_BWQCAM is not set # CONFIG_VIDEO_CQCAM is not set +# CONFIG_VIDEO_CPIA is not set # CONFIG_VIDEO_SAA5249 is not set # CONFIG_TUNER_3036 is not set # CONFIG_VIDEO_STRADIS is not set @@ -261,56 +274,6 @@ CONFIG_VIDEO_CYBERPRO=m # CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set -# -# USB support -# -CONFIG_USB=m - -# -# USB Controllers -# -# CONFIG_USB_UHCI is not set -# CONFIG_USB_UHCI_ALT is not set -CONFIG_USB_OHCI=m - -# -# Miscellaneous USB options -# -# CONFIG_USB_DEVICEFS is not set - -# -# USB Devices -# -CONFIG_USB_PRINTER=m -CONFIG_USB_SCANNER=m -CONFIG_USB_AUDIO=m -# CONFIG_USB_ACM is not set -# CONFIG_USB_SERIAL is not set -# CONFIG_USB_CPIA is not set -# CONFIG_USB_IBMCAM is not set -# CONFIG_USB_OV511 is not set -# CONFIG_USB_DC2XX is not set -# CONFIG_USB_STORAGE is not set -# CONFIG_USB_USS720 is not set -# CONFIG_USB_DABUSB is not set -# CONFIG_USB_PLUSB is not set -# CONFIG_USB_PEGASUS is not set -# CONFIG_USB_RIO500 is not set -# CONFIG_USB_DSBR is not set - -# -# USB HID -# -# CONFIG_USB_HID is not set -CONFIG_USB_KBD=m -CONFIG_USB_MOUSE=m -# CONFIG_USB_WACOM is not set -# CONFIG_USB_WMFORCE is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set - # # Console drivers # @@ -522,10 +485,12 @@ CONFIG_NE2K_PCI=y # CONFIG_HIPPI is not set # CONFIG_PLIP is not set CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set CONFIG_PPP_ASYNC=m # CONFIG_PPP_SYNC_TTY is not set CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m CONFIG_SLIP=m CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y @@ -588,9 +553,10 @@ CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC6210 is not set -# CONFIG_AEC6210_TUNING is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set # CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD7409 is not set # CONFIG_AMD7409_OVERRIDE is not set # CONFIG_BLK_DEV_CMD64X is not set @@ -610,6 +576,7 @@ CONFIG_BLK_DEV_PDC202XX=y # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_VIA82CXXX_TUNING is not set CONFIG_BLK_DEV_SL82C105=y # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y @@ -625,6 +592,7 @@ CONFIG_BLK_DEV_IDE_MODES=y # CONFIG_SOUND=m # CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set @@ -633,6 +601,7 @@ CONFIG_SOUND=m # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set CONFIG_SOUND_OSS=m # CONFIG_SOUND_TRACEINIT is not set # CONFIG_SOUND_DMAP is not set @@ -643,6 +612,7 @@ CONFIG_SOUND_ADLIB=m # CONFIG_SOUND_CS4232 is not set # CONFIG_SOUND_SSCAPE is not set # CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_ICH is not set # CONFIG_SOUND_VMIDI is not set # CONFIG_SOUND_TRIX is not set # CONFIG_SOUND_MSS is not set @@ -657,7 +627,6 @@ CONFIG_SOUND_SB=m # CONFIG_SOUND_AWE32_SYNTH is not set # CONFIG_SOUND_WAVEFRONT is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set # CONFIG_SOUND_OPL3SA1 is not set # CONFIG_SOUND_OPL3SA2 is not set @@ -670,8 +639,8 @@ CONFIG_SOUND_WAVEARTIST=m # File systems # # CONFIG_QUOTA is not set -CONFIG_AUTOFS_FS=y -# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=y CONFIG_ADFS_FS=m # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -683,10 +652,12 @@ CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set CONFIG_ISO9660_FS=m CONFIG_JOLIET=y # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set @@ -694,17 +665,22 @@ CONFIG_PROC_FS=y # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set CONFIG_ROOT_NFS=y CONFIG_NFSD=m # CONFIG_NFSD_V3 is not set @@ -712,6 +688,16 @@ CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types @@ -766,6 +752,57 @@ CONFIG_NLS_ISO8859_2=m CONFIG_NLS_ISO8859_15=m # CONFIG_NLS_KOI8_R is not set +# +# USB support +# +CONFIG_USB=m +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +CONFIG_USB_OHCI=m + +# +# USB Devices +# +CONFIG_USB_PRINTER=m +CONFIG_USB_SCANNER=m +CONFIG_USB_AUDIO=m +# CONFIG_USB_ACM is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_DABUSB is not set +# CONFIG_USB_PLUSB is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_DSBR is not set + +# +# USB HID +# +# CONFIG_USB_HID is not set +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +# CONFIG_USB_WACOM is not set +# CONFIG_USB_WMFORCE is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set + # # Kernel hacking # @@ -774,4 +811,5 @@ CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y -# CONFIG_DEBUG_LL is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set diff --git a/arch/arm/def-configs/rpc b/arch/arm/def-configs/rpc index a22e1d992585..d55bdf89f2b3 100644 --- a/arch/arm/def-configs/rpc +++ b/arch/arm/def-configs/rpc @@ -2,6 +2,7 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y +CONFIG_UID16=y # # Code maturity level options @@ -9,7 +10,7 @@ CONFIG_ARM=y CONFIG_EXPERIMENTAL=y # -# System and processor type +# System and Processor Type # # CONFIG_ARCH_ARC is not set # CONFIG_ARCH_A5K is not set @@ -23,7 +24,11 @@ CONFIG_CPU_32v3=y CONFIG_CPU_ARM6=y CONFIG_CPU_ARM7=y CONFIG_CPU_SA110=y +# CONFIG_PCI is not set +# CONFIG_ISA is not set # CONFIG_ISA_DMA is not set +# CONFIG_SBUS is not set +# CONFIG_PCMCIA is not set # CONFIG_ALIGNMENT_TRAP is not set # @@ -47,10 +52,14 @@ CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_ARTHUR is not set + +# +# Parallel port support +# CONFIG_PARPORT=y CONFIG_PARPORT_PC=y # CONFIG_PARPORT_PC_FIFO is not set -# CONFIG_PARPORT_PC_PCMCIA is not set +CONFIG_PARPORT_PC_SUPERIO=y # CONFIG_PARPORT_ARC is not set # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set @@ -63,7 +72,6 @@ CONFIG_PARPORT_PC=y # I2O device support # # CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set # CONFIG_I2O_BLOCK is not set # CONFIG_I2O_LAN is not set # CONFIG_I2O_SCSI is not set @@ -79,44 +87,23 @@ CONFIG_PARPORT_PC=y # Block devices # CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -CONFIG_IDEDISK_MULTI_MODE=y -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_BLK_DEV_CMD640 is not set -CONFIG_BLK_DEV_IDE_ICSIDE=y -CONFIG_BLK_DEV_IDEDMA_ICS=y -CONFIG_IDEDMA_ICS_AUTO=y -CONFIG_BLK_DEV_IDE_RAPIDE=y -CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_AUTO=y -# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set # # Additional Block Devices # CONFIG_BLK_DEV_LOOP=m # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_RAID15_DANGEROUS is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_HD is not set # # Acorn-specific block devices @@ -138,6 +125,17 @@ CONFIG_PRINTER=m # CONFIG_LP_CONSOLE is not set # CONFIG_PPDEV is not set +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=y + # # Mice # @@ -177,19 +175,9 @@ CONFIG_MOUSE=y # CONFIG_FTAPE is not set # CONFIG_DRM is not set # CONFIG_DRM_TDFX is not set - -# -# PCMCIA character device support -# -# CONFIG_PCMCIA_SERIAL_CS is not set # CONFIG_AGP is not set CONFIG_RPCMOUSE=y -# -# Support for USB -# -# CONFIG_USB is not set - # # Console drivers # @@ -201,10 +189,6 @@ CONFIG_FB=y CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y CONFIG_FB_ACORN=y -# CONFIG_FB_MATROX is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_3DFX is not set # CONFIG_FB_VIRTUAL is not set CONFIG_FBCON_ADVANCED=y CONFIG_FBCON_MFB=y @@ -222,6 +206,7 @@ CONFIG_FBCON_CFB32=y # CONFIG_FBCON_MAC is not set # CONFIG_FBCON_VGA_PLANES is not set # CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set # CONFIG_FBCON_FONTWIDTH8_ONLY is not set CONFIG_FBCON_FONTS=y # CONFIG_FONT_8x8 is not set @@ -298,6 +283,7 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_NET_SB1000 is not set @@ -312,12 +298,10 @@ CONFIG_ARM_ETHERH=y # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_EISA is not set +# CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set # @@ -330,10 +314,12 @@ CONFIG_ARM_ETHERH=y # CONFIG_HIPPI is not set # CONFIG_PLIP is not set CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set # CONFIG_PPP_ASYNC is not set # CONFIG_PPP_SYNC_TTY is not set # CONFIG_PPP_DEFLATE is not set # CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m # CONFIG_SLIP is not set # @@ -342,7 +328,7 @@ CONFIG_PPP=m # CONFIG_NET_RADIO is not set # -# Token Ring driver support +# Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -355,9 +341,42 @@ CONFIG_PPP=m # CONFIG_WAN is not set # -# PCMCIA network device support +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices # -# CONFIG_NET_PCMCIA is not set +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +CONFIG_BLK_DEV_IDE_ICSIDE=y +CONFIG_BLK_DEV_IDEDMA_ICS=y +CONFIG_IDEDMA_ICS_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDE_RAPIDE=y +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_IDE_MODES is not set # # SCSI support @@ -368,9 +387,11 @@ CONFIG_SCSI=y # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y -# CONFIG_CHR_DEV_ST is not set +CONFIG_SD_EXTRA_DEVS=8 +CONFIG_CHR_DEV_ST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y # @@ -390,12 +411,12 @@ CONFIG_SCSI_LOGGING=y # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_DTC3280 is not set # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_DMA is not set @@ -403,6 +424,8 @@ CONFIG_SCSI_LOGGING=y # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set CONFIG_SCSI_PPA=m CONFIG_SCSI_IMM=m # CONFIG_SCSI_IZIP_EPP16 is not set @@ -410,15 +433,14 @@ CONFIG_SCSI_IMM=m # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set # CONFIG_SCSI_DEBUG is not set CONFIG_SCSI_ACORNSCSI_3=m CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y @@ -439,6 +461,7 @@ CONFIG_SCSI_OAK1=m # CONFIG_SOUND=m # CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set @@ -447,12 +470,18 @@ CONFIG_SOUND=m # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set # CONFIG_SOUND_AD1816 is not set # CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set # CONFIG_SOUND_CS4232 is not set # CONFIG_SOUND_SSCAPE is not set # CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_ICH is not set # CONFIG_SOUND_VMIDI is not set # CONFIG_SOUND_TRIX is not set # CONFIG_SOUND_MSS is not set @@ -460,30 +489,29 @@ CONFIG_SOUND_OSS=m # CONFIG_SOUND_NM256 is not set # CONFIG_SOUND_MAD16 is not set # CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set # CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_SOFTOSS is not set +CONFIG_SOUND_SOFTOSS=m # CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set # CONFIG_SOUND_WAVEFRONT is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set # CONFIG_SOUND_OPL3SA1 is not set # CONFIG_SOUND_OPL3SA2 is not set # CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set CONFIG_SOUND_VIDC=m # CONFIG_SOUND_WAVEARTIST is not set # -# Additional low level sound drivers -# -# CONFIG_LOWLEVEL_SOUND is not set - -# -# Filesystems +# File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=m CONFIG_ADFS_FS=y +# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set @@ -492,35 +520,66 @@ CONFIG_ADFS_FS=y # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y CONFIG_JOLIET=y # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set # CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types # CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +CONFIG_ACORN_PARTITION_ICS=y +CONFIG_ACORN_PARTITION_ADFS=y +CONFIG_ACORN_PARTITION_POWERTEC=y +CONFIG_ACORN_PARTITION_RISCIX=y CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +# CONFIG_ATARI_PARTITION is not set CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y CONFIG_BSD_DISKLABEL=y @@ -528,13 +587,6 @@ CONFIG_SOLARIS_X86_PARTITION=y # CONFIG_UNIXWARE_DISKLABEL is not set CONFIG_SGI_PARTITION=y CONFIG_SUN_PARTITION=y -CONFIG_AMIGA_PARTITION=y -# CONFIG_ATARI_PARTITION is not set -CONFIG_ACORN_PARTITION=y -CONFIG_ACORN_PARTITION_ADFS=y -CONFIG_ACORN_PARTITION_ICS=y -CONFIG_ACORN_PARTITION_POWERTEC=y -CONFIG_ACORN_PARTITION_RISCIX=y CONFIG_NLS=y # @@ -569,6 +621,11 @@ CONFIG_NLS_ISO8859_9=m # CONFIG_NLS_ISO8859_15 is not set CONFIG_NLS_KOI8_R=m +# +# USB support +# +# CONFIG_USB is not set + # # Kernel hacking # diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index d8f14a756d30..a129ca2f63a3 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -34,7 +34,7 @@ obj- := export-objs := armksyms.o dma.o ecard.o hw-footbridge.o leds-$(MACHINE).o -obj-$(CONFIG_ARCH_ACORN) += dma.o ecard.o iic.o fiq.o time-acorn.o +obj-$(CONFIG_ARCH_ACORN) += dma.o ecard.o fiq.o time-acorn.o obj-$(CONFIG_DEBUG_LL) += debug-$(PROCESSOR).o obj-$(CONFIG_MODULES) += armksyms.o obj-$(CONFIG_LEDS) += leds-$(MACHINE).o diff --git a/arch/arm/kernel/iic.c b/arch/arm/kernel/iic.c deleted file mode 100644 index c9a672a321c4..000000000000 --- a/arch/arm/kernel/iic.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * linux/arch/arm/kernel/iic.c - * - * Copyright (C) 1995, 1996 Russell King - * - * IIC is used to get the current time from the CMOS rtc. - */ - -#include -#include - -#include -#include -#include -#include - -#define FORCE_ONES 0xdc - -/* - * if delay loop has been calibrated then us that, - * else use IOC timer 1. - */ -static void iic_delay(void) -{ - extern unsigned long loops_per_sec; - if (loops_per_sec != (1 << 12)) { - udelay(100); /* was 10 */ - return; - } else { - unsigned long flags; - save_flags_cli(flags); - - outb(254, IOC_T1LTCHL); - outb(255, IOC_T1LTCHH); - outb(0, IOC_T1GO); - outb(1<<6, IOC_IRQCLRA); /* clear T1 irq */ - outb(10, IOC_T1LTCHL); /* was 4 */ - outb(0, IOC_T1LTCHH); - outb(0, IOC_T1GO); - while ((inb(IOC_IRQSTATA) & (1<<6)) == 0); - restore_flags(flags); - } -} - -#define IIC_INIT() dat = (inb(IOC_CONTROL) | FORCE_ONES) & ~3 -#define IIC_SET_DAT outb(dat|=1, IOC_CONTROL); -#define IIC_CLR_DAT outb(dat&=~1, IOC_CONTROL); -#define IIC_SET_CLK outb(dat|=2, IOC_CONTROL); -#define IIC_CLR_CLK outb(dat&=~2, IOC_CONTROL); -#define IIC_DELAY iic_delay(); -#define IIC_READ_DATA() (inb(IOC_CONTROL) & 1) - -static inline void iic_set_lines(int clk, int dat) -{ - int old; - - old = inb(IOC_CONTROL) | FORCE_ONES; - - old &= ~3; - - if (clk) - old |= 2; - if (dat) - old |= 1; - - outb(old, IOC_CONTROL); - - iic_delay(); -} - -static inline unsigned int iic_read_data(void) -{ - return inb(IOC_CONTROL) & 1; -} - -/* - * C: ==~~_ - * D: =~~__ - */ -static inline void iic_start(void) -{ - unsigned int dat; - - IIC_INIT(); - - IIC_SET_DAT - IIC_DELAY - IIC_SET_CLK - IIC_DELAY - - IIC_CLR_DAT - IIC_DELAY - IIC_CLR_CLK - IIC_DELAY -} - -/* - * C: __~~ - * D: =__~ - */ -static inline void iic_stop(void) -{ - unsigned int dat; - - IIC_INIT(); - - IIC_CLR_DAT - IIC_DELAY - IIC_SET_CLK - IIC_DELAY - IIC_SET_DAT - IIC_DELAY -} - -/* - * C: __~_ - * D: =___ - */ -static inline void iic_acknowledge(void) -{ - unsigned int dat; - - IIC_INIT(); - - IIC_CLR_DAT - IIC_DELAY - IIC_SET_CLK - IIC_DELAY - IIC_CLR_CLK - IIC_DELAY -} - -/* - * C: __~_ - * D: =~H~ - */ -static inline int iic_is_acknowledged(void) -{ - unsigned int dat, ack_bit; - - IIC_INIT(); - - IIC_SET_DAT - IIC_DELAY - IIC_SET_CLK - IIC_DELAY - - ack_bit = IIC_READ_DATA(); - - IIC_CLR_CLK - IIC_DELAY - - return ack_bit == 0; -} - -/* - * C: _~__~__~__~__~__~__~__~_ - * D: =DDXDDXDDXDDXDDXDDXDDXDD - */ -static void iic_sendbyte(unsigned int b) -{ - unsigned int dat, i; - - IIC_INIT(); - - for (i = 0; i < 8; i++) { - if (b & 128) - IIC_SET_DAT - else - IIC_CLR_DAT - IIC_DELAY - - IIC_SET_CLK - IIC_DELAY - IIC_CLR_CLK - IIC_DELAY - - b <<= 1; - } -} - -/* - * C: __~_~_~_~_~_~_~_~_ - * D: =~HHHHHHHHHHHHHHHH - */ -static unsigned char iic_recvbyte(void) -{ - unsigned int dat, i, in; - - IIC_INIT(); - - IIC_SET_DAT - IIC_DELAY - - in = 0; - for (i = 0; i < 8; i++) { - IIC_SET_CLK - IIC_DELAY - - in = (in << 1) | IIC_READ_DATA(); - - IIC_CLR_CLK - IIC_DELAY - } - - return in; -} - -int iic_control (unsigned char addr, unsigned char loc, unsigned char *buf, int len) -{ - int i, err = -EIO; - - iic_start(); - iic_sendbyte(addr & 0xfe); - if (!iic_is_acknowledged()) - goto error; - - iic_sendbyte(loc); - if (!iic_is_acknowledged()) - goto error; - - if (addr & 1) { - iic_stop(); - iic_start(); - iic_sendbyte(addr|1); - if (!iic_is_acknowledged()) - goto error; - - for (i = 0; i < len - 1; i++) { - buf[i] = iic_recvbyte(); - iic_acknowledge(); - } - buf[i] = iic_recvbyte(); - } else { - for (i = 0; i < len; i++) { - iic_sendbyte(buf[i]); - - if (!iic_is_acknowledged()) - goto error; - } - } - - err = 0; -error: - iic_stop(); - - return err; -} diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 5f48f951abf3..e932164bf8b5 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -20,6 +20,7 @@ L_OBJS_rpc := io-acorn.o floppydma.o L_OBJS_clps7500 := io-acorn.o L_OBJS_ebsa110 := io-ebsa110.o L_OBJS_footbridge := io-footbridge.o +L_OBJS_l7200 := io-acorn.o L_OBJS_nexuspci := io-footbridge.o L_OBJS_sa1100 := io-footbridge.o L_OBJS_shark := io-shark.o diff --git a/arch/i386/defconfig b/arch/i386/defconfig index f618cac4bb7e..e00ac753a26c 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -111,7 +111,6 @@ CONFIG_BLK_DEV_FD=y # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set @@ -169,6 +168,13 @@ CONFIG_BLK_DEV_IDE=y # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c index 9d21c617e17e..2e220bc06ec7 100644 --- a/arch/i386/kernel/acpi.c +++ b/arch/i386/kernel/acpi.c @@ -824,7 +824,7 @@ const static struct {acpi_init_via}, }; -const static struct pci_device_id acpi_pci_tbl[] __devinitdata = +const static struct pci_device_id acpi_pci_tbl[] = { {0x8086, 0x7113, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_INTEL_PIIX4}, {0x1106, 0x3040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_586}, diff --git a/arch/i386/kernel/pci-i386.c b/arch/i386/kernel/pci-i386.c index afb90ab125ac..53349bd0a665 100644 --- a/arch/i386/kernel/pci-i386.c +++ b/arch/i386/kernel/pci-i386.c @@ -121,6 +121,19 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, } } +/* + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might have be mirrored at 0x0100-0x03ff.. + */ void pcibios_align_resource(void *data, struct resource *res, unsigned long size) { @@ -129,17 +142,16 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size) if (res->flags & IORESOURCE_IO) { unsigned long start = res->start; - /* We need to avoid collisions with `mirrored' VGA ports - and other strange ISA hardware, so we always want the - addresses kilobyte aligned. */ if (size > 0x100) { printk(KERN_ERR "PCI: I/O Region %s/%d too large" " (%ld bytes)\n", dev->slot_name, dev->resource - res, size); } - start = (start + 1024 - 1) & ~(1024 - 1); - res->start = start; + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } } } diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig index fc6376f142be..cef645c3b11a 100644 --- a/arch/mips64/defconfig +++ b/arch/mips64/defconfig @@ -76,7 +76,6 @@ CONFIG_PCI_NAMES=y # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22 index e9a442e43a1c..85e7ace0e656 100644 --- a/arch/mips64/defconfig-ip22 +++ b/arch/mips64/defconfig-ip22 @@ -67,7 +67,6 @@ CONFIG_BINFMT_ELF=y # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27 index fc6376f142be..cef645c3b11a 100644 --- a/arch/mips64/defconfig-ip27 +++ b/arch/mips64/defconfig-ip27 @@ -76,7 +76,6 @@ CONFIG_PCI_NAMES=y # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set diff --git a/arch/mips64/kernel/process.c b/arch/mips64/kernel/process.c index 22ce0ed6d07d..b8a0b32784f2 100644 --- a/arch/mips64/kernel/process.c +++ b/arch/mips64/kernel/process.c @@ -7,7 +7,6 @@ * Copyright (C) 1994 - 1999 by Ralf Baechle and others. * Copyright (C) 1999 Silicon Graphics, Inc. */ -#include #include #include #include diff --git a/arch/mips64/kernel/signal32.c b/arch/mips64/kernel/signal32.c index e33a69d5ef6a..2a8e95eb19d4 100644 --- a/arch/mips64/kernel/signal32.c +++ b/arch/mips64/kernel/signal32.c @@ -8,7 +8,6 @@ * Copyright (C) 1994 - 1999 Ralf Baechle * Copyright (C) 1999 Silicon Graphics, Inc. */ -#include #include #include #include diff --git a/arch/mips64/sgi-ip27/ip27-init.c b/arch/mips64/sgi-ip27/ip27-init.c index 9e2df36625ce..7e412cb1e483 100644 --- a/arch/mips64/sgi-ip27/ip27-init.c +++ b/arch/mips64/sgi-ip27/ip27-init.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/arch/mips64/sgi-ip27/ip27-irq.c b/arch/mips64/sgi-ip27/ip27-irq.c index 2c0ddcc69924..4ffd7f90a0d6 100644 --- a/arch/mips64/sgi-ip27/ip27-irq.c +++ b/arch/mips64/sgi-ip27/ip27-irq.c @@ -5,6 +5,7 @@ * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) * Copyright (C) 1999 Silicon Graphics, Inc. */ +#include #include #include diff --git a/arch/mips64/sgi-ip27/ip27-setup.c b/arch/mips64/sgi-ip27/ip27-setup.c index 89f58c13de6e..74381a5e8e60 100644 --- a/arch/mips64/sgi-ip27/ip27-setup.c +++ b/arch/mips64/sgi-ip27/ip27-setup.c @@ -24,7 +24,6 @@ #include #include #include -#include /* Check against user dumbness. */ #ifdef CONFIG_VT diff --git a/arch/mips64/sgi-ip27/ip27-timer.c b/arch/mips64/sgi-ip27/ip27-timer.c index d5a1ed0581a5..7f19f5e96fd4 100644 --- a/arch/mips64/sgi-ip27/ip27-timer.c +++ b/arch/mips64/sgi-ip27/ip27-timer.c @@ -3,6 +3,7 @@ * Copytight (C) 1999 Ralf Baechle (ralf@gnu.org) * Copytight (C) 1999 Silicon Graphics, Inc. */ +#include #include #include #include diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c index 82ed8f9ec01e..4a7c20df35af 100644 --- a/arch/ppc/8260_io/enet.c +++ b/arch/ppc/8260_io/enet.c @@ -689,8 +689,8 @@ int __init scc_enet_init(void) cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; cep->cur_rx = cep->rx_bd_base; - ep->sen_genscc.scc_rfcr = SCC_EB; - ep->sen_genscc.scc_tfcr = SCC_EB; + ep->sen_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; + ep->sen_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; /* Set maximum bytes per receive buffer. * This appears to be an Ethernet frame size, not the buffer diff --git a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c index 9e93bcdd5428..c039a452c0d7 100644 --- a/arch/ppc/8260_io/uart.c +++ b/arch/ppc/8260_io/uart.c @@ -2536,8 +2536,8 @@ int __init rs_8xx_init(void) /* Set up the uart parameters in the * parameter ram. */ - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; + up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB; + up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB; /* Set this to 1 for now, so we get single * character interrupts. Using idle charater @@ -2579,8 +2579,8 @@ int __init rs_8xx_init(void) /* Set up the uart parameters in the * parameter ram. */ - sup->scc_genscc.scc_rfcr = SMC_EB; - sup->scc_genscc.scc_tfcr = SMC_EB; + sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; + sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; /* Set this to 1 for now, so we get single * character interrupts. Using idle charater @@ -2741,8 +2741,8 @@ static int __init serial_console_setup(struct console *co, char *options) */ up->smc_rbase = dp_addr; /* Base of receive buffer desc. */ up->smc_tbase = dp_addr+sizeof(cbd_t); /* Base of xmt buffer desc. */ - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; + up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB; + up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB; /* Set this to 1 for now, so we get single character interrupts. */ diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig index caf15d27d93d..051e964023c2 100644 --- a/arch/ppc/configs/common_defconfig +++ b/arch/ppc/configs/common_defconfig @@ -15,10 +15,11 @@ CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set # CONFIG_PPC64 is not set -# CONFIG_82xx is not set +# CONFIG_8260 is not set # CONFIG_8xx is not set CONFIG_ALL_PPC=y # CONFIG_GEMINI is not set +# CONFIG_EST8260 is not set # CONFIG_APUS is not set # CONFIG_SMP is not set CONFIG_ALTIVEC=y @@ -159,10 +160,10 @@ CONFIG_BLK_DEV_IDESCSI=y # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDEPCI_SHARE_IRQ is not set -# CONFIG_BLK_DEV_IDEDMA_PCI is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_OFFBOARD is not set -# CONFIG_IDEDMA_PCI_AUTO is not set -# CONFIG_BLK_DEV_IDEDMA is not set +CONFIG_IDEDMA_PCI_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set @@ -376,6 +377,11 @@ CONFIG_PPP=y # # CONFIG_HAMRADIO is not set +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + # # ISDN subsystem # @@ -607,6 +613,7 @@ CONFIG_SOUND=y CONFIG_DMASOUND_AWACS=y CONFIG_DMASOUND=y # CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set @@ -688,3 +695,4 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y + diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index c93118bae966..a14aa41ab745 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -15,10 +15,11 @@ CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set # CONFIG_PPC64 is not set -# CONFIG_82xx is not set +# CONFIG_8260 is not set # CONFIG_8xx is not set CONFIG_ALL_PPC=y # CONFIG_GEMINI is not set +# CONFIG_EST8260 is not set # CONFIG_APUS is not set # CONFIG_SMP is not set CONFIG_ALTIVEC=y @@ -159,10 +160,10 @@ CONFIG_BLK_DEV_IDESCSI=y # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDEPCI_SHARE_IRQ is not set -# CONFIG_BLK_DEV_IDEDMA_PCI is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_OFFBOARD is not set -# CONFIG_IDEDMA_PCI_AUTO is not set -# CONFIG_BLK_DEV_IDEDMA is not set +CONFIG_IDEDMA_PCI_AUTO=y +CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set @@ -376,6 +377,11 @@ CONFIG_PPP=y # # CONFIG_HAMRADIO is not set +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + # # ISDN subsystem # @@ -608,6 +614,7 @@ CONFIG_SOUND=y CONFIG_DMASOUND_AWACS=y CONFIG_DMASOUND=y # CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c index a2fbe5f14f7b..e609906cb7b1 100644 --- a/arch/ppc/kernel/chrp_pci.c +++ b/arch/ppc/kernel/chrp_pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "pci.h" @@ -31,7 +32,7 @@ volatile struct Hydra *Hydra = NULL; * limit the bus number to 3 bits */ -int gg2_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, +int __chrp gg2_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { if (bus > 7) { @@ -42,7 +43,7 @@ int gg2_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int gg2_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, +int __chrp gg2_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val) { if (bus > 7) { @@ -54,7 +55,7 @@ int gg2_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, } -int gg2_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, +int __chrp gg2_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { if (bus > 7) { @@ -65,7 +66,7 @@ int gg2_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int gg2_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, +int __chrp gg2_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char val) { if (bus > 7) @@ -74,7 +75,7 @@ int gg2_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int gg2_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, +int __chrp gg2_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val) { if (bus > 7) @@ -83,7 +84,7 @@ int gg2_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, +int __chrp gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { if (bus > 7) @@ -98,7 +99,7 @@ int gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, | (((o) & ~3) << 24)) unsigned int python_busnr = 0; -int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, +int __chrp python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { if (bus > python_busnr) { @@ -110,7 +111,7 @@ int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, +int __chrp python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val) { if (bus > python_busnr) { @@ -123,7 +124,7 @@ int python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, } -int python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, +int __chrp python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { if (bus > python_busnr) { @@ -135,7 +136,7 @@ int python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, +int __chrp python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char val) { if (bus > python_busnr) @@ -145,7 +146,7 @@ int python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, +int __chrp python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val) { if (bus > python_busnr) @@ -156,7 +157,7 @@ int python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, +int __chrp python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { if (bus > python_busnr) @@ -167,7 +168,7 @@ int python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, } -int rtas_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, +int __chrp rtas_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16); @@ -176,7 +177,7 @@ int rtas_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int rtas_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, +int __chrp rtas_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val) { unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16); @@ -186,7 +187,7 @@ int rtas_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, } -int rtas_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, +int __chrp rtas_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16); @@ -195,7 +196,7 @@ int rtas_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int rtas_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, +int __chrp rtas_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char val) { unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16); @@ -204,7 +205,7 @@ int rtas_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int rtas_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, +int __chrp rtas_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val) { unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16); @@ -213,7 +214,7 @@ int rtas_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } -int rtas_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, +int __chrp rtas_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { unsigned long addr = (offset&0xff) | ((dev_fn&0xff)<<8) | ((bus & 0xff)<<16); diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index 3b541c26f3d2..d8c22e1a6130 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -49,6 +49,7 @@ #include #include #include +#include #include "time.h" #include "local_irq.h" @@ -112,7 +113,7 @@ static const char *gg2_cachemodes[4] = { "Disabled", "Write-Through", "Copy-Back", "Transparent Mode" }; -int +int __chrp chrp_get_cpuinfo(char *buffer) { int i, len, sdramen; @@ -306,7 +307,7 @@ chrp_setup_arch(void) } } -void +void __chrp chrp_event_scan(void) { unsigned char log[1024]; @@ -317,7 +318,7 @@ chrp_event_scan(void) ppc_md.heartbeat_count = ppc_md.heartbeat_reset; } -void +void __chrp chrp_restart(char *cmd) { printk("RTAS system-reboot returned %d\n", @@ -325,7 +326,7 @@ chrp_restart(char *cmd) for (;;); } -void +void __chrp chrp_power_off(void) { /* allow power on only with power button press */ @@ -334,13 +335,13 @@ chrp_power_off(void) for (;;); } -void +void __chrp chrp_halt(void) { chrp_power_off(); } -u_int +u_int __chrp chrp_irq_cannonicalize(u_int irq) { if (irq == 2) @@ -353,7 +354,7 @@ chrp_irq_cannonicalize(u_int irq) } } -int chrp_get_irq( struct pt_regs *regs ) +int __chrp chrp_get_irq( struct pt_regs *regs ) { int irq; @@ -383,7 +384,7 @@ int chrp_get_irq( struct pt_regs *regs ) return irq; } -void chrp_post_irq(struct pt_regs* regs, int irq) +void __chrp chrp_post_irq(struct pt_regs* regs, int irq) { /* * If it's an i8259 irq then we've already done the @@ -445,7 +446,7 @@ int chrp_ide_ports_known = 0; ide_ioreg_t chrp_ide_regbase[MAX_HWIFS]; ide_ioreg_t chrp_idedma_regbase; -void +void __chrp chrp_ide_probe(void) { struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL); @@ -460,19 +461,19 @@ chrp_ide_probe(void) } } -void +void __chrp chrp_ide_insw(ide_ioreg_t port, void *buf, int ns) { ide_insw(port+_IO_BASE, buf, ns); } -void +void __chrp chrp_ide_outsw(ide_ioreg_t port, void *buf, int ns) { ide_outsw(port+_IO_BASE, buf, ns); } -int +int __chrp chrp_ide_default_irq(ide_ioreg_t base) { if (chrp_ide_ports_known == 0) @@ -480,7 +481,7 @@ chrp_ide_default_irq(ide_ioreg_t base) return chrp_ide_irq; } -ide_ioreg_t +ide_ioreg_t __chrp chrp_ide_default_io_base(int index) { if (chrp_ide_ports_known == 0) @@ -488,13 +489,13 @@ chrp_ide_default_io_base(int index) return chrp_ide_regbase[index]; } -int +int __chrp chrp_ide_check_region(ide_ioreg_t from, unsigned int extent) { return check_region(from, extent); } -void +void __chrp chrp_ide_request_region(ide_ioreg_t from, unsigned int extent, const char *name) @@ -502,20 +503,20 @@ chrp_ide_request_region(ide_ioreg_t from, request_region(from, extent, name); } -void +void __chrp chrp_ide_release_region(ide_ioreg_t from, unsigned int extent) { release_region(from, extent); } -void +void __chrp chrp_ide_fix_driveid(struct hd_driveid *id) { ppc_generic_ide_fix_driveid(id); } -void +void __chrp chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { ide_ioreg_t reg = data_port; @@ -629,7 +630,7 @@ void __init if ( ppc_md.progress ) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0); } -void +void __chrp chrp_progress(char *s, unsigned short hex) { extern unsigned int rtas_data; diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c index c692b54d08b5..6d275e517b34 100644 --- a/arch/ppc/kernel/chrp_time.c +++ b/arch/ppc/kernel/chrp_time.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "time.h" static int nvram_as1 = NVRAM_AS1; @@ -45,7 +46,7 @@ void __init chrp_time_init(void) nvram_data = base + 1; } -int chrp_cmos_clock_read(int addr) +int __chrp chrp_cmos_clock_read(int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); @@ -53,7 +54,7 @@ int chrp_cmos_clock_read(int addr) return (inb(nvram_data)); } -void chrp_cmos_clock_write(unsigned long val, int addr) +void __chrp chrp_cmos_clock_write(unsigned long val, int addr) { if (nvram_as1 != 0) outb(addr>>8, nvram_as1); @@ -65,7 +66,7 @@ void chrp_cmos_clock_write(unsigned long val, int addr) /* * Set the hardware clock. -- Cort */ -int chrp_set_rtc_time(unsigned long nowtime) +int __chrp chrp_set_rtc_time(unsigned long nowtime) { unsigned char save_control, save_freq_select; struct rtc_time tm; @@ -111,7 +112,7 @@ int chrp_set_rtc_time(unsigned long nowtime) return 0; } -unsigned long chrp_get_rtc_time(void) +unsigned long __chrp chrp_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; int i; diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index cc647a58b618..ad467894f7aa 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -291,25 +291,9 @@ ret_from_intercept: * -- Cort */ cmpi 0,r3,0 - bne ret_from_except - /* - * If we're returning from user mode we do things differently - * -- Cort - */ - lwz r3,_MSR(r1) - andi. r3,r3,MSR_PR - beq+ 10f - b 8f - + beq restore .globl ret_from_except ret_from_except: -0: /* disable interrupts */ - lis r30,int_control@h - ori r30,r30,int_control@l - lwz r30,0(r30) - mtlr r30 - blrl - lwz r5,_MSR(r1) andi. r5,r5,MSR_EE beq 2f @@ -341,65 +325,58 @@ lost_irq_ret: bl do_softirq .globl do_bottom_half_ret do_bottom_half_ret: -2: /* disable interrupts */ - lis r30,int_control@h - ori r30,r30,int_control@l - lwz r30,0(r30) - mtlr r30 - blrl - lwz r3,_MSR(r1) /* Returning to user mode? */ +2: lwz r3,_MSR(r1) /* Returning to user mode? */ andi. r3,r3,MSR_PR - beq+ 10f /* if so, check need_resched and signals */ + beq+ restore /* if so, check need_resched and signals */ + .globl ret_to_user_hook +ret_to_user_hook: + nop lwz r3,NEED_RESCHED(r2) cmpi 0,r3,0 /* check need_resched flag */ beq+ 7f bl schedule - b 0b 7: lwz r5,SIGPENDING(r2) /* Check for pending unblocked signals */ cmpwi 0,r5,0 - beq+ 8f + beq+ restore li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD bl do_signal .globl do_signal_ret do_signal_ret: - b 0b -8: /* - * We need to hard disable here even if RTL is active since - * being interrupted after here trashes the SPRG2 - * -- Cort - */ - mfmsr r0 /* Get current interrupt state */ - rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ - mtmsr r0 /* Update machine state */ - - addi r4,r1,INT_FRAME_SIZE /* size of frame */ - stw r4,THREAD+KSP(r2) /* save kernel stack pointer */ - tophys(r3,r1) - mtspr SPRG2,r3 /* phys exception stack pointer */ - b 11f -10: /* make sure we hard disable here, even if rtl is active -- Cort */ - mfmsr r0 /* Get current interrupt state */ - rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ - sync /* Some chip revs have problems here... */ - mtmsr r0 /* Update machine state */ -11: - lwz r2,_CTR(r1) +restore: + lwz r3,_CTR(r1) lwz r0,_LINK(r1) - mtctr r2 + mtctr r3 mtlr r0 - lwz r2,_XER(r1) - lwz r0,_CCR(r1) - mtspr XER,r2 - mtcrf 0xFF,r0 + lwz r3,_XER(r1) + mtspr XER,r3 REST_10GPRS(3, r1) REST_10GPRS(13, r1) REST_8GPRS(23, r1) REST_GPR(31, r1) - lwz r2,_NIP(r1) /* Restore environment */ + + /* make sure we hard disable here, even if rtl is active, to protect + * SRR[01] and SPRG2 -- Cort + */ + mfmsr r0 /* Get current interrupt state */ + rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ + sync /* Some chip revs have problems here... */ + mtmsr r0 /* Update machine state */ + + /* if returning to user mode, set new sprg2 and save kernel SP */ lwz r0,_MSR(r1) - mtspr SRR0,r2 mtspr SRR1,r0 + andi. r0,r0,MSR_PR + beq+ 1f + addi r0,r1,INT_FRAME_SIZE /* size of frame */ + stw r0,THREAD+KSP(r2) /* save kernel stack pointer */ + tophys(r2,r1) + mtspr SPRG2,r2 /* phys exception stack pointer */ +1: + lwz r2,_CCR(r1) + mtcrf 0xFF,r2 + lwz r2,_NIP(r1) + mtspr SRR0,r2 lwz r0,GPR0(r1) lwz r2,GPR2(r1) lwz r1,GPR1(r1) diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 6700806bd159..f88c5383d269 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -1459,7 +1459,8 @@ start_here: /* * Set up the segment registers for a new context. */ -_GLOBAL(set_context) + .globl set_context +set_context: rlwinm r3,r3,4,8,27 /* VSID = context << 4 */ addis r3,r3,0x6000 /* Set Ks, Ku bits */ li r0,12 /* TASK_SIZE / SEGMENT_SIZE */ diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 9b7d2be31483..6d7f2aff7891 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -58,6 +58,7 @@ long long __ashrdi3(long long, int); long long __ashldi3(long long, int); long long __lshrdi3(long long, int); int abs(int); +extern unsigned long ret_to_user_hook; EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(do_signal); @@ -284,3 +285,5 @@ EXPORT_SYMBOL(debugger_sstep); EXPORT_SYMBOL(debugger_iabr_match); EXPORT_SYMBOL(debugger_dabr_match); EXPORT_SYMBOL(debugger_fault_handler); + +EXPORT_SYMBOL(ret_to_user_hook); diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c index fe0bfcea2a00..3ccc8f51869e 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/ppc/kernel/ptrace.c @@ -1,7 +1,7 @@ /* * linux/arch/ppc/kernel/ptrace.c * - * PowerPC version + * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * Derived from "arch/m68k/kernel/ptrace.c" @@ -9,14 +9,14 @@ * Taken from linux/kernel/ptrace.c and modified for M680x0. * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds * - * Modified by Cort Dougan (cort@cs.nmt.edu) + * Modified by Cort Dougan (cort@hq.fsmlabs.com) + * and Paul Mackerras (paulus@linuxcare.com.au). * * This file is subject to the terms and conditions of the GNU General * Public License. See the file README.legal in the main directory of * this archive for more details. */ -#include #include #include #include @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include @@ -44,7 +44,7 @@ /* * Get contents of register REGNO in task TASK. */ -static inline long get_reg(struct task_struct *task, int regno) +static inline unsigned long get_reg(struct task_struct *task, int regno) { if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)) return ((unsigned long *)task->thread.regs)[regno]; @@ -64,7 +64,7 @@ static inline int put_reg(struct task_struct *task, int regno, ((unsigned long *)task->thread.regs)[regno] = data; return 0; } - return -1; + return -EIO; } static inline void @@ -81,216 +81,10 @@ clear_single_step(struct task_struct *task) regs->msr &= ~MSR_SE; } -#if 0 -/* - * This routine gets a long from any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - * - */ -static unsigned long get_long(struct task_struct * tsk, - struct vm_area_struct * vma, unsigned long addr) -{ - pgd_t * pgdir; - pmd_t * pgmiddle; - pte_t * pgtable; - unsigned long page; - -repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (pgd_none(*pgdir)) { - handle_mm_fault(tsk->mm, vma, addr, 0); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace[1]: bad page directory %lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return 0; - } - pgmiddle = pmd_offset(pgdir,addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk->mm, vma, addr, 0); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace[3]: bad pmd %lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return 0; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk->mm, vma, addr, 0); - goto repeat; - } - page = pte_page(*pgtable); -/* this is a hack for non-kernel-mapped video buffers and similar */ - if (MAP_NR(page) >= max_mapnr) - return 0; - page += addr & ~PAGE_MASK; - return *(unsigned long *) page; -} - -/* - * This routine puts a long into any process space by following the page - * tables. NOTE! You should check that the long isn't on a page boundary, - * and that it is in the task area before calling this: this routine does - * no checking. - * - * Now keeps R/W state of page so that a text page stays readonly - * even if a debugger scribbles breakpoints into it. -M.U- - */ -static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, - unsigned long addr, unsigned long data) -{ - pgd_t *pgdir; - pmd_t *pgmiddle; - pte_t *pgtable; - unsigned long page; - -repeat: - pgdir = pgd_offset(vma->vm_mm, addr); - if (!pgd_present(*pgdir)) { - handle_mm_fault(tsk->mm, vma, addr, 1); - goto repeat; - } - if (pgd_bad(*pgdir)) { - printk("ptrace[2]: bad page directory %lx\n", pgd_val(*pgdir)); - pgd_clear(pgdir); - return; - } - pgmiddle = pmd_offset(pgdir,addr); - if (pmd_none(*pgmiddle)) { - handle_mm_fault(tsk->mm, vma, addr, 1); - goto repeat; - } - if (pmd_bad(*pgmiddle)) { - printk("ptrace[4]: bad pmd %lx\n", pmd_val(*pgmiddle)); - pmd_clear(pgmiddle); - return; - } - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) { - handle_mm_fault(tsk->mm, vma, addr, 1); - goto repeat; - } - page = pte_page(*pgtable); - if (!pte_write(*pgtable)) { - handle_mm_fault(tsk->mm, vma, addr, 1); - goto repeat; - } -/* this is a hack for non-kernel-mapped video buffers and similar */ - if (MAP_NR(page) < max_mapnr) { - unsigned long phys_addr = page + (addr & ~PAGE_MASK); - *(unsigned long *) phys_addr = data; - flush_icache_range(phys_addr, phys_addr+4); - } -/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ -/* this should also re-instate whatever read-only mode there was before */ - set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - flush_tlb_all(); -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls get_long() to read a long. - */ -static int read_long(struct task_struct * tsk, unsigned long addr, - unsigned long * result) -{ - struct vm_area_struct * vma = find_extend_vma(tsk->mm, addr); - - if (!vma) - return -EIO; - if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { - unsigned long low,high; - struct vm_area_struct * vma_low = vma; - - if (addr + sizeof(long) >= vma->vm_end) { - vma_low = vma->vm_next; - if (!vma_low || vma_low->vm_start != vma->vm_end) - return -EIO; - } - high = get_long(tsk, vma,addr & ~(sizeof(long)-1)); - low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1)); - switch (addr & (sizeof(long)-1)) { - case 3: - low >>= 8; - low |= high << 24; - break; - case 2: - low >>= 16; - low |= high << 16; - break; - case 1: - low >>= 24; - low |= high << 8; - break; - } - *result = low; - } else - *result = get_long(tsk, vma,addr); - return 0; -} - -/* - * This routine checks the page boundaries, and that the offset is - * within the task area. It then calls put_long() to write a long. - */ -static int write_long(struct task_struct * tsk, unsigned long addr, - unsigned long data) -{ - struct vm_area_struct * vma = find_extend_vma(tsk->mm, addr); - - if (!vma) - return -EIO; - if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { - unsigned long low,high; - struct vm_area_struct * vma_low = vma; - - if (addr + sizeof(long) >= vma->vm_end) { - vma_low = vma->vm_next; - if (!vma_low || vma_low->vm_start != vma->vm_end) - return -EIO; - } - high = get_long(tsk, vma,addr & ~(sizeof(long)-1)); - low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1)); - switch (addr & (sizeof(long)-1)) { - case 0: /* shouldn't happen, but safety first */ - high = data; - break; - case 3: - low &= 0x000000ff; - low |= data << 8; - high &= ~0xff; - high |= data >> 24; - break; - case 2: - low &= 0x0000ffff; - low |= data << 16; - high &= ~0xffff; - high |= data >> 16; - break; - case 1: - low &= 0x00ffffff; - low |= data << 24; - high &= ~0xffffff; - high |= data >> 8; - break; - } - put_long(tsk, vma,addr & ~(sizeof(long)-1),high); - put_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1),low); - } else - put_long(tsk, vma,addr,data); - return 0; -} -#endif - -asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; int ret = -EPERM; - unsigned long flags; lock_kernel(); if (request == PTRACE_TRACEME) { @@ -302,209 +96,209 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = 0; goto out; } - if (pid == 1) /* you may not mess with init */ - goto out; ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); - read_unlock(&tasklist_lock); /* FIXME!!! */ - if ( !child ) + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) goto out; + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out_tsk; + if (request == PTRACE_ATTACH) { if (child == current) - goto out; + goto out_tsk; if ((!child->dumpable || (current->uid != child->euid) || - (current->uid != child->uid) || (current->uid != child->suid) || + (current->uid != child->uid) || (current->gid != child->egid) || - (current->gid != child->gid) || (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted))) + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out; + goto out_tsk; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) - goto out; + goto out_tsk; child->flags |= PF_PTRACED; - - write_lock_irqsave(&tasklist_lock, flags); + + write_lock_irq(&tasklist_lock); if (child->p_pptr != current) { REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); } - write_unlock_irqrestore(&tasklist_lock, flags); + write_unlock_irq(&tasklist_lock); send_sig(SIGSTOP, child, 1); ret = 0; - goto out; + goto out_tsk; } ret = -ESRCH; if (!(child->flags & PF_PTRACED)) - goto out; + goto out_tsk; if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) - goto out; + goto out_tsk; } if (child->p_pptr != current) - goto out; + goto out_tsk; switch (request) { /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp,(unsigned long *) data); + break; + } - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - goto out; - ret = put_user(tmp,(unsigned long *) data); - goto out; - } /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long tmp; - - if ((addr & 3) || addr < 0 || addr > (PT_FPSCR << 2)) { - ret = -EIO; - goto out; - } - - ret = verify_area(VERIFY_WRITE, (void *) data, - sizeof(long)); - if (ret) - goto out; - tmp = 0; /* Default return condition */ - addr = addr >> 2; /* temporary hack. */ - if (addr < PT_FPR0) { - tmp = get_reg(child, addr); - } - else if (addr >= PT_FPR0 && addr <= PT_FPSCR) { - if (child->thread.regs->msr & MSR_FP) - giveup_fpu(child); - tmp = ((long *)child->thread.fpr)[addr - PT_FPR0]; - } - else - ret = -EIO; - if (!ret) - put_user(tmp,(unsigned long *) data); - goto out; + /* XXX this will need fixing for 64-bit */ + case PTRACE_PEEKUSR: { + unsigned long index, tmp; + + ret = -EIO; + /* convert to index and check */ + index = (unsigned long) addr >> 2; + if ((addr & 3) || index > PT_FPSCR) + break; + + if (addr < PT_FPR0) { + tmp = get_reg(child, (int) index); + } else { + if (child->thread.regs->msr & MSR_FP) + giveup_fpu(child); + tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; } + ret = put_user(tmp,(unsigned long *) data); + break; + } - /* If I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) - goto out; - ret = -EIO; - goto out; - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - ret = -EIO; - if ((addr & 3) || addr < 0 || addr >= ((PT_FPR0 + 64) << 2)) - goto out; + /* If I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + break; + ret = -EIO; + break; - addr = addr >> 2; /* temporary hack. */ - - if (addr == PT_ORIG_R3) - goto out; - if (addr < PT_FPR0) { - if (put_reg(child, addr, data)) - goto out; - ret = 0; - goto out; - } - if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) { - if (child->thread.regs->msr & MSR_FP) - giveup_fpu(child); - ((long *)child->thread.fpr)[addr - PT_FPR0] = data; - ret = 0; - goto out; - } - goto out; + /* write the word at location addr in the USER area */ + /* XXX this will need fixing for 64-bit */ + case PTRACE_POKEUSR: { + unsigned long index; - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ - ret = -EIO; - if ((unsigned long) data >= _NSIG) - goto out; - if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; - else - child->flags &= ~PF_TRACESYS; - child->exit_code = data; - wake_up_process(child); - /* make sure the single step bit is not set. */ - clear_single_step(child); + ret = -EIO; + /* convert to index and check */ + index = (unsigned long) addr >> 2; + if ((addr & 3) || index > PT_FPSCR) + break; + + if (addr == PT_ORIG_R3) + break; + if (addr < PT_FPR0) { + ret = put_reg(child, addr, data); + } else { + if (child->thread.regs->msr & MSR_FP) + giveup_fpu(child); + ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; ret = 0; - goto out; } + break; + } + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + child->flags |= PF_TRACESYS; + else + child->flags &= ~PF_TRACESYS; + child->exit_code = data; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + ret = 0; + break; + } /* * make the child exit. Best I can do is send it a sigkill. * perhaps it should be put in the status that it wants to * exit. */ - case PTRACE_KILL: { - ret = 0; - if (child->state == TASK_ZOMBIE) /* already dead */ - goto out; - wake_up_process(child); - child->exit_code = SIGKILL; - /* make sure the single step bit is not set. */ - clear_single_step(child); - goto out; - } + case PTRACE_KILL: { + ret = 0; + if (child->state == TASK_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + break; + } - case PTRACE_SINGLESTEP: { /* set the trap flag. */ - ret = -EIO; - if ((unsigned long) data >= _NSIG) - goto out; - child->flags &= ~PF_TRACESYS; - set_single_step(child); - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; - goto out; - } + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->flags &= ~PF_TRACESYS; + set_single_step(child); + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } - case PTRACE_DETACH: { /* detach a process that was attached. */ - ret = -EIO; - if ((unsigned long) data >= _NSIG) - goto out; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); - wake_up_process(child); - child->exit_code = data; - write_lock_irqsave(&tasklist_lock, flags); - REMOVE_LINKS(child); - child->p_pptr = child->p_opptr; - SET_LINKS(child); - write_unlock_irqrestore(&tasklist_lock, flags); - /* make sure the single step bit is not set. */ - clear_single_step(child); - ret = 0; - goto out; - } + case PTRACE_DETACH: { /* detach a process that was attached. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->exit_code = data; + write_lock_irq(&tasklist_lock); + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + write_unlock_irq(&tasklist_lock); + /* make sure the single step bit is not set. */ + clear_single_step(child); + wake_up_process(child); + ret = 0; + break; + } - default: - ret = -EIO; - goto out; + default: + ret = -EIO; + break; } +out_tsk: + free_task_struct(child); out: unlock_kernel(); return ret; } -asmlinkage void syscall_trace(void) +void syscall_trace(void) { if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) - goto out; + return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); @@ -518,5 +312,4 @@ asmlinkage void syscall_trace(void) send_sig(current->exit_code, current, 1); current->exit_code = 0; } -out: } diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 49a8da139370..67895b87dca8 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -776,8 +776,11 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id) id->word127 = __le16_to_cpu(id->word127); id->dlf = __le16_to_cpu(id->dlf); id->csfo = __le16_to_cpu(id->csfo); - for (i = 0; i < 30; i++) - id->words130_159[i] = __le16_to_cpu(id->words130_159[i]); + for (i = 0; i < 26; i++) + id->words130_155[i] = __le16_to_cpu(id->words130_155[i]); + id->word156 = __le16_to_cpu(id->word156); + for (i = 0; i < 4; i++) + id->words157_159[i] = __le16_to_cpu(id->words157_159[i]); for (i = 0; i < 96; i++) id->words160_255[i] = __le16_to_cpu(id->words160_255[i]); } diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index b821249d9600..3877d11dce29 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -41,10 +41,7 @@ #include #include #include -/* Fixme - Why is this here? - Corey */ -#ifdef CONFIG_8xx #include -#endif #include #include "time.h" @@ -62,6 +59,7 @@ time_t last_rtc_update = 0; unsigned decrementer_count; /* count value for 1e6/HZ microseconds */ unsigned count_period_num; /* 1 decrementer count equals */ unsigned count_period_den; /* count_period_num / count_period_den us */ +unsigned long last_tb; /* * timer_interrupt - gets called when the decrementer overflows, @@ -103,6 +101,8 @@ int timer_interrupt(struct pt_regs * regs) */ while ((d = get_dec()) == dval) ; + asm volatile("mftb %0" : "=r" (last_tb) ); + /* * Don't play catchup between the call to time_init() * and sti() in init/main.c. @@ -149,20 +149,21 @@ int timer_interrupt(struct pt_regs * regs) */ void do_gettimeofday(struct timeval *tv) { - unsigned long flags; + unsigned long flags, diff; save_flags(flags); cli(); *tv = xtime; /* XXX we don't seem to have the decrementers synced properly yet */ #ifndef CONFIG_SMP - tv->tv_usec += (decrementer_count - get_dec()) - * count_period_num / count_period_den; - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } + asm volatile("mftb %0" : "=r" (diff) ); + diff -= last_tb; + + tv->tv_usec += diff * count_period_num / count_period_den; + tv->tv_sec += tv->tv_usec / 1000000; + tv->tv_usec = tv->tv_usec % 1000000; #endif + restore_flags(flags); } @@ -334,6 +335,3 @@ void to_tm(int tim, struct rtc_time * tm) */ GregorianDay(tm); } - - - diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 28a5a5035e7d..0701f7118e34 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -91,7 +91,7 @@ MachineCheckException(struct pt_regs *regs) { #if defined(CONFIG_8xx) && defined(CONFIG_PCI) /* the qspan pci read routines can cause machine checks -- Cort */ - bad_page_fault(regs,regs->dar); + bad_page_fault(regs, regs->dar); return; #endif #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) @@ -214,8 +214,6 @@ AlignmentException(struct pt_regs *regs) { int fixed; - if (regs->msr & MSR_FP) - giveup_fpu(current); fixed = fix_alignment(regs); if (fixed == 1) { regs->nip += 4; /* skip over emulated instruction */ @@ -223,7 +221,10 @@ AlignmentException(struct pt_regs *regs) } if (fixed == -EFAULT) { /* fixed == -EFAULT means the operand address was bad */ - bad_page_fault(regs, regs->dar); + if (user_mode(regs)) + force_sig(SIGSEGV, current); + else + bad_page_fault(regs, regs->dar); return; } _exception(SIGBUS, regs); diff --git a/arch/ppc/mbxboot/Makefile b/arch/ppc/mbxboot/Makefile index 9dd5d64f36cd..53611aa582f4 100644 --- a/arch/ppc/mbxboot/Makefile +++ b/arch/ppc/mbxboot/Makefile @@ -28,14 +28,14 @@ ISZ = 0 TFTPIMAGE=/tftpboot/zImage.embedded ifdef CONFIG_8xx -ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00180000 -OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o +ZLINKFLAGS = -T vmlinux.lds -Ttext 0x00180000 +OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o gzimage.o rdimage.o CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx endif ifdef CONFIG_8260 -ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00400000 -OBJECTS := head_8260.o misc.o ../coffboot/zlib.o m8260_tty.o embed_config.o +ZLINKFLAGS = -T vmlinux.lds -Ttext 0x00400000 +OBJECTS := head_8260.o misc.o ../coffboot/zlib.o m8260_tty.o embed_config.o gzimage.o rdimage.o CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8260 endif @@ -61,21 +61,32 @@ endif all: zImage zvmlinux.initrd: zvmlinux - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp1 $(OBJECTS) +# +# Build the boot loader images +# + $(OBJCOPY) $(OBJCOPY_ARGS) -R .gzimage gzimage.o $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp1 zvmlinux.initrd1 - $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 initrd` \ - -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 initrd` \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd1 image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd1 image` \ - -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) + --add-section=.gzimage=../coffboot/vmlinux.gz \ + --set-section-flags=.gzimage=alloc,load,readonly,data \ + gzimage.o + $(OBJCOPY) $(OBJCOPY_ARGS) -R .rdimage rdimage.o $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ - --add-section=initrd=ramdisk.image.gz \ - --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.initrd.tmp $@ + --add-section=.rdimage=ramdisk.image.gz \ + --set-section-flags=.rdimage=alloc,load,readonly,data \ + rdimage.o + $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS) +# +# Compute the sizes/offsets for the final image, and rebuild with these values. +# + $(CC) $(CFLAGS) \ + -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd .rdimage` \ + -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd .rdimage` \ + -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd .gzimage` \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd .gzimage` \ + -c -o misc.o misc.c + $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment $@ + $(OBJDUMP) -h $@ zImage: zvmlinux ln -sf zvmlinux zImage @@ -85,23 +96,27 @@ zImage.initrd: zvmlinux.initrd zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz # -# build the boot loader image and then compute the offset into it -# for the kernel image +# Build the boot loader images # - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.tmp $@ # -# then with the offset rebuild the bootloader so we know where the kernel is + $(OBJCOPY) $(OBJCOPY_ARGS) -R .gzimage gzimage.o + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ + --add-section=.gzimage=../coffboot/vmlinux.gz \ + --set-section-flags=.gzimage=alloc,load,readonly,data \ + gzimage.o + $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS) +# +# Compute the sizes/offsets for the final image, and rebuild with these values. # - $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ - -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \ - -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \ + $(CC) $(CFLAGS) \ + -DINITRD_OFFSET=0 \ + -DINITRD_SIZE=0 \ + -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux .gzimage` \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux .gzimage` \ -c -o misc.o misc.c - $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) - $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ - zvmlinux.tmp $@ - rm zvmlinux.tmp + $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS) + $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment $@ + $(OBJDUMP) -h $@ znetboot : zImage cp zImage $(TFTPIMAGE) diff --git a/arch/ppc/mbxboot/embed_config.c b/arch/ppc/mbxboot/embed_config.c index 1d76be70c5a7..eca2cb764f59 100644 --- a/arch/ppc/mbxboot/embed_config.c +++ b/arch/ppc/mbxboot/embed_config.c @@ -3,7 +3,7 @@ * not have boot monitor support for board information. */ #include -#include +#include #ifdef CONFIG_8xx #include #endif @@ -236,12 +236,12 @@ embed_config(bd_t *bd) * here for those people that may load the kernel with * a JTAG/COP tool and not the rom monitor. */ - bd->bi_baudrate = 115200; - bd->bi_intfreq = 200; - bd->bi_busfreq = 66; - bd->bi_cpmfreq = 66; - bd->bi_brgfreq = 33; - bd->bi_memsize = 16 * 1024 * 1024; + bd->bi_baudrate = 19200; + bd->bi_intfreq = 165; + bd->bi_busfreq = 33; + bd->bi_cpmfreq = 132; + bd->bi_brgfreq = bd->bi_cpmfreq / 2; /* BRGCLK = (CPM*2/4) */ + bd->bi_memsize = 16 * 1024 * 1024; #endif cp = (u_char *)def_enet_addr; @@ -250,3 +250,4 @@ embed_config(bd_t *bd) } } #endif /* EST8260 */ + diff --git a/arch/ppc/mbxboot/gzimage.c b/arch/ppc/mbxboot/gzimage.c new file mode 100644 index 000000000000..11ce5be8ea4b --- /dev/null +++ b/arch/ppc/mbxboot/gzimage.c @@ -0,0 +1,8 @@ +/* + * gzimage.c + * + * Dummy file to allow a compressed zImage to be added + * into a linker section, accessed by the boot coode + */ + +char dummy_for_gzimage; diff --git a/arch/ppc/mbxboot/head_8260.S b/arch/ppc/mbxboot/head_8260.S index 79377a2ac667..0895ce025961 100644 --- a/arch/ppc/mbxboot/head_8260.S +++ b/arch/ppc/mbxboot/head_8260.S @@ -9,10 +9,17 @@ * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $ * * Boot loader philosophy: + * * ROM loads us to some arbitrary location - * Move the boot code to the link address (8M) + * ROM loads these registers: + * + * R3 = Pointer to the board configuration data + * R5 = Pointer to Open Firmware data + * + * ROM jumps to start/start_ + * Move the boot code to the link address (4 MB) * Call decompress_kernel() - * Relocate the initrd, zimage and residual data to 8M + * Relocate the initrd, zimage and residual data to 4 MB * Decompress the kernel to 0 * Jump to the kernel entry * -- Cort diff --git a/arch/ppc/mbxboot/misc.c b/arch/ppc/mbxboot/misc.c index 683f53491011..d5a44df1ef95 100644 --- a/arch/ppc/mbxboot/misc.c +++ b/arch/ppc/mbxboot/misc.c @@ -24,6 +24,15 @@ #include #endif +/* + * The following references are needed to cause the linker to pull in the + * gzimage.o and rdimage.o files. These object files are special, + * since they get placed into the .gzimage and .rdimage ELF sections + * of the zvmlinux and zvmlinux.initrd files. + */ +extern char dummy_for_gzimage; +extern char dummy_for_rdimage; + /* * Please send me load/board info and such data for hardware not * listed here so I can keep track since things are getting tricky diff --git a/arch/ppc/mbxboot/rdimage.c b/arch/ppc/mbxboot/rdimage.c new file mode 100644 index 000000000000..e40fd1e2e94a --- /dev/null +++ b/arch/ppc/mbxboot/rdimage.c @@ -0,0 +1,8 @@ +/* + * rdimage.c + * + * Dummy file to allow a compressed initrd to be added + * into a linker section, accessed by the boot coode + */ + +char dummy_for_rdimage; diff --git a/arch/ppc/mbxboot/vmlinux.lds b/arch/ppc/mbxboot/vmlinux.lds new file mode 100644 index 000000000000..2bf2c87b3486 --- /dev/null +++ b/arch/ppc/mbxboot/vmlinux.lds @@ -0,0 +1,152 @@ +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } +/* .init : { *(.init) } =0*/ + .plt : { *(.plt) } + .text : + { + *(.text) + *(.fixup) + *(.got1) + } + _etext = .; + PROVIDE (etext = .); + .rodata : + { + *(.rodata) + *(.rodata1) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.got.plt) *(.got) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + .fixup : { *(.fixup) } + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { + *(.data.init); + __vtop_table_begin = .; + *(.vtop_fixup); + __vtop_table_end = .; + __ptov_table_begin = .; + *(.ptov_fixup); + __ptov_table_end = .; + } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(4096); + __init_end = .; + + . = ALIGN(4096); + __pmac_begin = .; + .text.pmac : { *(.text.pmac) } + .data.pmac : { *(.data.pmac) } + . = ALIGN(4096); + __pmac_end = .; + + . = ALIGN(4096); + __prep_begin = .; + .text.prep : { *(.text.prep) } + .data.prep : { *(.data.prep) } + . = ALIGN(4096); + __prep_end = .; + + . = ALIGN(4096); + __apus_begin = .; + .text.apus : { *(.text.apus) } + .data.apus : { *(.data.apus) } + . = ALIGN(4096); + __apus_end = .; + + . = ALIGN(4096); + __apus_begin = .; + .text.apus : { *(.text.apus) } + .data.apus : { *(.data.apus) } + . = ALIGN(4096); + __apus_end = .; + + . = ALIGN(4096); + __openfirmware_begin = .; + .text.openfirmware : { *(.text.openfirmware) } + .data.openfirmware : { *(.data.openfirmware) } + . = ALIGN(4096); + __openfirmware_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + + /* + * For loader only: Put the zImage after everything else + */ + _gzstart = . ; + .gzimage : { *(.gzimage) } + _gzend = . ; + + /* + * For loader only: Put the initrd after zImage + */ + _rdstart = . ; + .rdimage : { *(.rdimage) } + _rdend = . ; + +} diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index 076ee56e57f1..7a899252faf1 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -62,10 +62,21 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, { struct vm_area_struct * vma; struct mm_struct *mm = current->mm; + siginfo_t info; + int code = SEGV_MAPERR; #if defined(CONFIG_4xx) int is_write = error_code & ESR_DST; #else int is_write = error_code & 0x02000000; + + /* + * Fortunately the bit assignments in SRR1 for an instruction + * fault and DSISR for a data fault are mostly the same for the + * bits we are interested in. But there are some bits which + * indicate errors in DSISR but can validly be set in SRR1. + */ + if (regs->trap == 0x400) + error_code &= 0x48200000; #endif /* CONFIG_4xx */ #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) @@ -82,16 +93,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, #endif /* !CONFIG_4xx */ #endif /* CONFIG_XMON || CONFIG_KGDB */ - if (in_interrupt()) { - static int complained; - if (complained < 20) { - ++complained; - printk("page fault in interrupt handler, addr=%lx\n", - address); - show_regs(regs); - } - } - if (current == NULL || mm == NULL) { + if (in_interrupt() || mm == NULL) { bad_page_fault(regs, address); return; } @@ -107,10 +109,12 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, goto bad_area; good_area: + code = SEGV_ACCERR; #if defined(CONFIG_6xx) if (error_code & 0x95700000) /* an error such as lwarx to I/O controller space, address matching DABR, eciwx, etc. */ + goto bad_area; #endif /* CONFIG_6xx */ #if defined(CONFIG_8xx) /* The MPC8xx seems to always set 0x80000000, which is @@ -119,9 +123,8 @@ good_area: */ if (error_code & 0x10000000) /* Guarded storage error. */ -#endif /* CONFIG_8xx */ goto bad_area; - +#endif /* CONFIG_8xx */ /* a write */ if (is_write) { @@ -135,8 +138,25 @@ good_area: if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - if (!handle_mm_fault(mm, vma, address, is_write)) - goto bad_area; + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + switch (handle_mm_fault(mm, vma, address, is_write)) { + case 1: + current->min_flt++; + break; + case 2: + current->maj_flt++; + break; + case 0: + goto do_sigbus; + default: + goto out_of_memory; + } + up(&mm->mmap_sem); /* * keep track of tlb+htab misses that are good addrs but @@ -147,22 +167,55 @@ good_area: return; bad_area: - up(&mm->mmap_sem); pte_errors++; + + /* User mode accesses cause a SIGSEGV */ + if (user_mode(regs)) { + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = code; + info.si_addr = (void *) address; + force_sig_info(SIGSEGV, &info, current); + return; + } + + bad_page_fault(regs, address); + return; + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + up(&mm->mmap_sem); + printk("VM: killing process %s\n", current->comm); + if (user_mode(regs)) + do_exit(SIGKILL); bad_page_fault(regs, address); + return; + +do_sigbus: + up(&mm->mmap_sem); + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *)address; + force_sig_info (SIGBUS, &info, current); + if (!user_mode(regs)) + bad_page_fault(regs, address); } +/* + * bad_page_fault is called when we have a bad access from the kernel. + * It is called from do_page_fault above and from some of the procedures + * in traps.c. + */ void bad_page_fault(struct pt_regs *regs, unsigned long address) { unsigned long fixup; - if (user_mode(regs)) { - force_sig(SIGSEGV, current); - return; - } - /* Are we prepared to handle this fault? */ if ((fixup = search_exception_table(regs->nip)) != 0) { regs->nip = fixup; diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 80fb7575e7ca..fc3acdd5c25d 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -83,6 +83,7 @@ extern char _start[], _end[]; extern char etext[], _stext[]; extern char __init_begin, __init_end; extern char __prep_begin, __prep_end; +extern char __chrp_begin, __chrp_end; extern char __pmac_begin, __pmac_end; extern char __apus_begin, __apus_end; extern char __openfirmware_begin, __openfirmware_end; @@ -777,7 +778,7 @@ void __init free_initmem(void) unsigned long a; unsigned long num_freed_pages = 0, num_prep_pages = 0, num_pmac_pages = 0, num_openfirmware_pages = 0, - num_apus_pages = 0; + num_apus_pages = 0, num_chrp_pages = 0; #define FREESEC(START,END,CNT) do { \ a = (unsigned long)(&START); \ for (; a < (unsigned long)(&END); a += PAGE_SIZE) { \ @@ -794,6 +795,7 @@ void __init free_initmem(void) case _MACH_Pmac: FREESEC(__apus_begin,__apus_end,num_apus_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); + FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); break; case _MACH_chrp: FREESEC(__apus_begin,__apus_end,num_apus_pages); @@ -803,20 +805,24 @@ void __init free_initmem(void) case _MACH_prep: FREESEC(__apus_begin,__apus_end,num_apus_pages); FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); + FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); break; case _MACH_mbx: FREESEC(__apus_begin,__apus_end,num_apus_pages); FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); + FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); break; case _MACH_apus: FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); + FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); break; case _MACH_gemini: FREESEC(__apus_begin,__apus_end,num_apus_pages); FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); + FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); break; } @@ -829,6 +835,8 @@ void __init free_initmem(void) if ( num_prep_pages ) printk(" %ldk prep", PGTOKB(num_prep_pages)); + if ( num_chrp_pages ) + printk(" %ldk chrp", PGTOKB(num_chrp_pages)); if ( num_pmac_pages ) printk(" %ldk pmac", PGTOKB(num_pmac_pages)); if ( num_openfirmware_pages ) diff --git a/arch/ppc/treeboot/mkevimg b/arch/ppc/treeboot/mkevimg index 76f849bb708b..68eb4dd3f4ee 100644 --- a/arch/ppc/treeboot/mkevimg +++ b/arch/ppc/treeboot/mkevimg @@ -1,4 +1,4 @@ -#!/usr/local/bin/perl +#!/usr/bin/perl # # Copyright (c) 1998-1999 TiVo, Inc. diff --git a/arch/ppc/treeboot/mkirimg b/arch/ppc/treeboot/mkirimg index e8aa24e3d1c7..17a6f23281b3 100644 --- a/arch/ppc/treeboot/mkirimg +++ b/arch/ppc/treeboot/mkirimg @@ -1,4 +1,4 @@ -#!/usr/local/bin/perl +#!/usr/bin/perl # # Copyright (c) 1998-1999 TiVo, Inc. # Original ELF parsing code. @@ -332,7 +332,7 @@ require 'elf.pl'; syswrite(OUTPUT, $ibuf, $initialOffset); if ($imageFound) { - $testN = pack ("I2", $bss_addr + $bss_size, $image_size); + $testN = pack ("N2", $bss_addr + $bss_size, $image_size); syswrite(OUTPUT, $testN, length($testN)); printf("Updated symbol \"imageSect_start\" to 0x%08x\n", $bss_addr + $bss_size); @@ -342,7 +342,7 @@ require 'elf.pl'; } if ($initrdFound) { - $testN = pack ("I2", $bss_addr + $bss_size + $image_size, $initrd_size); + $testN = pack ("N2", $bss_addr + $bss_size + $image_size, $initrd_size); syswrite(OUTPUT, $testN, length($testN)); printf("Updated symbol \"initrdSect_start\" to 0x%08x\n", $bss_addr + $bss_size + $image_size); diff --git a/arch/ppc/vmlinux.lds b/arch/ppc/vmlinux.lds index 707c4ad2febf..7bfdc4efbf8b 100644 --- a/arch/ppc/vmlinux.lds +++ b/arch/ppc/vmlinux.lds @@ -103,6 +103,13 @@ SECTIONS . = ALIGN(4096); __prep_end = .; + . = ALIGN(4096); + __chrp_begin = .; + .text.chrp : { *(.text.chrp) } + .data.chrp : { *(.data.chrp) } + . = ALIGN(4096); + __chrp_end = .; + . = ALIGN(4096); __apus_begin = .; .text.apus : { *(.text.apus) } @@ -135,4 +142,3 @@ SECTIONS _end = . ; PROVIDE (end = .); } - diff --git a/drivers/acorn/net/Makefile b/drivers/acorn/net/Makefile index 27811e92ff42..095a43cef8ef 100644 --- a/drivers/acorn/net/Makefile +++ b/drivers/acorn/net/Makefile @@ -3,7 +3,7 @@ # Makefile for the Acorn ethercard network device drivers # -L_TARGET := acorn-net.a +O_TARGET := acorn-net.o MOD_LIST_NAME := ACORN_NET_MODULES obj-y := @@ -11,11 +11,11 @@ obj-m := obj-n := obj- := -obj-$(CONFIG_ARM_ETHER1) += ether1.o -obj-$(CONFIG_ARM_ETHER3) += ether3.o obj-$(CONFIG_ARM_ETHERH) += etherh.o +obj-$(CONFIG_ARM_ETHER3) += ether3.o +obj-$(CONFIG_ARM_ETHER1) += ether1.o -L_OBJS := $(obj-y) +O_OBJS := $(obj-y) M_OBJS := $(obj-m) include $(TOPDIR)/Rules.make diff --git a/drivers/acorn/net/ether1.c b/drivers/acorn/net/ether1.c index 65673b7f4434..d2a5ca052ab5 100644 --- a/drivers/acorn/net/ether1.c +++ b/drivers/acorn/net/ether1.c @@ -29,6 +29,7 @@ * TDR time-distance. * 1.05 RMK 31/12/1997 Removed calls to dev_tint for 2.1 * 1.06 RMK 10/02/2000 Updated for 2.3.43 + * 1.07 RMK 13/05/2000 Updated for 2.3.99-pre8 */ #include @@ -74,7 +75,7 @@ static void ether1_setmulticastlist(struct net_device *dev); static void ether1_timeout(struct net_device *dev); /* ------------------------------------------------------------------------- */ -static char *version = "ether1 ethernet driver (c) 2000 Russell King v1.06\n"; +static char *version = "ether1 ethernet driver (c) 2000 Russell King v1.07\n"; #define BUS_16 16 #define BUS_8 8 @@ -620,95 +621,6 @@ ether1_init_for_open (struct net_device *dev) return failures ? 1 : 0; } -static int __init -ether1_probe1(struct net_device *dev) -{ - static unsigned int version_printed = 0; - struct ether1_priv *priv; - int i; - - if (!dev->priv) - dev->priv = kmalloc (sizeof (struct ether1_priv), GFP_KERNEL); - - if (!dev->priv) - return 1; - - priv = (struct ether1_priv *)dev->priv; - memset (priv, 0, sizeof (struct ether1_priv)); - - if ((priv->bus_type = ether1_reset (dev)) == 0) { - kfree (dev->priv); - return 1; - } - - if (net_debug && version_printed++ == 0) - printk (KERN_INFO "%s", version); - - request_region (dev->base_addr, 16, "ether1"); - request_region (dev->base_addr + 0x800, 4096, "ether1(ram)"); - - printk (KERN_INFO "%s: ether1 at %lx, IRQ%d, ether address ", - dev->name, dev->base_addr, dev->irq); - - for (i = 0; i < 6; i++) - printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]); - - if (ether1_init_2 (dev)) { - kfree (dev->priv); - return 1; - } - - dev->open = ether1_open; - dev->stop = ether1_close; - dev->hard_start_xmit = ether1_sendpacket; - dev->get_stats = ether1_getstats; - dev->set_multicast_list = ether1_setmulticastlist; - dev->tx_timeout = ether1_timeout; - dev->watchdog_timeo = 5 * HZ / 100; - - /* Fill in the fields of the device structure with ethernet values */ - ether_setup (dev); - - return 0; -} - -/* ------------------------------------------------------------------------- */ - -static void __init -ether1_addr(struct net_device *dev) -{ - int i; - - for (i = 0; i < 6; i++) - dev->dev_addr[i] = inb (IDPROM_ADDRESS + i); -} - -int __init -ether1_probe(struct net_device *dev) -{ -#ifndef MODULE - struct expansion_card *ec; - - if (!dev) - return ENODEV; - - ecard_startfind (); - if ((ec = ecard_find (0, ether1_cids)) == NULL) - return ENODEV; - - dev->base_addr = ecard_address (ec, ECARD_IOC, ECARD_FAST); - dev->irq = ec->irq; - - ecard_claim (ec); - -#endif - ether1_addr (dev); - - if (ether1_probe1 (dev) == 0) - return 0; - return ENODEV; -} - /* ------------------------------------------------------------------------- */ static int @@ -1087,66 +999,118 @@ ether1_setmulticastlist (struct net_device *dev) /* ------------------------------------------------------------------------- */ -#ifdef MODULE +static void __init ether1_banner(void) +{ + static unsigned int version_printed = 0; -static struct ether_dev { - struct expansion_card *ec; - char name[9]; - struct net_device dev; -} ether_devs[MAX_ECARDS]; + if (net_debug && version_printed++ == 0) + printk (KERN_INFO "%s", version); +} -int -init_module (void) +static struct net_device * __init ether1_init_one(struct expansion_card *ec) { - struct expansion_card *ec; - int i, ret = -ENODEV; - - memset(ether_devs, 0, sizeof(ether_devs)); + struct net_device *dev; + struct ether1_priv *priv; + int i; - ecard_startfind (); - ec = ecard_find(0, ether1_cids); - i = 0; + ether1_banner(); - while (ec && i < MAX_ECARDS) { - ecard_claim(ec); + ecard_claim(ec); + + dev = init_etherdev(NULL, sizeof(struct ether1_priv)); + if (!dev) + goto out; - ether_devs[i].ec = ec; - ether_devs[i].dev.irq = ec->irq; - ether_devs[i].dev.base_addr = ecard_address(ec, ECARD_IOC, ECARD_FAST); - ether_devs[i].dev.init = ether1_probe; - ether_devs[i].dev.name = ether_devs[i].name; + dev->base_addr = ecard_address(ec, ECARD_IOC, ECARD_FAST); + dev->irq = ec->irq; - ret = register_netdev(ðer_devs[i].dev); + /* + * these will not fail - the nature of the bus ensures this + */ + request_region(dev->base_addr, 16, dev->name); + request_region(dev->base_addr + 0x800, 4096, dev->name); - if (ret) { - ecard_release(ec); - ether_devs[i].ec = NULL; - break; - } + priv = (struct ether1_priv *)dev->priv; + if ((priv->bus_type = ether1_reset(dev)) == 0) + goto free_dev; - i += 1; - ec = ecard_find(0, ether1_cids); + printk(KERN_INFO "%s: ether1 at %lx, IRQ%d, ether address ", + dev->name, dev->base_addr, dev->irq); + + for (i = 0; i < 6; i++) { + dev->dev_addr[i] = inb(IDPROM_ADDRESS + i); + printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]); } - return i != 0 ? 0 : ret; + if (ether1_init_2(dev)) + goto free_dev; + + dev->open = ether1_open; + dev->stop = ether1_close; + dev->hard_start_xmit = ether1_sendpacket; + dev->get_stats = ether1_getstats; + dev->set_multicast_list = ether1_setmulticastlist; + dev->tx_timeout = ether1_timeout; + dev->watchdog_timeo = 5 * HZ / 100; + return 0; + +free_dev: + release_region(dev->base_addr, 16); + release_region(dev->base_addr + 0x800, 4096); + unregister_netdev(dev); + kfree(dev); +out: + ecard_release(ec); + return dev; } -void -cleanup_module (void) +static struct expansion_card *e_card[MAX_ECARDS]; +static struct net_device *e_dev[MAX_ECARDS]; + +static int __init ether1_init(void) { - int i; + int i, ret = -ENODEV; + + ecard_startfind(); for (i = 0; i < MAX_ECARDS; i++) { - if (ether_devs[i].ec) { - unregister_netdev(ðer_devs[i].dev); + struct expansion_card *ec; + struct net_device *dev; - release_region(ether_devs[i].dev.base_addr, 16); - release_region(ether_devs[i].dev.base_addr + 0x800, 4096); + ec = ecard_find(0, ether1_cids); + if (!ec) + break; - ecard_release(ether_devs[i].ec); + dev = ether1_init_one(ec); + if (!dev) + break; + + e_card[i] = ec; + e_dev[i] = dev; + ret = 0; + } + + return ret; +} - ether_devs[i].ec = NULL; +static void __exit ether1_exit(void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) { + if (e_dev[i]) { + unregister_netdev(e_dev[i]); + release_region(e_dev[i]->base_addr, 16); + release_region(e_dev[i]->base_addr + 0x800, 4096); + kfree(e_dev[i]); + e_dev[i] = NULL; + } + if (e_card[i]) { + ecard_release(e_card[i]); + e_card[i] = NULL; } } } -#endif /* MODULE */ + +module_init(ether1_init); +module_exit(ether1_exit); diff --git a/drivers/acorn/net/ether3.c b/drivers/acorn/net/ether3.c index 03cc064c4ef1..11e3824810c1 100644 --- a/drivers/acorn/net/ether3.c +++ b/drivers/acorn/net/ether3.c @@ -37,9 +37,10 @@ * 1.15 RMK 30/04/1999 More fixes to the transmit routine for buggy * hardware. * 1.16 RMK 10/02/2000 Updated for 2.3.43 + * 1.17 RMK 13/05/2000 Updated for 2.3.99-pre8 */ -static char *version = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.16\n"; +static char *version = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n"; #include #include @@ -78,7 +79,6 @@ static const card_ids __init ether3_cids[] = { static void ether3_setmulticastlist(struct net_device *dev); static int ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt); static void ether3_tx(struct net_device *dev, struct dev_priv *priv); -static int ether3_probe1 (struct net_device *dev); static int ether3_open (struct net_device *dev); static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev); static void ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs); @@ -406,132 +406,6 @@ ether3_probe_bus_16(struct net_device *dev, int val) return read_val == val; } -/* - * This is the real probe routine. - */ -static int __init -ether3_probe1(struct net_device *dev) -{ - static unsigned version_printed = 0; - struct dev_priv *priv; - unsigned int i, bus_type, error = ENODEV; - const char *name = "ether3"; - - if (net_debug && version_printed++ == 0) - printk(version); - - if (!dev->priv) { - dev->priv = kmalloc(sizeof (struct dev_priv), GFP_KERNEL); - if (!dev->priv) { - printk(KERN_ERR "ether3_probe1: no memory\n"); - return -ENOMEM; - } - } - - priv = (struct dev_priv *) dev->priv; - memset(priv, 0, sizeof(struct dev_priv)); - - request_region(dev->base_addr, 128, name); - - /* Reset card... - */ - ether3_outb(0x80, REG_CONFIG2 + 1); - bus_type = BUS_UNKNOWN; - udelay(4); - - /* Test using Receive Pointer (16-bit register) to find out - * how the ether3 is connected to the bus... - */ - if (ether3_probe_bus_8(dev, 0x100) && - ether3_probe_bus_8(dev, 0x201)) - bus_type = BUS_8; - - if (bus_type == BUS_UNKNOWN && - ether3_probe_bus_16(dev, 0x101) && - ether3_probe_bus_16(dev, 0x201)) - bus_type = BUS_16; - - switch (bus_type) { - case BUS_UNKNOWN: - printk(KERN_ERR "%s: unable to identify bus width\n", dev->name); - goto failed; - - case BUS_8: - printk(KERN_ERR "%s: %s found, but is an unsupported " - "8-bit card\n", dev->name, name); - goto failed; - - default: - break; - } - - printk("%s: %s at %lx, IRQ%d, ether address ", - dev->name, name, dev->base_addr, dev->irq); - for (i = 0; i < 6; i++) - printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]); - - if (ether3_init_2(dev)) - goto failed; - - dev->open = ether3_open; - dev->stop = ether3_close; - dev->hard_start_xmit = ether3_sendpacket; - dev->get_stats = ether3_getstats; - dev->set_multicast_list = ether3_setmulticastlist; - dev->tx_timeout = ether3_timeout; - dev->watchdog_timeo = 5 * HZ / 100; - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - - return 0; - -failed: - kfree(dev->priv); - dev->priv = NULL; - release_region(dev->base_addr, 128); - return error; -} - -static void __init -ether3_get_dev(struct net_device *dev, struct expansion_card *ec) -{ - ecard_claim(ec); - - dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); - dev->irq = ec->irq; - - if (ec->cid.manufacturer == MANU_ANT && - ec->cid.product == PROD_ANT_ETHERB) { - dev->base_addr += 0x200; - } - - ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr); - ec->irqmask = 0xf0; - - ether3_addr(dev->dev_addr, ec); -} - -#ifndef MODULE -int __init -ether3_probe(struct net_device *dev) -{ - struct expansion_card *ec; - - if (!dev) - return ENODEV; - - ecard_startfind(); - - if ((ec = ecard_find(0, ether3_cids)) == NULL) - return ENODEV; - - ether3_get_dev(dev, ec); - - return ether3_probe1(dev); -} -#endif - /* * Open/initialize the board. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. @@ -903,63 +777,163 @@ ether3_tx(struct net_device *dev, struct dev_priv *priv) } } -#ifdef MODULE +static void __init ether3_banner(void) +{ + static unsigned version_printed = 0; -static struct ether_dev { - struct expansion_card *ec; - char name[9]; - struct net_device dev; -} ether_devs[MAX_ECARDS]; + if (net_debug && version_printed++ == 0) + printk(version); +} -int -init_module(void) +static const char * __init +ether3_get_dev(struct net_device *dev, struct expansion_card *ec) { - struct expansion_card *ec; - int i, ret = -ENODEV; + const char *name = "ether3"; + dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); + dev->irq = ec->irq; + + if (ec->cid.manufacturer == MANU_ANT && + ec->cid.product == PROD_ANT_ETHERB) { + dev->base_addr += 0x200; + name = "etherb"; + } - memset(ether_devs, 0, sizeof(ether_devs)); + ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr); + ec->irqmask = 0xf0; - ecard_startfind (); - ec = ecard_find(0, ether3_cids); - i = 0; + ether3_addr(dev->dev_addr, ec); - while (ec && i < MAX_ECARDS) { - ecard_claim(ec); + return name; +} - ether_devs[i].ec = ec; - ether_devs[i].dev.init = ether3_probe1; - ether_devs[i].dev.name = ether_devs[i].name; - ether3_get_dev(ðer_devs[i].dev, ec); +static struct net_device * __init ether3_init_one(struct expansion_card *ec) +{ + struct net_device *dev; + struct dev_priv *priv; + const char *name; + int i, bus_type; - ret = register_netdev(ðer_devs[i].dev); + ether3_banner(); - if (ret) { - ecard_release(ec); - ether_devs[i].ec = NULL; - } else - i += 1; + ecard_claim(ec); - ec = ecard_find(0, ether3_cids); + dev = init_etherdev(NULL, sizeof(struct dev_priv)); + if (!dev) + goto out; + + name = ether3_get_dev(dev, ec); + + /* + * this will not fail - the nature of the bus ensures this + */ + request_region(dev->base_addr, 128, dev->name); + + priv = (struct dev_priv *) dev->priv; + + /* Reset card... + */ + ether3_outb(0x80, REG_CONFIG2 + 1); + bus_type = BUS_UNKNOWN; + udelay(4); + + /* Test using Receive Pointer (16-bit register) to find out + * how the ether3 is connected to the bus... + */ + if (ether3_probe_bus_8(dev, 0x100) && + ether3_probe_bus_8(dev, 0x201)) + bus_type = BUS_8; + + if (bus_type == BUS_UNKNOWN && + ether3_probe_bus_16(dev, 0x101) && + ether3_probe_bus_16(dev, 0x201)) + bus_type = BUS_16; + + switch (bus_type) { + case BUS_UNKNOWN: + printk(KERN_ERR "%s: unable to identify bus width\n", dev->name); + goto failed; + + case BUS_8: + printk(KERN_ERR "%s: %s found, but is an unsupported " + "8-bit card\n", dev->name, name); + goto failed; + + default: + break; } - return i != 0 ? 0 : ret; + printk("%s: %s at %lx, IRQ%d, ether address ", + dev->name, name, dev->base_addr, dev->irq); + for (i = 0; i < 6; i++) + printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]); + + if (ether3_init_2(dev)) + goto failed; + + dev->open = ether3_open; + dev->stop = ether3_close; + dev->hard_start_xmit = ether3_sendpacket; + dev->get_stats = ether3_getstats; + dev->set_multicast_list = ether3_setmulticastlist; + dev->tx_timeout = ether3_timeout; + dev->watchdog_timeo = 5 * HZ / 100; + return 0; + +failed: + release_region(dev->base_addr, 128); + unregister_netdev(dev); + kfree(dev); +out: + ecard_release(ec); + return NULL; } -void -cleanup_module(void) +static struct expansion_card *e_card[MAX_ECARDS]; +static struct net_device *e_dev[MAX_ECARDS]; + +static int ether3_init(void) { - int i; + int i, ret = -ENODEV; + + ecard_startfind(); for (i = 0; i < MAX_ECARDS; i++) { - if (ether_devs[i].ec) { - unregister_netdev(ðer_devs[i].dev); + struct net_device *dev; + struct expansion_card *ec; - release_region(ether_devs[i].dev.base_addr, 128); + ec = ecard_find(0, ether3_cids); + if (!ec) + break; - ecard_release(ether_devs[i].ec); + dev = ether3_init_one(ec); + if (!dev) + break; + + e_card[i] = ec; + e_dev[i] = dev; + ret = 0; + } + + return ret; +} - ether_devs[i].ec = NULL; +static void ether3_exit(void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) { + if (e_dev[i]) { + unregister_netdev(e_dev[i]); + release_region(e_dev[i]->base_addr, 128); + kfree(e_dev[i]); + e_dev[i] = NULL; + } + if (e_card[i]) { + ecard_release(e_card[i]); + e_card[i] = NULL; } } } -#endif /* MODULE */ + +module_init(ether3_init); +module_exit(ether3_exit); diff --git a/drivers/acorn/net/etherh.c b/drivers/acorn/net/etherh.c index 71dcbbdbca1d..96f51c68eba6 100644 --- a/drivers/acorn/net/etherh.c +++ b/drivers/acorn/net/etherh.c @@ -14,6 +14,7 @@ * 23-11-1997 RMK 1.04 Added media autodetection * 16-04-1998 RMK 1.05 Improved media autodetection * 10-02-2000 RMK 1.06 Updated for 2.3.43 + * 13-05-2000 RMK 1.07 Updated for 2.3.99-pre8 * * Insmod Module Parameters * ------------------------ @@ -62,7 +63,8 @@ static const card_ids __init etherh_cids[] = { MODULE_AUTHOR("Russell King"); MODULE_DESCRIPTION("i3 EtherH driver"); -static char *version = "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King v1.06\n"; +static char *version __initdata = + "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King v1.07\n"; #define ETHERH500_DATAPORT 0x200 /* MEMC */ #define ETHERH500_NS8390 0x000 /* MEMC */ @@ -81,34 +83,10 @@ static char *version = "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King /* --------------------------------------------------------------------------- */ -/* - * Read the ethernet address string from the on board rom. - * This is an ascii string... - */ -static int __init -etherh_addr(char *addr, struct expansion_card *ec) -{ - struct in_chunk_dir cd; - char *s; - - if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) { - int i; - for (i = 0; i < 6; i++) { - addr[i] = simple_strtoul(s + 1, &s, 0x10); - if (*s != (i == 5? ')' : ':')) - break; - } - if (i == 6) - return 0; - } - return ENODEV; -} - static void etherh_setif(struct net_device *dev) { - unsigned long addr; - unsigned long flags; + unsigned long addr, flags; save_flags_cli(flags); @@ -118,19 +96,27 @@ etherh_setif(struct net_device *dev) case PROD_I3_ETHERLAN600A: addr = dev->base_addr + EN0_RCNTHI; - if (ei_status.interface_num) /* 10b2 */ + switch (dev->if_port) { + case IF_PORT_10BASE2: outb((inb(addr) & 0xf8) | 1, addr); - else /* 10bT */ + break; + case IF_PORT_10BASET: outb((inb(addr) & 0xf8), addr); + break; + } break; case PROD_I3_ETHERLAN500: addr = dev->rmem_start; - if (ei_status.interface_num) /* 10b2 */ + switch (dev->if_port) { + case IF_PORT_10BASE2: outb(inb(addr) & ~ETHERH_CP_IF, addr); - else /* 10bT */ + break; + case IF_PORT_10BASET: outb(inb(addr) | ETHERH_CP_IF, addr); + break; + } break; default: @@ -143,22 +129,30 @@ etherh_setif(struct net_device *dev) static int etherh_getifstat(struct net_device *dev) { - int stat; + int stat = 0; switch (dev->mem_end) { case PROD_I3_ETHERLAN600: case PROD_I3_ETHERLAN600A: - if (ei_status.interface_num) /* 10b2 */ + switch (dev->if_port) { + case IF_PORT_10BASE2: stat = 1; - else /* 10bT */ + break; + case IF_PORT_10BASET: stat = inb(dev->base_addr+EN0_RCNTHI) & 4; + break; + } break; case PROD_I3_ETHERLAN500: - if (ei_status.interface_num) /* 10b2 */ + switch (dev->if_port) { + case IF_PORT_10BASE2: stat = 1; - else /* 10bT */ + break; + case IF_PORT_10BASET: stat = inb(dev->rmem_start) & ETHERH_CP_HEARTBEAT; + break; + } break; default: @@ -170,14 +164,54 @@ etherh_getifstat(struct net_device *dev) } /* - * Reset the 8390 (hard reset) + * Configure the interface. Note that we ignore the other + * parts of ifmap, since its mostly meaningless for this driver. + */ +static int etherh_set_config(struct net_device *dev, struct ifmap *map) +{ + switch (map->port) { + case IF_PORT_10BASE2: + case IF_PORT_10BASET: + /* + * If the user explicitly sets the interface + * media type, turn off automedia detection. + */ + dev->flags &= ~IFF_AUTOMEDIA; + dev->if_port = map->port; + break; + + default: + return -EINVAL; + } + + etherh_setif(dev); + + return 0; +} + +/* + * Reset the 8390 (hard reset). Note that we can't actually do this. */ static void etherh_reset(struct net_device *dev) { outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, dev->base_addr); - etherh_setif(dev); + /* + * See if we need to change the interface type. + * Note that we use 'interface_num' as a flag + * to indicate that we need to change the media. + */ + if (dev->flags & IFF_AUTOMEDIA && ei_status.interface_num) { + ei_status.interface_num = 0; + + if (dev->if_port == IF_PORT_10BASET) + dev->if_port = IF_PORT_10BASE2; + else + dev->if_port = IF_PORT_10BASET; + + etherh_setif(dev); + } } /* @@ -332,8 +366,31 @@ etherh_open(struct net_device *dev) return -EAGAIN; } + /* + * Make sure that we aren't going to change the + * media type on the next reset - we are about to + * do automedia manually now. + */ + ei_status.interface_num = 0; + + /* + * If we are doing automedia detection, do it now. + * This is more reliable than the 8390's detection. + */ + if (dev->flags & IFF_AUTOMEDIA) { + dev->if_port = IF_PORT_10BASET; + etherh_setif(dev); + mdelay(1); + if (!etherh_getifstat(dev)) { + dev->if_port = IF_PORT_10BASE2; + etherh_setif(dev); + } + } else + etherh_setif(dev); + etherh_reset(dev); ei_open(dev); + return 0; } @@ -350,281 +407,266 @@ etherh_close(struct net_device *dev) return 0; } +static void etherh_irq_enable(ecard_t *ec, int irqnr) +{ + unsigned int ctrl_addr = (unsigned int)ec->irq_data; + outb(inb(ctrl_addr) | ETHERH_CP_IE, ctrl_addr); +} + +static void etherh_irq_disable(ecard_t *ec, int irqnr) +{ + unsigned int ctrl_addr = (unsigned int)ec->irq_data; + outb(inb(ctrl_addr) & ~ETHERH_CP_IE, ctrl_addr); +} + +static expansioncard_ops_t etherh_ops = { + etherh_irq_enable, + etherh_irq_disable, + NULL, + NULL, + NULL, + NULL +}; + /* - * This is the real probe routine. + * Initialisation */ -static int __init -etherh_probe1(struct net_device *dev) + +static void __init etherh_banner(void) { static int version_printed; - unsigned int addr, i, reg0, tmp; - const char *dev_type; - const char *if_type; - const char *name = "etherh"; - - addr = dev->base_addr; if (net_debug && version_printed++ == 0) printk(version); +} - switch (dev->mem_end) { - case PROD_I3_ETHERLAN500: - dev_type = "500"; - break; - case PROD_I3_ETHERLAN600: - dev_type = "600"; - break; - case PROD_I3_ETHERLAN600A: - dev_type = "600A"; - break; - default: - dev_type = ""; - } +static int __init etherh_check_presence(struct net_device *dev) +{ + unsigned int addr = dev->base_addr, reg0, tmp; - reg0 = inb (addr); + reg0 = inb(addr); if (reg0 == 0xff) { if (net_debug & DEBUG_INIT) - printk("%s: %s error: NS8390 command register wrong\n", - dev->name, name); + printk("%s: etherh error: NS8390 command register wrong\n", + dev->name); return -ENODEV; } - outb (E8390_NODMA | E8390_PAGE1 | E8390_STOP, addr + E8390_CMD); - tmp = inb (addr + 13); - outb (0xff, addr + 13); - outb (E8390_NODMA | E8390_PAGE0, addr + E8390_CMD); - inb (addr + EN0_COUNTER0); - if (inb (addr + EN0_COUNTER0) != 0) { + outb(E8390_NODMA | E8390_PAGE1 | E8390_STOP, addr + E8390_CMD); + tmp = inb(addr + 13); + outb(0xff, addr + 13); + outb(E8390_NODMA | E8390_PAGE0, addr + E8390_CMD); + inb(addr + EN0_COUNTER0); + if (inb(addr + EN0_COUNTER0) != 0) { if (net_debug & DEBUG_INIT) - printk("%s: %s error: NS8390 not found\n", - dev->name, name); - outb (reg0, addr); - outb (tmp, addr + 13); + printk("%s: etherh error: NS8390 not found\n", + dev->name); + outb(reg0, addr); + outb(tmp, addr + 13); return -ENODEV; } - if (ethdev_init(dev)) - return -ENOMEM; - - request_region(addr, 16, name); - - printk("%s: %s %s at %lx, IRQ%d, ether address ", - dev->name, name, dev_type, dev->base_addr, dev->irq); - - for (i = 0; i < 6; i++) - printk (i == 5 ? "%2.2x " : "%2.2x:", dev->dev_addr[i]); - - ei_status.name = name; - ei_status.word16 = 1; - ei_status.tx_start_page = ETHERH_TX_START_PAGE; - ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES; - ei_status.stop_page = ETHERH_STOP_PAGE; - ei_status.reset_8390 = etherh_reset; - ei_status.block_input = etherh_block_input; - ei_status.block_output = etherh_block_output; - ei_status.get_8390_hdr = etherh_get_header; - dev->open = etherh_open; - dev->stop = etherh_close; - - /* select 10bT */ - ei_status.interface_num = 0; - if_type = "10BaseT"; - etherh_setif(dev); - mdelay(1); - if (!etherh_getifstat(dev)) { - if_type = "10Base2"; - ei_status.interface_num = 1; - etherh_setif(dev); - } - if (!etherh_getifstat(dev)) - if_type = "UNKNOWN"; - - printk("%s\n", if_type); - - etherh_reset(dev); - NS8390_init (dev, 0); return 0; } -static void etherh_irq_enable(ecard_t *ec, int irqnr) +/* + * Read the ethernet address string from the on board rom. + * This is an ascii string... + */ +static int __init etherh_addr(char *addr, struct expansion_card *ec) { - unsigned int ctrl_addr = (unsigned int)ec->irq_data; - outb(inb(ctrl_addr) | ETHERH_CP_IE, ctrl_addr); + struct in_chunk_dir cd; + char *s; + + if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) { + int i; + for (i = 0; i < 6; i++) { + addr[i] = simple_strtoul(s + 1, &s, 0x10); + if (*s != (i == 5? ')' : ':')) + break; + } + if (i == 6) + return 0; + } + return ENODEV; } -static void etherh_irq_disable(ecard_t *ec, int irqnr) +static struct net_device * __init etherh_init_one(struct expansion_card *ec) { - unsigned int ctrl_addr = (unsigned int)ec->irq_data; - outb(inb(ctrl_addr) & ~ETHERH_CP_IE, ctrl_addr); -} + struct net_device *dev; + const char *dev_type; + int i; -static expansioncard_ops_t etherh_ops = { - etherh_irq_enable, - etherh_irq_disable, - NULL, - NULL, - NULL, - NULL -}; + etherh_banner(); -static void __init -etherh_initdev(ecard_t *ec, struct net_device *dev) -{ - ecard_claim (ec); + ecard_claim(ec); - dev->irq = ec->irq; - dev->mem_end = ec->cid.product; + dev = init_etherdev(NULL, 0); + if (!dev) + goto out; + + etherh_addr(dev->dev_addr, ec); + + dev->open = etherh_open; + dev->stop = etherh_close; + dev->set_config = etherh_set_config; + dev->irq = ec->irq; + dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); + dev->mem_end = ec->cid.product; + ec->ops = ðerh_ops; switch (ec->cid.product) { case PROD_I3_ETHERLAN500: - dev->base_addr = ecard_address (ec, ECARD_MEMC, 0) + ETHERH500_NS8390; - dev->mem_start = dev->base_addr + ETHERH500_DATAPORT; + dev->base_addr += ETHERH500_NS8390; + dev->mem_start = dev->base_addr + ETHERH500_DATAPORT; dev->rmem_start = (unsigned long) - ec->irq_data = (void *)ecard_address (ec, ECARD_IOC, ECARD_FAST) + ec->irq_data = (void *)ecard_address (ec, ECARD_IOC, ECARD_FAST) + ETHERH500_CTRLPORT; break; case PROD_I3_ETHERLAN600: case PROD_I3_ETHERLAN600A: - dev->base_addr = ecard_address (ec, ECARD_MEMC, 0) + ETHERH600_NS8390; + dev->base_addr += ETHERH600_NS8390; dev->mem_start = dev->base_addr + ETHERH600_DATAPORT; - ec->irq_data = (void *)(dev->base_addr + ETHERH600_CTRLPORT); + ec->irq_data = (void *)(dev->base_addr + ETHERH600_CTRLPORT); break; default: - printk ("%s: etherh error: unknown card type\n", dev->name); + printk("%s: etherh error: unknown card type %x\n", + dev->name, ec->cid.product); + goto out; } - ec->ops = ðerh_ops; - etherh_addr(dev->dev_addr, ec); -} + if (!request_region(dev->base_addr, 16, dev->name)) + goto region_not_free; -#ifndef MODULE -int __init -etherh_probe(struct net_device *dev) -{ - if (!dev) - return ENODEV; + if (etherh_check_presence(dev) || ethdev_init(dev)) + goto release; - if (!dev->base_addr || dev->base_addr == 0xffe0) { - struct expansion_card *ec; + switch (ec->cid.product) { + case PROD_I3_ETHERLAN500: + dev_type = "500"; + break; - ecard_startfind(); + case PROD_I3_ETHERLAN600: + dev_type = "600"; + break; - if ((ec = ecard_find (0, etherh_cids)) == NULL) - return ENODEV; + case PROD_I3_ETHERLAN600A: + dev_type = "600A"; + break; - etherh_initdev(ec, dev); + default: + dev_type = "unknown"; + break; } - return etherh_probe1(dev); -} -#endif -#ifdef MODULE -#define MAX_ETHERH_CARDS 2 + printk("%s: etherh %s at %lx, IRQ%d, ether address ", + dev->name, dev_type, dev->base_addr, dev->irq); -static int io[MAX_ETHERH_CARDS]; -static int irq[MAX_ETHERH_CARDS]; -static char ethernames[MAX_ETHERH_CARDS][9]; -static struct net_device *my_ethers[MAX_ETHERH_CARDS]; -static struct expansion_card *ec[MAX_ETHERH_CARDS]; + for (i = 0; i < 6; i++) + printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]); -static int -init_all_cards(void) -{ - struct net_device *dev = NULL; - int i, found = 0; + /* + * Unfortunately, ethdev_init eventually calls + * ether_setup, which re-writes dev->flags. + */ + switch (ec->cid.product) { + case PROD_I3_ETHERLAN500: + dev->if_port = IF_PORT_UNKNOWN; + break; - for (i = 0; i < MAX_ETHERH_CARDS; i++) { - my_ethers[i] = NULL; - ec[i] = NULL; - strcpy (ethernames[i], " "); + case PROD_I3_ETHERLAN600: + case PROD_I3_ETHERLAN600A: + dev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA; + dev->if_port = IF_PORT_10BASET; + break; } - ecard_startfind(); - - for (i = 0; i < MAX_ETHERH_CARDS; i++) { - if (!dev) - dev = (struct net_device *)kmalloc (sizeof (struct net_device), GFP_KERNEL); - if (dev) - memset (dev, 0, sizeof (struct net_device)); - - if (!io[i]) { - if ((ec[i] = ecard_find (0, etherh_cids)) == NULL) - continue; - - if (!dev) - return -ENOMEM; - - etherh_initdev (ec[i], dev); - } else { - ec[i] = NULL; - if (!dev) - return -ENOMEM; - dev->base_addr = io[i]; - dev->irq = irq[i]; - } - - dev->init = etherh_probe1; - dev->name = ethernames[i]; + ei_status.name = dev->name; + ei_status.word16 = 1; + ei_status.tx_start_page = ETHERH_TX_START_PAGE; + ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES; + ei_status.stop_page = ETHERH_STOP_PAGE; - my_ethers[i] = dev; + ei_status.reset_8390 = etherh_reset; + ei_status.block_input = etherh_block_input; + ei_status.block_output = etherh_block_output; + ei_status.get_8390_hdr = etherh_get_header; + ei_status.interface_num = 0; - if (register_netdev(dev) != 0) { - printk(KERN_ERR "No etherh card found at %08lX\n", - dev->base_addr); - if (ec[i]) { - ecard_release(ec[i]); - ec[i] = NULL; - } - continue; - } - found ++; - dev = NULL; - } + etherh_reset(dev); + NS8390_init(dev, 0); + return dev; + +release: + release_region(dev->base_addr, 16); +region_not_free: + unregister_netdev(dev); + kfree(dev); +out: + ecard_release(ec); + return NULL; +} - if (dev) - kfree (dev); +#define MAX_ETHERH_CARDS 2 - return found ? 0 : -ENODEV; -} +static struct net_device *e_dev[MAX_ETHERH_CARDS]; +static struct expansion_card *e_card[MAX_ETHERH_CARDS]; -int -init_module(void) +static int __init etherh_init(void) { - int ret; + int i, ret = -ENODEV; - if (load_8390_module(__FILE__)) + if (load_8390_module("etherh.c")) return -ENOSYS; lock_8390_module(); - ret = init_all_cards(); + ecard_startfind(); - if (ret) { - unlock_8390_module(); + for (i = 0; i < MAX_ECARDS; i++) { + struct expansion_card *ec; + struct net_device *dev; + + ec = ecard_find(0, etherh_cids); + if (!ec) + break; + + dev = etherh_init_one(ec); + if (!dev) + break; + + e_card[i] = ec; + e_dev[i] = dev; + ret = 0; } + if (ret) + unlock_8390_module(); + return ret; } -void -cleanup_module(void) +static void __exit etherh_exit(void) { int i; + for (i = 0; i < MAX_ETHERH_CARDS; i++) { - if (my_ethers[i]) { - unregister_netdev(my_ethers[i]); - release_region (my_ethers[i]->base_addr, 16); - kfree (my_ethers[i]); - my_ethers[i] = NULL; + if (e_dev[i]) { + unregister_netdev(e_dev[i]); + release_region(e_dev[i]->base_addr, 16); + kfree(e_dev[i]); + e_dev[i] = NULL; } - if (ec[i]) { - ec[i]->ops = NULL; - ecard_release(ec[i]); - ec[i] = NULL; + if (e_card[i]) { + e_card[i]->ops = NULL; + ecard_release(e_card[i]); + e_card[i] = NULL; } } unlock_8390_module(); } -#endif /* MODULE */ + +module_init(etherh_init); +module_exit(etherh_exit); diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 679545b7c716..37f0669d6dbe 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -49,10 +49,12 @@ fi bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD -bool ' DANGEROUS! RAID1/RAID5 code' CONFIG_RAID15_DANGEROUS -if [ "$CONFIG_RAID15_DANGEROUS" = "y" ]; then - dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD - dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' RAID-1/RAID-5 code (DANGEROUS)' CONFIG_RAID15_DANGEROUS + if [ "$CONFIG_RAID15_DANGEROUS" = "y" ]; then + dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD + dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD + fi fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 8254d0a7aa8c..64c70e33a5d8 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -1,5 +1,5 @@ /* - * linux/kernel/floppy.c + * linux/drivers/block/floppy.c * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1993, 1994 Alain Knaff @@ -96,6 +96,12 @@ * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent * features to asm/floppy.h. */ + +/* + * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of + * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting & + * use of '0' for NULL. + */ /* * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation @@ -123,19 +129,6 @@ /* do print messages for unexpected interrupts */ static int print_unex=1; #include - -/* the following is the mask of allowed drives. By default units 2 and - * 3 of both floppy controllers are disabled, because switching on the - * motor of these drives causes system hangs on some PCI computers. drive - * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if - * a drive is allowed. */ - -static int FLOPPY_IRQ=6; -static int FLOPPY_DMA=2; -static int allowed_drive_mask = 0x33; -static int irqdma_allocated = 0; - - #include #include #include @@ -177,6 +170,8 @@ static int slow_floppy = 0; #include #include +static int FLOPPY_IRQ=6; +static int FLOPPY_DMA=2; static int can_use_virtual_dma=2; /* ======= * can use virtual DMA: @@ -186,7 +181,7 @@ static int can_use_virtual_dma=2; * but fall back on virtual DMA when not enough memory available */ -static int use_virtual_dma=0; +static int use_virtual_dma; /* ======= * use virtual DMA * 0 using hard DMA @@ -207,6 +202,14 @@ static devfs_handle_t devfs_handle = NULL; #define K_64 0x10000 /* 64KB */ #include +/* the following is the mask of allowed drives. By default units 2 and + * 3 of both floppy controllers are disabled, because switching on the + * motor of these drives causes system hangs on some PCI computers. drive + * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if + * a drive is allowed. */ + +static int allowed_drive_mask = 0x33; +static int irqdma_allocated = 0; #define MAJOR_NR FLOPPY_MAJOR @@ -231,9 +234,9 @@ static devfs_handle_t devfs_handle = NULL; static inline void fallback_on_nodma_alloc(char **addr, size_t l) { #ifdef FLOPPY_CAN_FALLBACK_ON_NODMA - if(*addr) + if (*addr) return; /* we have the memory */ - if(can_use_virtual_dma != 2) + if (can_use_virtual_dma != 2) return; /* no fallback allowed */ printk("DMA memory shortage. Temporarily falling back on virtual DMA\n"); *addr = (char *) nodma_mem_alloc(l); @@ -393,6 +396,16 @@ static struct floppy_raw_cmd *raw_cmd, default_raw_cmd; * 'options'. Other parameters should be self-explanatory (see also * setfdprm(8)). */ +/* + Size + | Sectors per track + | | Head + | | | Tracks + | | | | Stretch + | | | | | Gap 1 size + | | | | | | Data rate, | 0x40 for perp + | | | | | | | Spec1 (stepping rate, head unload + | | | | | | | | /fmt gap (gap2) */ static struct floppy_struct floppy_type[32] = { { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */ { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */ @@ -403,7 +416,7 @@ static struct floppy_struct floppy_type[32] = { { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */ { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */ { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */ - { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120"}, /* 9 3.12MB 3.5" */ + { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */ { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */ { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */ @@ -491,8 +504,8 @@ static struct format_descr format_req; * not contain a 64k byte boundary crossing, or data will be * corrupted/lost. */ -static char *floppy_track_buffer=0; -static int max_buffer_sectors=0; +static char *floppy_track_buffer; +static int max_buffer_sectors; static int *errors; typedef void (*done_f)(int); @@ -503,7 +516,7 @@ static struct cont_t { void (*error)(void); /* this is called to tally an error */ done_f done; /* this is called to say if the operation has * succeeded/failed */ -} *cont=NULL; +} *cont; static void floppy_ready(void); static void floppy_start(void); @@ -551,14 +564,13 @@ static struct floppy_struct *_floppy = floppy_type; static unsigned char current_drive = 0; static long current_count_sectors = 0; static unsigned char sector_t; /* sector in track */ -static unsigned char in_sector_offset; /* offset within physical sector, - * expressed in units of 512 bytes */ +static unsigned char in_sector_offset; /* offset within physical sector, + * expressed in units of 512 bytes */ #ifndef fd_eject #define fd_eject(x) -EINVAL #endif - #ifdef DEBUGT static long unsigned debugtimer; #endif @@ -602,10 +614,10 @@ static void is_alive(const char *message) #define OLOGSIZE 20 static void (*lasthandler)(void) = NULL; -static unsigned long interruptjiffies=0; -static unsigned long resultjiffies=0; -static int resultsize=0; -static unsigned long lastredo=0; +static unsigned long interruptjiffies; +static unsigned long resultjiffies; +static int resultsize; +static unsigned long lastredo; static struct output_log { unsigned char data; @@ -613,7 +625,7 @@ static struct output_log { unsigned long jiffies; } output_log[OLOGSIZE]; -static int output_log_pos=0; +static int output_log_pos; #endif #define CURRENTD -1 @@ -640,7 +652,7 @@ static void reschedule_timeout(int drive, const char *message, int marg) static int maximum(int a, int b) { - if(a > b) + if (a > b) return a; else return b; @@ -649,7 +661,7 @@ static int maximum(int a, int b) static int minimum(int a, int b) { - if(a < b) + if (a < b) return a; else return b; @@ -697,11 +709,11 @@ static int disk_change(int drive) if (jiffies - UDRS->select_date < UDP->select_delay) DPRINT("WARNING disk change called early\n"); if (!(FDCS->dor & (0x10 << UNIT(drive))) || - (FDCS->dor & 3) != UNIT(drive) || - fdc != FDC(drive)){ + (FDCS->dor & 3) != UNIT(drive) || + fdc != FDC(drive)){ DPRINT("probing disk change on unselected drive\n"); DPRINT("drive=%d fdc=%d dor=%x\n",drive, FDC(drive), - FDCS->dor); + (unsigned int)FDCS->dor); } #endif @@ -791,7 +803,7 @@ static void twaddle(void) { if (DP->select_delay) return; - fd_outb(FDCS->dor & ~(0x10<dor & ~(0x10<dor, FD_DOR); DRS->select_date = jiffies; } @@ -1034,7 +1046,7 @@ static int wait_for_completion(unsigned long delay, timeout_fn function) } static spinlock_t floppy_hlt_lock = SPIN_LOCK_UNLOCKED; -static int hlt_disabled=0; +static int hlt_disabled; static void floppy_disable_hlt(void) { unsigned long flags; @@ -1090,7 +1102,7 @@ static void setup_DMA(void) f=claim_dma_lock(); fd_disable_dma(); #ifdef fd_dma_setup - if(fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length, + if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length, (raw_cmd->flags & FD_RAW_READ)? DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) { @@ -1120,7 +1132,7 @@ static void show_floppy(void); static int wait_til_ready(void) { int counter, status; - if(FDCS->reset) + if (FDCS->reset) return -1; for (counter = 0; counter < 10000; counter++) { status = fd_inb(FD_STATUS); @@ -1184,7 +1196,7 @@ static int result(void) else break; } - if(!initialising) { + if (!initialising) { DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n", fdc, status, i); show_floppy(); @@ -1198,7 +1210,7 @@ static int result(void) static int need_more_output(void) { int status; - if( (status = wait_til_ready()) < 0) + if ((status = wait_til_ready()) < 0) return -1; if ((status & (STATUS_READY|STATUS_DIR|STATUS_DMA)) == STATUS_READY) return MORE_OUTPUT; @@ -1249,7 +1261,7 @@ static int fdc_configure(void) { /* Turn on FIFO */ output_byte(FD_CONFIGURE); - if(need_more_output() != MORE_OUTPUT) + if (need_more_output() != MORE_OUTPUT) return 0; output_byte(0); output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf)); @@ -1304,7 +1316,7 @@ static void fdc_specify(void) /* chose the default rate table, not the one * where 1 = 2 Mbps */ output_byte(FD_DRIVESPEC); - if(need_more_output() == MORE_OUTPUT) { + if (need_more_output() == MORE_OUTPUT) { output_byte(UNIT(current_drive)); output_byte(0xc0); } @@ -1745,14 +1757,14 @@ void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs) do_print = !handler && print_unex && !initialising; inr = result(); - if(do_print) + if (do_print) print_result("unexpected interrupt", inr); if (inr == 0){ int max_sensei = 4; do { output_byte(FD_SENSEI); inr = result(); - if(do_print) + if (do_print) print_result("sensei", inr); max_sensei--; } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2 && max_sensei); @@ -2325,31 +2337,31 @@ static void rw_interrupt(void) nr_sectors = 0; CODE2SIZE; - if(ST1 & ST1_EOC) + if (ST1 & ST1_EOC) eoc = 1; else eoc = 0; - if(COMMAND & 0x80) + if (COMMAND & 0x80) heads = 2; else heads = 1; - nr_sectors = (((R_TRACK-TRACK) * heads + + nr_sectors = (((R_TRACK-TRACK) * heads + R_HEAD-HEAD) * SECT_PER_TRACK + - R_SECTOR-SECTOR + eoc) << SIZECODE >> 2; + R_SECTOR-SECTOR + eoc) << SIZECODE >> 2; #ifdef FLOPPY_SANITY_CHECK if (nr_sectors / ssize > - (in_sector_offset + current_count_sectors + ssize - 1)/ssize) { + (in_sector_offset + current_count_sectors + ssize - 1) / ssize) { DPRINT("long rw: %x instead of %lx\n", nr_sectors, current_count_sectors); printk("rs=%d s=%d\n", R_SECTOR, SECTOR); printk("rh=%d h=%d\n", R_HEAD, HEAD); printk("rt=%d t=%d\n", R_TRACK, TRACK); printk("heads=%d eoc=%d\n", heads, eoc); - printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK, - sector_t, ssize); + printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK, + sector_t, ssize); printk("in_sector_offset=%d\n", in_sector_offset); } #endif @@ -2547,22 +2559,24 @@ static inline int check_dma_crossing(char *start, * does not work with MT, hence we can only transfer one head at * a time */ -static void virtualdmabug_workaround(void) { +static void virtualdmabug_workaround(void) +{ int hard_sectors, end_sector; + if(CT(COMMAND) == FD_WRITE) { COMMAND &= ~0x80; /* switch off multiple track mode */ - + hard_sectors = raw_cmd->length >> (7 + SIZECODE); end_sector = SECTOR + hard_sectors - 1; #ifdef FLOPPY_SANITY_CHECK if(end_sector > SECT_PER_TRACK) { - printk("too many sectors %d > %d\n", - end_sector, SECT_PER_TRACK); + printk("too many sectors %d > %d\n", + end_sector, SECT_PER_TRACK); return; } #endif SECT_PER_TRACK = end_sector; /* make sure SECT_PER_TRACK points - * to end of transfer */ + * to end of transfer */ } } @@ -2603,7 +2617,7 @@ static int make_raw_rw_request(void) TRACK = CURRENT->sector / max_sector; sector_t = CURRENT->sector % max_sector; if (_floppy->track && TRACK >= _floppy->track) { - if(CURRENT->current_nr_sectors & 1) { + if (CURRENT->current_nr_sectors & 1) { current_count_sectors = 1; return 1; } else @@ -2935,7 +2949,7 @@ static void process_fd_request(void) static void do_fd_request(request_queue_t * q) { - if(usage_count == 0) { + if (usage_count == 0) { printk("warning: usage count=0, CURRENT=%p exiting\n", CURRENT); printk("sect=%ld cmd=%d\n", CURRENT->sector, CURRENT->cmd); return; @@ -3057,7 +3071,7 @@ static void raw_cmd_done(int flag) raw_cmd->flags |= FD_RAW_HARDFAILURE; } else { raw_cmd->reply_count = inr; - if(raw_cmd->reply_count > MAX_REPLIES) + if (raw_cmd->reply_count > MAX_REPLIES) raw_cmd->reply_count=0; for (i=0; i< raw_cmd->reply_count; i++) raw_cmd->reply[i] = reply_buffer[i]; @@ -3382,7 +3396,7 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g) process_fd_request(); *g = current_type[drive]; } - if(!*g) + if (!*g) return -ENODEV; return 0; } @@ -3420,8 +3434,8 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, /* convert compatibility eject ioctls into floppy eject ioctl. * We do this in order to provide a means to eject floppy disks before * installing the new fdutils package */ - if(cmd == CDROMEJECT || /* CD-ROM eject */ - cmd == 0x6470 /* SunOS floppy eject */) { + if (cmd == CDROMEJECT || /* CD-ROM eject */ + cmd == 0x6470 /* SunOS floppy eject */) { DPRINT("obsolete eject ioctl\n"); DPRINT("please use floppycontrol --eject\n"); cmd = FDEJECT; @@ -3467,7 +3481,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, switch (cmd) { case FDEJECT: - if(UDRS->fd_ref != 1) + if (UDRS->fd_ref != 1) /* somebody else has this drive open */ return -EBUSY; LOCK_FDC(drive,1); @@ -3508,9 +3522,9 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, CALL(poll_drive(1, FD_RAW_NEED_DISK)); ret = UDRS->flags; process_fd_request(); - if(ret & FD_VERIFY) + if (ret & FD_VERIFY) return -ENODEV; - if(!(ret & FD_DISK_WRITABLE)) + if (!(ret & FD_DISK_WRITABLE)) return -EROFS; return 0; case FDFMTTRK: @@ -3705,7 +3719,7 @@ static int floppy_open(struct inode * inode, struct file * filp) INFBOUND(try, 16); tmp= (char *)fd_dma_mem_alloc(1024*try); } - if(!tmp && !floppy_track_buffer) { + if (!tmp && !floppy_track_buffer) { fallback_on_nodma_alloc(&tmp, 2048 * try); } if (!tmp && !floppy_track_buffer) { @@ -3713,7 +3727,7 @@ static int floppy_open(struct inode * inode, struct file * filp) RETERR(ENXIO); } if (floppy_track_buffer) { - if(tmp) + if (tmp) fd_dma_mem_free((unsigned long)tmp,try*1024); } else { buffer_min = buffer_max = -1; @@ -3787,9 +3801,9 @@ static int floppy_revalidate(kdev_t dev) int cf; if (UTESTF(FD_DISK_CHANGED) || - UTESTF(FD_VERIFY) || - test_bit(drive, &fake_change) || - NO_GEOM){ + UTESTF(FD_VERIFY) || + test_bit(drive, &fake_change) || + NO_GEOM){ lock_fdc(drive,0); cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY); if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)){ @@ -3892,13 +3906,13 @@ static char __init get_fdc_version(void) return FDC_UNKNOWN; } - if(!fdc_configure()) { + if (!fdc_configure()) { printk(KERN_INFO "FDC %d is an 82072\n",fdc); return FDC_82072; /* 82072 doesn't know CONFIGURE */ } output_byte(FD_PERPENDICULAR); - if(need_more_output() == MORE_OUTPUT) { + if (need_more_output() == MORE_OUTPUT) { output_byte(0); } else { printk(KERN_INFO "FDC %d is an 82072A\n", fdc); @@ -4037,7 +4051,8 @@ static struct param_table { { "unexpected_interrupts", 0, &print_unex, 1, 0 }, { "no_unexpected_interrupts", 0, &print_unex, 0, 0 }, - { "L40SX", 0, &print_unex, 0, 0 } }; + { "L40SX", 0, &print_unex, 0, 0 } +}; static int __init floppy_setup(char *str) { @@ -4053,11 +4068,11 @@ static int __init floppy_setup(char *str) param = ints[1]; else param = config_params[i].def_param; - if(config_params[i].fn) + if (config_params[i].fn) config_params[i]. fn(ints,param, config_params[i].param2); - if(config_params[i].var) { + if (config_params[i].var) { DPRINT("%s=%d\n", str, param); *config_params[i].var = param; } @@ -4086,7 +4101,7 @@ int __init floppy_init(void) int i,unit,drive; - raw_cmd = 0; + raw_cmd = NULL; devfs_handle = devfs_mk_dir (NULL, "floppy", 0, NULL); if (devfs_register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { @@ -4174,7 +4189,7 @@ int __init floppy_init(void) FDCS->address = -1; continue; } - if(can_use_virtual_dma == 2 && FDCS->version < FDC_82072A) + if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A) can_use_virtual_dma = 0; have_no_fdc = 0; @@ -4192,13 +4207,13 @@ int __init floppy_init(void) if (have_no_fdc) { DPRINT("no floppy controllers found\n"); - floppy_tq.routine = (void *)(void *) empty; + floppy_tq.routine = (void *)(void *) empty; mark_bh(IMMEDIATE_BH); schedule(); - if (usage_count) - floppy_release_irq_and_dma(); + if (usage_count) + floppy_release_irq_and_dma(); blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); - devfs_unregister_blkdev(MAJOR_NR,"fd"); + devfs_unregister_blkdev(MAJOR_NR,"fd"); } for (drive = 0; drive < N_DRIVE; drive++) { @@ -4324,7 +4339,7 @@ static void floppy_release_irq_and_dma(void) if (floppy_track_buffer && max_buffer_sectors) { tmpsize = max_buffer_sectors*1024; tmpaddr = (unsigned long)floppy_track_buffer; - floppy_track_buffer = 0; + floppy_track_buffer = NULL; max_buffer_sectors = 0; buffer_min = buffer_max = -1; fd_dma_mem_free(tmpaddr, tmpsize); @@ -4357,7 +4372,7 @@ static void floppy_release_irq_and_dma(void) #ifdef MODULE -char *floppy=NULL; +char *floppy; static void __init parse_floppy_cfg_string(char *cfg) { @@ -4365,11 +4380,11 @@ static void __init parse_floppy_cfg_string(char *cfg) while(*cfg) { for(ptr = cfg;*cfg && *cfg != ' ' && *cfg != '\t'; cfg++); - if(*cfg) { + if (*cfg) { *cfg = '\0'; cfg++; } - if(*ptr) + if (*ptr) floppy_setup(ptr); } } @@ -4378,7 +4393,7 @@ int init_module(void) { printk(KERN_INFO "inserting floppy driver for " UTS_RELEASE "\n"); - if(floppy) + if (floppy) parse_floppy_cfg_string(floppy); return floppy_init(); } @@ -4411,7 +4426,7 @@ __setup ("floppy=", floppy_setup); void floppy_eject(void) { int dummy; - if(have_no_fdc) + if (have_no_fdc) return; if(floppy_grab_irq_and_dma()==0) { diff --git a/drivers/block/loop.c b/drivers/block/loop.c index bacb62fba9a8..9d518eaf9c31 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -289,7 +289,8 @@ repeat: if (lo->lo_flags & LO_FLAGS_READ_ONLY) goto error_out; } else if (current_request->cmd != READ) { - printk(KERN_ERR "unknown loop device command (%d)?!?", current_request->cmd); + printk(KERN_ERR "unknown loop device command (%d)?!?", + current_request->cmd); goto error_out; } @@ -423,8 +424,28 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg) /* Backed by a block device - don't need to hold onto a file structure */ lo->lo_backing_file = NULL; + + if (error) + goto out_putf; } else if (S_ISREG(inode->i_mode)) { struct address_space_operations *aops; + + aops = inode->i_mapping->a_ops; + /* + * If we can't read - sorry. If we only can't write - well, + * it's going to be read-only. + */ + error = -EINVAL; + if (!aops->readpage) + goto out_putf; + + if (!aops->prepare_write || !aops->commit_write) + lo->lo_flags |= LO_FLAGS_READ_ONLY; + + error = get_write_access(inode); + if (error) + goto out_putf; + /* Backed by a regular file - we need to hold onto a file structure for this file. Friggin' NFS can't live without it on write and for reading we use do_generic_file_read(), @@ -437,35 +458,23 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg) error = -ENFILE; lo->lo_backing_file = get_empty_filp(); - if (lo->lo_backing_file) { - lo->lo_backing_file->f_mode = file->f_mode; - lo->lo_backing_file->f_pos = file->f_pos; - lo->lo_backing_file->f_flags = file->f_flags; - lo->lo_backing_file->f_owner = file->f_owner; - lo->lo_backing_file->f_dentry = file->f_dentry; - lo->lo_backing_file->f_vfsmnt = file->f_vfsmnt; - lo->lo_backing_file->f_op = file->f_op; - lo->lo_backing_file->private_data = file->private_data; - file_moveto(lo->lo_backing_file, file); - - error = get_write_access(inode); - if (error) { - put_filp(lo->lo_backing_file); - lo->lo_backing_file = NULL; - } + if (lo->lo_backing_file == NULL) { + put_write_access(inode); + goto out_putf; } - aops = inode->i_mapping->a_ops; - /* - * If we can't read - sorry. If we only can't write - well, - * it's going to be read-only. - */ - if (!aops->readpage) - error = -EINVAL; - else if (!aops->prepare_write || !aops->commit_write) - lo->lo_flags |= LO_FLAGS_READ_ONLY; + + lo->lo_backing_file->f_mode = file->f_mode; + lo->lo_backing_file->f_pos = file->f_pos; + lo->lo_backing_file->f_flags = file->f_flags; + lo->lo_backing_file->f_owner = file->f_owner; + lo->lo_backing_file->f_dentry = file->f_dentry; + lo->lo_backing_file->f_vfsmnt = mntget(file->f_vfsmnt); + lo->lo_backing_file->f_op = file->f_op; + lo->lo_backing_file->private_data = file->private_data; + file_moveto(lo->lo_backing_file, file); + + error = 0; } - if (error) - goto out_putf; if (IS_RDONLY (inode) || is_read_only(lo->lo_device)) lo->lo_flags |= LO_FLAGS_READ_ONLY; @@ -477,9 +486,9 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg) lo->ioctl = NULL; figure_loop_size(lo); -out_putf: + out_putf: fput(file); -out: + out: if (error) MOD_DEC_USE_COUNT; return error; @@ -530,6 +539,7 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev) lo->lo_dentry = NULL; if (lo->lo_backing_file != NULL) { + put_write_access(lo->lo_backing_file->f_dentry->d_inode); fput(lo->lo_backing_file); lo->lo_backing_file = NULL; } else { diff --git a/drivers/block/xor.c b/drivers/block/xor.c index ca1bb15649fd..9f54be5a2877 100644 --- a/drivers/block/xor.c +++ b/drivers/block/xor.c @@ -15,6 +15,7 @@ * (for example /usr/src/linux/COPYING); if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #define BH_TRACE 0 #include #include diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 280bf4a927a6..e0831dd1e140 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -232,7 +232,8 @@ else endif endif -obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tda8425.o tda985x.o tea6300.o +obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o \ + tda7432.o tda8425.o tda985x.o tda9875.o tea6300.o tea6420.o ifeq ($(CONFIG_VIDEO_BT848),y) L_TUNERS=y else diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c index f55f992d8c20..f7c9b0db6b10 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -44,13 +44,6 @@ #include #include -#ifdef LOCK_I2C_BUS -# error INSTALL ERROR -# error gcc uses the old, obsolete i2c.h include file. Please install the \ - new i2c stack. Please install it by patching the kernel, otherwise \ - gcc will not find the new header files. -#endif - #include "bttv.h" #include "tuner.h" @@ -100,7 +93,7 @@ static int triton1=0; static unsigned long remap[BTTV_MAX]; static unsigned int radio[BTTV_MAX]; static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 }; -static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0}; +static unsigned int pll[BTTV_MAX] = { -1, -1, -1, -1}; static unsigned int fieldnr = 0; static unsigned int verbose = 1; static unsigned int debug = 0; @@ -713,19 +706,23 @@ static struct CARD { char *name; } cards[] = { { 0x00011002, BTTV_HAUPPAUGE878, "ATI TV Wonder" }, - { 0x00031461, BTTV_AVERMEDIA98, "AVerMedia TVPhone98" }, + { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00041461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" }, { 0x1118153b, BTTV_TERRATVALUE, "Terratec TV Value" }, + { 0x1200bd11, BTTV_PINNACLERAVE, "Pinnacle PCTV Rave" }, { 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" }, { 0x14610002, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" }, { 0x18501851, BTTV_CHRONOS_VS2, "Chronos Video Shuttle II" }, { 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" }, + { 0x263610b4, BTTV_STB2, "STB TV PCI FM, P/N 6000704" }, { 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" }, { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" }, { 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" }, { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master" }, + { 0x402010fc, 0 /* no tvcards entry yet */, "I-O Data Co. GV-BCV3/PCI" }, { 0x6606217d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0x1200bd11, BTTV_PINNACLERAVE, "Pinnacle PCTV Rave" }, { 0, -1, NULL } }; @@ -747,6 +744,13 @@ struct tvcard int tda9840:1; int tda985x:1; int tea63xx:1; + int tea64xx:1; + int tda7432:1; + int tda9875:1; + + /* other settings */ + int pll; + int tuner_type; }; static struct tvcard tvcards[] = @@ -754,144 +758,157 @@ static struct tvcard tvcards[] = /* 0x00 */ { " *** UNKNOWN *** ", 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "MIRO PCTV", 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "Hauppauge old", 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,0,1,0 }, + 1,1,0,1,0,0,0,1, PLL_NONE, -1 }, { "STB", 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, - 0,1,1,1,1 }, + 0,1,1,1,1,0,0,1, PLL_NONE, -1 }, { "Intel", - 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,1,1,0 }, + 3, 1, 0, -1, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "Diamond DTV2000", 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "AVerMedia TVPhone", 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "MATRIX-Vision MV-Delta", 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, /* 0x08 */ { "Fly Video II", 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1}, { 0, 0xc00, 0x800, 0x400, 0xc00, 0},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "TurboTV", 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "Hauppauge new (bt878)", 4, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,0,1,0 }, + 1,1,0,1,0,0,0,1, PLL_28, -1 }, { "MIRO PCTV pro", 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "ADS Technologies Channel Surfer TV", 3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "AVerMedia TVCapture 98", 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, { "Aimslab VHX", 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "Zoltrix TV-Max", 3, 1, 0, 2,15, { 2, 3, 1, 1}, {0 , 0, 1 , 0, 10},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, /* 0x10 */ { "Pixelview PlayTV (bt878)", - 3, 1, 0, 2, 0x01e000, { 2, 0, 1, 1}, + 3, 1, 0, 2, 0x01fe00, { 2, 0, 1, 1}, { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, { "Leadtek WinView 601", 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "AVEC Intercapture", 3, 2, 0, 2, 0, {2, 3, 1, 1}, {1, 0, 0, 0, 0},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "LifeView FlyKit w/o Tuner", 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}, { 0 },0, - 0,0,0,0,0 }, + 0,0,0,0,0,0,0,1, PLL_NONE, -1 }, { "CEI Raffles Card", 3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "Lucky Star Image World ConferenceTV", - 3, 1, 0, 2, 16777215, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0, - 1,1,1,1,0 }, + 3, 1, 0, 2, 0x00fffe07, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0, + 1,1,1,1,0,0,0,1, PLL_28, TUNER_PHILIPS_PAL_I }, { "Phoebe Tv Master + FM", 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "Modular Technology MM205 PCTV, bt878", 2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 },0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, /* 0x18 */ { "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)", 3, 1, 0, 2, 0xe00, { 2, 3, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, { "Terratec/Vobis TV-Boostar", 3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "Newer Hauppauge WinCam (bt878)", 4, 1, 0, 3, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "MAXI TV Video PCI2", 3, 1, 0, 2, 0xffff, { 2, 3, 1, 1}, { 0, 1, 2, 3, 0xc00},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, TUNER_PHILIPS_SECAM }, { "Terratec TerraTV+", 3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "Imagenation PXC200", 5, 1, -1, 4, 0, { 2, 3, 1, 0, 0}, { 0 }, 0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "FlyVideo 98", 3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1}, { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "iProTV", 3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, /* 0x20 */ { "Intel Create and Share PCI", 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "Terratec TerraTValue", - 3, 1, 0, 2, 0xf00, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0, - 1,1,1,1,0 }, + 3, 1, 0, 2, 0xffff00, { 2, 3, 1, 1}, + { 0x500, 0, 0x300, 0x900, 0x900},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, { "Leadtek WinFast 2000", 3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0}, { 0x621000,0x620100,0x621100,0x620000,0xE210000,0x620000},0, - 1,1,1,1,1 }, + 1,1,1,1,1,0,0,1, PLL_28, -1 }, { "Chronos Video Shuttle II", 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, { "Typhoon TView TV/FM Tuner", 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0, - 1,1,1,1,0 }, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, { "PixelView PlayTV pro", 3, 1, 0, 2, 0xff, { 2, 3, 1, 1 }, - { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0 }, + { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0, + 0,0,0,0,0,0,0,1, PLL_28, -1 }, { "TView99 CPH063", - 3, 1, 0, 2, 0x551e00, { 2, 0, 1, 1}, - { 0x551400, 0x551200, 0, 0, 0x551200 }, 0,1,1,1,1,0 }, + 3, 1, 0, 2, 0x551e00, { 2, 3, 1, 1}, + { 0x551400, 0x551200, 0, 0, 0, 0x551200 }, 0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, { "Pinnacle PCTV Rave", 3, 1, 0, 2, 0x03000F, { 2, 3, 1, 1}, { 2, 0, 0, 0, 1},0, - 1,1,1,1,0 }, - + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + /* 0x28 */ + { "STB2", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, + 0,1,1,1,0,1,1,1, PLL_NONE, -1 }, + { "AVerMedia TVPhone 98", + 3, 4, 0, 2, 4, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, + 1,1,1,1,0,0,0,1, PLL_28, 5 }, + { "ProVideo PV951", /* pic16c54 */ + 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, + 0,0,0,0,0,0,0,0, PLL_28, 1 }, }; #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard)) @@ -1477,6 +1494,10 @@ static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int unsigned char lmask, rmask, *p; int W, l, r; int i; + + if (debug) + printk("bttv clip: %dx%d+%d+%d\n",w,h,x,y); + /* bitmap is fixed width, 128 bytes (1024 pixels represented) */ if (x<0) { @@ -1497,10 +1518,10 @@ static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int w=1024-x; l=x>>3; - r=(x+w)>>3; + r=(x+w-1)>>3; W=r-l-1; lmask=lmaskt[x&7]; - rmask=rmaskt[(x+w)&7]; + rmask=rmaskt[(x+w-1)&7]; p=clipmap+128*y+l; if (W>0) @@ -1885,6 +1906,7 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp) #endif if (btv->gq_in == btv->gq_out) { + btv->gq_start = 1; btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } btv->gqueue[btv->gq_in++] = mp->frame; @@ -2033,14 +2055,15 @@ static void bttv_close(struct video_device *dev) btread(BT848_I2C); /* This fixes the PCI posting delay */ - /* - * This is sucky but right now I can't find a good way to - * be sure its safe to free the buffer. We wait 5-6 fields - * which is more than sufficient to be sure. - */ - - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/10); /* Wait 1/10th of a second */ + if (-1 != btv->gq_grab) { + /* + * This is sucky but right now I can't find a good way to + * be sure its safe to free the buffer. We wait 5-6 fields + * which is more than sufficient to be sure. + */ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); /* Wait 1/10th of a second */ + } /* * We have allowed it to drain. @@ -3063,7 +3086,7 @@ static void idcard(int i) btv->type=BTTV_HAUPPAUGE; } - /* STB cards have a eeprom @ 0xae */ + /* STB cards have a eeprom @ 0xae (old bt848) */ } else if (I2CRead(btv, I2C_STBEE, "eeprom")>=0) { btv->type=BTTV_STB; } @@ -3078,20 +3101,20 @@ static void idcard(int i) } /* print which board we have found */ - printk(KERN_INFO "bttv%d: model: ",btv->nr); - sprintf(btv->video_dev.name,"BT%d%s(%.22s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", tvcards[btv->type].name); - printk("%s\n",btv->video_dev.name); + printk(KERN_INFO "bttv%d: model: %s\n",btv->nr,btv->video_dev.name); + /* board specific initialisations */ if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) { /* auto detect tuner for MIRO cards */ btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7; } if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { + /* pick up some config infos from the eeprom */ if (0xa0 != eeprom) { eeprom = 0xa0; readee(btv,eeprom_data,0xa0); @@ -3099,32 +3122,42 @@ static void idcard(int i) hauppauge_eeprom(btv); hauppauge_boot_msp34xx(btv); } - if (btv->type == BTTV_MAXI) { - /* PHILIPS FI1216MK2 tuner (PAL/SECAM) */ - btv->tuner_type=TUNER_PHILIPS_SECAM; - } - if (btv->type == BTTV_PXC200) init_PXC200(btv); - - if (btv->type == BTTV_CONFERENCETV) - btv->tuner_type = 1; - - if (btv->type == BTTV_HAUPPAUGE878 || - btv->type == BTTV_CONFERENCETV || - btv->type == BTTV_PIXVIEWPLAYTV || - btv->type == BTTV_AVERMEDIA98 || - btv->type == BTTV_MAGICTVIEW061 || - btv->type == BTTV_MAGICTVIEW063 || - btv->type == BTTV_CHRONOS_VS2 || - btv->type == BTTV_TYPHOON_TVIEW || - btv->type == BTTV_PXELVWPLTVPRO || - btv->type == BTTV_WINFAST2000) { - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; - } - if (btv->tuner_type != -1) + + /* pll configuration */ + if (!(btv->id==848 && btv->revision==0x11)) { + /* defaults from card list */ + if (PLL_28 == tvcards[btv->type].pll) { + btv->pll.pll_ifreq=28636363; + btv->pll.pll_crystal=BT848_IFORM_XT0; + } + /* insmod options can override */ + switch (pll[btv->nr]) { + case 0: /* none */ + btv->pll.pll_crystal = 0; + btv->pll.pll_ifreq = 0; + btv->pll.pll_ofreq = 0; + break; + case 1: /* 28 MHz */ + btv->pll.pll_ifreq = 28636363; + btv->pll.pll_ofreq = 0; + btv->pll.pll_crystal=BT848_IFORM_XT0; + break; + case 2: /* 35 MHz */ + btv->pll.pll_ifreq = 35468950; + btv->pll.pll_ofreq = 0; + btv->pll.pll_crystal=BT848_IFORM_XT1; + break; + } + } + + + /* tuner configuration */ + if (-1 != tvcards[btv->type].tuner_type) + btv->tuner_type = tvcards[btv->type].tuner_type; + if (btv->tuner_type != -1) call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); /* try to detect audio/fader chips */ @@ -3154,12 +3187,28 @@ static void idcard(int i) request_module("tda985x"); } - if (tvcards[btv->type].tea63xx /* && - I2CRead(btv, I2C_TEA6300, "TEA63xx") >= 0 */) { + if (tvcards[btv->type].tda9875 && + I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) { + if (autoload) + request_module("tda9875"); + } + + if (tvcards[btv->type].tda7432 && + I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) { + if (autoload) + request_module("tda7432"); + } + + if (tvcards[btv->type].tea63xx) { if (autoload) request_module("tea6300"); } + if (tvcards[btv->type].tea64xx) { + if (autoload) + request_module("tea6420"); + } + if (tvcards[btv->type].tuner != -1) { if (autoload) request_module("tuner"); @@ -3242,7 +3291,11 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags) btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); } - btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); + if (btv->gq_start) { + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); + } else { + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); + } btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); /* enable cpaturing and DMA */ @@ -3561,6 +3614,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) } if (stat&(8<<28)) { + btv->gq_start = 0; btv->gq_grab = btv->gqueue[btv->gq_out++]; btv->gq_out = btv->gq_out % MAX_GBUFFERS; if (debug) @@ -3661,8 +3715,7 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) btv->id=dev->device; btv->irq=dev->irq; - btv->bt848_adr=pci_resource_start(dev, 0); - + btv->bt848_adr=pci_resource_start(dev, 0); if (pci_enable_device(dev)) return -EIO; if (!request_mem_region(pci_resource_start(dev,0), @@ -3689,29 +3742,7 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) cmd = (cmd | PCI_COMMAND_MEMORY ); pci_write_config_dword(dev, PCI_COMMAND, cmd); #endif - - btv->pll.pll_crystal = 0; - btv->pll.pll_ifreq = 0; - btv->pll.pll_ofreq = 0; - btv->pll.pll_current = 0; - if (!(btv->id==848 && btv->revision==0x11)) { - switch (pll[btv->nr]) { - case 0: - /* off */ - break; - case 1: - /* 28 MHz crystal installed */ - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; - break; - case 2: - /* 35 MHz crystal installed */ - btv->pll.pll_ifreq=35468950; - btv->pll.pll_crystal=BT848_IFORM_XT1; - break; - } - } - + #ifdef __sparc__ btv->bt848_mem=(unsigned char *)btv->bt848_adr; #else diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h index be929c6c9be2..4ac092e1e927 100644 --- a/drivers/char/bttv.h +++ b/drivers/char/bttv.h @@ -1,4 +1,4 @@ -/* +/* bttv - Bt848 frame grabber driver Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) @@ -21,7 +21,7 @@ #ifndef _BTTV_H_ #define _BTTV_H_ -#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,25) +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,28) #include #include @@ -183,7 +183,7 @@ struct bttv { struct bttv_gbuf *gbuf; int gqueue[MAX_GBUFFERS]; - int gq_in,gq_out,gq_grab; + int gq_in,gq_out,gq_grab,gq_start; char *fbuffer; struct bttv_pll_info pll; @@ -272,7 +272,13 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #define BTTV_PXELVWPLTVPRO 0x25 #define BTTV_MAGICTVIEW063 0x26 #define BTTV_PINNACLERAVE 0x27 +#define BTTV_STB2 0x28 +#define BTTV_AVPHONE98 0x29 +#define BTTV_PV951 0x2a +#define PLL_NONE 0 +#define PLL_28 1 +#define PLL_35 2 #define AUDIO_TUNER 0x00 #define AUDIO_RADIO 0x01 @@ -289,9 +295,11 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #define TEA6300 0x04 #define I2C_TSA5522 0xc2 +#define I2C_TDA7432 0x8a +#define I2C_TDA8425 0x82 #define I2C_TDA9840 0x84 #define I2C_TDA9850 0xb6 -#define I2C_TDA8425 0x82 +#define I2C_TDA9875 0xb0 #define I2C_HAUPEE 0xa0 #define I2C_STBEE 0xae #define I2C_VHX 0xc0 diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 6763b068a21c..9238ae3eb214 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -4075,7 +4075,7 @@ err_out: } -static struct pci_device_id epca_pci_tbl[] __devinitdata = { +static struct pci_device_id epca_pci_tbl[] __initdata = { { PCI_VENDOR_DIGI, PCI_DEVICE_XR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xr }, { PCI_VENDOR_DIGI, PCI_DEVICE_XEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xem }, { PCI_VENDOR_DIGI, PCI_DEVICE_CX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_cx }, diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 2d275e59259e..ab6b65f0abe2 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -231,9 +231,10 @@ static ssize_t read_kmem(struct file *file, char *buf, { unsigned long p = *ppos; ssize_t read = 0; - ssize_t virtr; + ssize_t virtr = 0; + char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ - if (p < (unsigned long) high_memory) { + if (p < (unsigned long) high_memory) { read = count; if (count > (unsigned long) high_memory - p) read = (unsigned long) high_memory - p; @@ -258,11 +259,27 @@ static ssize_t read_kmem(struct file *file, char *buf, count -= read; } - virtr = vread(buf, (char *)p, count); - if (virtr < 0) - return virtr; - *ppos += p + virtr; - return virtr + read; + kbuf = (char *)__get_free_page(GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + while (count > 0) { + int len = count; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + len = vread(kbuf, (char *)p, len); + if (len && copy_to_user(buf, kbuf, len)) { + free_page((unsigned long)kbuf); + return -EFAULT; + } + count -= len; + buf += len; + virtr += len; + p += len; + } + free_page((unsigned long)kbuf); + *ppos = p; + return virtr + read; } /* diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c index 6b86db95be81..f4252a07122c 100644 --- a/drivers/char/msp3400.c +++ b/drivers/char/msp3400.c @@ -871,7 +871,7 @@ static int msp3400c_thread(void *data) /* unmute */ msp3400c_setvolume(client, msp->left, msp->right); - if (msp->watch_stereo) + if (msp->watch_stereo) mod_timer(&msp->wake_stereo, jiffies+5*HZ); if (debug) @@ -1086,7 +1086,7 @@ static int msp3410d_thread(void *data) msp3400c_settreble(client, msp->treble); msp3400c_setvolume(client, msp->left, msp->right); - if (msp->watch_stereo) + if (msp->watch_stereo) mod_timer(&msp->wake_stereo, jiffies+HZ); msp->active = 0; @@ -1236,7 +1236,7 @@ static int msp3400c_mixer_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct i2c_client *client = NULL; + struct i2c_client *client; struct msp3400c *msp; int i; @@ -1246,12 +1246,12 @@ msp3400c_mixer_open(struct inode *inode, struct file *file) if (msp->mixer_num == minor) { client = msps[i]; file->private_data = client; - goto match; + break; } } - return -ENODEV; + if (MSP3400_MAX == i) + return -ENODEV; -match: /* lock bttv in memory while the mixer is in use */ if (client->adapter->inc_use) client->adapter->inc_use(client->adapter); @@ -1265,8 +1265,8 @@ msp3400c_mixer_release(struct inode *inode, struct file *file) { struct i2c_client *client = file->private_data; - if (client->adapter->inc_use) - client->adapter->inc_use(client->adapter); + if (client->adapter->dec_use) + client->adapter->dec_use(client->adapter); MOD_DEC_USE_COUNT; return 0; } diff --git a/drivers/char/tda7432.c b/drivers/char/tda7432.c new file mode 100644 index 000000000000..4880913106d2 --- /dev/null +++ b/drivers/char/tda7432.c @@ -0,0 +1,505 @@ +/* + * For the STS-Thompson TDA7432 audio processor chip + * + * Handles audio functions: volume, balance, tone, loudness + * This driver will not complain if used with any + * other i2c device with the same address. + * + * Copyright (c) 2000 Eric Sandeen + * This code is placed under the terms of the GNU General Public License + * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) + * Which was based on tda8425.c by Greg Alexander (c) 1998 + * + * OPTIONS: + * debug - set to 1 if you'd like to see debug messages + * set to 2 if you'd like to be inundated with debug messages + * + * loudness - set between 0 and 15 for varying degrees of loudness effect + * + * TODO: + * Implement tone controls + * + * Revision: 0.3 - Fixed silly reversed volume controls. :) + * Revision: 0.2 - Cleaned up #defines + * fixed volume control + * Added I2C_DRIVERID_TDA7432 + * added loudness insmod control + * Revision: 0.1 - initial version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + +/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */ +#ifndef I2C_DRIVERID_TDA7432 + #define I2C_DRIVERID_TDA7432 27 +#endif + + +MODULE_AUTHOR("Eric Sandeen "); +MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip"); + +MODULE_PARM(debug,"i"); +MODULE_PARM(loudness,"i"); +static int loudness = 0; /* disable loudness by default */ +static int debug = 0; /* insmod parameter */ + + +/* Address to scan (I2C address of this chip) */ +static unsigned short normal_i2c[] = { + I2C_TDA7432 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +/* Structure of address and subaddresses for the tda7432 */ + +struct tda7432 { + int addr; + int input; + int volume; + int tone; + int lf, lr, rf, rr; + int loud; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define dprintk if (debug) printk +#define d2printk if (debug > 1) printk + +/* The TDA7432 is made by STS-Thompson + * http://www.st.com + * http://us.st.com/stonline/books/pdf/docs/4056.pdf + * + * TDA7432: I2C-bus controlled basic audio processor + * + * The TDA7432 controls basic audio functions like volume, balance, + * and tone control (including loudness). It also has four channel + * output (for front and rear). Since most vidcap cards probably + * don't have 4 channel output, this driver will set front & rear + * together (no independent control). + */ + + /* Subaddresses for TDA7432 */ + +#define TDA7432_IN 0x00 /* Input select */ +#define TDA7432_VL 0x01 /* Volume */ +#define TDA7432_TN 0x02 /* Bass, Treble (Tone) */ +#define TDA7432_LF 0x03 /* Attenuation LF (Left Front) */ +#define TDA7432_LR 0x04 /* Attenuation LR (Left Rear) */ +#define TDA7432_RF 0x05 /* Attenuation RF (Right Front) */ +#define TDA7432_RR 0x06 /* Attenuation RR (Right Rear) */ +#define TDA7432_LD 0x07 /* Loudness */ + + + /* Masks for bits in TDA7432 subaddresses */ + +/* Many of these not used - just for documentation */ + +/* Subaddress 0x00 - Input selection and bass control */ + +/* Bits 0,1,2 control input: + * 0x00 - Stereo input + * 0x02 - Mono input + * 0x03 - Mute + * Mono probably isn't used - I'm guessing only the stereo + * input is connected on most cards, so we'll set it to stereo. + * + * Bit 3 controls bass cut: 0/1 is non-symmetric/symmetric bass cut + * Bit 4 controls bass range: 0/1 is extended/standard bass range + * + * Highest 3 bits not used + */ + +#define TDA7432_STEREO_IN 0 +#define TDA7432_MONO_IN 2 /* Probably won't be used */ +#define TDA7432_MUTE 3 /* Probably won't be used */ +#define TDA7432_BASS_SYM 1 << 3 +#define TDA7432_BASS_NORM 1 << 4 + +/* Subaddress 0x01 - Volume */ + +/* Lower 7 bits control volume from -79dB to +32dB in 1dB steps + * Recommended maximum is +20 dB + * + * +32dB: 0x00 + * +20dB: 0x0c + * 0dB: 0x20 + * -79dB: 0x6f + * + * MSB (bit 7) controls loudness: 1/0 is loudness on/off + */ + +#define TDA7432_VOL_0DB 0x20 +#define TDA7432_LD_ON 1 << 7 + + +/* Subaddress 0x02 - Tone control */ + +/* Bits 0,1,2 control absolute treble gain from 0dB to 14dB + * 0x0 is 14dB, 0x7 is 0dB + * + * Bit 3 controls treble attenuation/gain (sign) + * 1 = gain (+) + * 0 = attenuation (-) + * + * Bits 4,5,6 control absolute bass gain from 0dB to 14dB + * (This is only true for normal base range, set in 0x00) + * 0x0 << 4 is 14dB, 0x7 is 0dB + * + * Bit 7 controls bass attenuation/gain (sign) + * 1 << 7 = gain (+) + * 0 << 7 = attenuation (-) + * + * Example: + * 1 1 0 1 0 1 0 1 is +4dB bass, -4dB treble + */ + +#define TDA7432_TREBLE_0DB 0xf +#define TDA7432_TREBLE 7 +#define TDA7432_TREBLE_GAIN 1 << 3 +#define TDA7432_BASS_0DB 0xf << 4 +#define TDA7432_BASS 7 << 4 +#define TDA7432_BASS_GAIN 1 << 7 + + +/* Subaddress 0x03 - Left Front attenuation */ +/* Subaddress 0x04 - Left Rear attenuation */ +/* Subaddress 0x05 - Right Front attenuation */ +/* Subaddress 0x06 - Right Rear attenuation */ + +/* Bits 0,1,2,3,4 control attenuation from 0dB to -37.5dB + * in 1.5dB steps. + * + * 0x00 is 0dB + * 0x1f is -37.5dB + * + * Bit 5 mutes that channel when set (1 = mute, 0 = unmute) + * We'll use the mute on the input, though (above) + * Bits 6,7 unused + */ + +#define TDA7432_ATTEN_0DB 0x00 + + +/* Subaddress 0x07 - Loudness Control */ + +/* Bits 0,1,2,3 control loudness from 0dB to -15dB in 1dB steps + * when bit 4 is NOT set + * + * 0x0 is 0dB + * 0xf is -15dB + * + * If bit 4 is set, then there is a flat attenuation according to + * the lower 4 bits, as above. + * + * Bits 5,6,7 unused + */ + + + +/* Begin code */ + +static int tda7432_write(struct i2c_client *client, int subaddr, int val) +{ + unsigned char buffer[2]; + d2printk("tda7432: In tda7432_write\n"); + dprintk("tda7432: Writing %d 0x%x\n", subaddr, val); + buffer[0] = subaddr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda7432: I/O error, trying (write %d 0x%x)\n", + subaddr, val); + return -1; + } + return 0; +} + +/* I don't think we ever actually _read_ the chip... */ +#if 0 +static int tda7432_read(struct i2c_client *client) +{ + unsigned char buffer; + d2printk("tda7432: In tda7432_read\n"); + if (1 != i2c_master_recv(client,&buffer,1)) { + printk(KERN_WARNING "tda7432: I/O error, trying (read)\n"); + return -1; + } + dprintk("tda7432: Read 0x%02x\n", buffer); + return buffer; +} +#endif + +static int tda7432_set(struct i2c_client *client) +{ + struct tda7432 *t = client->data; + unsigned char buf[16]; + d2printk("tda7432: In tda7432_set\n"); + + dprintk(KERN_INFO + "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + t->input,t->volume,t->tone,t->lf,t->lr,t->rf,t->rr,t->loud); + buf[0] = TDA7432_IN; + buf[1] = t->input; + buf[2] = t->volume; + buf[3] = t->tone; + buf[4] = t->lf; + buf[5] = t->lr; + buf[6] = t->rf; + buf[7] = t->rr; + buf[8] = t->loud; + if (9 != i2c_master_send(client,buf,9)) { + printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n"); + return -1; + } + + return 0; +} + +static void do_tda7432_init(struct i2c_client *client) +{ + struct tda7432 *t = client->data; + d2printk("tda7432: In tda7432_init\n"); + + t->input = TDA7432_STEREO_IN | /* Main (stereo) input */ + TDA7432_BASS_SYM | /* Symmetric bass cut */ + TDA7432_BASS_NORM; /* Normal bass range */ + t->volume = TDA7432_VOL_0DB; /* 0dB Volume */ + if (loudness) /* Turn loudness on? */ + t->volume |= TDA7432_LD_ON; + t->tone = TDA7432_TREBLE_0DB | /* 0dB Treble */ + TDA7432_BASS_0DB; /* 0dB Bass */ + t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ + t->lr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ + t->rf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ + t->rr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ + t->loud = loudness; /* insmod parameter */ + + tda7432_set(client); +} + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda7432_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda7432 *t; + struct i2c_client *client; + d2printk("tda7432: In tda7432_attach\n"); + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = t = kmalloc(sizeof *t,GFP_KERNEL); + if (!t) + return -ENOMEM; + memset(t,0,sizeof *t); + do_tda7432_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA7432"); + printk(KERN_INFO "tda7432: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda7432_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda7432_attach); + return 0; +} + +static int tda7432_detach(struct i2c_client *client) +{ + struct tda7432 *t = client->data; + + do_tda7432_init(client); + i2c_detach_client(client); + + kfree(t); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda7432_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda7432 *t = client->data; + d2printk("tda7432: In tda7432_command\n"); +#if 0 + __u16 *sarg = arg; +#endif + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + + /* Query card - scale from TDA7432 settings to V4L settings */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + dprintk("tda7432: VIDIOCGAUDIO\n"); + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + + /* Master volume control + * V4L volume is min 0, max 65535 + * TDA7432 Volume: + * Min (-79dB) is 0x6f + * Max (+20dB) is 0x07 + * (Mask out bit 7 of vol - it's for the loudness setting) + */ + + va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630; + + /* Balance depends on L,R attenuation + * V4L balance is 0 to 65535, middle is 32768 + * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f + * to scale up to V4L numbers, mult by 1057 + * attenuation exists for lf, lr, rf, rr + * we use only lf and rf (front channels) + */ + + if ( (t->lf) < (t->rf) ) + /* right is attenuated, balance shifted left */ + va->balance = (32768 - 1057*(t->rf)); + else + /* left is attenuated, balance shifted right */ + va->balance = (32768 + 1057*(t->lf)); + + /* Bass/treble */ + va->bass = 32768; /* brain hurts... set to middle for now */ + va->treble = 32768; /* brain hurts... set to middle for now */ + + break; /* VIDIOCGAUDIO case */ + } + + /* Set card - scale from V4L settings to TDA7432 settings */ + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + dprintk("tda7432: VIDEOCSAUDIO\n"); + + t->volume = 0x6f - ( (va->volume)/630 ); + + if (loudness) /* Turn on the loudness bit */ + t->volume |= TDA7432_LD_ON; + + if (va->balance < 32768) { + /* shifted to left, attenuate right */ + t->rr = (32768 - va->balance)/1057; + t->rf = t->rr; + } + else { + /* shifted to right, attenuate left */ + t->lf = (va->balance - 32768)/1057; + t->lr = t->lf; + } + + /* t->tone = 0xff; */ /* Brain hurts - no tone control for now... */ + + tda7432_write(client,TDA7432_VL, t->volume); + /* tda7432_write(client,TDA7432_TN, t->tone); */ + tda7432_write(client,TDA7432_LF, t->lf); + tda7432_write(client,TDA7432_LR, t->lr); + tda7432_write(client,TDA7432_RF, t->rf); + tda7432_write(client,TDA7432_RR, t->rr); + + break; + + } /* end of VIDEOCSAUDIO case */ + + default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ + + /* nothing */ + d2printk("tda7432: Default\n"); + + } /* end of (cmd) switch */ + + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda7432 driver", + I2C_DRIVERID_TDA7432, + I2C_DF_NOTIFY, + tda7432_probe, + tda7432_detach, + tda7432_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda7432_init(void) +#endif +{ + + if ( (loudness < 0) || (loudness > 15) ) + { + printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n"); + return -EINVAL; + } + + + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/char/tda8425.c b/drivers/char/tda8425.c index 73df0b4ac89a..a1dec22ebc5b 100644 --- a/drivers/char/tda8425.c +++ b/drivers/char/tda8425.c @@ -31,7 +31,6 @@ #include "audiochip.h" /* Addresses to scan */ -#define I2C_TDA8425 0x82 static unsigned short normal_i2c[] = { I2C_TDA8425 >> 1, I2C_CLIENT_END}; diff --git a/drivers/char/tda985x.c b/drivers/char/tda985x.c index 62bcf15ba2cd..73fb9bd52201 100644 --- a/drivers/char/tda985x.c +++ b/drivers/char/tda985x.c @@ -13,6 +13,7 @@ * * OPTIONS: * debug - set to 1 if you'd like to see debug messages + * - set to 2 if you'd like to be flooded with debug messages * chip - set to 9850 or 9855 to select your chip (default 9855) * * TODO: @@ -20,7 +21,8 @@ * and unmote to fix. - Is this still here? * Fine tune sound * Get rest of capabilities into video_audio struct... - * + * + * Revision 0.5 - cleaned up debugging messages, added debug level=2 * Revision: 0.4 - check for correct chip= insmod value * also cleaned up comments a bit * Revision: 0.3 - took out extraneous tda985x_write in tda985x_command @@ -55,9 +57,10 @@ static int chip = 9855; /* insmod parameter */ #define I2C_TDA985x_H 0xb6 static unsigned short normal_i2c[] = {I2C_CLIENT_END}; static unsigned short normal_i2c_range[] = { - I2C_TDA985x_L >> 1, - I2C_TDA985x_H >> 1, - I2C_CLIENT_END}; + I2C_TDA985x_L >> 1, + I2C_TDA985x_H >> 1, + I2C_CLIENT_END +}; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; @@ -84,6 +87,7 @@ static struct i2c_driver driver; static struct i2c_client client_template; #define dprintk if (debug) printk +#define d2printk if (debug == 2) printk /* The TDA9850 and TDA9855 are both made by Philips Semiconductor * http://www.semiconductors.philips.com @@ -154,9 +158,9 @@ static struct i2c_client client_template; #define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ #define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ #define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ - /* Bits 0 to 3 select various combinations - * of line in and line out, only the - * interesting ones are defined */ + /* Bits 0 to 3 select various combinations + * of line in and line out, only the + * interesting ones are defined */ #define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ #define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ @@ -213,8 +217,8 @@ static struct i2c_client client_template; static int tda985x_write(struct i2c_client *client, int subaddr, int val) { unsigned char buffer[2]; - dprintk("In tda985x_write\n"); - dprintk("Writing %d 0x%x\n", subaddr, val); + d2printk("tda985x: In tda985x_write\n"); + dprintk("tda985x: Writing %d 0x%x\n", subaddr, val); buffer[0] = subaddr; buffer[1] = val; if (2 != i2c_master_send(client,buffer,2)) { @@ -228,12 +232,12 @@ static int tda985x_write(struct i2c_client *client, int subaddr, int val) static int tda985x_read(struct i2c_client *client) { unsigned char buffer; - dprintk("In tda985x_read\n"); + d2printk("tda985x: In tda985x_read\n"); if (1 != i2c_master_recv(client,&buffer,1)) { printk(KERN_WARNING "tda985x: I/O error, trying (read)\n"); return -1; } - dprintk("Read 0x%02x\n", buffer); + dprintk("tda985x: Read 0x%02x\n", buffer); return buffer; } @@ -241,12 +245,12 @@ static int tda985x_set(struct i2c_client *client) { struct tda985x *t = client->data; unsigned char buf[16]; - dprintk("In tda985x_set\n"); + d2printk("tda985x: In tda985x_set\n"); if (chip == 9855) { dprintk(KERN_INFO - "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + "tda985x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", t->rvol,t->lvol,t->bass,t->treble,t->sub, t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); buf[0] = TDA9855_VR; @@ -262,7 +266,7 @@ static int tda985x_set(struct i2c_client *client) buf[10] = t->a2; buf[11] = t->a3; if (12 != i2c_master_send(client,buf,12)) { - printk(KERN_WARNING "tda9855: I/O error, trying tda985x_set\n"); + printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n"); return -1; } } @@ -270,7 +274,7 @@ static int tda985x_set(struct i2c_client *client) else if (chip == 9850) { dprintk(KERN_INFO - "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + "tda986x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", t->c4,t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); buf[0] = TDA9850_C4; buf[1] = t->c4; @@ -281,7 +285,7 @@ static int tda985x_set(struct i2c_client *client) buf[6] = t->a2; buf[7] = t->a3; if (8 != i2c_master_send(client,buf,8)) { - printk(KERN_WARNING "tda9850: I/O error, trying tda985x_set\n"); + printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n"); return -1; } } @@ -292,11 +296,11 @@ static int tda985x_set(struct i2c_client *client) static void do_tda985x_init(struct i2c_client *client) { struct tda985x *t = client->data; - dprintk("In tda985x_init\n"); + d2printk("tda985x: In tda985x_init\n"); if (chip == 9855) { - printk("Using tda9855 options\n"); + printk("tda985x: Using tda9855 options\n"); t->rvol = 0x6f; /* 0dB */ t->lvol = 0x6f; /* 0dB */ t->bass = 0x0e; /* 0dB */ @@ -313,7 +317,7 @@ static void do_tda985x_init(struct i2c_client *client) else if (chip == 9850) { - printk("Using tda9850 options\n"); + printk("tda985x: Using tda9850 options\n"); t->c4 = 0x08; /* Set stereo noise thresh to nominal */ t->c5 = 0x08; /* Set SAP noise threshold to nominal */ t->c6 = TDA985x_STEREO; /* Select Stereo mode for decoder */ @@ -337,7 +341,7 @@ static int tda985x_attach(struct i2c_adapter *adap, int addr, { struct tda985x *t; struct i2c_client *client; - dprintk("In tda985x_attach\n"); + d2printk("tda985x: In tda985x_attach\n"); client = kmalloc(sizeof *client,GFP_KERNEL); if (!client) return -ENOMEM; @@ -382,7 +386,7 @@ static int tda985x_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tda985x *t = client->data; - dprintk("In tda985x_command...\n"); + d2printk("tda985x: In tda985x_command\n"); #if 0 __u16 *sarg = arg; #endif @@ -394,7 +398,7 @@ static int tda985x_command(struct i2c_client *client, case VIDIOCGAUDIO: { struct video_audio *va = arg; - dprintk("VIDIOCGAUDIO\n"); + dprintk("tda985x: VIDIOCGAUDIO\n"); if (chip == 9855) { int left,right; @@ -430,7 +434,7 @@ static int tda985x_command(struct i2c_client *client, case VIDIOCSAUDIO: { struct video_audio *va = arg; - dprintk("VIDEOCSAUDIO...\n"); + dprintk("tda985x: VIDEOCSAUDIO\n"); if (chip == 9855) { int left,right; @@ -453,17 +457,17 @@ static int tda985x_command(struct i2c_client *client, switch (va->mode) { case VIDEO_SOUND_MONO: - dprintk("VIDEO_SOUND_MONO\n"); + dprintk("tda985x: VIDEO_SOUND_MONO\n"); t->c6= TDA985x_MONO | (t->c6 & 0x3f); tda985x_write(client,TDA985x_C6,t->c6); break; case VIDEO_SOUND_STEREO: - dprintk("VIDEO_SOUND_STEREO\n"); + dprintk("tda985x: VIDEO_SOUND_STEREO\n"); t->c6= TDA985x_STEREO | (t->c6 & 0x3f); tda985x_write(client,TDA985x_C6,t->c6); break; case VIDEO_SOUND_LANG1: - dprintk("VIDEO_SOUND_LANG1\n"); + dprintk("tda985x: VIDEO_SOUND_LANG1\n"); t->c6= TDA985x_SAP | (t->c6 & 0x3f); tda985x_write(client,TDA985x_C6,t->c6); break; @@ -476,7 +480,7 @@ static int tda985x_command(struct i2c_client *client, default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ /* nothing */ - dprintk("Default\n"); + d2printk("tda985x: Default\n"); } /* end of (cmd) switch */ diff --git a/drivers/char/tda9875.c b/drivers/char/tda9875.c new file mode 100644 index 000000000000..da3ceebfe621 --- /dev/null +++ b/drivers/char/tda9875.c @@ -0,0 +1,371 @@ +/* + * For the TDA9875 chip + * (The TDA9875 is used on the Diamond DTV2000 french version + * Other cards probably use these chips as well.) + * This driver will not complain if used with any + * other i2c device with the same address. + * + * Copyright (c) 2000 Guillamue Delvit based on Gerd Knorr source and + * Eric Sandeen + * This code is placed under the terms of the GNU General Public License + * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) + * Which was based on tda8425.c by Greg Alexander (c) 1998 + * + * OPTIONS: + * debug - set to 1 if you'd like to see debug messages + * + * Revision: 0.1 - original version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + +/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */ +#ifndef I2C_DRIVERID_TDA9875 + #define I2C_DRIVERID_TDA9875 28 +#endif + + +MODULE_PARM(debug,"i"); + +static int debug = 0; /* insmod parameter */ + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { + I2C_TDA9875 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +/* This is a superset of the TDA9875 */ +struct tda9875 { + int mode; + int rvol, lvol; + int bass, treble; +}; + + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define dprintk if (debug) printk + +/* The TDA9875 is made by Philips Semiconductor + * http://www.semiconductors.philips.com + * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator + * + */ + + /* subaddresses for TDA9875 */ +#define TDA9875_MUT 0x12 /*General mute (value --> 0b11001100*/ +#define TDA9875_CFG 0x01 /* Config register (value --> 0b00000000 */ +#define TDA9875_DACOS 0x13 /*DAC i/o select (ADC) 0b0000100*/ +#define TDA9875_LOSR 0x16 /*Line output select regirter 0b0100 0001*/ + +#define TDA9875_CH1V 0x0c /*Chanel 1 volume (mute)*/ +#define TDA9875_CH2V 0x0d /*Chanel 2 volume (mute)*/ +#define TDA9875_SC1 0x14 /*SCART 1 in (mono)*/ +#define TDA9875_SC2 0x15 /*SCART 2 in (mono)*/ + +#define TDA9875_ADCIS 0x17 /*ADC input select (mono) 0b0110 000*/ +#define TDA9875_AER 0x19 /*Audio effect (AVL+Pseudo) 0b0000 0110*/ +#define TDA9875_MCS 0x18 /*Main channel select (DAC) 0b0000100*/ +#define TDA9875_MVL 0x1a /* Main volume gauche */ +#define TDA9875_MVR 0x1b /* Main volume droite */ +#define TDA9875_MBA 0x1d /* Main Basse */ +#define TDA9875_MTR 0x1e /* Main treble */ +#define TDA9875_ACS 0x1f /* Auxilary channel select (FM) 0b0000000*/ +#define TDA9875_AVL 0x20 /* Auxilary volume gauche */ +#define TDA9875_AVR 0x21 /* Auxilary volume droite */ +#define TDA9875_ABA 0x22 /* Auxilary Basse */ +#define TDA9875_ATR 0x23 /* Auxilary treble */ + +#define TDA9875_MSR 0x02 /* Monitor select register */ +#define TDA9875_C1MSB 0x03 /* Carrier 1 (FM) frequency register MSB */ +#define TDA9875_C1MIB 0x04 /* Carrier 1 (FM) frequency register (16-8]b */ +#define TDA9875_C1LSB 0x05 /* Carrier 1 (FM) frequency register LSB */ +#define TDA9875_C2MSB 0x06 /* Carrier 2 (nicam) frequency register MSB */ +#define TDA9875_C2MIB 0x07 /* Carrier 2 (nicam) frequency register (16-8]b */ +#define TDA9875_C2LSB 0x08 /* Carrier 2 (nicam) frequency register LSB */ +#define TDA9875_DCR 0x09 /* Demodulateur configuration regirter*/ +#define TDA9875_DEEM 0x0a /* FM de-emphasis regirter*/ +#define TDA9875_FMAT 0x0b /* FM Matrix regirter*/ + +/* values */ +#define TDA9875_MUTE_ON 0xff /* general mute */ +#define TDA9875_MUTE_OFF 0xcc /* general no mute */ + + + +/* Begin code */ + +static int tda9875_write(struct i2c_client *client, int subaddr, int val) +{ + unsigned char buffer[2]; + dprintk("In tda9875_write\n"); + dprintk("Writing %d 0x%x\n", subaddr, val); + buffer[0] = subaddr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda9875: I/O error, trying (write %d 0x%x)\n", + subaddr, val); + return -1; + } + return 0; +} + +#if 0 +static int tda9875_read(struct i2c_client *client) +{ + unsigned char buffer; + dprintk("In tda9875_read\n"); + if (1 != i2c_master_recv(client,&buffer,1)) { + printk(KERN_WARNING "tda9875: I/O error, trying (read)\n"); + return -1; + } + dprintk("Read 0x%02x\n", buffer); + return buffer; +} +#endif + +static void tda9875_set(struct i2c_client *client) +{ + struct tda9875 *tda = client->data; + + dprintk(KERN_DEBUG "tda9875_set(%04x,%04x,%04x,%04x)\n",tda->lvol,tda->rvol,tda->bass,tda->treble); + tda9875_write(client, TDA9875_MVL, tda->lvol / 600 - 84); + tda9875_write(client, TDA9875_MVR, tda->rvol / 600 -84); + tda9875_write(client, TDA9875_MBA, tda->bass / 2340 -12); + tda9875_write(client, TDA9875_MTR, tda->treble / 2621 -12); +} + +static void do_tda9875_init(struct i2c_client *client) +{ + struct tda9875 *t = client->data; + dprintk("In tda9875_init\n"); + tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/ + tda9875_write(client, TDA9875_MSR, 0x03 ); /* Monitor 0b00000XXX*/ + tda9875_write(client, TDA9875_C1MSB, 0x00 ); /*Car1(FM) MSB XMHz*/ + tda9875_write(client, TDA9875_C1MIB, 0x00 ); /*Car1(FM) MIB XMHz*/ + tda9875_write(client, TDA9875_C1LSB, 0x00 ); /*Car1(FM) LSB XMHz*/ + tda9875_write(client, TDA9875_C2MSB, 0x00 ); /*Car2(NICAM) MSB XMHz*/ + tda9875_write(client, TDA9875_C2MIB, 0x00 ); /*Car2(NICAM) MIB XMHz*/ + tda9875_write(client, TDA9875_C2LSB, 0x00 ); /*Car2(NICAM) LSB XMHz*/ + tda9875_write(client, TDA9875_DCR, 0x00 ); /*Demod config 0x00*/ + tda9875_write(client, TDA9875_DEEM, 0x44 ); /*DE-Emph 0b0100 0100*/ + tda9875_write(client, TDA9875_FMAT, 0x00 ); /*FM Matrix reg 0x00*/ + tda9875_write(client, TDA9875_SC1, 0x00 ); /* SCART 1 (SC1)*/ + tda9875_write(client, TDA9875_SC2, 0x01 ); /* SCART 2 (sc2)*/ + + tda9875_write(client, TDA9875_CH1V, 0x10 ); /* Chanel volume 1 mute*/ + tda9875_write(client, TDA9875_CH2V, 0x10 ); /* Chanel volume 2 mute */ + tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/ + tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/ + tda9875_write(client, TDA9875_LOSR, 0x00 ); /* line out (in:mono)*/ + tda9875_write(client, TDA9875_AER, 0x00 ); /*06 Effect (AVL+PSEUDO) */ + tda9875_write(client, TDA9875_MCS, 0x44 ); /* Main ch select (DAC) */ + tda9875_write(client, TDA9875_MVL, 0x03 ); /* Vol Main left 10dB */ + tda9875_write(client, TDA9875_MVR, 0x03 ); /* Vol Main right 10dB*/ + tda9875_write(client, TDA9875_MBA, 0x00 ); /* Main Bass Main 0dB*/ + tda9875_write(client, TDA9875_MTR, 0x00 ); /* Main Treble Main 0dB*/ + tda9875_write(client, TDA9875_ACS, 0x44 ); /* Aux chan select (dac)*/ + tda9875_write(client, TDA9875_AVL, 0x00 ); /* Vol Aux left 0dB*/ + tda9875_write(client, TDA9875_AVR, 0x00 ); /* Vol Aux right 0dB*/ + tda9875_write(client, TDA9875_ABA, 0x00 ); /* Aux Bass Main 0dB*/ + tda9875_write(client, TDA9875_ATR, 0x00 ); /* Aux Aigus Main 0dB*/ + + tda9875_write(client, TDA9875_MUT, 0xcc ); /* General mute */ + + t->mode=AUDIO_MUTE; + t->lvol=t->rvol =51000; /* 0dB */ + t->bass=30420; /* 0dB */ + t->treble=34073; /* 0dB */ + tda9875_set(client); + +} + + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda9875_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda9875 *t; + struct i2c_client *client; + dprintk("In tda9875_attach\n"); + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = t = kmalloc(sizeof *t,GFP_KERNEL); + if (!t) + return -ENOMEM; + memset(t,0,sizeof *t); + do_tda9875_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA9875"); + printk(KERN_INFO "tda9875: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda9875_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda9875_attach); + return 0; +} + +static int tda9875_detach(struct i2c_client *client) +{ + struct tda9875 *t = client->data; + + do_tda9875_init(client); + i2c_detach_client(client); + + kfree(t); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda9875_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda9875 *t = client->data; + + dprintk("In tda9875_command...\n"); + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + int left,right; + + dprintk("VIDIOCGAUDIO\n"); + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + + /* min is -84 max is 24 */ + left = (t->lvol+85)*600; + right = (t->rvol+85)*600; + va->volume=MAX(left,right); + va->balance=(32768*MIN(left,right))/ + (va->volume ? va->volume : 1); + va->balance=(leftbalance) : va->balance; + va->bass = (t->bass+13)*2340; /* min -12 max +15 */ + va->treble = (t->treble+13)*2621;/* min -12 max +12 */ + + va->mode |= VIDEO_SOUND_MONO; + + + break; /* VIDIOCGAUDIO case */ + } + + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + int left,right; + + dprintk("VIDEOCSAUDIO...\n"); + left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + right = (MIN(va->balance,32768) * + va->volume) / 32768; + t->lvol = left/600-84; + t->rvol = right/600-84; + t->bass = va->bass/2340-12; + t->treble = va->treble/2621-12; + tda9875_set(client); + + break; + + } /* end of VIDEOCSAUDIO case */ + + default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ + + /* nothing */ + dprintk("Default\n"); + + } /* end of (cmd) switch */ + + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda9875 driver", + I2C_DRIVERID_TDA9875, /* Get new one for TDA9875 */ + I2C_DF_NOTIFY, + tda9875_probe, + tda9875_detach, + tda9875_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda9875_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/drivers/char/tea6420.c b/drivers/char/tea6420.c new file mode 100644 index 000000000000..231ed9e4e0fd --- /dev/null +++ b/drivers/char/tea6420.c @@ -0,0 +1,268 @@ +/* + * for the TEA6420 chip (only found on 3DFX (STB) TV/FM cards to the best + * of my knowledge) + * Copyright (C) 2000 Dave Stuart + * This code is placed under the terms of the GNU General Public License + * Code liberally copied from tea6300 by . . . + * + * Copyright (c) 1998 Greg Alexander + * This code is placed under the terms of the GNU General Public License + * Code liberally copied from msp3400.c, which is by Gerd Knorr + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "audiochip.h" + + +/* Addresses to scan */ +#define I2C_TEA6420 0x98 +static unsigned short normal_i2c[] = { + I2C_TEA6420 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + + +MODULE_PARM(debug,"i"); +static int debug = 0; /* insmod parameter */ + +#define dprintk if (debug) printk + + +struct tea6420 { + int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */ + int stereo; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define TEA6420_S_SA 0x00 /* stereo A input */ +#define TEA6420_S_SB 0x01 /* stereo B */ +#define TEA6420_S_SC 0x02 /* stereo C */ +#define TEA6420_S_SD 0x03 /* stereo D */ +#define TEA6420_S_SE 0x04 /* stereo E */ +#define TEA6420_S_GMU 0x05 /* general mute */ + + +/* ******************************** * + * functions for talking to TEA6420 * + * ******************************** */ + +static int tea6420_write(struct i2c_client *client, int val) +{ + unsigned char buffer[2]; + int result; + +/* buffer[0] = addr; */ + buffer[0] = val; + result = i2c_master_send(client,buffer,1); + if (1 != result) { + printk(KERN_WARNING "tea6420: I/O error, trying (write +0x%x) result = %d\n", val, result); + return -1; + } + return 0; +} + + +static void do_tea6420_init(struct i2c_client *client) +{ + struct tea6420 *tea = client->data; + + tea->mode=AUDIO_OFF; + tea->stereo=1; + tea6420_write(client, TEA6420_S_GMU); /* mute */ +} + +static void tea6420_audio(struct i2c_client *client, int mode) +{ + struct tea6420 *tea = client->data; + + /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */ + dprintk(KERN_DEBUG "tea6420_audio:%d (T,R,E,I,O)\n",mode); + tea->mode=mode; + if (mode==AUDIO_OFF) { /* just mute it */ + tea6420_write(client, TEA6420_S_GMU); + return; + } + switch(mode) { + case AUDIO_TUNER: + tea6420_write(client, TEA6420_S_SA); + break; + case AUDIO_RADIO: + tea6420_write(client, TEA6420_S_SB); + break; + case AUDIO_EXTERN: + tea6420_write(client, TEA6420_S_SC); + break; + } +} + + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tea6420_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tea6420 *tea; + struct i2c_client *client; + + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL); + if (!tea) + return -ENOMEM; + memset(tea,0,sizeof *tea); + do_tea6420_init(client); + + MOD_INC_USE_COUNT; + strcpy(client->name,"TEA6420"); + printk(KERN_INFO "tea6420: initialized\n"); + + i2c_attach_client(client); + return 0; +} + +static int tea6420_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tea6420_attach); + return 0; +} + +static int tea6420_detach(struct i2c_client *client) +{ + struct tea6420 *tea = client->data; + + do_tea6420_init(client); + i2c_detach_client(client); + + kfree(tea); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int +tea6420_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + __u16 *sarg = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + tea6420_audio(client,AUDIO_RADIO); + break; + case AUDC_SET_INPUT: + tea6420_audio(client,*sarg); + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; +/* va->volume=MAX(tea->left,tea->right); + va->balance=(32768*MIN(tea->left,tea->right))/ + (va->volume ? va->volume : 1); + va->balance=(tea->leftright)? + (65535-va->balance) : va->balance; + va->bass = tea->bass; + va->treble = tea->treble; +*/ break; + } + case VIDIOCSAUDIO: + { + +/* tea->left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + tea->right = (MIN(va->balance,32768) * + va->volume) / 32768; + tea->bass = va->bass; + tea->treble = va->treble; + tea6420_set(client); +*/ break; + } + +default: + /* nothing */ + } + return 0; +} + +static struct i2c_driver driver = { + "i2c tea6420 driver", + I2C_DRIVERID_TEA6420, + I2C_DF_NOTIFY, + tea6420_probe, + tea6420_detach, + tea6420_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tea6420_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/ide/Config.in b/drivers/ide/Config.in index 6d68bd5ea0f5..45e2da6b3532 100644 --- a/drivers/ide/Config.in +++ b/drivers/ide/Config.in @@ -12,6 +12,15 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE dep_mbool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK + + define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n + dep_mbool ' Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR + dep_mbool ' IMB Vendor Specific' CONFIG_BLK_DEV_IDEDISK_IBM $CONFIG_BLK_DEV_IDEDISK_VENDOR + dep_mbool ' Maxtor Vendor Specific' CONFIG_BLK_DEV_IDEDISK_MAXTOR $CONFIG_BLK_DEV_IDEDISK_VENDOR + dep_mbool ' Quantum Vendor Specific' CONFIG_BLK_DEV_IDEDISK_QUANTUM $CONFIG_BLK_DEV_IDEDISK_VENDOR + dep_mbool ' Seagate Vendor Specific' CONFIG_BLK_DEV_IDEDISK_SEAGATE $CONFIG_BLK_DEV_IDEDISK_VENDOR + dep_mbool ' Western Digital Vendor Specific' CONFIG_BLK_DEV_IDEDISK_WD $CONFIG_BLK_DEV_IDEDISK_VENDOR + dep_tristate ' PCMCIA IDE support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE diff --git a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c index 0158b427975b..75b3153b7ad1 100644 --- a/drivers/ide/aec62xx.c +++ b/drivers/ide/aec62xx.c @@ -176,6 +176,7 @@ struct chipset_bus_clock_list_entry { }; struct chipset_bus_clock_list_entry aec62xx_base [] = { +#ifdef CONFIG_BLK_DEV_IDEDMA { XFER_UDMA_4, 0x41, 0x04, 0x31, 0x05 }, { XFER_UDMA_3, 0x41, 0x03, 0x31, 0x04 }, { XFER_UDMA_2, 0x41, 0x02, 0x31, 0x03 }, @@ -185,7 +186,7 @@ struct chipset_bus_clock_list_entry aec62xx_base [] = { { XFER_MW_DMA_2, 0x41, 0x00, 0x31, 0x00 }, { XFER_MW_DMA_1, 0x42, 0x00, 0x31, 0x00 }, { XFER_MW_DMA_0, 0x7a, 0x00, 0x0a, 0x00 }, - +#endif /* CONFIG_BLK_DEV_IDEDMA */ { XFER_PIO_4, 0x41, 0x00, 0x31, 0x00 }, { XFER_PIO_3, 0x43, 0x00, 0x33, 0x00 }, { XFER_PIO_2, 0x78, 0x00, 0x08, 0x00 }, @@ -202,18 +203,22 @@ extern char *ide_xfer_verbose (byte xfer_rate); static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table) { + int bus_speed = system_bus_clock(); + for ( ; chipset_table->xfer_speed ; chipset_table++) if (chipset_table->xfer_speed == speed) { - return ((byte) ((1) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34)); + return ((byte) ((bus_speed <= 33) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34)); } return 0x00; } static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table) { + int bus_speed = system_bus_clock(); + for ( ; chipset_table->xfer_speed ; chipset_table++) if (chipset_table->xfer_speed == speed) { - return ((byte) ((1) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34)); + return ((byte) ((bus_speed <= 33) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34)); } return 0x00; } @@ -222,8 +227,6 @@ static int aec6210_tune_chipset (ide_drive_t *drive, byte speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - byte unit = (drive->select.b.unit & 0x01); - int drive_number = ((hwif->channel ? 2 : 0) + unit); int err = 0; unsigned short d_conf = 0x0000; byte ultra = 0x00; @@ -236,18 +239,18 @@ static int aec6210_tune_chipset (ide_drive_t *drive, byte speed) __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only */ - pci_read_config_word(dev, 0x40|(2*drive_number), &d_conf); + pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf); tmp0 = pci_bus_clock_list(speed, aec62xx_base); SPLIT_BYTE(tmp0,tmp1,tmp2); MAKE_WORD(d_conf,tmp1,tmp2); - pci_write_config_word(dev, 0x40|(2*drive_number), d_conf); + pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf); tmp1 = 0x00; tmp2 = 0x00; pci_read_config_byte(dev, 0x54, &ultra); - tmp1 = ((0x00 << (2*drive_number)) | (ultra & ~(3 << (2*drive_number)))); + tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn)))); ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base); - tmp2 = ((ultra_conf << (2*drive_number)) | (tmp1 & ~(3 << (2*drive_number)))); + tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn)))); pci_write_config_byte(dev, 0x54, tmp2); __restore_flags(flags); /* local CPU only */ @@ -261,7 +264,6 @@ static int aec6260_tune_chipset (ide_drive_t *drive, byte speed) ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; byte unit = (drive->select.b.unit & 0x01); - int drive_number = ((hwif->channel ? 2 : 0) + unit); byte ultra_pci = hwif->channel ? 0x45 : 0x44; int err = 0; byte drive_conf = 0x00; @@ -269,15 +271,14 @@ static int aec6260_tune_chipset (ide_drive_t *drive, byte speed) byte ultra = 0x00; byte tmp1 = 0x00; byte tmp2 = 0x00; - unsigned long flags; __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only */ - pci_read_config_byte(dev, 0x40|drive_number, &drive_conf); + pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf); drive_conf = pci_bus_clock_list(speed, aec62xx_base); - pci_write_config_byte(dev, 0x40|drive_number, drive_conf); + pci_write_config_byte(dev, 0x40|drive->dn, drive_conf); pci_read_config_byte(dev, ultra_pci, &ultra); tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit)))); @@ -286,10 +287,24 @@ static int aec6260_tune_chipset (ide_drive_t *drive, byte speed) pci_write_config_byte(dev, ultra_pci, tmp2); __restore_flags(flags); /* local CPU only */ + if (!drive->init_speed) + drive->init_speed = speed; + err = ide_config_drive_speed(drive, speed); + drive->current_speed = speed; return(err); } + +static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed) +{ + if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) { + return ((int) aec6210_tune_chipset(drive, speed)); + } else { + return ((int) aec6260_tune_chipset(drive, speed)); + } +} + #ifdef CONFIG_BLK_DEV_IDEDMA static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra) { @@ -524,7 +539,7 @@ void __init ide_init_aec62xx (ide_hwif_t *hwif) { #ifdef CONFIG_AEC62XX_TUNING hwif->tuneproc = &aec62xx_tune_drive; - + hwif->speedproc = &aec62xx_tune_chipset; #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) hwif->dmaproc = &aec62xx_dmaproc; diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c index c5f570674a10..02af0a0f801a 100644 --- a/drivers/ide/alim15x3.c +++ b/drivers/ide/alim15x3.c @@ -333,6 +333,7 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed) err = ide_config_drive_speed(drive, speed); +#ifdef CONFIG_BLK_DEV_IDEDMA if (speed >= XFER_SW_DMA_0) { unsigned long dma_base = hwif->dma_base; @@ -353,6 +354,9 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed) pci_write_config_byte(dev, 0x4b, tmpbyte); } } +#endif /* CONFIG_BLK_DEV_IDEDMA */ + + drive->current_speed = speed; return (err); } @@ -399,6 +403,9 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33) (void) ali15x3_tune_chipset(drive, speed); + if (!drive->init_speed) + drive->init_speed = speed; + rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : @@ -629,7 +636,7 @@ unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif) * has 80-pin (from host view) */ pci_read_config_byte(dev, 0x4a, &tmpbyte); - ata66 = (!(tmpbyte & ata66mask)) ? 0 : 1; + ata66 = (!(tmpbyte & ata66mask)) ? 1 : 0; __restore_flags(flags); return(ata66); @@ -673,6 +680,7 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif) hwif->tuneproc = &ali15x3_tune_drive; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; + hwif->speedproc = &ali15x3_tune_chipset; #ifndef CONFIG_BLK_DEV_IDEDMA hwif->autodma = 0; return; diff --git a/drivers/ide/amd7409.c b/drivers/ide/amd7409.c index 14a8a83f15c7..d54a240d4c93 100644 --- a/drivers/ide/amd7409.c +++ b/drivers/ide/amd7409.c @@ -81,21 +81,22 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed) struct pci_dev *dev = hwif->pci_dev; int err = 0; byte unit = (drive->select.b.unit & 0x01); - int drive_number = ((HWIF(drive)->channel ? 2 : 0) + unit); +#ifdef CONFIG_BLK_DEV_IDEDMA unsigned long dma_base = hwif->dma_base; +#endif /* CONFIG_BLK_DEV_IDEDMA */ byte drive_pci = 0x00; byte drive_pci2 = 0x00; byte ultra_timing = 0x00; byte dma_pio_timing = 0x00; byte pio_timing = 0x00; - switch (drive_number) { + switch (drive->dn) { case 0: drive_pci = 0x53; drive_pci2 = 0x4b; break; case 1: drive_pci = 0x52; drive_pci2 = 0x4a; break; case 2: drive_pci = 0x51; drive_pci2 = 0x49; break; case 3: drive_pci = 0x50; drive_pci2 = 0x48; break; default: - return ((int) ide_dma_off_quietly); + return -1; } pci_read_config_byte(dev, drive_pci, &ultra_timing); @@ -109,7 +110,7 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed) ultra_timing &= ~0xC7; dma_pio_timing &= ~0xFF; - pio_timing &= ~(0x03 << drive_number); + pio_timing &= ~(0x03 << drive->dn); #ifdef DEBUG printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ", @@ -117,67 +118,74 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed) #endif switch(speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_4: ultra_timing |= 0x45; dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; case XFER_UDMA_3: ultra_timing |= 0x44; dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; case XFER_UDMA_2: ultra_timing |= 0x40; dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; case XFER_UDMA_1: ultra_timing |= 0x41; dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; case XFER_UDMA_0: ultra_timing |= 0x42; dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; case XFER_MW_DMA_2: dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; case XFER_MW_DMA_1: dma_pio_timing |= 0x21; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; case XFER_MW_DMA_0: dma_pio_timing |= 0x77; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; +#endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: dma_pio_timing |= 0x20; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; case XFER_PIO_3: dma_pio_timing |= 0x22; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; case XFER_PIO_2: dma_pio_timing |= 0x42; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; case XFER_PIO_1: dma_pio_timing |= 0x65; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; case XFER_PIO_0: default: dma_pio_timing |= 0xA8; - pio_timing |= (0x03 << drive_number); + pio_timing |= (0x03 << drive->dn); break; } + if (!drive->init_speed) + drive->init_speed = speed; + +#ifdef CONFIG_BLK_DEV_IDEDMA pci_write_config_byte(dev, drive_pci, ultra_timing); +#endif /* CONFIG_BLK_DEV_IDEDMA */ pci_write_config_byte(dev, drive_pci2, dma_pio_timing); pci_write_config_byte(dev, 0x4c, pio_timing); @@ -186,12 +194,16 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed) ultra_timing, dma_pio_timing, pio_timing); #endif +#ifdef CONFIG_BLK_DEV_IDEDMA if (speed > XFER_PIO_4) { outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); } else { outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); } +#endif /* CONFIG_BLK_DEV_IDEDMA */ + err = ide_config_drive_speed(drive, speed); + drive->current_speed = speed; return (err); } @@ -231,6 +243,7 @@ static void config_chipset_for_pio (ide_drive_t *drive) break; } (void) amd7409_tune_chipset(drive, speed); + drive->current_speed = speed; } static void amd7409_tune_drive (ide_drive_t *drive, byte pio) @@ -403,13 +416,14 @@ unsigned int __init ata66_amd7409 (ide_hwif_t *hwif) void __init ide_init_amd7409 (ide_hwif_t *hwif) { hwif->tuneproc = &amd7409_tune_drive; + hwif->speedproc = &amd7409_tune_chipset; #ifndef CONFIG_BLK_DEV_IDEDMA hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; hwif->autodma = 0; return; -#endif /* CONFIG_BLK_DEV_IDEDMA */ +#else if (hwif->dma_base) { hwif->dmaproc = &amd7409_dmaproc; @@ -419,6 +433,7 @@ void __init ide_init_amd7409 (ide_hwif_t *hwif) hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } +#endif /* CONFIG_BLK_DEV_IDEDMA */ } void ide_dmacapable_amd7409 (ide_hwif_t *hwif, unsigned long dmabase) diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c index 8e100de3c20a..7e9f0c7eecb9 100644 --- a/drivers/ide/cmd64x.c +++ b/drivers/ide/cmd64x.c @@ -344,9 +344,9 @@ static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed) (void) ide_config_drive_speed(drive, speed); } -#ifdef CONFIG_BLK_DEV_IDEDMA -static int tune_chipset_for_dma (ide_drive_t *drive, byte speed) +static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; byte unit = (drive->select.b.unit & 0x01); @@ -357,6 +357,8 @@ static int tune_chipset_for_dma (ide_drive_t *drive, byte speed) u8 regU = 0; u8 regD = 0; + if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) return 1; + (void) pci_read_config_byte(dev, pciD, ®D); (void) pci_read_config_byte(dev, pciU, ®U); regD &= ~(unit ? 0x40 : 0x20); @@ -378,17 +380,37 @@ static int tune_chipset_for_dma (ide_drive_t *drive, byte speed) case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break; case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break; case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break; +#else + int err = 0; + + switch(speed) { +#endif /* CONFIG_BLK_DEV_IDEDMA */ + case XFER_PIO_4: cmd64x_tuneproc(drive, 4); break; + case XFER_PIO_3: cmd64x_tuneproc(drive, 3); break; + case XFER_PIO_2: cmd64x_tuneproc(drive, 2); break; + case XFER_PIO_1: cmd64x_tuneproc(drive, 1); break; + case XFER_PIO_0: cmd64x_tuneproc(drive, 0); break; + default: return 1; } +#ifdef CONFIG_BLK_DEV_IDEDMA (void) pci_write_config_byte(dev, pciU, regU); +#endif /* CONFIG_BLK_DEV_IDEDMA */ + err = ide_config_drive_speed(drive, speed); + + drive->current_speed = speed; + +#ifdef CONFIG_BLK_DEV_IDEDMA regD |= (unit ? 0x40 : 0x20); (void) pci_write_config_byte(dev, pciD, regD); +#endif /* CONFIG_BLK_DEV_IDEDMA */ return err; } +#ifdef CONFIG_BLK_DEV_IDEDMA static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) { struct hd_driveid *id = drive->id; @@ -450,12 +472,15 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul set_pio = 1; } + if (!drive->init_speed) + drive->init_speed = speed; + config_chipset_for_pio(drive, set_pio); if (set_pio) return ((int) ide_dma_off_quietly); - if (tune_chipset_for_dma(drive, speed)) + if (cmd64x_tune_chipset(drive, speed)) return ((int) ide_dma_off); rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : @@ -680,8 +705,9 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif) class_rev &= 0xff; hwif->tuneproc = &cmd64x_tuneproc; + hwif->speedproc = &cmd64x_tune_chipset; hwif->drives[0].autotune = 1; - hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; if (!hwif->dma_base) return; diff --git a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c index a68e7f7408af..911068f78461 100644 --- a/drivers/ide/hpt34x.c +++ b/drivers/ide/hpt34x.c @@ -96,14 +96,13 @@ extern char *ide_xfer_verbose (byte xfer_rate); static void hpt34x_clear_chipset (ide_drive_t *drive) { - int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); unsigned int reg1 = 0, tmp1 = 0; unsigned int reg2 = 0, tmp2 = 0; pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1); pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); - tmp1 = ((0x00 << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number)))); - tmp2 = (reg2 & ~(0x11 << drive_number)); + tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); + tmp2 = (reg2 & ~(0x11 << drive->dn)); pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); } @@ -112,7 +111,6 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed) { int err; byte hi_speed, lo_speed; - int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); unsigned int reg1 = 0, tmp1 = 0; unsigned int reg2 = 0, tmp2 = 0; @@ -127,20 +125,24 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed) pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, ®1); pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, ®2); - tmp1 = ((lo_speed << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number)))); - tmp2 = ((hi_speed << drive_number) | reg2); + tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); + tmp2 = ((hi_speed << drive->dn) | reg2); err = ide_config_drive_speed(drive, speed); pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1); pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2); + if (!drive->init_speed) + drive->init_speed = speed; + #if HPT343_DEBUG_DRIVE_INFO printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \ " (0x%02x 0x%02x) 0x%04x\n", drive->name, ide_xfer_verbose(speed), - drive_number, reg1, tmp1, reg2, tmp2, + drive->dn, reg1, tmp1, reg2, tmp2, hi_speed, lo_speed, err); #endif /* HPT343_DEBUG_DRIVE_INFO */ + drive->current_speed = speed; return(err); } @@ -410,6 +412,7 @@ unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name) void __init ide_init_hpt34x (ide_hwif_t *hwif) { hwif->tuneproc = &hpt34x_tune_drive; + hwif->speedproc = &hpt34x_tune_chipset; #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c index fd5971ef9649..28232b5768dc 100644 --- a/drivers/ide/hpt366.c +++ b/drivers/ide/hpt366.c @@ -173,6 +173,14 @@ extern char *ide_xfer_verbose (byte xfer_rate); byte hpt363_shared_irq = 0; byte hpt363_shared_pin = 0; +static unsigned int pci_rev_check_hpt366 (struct pci_dev *dev) +{ + unsigned int class_rev; + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; + return ((int) (class_rev == 0x03) ? 1 : 0); +} + static int check_in_drive_lists (ide_drive_t *drive, const char **list) { struct hd_driveid *id = drive->id; @@ -212,9 +220,6 @@ static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_lis static int hpt366_tune_chipset (ide_drive_t *drive, byte speed) { int err; -#if HPT366_DEBUG_DRIVE_INFO - int drive_number = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); -#endif /* HPT366_DEBUG_DRIVE_INFO */ byte regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40; unsigned int reg1 = 0; unsigned int reg2 = 0; @@ -251,11 +256,15 @@ static int hpt366_tune_chipset (ide_drive_t *drive, byte speed) pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2); err = ide_config_drive_speed(drive, speed); + if (!drive->init_speed) + drive->init_speed = speed; + #if HPT366_DEBUG_DRIVE_INFO printk("%s: speed=0x%02x(%s), drive%d, old=0x%08x, new=0x%08x, err=0x%04x\n", drive->name, speed, ide_xfer_verbose(speed), - drive_number, reg1, reg2, err); + drive->dn, reg1, reg2, err); #endif /* HPT366_DEBUG_DRIVE_INFO */ + drive->current_speed = speed; return(err); } @@ -469,10 +478,12 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) case ide_dma_check: return config_drive_xfer_rate(drive); case ide_dma_lostirq: +#if 0 pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); pci_write_config_byte(HWIF(drive)->pci_dev, 0x50, reg50h|0x03); pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); /* ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); */ +#endif case ide_dma_timeout: default: break; @@ -508,6 +519,8 @@ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name) if (!hpt366_proc) { hpt366_proc = 1; bmide_dev = dev; + if (pci_rev_check_hpt366(dev)) + bmide2_dev = dev; hpt366_display_info = &hpt366_get_info; } if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) { @@ -533,7 +546,11 @@ unsigned int __init ata66_hpt366 (ide_hwif_t *hwif) void __init ide_init_hpt366 (ide_hwif_t *hwif) { + if (pci_rev_check_hpt366(hwif->pci_dev)) return; + hwif->tuneproc = &hpt366_tune_drive; + hwif->speedproc = &hpt366_tune_chipset; + #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { hwif->dmaproc = &hpt366_dmaproc; @@ -556,6 +573,11 @@ void ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase) byte dma_new = 0, dma_old = inb(dmabase+2); unsigned long flags; + if (pci_rev_check_hpt366(hwif->pci_dev)) { + ide_setup_dma(hwif, dmabase, 8); + return; + } + __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only */ diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c index 8ef0f9356e1b..dcc50362faae 100644 --- a/drivers/ide/icside.c +++ b/drivers/ide/icside.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -219,55 +220,73 @@ static iftype_t icside_identifyif (struct expansion_card *ec) * here, but we rely on the main IDE driver spotting that both * interfaces use the same IRQ, which should guarantee this. */ -#define TABLE_SIZE 2048 +#define NR_ENTRIES 256 +#define TABLE_SIZE (NR_ENTRIES * 8) -static int -icside_build_dmatable(ide_drive_t *drive, int reading) +static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq) { - struct request *rq = HWGROUP(drive)->rq; - struct buffer_head *bh = rq->bh; - unsigned long addr, size; - unsigned char *virt_addr; - unsigned int count = 0; - dmasg_t *sg = (dmasg_t *)HWIF(drive)->dmatable_cpu; + struct buffer_head *bh; + struct scatterlist *sg = hwif->sg_table; + int nents = 0; + if (rq->cmd == READ) + hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; + else + hwif->sg_dma_direction = PCI_DMA_TODEVICE; + bh = rq->bh; do { - if (bh == NULL) { - /* paging requests have (rq->bh == NULL) */ - virt_addr = rq->buffer; - addr = virt_to_bus (virt_addr); - size = rq->nr_sectors << 9; - } else { - /* group sequential buffers into one large buffer */ - virt_addr = bh->b_data; - addr = virt_to_bus (virt_addr); - size = bh->b_size; - while ((bh = bh->b_reqnext) != NULL) { - if ((addr + size) != virt_to_bus (bh->b_data)) - break; - size += bh->b_size; - } - } + unsigned char *virt_addr = bh->b_data; + unsigned int size = bh->b_size; - if (addr & 3) { - printk("%s: misaligned DMA buffer\n", drive->name); - return 0; + while ((bh = bh->b_reqnext) != NULL) { + if ((virt_addr + size) != (unsigned char *)bh->b_data) + break; + size += bh->b_size; } + memset(&sg[nents], 0, sizeof(*sg)); + sg[nents].address = virt_addr; + sg[nents].length = size; + nents++; + } while (bh != NULL); - if (size) { - if (reading) - dma_cache_inv((unsigned int)virt_addr, size); - else - dma_cache_wback((unsigned int)virt_addr, size); - } + return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction); +} - sg[count].address = addr; - sg[count].length = size; - if (++count >= (TABLE_SIZE / sizeof(dmasg_t))) { - printk("%s: DMA table too small\n", drive->name); +static int +icside_build_dmatable(ide_drive_t *drive, int reading) +{ + dmasg_t *ide_sg = (dmasg_t *)HWIF(drive)->dmatable_cpu; + unsigned int count = 0; + int i; + struct scatterlist *sg; + + HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq); + + sg = HWIF(drive)->sg_table; + while (i && sg_dma_len(sg)) { + u32 cur_addr; + u32 cur_len; + + cur_addr = sg_dma_address(sg); + cur_len = sg_dma_len(sg); + + if (count >= (TABLE_SIZE / sizeof(dmasg_t))) { + printk("%s: DMA table too small\n", + drive->name); + pci_unmap_sg(NULL, + HWIF(drive)->sg_table, + HWIF(drive)->sg_nents, + HWIF(drive)->sg_dma_direction); return 0; + } else { + ide_sg[count].address = cur_addr; + ide_sg[count].length = cur_len; } - } while (bh != NULL); + + count++; + sg++; + i--; + } if (!count) printk("%s: empty DMA table?\n", drive->name); @@ -275,6 +294,15 @@ icside_build_dmatable(ide_drive_t *drive, int reading) return count; } +/* Teardown mappings after DMA has completed. */ +static void icside_destroy_dmatable(ide_drive_t *drive) +{ + struct scatterlist *sg = HWIF(drive)->sg_table; + int nents = HWIF(drive)->sg_nents; + + pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction); +} + static int icside_config_if(ide_drive_t *drive, int xfer_mode) { @@ -303,6 +331,9 @@ icside_config_if(ide_drive_t *drive, int xfer_mode) break; } + if (!drive->init_speed) + drive->init_speed = (byte) xfer_mode; + if (drive->drive_data && ide_config_drive_speed(drive, (byte) xfer_mode) == 0) func = ide_dma_on; @@ -312,9 +343,17 @@ icside_config_if(ide_drive_t *drive, int xfer_mode) printk("%s: %s selected (peak %dMB/s)\n", drive->name, ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); + drive->current_speed = (byte) xfer_mode; + return func; } +static int +icside_set_speed(ide_drive_t *drive, byte speed) +{ + return ((int) icside_config_if(drive, (int) speed)); +} + static int icside_dma_check(ide_drive_t *drive) { @@ -415,6 +454,7 @@ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive) case ide_dma_end: drive->waiting_for_dma = 0; disable_dma(hwif->hw.dma); + icside_destroy_dmatable(drive); return get_dma_residue(hwif->hw.dma) != 0; case ide_dma_test_irq: @@ -425,8 +465,7 @@ icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive) } } -static unsigned long -icside_alloc_dmatable(void) +static void *icside_alloc_dmatable(void) { static unsigned long dmatable; static unsigned int leftover; @@ -448,28 +487,39 @@ icside_alloc_dmatable(void) leftover -= TABLE_SIZE; } - return table; + return (void *)table; } static int icside_setup_dma(ide_hwif_t *hwif, int autodma) { - unsigned long table = icside_alloc_dmatable(); - printk(" %s: SG-DMA", hwif->name); - if (!table) - printk(" -- ERROR, unable to allocate DMA table\n"); - else { - hwif->dmatable_cpu = (void *)table; - hwif->dmaproc = icside_dmaproc; - hwif->autodma = autodma; + hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES, + GFP_KERNEL); + if (!hwif->sg_table) + goto failed; + + hwif->dmatable_cpu = icside_alloc_dmatable(); - printk(" capable%s\n", autodma ? - ", auto-enable" : ""); + if (!hwif->dmatable_cpu) { + kfree(hwif->sg_table); + hwif->sg_table = NULL; + goto failed; } - return hwif->dmatable_cpu != NULL; + hwif->dmaproc = &icside_dmaproc; + hwif->autodma = autodma; + hwif->speedproc = &icside_set_speed; + + printk(" capable%s\n", autodma ? + ", auto-enable" : ""); + + return 1; + +failed: + printk(" -- ERROR, unable to allocate DMA table\n"); + return 0; } #endif diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 66bf35a70c0d..4e2952018049 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -33,8 +33,6 @@ #undef REALLY_SLOW_IO /* most systems can safely undef this */ -#define _IDE_DISK_C /* Tell linux/hdsmart.h it's really us */ - #include #include #include @@ -688,13 +686,12 @@ static int set_multcount(ide_drive_t *drive, int arg) static int set_nowerr(ide_drive_t *drive, int arg) { - unsigned long flags; - - if (ide_spin_wait_hwgroup(drive, &flags)) + if (ide_spin_wait_hwgroup(drive)) return -EBUSY; + drive->nowerr = arg; drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irq(&io_request_lock); return 0; } @@ -713,7 +710,7 @@ static void idedisk_add_settings(ide_drive_t *drive) ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL); ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); - + ide_add_setting(drive, "lun", SETTING_RW, -1, -1, TYPE_INT, 0, 7, 1, 1, &drive->lun, NULL); } /* diff --git a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c index 371f57ad8dbe..fcf0aab63377 100644 --- a/drivers/ide/ide-features.c +++ b/drivers/ide/ide-features.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -108,6 +109,46 @@ char *ide_dmafunc_verbose (ide_dma_action_t dmafunc) } } +/* + * + */ +byte ide_auto_reduce_xfer (ide_drive_t *drive) +{ + switch(drive->current_speed) { + case XFER_UDMA_7: return XFER_UDMA_6; + case XFER_UDMA_6: return XFER_UDMA_5; + case XFER_UDMA_5: return XFER_UDMA_4; + case XFER_UDMA_4: return XFER_UDMA_3; + case XFER_UDMA_3: return XFER_UDMA_2; + case XFER_UDMA_2: return XFER_UDMA_1; + case XFER_UDMA_1: return XFER_UDMA_0; + case XFER_UDMA_0: + if (drive->id->dma_mword & 0x0004) return XFER_MW_DMA_2; + else if (drive->id->dma_mword & 0x0002) return XFER_MW_DMA_1; + else if (drive->id->dma_mword & 0x0001) return XFER_MW_DMA_0; + else return XFER_PIO_4; + case XFER_MW_DMA_2: return XFER_MW_DMA_1; + case XFER_MW_DMA_1: return XFER_MW_DMA_0; + case XFER_MW_DMA_0: + if (drive->id->dma_1word & 0x0004) return XFER_SW_DMA_2; + else if (drive->id->dma_1word & 0x0002) return XFER_SW_DMA_1; + else if (drive->id->dma_1word & 0x0001) return XFER_SW_DMA_0; + else return XFER_PIO_4; + case XFER_SW_DMA_2: return XFER_SW_DMA_1; + case XFER_SW_DMA_1: return XFER_SW_DMA_0; + case XFER_SW_DMA_0: + { + return XFER_PIO_4; + } + case XFER_PIO_4: return XFER_PIO_3; + case XFER_PIO_3: return XFER_PIO_2; + case XFER_PIO_2: return XFER_PIO_1; + case XFER_PIO_1: return XFER_PIO_0; + case XFER_PIO_0: + default: return XFER_PIO_SLOW; + } +} + /* * Update the */ @@ -136,8 +177,10 @@ int ide_driveid_update (ide_drive_t *drive) ide_delay_50ms(); /* give drive a breather */ } while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT); ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */ - if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) + if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) { + printk("%s: CHECK for good STATUS\n", drive->name); return 0; + } __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only; some systems need this */ id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC); @@ -146,17 +189,14 @@ int ide_driveid_update (ide_drive_t *drive) ide__sti(); /* local CPU only */ __restore_flags(flags); /* local CPU only */ ide_fix_driveid(id); - if (id && id->cyls) { + if (id) { drive->id->dma_ultra = id->dma_ultra; drive->id->dma_mword = id->dma_mword; drive->id->dma_1word = id->dma_1word; /* anything more ? */ -#ifdef DEBUG - printk("%s: dma_ultra=%04X, dma_mword=%04X, dma_1word=%04X\n", - drive->name, id->dma_ultra, id->dma_mword, id->dma_1word); -#endif kfree(id); } + return 1; } @@ -167,7 +207,7 @@ int ide_driveid_update (ide_drive_t *drive) * in combination with the device (usually a disk) properly detect * and acknowledge each end of the ribbon. */ -int ide_ata66_check (ide_drive_t *drive, int cmd, int nsect, int feature) +int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature) { if ((cmd == WIN_SETFEATURES) && (nsect > XFER_UDMA_2) && @@ -189,15 +229,16 @@ int ide_ata66_check (ide_drive_t *drive, int cmd, int nsect, int feature) * 1 : Safe to update drive->id DMA registers. * 0 : OOPs not allowed. */ -int set_transfer (ide_drive_t *drive, int cmd, int nsect, int feature) +int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature) { - struct hd_driveid *id = drive->id; - if ((cmd == WIN_SETFEATURES) && (nsect >= XFER_SW_DMA_0) && (feature == SETFEATURES_XFER) && - (id->dma_ultra || id->dma_mword || id->dma_1word)) + (drive->id->dma_ultra || + drive->id->dma_mword || + drive->id->dma_1word)) return 1; + return 0; } @@ -219,6 +260,8 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed) byte unit = (drive->select.b.unit & 0x01); byte stat; + outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); + /* * Don't use ide_wait_cmd here - it will * attempt to set_geometry and recalibrate, @@ -307,6 +350,7 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed) return error; } +EXPORT_SYMBOL(ide_auto_reduce_xfer); EXPORT_SYMBOL(ide_driveid_update); EXPORT_SYMBOL(ide_ata66_check); EXPORT_SYMBOL(set_transfer); diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c index 8d999d91c618..c10ae4b51cbf 100644 --- a/drivers/ide/ide-pci.c +++ b/drivers/ide/ide-pci.c @@ -30,6 +30,7 @@ #define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1}) #define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB}) #define DEVID_PIIX4E ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1}) +#define DEVID_PIIX4E2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1}) #define DEVID_PIIX4U ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1}) #define DEVID_PIIX4U2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1}) #define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561}) @@ -303,6 +304,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = { {DEVID_PIIX3, "PIIX3", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4E, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4E2, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4U, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4U2, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, @@ -476,6 +478,7 @@ static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t * unsigned short pcicmd = 0, tried_config = 0; byte tmp = 0; ide_hwif_t *hwif, *mate = NULL; + unsigned int class_rev; #ifdef CONFIG_IDEDMA_AUTO autodma = 1; @@ -504,6 +507,11 @@ check_if_enabled: } if (tried_config) printk("%s: device enabled (Linux)\n", d->name); + + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; + printk("%s: chipset revision %d\n", d->name, class_rev); + /* * Can we trust the reported IRQ? */ @@ -545,7 +553,7 @@ check_if_enabled: ide_pci_enablebit_t *e = &(d->enablebits[port]); if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val)) continue; /* port not enabled */ - if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port)) + if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port) && (class_rev != 0x03)) return; if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) { ctl = dev->resource[(2*port)+1].start; @@ -656,9 +664,19 @@ static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_devic struct pci_dev *dev2 = NULL, *findev; ide_pci_device_t *d2; unsigned char pin1 = 0, pin2 = 0; + unsigned int class_rev; if (PCI_FUNC(dev->devfn) & 1) return; + + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + class_rev &= 0xff; + + switch(class_rev) { + case 3: return; + default: break; + } + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); pci_for_each_dev(findev) { if ((findev->vendor == dev->vendor) && diff --git a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c index 7f5226db9db1..45bbe77ac130 100644 --- a/drivers/ide/ide-pmac.c +++ b/drivers/ide/ide-pmac.c @@ -7,6 +7,8 @@ * * Copyright (C) 1998 Paul Mackerras. * + * Bits from Benjamin Herrenschmidt + * * 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 @@ -16,12 +18,6 @@ * * Copyright (c) 1995-1998 Mark Lord * - * BenH: I began adding more complete timing setup code, mostly because DMA - * won't work on new machines unless timings are setup correctly. This - * code was mainly stolen from Cmd646 driver and should be completed to - * include real timing calc. instead of hard coded values. The format of - * the timing register can be found in Darwin's source code, except for - * Keylargo ATA-4 controller. */ #include #include @@ -44,14 +40,18 @@ #endif #include "ide_modes.h" +extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); + #undef IDE_PMAC_DEBUG -#define IDE_SYSCLK_NS 30 +#define IDE_SYSCLK_NS 30 +#define IDE_SYSCLK_ULTRA_PS 0x1d4c /* (15 * 1000 / 2)*/ struct pmac_ide_hwif { ide_ioreg_t regbase; int irq; int kind; + int aapl_bus_id; struct device_node* node; u32 timings[2]; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC @@ -90,17 +90,27 @@ static pmac_ide_timing mdma_timings[] = static pmac_ide_timing udma_timings[] = { { 0, 114 }, /* Mode 0 */ - { 0, 73 }, /* 1 */ - { 0, 54 }, /* 2 */ - { 0, 39 }, /* 3 */ - { 0, 25 } /* 4 */ + { 0, 75 }, /* 1 */ + { 0, 55 }, /* 2 */ + { 100, 45 }, /* 3 */ + { 100, 25 } /* 4 */ }; -#define MAX_DCMDS 256 /* allow up to 256 DBDMA commands per xfer */ +/* allow up to 256 DBDMA commands per xfer */ +#define MAX_DCMDS 256 + +/* Wait 1.5s for disk to answer on IDE bus after + * enable operation. + * NOTE: There is at least one case I know of a disk that needs about 10sec + * before anwering on the bus. I beleive we could add a kernel command + * line arg to override this delay for such cases. + */ +#define IDE_WAKEUP_DELAY_MS 1500 static void pmac_ide_setup_dma(struct device_node *np, int ix); static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive); static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr); +static int pmac_ide_tune_chipset(ide_drive_t *drive, byte speed); static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio); static void pmac_ide_selectproc(ide_drive_t *drive); @@ -156,14 +166,6 @@ void pmac_ide_init_hwif_ports(hw_regs_t *hw, return; } - /* we check only for -EINVAL meaning that we have found a matching - bay but with the wrong device type */ - i = check_media_bay_by_base(data_port, MB_CD); - if (i == -EINVAL) { - hw->io_ports[IDE_DATA_OFFSET] = 0; - return; - } - for (i = 0; i < 8; ++i) hw->io_ports[i] = data_port + i * 0x10; hw->io_ports[8] = data_port + 0x160; @@ -178,6 +180,7 @@ void pmac_ide_init_hwif_ports(hw_regs_t *hw, #ifdef CONFIG_PMAC_IDEDMA_AUTO ide_hwifs[ix].autodma = 1; #endif +// ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset; } } @@ -214,7 +217,9 @@ pmac_ide_selectproc(ide_drive_t *drive) /* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */ #define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS) +#define SYSCLK_TICKS_UDMA(t) (((t) + IDE_SYSCLK_ULTRA_PS - 1) / IDE_SYSCLK_ULTRA_PS) +/* Calculate PIO timings */ static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio) { @@ -227,26 +232,31 @@ pmac_ide_tuneproc(ide_drive_t *drive, byte pio) if (i < 0) return; - /* The "ata-4" IDE controller of UMA machines is a bit different. - * We don't do anything for PIO modes until we know how to do the - * calculation. - */ - if (pmac_ide[i].kind == controller_kl_ata4) - return; - pio = ide_get_best_pio_mode(drive, pio, 4, &d); accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time); - if (accessTicks < 4) - accessTicks = 4; - recTicks = SYSCLK_TICKS(d.cycle_time) - accessTicks - 4; - if (recTicks < 1) - recTicks = 1; if (drive->select.all & 0x10) timings = &pmac_ide[i].timings[1]; else timings = &pmac_ide[i].timings[0]; - *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5); + if (pmac_ide[i].kind == controller_kl_ata4) { + /* The "ata-4" IDE controller of Core99 machines */ + accessTicks = SYSCLK_TICKS_UDMA(ide_pio_timings[pio].active_time * 1000); + recTicks = SYSCLK_TICKS_UDMA(d.cycle_time * 1000) - accessTicks; + + *timings = ((*timings) & 0x1FFFFFC00) | accessTicks | (recTicks << 5); + } else { + /* The old "ata-3" IDE controller */ + accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time); + if (accessTicks < 4) + accessTicks = 4; + recTicks = SYSCLK_TICKS(d.cycle_time) - accessTicks - 4; + if (recTicks < 1) + recTicks = 1; + + *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5); + } + #ifdef IDE_PMAC_DEBUG printk("ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n", pio, *timings); @@ -294,7 +304,7 @@ pmac_ide_probe(void) struct device_node *atas; struct device_node *p, **pp, *removables, **rp; unsigned long base; - int irq; + int irq, big_delay; ide_hwif_t *hwif; if (_machine != _MACH_Pmac) @@ -322,9 +332,11 @@ pmac_ide_probe(void) } *rp = NULL; *pp = removables; + big_delay = 0; for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) { struct device_node *tp; + int *bidp; /* * If this node is not under a mac-io or dbdma node, @@ -378,6 +390,9 @@ pmac_ide_probe(void) else pmac_ide[i].kind = controller_ohare; + bidp = (int *)get_property(np, "AAPL,bus-id", NULL); + pmac_ide[i].aapl_bus_id = bidp ? *bidp : 0; + if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) { media_bay_set_ide_infos(np->parent,base,irq,i); @@ -388,42 +403,41 @@ pmac_ide_probe(void) */ feature_set(np, FEATURE_IDE0_enable); } else { - /* This is necessary to enable IDE when net-booting */ - int *bidp = (int *)get_property(np, "AAPL,bus-id", NULL); - int bid = bidp ? *bidp : 0; - printk("pmac_ide: enabling IDE bus ID %d\n", bid); - switch(bid) { + /* This is necessary to enable IDE when net-booting */ + printk("pmac_ide: enabling IDE bus ID %d\n", + pmac_ide[i].aapl_bus_id); + switch(pmac_ide[i].aapl_bus_id) { case 0: feature_set(np, FEATURE_IDE0_reset); - feature_set(np, FEATURE_IOBUS_enable); mdelay(10); feature_set(np, FEATURE_IDE0_enable); mdelay(10); feature_clear(np, FEATURE_IDE0_reset); break; case 1: - feature_set(np, FEATURE_Mediabay_IDE_reset); + feature_set(np, FEATURE_IDE1_reset); mdelay(10); - feature_set(np, FEATURE_Mediabay_IDE_enable); + feature_set(np, FEATURE_IDE1_enable); mdelay(10); - feature_clear(np, FEATURE_Mediabay_IDE_reset); + feature_clear(np, FEATURE_IDE1_reset); break; case 2: - /* This one exists only for KL, I don't know about any - enable bit */ + /* This one exists only for KL, I don't know + about any enable bit */ feature_set(np, FEATURE_IDE2_reset); mdelay(10); feature_clear(np, FEATURE_IDE2_reset); break; } - mdelay(1000); + big_delay = 1; } hwif = &ide_hwifs[i]; pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); hwif->chipset = ide_pmac; - hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; + hwif->noprobe = (!hwif->io_ports[IDE_DATA_OFFSET]) || + (check_media_bay_by_base(base, MB_CD) == -EINVAL); #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC if (np->n_addrs >= 2) { @@ -435,6 +449,8 @@ pmac_ide_probe(void) ++i; } pmac_ide_count = i; + if (big_delay) + mdelay(IDE_WAKEUP_DELAY_MS); #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&idepmac_sleep_notifier); @@ -642,6 +658,7 @@ out: return result; } +/* Calculate MultiWord DMA timings */ static int pmac_ide_mdma_enable(ide_drive_t *drive, int idx) { @@ -652,18 +669,15 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx) int accessTicks, recTicks; struct hd_driveid *id = drive->id; - /* For now, we don't know these values */ - if (pmac_ide[idx].kind == controller_kl_ata4 && feature != IDE_DMA2_ENABLE) - return 0; - if (pmac_ide[idx].kind != controller_kl_ata4 && feature == IDE_DMA0_ENABLE) - return 0; - /* Set feature on drive */ printk("%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf); if (pmac_ide_do_setfeature(drive, feature)) { printk("%s: Failed !\n", drive->name); return 0; } + + if (!drive->init_speed) + drive->init_speed = feature; /* which drive is it ? */ if (drive->select.all & 0x10) @@ -681,7 +695,10 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx) /* For ata-4 controller, we don't know the calculation */ if (pmac_ide[idx].kind == controller_kl_ata4) { - *timings = 0x00019465; /* MDMA2 */ + accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); + recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks; + *timings = ((*timings) & 0xffe003ff) | + (accessTicks | (recTicks << 5)) << 10; } else { int halfTick = 0; int origAccessTime = accessTime; @@ -696,7 +713,9 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx) recTicks = 1; cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS; - if ((accessTicks > 1) && + /* KeyLargo ata-3 don't support the half-tick stuff */ + if ((pmac_ide[idx].kind != controller_kl_ata3) && + (accessTicks > 1) && ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) && ((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) { halfTick = 1; @@ -708,21 +727,21 @@ pmac_ide_mdma_enable(ide_drive_t *drive, int idx) #ifdef IDE_PMAC_DEBUG printk("ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n", feature & 0xf, *timings); -#endif +#endif + drive->current_speed = feature; return 1; } +/* Calculate Ultra DMA timings */ static int pmac_ide_udma_enable(ide_drive_t *drive, int idx) { byte bits = drive->id->dma_ultra & 0x1f; byte feature = udma_bits_to_command(bits); - u32 timings; + int cycleTime, accessTime; + int rdyToPauseTicks, cycleTicks; + u32 *timings; - /* We support only those values */ - if (feature != IDE_UDMA4_ENABLE && feature != IDE_UDMA2_ENABLE) - return 0; - /* Set feature on drive */ printk("%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf); if (pmac_ide_do_setfeature(drive, feature)) { @@ -730,23 +749,25 @@ pmac_ide_udma_enable(ide_drive_t *drive, int idx) return 0; } - /* Put this channel into UDMA mode. - * This value is set by MacOS on the iBook for U/DMA2 - */ - switch(feature) { - case IDE_UDMA4_ENABLE: - timings = 0x0cd00065; - break; - case IDE_UDMA2_ENABLE: - timings = 0x11100065; - break; - } - + if (!drive->init_speed) + drive->init_speed = feature; + + /* which drive is it ? */ if (drive->select.all & 0x10) - pmac_ide[idx].timings[1] = timings; + timings = &pmac_ide[idx].timings[1]; else - pmac_ide[idx].timings[0] = timings; - + timings = &pmac_ide[idx].timings[0]; + + cycleTime = udma_timings[feature & 0xf].cycleTime; + accessTime = udma_timings[feature & 0xf].accessTime; + + rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); + cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000); + + *timings = ((*timings) & 0xe00fffff) | + ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20; + + drive->current_speed = feature; return 1; } @@ -792,6 +813,12 @@ pmac_ide_dma_onoff(ide_drive_t *drive, int enable) return 0; } +static int +pmac_ide_tune_chipset(ide_drive_t *drive, byte speed) +{ + return 0; +} + int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -813,6 +840,7 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) pmac_ide_dma_onoff(drive, (func == ide_dma_on)); break; case ide_dma_check: + printk("IDE-DMA check !\n"); if (hwif->autodma) pmac_ide_dma_onoff(drive, 1); break; @@ -837,8 +865,21 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) return (dstat & (RUN|DEAD|ACTIVE)) != RUN; case ide_dma_test_irq: return (in_le32(&dma->status) & (RUN|ACTIVE)) == RUN; + + /* Let's implement tose just in case someone wants them */ + case ide_dma_bad_drive: + case ide_dma_good_drive: + return check_drive_lists(drive, (func == ide_dma_good_drive)); + case ide_dma_verbose: + return report_drive_dmaing(drive); + case ide_dma_retune: + case ide_dma_lostirq: + case ide_dma_timeout: + printk("ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func); + return 1; default: - printk(KERN_ERR "pmac_ide_dmaproc: bad func %d\n", func); + printk("ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func); + return 1; } return 0; } @@ -869,8 +910,20 @@ static void idepmac_sleep_disk(int i, unsigned long base) } } feature_set(np, FEATURE_IDE0_reset); - feature_clear(np, FEATURE_IOBUS_enable); feature_clear(np, FEATURE_IDE0_enable); + switch(pmac_ide[i].aapl_bus_id) { + case 0: + feature_set(np, FEATURE_IDE0_reset); + feature_clear(np, FEATURE_IDE0_enable); + break; + case 1: + feature_set(np, FEATURE_IDE1_reset); + feature_clear(np, FEATURE_IDE1_enable); + break; + case 2: + feature_set(np, FEATURE_IDE2_reset); + break; + } pmac_ide[i].timings[0] = 0; pmac_ide[i].timings[1] = 0; } @@ -881,12 +934,30 @@ static void idepmac_wake_disk(int i, unsigned long base) int j; /* Revive IDE disk and controller */ - feature_set(np, FEATURE_IOBUS_enable); - mdelay(10); - feature_set(np, FEATURE_IDE0_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE0_reset); - mdelay(100); + switch(pmac_ide[i].aapl_bus_id) { + case 0: + feature_set(np, FEATURE_IDE0_reset); + mdelay(10); + feature_set(np, FEATURE_IDE0_enable); + mdelay(10); + feature_clear(np, FEATURE_IDE0_reset); + break; + case 1: + feature_set(np, FEATURE_IDE1_reset); + mdelay(10); + feature_set(np, FEATURE_IDE1_enable); + mdelay(10); + feature_clear(np, FEATURE_IDE1_reset); + break; + case 2: + /* This one exists only for KL, I don't know + about any enable bit */ + feature_set(np, FEATURE_IDE2_reset); + mdelay(10); + feature_clear(np, FEATURE_IDE2_reset); + break; + } + mdelay(IDE_WAKEUP_DELAY_MS); /* Reset timings */ pmac_ide_selectproc(&ide_hwifs[i].drives[0]); @@ -940,7 +1011,7 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) /* Disable irq during sleep */ disable_irq(pmac_ide[i].irq); ret = check_media_bay_by_base(base, MB_CD); - if (ret == -ENODEV) + if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present) /* not media bay - put the disk to sleep */ idepmac_sleep_disk(i, base); } @@ -953,7 +1024,7 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) hwif = &ide_hwifs[i]; /* We don't handle media bay devices this way */ ret = check_media_bay_by_base(base, MB_CD); - if (ret == -ENODEV) + if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present) idepmac_wake_disk(i, base); else if (ret == 0) idepmac_wake_bay(i, base); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 7c5130e77f5f..83b14b1fd7d3 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -56,6 +56,11 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ ide__sti(); /* local CPU only */ ide_fix_driveid(id); + + if (id->word156 == 0x4d42) { + printk("%s: drive->id->word156 == 0x%04x \n", drive->name, drive->id->word156); + } + if (!drive->forced_lun) drive->last_lun = id->last_lun & 0x7; #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA) @@ -764,9 +769,10 @@ static void init_gendisk (ide_hwif_t *hwif) char name[64]; ide_add_generic_settings(hwif->drives + unit); + hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit); sprintf (name, "host%d/bus%d/target%d/lun%d", (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index, - hwif->channel, unit, 0); + hwif->channel, unit, hwif->drives[unit].lun); hwif->drives[unit].de = devfs_mk_dir (ide_devfs_handle, name, 0, NULL); } @@ -775,9 +781,9 @@ static void init_gendisk (ide_hwif_t *hwif) static int hwif_init (ide_hwif_t *hwif) { - ide_drive_t *drive; - void (*rfn)(request_queue_t *); - + request_queue_t *q; + unsigned int unit; + if (!hwif->present) return 0; if (!hwif->irq) { @@ -795,39 +801,7 @@ static int hwif_init (ide_hwif_t *hwif) #endif /* CONFIG_BLK_DEV_HD */ hwif->present = 0; /* we set it back to 1 if all is ok below */ - switch (hwif->major) { - case IDE0_MAJOR: rfn = &do_ide0_request; break; -#if MAX_HWIFS > 1 - case IDE1_MAJOR: rfn = &do_ide1_request; break; -#endif -#if MAX_HWIFS > 2 - case IDE2_MAJOR: rfn = &do_ide2_request; break; -#endif -#if MAX_HWIFS > 3 - case IDE3_MAJOR: rfn = &do_ide3_request; break; -#endif -#if MAX_HWIFS > 4 - case IDE4_MAJOR: rfn = &do_ide4_request; break; -#endif -#if MAX_HWIFS > 5 - case IDE5_MAJOR: rfn = &do_ide5_request; break; -#endif -#if MAX_HWIFS > 6 - case IDE6_MAJOR: rfn = &do_ide6_request; break; -#endif -#if MAX_HWIFS > 7 - case IDE7_MAJOR: rfn = &do_ide7_request; break; -#endif -#if MAX_HWIFS > 8 - case IDE8_MAJOR: rfn = &do_ide8_request; break; -#endif -#if MAX_HWIFS > 9 - case IDE9_MAJOR: rfn = &do_ide9_request; break; -#endif - default: - printk("%s: request_fn NOT DEFINED\n", hwif->name); - return (hwif->present = 0); - } + if (devfs_register_blkdev (hwif->major, hwif->name, ide_fops)) { printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major); return (hwif->present = 0); @@ -860,19 +834,11 @@ static int hwif_init (ide_hwif_t *hwif) read_ahead[hwif->major] = 8; /* (4kB) */ hwif->present = 1; /* success */ - /* - * FIXME(eric) - This needs to be tested. I *think* that this - * is correct. Also, I believe that there is no longer any - * reason to have multiple functions (do_ide[0-7]_request) - * functions - the queuedata field could be used to indicate - * the correct hardware group - either this, or we could add - * a new field to request_queue_t to hold this information. - */ - drive = &hwif->drives[0]; - blk_init_queue(&drive->queue, rfn); - - drive = &hwif->drives[1]; - blk_init_queue(&drive->queue, rfn); + for (unit = 0; unit < MAX_DRIVES; ++unit) { + q = &hwif->drives[unit].queue; + q->queuedata = hwif->hwgroup; + blk_init_queue(q, do_ide_request); + } #if (DEBUG_SPINLOCK > 0) { diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 039c0bfd9fbf..cb34d354478e 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -321,6 +321,7 @@ int drive_is_flashcard (ide_drive_t *drive) || !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */ || !strncmp(id->model, "SunDisk SDCFB", 13) /* SunDisk */ || !strncmp(id->model, "HAGIWARA HPC", 12) /* Hagiwara */ + || !strncmp(id->model, "LEXAR ATA_FLASH", 15) /* Lexar */ || !strncmp(id->model, "ATA_FLASH", 9)) /* Simple Tech */ { return 1; /* yes, it is a flash memory card */ @@ -767,6 +768,18 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) args[1] = err; args[2] = IN_BYTE(IDE_NSECTOR_REG); } + } else if (rq->cmd == IDE_DRIVE_TASK) { + byte *args = (byte *) rq->buffer; + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + if (args) { + args[0] = stat; + args[1] = err; + args[2] = IN_BYTE(IDE_NSECTOR_REG); + args[3] = IN_BYTE(IDE_SECTOR_REG); + args[4] = IN_BYTE(IDE_LCYL_REG); + args[5] = IN_BYTE(IDE_HCYL_REG); + args[6] = IN_BYTE(IDE_SELECT_REG); + } } spin_lock_irqsave(&io_request_lock, flags); blkdev_dequeue_request(rq); @@ -876,7 +889,7 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat) if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; /* retry only "normal" I/O: */ - if (rq->cmd == IDE_DRIVE_CMD) { + if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return ide_stopped; @@ -1036,7 +1049,20 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, by static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) { byte *args = rq->buffer; - if (args) { + if (args && rq->cmd == IDE_DRIVE_TASK) { + +#ifdef DEBUG + printk("%s: DRIVE_TASK_CMD data=x%02x cmd=0x%02x fr=0x%02x ns=0x%02x sc=0x%02x lcyl=0x%02x hcyl=0x%02x sel=0x%02x\n", + drive->name, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); +#endif + OUT_BYTE(args[1], IDE_FEATURE_REG); + OUT_BYTE(args[3], IDE_SECTOR_REG); + OUT_BYTE(args[4], IDE_LCYL_REG); + OUT_BYTE(args[5], IDE_HCYL_REG); + OUT_BYTE(args[6], IDE_SELECT_REG); + ide_cmd(drive, args[0], args[2], &drive_cmd_intr); + return ide_started; + } else if (args) { #ifdef DEBUG printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n", drive->name, args[0], args[1], args[2], args[3]); @@ -1116,7 +1142,7 @@ static ide_startstop_t start_request (ide_drive_t *drive) return startstop; } if (!drive->special.all) { - if (rq->cmd == IDE_DRIVE_CMD) { + if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) { return execute_drive_cmd(drive, rq); } if (drive->driver != NULL) { @@ -1225,7 +1251,7 @@ repeat: * the driver. This makes the driver much more friendlier to shared IRQs * than previous designs, while remaining 100% (?) SMP safe and capable. */ -static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) +static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq) { ide_drive_t *drive; ide_hwif_t *hwif; @@ -1313,73 +1339,13 @@ request_queue_t *ide_get_queue (kdev_t dev) return &hwif->drives[DEVICE_NR(dev) & 1].queue; } -void do_ide0_request (request_queue_t *q) -{ - ide_do_request (ide_hwifs[0].hwgroup, 0); -} - -#if MAX_HWIFS > 1 -void do_ide1_request (request_queue_t *q) -{ - ide_do_request (ide_hwifs[1].hwgroup, 0); -} -#endif /* MAX_HWIFS > 1 */ - -#if MAX_HWIFS > 2 -void do_ide2_request (request_queue_t *q) -{ - ide_do_request (ide_hwifs[2].hwgroup, 0); -} -#endif /* MAX_HWIFS > 2 */ - -#if MAX_HWIFS > 3 -void do_ide3_request (request_queue_t *q) -{ - ide_do_request (ide_hwifs[3].hwgroup, 0); -} -#endif /* MAX_HWIFS > 3 */ - -#if MAX_HWIFS > 4 -void do_ide4_request (request_queue_t *q) -{ - ide_do_request (ide_hwifs[4].hwgroup, 0); -} -#endif /* MAX_HWIFS > 4 */ - -#if MAX_HWIFS > 5 -void do_ide5_request (request_queue_t *q) -{ - ide_do_request (ide_hwifs[5].hwgroup, 0); -} -#endif /* MAX_HWIFS > 5 */ - -#if MAX_HWIFS > 6 -void do_ide6_request (request_queue_t *q) -{ - ide_do_request (ide_hwifs[6].hwgroup, 0); -} -#endif /* MAX_HWIFS > 6 */ - -#if MAX_HWIFS > 7 -void do_ide7_request (request_queue_t *q) -{ - ide_do_request (ide_hwifs[7].hwgroup, 0); -} -#endif /* MAX_HWIFS > 7 */ - -#if MAX_HWIFS > 8 -void do_ide8_request (request_queue_t *q) -{ - ide_do_request (ide_hwifs[8].hwgroup, 0); -} -#endif /* MAX_HWIFS > 8 */ - -#if MAX_HWIFS > 9 -void do_ide9_request (request_queue_t *q) +/* + * Passes the stuff to ide_do_request + */ +void do_ide_request(request_queue_t *q) { - ide_do_request (ide_hwifs[9].hwgroup, 0); + ide_do_request(q->queuedata, 0); } -#endif /* MAX_HWIFS > 9 */ /* * ide_timer_expiry() is our timeout function for all drive operations. @@ -1656,16 +1622,8 @@ ide_drive_t *get_info_ptr (kdev_t i_rdev) */ void ide_init_drive_cmd (struct request *rq) { - rq->buffer = NULL; + memset(rq, 0, sizeof(*rq)); rq->cmd = IDE_DRIVE_CMD; - rq->sector = 0; - rq->nr_sectors = 0; - rq->nr_segments = 0; - rq->current_nr_sectors = 0; - rq->sem = NULL; - rq->bh = NULL; - rq->bhtail = NULL; - rq->q = NULL; } /* @@ -2049,8 +2007,10 @@ void ide_unregister (unsigned int index) hwgroup->hwif = HWIF(hwgroup->drive); #ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->dma_base) + if (hwif->dma_base) { (void) ide_release_dma(hwif); + hwif->dma_base = 0; + } #endif /* CONFIG_BLK_DEV_IDEDMA */ /* @@ -2083,6 +2043,7 @@ void ide_unregister (unsigned int index) init_hwif_data (index); /* restore hwif data to pristine status */ hwif->hwgroup = old_hwif.hwgroup; hwif->tuneproc = old_hwif.tuneproc; + hwif->speedproc = old_hwif.speedproc; hwif->selectproc = old_hwif.selectproc; hwif->resetproc = old_hwif.resetproc; hwif->dmaproc = old_hwif.dmaproc; @@ -2103,7 +2064,7 @@ void ide_unregister (unsigned int index) hwif->pci_devid = old_hwif.pci_devid; #endif /* CONFIG_BLK_DEV_IDEPCI */ hwif->straight8 = old_hwif.straight8; - + hwif->hwif_data = old_hwif.hwif_data; abort: restore_flags(flags); /* all CPUs */ } @@ -2304,24 +2265,24 @@ int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting) return val; } -int ide_spin_wait_hwgroup (ide_drive_t *drive, unsigned long *flags) +int ide_spin_wait_hwgroup (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); unsigned long timeout = jiffies + (3 * HZ); - spin_lock_irqsave(&io_request_lock, *flags); + spin_lock_irq(&io_request_lock); while (hwgroup->busy) { - unsigned long lflags; - spin_unlock_irqrestore(&io_request_lock, *flags); - __save_flags(lflags); /* local CPU only */ + unsigned long flags; + spin_unlock_irq(&io_request_lock); + __save_flags(flags); /* local CPU only */ __sti(); /* local CPU only; needed for jiffies */ if (0 < (signed long)(jiffies - timeout)) { - __restore_flags(lflags); /* local CPU only */ + __restore_flags(flags); printk("%s: channel busy\n", drive->name); return -EBUSY; } - __restore_flags(lflags); /* local CPU only */ - spin_lock_irqsave(&io_request_lock, *flags); + __restore_flags(flags); /* local CPU only */ + spin_lock_irq(&io_request_lock); } return 0; } @@ -2333,7 +2294,6 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive, unsigned long *flags) */ int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val) { - unsigned long flags; int i; u32 *p; @@ -2345,7 +2305,7 @@ int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val) return -EINVAL; if (setting->set) return setting->set(drive, val); - if (ide_spin_wait_hwgroup(drive, &flags)) + if (ide_spin_wait_hwgroup(drive)) return -EBUSY; switch (setting->data_type) { case TYPE_BYTE: @@ -2363,7 +2323,7 @@ int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val) *p = val; break; } - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irq(&io_request_lock); return 0; } @@ -2416,6 +2376,9 @@ void ide_add_generic_settings (ide_drive_t *drive) ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL); ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma); ide_add_setting(drive, "ide_scsi", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, NULL); + ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 69, 1, 1, &drive->init_speed, NULL); + ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 69, 1, 1, &drive->current_speed, NULL); + ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL); } int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf) @@ -2435,6 +2398,16 @@ int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int secto return ide_do_drive_cmd(drive, &rq, ide_wait); } +int ide_wait_cmd_task (ide_drive_t *drive, byte *buf) +{ + struct request rq; + + ide_init_drive_cmd(&rq); + rq.cmd = IDE_DRIVE_TASK; + rq.buffer = buf; + return ide_do_drive_cmd(drive, &rq, ide_wait); +} + /* * Delay for *at least* 50ms. As we don't know how much time is left * until the next tick occurs, we wait an extra tick to be safe. @@ -2551,6 +2524,7 @@ static int ide_ioctl (struct inode *inode, struct file *file, case HDIO_DRIVE_CMD: { byte args[4], *argbuf = args; + byte xfer_rate = 0; int argsize = 4; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (NULL == (void *) arg) @@ -2564,18 +2538,22 @@ static int ide_ioctl (struct inode *inode, struct file *file, return -ENOMEM; memcpy(argbuf, args, 4); } - if (ide_ata66_check(drive, args[0], args[1], args[2])) - goto abort; + + if (set_transfer(drive, args[0], args[1], args[2])) { + xfer_rate = args[1]; + if (ide_ata66_check(drive, args[0], args[1], args[2])) + goto abort; + } err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf); - if (!err && set_transfer(drive, args[0], args[1], args[2])) { -#if 0 + if (!err && xfer_rate) { /* active-retuning-calls future */ - if (HWIF(drive)->tune2proc) - HWIF(drive)->tune2proc(drive, args[1]); -#endif + if ((HWIF(drive)->speedproc) != NULL) + HWIF(drive)->speedproc(drive, xfer_rate); ide_driveid_update(drive); + } else { + printk("%s: \n", drive->name); } abort: if (copy_to_user((void *)arg, argbuf, argsize)) @@ -2584,6 +2562,18 @@ static int ide_ioctl (struct inode *inode, struct file *file, kfree(argbuf); return err; } + case HDIO_DRIVE_TASK: + { + byte args[7], *argbuf = args; + int argsize = 7; + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (copy_from_user(args, (void *)arg, 7)) + return -EFAULT; + err = ide_wait_cmd_task(drive, argbuf); + if (copy_to_user((void *)arg, argbuf, argsize)) + err = -EFAULT; + return err; + } case HDIO_SCAN_HWIF: { @@ -3512,37 +3502,9 @@ EXPORT_SYMBOL(ide_timer_expiry); EXPORT_SYMBOL(ide_intr); EXPORT_SYMBOL(ide_fops); EXPORT_SYMBOL(ide_get_queue); -EXPORT_SYMBOL(do_ide0_request); EXPORT_SYMBOL(ide_add_generic_settings); EXPORT_SYMBOL(ide_devfs_handle); -#if MAX_HWIFS > 1 -EXPORT_SYMBOL(do_ide1_request); -#endif /* MAX_HWIFS > 1 */ -#if MAX_HWIFS > 2 -EXPORT_SYMBOL(do_ide2_request); -#endif /* MAX_HWIFS > 2 */ -#if MAX_HWIFS > 3 -EXPORT_SYMBOL(do_ide3_request); -#endif /* MAX_HWIFS > 3 */ -#if MAX_HWIFS > 4 -EXPORT_SYMBOL(do_ide4_request); -#endif /* MAX_HWIFS > 4 */ -#if MAX_HWIFS > 5 -EXPORT_SYMBOL(do_ide5_request); -#endif /* MAX_HWIFS > 5 */ -#if MAX_HWIFS > 6 -EXPORT_SYMBOL(do_ide6_request); -#endif /* MAX_HWIFS > 6 */ -#if MAX_HWIFS > 7 -EXPORT_SYMBOL(do_ide7_request); -#endif /* MAX_HWIFS > 7 */ -#if MAX_HWIFS > 8 -EXPORT_SYMBOL(do_ide8_request); -#endif /* MAX_HWIFS > 8 */ -#if MAX_HWIFS > 9 -EXPORT_SYMBOL(do_ide9_request); -#endif /* MAX_HWIFS > 9 */ - +EXPORT_SYMBOL(do_ide_request); /* * Driver module */ @@ -3567,6 +3529,7 @@ EXPORT_SYMBOL(ide_end_request); EXPORT_SYMBOL(ide_revalidate_disk); EXPORT_SYMBOL(ide_cmd); EXPORT_SYMBOL(ide_wait_cmd); +EXPORT_SYMBOL(ide_wait_cmd_task); EXPORT_SYMBOL(ide_delay_50ms); EXPORT_SYMBOL(ide_stall_queue); #ifdef CONFIG_PROC_FS @@ -3652,8 +3615,13 @@ void cleanup_module (void) { int index; - for (index = 0; index < MAX_HWIFS; ++index) + for (index = 0; index < MAX_HWIFS; ++index) { ide_unregister(index); +#ifdef CONFIG_BLK_DEV_IDEDMA + if (ide_hwifs[index].dma_base) + (void) ide_release_dma(&ide_hwifs[index]); +#endif /* CONFIG_BLK_DEV_IDEDMA */ + } #ifdef CONFIG_PROC_FS proc_ide_destroy(); diff --git a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c index b93c6ad1b672..f16d33921435 100644 --- a/drivers/ide/pdc202xx.c +++ b/drivers/ide/pdc202xx.c @@ -262,59 +262,99 @@ static void decode_registers (byte registers, byte value) #endif /* PDC202XX_DECODE_REGISTER_INFO */ -/* 0 1 2 3 4 5 6 7 8 - * 960, 480, 390, 300, 240, 180, 120, 90, 60 - * 180, 150, 120, 90, 60 - * DMA_Speed - * 180, 120, 90, 90, 90, 60, 30 - * 11, 5, 4, 3, 2, 1, 0 - */ -static int config_chipset_for_pio (ide_drive_t *drive, byte pio) +static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - byte drive_pci, speed; - byte AP, BP, TA, TB; - int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - int err; + unsigned int drive_conf; + int err; + byte drive_pci, AP, BP, CP, DP; + byte TA = 0, TB = 0, TC = 0; - switch (drive_number) { + switch (drive->dn) { case 0: drive_pci = 0x60; break; case 1: drive_pci = 0x64; break; case 2: drive_pci = 0x68; break; case 3: drive_pci = 0x6c; break; - default: return 1; + default: return -1; } + if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) return -1; + + pci_read_config_dword(dev, drive_pci, &drive_conf); pci_read_config_byte(dev, (drive_pci), &AP); pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + pci_read_config_byte(dev, (drive_pci)|0x02, &CP); + pci_read_config_byte(dev, (drive_pci)|0x03, &DP); +#ifdef CONFIG_BLK_DEV_IDEDMA + if (speed >= XFER_SW_DMA_0) { + if ((BP & 0xF0) && (CP & 0x0F)) { + /* clear DMA modes of upper 842 bits of B Register */ + /* clear PIO forced mode upper 1 bit of B Register */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0xF0); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + + /* clear DMA modes of lower 8421 bits of C Register */ + pci_write_config_byte(dev, (drive_pci)|0x02, CP & ~0x0F); + pci_read_config_byte(dev, (drive_pci)|0x02, &CP); + } + } else { +#else + { +#endif /* CONFIG_BLK_DEV_IDEDMA */ + if ((AP & 0x0F) || (BP & 0x07)) { + /* clear PIO modes of lower 8421 bits of A Register */ + pci_write_config_byte(dev, (drive_pci), AP & ~0x0F); + pci_read_config_byte(dev, (drive_pci), &AP); - if ((AP & 0x0F) || (BP & 0x07)) { - /* clear PIO modes of lower 8421 bits of A Register */ - pci_write_config_byte(dev, (drive_pci), AP & ~0x0F); - pci_read_config_byte(dev, (drive_pci), &AP); + /* clear PIO modes of lower 421 bits of B Register */ + pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - /* clear PIO modes of lower 421 bits of B Register */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + pci_read_config_byte(dev, (drive_pci), &AP); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + } + } - pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + pci_read_config_byte(dev, (drive_pci), &AP); + pci_read_config_byte(dev, (drive_pci)|0x01, &BP); + pci_read_config_byte(dev, (drive_pci)|0x02, &CP); + + switch(speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA + case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; /* speed 8 == UDMA mode 4 */ + case XFER_UDMA_3: TB = 0x40; TC = 0x02; break; /* speed 7 == UDMA mode 3 */ + case XFER_UDMA_2: TB = 0x20; TC = 0x01; break; /* speed 6 == UDMA mode 2 */ + case XFER_UDMA_1: TB = 0x40; TC = 0x02; break; /* speed 5 == UDMA mode 1 */ + case XFER_UDMA_0: TB = 0x60; TC = 0x03; break; /* speed 4 == UDMA mode 0 */ + case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break; /* speed 4 == MDMA mode 2 */ + case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break; /* speed 3 == MDMA mode 1 */ + case XFER_MW_DMA_0: TB = 0x60; TC = 0x05; break; /* speed 2 == MDMA mode 0 */ + case XFER_SW_DMA_2: TB = 0x60; TC = 0x05; break; /* speed 0 == SDMA mode 2 */ + case XFER_SW_DMA_1: TB = 0x80; TC = 0x06; break; /* speed 1 == SDMA mode 1 */ + case XFER_SW_DMA_0: TB = 0xC0; TC = 0x0B; break; /* speed 0 == SDMA mode 0 */ +#endif /* CONFIG_BLK_DEV_IDEDMA */ + case XFER_PIO_4: TA = 0x01; TB = 0x04; break; + case XFER_PIO_3: TA = 0x02; TB = 0x06; break; + case XFER_PIO_2: TA = 0x03; TB = 0x08; break; + case XFER_PIO_1: TA = 0x05; TB = 0x0C; break; + case XFER_PIO_0: + default: TA = 0x09; TB = 0x13; break; } - pio = (pio == 5) ? 4 : pio; - switch (ide_get_best_pio_mode(drive, 255, pio, NULL)) { - case 4:speed = XFER_PIO_4; TA=0x01; TB=0x04; break; - case 3:speed = XFER_PIO_3; TA=0x02; TB=0x06; break; - case 2:speed = XFER_PIO_2; TA=0x03; TB=0x08; break; - case 1:speed = XFER_PIO_1; TA=0x05; TB=0x0C; break; - case 0: - default:speed = XFER_PIO_0; TA=0x09; TB=0x13; break; +#ifdef CONFIG_BLK_DEV_IDEDMA + if (speed >= XFER_SW_DMA_0) { + pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); + pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC); + } else { +#else + { +#endif /* CONFIG_BLK_DEV_IDEDMA */ + pci_write_config_byte(dev, (drive_pci), AP|TA); + pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); } - pci_write_config_byte(dev, (drive_pci), AP|TA); - pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); #if PDC202XX_DECODE_REGISTER_INFO pci_read_config_byte(dev, (drive_pci), &AP); @@ -333,13 +373,30 @@ static int config_chipset_for_pio (ide_drive_t *drive, byte pio) #if PDC202XX_DEBUG_DRIVE_INFO printk("%s: %s drive%d 0x%08x ", drive->name, ide_xfer_verbose(speed), - drive_number, drive_conf); + drive->dn, drive_conf); pci_read_config_dword(dev, drive_pci, &drive_conf); printk("0x%08x\n", drive_conf); #endif /* PDC202XX_DEBUG_DRIVE_INFO */ return err; } +/* 0 1 2 3 4 5 6 7 8 + * 960, 480, 390, 300, 240, 180, 120, 90, 60 + * 180, 150, 120, 90, 60 + * DMA_Speed + * 180, 120, 90, 90, 90, 60, 30 + * 11, 5, 4, 3, 2, 1, 0 + */ +static int config_chipset_for_pio (ide_drive_t *drive, byte pio) +{ + byte speed = 0x00; + + pio = (pio == 5) ? 4 : pio; + speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL); + + return ((int) pdc202xx_tune_chipset(drive, speed)); +} + static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio) { (void) config_chipset_for_pio(drive, pio); @@ -352,15 +409,15 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; unsigned long high_16 = dev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK; + unsigned long dma_base = hwif->dma_base; + byte unit = (drive->select.b.unit & 0x01); - int err; unsigned int drive_conf; byte drive_pci; byte test1, test2, speed = -1; - byte AP, BP, CP, DP, TB, TC; + byte AP; unsigned short EP; byte CLKSPD = IN_BYTE(high_16 + 0x11); - int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; byte udma_33 = ultra ? (inb(high_16 + 0x001f) & 1) : 0; @@ -397,9 +454,9 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) * check to make sure drive on same channel * is u66 capable */ - if (hwif->drives[!(drive_number%2)].id) { - if ((hwif->drives[!(drive_number%2)].id->dma_ultra & 0x0010) || - (hwif->drives[!(drive_number%2)].id->dma_ultra & 0x0008)) { + if (hwif->drives[!(drive->dn%2)].id) { + if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) || + (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) { OUT_BYTE(CLKSPD | mask, (high_16 + 0x11)); } else { OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11)); @@ -410,7 +467,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) } } - switch(drive_number) { + switch(drive->dn) { case 0: drive_pci = 0x60; pci_read_config_dword(dev, drive_pci, &drive_conf); if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) @@ -451,101 +508,34 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) chipset_is_set: - if (drive->media != ide_disk) - return ide_dma_off_quietly; + if (drive->media != ide_disk) return ide_dma_off_quietly; pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - pci_read_config_byte(dev, (drive_pci)|0x03, &DP); - - if (id->capability & 4) { /* IORDY_EN */ + if (id->capability & 4) /* IORDY_EN */ pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN); - pci_read_config_byte(dev, (drive_pci), &AP); - } - - if (drive->media == ide_disk) { /* PREFETCH_EN */ - pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN); - pci_read_config_byte(dev, (drive_pci), &AP); - } - - if ((BP & 0xF0) && (CP & 0x0F)) { - /* clear DMA modes of upper 842 bits of B Register */ - /* clear PIO forced mode upper 1 bit of B Register */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0xF0); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - - /* clear DMA modes of lower 8421 bits of C Register */ - pci_write_config_byte(dev, (drive_pci)|0x02, CP & ~0x0F); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - } - pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); + if (drive->media == ide_disk) /* PREFETCH_EN */ + pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN); - if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) { - /* speed 8 == UDMA mode 4 == speed 6 plus cable */ - speed = XFER_UDMA_4; TB = 0x20; TC = 0x01; - } else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) { - /* speed 7 == UDMA mode 3 == speed 5 plus cable */ - speed = XFER_UDMA_3; TB = 0x40; TC = 0x02; - } else if ((id->dma_ultra & 0x0004) && (udma_33)) { - /* speed 6 == UDMA mode 2 */ - speed = XFER_UDMA_2; TB = 0x20; TC = 0x01; - } else if ((id->dma_ultra & 0x0002) && (udma_33)) { - /* speed 5 == UDMA mode 1 */ - speed = XFER_UDMA_1; TB = 0x40; TC = 0x02; - } else if ((id->dma_ultra & 0x0001) && (udma_33)) { - /* speed 4 == UDMA mode 0 */ - speed = XFER_UDMA_0; TB = 0x60; TC = 0x03; - } else if (id->dma_mword & 0x0004) { - /* speed 4 == DMA mode 2 multi-word */ - speed = XFER_MW_DMA_2; TB = 0x60; TC = 0x03; - } else if (id->dma_mword & 0x0002) { - /* speed 3 == DMA mode 1 multi-word */ - speed = XFER_MW_DMA_1; TB = 0x60; TC = 0x04; - } else if (id->dma_mword & 0x0001) { - /* speed 2 == DMA mode 0 multi-word */ - speed = XFER_MW_DMA_0; TB = 0x60; TC = 0x05; - } else if (id->dma_1word & 0x0004) { - /* speed 2 == DMA mode 2 single-word */ - speed = XFER_SW_DMA_2; TB = 0x60; TC = 0x05; - } else if (id->dma_1word & 0x0002) { - /* speed 1 == DMA mode 1 single-word */ - speed = XFER_SW_DMA_1; TB = 0x80; TC = 0x06; - } else if (id->dma_1word & 0x0001) { - /* speed 0 == DMA mode 0 single-word */ - speed = XFER_SW_DMA_0; TB = 0xC0; TC = 0x0B; - } else { + if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) speed = XFER_UDMA_4; + else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) speed = XFER_UDMA_3; + else if ((id->dma_ultra & 0x0004) && (udma_33)) speed = XFER_UDMA_2; + else if ((id->dma_ultra & 0x0002) && (udma_33)) speed = XFER_UDMA_1; + else if ((id->dma_ultra & 0x0001) && (udma_33)) speed = XFER_UDMA_0; + else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2; + else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1; + else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0; + else if (id->dma_1word & 0x0004) speed = XFER_SW_DMA_2; + else if (id->dma_1word & 0x0002) speed = XFER_SW_DMA_1; + else if (id->dma_1word & 0x0001) speed = XFER_SW_DMA_0; + else { /* restore original pci-config space */ pci_write_config_dword(dev, drive_pci, drive_conf); return ide_dma_off_quietly; } - pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC); - -#if PDC202XX_DECODE_REGISTER_INFO - pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - - decode_registers(REG_A, AP); - decode_registers(REG_B, BP); - decode_registers(REG_C, CP); - decode_registers(REG_D, DP); -#endif /* PDC202XX_DECODE_REGISTER_INFO */ - - err = ide_config_drive_speed(drive, speed); - -#if PDC202XX_DEBUG_DRIVE_INFO - printk("%s: %s drive%d 0x%08x ", - drive->name, ide_xfer_verbose(speed), - drive_number, drive_conf); - pci_read_config_dword(dev, drive_pci, &drive_conf); - printk("0x%08x\n", drive_conf); -#endif /* PDC202XX_DEBUG_DRIVE_INFO */ + outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); + (void) pdc202xx_tune_chipset(drive, speed); return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : @@ -716,6 +706,7 @@ unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif) void __init ide_init_pdc202xx (ide_hwif_t *hwif) { hwif->tuneproc = &pdc202xx_tune_drive; + hwif->speedproc = &pdc202xx_tune_chipset; #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) { diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c index fafd0533feef..90af168c351f 100644 --- a/drivers/ide/piix.c +++ b/drivers/ide/piix.c @@ -112,6 +112,7 @@ static int piix_get_info (char *buffer, char **addr, off_t offset, int count) p += sprintf(p, "\n Intel PIIX4 Ultra 66 Chipset.\n"); break; case PCI_DEVICE_ID_INTEL_82801AB_1: + case PCI_DEVICE_ID_INTEL_82443MX_1: case PCI_DEVICE_ID_INTEL_82371AB: p += sprintf(p, "\n Intel PIIX4 Ultra 33 Chipset.\n"); break; @@ -258,28 +259,18 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio) } #if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING) -static int piix_config_drive_for_dma (ide_drive_t *drive) +static int piix_tune_chipset (ide_drive_t *drive, byte speed) { - struct hd_driveid *id = drive->id; ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - - int sitre; - short reg4042, reg44, reg48, reg4a, reg54; - byte speed; - byte maslave = hwif->channel ? 0x42 : 0x40; - byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; - int ultra66 = ((dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || - (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0; - int ultra = ((ultra66) || - (dev->device == PCI_DEVICE_ID_INTEL_82371AB) || - (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0; - int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); - int a_speed = 2 << (drive_number * 4); - int u_flag = 1 << drive_number; - int v_flag = 0x10 << drive_number; + int a_speed = 2 << (drive->dn * 4); + int u_flag = 1 << drive->dn; + int v_flag = 0x10 << drive->dn; int u_speed = 0; + int err = 0; + int sitre; + short reg4042, reg44, reg48, reg4a, reg54; pci_read_config_word(dev, maslave, ®4042); sitre = (reg4042 & 0x4000) ? 1 : 0; @@ -288,29 +279,16 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) pci_read_config_word(dev, 0x4a, ®4a); pci_read_config_word(dev, 0x54, ®54); - if ((id->dma_ultra & 0x0010) && (ultra)) { - u_speed = 2 << (drive_number * 4); - speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0008) && (ultra)) { - u_speed = 1 << (drive_number * 4); - speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0004) && (ultra)) { - u_speed = 2 << (drive_number * 4); - speed = XFER_UDMA_2; - } else if ((id->dma_ultra & 0x0002) && (ultra)) { - u_speed = 1 << (drive_number * 4); - speed = XFER_UDMA_1; - } else if ((id->dma_ultra & 0x0001) && (ultra)) { - u_speed = 0 << (drive_number * 4); - speed = XFER_UDMA_0; - } else if (id->dma_mword & 0x0004) { - speed = XFER_MW_DMA_2; - } else if (id->dma_mword & 0x0002) { - speed = XFER_MW_DMA_1; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else { - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + switch(speed) { + case XFER_UDMA_4: + case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; + case XFER_UDMA_3: + case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; + case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_SW_DMA_2: break; + default: return -1; } if (speed >= XFER_UDMA_0) { @@ -328,7 +306,6 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) pci_write_config_word(dev, 0x54, reg54 & ~v_flag); } } - if (speed < XFER_UDMA_0) { if (reg48 & u_flag) pci_write_config_word(dev, 0x48, reg48 & ~u_flag); @@ -340,11 +317,52 @@ static int piix_config_drive_for_dma (ide_drive_t *drive) piix_tune_drive(drive, piix_dma_2_pio(speed)); - (void) ide_config_drive_speed(drive, speed); - #if PIIX_DEBUG_DRIVE_INFO - printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive_number); + printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); #endif /* PIIX_DEBUG_DRIVE_INFO */ + if (!drive->init_speed) + drive->init_speed = speed; + err = ide_config_drive_speed(drive, speed); + drive->current_speed = speed; + return err; +} + +static int piix_config_drive_for_dma (ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + byte speed; + + byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; + int ultra66 = ((dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || + (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0; + int ultra = ((ultra66) || + (dev->device == PCI_DEVICE_ID_INTEL_82371AB) || + (dev->device == PCI_DEVICE_ID_INTEL_82443MX_1) || + (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0; + + if ((id->dma_ultra & 0x0010) && (ultra)) { + speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0008) && (ultra)) { + speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0004) && (ultra)) { + speed = XFER_UDMA_2; + } else if ((id->dma_ultra & 0x0002) && (ultra)) { + speed = XFER_UDMA_1; + } else if ((id->dma_ultra & 0x0001) && (ultra)) { + speed = XFER_UDMA_0; + } else if (id->dma_mword & 0x0004) { + speed = XFER_MW_DMA_2; + } else if (id->dma_mword & 0x0002) { + speed = XFER_MW_DMA_1; + } else if (id->dma_1word & 0x0004) { + speed = XFER_SW_DMA_2; + } else { + speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); + } + + (void) piix_tune_chipset(drive, speed); return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : @@ -413,6 +431,7 @@ void __init ide_init_piix (ide_hwif_t *hwif) #ifdef CONFIG_PIIX_TUNING hwif->autodma = 1; hwif->dmaproc = &piix_dmaproc; + hwif->speedproc = &piix_tune_chipset; #endif /* CONFIG_PIIX_TUNING */ #endif /* !CONFIG_BLK_DEV_IDEDMA */ } diff --git a/drivers/ide/qd6580.c b/drivers/ide/qd6580.c index ad56c295ceeb..4c00de5042f1 100644 --- a/drivers/ide/qd6580.c +++ b/drivers/ide/qd6580.c @@ -1,12 +1,21 @@ /* - * linux/drivers/ide/qd6580.c Version 0.02 Feb 09, 1996 + * linux/drivers/ide/qd6580.c Version 0.03 May 13, 2000 * - * Copyright (C) 1996 Linus Torvalds & author (see below) + * Copyright (C) 1996-2000 Linus Torvalds & author (see below) */ /* - * QDI QD6580 EIDE controller fast support by Colten Edwards. - * No net access, but (maybe) can be reached at pje120@cs.usask.ca + * Version 0.03 Cleaned auto-tune, added probe + * + * QDI QD6580 EIDE controller fast support + * + * To activate controller support use kernel parameter "ide0=qd6580" + * To enable tuning use kernel parameter "ide0=autotune" + */ + +/* + * Rewritten from the work of Colten Edwards by + * Samuel Thibault */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -27,42 +36,237 @@ #include "ide_modes.h" /* - * Register 0xb3 looks like: - * 0x4f is fast mode3 ? - * 0x3f is medium mode2 ? - * 0x2f is slower mode1 ? - * 0x1f is slower yet mode0 ? - * 0x0f ??? ??? + * I/O ports are 0xb0 0xb1 0xb2 and 0xb3 + * or 0x30 0x31 0x32 and 0x33 + * -- this is a dual IDE interface with I/O chips + * + * More research on qd6580 being done by willmore@cig.mot.com (David) + */ + +/* + * 0xb0: Timer1 * - * Don't know whether this sets BOTH drives, or just the first drive. - * Don't know if there is a separate setting for the second drive. + * + * 0xb1: Status * - * Feel free to patch this if you have one of these beasts - * and can work out the answers! + * && 0xf0 is either 0b1010000 or 0b01010000, or else it isn't a qd6580 + * bit 3 & 2: unknown (useless ?) I have 0 & 1, respectively + * bit 1: 1 if qd6580 baseport is 0xb0 + * 0 if qd6580 baseport is 0x30 + * bit 0: 1 if ide baseport is 0x1f0 + * 0 if ide baseport is 0x170 + * (? Strange: the Dos driver uses it, and then forces baseport to 0x1f0 ?) + * + * + * 0xb2: Timer2 * - * I/O ports are 0xb0 0xb2 and 0xb3 + * + * 0xb3: Control * - * More research on qd6580 being done by willmore@cig.mot.com (David) - * -- this is apparently a *dual* IDE interface + * bits 0-3 are always set 1 + * bit 6 : if 1, must be set 1 + * bit 1 : if 1, bit 7 must be set 1 + * bit 0 : if 1, drives are independant, we can have two different timers for + * the two drives. + * if 0, we have to take the slowest drive into account, + * but we may tune the second hwif ? */ -static void tune_qd6580 (ide_drive_t *drive, byte pio) +typedef struct ide_hd_timings_s { + int active_time; /* Active pulse (ns) minimum */ + int recovery_time; /* Recovery pulse (ns) minimum */ +} ide_hd_timings_t; + +static int basePort; /* base port address (0x30 or 0xb0) */ +static byte status; /* status register of qd6580 */ +static byte control; /* control register of qd6580 */ + +/* truncates a in [b,c] */ +#define IDE_IN(a,b,c) ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) ) + +static int bus_clock; /* Vesa local bus clock (ns) */ +static int tuned=0; /* to remember whether we've already been tuned */ + +/* + * tune_drive + * + * Finds timings for the specified drive, returns it in struc t + */ + +static void tune_drive ( ide_drive_t *drive, byte pio, ide_hd_timings_t *t) +{ + ide_pio_data_t d; + + t->active_time = 0xaf; + t->recovery_time = 0x19f; /* worst cases values from the dos driver */ + + if (drive->present == 0) { /* not present : free to give any timing */ + t->active_time = 0x0; + t->recovery_time = 0x0; + return; + } + + pio = ide_get_best_pio_mode(drive, pio, 4, &d); + + if (pio) { + + switch (pio) { + case 0: break; + case 3: t->active_time = 0x56; + t->recovery_time = d.cycle_time-0x66; + break; + case 4: t->active_time = 0x46; + t->recovery_time = d.cycle_time-0x3d; + break; + default: if (d.cycle_time >= 0xb4) { + t->active_time = 0x6e; + t->recovery_time = d.cycle_time - 0x78; + } else { + t->active_time = ide_pio_timings[pio].active_time; + t->recovery_time = d.cycle_time + -t->active_time + -ide_pio_timings[pio].setup_time; + } + } + } + printk("%s: PIO mode%d, tim1=%dns tim2=%dns\n", drive->name, pio, t->active_time, t->recovery_time); +} + +/* + * tune_ide + * + * Tunes the whole ide, ie tunes each drives, and takes the worst timings + * to tune qd6580 + */ + +static void tune_ide ( ide_hwif_t *hwif, byte pio ) { unsigned long flags; + ide_hd_timings_t t[2]={{0,0},{0,0}}; + + byte active_cycle; + byte recovery_cycle; + byte parameter; + int bus_speed = ide_system_bus_speed (); + + bus_clock = 1000 / bus_speed; + + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ + outb( (bus_clock<30) ? 0x0 : 0x0a, basePort + 0x02); + outb( 0x40 | ((control & 0x02) ? 0x9f:0x1f), basePort+0x03); + restore_flags(flags); - pio = ide_get_best_pio_mode(drive, pio, 3, NULL); + tune_drive (&hwif->drives[0], pio, &t[0]); + tune_drive (&hwif->drives[1], pio, &t[1]); - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ - outb_p(0x8d,0xb0); - outb_p(0x0 ,0xb2); - outb_p(((pio+1)<<4)|0x0f,0xb3); + t[0].active_time = IDE_MAX(t[0].active_time, t[1].active_time); + t[0].recovery_time = IDE_MAX(t[0].recovery_time,t[1].recovery_time); + + active_cycle = 17-IDE_IN(t[0].active_time / bus_clock + 1, 2, 17); + recovery_cycle = 15-IDE_IN(t[0].recovery_time / bus_clock + 1, 2, 15); + + parameter=active_cycle | (recovery_cycle<<4); + + printk("%s: tim1=%dns tim2=%dns => %#x\n", hwif->name, t[0].active_time, t[0].recovery_time, parameter); + + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ + outb_p(parameter,0xb0); inb(0x3f6); restore_flags(flags); /* all CPUs */ + +} + +/* + * tune_qd6580 + * + * tunes the hwif if not tuned + */ + +static void tune_qd6580 (ide_drive_t *drive, byte pio) +{ + if (! tuned) { + tune_ide(HWIF(drive), pio); + tuned = 1; + } +} + +/* + * testreg + * + * tests if the given port is a register + */ + +static int __init testreg(int port) +{ + byte savereg; + byte readreg; + unsigned long flags; + + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ + savereg = inb(port); + outb_p(0x15,port); /* safe value */ + readreg = inb_p(port); + outb(savereg,port); + restore_flags(flags); /* all CPUs */ + + if (savereg == 0x15) { + printk("Outch ! the probe for qd6580 isn't reliable !\n"); + printk("Please contact samuel.thibault@fnac.net to tell about your hardware\n"); + printk("Assuming qd6580 is present"); + } + + return (readreg == 0x15); } +/* + * trybase: + * + * tries to find a qd6580 at the given base and save it if found + */ + +static int __init trybase (int base) +{ + unsigned long flags; + + save_flags(flags); /* all CPUs */ + cli(); /* all CPUs */ + status = inb(base+0x01); + control = inb(base+0x03); + restore_flags(flags); /* all CPUs */ + + if (((status & 0xf0) != 0x50) && ((status & 0xf0) != 0xa0)) return(0); + if (! ( ((status & 0x02) == 0x0) == (base == 0x30) ) ) return (0); + + /* Seems to be OK, let's use it */ + + basePort = base; + return(testreg(base)); +} + +/* + * probe: + * + * probes qd6580 at 0xb0 (the default) or 0x30 + */ + +static int __init probe (void) +{ + return (trybase(0xb0) ? 1 : trybase(0x30)); +} + + void __init init_qd6580 (void) { + if (! probe()) { + printk("qd6580: not found\n"); + return; + } + + printk("qd6580: base=%#x, status=%#x, control=%#x\n", basePort, status, control); + ide_hwifs[0].chipset = ide_qd6580; ide_hwifs[1].chipset = ide_qd6580; ide_hwifs[0].tuneproc = &tune_qd6580; diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c index 581992c63d2c..be56a7f2489a 100644 --- a/drivers/ide/sis5513.c +++ b/drivers/ide/sis5513.c @@ -227,9 +227,8 @@ static void config_drive_art_rwp (ide_drive_t *drive) ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); byte reg4bh = 0; - byte rw_prefetch = (0x11 << drive_number); + byte rw_prefetch = (0x11 << drive->dn); pci_read_config_byte(dev, 0x4b, ®4bh); if (drive->media != ide_disk) @@ -248,12 +247,8 @@ static void config_art_rwp_pio (ide_drive_t *drive, byte pio) unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; unsigned short xfer_pio = drive->id->eide_pio_modes; - int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); -#if 0 config_drive_art_rwp(drive); -#endif - pio = ide_get_best_pio_mode(drive, 255, pio, NULL); if (xfer_pio> 4) @@ -281,7 +276,7 @@ static void config_art_rwp_pio (ide_drive_t *drive, byte pio) * Cycle time 20T (600ns) 13T (390ns) 8T (240ns) 6T (180ns) 4T (120ns) */ - switch(drive_number) { + switch(drive->dn) { case 0: drive_pci = 0x40; break; case 1: drive_pci = 0x42; break; case 2: drive_pci = 0x44; break; @@ -329,7 +324,7 @@ static int config_chipset_for_pio (ide_drive_t *drive, byte pio) return err; } -#undef SIS5513_TUNEPROC +#define SIS5513_TUNEPROC #ifdef SIS5513_TUNEPROC static void sis5513_tune_drive (ide_drive_t *drive, byte pio) @@ -354,7 +349,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) unsigned long dma_base = hwif->dma_base; byte unit = (drive->select.b.unit & 0x01); byte speed = 0x00, unmask = 0xE0, four_two = 0x00; - int drive_number = ((hwif->channel ? 2 : 0) + unit); byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; if (host_dev) { @@ -370,7 +364,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) } } - switch(drive_number) { + switch(drive->dn) { case 0: drive_pci = 0x40;break; case 1: drive_pci = 0x42;break; case 2: drive_pci = 0x44;break; @@ -438,7 +432,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra) err = ide_config_drive_speed(drive, speed); #if SIS5513_DEBUG_DRIVE_INFO - printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive_number); + printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn); #endif /* SIS5513_DEBUG_DRIVE_INFO */ return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index f9d96a86560e..39258362ca8d 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -115,6 +115,7 @@ static struct chipset_bus_clock_list_entry * via82cxxx_table = NULL; struct chipset_bus_clock_list_entry via82cxxx_type_one [] = { /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ +#ifdef CONFIG_BLK_DEV_IDEDMA { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { XFER_UDMA_3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { XFER_UDMA_2, 0x60, 0x20, 0x60, 0x20, 0x60, 0x21, 0x00, 0x00 }, @@ -124,7 +125,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_one [] = { { XFER_MW_DMA_2, 0x03, 0x20, 0x03, 0x20, 0x03, 0x21, 0x00, 0x00 }, { XFER_MW_DMA_1, 0x03, 0x31, 0x03, 0x31, 0x03, 0x32, 0x00, 0x00 }, { XFER_MW_DMA_0, 0x03, 0x31, 0x03, 0x31, 0x03, 0x32, 0x00, 0x00 }, - +#endif /* CONFIG_BLK_DEV_IDEDMA */ { XFER_PIO_4, 0x03, 0x20, 0x03, 0x20, 0x03, 0x21, 0x00, 0x00 }, { XFER_PIO_3, 0x03, 0x31, 0x03, 0x31, 0x03, 0x32, 0x00, 0x00 }, { XFER_PIO_2, 0x03, 0x65, 0x03, 0x65, 0x03, 0x76, 0x00, 0x00 }, @@ -135,6 +136,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_one [] = { struct chipset_bus_clock_list_entry via82cxxx_type_two [] = { /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ +#ifdef CONFIG_BLK_DEV_IDEDMA { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { XFER_UDMA_3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { XFER_UDMA_2, 0xE0, 0x20, 0xE0, 0x20, 0xE1, 0x31, 0xE1, 0x32 }, @@ -144,7 +146,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_two [] = { { XFER_MW_DMA_2, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, { XFER_MW_DMA_1, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, { XFER_MW_DMA_0, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, - +#endif /* CONFIG_BLK_DEV_IDEDMA */ { XFER_PIO_4, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, { XFER_PIO_3, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, { XFER_PIO_2, 0x03, 0x65, 0x03, 0x65, 0x03, 0x87, 0x03, 0xA8 }, @@ -155,6 +157,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_two [] = { struct chipset_bus_clock_list_entry via82cxxx_type_three [] = { /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ +#ifdef CONFIG_BLK_DEV_IDEDMA { XFER_UDMA_4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { XFER_UDMA_3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { XFER_UDMA_2, 0xE0, 0x20, 0xE0, 0x20, 0xE1, 0x31, 0xE1, 0x32 }, @@ -164,7 +167,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_three [] = { { XFER_MW_DMA_2, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, { XFER_MW_DMA_1, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, { XFER_MW_DMA_0, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, - +#endif /* CONFIG_BLK_DEV_IDEDMA */ { XFER_PIO_4, 0x03, 0x20, 0x03, 0x20, 0x03, 0x31, 0x03, 0x32 }, { XFER_PIO_3, 0x03, 0x31, 0x03, 0x31, 0x03, 0x42, 0x03, 0x53 }, { XFER_PIO_2, 0x03, 0x65, 0x03, 0x65, 0x03, 0x87, 0x03, 0xA8 }, @@ -175,6 +178,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_three [] = { struct chipset_bus_clock_list_entry via82cxxx_type_four [] = { /* speed */ /* 25 */ /* 33 */ /* 37.5 */ /* 41.5 */ +#ifdef CONFIG_BLK_DEV_IDEDMA { XFER_UDMA_4, 0x00, 0x00, 0xE0, 0x20, 0xE1, 0x31, 0x00, 0x00 }, { XFER_UDMA_3, 0x00, 0x00, 0xE1, 0x20, 0xE2, 0x31, 0x00, 0x00 }, { XFER_UDMA_2, 0x00, 0x00, 0xE2, 0x20, 0xE4, 0x31, 0x00, 0x00 }, @@ -184,7 +188,7 @@ struct chipset_bus_clock_list_entry via82cxxx_type_four [] = { { XFER_MW_DMA_2, 0x00, 0x00, 0x03, 0x20, 0x03, 0x31, 0x00, 0x00 }, { XFER_MW_DMA_1, 0x00, 0x00, 0x03, 0x31, 0x03, 0x42, 0x00, 0x00 }, { XFER_MW_DMA_0, 0x00, 0x00, 0x03, 0x31, 0x03, 0x42, 0x00, 0x00 }, - +#endif /* CONFIG_BLK_DEV_IDEDMA */ { XFER_PIO_4, 0x00, 0x00, 0x03, 0x20, 0x03, 0x31, 0x00, 0x00 }, { XFER_PIO_3, 0x00, 0x00, 0x03, 0x31, 0x03, 0x42, 0x00, 0x00 }, { XFER_PIO_2, 0x00, 0x00, 0x03, 0x65, 0x03, 0x87, 0x00, 0x00 }, @@ -651,8 +655,7 @@ static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - byte unit = (drive->select.b.unit & 0x01); - int drive_number = ((hwif->channel ? 2 : 0) + unit); + struct chipset_bus_clock_list_entry * temp_table = NULL; byte ata2_pci = 0x00; byte ata3_pci = 0x00; @@ -662,7 +665,10 @@ static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed) int bus_speed = system_bus_clock(); - switch(drive_number) { + if (via82cxxx_table == NULL) + return -1; + + switch(drive->dn) { case 0: ata2_pci = 0x4b; ata3_pci = 0x53; break; case 1: ata2_pci = 0x4a; ata3_pci = 0x52; break; case 2: ata2_pci = 0x49; ata3_pci = 0x51; break; @@ -671,16 +677,26 @@ static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed) return -1; } + if ((via82cxxx_table == via82cxxx_type_four) && (speed <= XFER_UDMA_2)) { + temp_table = via82cxxx_type_three; + } else { + temp_table = via82cxxx_table; + } + pci_read_config_byte(dev, ata2_pci, &timing); - timing = pci_bus_clock_list(speed, bus_speed, via82cxxx_table); + timing = pci_bus_clock_list(speed, bus_speed, temp_table); pci_write_config_byte(dev, ata2_pci, timing); pci_read_config_byte(dev, ata3_pci, &ultra); - ultra = pci_bus_clock_list_ultra(speed, bus_speed, via82cxxx_table); + ultra = pci_bus_clock_list_ultra(speed, bus_speed, temp_table); pci_write_config_byte(dev, ata3_pci, ultra); + if (!drive->init_speed) + drive->init_speed = speed; + err = ide_config_drive_speed(drive, speed); + drive->current_speed = speed; return(err); } @@ -845,6 +861,7 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name) struct pci_dev *isa; int i, j, ata33, ata66; + int bus_speed = system_bus_clock(); byte revision = 0; for (i = 0; i < arraysize (ApolloHostChipInfo) && !host_dev; i++) { @@ -873,18 +890,26 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name) ata33 = 1; ata66 = 0; + via82cxxx_table = ApolloISAChipInfo[j].chipset_table; + if (ApolloISAChipInfo[j].flags & VIA_FLAG_CHECK_REV) { pci_read_config_byte(isa_dev, 0x0d, &revision); ata33 = (revision >= 0x20) ? 1 : 0; } else if (ApolloISAChipInfo[j].flags & VIA_FLAG_ATA_66) { + byte ata66_0 = 0, ata66_1 = 0; ata33 = 0; ata66 = 1; + pci_read_config_byte(dev, 0x50, &ata66_1); + pci_read_config_byte(dev, 0x52, &ata66_0); + if ((ata66_0 & 0x04) || (ata66_1 & 0x04)) { + via82cxxx_table = (bus_speed == 33 || bus_speed == 37) ? + via82cxxx_type_four : + via82cxxx_type_three; + } } if (ata33 | ata66) printk(" Chipset Core ATA-%s", ata66 ? "66" : "33"); - - via82cxxx_table = ApolloISAChipInfo[j].chipset_table; } printk("\n"); } @@ -915,6 +940,7 @@ void __init ide_init_via82cxxx (ide_hwif_t *hwif) #ifdef CONFIG_VIA82CXXX_TUNING hwif->tuneproc = &via82cxxx_tune_drive; + hwif->speedproc = &via82cxxx_tune_chipset; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; hwif->autodma = 0; diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 466a83dbc416..de0946642196 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -95,10 +95,6 @@ extern int bionet_probe(struct net_device *); extern int pamsnet_probe(struct net_device *); extern int cs89x0_probe(struct net_device *dev); extern int ethertap_probe(struct net_device *dev); -extern int ether1_probe (struct net_device *dev); -extern int ether3_probe (struct net_device *dev); -extern int etherh_probe (struct net_device *dev); -extern int am79c961_probe(struct net_device *dev); extern int hplance_probe(struct net_device *dev); extern int bagetlance_probe(struct net_device *); extern int dec_lance_probe(struct net_device *); @@ -401,22 +397,6 @@ struct devprobe mips_probes[] __initdata = { {NULL, 0}, }; -struct devprobe arm_probes[] __initdata = { -#ifdef CONFIG_ARM_ETHERH - {etherh_probe , 0}, -#endif -#ifdef CONFIG_ARM_ETHER3 - {ether3_probe , 0}, -#endif -#ifdef CONFIG_ARM_ETHER1 - {ether1_probe , 0}, -#endif -#ifdef CONFIG_ARM_AM79C961A - {am79c961_probe, 0}, -#endif - {NULL, 0}, -}; - /* * Unified ethernet device probe, segmented per architecture and * per bus interface. This drives the legacy devices only for now. @@ -437,8 +417,6 @@ static int __init ethif_probe(struct net_device *dev) * The arch specific probes are 1st so that any on-board ethernet * will be probed before other ISA/EISA/MCA/PCI bus cards. */ - if (probe_list(dev, arm_probes) == 0) - return 0; if (probe_list(dev, m68k_probes) == 0) return 0; if (probe_list(dev, mips_probes) == 0) diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 7d53e1260f93..29d5d7638795 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2966,6 +2966,6 @@ static int __init read_eeprom_byte(struct net_device *dev, /* * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c" + * compile-command: "gcc -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c" * End: */ diff --git a/drivers/net/am79c961a.c b/drivers/net/am79c961a.c index c7e7f2fe5731..83012de44910 100644 --- a/drivers/net/am79c961a.c +++ b/drivers/net/am79c961a.c @@ -3,7 +3,10 @@ * * Derived from various things including skeleton.c * - * R.M.King 1995. + * Russell King 1995-2000. + * + * This is a special driver for the am79c961A Lance chip used in the + * Intel (formally Digital Equipment Corp) EBSA110 platform. */ #include #include @@ -21,9 +24,11 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -33,26 +38,13 @@ #include "am79c961a.h" -static int am79c961_probe1 (struct net_device *dev); -static int am79c961_open (struct net_device *dev); -static int am79c961_sendpacket (struct sk_buff *skb, struct net_device *dev); static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs); static void am79c961_rx (struct net_device *dev, struct dev_priv *priv); static void am79c961_tx (struct net_device *dev, struct dev_priv *priv); -static int am79c961_close (struct net_device *dev); -static struct enet_statistics *am79c961_getstats (struct net_device *dev); -static void am79c961_setmulticastlist (struct net_device *dev); -static void am79c961_timeout(struct net_device *dev); static unsigned int net_debug = NET_DEBUG; -static void -am79c961_setmulticastlist (struct net_device *dev); - -static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.01\n"; - -#define FUNC_PROLOGUE \ - struct dev_priv *priv = (struct dev_priv *)dev->priv +static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.02\n"; /* --------------------------------------------------------------------------- */ @@ -270,109 +262,6 @@ am79c961_init_for_open(struct net_device *dev) write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT); } -static int -am79c961_init(struct net_device *dev) -{ - unsigned long flags; - - am79c961_ramtest(dev, 0x66); - am79c961_ramtest(dev, 0x99); - - save_flags_cli (flags); - - write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */ - write_rreg (dev->base_addr, CSR0, CSR0_STOP); - write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); - - restore_flags (flags); - - return 0; -} - -/* - * This is the real probe routine. - */ -static int -am79c961_probe1(struct net_device *dev) -{ - static unsigned version_printed = 0; - struct dev_priv *priv; - int i; - - if (!dev->priv) { - dev->priv = kmalloc (sizeof (struct dev_priv), GFP_KERNEL); - if (!dev->priv) - return -ENOMEM; - } - - priv = (struct dev_priv *) dev->priv; - memset (priv, 0, sizeof(struct dev_priv)); - - /* - * The PNP initialisation should have been done by the ether bootp loader. - */ - inb((dev->base_addr + NET_RESET) >> 1); /* reset the device */ - - udelay (5); - - if (inb (dev->base_addr >> 1) != 0x08 || - inb ((dev->base_addr >> 1) + 1) != 00 || - inb ((dev->base_addr >> 1) + 2) != 0x2b) { - kfree (dev->priv); - dev->priv = NULL; - return -ENODEV; - } - - /* - * Ok, we've found a valid hw ID - */ - - if (net_debug && version_printed++ == 0) - printk (KERN_INFO "%s", version); - - printk(KERN_INFO "%s: am79c961 found [%04lx, %d] ", dev->name, dev->base_addr, dev->irq); - request_region (dev->base_addr, 0x18, "am79c961"); - - /* Retrive and print the ethernet address. */ - for (i = 0; i < 6; i++) { - dev->dev_addr[i] = inb ((dev->base_addr >> 1) + i) & 0xff; - printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); - } - - if (am79c961_init(dev)) { - kfree (dev->priv); - dev->priv = NULL; - return -ENODEV; - } - - dev->open = am79c961_open; - dev->stop = am79c961_close; - dev->hard_start_xmit = am79c961_sendpacket; - dev->get_stats = am79c961_getstats; - dev->set_multicast_list = am79c961_setmulticastlist; - dev->tx_timeout = am79c961_timeout; - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - - return 0; -} - -int -am79c961_probe(struct net_device *dev) -{ - static int initialised = 0; - - if (initialised) - return -ENODEV; - initialised = 1; - - dev->base_addr = 0x220; - dev->irq = 3; - - return am79c961_probe1(dev); -} - /* * Open/initialize the board. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. @@ -408,9 +297,17 @@ am79c961_open(struct net_device *dev) static int am79c961_close(struct net_device *dev) { + unsigned long flags; + netif_stop_queue(dev); - am79c961_init(dev); + save_flags_cli (flags); + + write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */ + write_rreg (dev->base_addr, CSR0, CSR0_STOP); + write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); + + restore_flags (flags); free_irq (dev->irq, dev); @@ -709,3 +606,103 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv) netif_wake_queue(dev); } + +static int +am79c961_hw_init(struct net_device *dev) +{ + unsigned long flags; + + am79c961_ramtest(dev, 0x66); + am79c961_ramtest(dev, 0x99); + + save_flags_cli (flags); + + write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */ + write_rreg (dev->base_addr, CSR0, CSR0_STOP); + write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); + + restore_flags (flags); + + return 0; +} + +static void __init am79c961_banner(void) +{ + static unsigned version_printed = 0; + + if (net_debug && version_printed++ == 0) + printk(KERN_INFO "%s", version); +} + +static int __init am79c961_init(void) +{ + struct net_device *dev; + struct dev_priv *priv; + int i, ret; + + dev = init_etherdev(NULL, sizeof(struct dev_priv)); + ret = -ENOMEM; + if (!dev) + goto out; + + priv = (struct dev_priv *) dev->priv; + + /* + * Fixed address and IRQ lines here. + * The PNP initialisation should have been + * done by the ether bootp loader. + */ + dev->base_addr = 0x220; + dev->irq = IRQ_EBSA110_ETHERNET; + + /* + * Reset the device. + */ + inb((dev->base_addr + NET_RESET) >> 1); + udelay(5); + + /* + * Check the manufacturer part of the + * ether address. + */ + ret = -ENODEV; + if (inb(dev->base_addr >> 1) != 0x08 || + inb((dev->base_addr >> 1) + 1) != 00 || + inb((dev->base_addr >> 1) + 2) != 0x2b) + goto nodev; + + if (!request_region(dev->base_addr, 0x18, dev->name)) + goto nodev; + + am79c961_banner(); + printk(KERN_INFO "%s: am79c961 found at %08lx, IRQ%d, ether address ", + dev->name, dev->base_addr, dev->irq); + + /* Retrive and print the ethernet address. */ + for (i = 0; i < 6; i++) { + dev->dev_addr[i] = inb((dev->base_addr >> 1) + i) & 0xff; + printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); + } + + if (am79c961_hw_init(dev)) + goto release; + + dev->open = am79c961_open; + dev->stop = am79c961_close; + dev->hard_start_xmit = am79c961_sendpacket; + dev->get_stats = am79c961_getstats; + dev->set_multicast_list = am79c961_setmulticastlist; + dev->tx_timeout = am79c961_timeout; + + return 0; + +release: + release_region(dev->base_addr, 0x18); +nodev: + unregister_netdev(dev); + kfree(dev); +out: + return ret; +} + +module_init(am79c961_init); diff --git a/drivers/net/setup.c b/drivers/net/setup.c index 7e01e3f83b65..65e85e808db6 100644 --- a/drivers/net/setup.c +++ b/drivers/net/setup.c @@ -34,7 +34,7 @@ extern int abyss_probe(void); extern int madgemc_probe(void); extern int tms_pci_probe(void); -/* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is tring of 9 zeros. */ +/* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */ #define __PAD6 "\0\0\0\0\0\0\0\0\0" #define __PAD5 __PAD6 "\0" #define __PAD4 __PAD5 "\0" diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 8efaf47f8bd2..c92e73180dc9 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -75,7 +75,7 @@ static char * card_names[] = { "SiS 900 PCI Fast Ethernet", "SiS 7016 PCI Fast Ethernet" }; -static struct pci_device_id sis900_pci_tbl [] __devinitdata = { +static struct pci_device_id sis900_pci_tbl [] __initdata = { {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_900}, {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016, diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog index 1e09974c9d4b..0d1fd72e6d43 100644 --- a/drivers/parport/ChangeLog +++ b/drivers/parport/ChangeLog @@ -1,3 +1,39 @@ +2000-05-15 Gunther Mayer + + * parport_pc.c (parport_pc_compat_write_block_pio): Check for + timeouts. + (parport_pc_ecp_write_block_pio): Likewise. + (parport_pc_ecp_read_block_pio): Likewise. + +2000-05-02 Gunther Mayer + + * parport_pc.c: PCI SYBA patch and verbose PCI detection. + +2000-05-02 Gunther Mayer + + * parport_pc.c (decode_smsc): Fix SMSC 665/666 identification. + +2000-04-28 Tim Waugh + + * ieee1284.c: Short function descriptions can't be multiline. + + * daisy.c: Short function descriptions can't be multiline. + +2000-04-19 Tim Waugh + + * parport_pc.c (parport_pc_fifo_write_block_dma): Make maxlen + calculation a bit clearer. + + * ieee1284.c (parport_negotiate): Turn on data line drivers. + + * ieee1284_ops.c (parport_ieee1284_read_byte): Turn off data line + drivers. + (parport_ieee1284_write_compat): Turn on data line drivers. + + * daisy.c (assign_addrs): Turn on data line drivers. + (cpp_mux): Likewise. + (cpp_daisy): Likewise. + 2000-04-04 Tim Waugh * parport_pc.c: Add support for another PCI card. diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c index ead3443b4f95..b99d5a344ed0 100644 --- a/drivers/parport/daisy.c +++ b/drivers/parport/daisy.c @@ -252,8 +252,7 @@ void parport_close (struct pardevice *dev) } /** - * parport_device_num - convert device coordinates into a - * canonical device number + * parport_device_num - convert device coordinates * @parport: parallel port number * @mux: multiplexor port number (-1 for no multiplexor) * @daisy: daisy chain address (-1 for no daisy chain address) @@ -279,8 +278,7 @@ int parport_device_num (int parport, int mux, int daisy) } /** - * parport_device_coords - convert a canonical device number into - * device coordinates + * parport_device_coords - convert canonical device number * @devnum: device number * @parport: pointer to storage for parallel port number * @mux: pointer to storage for multiplexor port number @@ -325,6 +323,7 @@ static int cpp_daisy (struct parport *port, int cmd) { unsigned char s; + parport_data_forward (port); parport_write_data (port, 0xaa); udelay (2); parport_write_data (port, 0x55); udelay (2); parport_write_data (port, 0x00); udelay (2); @@ -373,6 +372,7 @@ static int cpp_mux (struct parport *port, int cmd) unsigned char s; int rc; + parport_data_forward (port); parport_write_data (port, 0xaa); udelay (2); parport_write_data (port, 0x55); udelay (2); parport_write_data (port, 0xf0); udelay (2); @@ -430,6 +430,7 @@ static int assign_addrs (struct parport *port) int thisdev = numdevs; char *deviceid; + parport_data_forward (port); parport_write_data (port, 0xaa); udelay (2); parport_write_data (port, 0x55); udelay (2); parport_write_data (port, 0x00); udelay (2); @@ -502,8 +503,7 @@ static int assign_addrs (struct parport *port) 'from' itself is skipped. */ /** - * parport_find_device - find a device with a specified - * manufacturer and model string + * parport_find_device - find a specific device * @mfg: required manufacturer string * @mdl: required model string * @from: previous device number found in search, or %NULL for diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c index f25c50abdeaf..11f98bea035c 100644 --- a/drivers/parport/ieee1284.c +++ b/drivers/parport/ieee1284.c @@ -380,6 +380,7 @@ int parport_negotiate (struct parport *port, int mode) udelay(1); /* Event 0: Set data */ + parport_data_forward (port); parport_write_data (port, m); udelay (400); /* Shouldn't need to wait this long. */ @@ -734,7 +735,6 @@ ssize_t parport_read (struct parport *port, void *buffer, size_t len) /** * parport_set_timeout - set the inactivity timeout for a device - * on a port * @dev: device on a port * @inactivity: inactivity timeout (in jiffies) * diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c index a3b76ffbc18a..cf5c5fb03c03 100644 --- a/drivers/parport/ieee1284_ops.c +++ b/drivers/parport/ieee1284_ops.c @@ -57,6 +57,7 @@ size_t parport_ieee1284_write_compat (struct parport *port, port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; parport_write_control (port, ctl); + parport_data_forward (port); while (count < len) { long expire = jiffies + dev->timeout; long wait = (HZ + 99) / 100; @@ -268,6 +269,9 @@ size_t parport_ieee1284_read_byte (struct parport *port, break; } + /* Event 14: Place data bus in high impedance state. */ + parport_data_reverse (port); + /* Event 7: Set nAutoFd low. */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 5c78c1565684..a759b2d7462e 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -704,6 +704,7 @@ size_t parport_pc_compat_write_block_pio (struct parport *port, int flags) { size_t written; + int r; /* Special case: a timeout of zero means we cannot call schedule(). */ if (!port->physport->cad->timeout) @@ -745,9 +746,14 @@ size_t parport_pc_compat_write_block_pio (struct parport *port, frob_econtrol (port, 0xe0, ECR_PS2 << 5); } - parport_wait_peripheral (port, - PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY); + r = parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY); + if (r) + printk (KERN_DEBUG + "%s: BUSY timeout (%d) in compat_write_block_pio\n", + port->name, r); + port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; return written; @@ -760,6 +766,7 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port, int flags) { size_t written; + int r; /* Special case: a timeout of zero means we cannot call schedule(). */ if (!port->physport->cad->timeout) @@ -772,9 +779,12 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port, parport_frob_control (port, PARPORT_CONTROL_INIT, 0); /* Event 40: PError goes high. */ - parport_wait_peripheral (port, - PARPORT_STATUS_PAPEROUT, - PARPORT_STATUS_PAPEROUT); + r = parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + if (r) + printk (KERN_DEBUG "%s: PError timeout (%d) " + "in ecp_write_block_pio\n", port->name, r); } /* Set up ECP parallel port mode.*/ @@ -818,18 +828,30 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port, parport_pc_data_reverse (port); /* Must be in PS2 mode */ udelay (5); parport_frob_control (port, PARPORT_CONTROL_INIT, 0); - parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); + r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); + if (r) + printk (KERN_DEBUG "%s: PE,1 timeout (%d) " + "in ecp_write_block_pio\n", port->name, r); + parport_frob_control (port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT); - parport_wait_peripheral (port, - PARPORT_STATUS_PAPEROUT, - PARPORT_STATUS_PAPEROUT); + r = parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + if (r) + printk (KERN_DEBUG "%s: PE,2 timeout (%d) " + "in ecp_write_block_pio\n", port->name, r); } - parport_wait_peripheral (port, - PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY); + r = parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY); + if(r) + printk (KERN_DEBUG + "%s: BUSY timeout (%d) in ecp_write_block_pio\n", + port->name, r); + port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; return written; @@ -840,6 +862,7 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port, { size_t left = length; size_t fifofull; + int r; const int fifo = FIFO(port); const struct parport_pc_private *priv = port->physport->private_data; const int fifo_depth = priv->fifo_depth; @@ -882,7 +905,10 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port, 0); /* Event 40: PError goes low */ - parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); + r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); + if (r) + printk (KERN_DEBUG "%s: PE timeout Event 40 (%d) " + "in ecp_read_block_pio\n", port->name, r); } /* Set up ECP FIFO mode.*/ @@ -961,9 +987,14 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port, /* Go to forward idle mode to shut the peripheral up. */ parport_frob_control (port, PARPORT_CONTROL_INIT, 0); - parport_wait_peripheral (port, - PARPORT_STATUS_PAPEROUT, - PARPORT_STATUS_PAPEROUT); + r = parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + if (r) + printk (KERN_DEBUG + "%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n", + port->name, r); + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; /* Finish up. */ @@ -1218,7 +1249,7 @@ static void __devinit decode_smsc(int efer, int key, int devid, int devrev) if (devid == devrev) /* simple heuristics, we happened to read some - non-winbond register */ + non-smsc register */ return; func=NULL; @@ -1228,8 +1259,8 @@ static void __devinit decode_smsc(int efer, int key, int devid, int devrev) if (id==0x0302) {type="37c669"; func=show_parconfig_smsc37c669;} else if (id==0x6582) type="37c665IR"; - else if ((id==0x6502) && (key==0x44)) type="37c665GT"; - else if ((id==0x6502) && (key==0x55)) type="37c666GT"; + else if (devid==0x65) type="37c665GT"; + else if (devid==0x66) type="37c666GT"; if(type==NULL) printk("SMSC unknown chip type\n"); @@ -2263,6 +2294,7 @@ enum parport_pc_pci_cards { plx_9050, afavlab_tk9902, timedia_1889, + syba_2p_epp, }; @@ -2270,9 +2302,11 @@ enum parport_pc_pci_cards { * (but offset by last_sio) */ static struct parport_pc_pci { int numports; - struct { + struct { /* BAR (base address registers) numbers in the config + space header */ int lo; - int hi; /* -ve if not there */ + int hi; /* -1 if not there, >6 for offset-method (max + BAR is 6) */ } addr[4]; } cards[] __devinitdata = { /* siig_1s1p_10x_550 */ { 1, { { 3, 4 }, } }, @@ -2301,6 +2335,9 @@ static struct parport_pc_pci { /* plx_9050 */ { 2, { { 4, -1 }, { 5, -1 }, } }, /* afavlab_tk9902 */ { 1, { { 0, 1 }, } }, /* timedia_1889 */ { 1, { { 2, -1 }, } }, + /* SYBA uses fixed offsets in + a 1K io window */ + /* syba_2p_epp */ { 2, { { 0, 0x078 }, { 0, 0x178 }, } }, }; static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = { @@ -2360,6 +2397,7 @@ static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, afavlab_tk9902 }, { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, PCI_ANY_ID, PCI_ANY_ID, 0, 0, timedia_1889 }, + { 0x1592, 0x0782, PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_2p_epp }, { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl); @@ -2384,9 +2422,16 @@ static int __devinit parport_pc_pci_probe (struct pci_dev *dev, unsigned long io_lo, io_hi; io_lo = pci_resource_start (dev, lo); io_hi = 0; - if (hi >= 0) + if ((hi >= 0) && (hi <= 6)) io_hi = pci_resource_start (dev, hi); + else if (hi > 6) + io_lo += hi; /* Reinterpret the meaning of + "hi" as an offset (see SYBA + def.) */ /* TODO: test if sharing interrupts works */ + printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, " + "I/O at %#lx(%#lx)\n", parport_pc_pci_tbl[i].vendor, + parport_pc_pci_tbl[i].device, io_lo, io_hi); if (parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, dev)) count++; diff --git a/drivers/sound/i810_audio.c b/drivers/sound/i810_audio.c index 4e42146614bd..76bfcc3c0580 100644 --- a/drivers/sound/i810_audio.c +++ b/drivers/sound/i810_audio.c @@ -189,7 +189,7 @@ static char * card_names[] = { "Intel 440MX" }; -static struct pci_device_id i810_pci_tbl [] __devinitdata = { +static struct pci_device_id i810_pci_tbl [] __initdata = { {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA}, {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82901, diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c index aa680aefc98e..a1f462f3b34d 100644 --- a/drivers/sound/trident.c +++ b/drivers/sound/trident.c @@ -147,7 +147,7 @@ static char * card_names[] = { "ALi Audio Accelerator" }; -static struct pci_device_id trident_pci_tbl [] __devinitdata = { +static struct pci_device_id trident_pci_tbl [] __initdata = { {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_DX}, {PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, diff --git a/drivers/sound/via82cxxx_audio.c b/drivers/sound/via82cxxx_audio.c index 03aa75bf0878..e4403d9664ab 100644 --- a/drivers/sound/via82cxxx_audio.c +++ b/drivers/sound/via82cxxx_audio.c @@ -303,7 +303,7 @@ static void via_chan_pcm_fmt (struct via_info *card, */ -static struct pci_device_id via_pci_tbl[] __devinitdata = { +static struct pci_device_id via_pci_tbl[] __initdata = { { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0, } }; diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c index 354c1d6cf924..40903a9c299a 100644 --- a/drivers/usb/audio.c +++ b/drivers/usb/audio.c @@ -3,7 +3,7 @@ /* * audio.c -- USB Audio Class driver * - * Copyright (C) 1999 + * Copyright (C) 1999, 2000 * Alan Cox (alan@lxorguk.ukuu.org.uk) * Thomas Sailer (sailer@ife.ee.ethz.ch) * @@ -59,6 +59,21 @@ * 1999-12-20: Fix bad bug in conversion to per interface probing. * disconnect was called multiple times for the audio device, * leading to a premature freeing of the audio structures + * 2000-05-13: I don't remember who changed the find_format routine, + * but the change was completely broken for the Dallas + * chip. Anyway taking sampling rate into account in find_format + * is bad and should not be done unless there are devices with + * completely broken audio descriptors. Unless someone shows + * me such a descriptor, I will not allow find_format to + * take the sampling rate into account. + * Also, the former find_format made: + * - mpg123 play mono instead of stereo + * - sox completely fail for wav's with sample rates < 44.1kHz + * for the Dallas chip. + * Also fix a rather long standing problem with applications that + * use "small" writes producing no sound at all. + * 2000-05-15: My fears came true, the Philips camera indeed has pretty stupid + * audio descriptors. * */ @@ -441,9 +456,9 @@ static int dmabuf_init(struct dmabuf *db) db->bufsize = nr << PAGE_SHIFT; db->ready = 1; printk(KERN_DEBUG "dmabuf_init: bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d " - "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d\n", + "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x\n", bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize, - db->numfrag, db->dmasize, db->bufsize); + db->numfrag, db->dmasize, db->bufsize, db->format); return 0; } @@ -973,6 +988,8 @@ static int usbin_start(struct usb_audiodev *as) } spin_lock_irqsave(&as->lock, flags); } + if (u->dma.count <= 0 && !u->dma.mapped) + return 0; u->flags |= FLG_RUNNING; if (!(u->flags & FLG_URB0RUNNING)) { urb = &u->durb[0].urb; @@ -1332,6 +1349,8 @@ static int usbout_start(struct usb_audiodev *as) } spin_lock_irqsave(&as->lock, flags); } + if (u->dma.count <= 0 && !u->dma.mapped) + return 0; u->flags |= FLG_RUNNING; if (!(u->flags & FLG_URB0RUNNING)) { urb = &u->durb[0].urb; @@ -1395,30 +1414,39 @@ static int usbout_start(struct usb_audiodev *as) /* --------------------------------------------------------------------- */ -static unsigned int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int rate) +static unsigned int format_goodness(struct audioformat *afp, unsigned int fmt, unsigned int srate) { - unsigned int i; + unsigned int g = 0; + + if (srate < afp->sratelo) + g += afp->sratelo - srate; + if (srate > afp->sratehi) + g += srate - afp->sratehi; + if (AFMT_ISSTEREO(afp->format) && !AFMT_ISSTEREO(fmt)) + g += 0x100000; + if (!AFMT_ISSTEREO(afp->format) && AFMT_ISSTEREO(fmt)) + g += 0x400000; + if (AFMT_IS16BIT(afp->format) && !AFMT_IS16BIT(fmt)) + g += 0x100000; + if (!AFMT_IS16BIT(afp->format) && AFMT_IS16BIT(fmt)) + g += 0x400000; + return g; +} + +static int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int srate) +{ + unsigned int i, g, gb = ~0; + int j = -1; /* default to failure */ - /* first find an exact match, taking both format and sample rate into account, - but ignore stereo bit */ + /* find "best" format (according to format_goodness) */ for (i = 0; i < nr; i++) { - if (afp[i].format == (fmt & ~AFMT_STEREO) && rate >= afp[i].sratelo && rate <= afp[i].sratehi) - return i; + g = format_goodness(&afp[i], fmt, srate); + if (g >= gb) + continue; + j = i; + gb = g; } - - /* second find a match with the same stereo/mono and 8bit/16bit property */ - for (i = 0; i < nr; i++) - if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) && - !AFMT_IS16BIT(afp[i].format) == !AFMT_IS16BIT(fmt) && - rate >= afp[i].sratelo && rate <= afp[i].sratehi) - return i; - /* third find a match with the same number of channels */ - for (i = 0; i < nr; i++) - if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) && - rate >= afp[i].sratelo && rate <= afp[i].sratehi) - return i; - /* return failure */ - return -1; + return j; } static int set_format_in(struct usb_audiodev *as) @@ -1430,9 +1458,9 @@ static int set_format_in(struct usb_audiodev *as) struct usbin *u = &as->usbin; struct dmabuf *d = &u->dma; struct audioformat *fmt; - unsigned int fmtnr, ep; + unsigned int ep; unsigned char data[3]; - int ret; + int fmtnr, ret; if (u->interface < 0 || u->interface >= config->bNumInterfaces) return 0; @@ -1465,7 +1493,9 @@ static int set_format_in(struct usb_audiodev *as) d->srate = fmt->sratelo; if (d->srate > fmt->sratehi) d->srate = fmt->sratehi; -printk(KERN_DEBUG "usb_audio: set_format_in: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting); +#if 1 + printk(KERN_DEBUG "usb_audio: set_format_in: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting); +#endif if (usb_set_interface(dev, alts->bInterfaceNumber, fmt->altsetting) < 0) { printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n", dev->devnum, u->interface, fmt->altsetting); @@ -1517,9 +1547,9 @@ static int set_format_out(struct usb_audiodev *as) struct usbout *u = &as->usbout; struct dmabuf *d = &u->dma; struct audioformat *fmt; - unsigned int fmtnr, ep; + unsigned int ep; unsigned char data[3]; - int ret; + int fmtnr, ret; if (u->interface < 0 || u->interface >= config->bNumInterfaces) return 0; @@ -1559,7 +1589,9 @@ static int set_format_out(struct usb_audiodev *as) d->srate = fmt->sratelo; if (d->srate > fmt->sratehi) d->srate = fmt->sratehi; -printk(KERN_DEBUG "usb_audio: set_format_out: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting); +#if 1 + printk(KERN_DEBUG "usb_audio: set_format_out: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting); +#endif if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) { printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n", dev->devnum, u->interface, fmt->altsetting); @@ -1927,6 +1959,7 @@ static int drain_out(struct usb_audiodev *as, int nonblock) if (as->usbout.dma.mapped || !as->usbout.dma.ready) return 0; + usbout_start(as); add_wait_queue(&as->usbout.dma.wait, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); @@ -2033,6 +2066,7 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou ssize_t ret = 0; unsigned long flags; unsigned int ptr; + unsigned int start_thr; int cnt, err; if (ppos != &file->f_pos) @@ -2043,10 +2077,11 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + start_thr = (as->usbout.dma.srate << AFMT_BYTESSHIFT(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES)); add_wait_queue(&as->usbout.dma.wait, &wait); while (count > 0) { #if 0 - printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%x\n", + printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%lx\n", count, as->usbout.dma.count, as->usbout.dma.rdptr, as->usbout.dma.wrptr, as->usbout.dma.dmasize, as->usbout.dma.fragsize, as->usbout.flags, current->state); #endif @@ -2097,7 +2132,7 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou count -= cnt; buffer += cnt; ret += cnt; - if (usbout_start(as)) { + if (as->usbout.dma.count >= start_thr && usbout_start(as)) { if (!ret) ret = -ENODEV; break; @@ -2525,17 +2560,6 @@ static /*const*/ struct file_operations usb_audio_fops = { /* --------------------------------------------------------------------- */ -/* - * TO DO in order to get to the point of building an OSS interface - * structure, let alone playing music.. - * - * Use kmalloc/kfree for the descriptors we build - * Write the descriptor->OSS convertor code - * Figure how we deal with mixers - * Check alternate configurations. For now assume we will find one - * zero bandwidth (idle) config and one or more live one pers interface. - */ - static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum); static void usb_audio_disconnect(struct usb_device *dev, void *ptr); @@ -2543,25 +2567,11 @@ static struct usb_driver usb_audio_driver = { "audio", usb_audio_probe, usb_audio_disconnect, - /*{ NULL, NULL }, */ LIST_HEAD_INIT(usb_audio_driver.driver_list), + LIST_HEAD_INIT(usb_audio_driver.driver_list), NULL, 0 }; - -#if 0 -static int usb_audio_irq(int state, void *buffer, int len, void *dev_id) -{ -#if 0 - struct usb_audio_device *aud = (struct usb_audio_device *)dev_id; - - printk(KERN_DEBUG "irq on %p\n", aud); -#endif - - return 1; -} -#endif - static void *find_descriptor(void *descstart, unsigned int desclen, void *after, u8 dtype, int iface, int altsetting) { @@ -3559,11 +3569,6 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr) unregister_sound_mixer(ms->dev_mixer); ms->dev_mixer = -1; } -#if 0 - if(aud->irq_handle) - usb_release_irq(dev, aud->irq_handle, aud->irqpipe); - aud->irq_handle = NULL; -#endif release(s); wake_up(&open_wait); } diff --git a/drivers/usb/input.c b/drivers/usb/input.c index 73f39db7ca22..35f268fac5b1 100644 --- a/drivers/usb/input.c +++ b/drivers/usb/input.c @@ -244,6 +244,7 @@ void input_unregister_device(struct input_dev *dev) { struct input_handle *handle = dev->handle; struct input_dev **devptr = &input_dev; + struct input_handle *dnext; /* * Kill any pending repeat timers. @@ -256,9 +257,10 @@ void input_unregister_device(struct input_dev *dev) */ while (handle) { + dnext = handle->dnext; input_unlink_handle(handle); handle->handler->disconnect(handle); - handle = handle->dnext; + handle = dnext; } /* @@ -309,15 +311,17 @@ void input_unregister_handler(struct input_handler *handler) { struct input_handler **handlerptr = &input_handler; struct input_handle *handle = handler->handle; + struct input_handle *hnext; /* * Tell the handler to disconnect from all devices it keeps open. */ while (handle) { + hnext = handle->hnext; input_unlink_handle(handle); handler->disconnect(handle); - handle = handle->hnext; + handle = hnext; } /* diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index d64258e8ed0b..c013a8154029 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -1,5 +1,5 @@ /* - * printer.c Version 0.3 + * printer.c Version 0.4 * * Copyright (c) 1999 Michael Gee * Copyright (c) 1999 Pavel Machek @@ -13,6 +13,7 @@ * v0.1 - thorough cleaning, URBification, almost a rewrite * v0.2 - some more cleanups * v0.3 - cleaner again, waitqueue fixes + * v0.4 - fixes in unidirectional mode */ /* @@ -102,7 +103,7 @@ static void usblp_bulk(struct urb *urb) return; if (urb->status) - warn("nonzero read bulk status received: %d", urb->status); + warn("nonzero read/write bulk status received: %d", urb->status); wake_up_interruptible(&usblp->wait); } @@ -172,9 +173,12 @@ static int usblp_open(struct inode *inode, struct file *file) usblp->writeurb.transfer_buffer_length = 0; usblp->writeurb.status = 0; - usblp->readcount = 0; - usb_submit_urb(&usblp->readurb); + if (usblp->bidir) { + usblp->readcount = 0; + usb_submit_urb(&usblp->readurb); + } + return 0; } @@ -185,7 +189,8 @@ static int usblp_release(struct inode *inode, struct file *file) usblp->used = 0; if (usblp->dev) { - usb_unlink_urb(&usblp->readurb); + if (usblp->bidir) + usb_unlink_urb(&usblp->readurb); usb_unlink_urb(&usblp->writeurb); MOD_DEC_USE_COUNT; return 0; @@ -203,8 +208,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait { struct usblp *usblp = file->private_data; poll_wait(file, &usblp->wait, wait); - return (usblp->readurb.status == -EINPROGRESS ? 0 : POLLIN | POLLRDNORM) - | (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM); + return ((usblp->bidir || usblp->readurb.status == -EINPROGRESS) ? 0 : POLLIN | POLLRDNORM) + | (usblp->writeurb.status == -EINPROGRESS ? 0 : POLLOUT | POLLWRNORM); } static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) @@ -315,7 +320,6 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum) int minor, i, alts = -1, bidir = 0; char *buf; - for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) { interface = &dev->actconfig->interface[ifnum].altsetting[i]; @@ -342,22 +346,21 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum) err("can't set desired altsetting %d on interface %d", alts, ifnum); epwrite = interface->endpoint + 0; - epread = NULL; - - if (bidir) { - epread = interface->endpoint + 1; - if ((epread->bEndpointAddress & 0x80) != 0x80) { - epwrite = interface->endpoint + 1; - epread = interface->endpoint + 0; + epread = bidir ? interface->endpoint + 1 : NULL; - if ((epread->bEndpointAddress & 0x80) != 0x80) - return NULL; - } + if ((epwrite->bEndpointAddress & 0x80) == 0x80) { + if (interface->bNumEndpoints == 1) + return NULL; + epwrite = interface->endpoint + 1; + epread = bidir ? interface->endpoint + 0 : NULL; } if ((epwrite->bEndpointAddress & 0x80) == 0x80) return NULL; + if (bidir && (epread->bEndpointAddress & 0x80) != 0x80) + return NULL; + for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++); if (usblp_table[minor]) { err("no more free usblp devices"); @@ -386,10 +389,9 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum) FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), buf, 0, usblp_bulk, usblp); - if (bidir) { + if (bidir) FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp); - } info("usblp%d: USB %sdirectional printer dev %d if %d alt %d", minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts); @@ -408,8 +410,9 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr) usblp->dev = NULL; - usb_unlink_urb(&usblp->readurb); usb_unlink_urb(&usblp->writeurb); + if (usblp->bidir) + usb_unlink_urb(&usblp->readurb); kfree(usblp->writeurb.transfer_buffer); diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c index 8a33186128fc..f2c51f2058ca 100644 --- a/drivers/usb/usb-uhci.c +++ b/drivers/usb/usb-uhci.c @@ -12,7 +12,7 @@ * (C) Copyright 1999 Johannes Erdfelt * (C) Copyright 1999 Randy Dunlap * - * $Id: usb-uhci.c,v 1.228 2000/04/02 19:55:51 acher Exp $ + * $Id: usb-uhci.c,v 1.231 2000/05/13 15:34:17 acher Exp $ */ #include @@ -48,7 +48,7 @@ /* This enables an extra UHCI slab for memory debugging */ #define DEBUG_SLAB -#define VERSTR "$Revision: 1.228 $ time " __TIME__ " " __DATE__ +#define VERSTR "$Revision: 1.231 $ time " __TIME__ " " __DATE__ #include #include "usb-uhci.h" @@ -109,10 +109,10 @@ void clean_descs(uhci_t *s, int force) while (q != &s->free_desc) { qh = list_entry (q, uhci_desc_t, horizontal); + q=qh->horizontal.prev; + if ((qh->last_used!=now) || force) delete_qh(s,qh); - - q=qh->horizontal.prev; } } /*-------------------------------------------------------------------*/ @@ -1142,6 +1142,12 @@ _static void uhci_cleanup_unlink(uhci_t *s, int force) if (!(urb->transfer_flags & USB_TIMEOUT_KILLED)) urb->status = -ENOENT; // now the urb is really dead + switch (usb_pipetype (pipe)) { + case PIPE_ISOCHRONOUS: + case PIPE_INTERRUPT: + uhci_clean_iso_step2(s, urb_priv); + break; + } usb_dec_dev_use (dev); #ifdef DEBUG_SLAB @@ -1149,12 +1155,7 @@ _static void uhci_cleanup_unlink(uhci_t *s, int force) #else kfree (urb_priv); #endif - switch (usb_pipetype (pipe)) { - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: - uhci_clean_iso_step2(s, urb_priv); - break; - } + list_del (&urb->urb_list); } } @@ -1168,7 +1169,9 @@ _static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb) async_dbg("unlink_urb_async called %p",urb); - if (urb->status == -EINPROGRESS) { + if ((urb->status == -EINPROGRESS) || + ((usb_pipetype (urb->pipe) == PIPE_INTERRUPT) && ((urb_priv_t*)urb->hcpriv)->flags)) + { ((urb_priv_t*)urb->hcpriv)->started = ~0; dequeue_urb (s, urb); @@ -1560,7 +1563,7 @@ _static int uhci_submit_urb (urb_t *urb) urb->hcpriv = urb_priv; INIT_LIST_HEAD (&urb_priv->desc_list); - urb_priv->short_control_packet = 0; + urb_priv->flags = 0; dbg("submit_urb: scheduling %p", urb); urb_priv->next_queued_urb = NULL; urb_priv->prev_queued_urb = NULL; @@ -2151,7 +2154,7 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode) status stage is completed */ - if (urb_priv->short_control_packet && + if (urb_priv->flags && ((qh->hw.qh.element == UHCI_PTR_TERM) ||(!(last_desc->hw.td.status & TD_CTRL_ACTIVE)))) goto transfer_finished; @@ -2199,7 +2202,7 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode) dbg("short packet during control transfer, retrigger status stage @ %p",last_desc); //uhci_show_td (desc); //uhci_show_td (last_desc); - urb_priv->short_control_packet=1; + urb_priv->flags = 1; // mark as short control packet return 0; } } @@ -2280,35 +2283,43 @@ _static int process_interrupt (uhci_t *s, urb_t *urb) if (urb->complete) { //dbg("process_interrupt: calling completion, status %i",status); urb->status = status; - + ((urb_priv_t*)urb->hcpriv)->flags=1; // if unlink_urb is called during completion + spin_unlock(&s->urb_list_lock); urb->complete ((struct urb *) urb); spin_lock(&s->urb_list_lock); - - urb->status = -EINPROGRESS; + + ((urb_priv_t*)urb->hcpriv)->flags=0; } + + if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) && + (urb->status != -ENOENT)) { + + urb->status = -EINPROGRESS; - // Recycle INT-TD if interval!=0, else mark TD as one-shot - if (urb->interval) { - - desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE); - if (status==0) { - ((urb_priv_t*)urb->hcpriv)->started=jiffies; - desc->hw.td.info |= (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE); - usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); - } else { - desc->hw.td.info |= (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE); + // Recycle INT-TD if interval!=0, else mark TD as one-shot + if (urb->interval) { + + desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE); + if (status==0) { + ((urb_priv_t*)urb->hcpriv)->started=jiffies; + desc->hw.td.info |= (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE); + usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); + } else { + desc->hw.td.info |= (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE); + } + desc->hw.td.status= (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | + (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); + mb(); + } + else { + uhci_unlink_urb_async(s, urb); + desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD } - desc->hw.td.status= (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | - (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); - mb(); - } - else { - desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD } } @@ -2334,7 +2345,7 @@ _static int process_iso (uhci_t *s, urb_t *urb, int mode) dbg("process iso urb %p, %li, %i, %i, %i %08x",urb,jiffies,UHCI_GET_CURRENT_FRAME(s), urb->number_of_packets,mode,desc->hw.td.status); - for (i = 0; p != &urb_priv->desc_list; p = p->next, i++) { + for (i = 0; p != &urb_priv->desc_list; i++) { desc = list_entry (p, uhci_desc_t, desc_list); //uhci_show_td(desc); @@ -2378,8 +2389,9 @@ _static int process_iso (uhci_t *s, urb_t *urb, int mode) dbg("process_iso: %i: len:%d %08x status:%x", i, urb->iso_frame_desc[i].actual_length, desc->hw.td.status,urb->iso_frame_desc[i].status); - delete_desc (desc); list_del (p); + p = p->next; + delete_desc (desc); } dbg("process_iso: exit %i (%d), actual_len %i", i, ret,urb->actual_length); @@ -2824,7 +2836,6 @@ int __init uhci_init (void) if (type != 0) continue; - if (pci_enable_device (dev) < 0) continue; diff --git a/drivers/usb/usb-uhci.h b/drivers/usb/usb-uhci.h index 3c5717d1eb30..67eb4d210cbf 100644 --- a/drivers/usb/usb-uhci.h +++ b/drivers/usb/usb-uhci.h @@ -2,7 +2,7 @@ #define __LINUX_UHCI_H /* - $Id: usb-uhci.h,v 1.54 2000/04/02 19:55:53 acher Exp $ + $Id: usb-uhci.h,v 1.55 2000/05/13 12:50:30 acher Exp $ */ #define MODNAME "usb-uhci" #define UHCI_LATENCY_TIMER 0 @@ -160,7 +160,7 @@ typedef struct { uhci_desc_t *bottom_qh; uhci_desc_t *next_qh; // next helper QH char use_loop; - char short_control_packet; + char flags; } urb_priv_t, *purb_priv_t; struct virt_root_hub { diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 2e87c79d7d6e..8a8bea5a0d4e 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -1636,3 +1636,5 @@ static void __exit cyberpro_exit(void) module_init(cyber2000fb_init); #endif module_exit(cyberpro_exit); + +MODULE_DEVICE_TABLE(pci, cyberpro_pci_table); diff --git a/drivers/video/cyber2000fb.h b/drivers/video/cyber2000fb.h index eefc038da620..c6d605553581 100644 --- a/drivers/video/cyber2000fb.h +++ b/drivers/video/cyber2000fb.h @@ -3,6 +3,7 @@ * * Integraphics Cyber2000 frame buffer device */ +#include #define cyber2000_outb(dat,reg) writeb(dat, CyberRegs + reg) #define cyber2000_outw(dat,reg) writew(dat, CyberRegs + reg) diff --git a/fs/Makefile b/fs/Makefile index 9219a138f6ea..0693daf69fdd 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -21,7 +21,7 @@ ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ nfsd nls devpts devfs adfs partitions qnx4 udf bfs cramfs \ openpromfs autofs4 ramfs -SUB_DIRS := partitions +SUB_DIRS := ifeq ($(CONFIG_QUOTA),y) O_OBJS += dquot.o @@ -29,6 +29,14 @@ else O_OBJS += noquot.o endif +ifdef CONFIG_PROC_FS +SUB_DIRS += proc +endif + +SUB_DIRS += partitions + +# Do not add any filesystems before this line + ifeq ($(CONFIG_EXT2_FS),y) SUB_DIRS += ext2 else @@ -93,10 +101,6 @@ else endif endif -ifdef CONFIG_PROC_FS -SUB_DIRS += proc -endif - ifeq ($(CONFIG_BFS_FS),y) SUB_DIRS += bfs else diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 49d818e21e71..ef4af4dfefda 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -86,6 +86,8 @@ static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) struct user dump; #if defined(__alpha__) # define START_DATA(u) (u.start_data) +#elif defined(__arm__) +# define START_DATA(u) ((u.u_tsize << PAGE_SHIFT) + u.start_code) #elif defined(__sparc__) # define START_DATA(u) (u.u_tsize) #elif defined(__i386__) || defined(__mc68000__) @@ -217,7 +219,7 @@ static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm) envp = (char **) sp; sp -= argc+1; argv = (char **) sp; -#if defined(__i386__) || defined(__mc68000__) +#if defined(__i386__) || defined(__mc68000__) || defined(__arm__) put_user((unsigned long) envp,--sp); put_user((unsigned long) argv,--sp); #endif diff --git a/fs/dcache.c b/fs/dcache.c index 1b3ff98b2530..6eac456ad622 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -788,7 +788,7 @@ void d_rehash(struct dentry * entry) * Note that we have to be a lot more careful about getting the hash * switched - we have to switch the hash value properly even if it * then no longer matches the actual (corrupted) string of the target. - * The has value has to match the hash queue that the dentry is on.. + * The hash value has to match the hash queue that the dentry is on.. */ static inline void switch_names(struct dentry * dentry, struct dentry * target) { diff --git a/fs/exec.c b/fs/exec.c index 992bbd6aa8a7..eded5971f2b6 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -288,6 +288,7 @@ int setup_arg_pages(struct linux_binprm *bprm) if (!mpnt) return -ENOMEM; + down(¤t->mm->mmap_sem); { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; @@ -311,6 +312,7 @@ int setup_arg_pages(struct linux_binprm *bprm) } stack_base += PAGE_SIZE; } + up(¤t->mm->mmap_sem); return 0; } diff --git a/fs/hfs/balloc.c b/fs/hfs/balloc.c index d7e17e72f847..4edd6b7482dc 100644 --- a/fs/hfs/balloc.c +++ b/fs/hfs/balloc.c @@ -86,6 +86,8 @@ static struct hfs_bnode_ref hfs_bnode_init(struct hfs_btree * tree, retval.bn->magic = HFS_BNODE_MAGIC; retval.bn->tree = tree; retval.bn->node = node; + hfs_init_waitqueue(&retval.bn->wqueue); + hfs_init_waitqueue(&retval.bn->rqueue); hfs_bnode_lock(&retval, HFS_LOCK_WRITE); retval.bn->buf = get_new_node(tree, node); diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 85e3a909b76d..e2b975fae965 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -60,7 +60,7 @@ typedef struct { hfs_byte_t RExtRec[12]; /* first extent record for the resource fork */ hfs_lword_t Resrv; /* reserved by Apple */ -} FIL_REC; +} __attribute__((packed)) FIL_REC; /* the catalog record for a directory */ typedef struct { @@ -74,14 +74,14 @@ typedef struct { hfs_dinfo_t UsrInfo; /* data used by the Finder */ hfs_dxinfo_t FndrInfo; /* more data used by Finder */ hfs_byte_t Resrv[16]; /* reserved by Apple */ -} DIR_REC; +} __attribute__((packed)) DIR_REC; /* the catalog record for a thread */ typedef struct { hfs_byte_t Reserv[8]; /* reserved by Apple */ hfs_lword_t ParID; /* CNID of parent directory */ struct hfs_name CName; /* The name of this entry */ -} THD_REC; +} __attribute__((packed)) THD_REC; /* A catalog tree record */ struct hfs_cat_rec { @@ -92,7 +92,7 @@ struct hfs_cat_rec { DIR_REC dir; THD_REC thd; } u; -}; +} __attribute__((packed)); /*================ File-local variables ================*/ diff --git a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c index 80e47fc62843..ba62615b0357 100644 --- a/fs/hfs/file_hdr.c +++ b/fs/hfs/file_hdr.c @@ -158,7 +158,7 @@ struct hdr_hdr { hfs_byte_t filler[16]; hfs_word_t entries; hfs_byte_t descrs[12*HFS_HDR_MAX]; -}; +} __attribute__((packed)); /*================ File-local functions ================*/ diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h index 3819a685f480..9552bbb34154 100644 --- a/fs/hfs/hfs.h +++ b/fs/hfs/hfs.h @@ -130,7 +130,7 @@ struct hfs_name { hfs_byte_t Len; hfs_byte_t Name[31]; -}; +} __attribute__((packed)); typedef struct { hfs_word_t v; @@ -150,21 +150,21 @@ typedef struct { hfs_word_t fdFlags; hfs_point_t fdLocation; hfs_word_t fdFldr; -} hfs_finfo_t; +} __attribute__((packed)) hfs_finfo_t; typedef struct { hfs_word_t fdIconID; hfs_byte_t fdUnused[8]; hfs_word_t fdComment; hfs_lword_t fdPutAway; -} hfs_fxinfo_t; +} __attribute__((packed)) hfs_fxinfo_t; typedef struct { hfs_rect_t frRect; hfs_word_t frFlags; hfs_point_t frLocation; hfs_word_t frView; -} hfs_dinfo_t; +} __attribute__((packed)) hfs_dinfo_t; typedef struct { hfs_point_t frScroll; @@ -172,7 +172,7 @@ typedef struct { hfs_word_t frUnused; hfs_word_t frComment; hfs_lword_t frPutAway; -} hfs_dxinfo_t; +} __attribute__((packed)) hfs_dxinfo_t; union hfs_finder_info { struct { @@ -189,7 +189,7 @@ union hfs_finder_info { struct hfs_bkey { hfs_byte_t KeyLen; /* number of bytes in the key */ hfs_byte_t value[1]; /* (KeyLen) bytes of key */ -}; +} __attribute__((packed)); /* Cast to a pointer to a generic bkey */ #define HFS_BKEY(X) (((void)((X)->KeyLen)), ((struct hfs_bkey *)(X))) @@ -200,7 +200,7 @@ struct hfs_cat_key { hfs_byte_t Resrv1; /* padding */ hfs_lword_t ParID; /* CNID of the parent dir */ struct hfs_name CName; /* The filename of the entry */ -}; +} __attribute__((packed)); /* The key used in the extents b-tree: */ struct hfs_ext_key { @@ -208,7 +208,7 @@ struct hfs_ext_key { hfs_byte_t FkType; /* HFS_FK_{DATA,RSRC} */ hfs_lword_t FNum; /* The File ID of the file */ hfs_word_t FABN; /* allocation blocks number*/ -}; +} __attribute__((packed)); /*======== Data structures kept in memory ========*/ diff --git a/fs/hfs/hfs_btree.h b/fs/hfs/hfs_btree.h index 97423b350179..39d6df4d52d8 100644 --- a/fs/hfs/hfs_btree.h +++ b/fs/hfs/hfs_btree.h @@ -90,7 +90,7 @@ struct BTHdrRec { hfs_byte_t bthResv2; /* reserved */ hfs_lword_t bthAtrb; /* (F) attributes */ hfs_lword_t bthResv3[16]; /* Reserved */ -}; +} __attribute__((packed)); /* * struct NodeDescriptor @@ -112,7 +112,7 @@ struct NodeDescriptor { hfs_byte_t ndNHeight; /* (F) The level of this node (leaves=1) */ hfs_word_t ndNRecs; /* (V) The number of records in this node */ hfs_word_t ndResv2; /* Reserved */ -}; +} __attribute__((packed)); /* * typedef hfs_cmpfn diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c index 386a6ae7936b..b44fdafc8390 100644 --- a/fs/hfs/mdb.c +++ b/fs/hfs/mdb.c @@ -71,7 +71,7 @@ struct raw_mdb { hfs_byte_t drXTExtRec[12]; /* extents B-tree's first 3 extents */ hfs_lword_t drCTFlSize; /* bytes in the catalog B-tree */ hfs_byte_t drCTExtRec[12]; /* catalog B-tree's first 3 extents */ -}; +} __attribute__((packed)); /*================ Global functions ================*/ diff --git a/fs/hfs/part_tbl.c b/fs/hfs/part_tbl.c index 12922c6d7819..2392a0791bec 100644 --- a/fs/hfs/part_tbl.c +++ b/fs/hfs/part_tbl.c @@ -77,7 +77,7 @@ struct old_pmap { hfs_lword_t pdSize; hfs_lword_t pdFSID; } pdEntry[42]; -}; +} __attribute__((packed)); /*================ File-local functions ================*/ diff --git a/fs/inode.c b/fs/inode.c index 1bacb24a7b2f..64373d6ad05d 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -377,7 +377,7 @@ static int invalidate_list(struct list_head *head, struct super_block * sb, stru * * Discard all of the inodes for a given superblock. If the discard * fails because there are busy inodes then a non zero value is returned. - * If the discard is successful all the inodes are dicarded. + * If the discard is successful all the inodes have been discarded. */ int invalidate_inodes(struct super_block * sb) @@ -470,7 +470,7 @@ int shrink_icache_memory(int priority, int gfp_mask) /* * Called with the inode lock held. * NOTE: we are not increasing the inode-refcount, you must call __iget() - * by hand after calling find_inode now! This simplify iunique and won't + * by hand after calling find_inode now! This simplifies iunique and won't * add any additional branch in the common code. */ static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque) diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 376eed9cc4ab..cc3025ee3268 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -233,11 +233,21 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc) struct rpc_clnt *clnt; struct nlm_args *argp = &req->a_args; struct nlm_res *resp = &req->a_res; + struct file *filp = argp->lock.fl.fl_file; + struct rpc_message msg; int status; dprintk("lockd: call procedure %s on %s\n", nlm_procname(proc), host->h_name); + msg.rpc_proc = proc; + msg.rpc_argp = argp; + msg.rpc_resp = resp; + if (filp) + msg.rpc_cred = nfs_file_cred(filp); + else + msg.rpc_cred = NULL; + do { if (host->h_reclaiming && !argp->reclaim) { interruptible_sleep_on(&host->h_gracewait); @@ -249,7 +259,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc) return -ENOLCK; /* Perform the RPC call. If an error occurs, try again */ - if ((status = rpc_call(clnt, proc, argp, resp, 0)) < 0) { + if ((status = rpc_call_sync(clnt, &msg, 0)) < 0) { dprintk("lockd: rpc_call returned error %d\n", -status); switch (status) { case -EPROTONOSUPPORT: @@ -330,11 +340,31 @@ int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback) { struct nlm_host *host = req->a_host; - int status; + struct rpc_clnt *clnt; + struct nlm_args *argp = &req->a_args; + struct nlm_res *resp = &req->a_res; + struct file *file = argp->lock.fl.fl_file; + struct rpc_message msg; + int status; + dprintk("lockd: call procedure %s on %s (async)\n", + nlm_procname(proc), host->h_name); + + /* If we have no RPC client yet, create one. */ + if ((clnt = nlm_bind_host(host)) == NULL) + return -ENOLCK; + + /* bootstrap and kick off the async RPC call */ + msg.rpc_proc = proc; + msg.rpc_argp = argp; + msg.rpc_resp =resp; + if (file) + msg.rpc_cred = nfs_file_cred(file); + else + msg.rpc_cred = NULL; /* Increment host refcount */ nlm_get_host(host); - status = nlmsvc_async_call(req, proc, callback); + status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req); if (status < 0) nlm_release_host(host); return status; diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 97a9d27efddf..279fcc3c19c0 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -533,8 +533,10 @@ callback: nlmsvc_insert_block(block, jiffies + 30 * HZ); /* Call the client */ - nlmclnt_async_call(&block->b_call, NLMPROC_GRANTED_MSG, - nlmsvc_grant_callback); + nlm_get_host(block->b_call.a_host); + if (nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG, + nlmsvc_grant_callback) < 0) + nlm_release_host(block->b_call.a_host); up(&file->f_sema); } diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 2d2ee4a02975..20840acbadef 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -71,6 +71,70 @@ struct inode_operations nfs_dir_inode_operations = { }; typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int); +typedef struct { + struct file *file; + struct page *page; + unsigned long page_index; + unsigned page_offset; + u64 target; + struct nfs_entry *entry; + decode_dirent_t decode; + int plus; + int error; +} nfs_readdir_descriptor_t; + +/* Now we cache directories properly, by stuffing the dirent + * data directly in the page cache. + * + * Inode invalidation due to refresh etc. takes care of + * _everything_, no sloppy entry flushing logic, no extraneous + * copying, network direct to page cache, the way it was meant + * to be. + * + * NOTE: Dirent information verification is done always by the + * page-in of the RPC reply, nowhere else, this simplies + * things substantially. + */ +static +int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) +{ + struct dentry *dir = desc->file->f_dentry; + struct inode *inode = dir->d_inode; + void *buffer = (void *)kmap(page); + int plus = NFS_USE_READDIRPLUS(inode); + int error; + + dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index); + + again: + error = NFS_PROTO(inode)->readdir(dir, desc->entry->cookie, buffer, + NFS_SERVER(inode)->dtsize, plus); + /* We requested READDIRPLUS, but the server doesn't grok it */ + if (desc->plus && error == -ENOTSUPP) { + NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS; + plus = 0; + goto again; + } + if (error < 0) + goto error; + SetPageUptodate(page); + kunmap(page); + /* Ensure consistent page alignment of the data. + * Note: assumes we have exclusive access to this mapping either + * throught inode->i_sem or some other mechanism. + */ + if (page->index == 0) + invalidate_inode_pages(inode); + UnlockPage(page); + return 0; + error: + SetPageError(page); + kunmap(page); + UnlockPage(page); + invalidate_inode_pages(inode); + desc->error = error; + return -EIO; +} /* * Given a pointer to a buffer that has already been filled by a call @@ -81,309 +145,217 @@ typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int); * read. */ static inline -long find_dirent(struct page *page, loff_t offset, - struct nfs_entry *entry, - decode_dirent_t decode, int plus, int use_cookie) +int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page) { - u8 *p = (u8 *)kmap(page), - *start = p; - unsigned long base = page_offset(page), - pg_offset = 0; - int loop_count = 0; + struct nfs_entry *entry = desc->entry; + char *start = (char *)kmap(page), + *p = start; + int loop_count = 0, + status = 0; - if (!p) - return -EIO; for(;;) { - p = (u8*)decode((__u32*)p, entry, plus); - if (IS_ERR(p)) + p = (char *)desc->decode((u32*)p, entry, desc->plus); + if (IS_ERR(p)) { + status = PTR_ERR(p); break; - pg_offset = p - start; - entry->prev = entry->offset; - entry->offset = base + pg_offset; - if ((use_cookie ? entry->cookie : entry->offset) > offset) + } + desc->page_offset = p - start; + dfprintk(VFS, "NFS: found cookie %Lu\n", (long long)entry->cookie); + if (entry->prev_cookie == desc->target) break; if (loop_count++ > 200) { loop_count = 0; schedule(); } } - kunmap(page); - return (IS_ERR(p)) ? PTR_ERR(p) : (long)pg_offset; + dfprintk(VFS, "NFS: find_dirent() returns %d\n", status); + return status; } /* * Find the given page, and call find_dirent() in order to try to * return the next entry. - * - * Returns -EIO if the page is not available, or up to date. */ static inline -long find_dirent_page(struct inode *inode, loff_t offset, - struct nfs_entry *entry) +int find_dirent_page(nfs_readdir_descriptor_t *desc) { - decode_dirent_t decode = NFS_PROTO(inode)->decode_dirent; + struct inode *inode = desc->file->f_dentry->d_inode; struct page *page; - unsigned long index = entry->offset >> PAGE_CACHE_SHIFT; - long status = -EIO; - int plus = NFS_USE_READDIRPLUS(inode), - use_cookie = NFS_MONOTONE_COOKIES(inode); - - dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", entry->offset & PAGE_CACHE_MASK); - - if (entry->page) - page_cache_release(entry->page); + unsigned long index = desc->page_index; + int status; - page = find_get_page(&inode->i_data, index); + dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", desc->page_index); - if (page && Page_Uptodate(page)) - status = find_dirent(page, offset, entry, decode, plus, use_cookie); - - /* NB: on successful return we will be holding the page */ - if (status < 0) { - entry->page = NULL; - if (page) - page_cache_release(page); - } else - entry->page = page; + if (desc->page) { + page_cache_release(desc->page); + desc->page = NULL; + } - dfprintk(VFS, "NFS: find_dirent_page() returns %ld\n", status); + page = read_cache_page(&inode->i_data, index, + (filler_t *)nfs_readdir_filler, desc); + if (IS_ERR(page)) { + status = PTR_ERR(page); + goto out; + } + if (!Page_Uptodate(page)) + goto read_error; + + /* NOTE: Someone else may have changed the READDIRPLUS flag */ + desc->plus = NFS_USE_READDIRPLUS(inode); + status = find_dirent(desc, page); + if (status >= 0) + desc->page = page; + else + page_cache_release(page); + out: + dfprintk(VFS, "NFS: find_dirent_page() returns %d\n", status); return status; + read_error: + page_cache_release(page); + return -EIO; } - /* * Recurse through the page cache pages, and return a * filled nfs_entry structure of the next directory entry if possible. * - * The target for the search is position 'offset'. - * The latter may either be an offset into the page cache, or (better) - * a cookie depending on whether we're interested in strictly following - * the RFC wrt. not assuming monotonicity of cookies or not. - * - * For most systems, the latter is more reliable since it naturally - * copes with holes in the directory. + * The target for the search is 'desc->target'. */ static inline -long search_cached_dirent_pages(struct inode *inode, loff_t offset, - struct nfs_entry *entry) +int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) { - long res = 0; + int res = 0; int loop_count = 0; - dfprintk(VFS, "NFS: search_cached_dirent_pages() searching for cookie %Ld\n", (long long)offset); + dfprintk(VFS, "NFS: readdir_search_pagecache() searching for cookie %Lu\n", (long long)desc->target); for (;;) { - res = find_dirent_page(inode, offset, entry); - if (res == -EAGAIN) { - /* Align to beginning of next page */ - entry->offset &= PAGE_CACHE_MASK; - entry->offset += PAGE_CACHE_SIZE; - } + res = find_dirent_page(desc); if (res != -EAGAIN) break; + /* Align to beginning of next page */ + desc->page_offset = 0; + desc->page_index ++; if (loop_count++ > 200) { loop_count = 0; schedule(); } } - if (res < 0 && entry->page) { - page_cache_release(entry->page); - entry->page = NULL; - } - dfprintk(VFS, "NFS: search_cached_dirent_pages() returned %ld\n", res); + dfprintk(VFS, "NFS: readdir_search_pagecache() returned %d\n", res); return res; } - -/* Now we cache directories properly, by stuffing the dirent - * data directly in the page cache. - * - * Inode invalidation due to refresh etc. takes care of - * _everything_, no sloppy entry flushing logic, no extraneous - * copying, network direct to page cache, the way it was meant - * to be. - * - * NOTE: Dirent information verification is done always by the - * page-in of the RPC reply, nowhere else, this simplies - * things substantially. - */ -static inline -long try_to_get_dirent_page(struct file *file, struct inode *inode, - struct nfs_entry *entry) -{ - struct dentry *dir = file->f_dentry; - struct page *page; - __u32 *p; - unsigned long index = entry->offset >> PAGE_CACHE_SHIFT; - long res = 0; - unsigned int dtsize = NFS_SERVER(inode)->dtsize; - int plus = NFS_USE_READDIRPLUS(inode); - - dfprintk(VFS, "NFS: try_to_get_dirent_page() reading directory page @ index %ld\n", index); - - page = grab_cache_page(&inode->i_data, index); - - if (!page) { - res = -ENOMEM; - goto out; - } - - if (Page_Uptodate(page)) { - dfprintk(VFS, "NFS: try_to_get_dirent_page(): page already up to date.\n"); - goto unlock_out; - } - - p = (__u32 *)kmap(page); - - if (dtsize > PAGE_CACHE_SIZE) - dtsize = PAGE_CACHE_SIZE; - res = NFS_PROTO(inode)->readdir(dir, entry->cookie, p, dtsize, plus); - - kunmap(page); - - if (res < 0) - goto error; - if (PageError(page)) - ClearPageError(page); - SetPageUptodate(page); - - unlock_out: - UnlockPage(page); - page_cache_release(page); - out: - dfprintk(VFS, "NFS: try_to_get_dirent_page() returns %ld\n", res); - return res; - error: - SetPageError(page); - goto unlock_out; -} - -/* Recover from a revalidation flush. The case here is that - * the inode for the directory got invalidated somehow, and - * all of our cached information is lost. In order to get - * a correct cookie for the current readdir request from the - * user, we must (re-)fetch all the older readdir page cache - * entries. - * - * Returns < 0 if some error occurs. +/* + * Once we've found the start of the dirent within a page: fill 'er up... */ -static inline -long refetch_to_readdir(struct file *file, struct inode *inode, - loff_t off, struct nfs_entry *entry) +static +int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, + filldir_t filldir) { - struct nfs_entry my_dirent, - *dirent = &my_dirent; - long res; - int plus = NFS_USE_READDIRPLUS(inode), - use_cookie = NFS_MONOTONE_COOKIES(inode), - loop_count = 0; - - dfprintk(VFS, "NFS: refetch_to_readdir() searching for cookie %Ld\n", (long long)off); - *dirent = *entry; - entry->page = NULL; - - for (res = 0;res >= 0;) { - if (loop_count++ > 200) { - loop_count = 0; - schedule(); - } + struct file *file = desc->file; + struct nfs_entry *entry = desc->entry; + char *start = (char *)kmap(desc->page), + *p = start + desc->page_offset; + unsigned long fileid; + int loop_count = 0, + res = 0; - /* Search for last cookie in page cache */ - res = search_cached_dirent_pages(inode, off, dirent); + dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ cookie %Lu\n", (long long)desc->target); - if (res >= 0) { - /* Cookie was found */ - if ((use_cookie?dirent->cookie:dirent->offset) > off) { - *entry = *dirent; - dirent->page = NULL; - break; + for(;;) { + /* Note: entry->prev_cookie contains the cookie for + * retrieving the current dirent on the server */ + fileid = nfs_fileid_to_ino_t(entry->ino); + res = filldir(dirent, entry->name, entry->len, + entry->prev_cookie, fileid); + if (res < 0) + break; + file->f_pos = desc->target = entry->cookie; + p = (char *)desc->decode((u32 *)p, entry, desc->plus); + if (IS_ERR(p)) { + if (PTR_ERR(p) == -EAGAIN) { + desc->page_offset = 0; + desc->page_index ++; } - continue; - } - - if (dirent->page) - page_cache_release(dirent->page); - dirent->page = NULL; - - if (res != -EIO) { - *entry = *dirent; break; } - - /* Read in a new page */ - res = try_to_get_dirent_page(file, inode, dirent); - if (res == -EBADCOOKIE) { - memset(dirent, 0, sizeof(*dirent)); - nfs_zap_caches(inode); - res = 0; - } - /* We requested READDIRPLUS, but the server doesn't grok it */ - if (plus && res == -ENOTSUPP) { - NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS; - memset(dirent, 0, sizeof(*dirent)); - nfs_zap_caches(inode); - plus = 0; - res = 0; + desc->page_offset = p - start; + if (loop_count++ > 200) { + loop_count = 0; + schedule(); } } - if (dirent->page) - page_cache_release(dirent->page); + kunmap(desc->page); + page_cache_release(desc->page); + desc->page = NULL; - dfprintk(VFS, "NFS: refetch_to_readdir() returns %ld\n", res); + dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", (long long)desc->target, res); return res; } /* - * Once we've found the start of the dirent within a page: fill 'er up... + * If we cannot find a cookie in our cache, we suspect that this is + * because it points to a deleted file, so we ask the server to return + * whatever it thinks is the next entry. We then feed this to filldir. + * If all goes well, we should then be able to find our way round the + * cache on the next call to readdir_search_pagecache(); + * + * NOTE: we cannot add the anonymous page to the pagecache because + * the data it contains might not be page aligned. Besides, + * we should already have a complete representation of the + * directory in the page cache by the time we get here. */ -static -int nfs_do_filldir(struct file *file, struct inode *inode, - struct nfs_entry *entry, void *dirent, filldir_t filldir) +static inline +int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, + filldir_t filldir) { - decode_dirent_t decode = NFS_PROTO(inode)->decode_dirent; - struct page *page = entry->page; - __u8 *p, - *start; - unsigned long base = page_offset(page), - offset = entry->offset, - pg_offset, - fileid; - int plus = NFS_USE_READDIRPLUS(inode), - use_cookie = NFS_MONOTONE_COOKIES(inode), - loop_count = 0, - res = 0; - - dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ offset %ld\n", entry->offset); - pg_offset = offset & ~PAGE_CACHE_MASK; - start = (u8*)kmap(page); - p = start + pg_offset; + struct dentry *dir = desc->file->f_dentry; + struct inode *inode = dir->d_inode; + struct page *page = NULL; + u32 *p; + int status = -EIO; + + dfprintk(VFS, "NFS: uncached_readdir() searching for cookie %Lu\n", (long long)desc->target); + if (desc->page) { + page_cache_release(desc->page); + desc->page = NULL; + } - for(;;) { - /* Note: entry->prev contains the offset of the start of the - * current dirent */ - fileid = nfs_fileid_to_ino_t(entry->ino); - if (use_cookie) - res = filldir(dirent, entry->name, entry->len, entry->prev_cookie, fileid); + page = page_cache_alloc(); + if (!page) { + status = -ENOMEM; + goto out; + } + p = (u32 *)kmap(page); + status = NFS_PROTO(inode)->readdir(dir, desc->target, p, + NFS_SERVER(inode)->dtsize, 0); + if (status >= 0) { + p = desc->decode(p, desc->entry, 0); + if (IS_ERR(p)) + status = PTR_ERR(p); else - res = filldir(dirent, entry->name, entry->len, entry->prev, fileid); - if (res < 0) - break; - file->f_pos = (use_cookie) ? entry->cookie : entry->offset; - p = (u8*)decode((__u32*)p, entry, plus); - if (!p || IS_ERR(p)) - break; - pg_offset = p - start; - entry->prev = entry->offset; - entry->offset = base + pg_offset; - if (loop_count++ > 200) { - loop_count = 0; - schedule(); - } + desc->entry->prev_cookie = desc->target; } kunmap(page); - - dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ offset %ld; returning = %d\n", entry->offset, res); - return res; + if (status < 0) + goto out_release; + + desc->page_index = 0; + desc->page_offset = 0; + desc->page = page; + status = nfs_do_filldir(desc, dirent, filldir); + + /* Reset read descriptor so it searches the page cache from + * the start upon the next call to readdir_search_pagecache() */ + desc->page_index = 0; + desc->page_offset = 0; + memset(desc->entry, 0, sizeof(*desc->entry)); + out: + dfprintk(VFS, "NFS: uncached_readdir() returns %d\n", status); + return status; + out_release: + page_cache_release(page); + goto out; } /* The file offset position is now represented as a true offset into the @@ -393,10 +365,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; - struct page *page; - struct nfs_entry my_entry, - *entry = &my_entry; - loff_t offset; + nfs_readdir_descriptor_t my_desc, + *desc = &my_desc; + struct nfs_entry my_entry; long res; res = nfs_revalidate(dentry); @@ -409,36 +380,41 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) * read from the last dirent to revalidate f_pos * itself. */ - memset(entry, 0, sizeof(*entry)); + memset(desc, 0, sizeof(*desc)); + memset(&my_entry, 0, sizeof(my_entry)); - offset = filp->f_pos; + desc->file = filp; + desc->target = filp->f_pos; + desc->entry = &my_entry; + desc->decode = NFS_PROTO(inode)->decode_dirent; - while(!entry->eof) { - res = search_cached_dirent_pages(inode, offset, entry); - - if (res < 0) { - if (entry->eof) - break; - res = refetch_to_readdir(filp, inode, offset, entry); - if (res < 0) + while(!desc->entry->eof) { + res = readdir_search_pagecache(desc); + if (res == -EBADCOOKIE) { + /* This means either end of directory */ + if (desc->entry->cookie == desc->target) { + res = 0; break; + } + /* Or that the server has 'lost' a cookie */ + res = uncached_readdir(desc, dirent, filldir); + if (res >= 0) + continue; } + if (res < 0) + break; - page = entry->page; - if (!page) - printk(KERN_ERR "NFS: Missing page...\n"); - res = nfs_do_filldir(filp, inode, entry, dirent, filldir); - page_cache_release(page); - entry->page = NULL; + res = nfs_do_filldir(desc, dirent, filldir); if (res < 0) { res = 0; break; } - offset = filp->f_pos; } - if (entry->page) - page_cache_release(entry->page); - if (res < 0 && res != -EBADCOOKIE) + if (desc->page) + page_cache_release(desc->page); + if (desc->error < 0) + return desc->error; + if (res < 0) return res; return 0; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 2d71aa7b5c83..5b1092846a45 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -895,11 +895,20 @@ nfs_revalidate(struct dentry *dentry) */ int nfs_open(struct inode *inode, struct file *filp) { + struct rpc_auth *auth = NFS_CLIENT(inode)->cl_auth; + struct rpc_cred *cred = rpcauth_lookupcred(auth, 0); + + filp->private_data = cred; return 0; } int nfs_release(struct inode *inode, struct file *filp) { + struct rpc_auth *auth = NFS_CLIENT(inode)->cl_auth; + struct rpc_cred *cred = nfs_file_cred(filp); + + if (cred) + rpcauth_releasecred(auth, cred); return 0; } diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 1dd1553ba138..a8b61c2e7ef1 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -485,13 +485,6 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res) break; } } - p++; /* EOF flag */ - - if (p > end) { - printk(KERN_NOTICE - "NFS: short packet in readdir reply!\n"); - return -errno_NFSERR_IO; - } return nr; } diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 67de662a6b10..4502e46018a0 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -138,14 +138,16 @@ nfs3_proc_readlink(struct dentry *dentry, void *buffer, unsigned int buflen) } static int -nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags, +nfs3_proc_read(struct file *file, struct nfs_fattr *fattr, int flags, loff_t offset, unsigned int count, void *buffer, int *eofp) { + struct dentry *dentry = file->f_dentry; + struct rpc_cred *cred = nfs_file_cred(file); struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1, {{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} }; struct nfs_readres res = { fattr, count, 0 }; - struct rpc_message msg = { NFS3PROC_READ, &arg, &res, NULL }; + struct rpc_message msg = { NFS3PROC_READ, &arg, &res, cred }; int status; dprintk("NFS call read %d @ %Ld\n", count, (long long)offset); @@ -157,16 +159,18 @@ nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags, } static int -nfs3_proc_write(struct dentry *dentry, struct nfs_fattr *fattr, int flags, +nfs3_proc_write(struct file *file, struct nfs_fattr *fattr, int flags, loff_t offset, unsigned int count, void *buffer, struct nfs_writeverf *verf) { + struct dentry *dentry = file->f_dentry; + struct rpc_cred *cred = nfs_file_cred(file); struct nfs_writeargs arg = { NFS_FH(dentry), offset, count, NFS_FILE_SYNC, 1, {{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} }; struct nfs_writeres res = { fattr, verf, 0 }; - struct rpc_message msg = { NFS3PROC_WRITE, &arg, &res, NULL }; + struct rpc_message msg = { NFS3PROC_WRITE, &arg, &res, cred }; int status, rpcflags = 0; dprintk("NFS call write %d @ %Ld\n", count, (long long)offset); diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index d6d5322174f6..8cfe862f43f9 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -122,14 +122,16 @@ nfs_proc_readlink(struct dentry *dentry, void *buffer, unsigned int bufsiz) } static int -nfs_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags, +nfs_proc_read(struct file *file, struct nfs_fattr *fattr, int flags, loff_t offset, unsigned int count, void *buffer, int *eofp) { + struct dentry *dentry = file->f_dentry; + struct rpc_cred *cred = nfs_file_cred(file); struct nfs_readargs arg = { NFS_FH(dentry), offset, count, 1, {{ buffer, count }, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} }; struct nfs_readres res = { fattr, count, 0}; - struct rpc_message msg = { NFSPROC_READ, &arg, &res, NULL }; + struct rpc_message msg = { NFSPROC_READ, &arg, &res, cred }; int status; dprintk("NFS call read %d @ %Ld\n", count, (long long)offset); @@ -142,16 +144,18 @@ nfs_proc_read(struct dentry *dentry, struct nfs_fattr *fattr, int flags, } static int -nfs_proc_write(struct dentry *dentry, struct nfs_fattr *fattr, int how, +nfs_proc_write(struct file *file, struct nfs_fattr *fattr, int how, loff_t offset, unsigned int count, void *buffer, struct nfs_writeverf *verf) { + struct dentry *dentry = file->f_dentry; + struct rpc_cred *cred = nfs_file_cred(file); struct nfs_writeargs arg = {NFS_FH(dentry), offset, count, NFS_FILE_SYNC, 1, {{buffer, count}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}}; struct nfs_writeres res = {fattr, verf, count}; - struct rpc_message msg = { NFSPROC_WRITE, &arg, &res, NULL }; + struct rpc_message msg = { NFSPROC_WRITE, &arg, &res, cred }; int status, flags = 0; dprintk("NFS call write %d @ %Ld\n", count, (long long)offset); diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 1c70ae58df7c..b15f50e61506 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -83,8 +83,9 @@ static void nfs_readdata_release(struct rpc_task *task) * Read a page synchronously. */ static int -nfs_readpage_sync(struct dentry *dentry, struct page *page) +nfs_readpage_sync(struct file *file, struct page *page) { + struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; struct nfs_fattr fattr; loff_t offset = page_offset(page); @@ -112,7 +113,7 @@ nfs_readpage_sync(struct dentry *dentry, struct page *page) (long long)offset, rsize, buffer); lock_kernel(); - result = NFS_PROTO(inode)->read(dentry, &fattr, flags, offset, + result = NFS_PROTO(inode)->read(file, &fattr, flags, offset, rsize, buffer, &eof); unlock_kernel(); nfs_refresh_inode(inode, &fattr); @@ -195,9 +196,9 @@ nfs_mark_request_read(struct nfs_page *req) } static int -nfs_readpage_async(struct dentry *dentry, struct page *page) +nfs_readpage_async(struct file *file, struct page *page) { - struct inode *inode = dentry->d_inode; + struct inode *inode = file->f_dentry->d_inode; struct nfs_page *req, *new = NULL; int result; @@ -227,7 +228,7 @@ nfs_readpage_async(struct dentry *dentry, struct page *page) } result = -ENOMEM; - new = nfs_create_request(dentry, page, 0, PAGE_CACHE_SIZE); + new = nfs_create_request(file, page, 0, PAGE_CACHE_SIZE); if (!new) break; } @@ -462,20 +463,16 @@ nfs_readpage_result(struct rpc_task *task) /* * Read a page over NFS. * We read the page synchronously in the following cases: - * - The file is a swap file. Swap-ins are always sync operations, - * so there's no need bothering to make async reads 100% fail-safe. * - The NFS rsize is smaller than PAGE_CACHE_SIZE. We could kludge our way * around this by creating several consecutive read requests, but * that's hardly worth it. * - The error flag is set for this page. This happens only when a * previous async read operation failed. - * - The server is congested. */ int nfs_readpage(struct file *file, struct page *page) { - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = file->f_dentry->d_inode; int error; dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", @@ -493,11 +490,11 @@ nfs_readpage(struct file *file, struct page *page) error = -1; if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) - error = nfs_readpage_async(dentry, page); + error = nfs_readpage_async(file, page); if (error >= 0) goto out; - error = nfs_readpage_sync(dentry, page); + error = nfs_readpage_sync(file, page); if (error < 0 && IS_SWAPFILE(inode)) printk("Aiee.. nfs swap-in of page failed!\n"); out: diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 52af85acb456..464776ac3c68 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -89,8 +89,7 @@ struct nfs_write_data { /* * Local function declarations */ -static struct nfs_page * nfs_update_request(struct file*, struct dentry *, - struct page *page, +static struct nfs_page * nfs_update_request(struct file*, struct page *page, unsigned int, unsigned int); static void nfs_strategy(struct inode *inode); static void nfs_writeback_done(struct rpc_task *); @@ -168,9 +167,10 @@ nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr) * Offset is the data offset within the page. */ static int -nfs_writepage_sync(struct dentry *dentry, struct page *page, +nfs_writepage_sync(struct file *file, struct page *page, unsigned int offset, unsigned int count) { + struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; loff_t base; unsigned int wsize = NFS_SERVER(inode)->wsize; @@ -193,7 +193,7 @@ nfs_writepage_sync(struct dentry *dentry, struct page *page, if (count < wsize && !IS_SWAPFILE(inode)) wsize = count; - result = NFS_PROTO(inode)->write(dentry, &fattr, flags, + result = NFS_PROTO(inode)->write(file, &fattr, flags, base, wsize, buffer, &verf); nfs_write_attributes(inode, &fattr); @@ -229,18 +229,18 @@ io_error: } static int -nfs_writepage_async(struct file *file, struct dentry *dentry, struct page *page, +nfs_writepage_async(struct file *file, struct page *page, unsigned int offset, unsigned int count) { struct nfs_page *req; int status; - req = nfs_update_request(file, dentry, page, offset, count); + req = nfs_update_request(file, page, offset, count); status = (IS_ERR(req)) ? PTR_ERR(req) : 0; if (status < 0) goto out; nfs_release_request(req); - nfs_strategy(dentry->d_inode); + nfs_strategy(file->f_dentry->d_inode); out: return status; } @@ -251,8 +251,7 @@ nfs_writepage_async(struct file *file, struct dentry *dentry, struct page *page, int nfs_writepage(struct file *file, struct page *page) { - struct dentry *dentry = file->f_dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = file->f_dentry->d_inode; unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT; unsigned offset = PAGE_CACHE_SIZE; int err; @@ -267,11 +266,11 @@ nfs_writepage(struct file *file, struct page *page) return -EIO; do_it: if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) { - err = nfs_writepage_async(file, dentry, page, 0, offset); + err = nfs_writepage_async(file, page, 0, offset); if (err >= 0) goto out_ok; } - err = nfs_writepage_sync(dentry, page, 0, offset); + err = nfs_writepage_sync(file, page, 0, offset); if ( err == offset) goto out_ok; return err; @@ -476,10 +475,12 @@ nfs_mark_request_commit(struct nfs_page *req) * Page must be locked by the caller. This makes sure we never create * two different requests for the same page, and avoids possible deadlock * when we reach the hard limit on the number of dirty pages. + * It should be safe to sleep here. */ -struct nfs_page *nfs_create_request(struct dentry *dentry, struct page *page, +struct nfs_page *nfs_create_request(struct file *file, struct page *page, unsigned int offset, unsigned int count) { + struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); struct nfs_page *req = NULL; @@ -531,8 +532,10 @@ struct nfs_page *nfs_create_request(struct dentry *dentry, struct page *page, page_cache_get(page); req->wb_offset = offset; req->wb_bytes = count; - req->wb_dentry = dget(dentry); - req->wb_cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); + req->wb_file = file; + get_file(file); + req->wb_dentry = dentry; + req->wb_cred = nfs_file_cred(file); req->wb_count = 1; /* register request's existence */ @@ -573,12 +576,7 @@ nfs_release_request(struct nfs_page *req) if (NFS_WBACK_BUSY(req)) printk(KERN_ERR "NFS: Request released while still locked!\n"); - rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred); - lock_kernel(); - if (req->wb_file) - fput(req->wb_file); - dput(req->wb_dentry); - unlock_kernel(); + fput(req->wb_file); page_cache_release(page); nfs_page_free(req); /* wake up anyone waiting to allocate a request */ @@ -789,10 +787,6 @@ int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned if (prev) { if (req->wb_file != prev->wb_file) break; - if (req->wb_dentry != prev->wb_dentry) - break; - if (req->wb_cred != prev->wb_cred) - break; if (page_index(req->wb_page) != page_index(prev->wb_page)+1) break; @@ -818,10 +812,10 @@ int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned * Note: Should always be called with the Page Lock held! */ static struct nfs_page * -nfs_update_request(struct file* file, struct dentry *dentry, struct page *page, +nfs_update_request(struct file* file, struct page *page, unsigned int offset, unsigned int bytes) { - struct inode *inode = dentry->d_inode; + struct inode *inode = file->f_dentry->d_inode; struct nfs_page *req, *new = NULL; unsigned long rqend, end; @@ -856,21 +850,14 @@ nfs_update_request(struct file* file, struct dentry *dentry, struct page *page, } spin_unlock(&nfs_wreq_lock); - - /* Create the request. It's safe to sleep in this call because - * we only get here if the page is locked. - * + /* * If we're over the soft limit, flush out old requests */ - if (file && nfs_nr_requests >= MAX_REQUEST_SOFT) + if (inode->u.nfs_i.npages >= MAX_REQUEST_SOFT) nfs_wb_file(inode, file); - new = nfs_create_request(dentry, page, offset, bytes); + new = nfs_create_request(file, page, offset, bytes); if (!new) return ERR_PTR(-ENOMEM); - if (file) { - new->wb_file = file; - get_file(file); - } /* If the region is locked, adjust the timeout */ if (region_locked(inode, new)) new->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY; @@ -1006,7 +993,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign * page synchronously. */ if (NFS_SERVER(inode)->wsize < PAGE_SIZE) - return nfs_writepage_sync(dentry, page, offset, count); + return nfs_writepage_sync(file, page, offset, count); /* * Try to find an NFS request corresponding to this page @@ -1015,7 +1002,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsign * it out now. */ do { - req = nfs_update_request(file, dentry, page, offset, count); + req = nfs_update_request(file, page, offset, count); status = (IS_ERR(req)) ? PTR_ERR(req) : 0; if (status != -EBUSY) break; diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 13b5ca946db7..d053ad1be1e4 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -134,6 +134,9 @@ char *disk_name (struct gendisk *hd, int minor, char *buf) case IDE0_MAJOR: maj = "hd"; break; + case MD_MAJOR: + unit -= 'a'-'0'; + break; } if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) { unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16; diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index 13ec76b02019..01db469dac98 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -315,13 +315,12 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t size_t elf_buflen; int num_vma; - /* XXX we need to somehow lock vmlist between here - * and after elf_kcore_store_hdr() returns. - * For now assume that num_vma does not change (TA) - */ + read_lock(&vmlist_lock); proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen); - if (buflen == 0 || *fpos >= size) + if (buflen == 0 || *fpos >= size) { + read_unlock(&vmlist_lock); return 0; + } /* trim buflen to not go beyond EOF */ if (buflen > size - *fpos) @@ -335,10 +334,13 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t if (buflen < tsz) tsz = buflen; elf_buf = kmalloc(elf_buflen, GFP_ATOMIC); - if (!elf_buf) + if (!elf_buf) { + read_unlock(&vmlist_lock); return -ENOMEM; + } memset(elf_buf, 0, elf_buflen); elf_kcore_store_hdr(elf_buf, num_vma, elf_buflen); + read_unlock(&vmlist_lock); if (copy_to_user(buffer, elf_buf + *fpos, tsz)) { kfree(elf_buf); return -EFAULT; @@ -352,7 +354,8 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t /* leave now if filled buffer already */ if (buflen == 0) return acc; - } + } else + read_unlock(&vmlist_lock); /* where page 0 not mapped, write zeros into buffer */ #if defined (__i386__) || defined (__mc68000__) diff --git a/fs/super.c b/fs/super.c index b32b1fc6cd5f..b5761f2c9e09 100644 --- a/fs/super.c +++ b/fs/super.c @@ -76,7 +76,7 @@ LIST_HEAD(super_blocks); * Once the reference is obtained we can drop the spinlock. */ -static struct file_system_type *file_systems = NULL; +static struct file_system_type *file_systems; static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED; /* WARNING: This can be used only if we _already_ own a reference */ diff --git a/include/asm-arm/arch-ebsa285/irq.h b/include/asm-arm/arch-ebsa285/irq.h index 9dcfa9480e84..134729f34af5 100644 --- a/include/asm-arm/arch-ebsa285/irq.h +++ b/include/asm-arm/arch-ebsa285/irq.h @@ -44,19 +44,8 @@ static int isa_irq = -1; static inline int fixup_irq(unsigned int irq) { #ifdef CONFIG_HOST_FOOTBRIDGE - if (irq == isa_irq) { + if (irq == isa_irq) irq = *(unsigned char *)PCIIACK_BASE; - - /* - * The NetWinder appears to randomly give wrong interrupt - * numbers from time to time. When it does, map them to - * the unused IRQ 13 - */ - if (irq >= NR_IRQS) { - printk(KERN_ERR "Strange interrupt %d?\n", irq); - irq = _ISA_IRQ(13); - } - } #endif return irq; diff --git a/include/asm-arm/arch-l7200/dma.h b/include/asm-arm/arch-l7200/dma.h new file mode 100644 index 000000000000..be68279f7227 --- /dev/null +++ b/include/asm-arm/arch-l7200/dma.h @@ -0,0 +1,23 @@ +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +/* + * This is the maximum DMA address that can be DMAd to. + * There should not be more than (0xd0000000 - 0xc0000000) + * bytes of RAM. + */ +#define MAX_DMA_ADDRESS 0xd0000000 +#define MAX_DMA_CHANNELS 8 + +#define DMA_0 0 +#define DMA_1 1 +#define DMA_2 2 +#define DMA_3 3 +#define DMA_S0 4 +#define DMA_S1 5 +#define DMA_VIRTUAL_FLOPPY 6 +#define DMA_VIRTUAL_SOUND 7 + +#define DMA_FLOPPY DMA_VIRTUAL_FLOPPY + +#endif diff --git a/include/asm-arm/arch-l7200/hardware.h b/include/asm-arm/arch-l7200/hardware.h new file mode 100644 index 000000000000..d800cbc8d094 --- /dev/null +++ b/include/asm-arm/arch-l7200/hardware.h @@ -0,0 +1,49 @@ +/* + * linux/include/asm-arm/arch-l7200/hardware.h + * + * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net) + * Steve Hill (sjhill@cotw.com) + * + * This file contains the hardware definitions for the + * LinkUp Systems L7200 SOC development board. + * + * Changelog: + * 02-01-2000 RS Created L7200 version, derived from rpc code + * 03-21-2000 SJH Cleaned up file + * 04-21-2000 RS Changed mapping of I/O in virtual space + * 04-25-2000 SJH Removed unused symbols and such + * 05-05-2000 SJH Complete rewrite + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +/* Hardware addresses of major areas. + * *_START is the physical address + * *_SIZE is the size of the region + * *_BASE is the virtual address + */ +#define RAM_START 0xf0000000 +#define RAM_SIZE 0x02000000 +#define RAM_BASE 0xc0000000 + +#define IO_START 0x80000000 /* I/O */ +#define IO_SIZE 0x01000000 +#define IO_BASE 0xd0000000 + +#define IO_START_2 0x90000000 /* I/O */ +#define IO_SIZE_2 0x01000000 +#define IO_BASE_2 0xd1000000 + +#define ISA_START 0x20000000 /* ISA */ +#define ISA_SIZE 0x20000000 +#define ISA_BASE 0xe0000000 + +#define FLUSH_BASE_PHYS 0x40000000 /* ROM */ +#define FLUSH_BASE 0xdf000000 + +#define PARAMS_BASE (PAGE_OFFSET + 0x0100) +#define Z_PARAMS_BASE (RAM_START + PARAMS_OFFSET) + +#define PCIO_BASE IO_BASE + +#endif diff --git a/include/asm-arm/arch-l7200/ide.h b/include/asm-arm/arch-l7200/ide.h new file mode 100644 index 000000000000..0cfcf3aacb8d --- /dev/null +++ b/include/asm-arm/arch-l7200/ide.h @@ -0,0 +1,27 @@ +/* + * linux/include/asm-arm/arch-l7200/ide.h + * + * Copyright (c) 2000 Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 29-03-2000 SJH Created file placeholder + */ +#include + +/* + * Set up a hw structure for a specified data port, control port and IRQ. + * This should follow whatever the default interface uses. + */ +static __inline__ void +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq) +{ +} + +/* + * This registers the standard ports for this architecture with the IDE + * driver. + */ +static __inline__ void +ide_init_default_hwifs(void) +{ +} diff --git a/include/asm-arm/arch-l7200/io.h b/include/asm-arm/arch-l7200/io.h new file mode 100644 index 000000000000..787b621089f1 --- /dev/null +++ b/include/asm-arm/arch-l7200/io.h @@ -0,0 +1,210 @@ +/* + * linux/include/asm-arm/arch-l7200/io.h + * + * Copyright (C) 2000 Steven Hill (sjhill@cotw.com) + * + * Modifications: + * 21-03-2000 SJH Created from linux/include/asm-arm/arch-nexuspci/io.h + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#include + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * We use two different types of addressing - PC style addresses, and ARM + * addresses. PC style accesses the PC hardware with the normal PC IO + * addresses, eg 0x3f8 for serial#1. ARM addresses are 0x80000000+ + * and are translated to the start of IO. Note that all addresses are + * shifted left! + */ +#define __PORT_PCIO(x) (!((x) & 0x80000000)) + +/* + * Dynamic IO functions. + */ + +extern __inline__ void __outb (unsigned int value, unsigned int port) +{ + unsigned long temp; + __asm__ __volatile__( + "tst %2, #0x80000000\n\t" + "mov %0, %4\n\t" + "addeq %0, %0, %3\n\t" + "strb %1, [%0, %2, lsl #2] @ outb" + : "=&r" (temp) + : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) + : "cc"); +} + +extern __inline__ void __outw (unsigned int value, unsigned int port) +{ + unsigned long temp; + __asm__ __volatile__( + "tst %2, #0x80000000\n\t" + "mov %0, %4\n\t" + "addeq %0, %0, %3\n\t" + "str %1, [%0, %2, lsl #2] @ outw" + : "=&r" (temp) + : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) + : "cc"); +} + +extern __inline__ void __outl (unsigned int value, unsigned int port) +{ + unsigned long temp; + __asm__ __volatile__( + "tst %2, #0x80000000\n\t" + "mov %0, %4\n\t" + "addeq %0, %0, %3\n\t" + "str %1, [%0, %2, lsl #2] @ outl" + : "=&r" (temp) + : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) + : "cc"); +} + +#define DECLARE_DYN_IN(sz,fnsuffix,instr) \ +extern __inline__ unsigned sz __in##fnsuffix (unsigned int port) \ +{ \ + unsigned long temp, value; \ + __asm__ __volatile__( \ + "tst %2, #0x80000000\n\t" \ + "mov %0, %4\n\t" \ + "addeq %0, %0, %3\n\t" \ + "ldr" ##instr## " %1, [%0, %2, lsl #2] @ in"###fnsuffix \ + : "=&r" (temp), "=r" (value) \ + : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) \ + : "cc"); \ + return (unsigned sz)value; \ +} + +extern __inline__ unsigned int __ioaddr (unsigned int port) \ +{ \ + if (__PORT_PCIO(port)) \ + return (unsigned int)(PCIO_BASE + (port << 2)); \ + else \ + return (unsigned int)(IO_BASE + (port << 2)); \ +} + +#define DECLARE_IO(sz,fnsuffix,instr) \ + DECLARE_DYN_IN(sz,fnsuffix,instr) + +DECLARE_IO(char,b,"b") +DECLARE_IO(short,w,"") +DECLARE_IO(int,l,"") + +#undef DECLARE_IO +#undef DECLARE_DYN_IN + +/* + * Constant address IO functions + * + * These have to be macros for the 'J' constraint to work - + * +/-4096 immediate operand. + */ +#define __outbc(value,port) \ +({ \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "strb %0, [%1, %2] @ outbc" \ + : : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "strb %0, [%1, %2] @ outbc" \ + : : "r" (value), "r" (IO_BASE), "r" ((port) << 2)); \ +}) + +#define __inbc(port) \ +({ \ + unsigned char result; \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "ldrb %0, [%1, %2] @ inbc" \ + : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "ldrb %0, [%1, %2] @ inbc" \ + : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \ + result; \ +}) + +#define __outwc(value,port) \ +({ \ + unsigned long v = value; \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "str %0, [%1, %2] @ outwc" \ + : : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "str %0, [%1, %2] @ outwc" \ + : : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2)); \ +}) + +#define __inwc(port) \ +({ \ + unsigned short result; \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "ldr %0, [%1, %2] @ inwc" \ + : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "ldr %0, [%1, %2] @ inwc" \ + : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \ + result & 0xffff; \ +}) + +#define __outlc(value,port) \ +({ \ + unsigned long v = value; \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "str %0, [%1, %2] @ outlc" \ + : : "r" (v), "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "str %0, [%1, %2] @ outlc" \ + : : "r" (v), "r" (IO_BASE), "r" ((port) << 2)); \ +}) + +#define __inlc(port) \ +({ \ + unsigned long result; \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "ldr %0, [%1, %2] @ inlc" \ + : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "ldr %0, [%1, %2] @ inlc" \ + : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \ + result; \ +}) + +#define __ioaddrc(port) \ + (__PORT_PCIO((port)) ? PCIO_BASE + ((port) << 2) : IO_BASE + ((port) << 2)) + +#define inb(p) (__builtin_constant_p((p)) ? __inbc(p) : __inb(p)) +#define inw(p) (__builtin_constant_p((p)) ? __inwc(p) : __inw(p)) +#define inl(p) (__builtin_constant_p((p)) ? __inlc(p) : __inl(p)) +#define outb(v,p) (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p)) +#define outw(v,p) (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p)) +#define outl(v,p) (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p)) +#define __ioaddr(p) (__builtin_constant_p((p)) ? __ioaddr(p) : __ioaddrc(p)) + +/* + * Translated address IO functions + * + * IO address has already been translated to a virtual address + */ +#define outb_t(v,p) (*(volatile unsigned char *)(p) = (v)) +#define inb_t(p) (*(volatile unsigned char *)(p)) +#define outw_t(v,p) (*(volatile unsigned int *)(p) = (v)) +#define inw_t(p) (*(volatile unsigned int *)(p)) +#define outl_t(v,p) (*(volatile unsigned long *)(p) = (v)) +#define inl_t(p) (*(volatile unsigned long *)(p)) + +#endif diff --git a/include/asm-arm/arch-l7200/irq.h b/include/asm-arm/arch-l7200/irq.h new file mode 100644 index 000000000000..58b61664fdde --- /dev/null +++ b/include/asm-arm/arch-l7200/irq.h @@ -0,0 +1,66 @@ +/* + * include/asm-arm/arch-l7200/irq.h + * + * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.ne + * Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 01-02-2000 RS Created l7200 version, derived from ebsa110 code + * 04-15-2000 RS Made dependent on hardware.h + * 05-05-2000 SJH Complete rewrite + */ + +/* + * IRQ base register + */ +#define IRQ_BASE (IO_BASE_2 + 0x1000) + +/* + * Normal IRQ registers + */ +#define IRQ_STATUS (*(volatile unsigned long *) (IRQ_BASE + 0x000)) +#define IRQ_RAWSTATUS (*(volatile unsigned long *) (IRQ_BASE + 0x004)) +#define IRQ_ENABLE (*(volatile unsigned long *) (IRQ_BASE + 0x008)) +#define IRQ_ENABLECLEAR (*(volatile unsigned long *) (IRQ_BASE + 0x00c)) +#define IRQ_SOFT (*(volatile unsigned long *) (IRQ_BASE + 0x010)) +#define IRQ_SOURCESEL (*(volatile unsigned long *) (IRQ_BASE + 0x018)) + +/* + * Fast IRQ registers + */ +#define FIQ_STATUS (*(volatile unsigned long *) (IRQ_BASE + 0x100)) +#define FIQ_RAWSTATUS (*(volatile unsigned long *) (IRQ_BASE + 0x104)) +#define FIQ_ENABLE (*(volatile unsigned long *) (IRQ_BASE + 0x108)) +#define FIQ_ENABLECLEAR (*(volatile unsigned long *) (IRQ_BASE + 0x10c)) +#define FIQ_SOFT (*(volatile unsigned long *) (IRQ_BASE + 0x110)) +#define FIQ_SOURCESEL (*(volatile unsigned long *) (IRQ_BASE + 0x118)) + +#define fixup_irq(x) (x) + +static void l7200_mask_irq(unsigned int irq) +{ + IRQ_ENABLECLEAR = 1 << irq; +} + +static void l7200_unmask_irq(unsigned int irq) +{ + IRQ_ENABLE = 1 << irq; +} + +static __inline__ void irq_init_irq(void) +{ + int irq; + + IRQ_ENABLECLEAR = 0xffffffff; /* clear all interrupt enables */ + FIQ_ENABLECLEAR = 0xffffffff; /* clear all fast interrupt enables */ + + for (irq = 0; irq < NR_IRQS; irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = l7200_mask_irq; + irq_desc[irq].mask = l7200_mask_irq; + irq_desc[irq].unmask = l7200_unmask_irq; + } + + init_FIQ(); +} diff --git a/include/asm-arm/arch-l7200/irqs.h b/include/asm-arm/arch-l7200/irqs.h new file mode 100644 index 000000000000..175efa1bd324 --- /dev/null +++ b/include/asm-arm/arch-l7200/irqs.h @@ -0,0 +1,45 @@ +/* + * include/asm-arm/arch-l7200/irqs.h + * + * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net) + * Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 01-02-2000 RS Create l7200 version + * 03-28-2000 SJH Removed unused interrupt + */ + +#define NR_IRQS 32 + +#define IRQ_STWDOG 0 /* Watchdog timer */ +#define IRQ_PROG 1 /* Programmable interrupt */ +#define IRQ_DEBUG_RX 2 /* Comm Rx debug */ +#define IRQ_DEBUG_TX 3 /* Comm Tx debug */ +#define IRQ_GCTC1 4 /* Timer 1 */ +#define IRQ_GCTC2 5 /* Timer 2 */ +#define IRQ_DMA 6 /* DMA controller */ +#define IRQ_CLCD 7 /* Color LCD controller */ +#define IRQ_SM_RX 8 /* Smart card */ +#define IRQ_SM_TX 9 /* Smart cart */ +#define IRQ_SM_RST 10 /* Smart card */ +#define IRQ_SIB 11 /* Serial Interface Bus */ +#define IRQ_MMC 12 /* MultiMediaCard */ +#define IRQ_SSP1 13 /* Synchronous Serial Port 1 */ +#define IRQ_SSP2 14 /* Synchronous Serial Port 1 */ +#define IRQ_SPI 15 /* SPI slave */ +#define IRQ_UART_1 16 /* UART 1 */ +#define IRQ_UART_2 17 /* UART 2 */ +#define IRQ_IRDA 18 /* IRDA */ +#define IRQ_RTC_TICK 19 /* Real Time Clock tick */ +#define IRQ_RTC_ALARM 20 /* Real Time Clock alarm */ +#define IRQ_GPIO 21 /* General Purpose IO */ +#define IRQ_GPIO_DMA 22 /* General Purpose IO, DMA */ +#define IRQ_M2M 23 /* Memory to memory DMA */ +#define IRQ_RESERVED 24 /* RESERVED, don't use */ +#define IRQ_INTF 25 /* External active low interrupt */ +#define IRQ_INT0 26 /* External active low interrupt */ +#define IRQ_INT1 27 /* External active low interrupt */ +#define IRQ_INT2 28 /* External active low interrupt */ +#define IRQ_INT3 29 /* External active low interrupt */ +#define IRQ_BAT_LO 30 /* Low batery or external power */ +#define IRQ_MEDIA_CHG 31 /* Media change interrupt */ diff --git a/include/asm-arm/arch-l7200/memory.h b/include/asm-arm/arch-l7200/memory.h new file mode 100644 index 000000000000..f2aaabd5c56b --- /dev/null +++ b/include/asm-arm/arch-l7200/memory.h @@ -0,0 +1,44 @@ +/* + * linux/include/asm-arm/arch-l7200/memory.h + * + * Copyright (c) 2000 Steven Hill (sjhill@cotw.com) + * Copyright (c) 2000 Rob Scott (rscott@mtrob.fdns.net) + * + * Changelog: + * 03-13-2000 SJH Created + * 04-13-2000 RS Changed bus macros for new addr + * 05-03-2000 SJH Removed bus macros and fixed virt_to_phys macro + */ +#ifndef __ASM_ARCH_MMU_H +#define __ASM_ARCH_MMU_H + +/* + * Task size: 3GB + */ +#define TASK_SIZE (0xc0000000UL) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * Page offset: 3GB + */ +#define PAGE_OFFSET (0xc0000000UL) + +/* + * Physical DRAM offset on the L7200 SDB. + */ +#define PHYS_OFFSET (0xf0000000UL) + +/* + * The DRAM is contiguous. + */ +#define __virt_to_phys__is_a_macro +#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + PHYS_OFFSET) +#define __phys_to_virt__is_a_macro +#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - PHYS_OFFSET) + +#define __virt_to_bus__is_a_macro +#define __virt_to_bus(x) __virt_to_phys(x) +#define __bus_to_virt__is_a_macro +#define __bus_to_virt(x) __phys_to_virt(x) + +#endif diff --git a/include/asm-arm/arch-l7200/param.h b/include/asm-arm/arch-l7200/param.h new file mode 100644 index 000000000000..5cd0bcc7826c --- /dev/null +++ b/include/asm-arm/arch-l7200/param.h @@ -0,0 +1,23 @@ +/* + * linux/include/asm-arm/arch-l7200/param.h + * + * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net) + * Steve Hill (sjhill@cotw.com) + * + * This file contains the hardware definitions for the + * LinkUp Systems L7200 SOC development board. + * + * Changelog: + * 04-21-2000 RS Created L7200 version + * 04-25-2000 SJH Cleaned up file + * 05-03-2000 SJH Change comments and rate + */ +#ifndef __ASM_ARCH_PARAM_H +#define __ASM_ARCH_PARAM_H + +/* + * See 'time.h' for how the RTC HZ rate is set + */ +#define HZ 128 + +#endif diff --git a/include/asm-arm/arch-l7200/processor.h b/include/asm-arm/arch-l7200/processor.h new file mode 100644 index 000000000000..ee4b4b2ca057 --- /dev/null +++ b/include/asm-arm/arch-l7200/processor.h @@ -0,0 +1,27 @@ +/* + * linux/include/asm-arm/arch-l7200/processor.h + * + * Copyright (c) 2000 Steven Hill (sjhill@cotw.com) + * + * Changelog: + * 03-21-2000 SJH Created + * 05-03-2000 SJH Comment cleaning + */ + +#ifndef __ASM_ARCH_PROCESSOR_H +#define __ASM_ARCH_PROCESSOR_H + +/* + * Bus types + */ +#define EISA_bus 0 +#define EISA_bus__is_a_macro /* for versions in ksyms.c */ +#define MCA_bus 0 +#define MCA_bus__is_a_macro /* for versions in ksyms.c */ + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + +#endif diff --git a/include/asm-arm/arch-l7200/serial_l7200.h b/include/asm-arm/arch-l7200/serial_l7200.h new file mode 100644 index 000000000000..238c595d97ea --- /dev/null +++ b/include/asm-arm/arch-l7200/serial_l7200.h @@ -0,0 +1,101 @@ +/* + * linux/include/asm-arm/arch-l7200/serial_l7200.h + * + * Copyright (c) 2000 Steven Hill (sjhill@cotw.com) + * + * Changelog: + * 05-09-2000 SJH Created + */ +#ifndef __ASM_ARCH_SERIAL_L7200_H +#define __ASM_ARCH_SERIAL_L7200_H + +#include + +/* + * This assumes you have a 3.6864 MHz clock for your UART. + */ +#define BASE_BAUD 3686400 + +/* + * UART base register addresses + */ +#define UART1_BASE (IO_BASE + 0x00044000) +#define UART2_BASE (IO_BASE + 0x00045000) + +/* + * UART register offsets + */ +#define UARTDR 0x00 /* Tx/Rx data */ +#define RXSTAT 0x04 /* Rx status */ +#define H_UBRLCR 0x08 /* mode register high */ +#define M_UBRLCR 0x0C /* mode reg mid (MSB of buad)*/ +#define L_UBRLCR 0x10 /* mode reg low (LSB of baud)*/ +#define UARTCON 0x14 /* control register */ +#define UARTFLG 0x18 /* flag register */ +#define UARTINTSTAT 0x1C /* FIFO IRQ status register */ +#define UARTINTMASK 0x20 /* FIFO IRQ mask register */ + +/* + * UART baud rate register values + */ +#define BR_110 0x827 +#define BR_1200 0x06e +#define BR_2400 0x05f +#define BR_4800 0x02f +#define BR_9600 0x017 +#define BR_14400 0x00f +#define BR_19200 0x00b +#define BR_38400 0x005 +#define BR_57600 0x003 +#define BR_76800 0x002 +#define BR_115200 0x001 + +/* + * Receiver status register (RXSTAT) mask values + */ +#define RXSTAT_NO_ERR 0x00 /* No error */ +#define RXSTAT_FRM_ERR 0x01 /* Framing error */ +#define RXSTAT_PAR_ERR 0x02 /* Parity error */ +#define RXSTAT_OVR_ERR 0x04 /* Overrun error */ + +/* + * High byte of UART bit rate and line control register (H_UBRLCR) values + */ +#define UBRLCR_BRK 0x01 /* generate break on tx */ +#define UBRLCR_PEN 0x02 /* enable parity */ +#define UBRLCR_PDIS 0x00 /* disable parity */ +#define UBRLCR_EVEN 0x04 /* 1= even parity,0 = odd parity */ +#define UBRLCR_STP2 0x08 /* transmit 2 stop bits */ +#define UBRLCR_FIFO 0x10 /* enable FIFO */ +#define UBRLCR_LEN5 0x60 /* word length5 */ +#define UBRLCR_LEN6 0x40 /* word length6 */ +#define UBRLCR_LEN7 0x20 /* word length7 */ +#define UBRLCR_LEN8 0x00 /* word length8 */ + +/* + * UART control register (UARTCON) values + */ +#define UARTCON_UARTEN 0x01 /* Enable UART */ +#define UARTCON_DMAONERR 0x08 /* Mask RxDmaRq when errors occur */ + +/* + * UART flag register (UARTFLG) mask values + */ +#define UARTFLG_UTXFF 0x20 /* Transmit FIFO full */ +#define UARTFLG_URXFE 0x10 /* Receiver FIFO empty */ +#define UARTFLG_UBUSY 0x08 /* Transmitter busy */ +#define UARTFLG_DCD 0x04 /* Data carrier detect */ +#define UARTFLG_DSR 0x02 /* Data set ready */ +#define UARTFLG_CTS 0x01 /* Clear to send */ + +/* + * UART interrupt status/clear registers (UARTINTSTAT/CLR) values + */ +#define UART_TXINT 0x01 /* TX interrupt */ +#define UART_RXINT 0x02 /* RX interrupt */ +#define UART_RXERRINT 0x04 /* RX error interrupt */ +#define UART_MSINT 0x08 /* Modem Status interrupt */ +#define UART_UDINT 0x10 /* UART Disabled interrupt */ +#define UART_ALLIRQS 0x1f /* All interrupts */ + +#endif diff --git a/include/asm-arm/arch-l7200/system.h b/include/asm-arm/arch-l7200/system.h new file mode 100644 index 000000000000..c3bbe37733a1 --- /dev/null +++ b/include/asm-arm/arch-l7200/system.h @@ -0,0 +1,30 @@ +/* + * linux/include/asm-arm/arch-l7200/system.h + * + * Copyright (c) 2000 Steven Hill (sjhill@cotw.com) + * + * Changelog + * 03-21-2000 SJH Created + * 04-26-2000 SJH Fixed functions + * 05-03-2000 SJH Removed usage of obsolete 'iomd.h' + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +extern __inline__ void arch_idle(void) +{ + while (!current->need_resched && !hlt_counter) + { }; +/* outb(0, IOMD_SUSMODE);*/ +} + +#define arch_power_off() do { } while (0) + +extern inline void arch_reset(char mode) +{ + if (mode == 's') { + cpu_reset(0); + } +} + +#endif diff --git a/include/asm-arm/arch-l7200/time.h b/include/asm-arm/arch-l7200/time.h new file mode 100644 index 000000000000..077735e218dd --- /dev/null +++ b/include/asm-arm/arch-l7200/time.h @@ -0,0 +1,68 @@ +/* + * linux/include/asm-arm/arch-l7200/time.h + * + * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net) + * Steve Hill (sjhill@cotw.com) + * + * Changelog: + * 01-02-2000 RS Created l7200 version, derived from rpc code + * 05-03-2000 SJH Complete rewrite + */ +#ifndef _ASM_ARCH_TIME_H +#define _ASM_ARCH_TIME_H + +#include + +/* + * RTC base register address + */ +#define RTC_BASE (IO_BASE_2 + 0x2000) + +/* + * RTC registers + */ +#define RTC_RTCDR (*(volatile unsigned char *) (RTC_BASE + 0x000)) +#define RTC_RTCMR (*(volatile unsigned char *) (RTC_BASE + 0x004)) +#define RTC_RTCS (*(volatile unsigned char *) (RTC_BASE + 0x008)) +#define RTC_RTCC (*(volatile unsigned char *) (RTC_BASE + 0x008)) +#define RTC_RTCDV (*(volatile unsigned char *) (RTC_BASE + 0x00c)) +#define RTC_RTCCR (*(volatile unsigned char *) (RTC_BASE + 0x010)) + +/* + * RTCCR register values + */ +#define RTC_RATE_32 0x00 /* 32 Hz tick */ +#define RTC_RATE_64 0x10 /* 64 Hz tick */ +#define RTC_RATE_128 0x20 /* 128 Hz tick */ +#define RTC_RATE_256 0x30 /* 256 Hz tick */ +#define RTC_EN_ALARM 0x01 /* Enable alarm */ +#define RTC_EN_TIC 0x04 /* Enable counter */ +#define RTC_EN_STWDOG 0x08 /* Enable watchdog */ + +/* + * Handler for timer interrupt + */ +static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_timer(regs); + do_profile(regs); + RTC_RTCC = 0; /* Clear interrupt */ +} + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +extern __inline__ void setup_timer(void) +{ + xtime.tv_sec = RTC_RTCDR; + + RTC_RTCC = 0; /* Clear interrupt */ + + timer_irq.handler = timer_interrupt; + + setup_arm_irq(IRQ_RTC_TICK, &timer_irq); + + RTC_RTCCR = RTC_RATE_128 | RTC_EN_TIC; /* Set rate and enable timer */ +} + +#endif diff --git a/include/asm-arm/arch-l7200/timex.h b/include/asm-arm/arch-l7200/timex.h new file mode 100644 index 000000000000..3c3202620f00 --- /dev/null +++ b/include/asm-arm/arch-l7200/timex.h @@ -0,0 +1,20 @@ +/* + * linux/include/asm-arm/arch-l7200/timex.h + * + * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.net) + * Steve Hill (sjhill@cotw.com) + * + * 04-21-2000 RS Created file + * 05-03-2000 SJH Tick rate was wrong + * + */ + +/* + * On the ARM720T, clock ticks are set to 128 Hz. + * + * NOTE: The actual RTC value is set in 'time.h' which + * must be changed when choosing a different tick + * rate. The value of HZ in 'param.h' must also + * be changed to match below. + */ +#define CLOCK_TICK_RATE 128 diff --git a/include/asm-arm/arch-l7200/uncompress.h b/include/asm-arm/arch-l7200/uncompress.h new file mode 100644 index 000000000000..d2e56455b869 --- /dev/null +++ b/include/asm-arm/arch-l7200/uncompress.h @@ -0,0 +1,19 @@ +/* + * linux/include/asm-arm/arch-l7200/uncompress.h + * + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + */ + +static __inline__ void putc(char c) +{ +} + +static void puts(const char *s) +{ +} + +static __inline__ void arch_decomp_setup(void) +{ +} + +#define arch_decomp_wdog() diff --git a/include/asm-arm/arch-l7200/vmalloc.h b/include/asm-arm/arch-l7200/vmalloc.h new file mode 100644 index 000000000000..04fa07e7cbf5 --- /dev/null +++ b/include/asm-arm/arch-l7200/vmalloc.h @@ -0,0 +1,16 @@ +/* + * linux/include/asm-arm/arch-l7200/vmalloc.h + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + 0x10000000) diff --git a/include/asm-arm/hardirq.h b/include/asm-arm/hardirq.h index 77a36a2a480a..c12ed91e31f4 100644 --- a/include/asm-arm/hardirq.h +++ b/include/asm-arm/hardirq.h @@ -5,23 +5,27 @@ #include extern unsigned int local_irq_count[NR_CPUS]; +extern unsigned int local_bh_count[NR_CPUS]; + +#define local_irq_count(cpu) (local_irq_count[(cpu)]) +#define local_bh_count(cpu) (local_bh_count[(cpu)]) /* * Are we in an interrupt context? Either doing bottom half * or hardware interrupt processing? */ #define in_interrupt() ({ const int __cpu = smp_processor_id(); \ - (local_irq_count[__cpu] + local_bh_count[__cpu] != 0); }) + (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); }) -#define in_irq() (local_irq_count[smp_processor_id()] != 0) +#define in_irq() (local_irq_count(smp_processor_id()) != 0) #ifndef CONFIG_SMP -#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0) +#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0) #define hardirq_endlock(cpu) do { } while (0) -#define hardirq_enter(cpu) (local_irq_count[cpu]++) -#define hardirq_exit(cpu) (local_irq_count[cpu]--) +#define irq_enter(cpu,irq) (local_irq_count(cpu)++) +#define irq_exit(cpu,irq) (local_irq_count(cpu)--) #define synchronize_irq() do { } while (0) diff --git a/include/asm-arm/proc-armo/semaphore.h b/include/asm-arm/proc-armo/semaphore.h deleted file mode 100644 index 6926fad126af..000000000000 --- a/include/asm-arm/proc-armo/semaphore.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * linux/include/asm-arm/proc-armo/locks.h - * - * Copyright (C) 2000 Russell King - * - * Interrupt safe locking assembler. - */ -#ifndef __ASM_PROC_LOCKS_H -#define __ASM_PROC_LOCKS_H - -#define __down_op(ptr,fail) \ - ({ \ - __asm__ __volatile__ ( \ - "@ atomic down operation\n" \ -" mov r0, pc\n" \ -" orr lr, r0, #0x08000000\n" \ -" teqp lr, #0\n" \ -" ldr lr, [%0]\n" \ -" and r0, r0, #0x0c000003\n" \ -" subs lr, lr, #1\n" \ -" str lr, [%0]\n" \ -" orrmi r0, r0, #0x80000000 @ set N\n" \ -" teqp r0, #0\n" \ -" movmi r0, %0\n" \ - blmi " SYMBOL_NAME_STR(fail) \ - : \ - : "r" (ptr) \ - : "r0", "lr", "cc"); \ - }) - -#define __down_op_ret(ptr,fail) \ - ({ \ - unsigned int result; \ - __asm__ __volatile__ ( \ -" @ down_op_ret\n" \ -" mov r0, pc\n" \ -" orr lr, r0, #0x08000000\n" \ -" teqp lr, #0\n" \ -" ldr lr, [%1]\m" \ -" and r0, r0, #0x0c000003\n" \ -" subs lr, lr, #1\n" \ -" str lr, [%1]\n" \ -" orrmi r0, r0, #0x80000000 @ set N\n" \ -" teqp r0, #0\n" \ -" movmi r0, %1\n" \ -" movpl r0, #0\n" \ -" blmi " SYMBOL_NAME_STR(fail) "\n" \ -" mov %0, r0" \ - : "=&r" (result) \ - : "r" (ptr) \ - : "r0", "lr", "cc"); \ - result; \ - }) - -#define __up_op(ptr,wake) \ - ({ \ - __asm__ __volatile__ ( \ - "@ up_op\n" \ - mov r0, pc\n" \ - orr lr, r0, #0x08000000\n" \ - teqp lr, #0\n" \ - ldr lr, [%0]\n" \ - and r0, r0, #0x0c000003\n" \ - adds lr, lr, #1\n" \ - str lr, [%0]\n" \ - orrle r0, r0, #0x80000000 @ set N\n" \ - teqp r0, #0\n" \ - movmi r0, %0\n" \ - blmi " SYMBOL_NAME_STR(wake) \ - : \ - : "r" (ptr) \ - : "r0", "lr", "cc"); \ - }) - -#endif diff --git a/include/asm-arm/proc-armv/locks.h b/include/asm-arm/proc-armv/locks.h index c1cfded3e4d8..0a0391faee7e 100644 --- a/include/asm-arm/proc-armv/locks.h +++ b/include/asm-arm/proc-armv/locks.h @@ -12,18 +12,18 @@ ({ \ __asm__ __volatile__( \ "@ down_op\n" \ -" mrs r0, cpsr\n" \ -" orr lr, r0, #128\n" \ +" mrs ip, cpsr\n" \ +" orr lr, ip, #128\n" \ " msr cpsr_c, lr\n" \ " ldr lr, [%0]\n" \ " subs lr, lr, %1\n" \ " str lr, [%0]\n" \ -" msr cpsr_c, r0\n" \ -" movmi r0, %0\n" \ +" msr cpsr_c, ip\n" \ +" movmi ip, %0\n" \ " blmi " SYMBOL_NAME_STR(fail) \ : \ : "r" (ptr), "I" (1) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ }) #define __down_op_ret(ptr,fail) \ @@ -31,20 +31,20 @@ unsigned int ret; \ __asm__ __volatile__( \ "@ down_op_ret\n" \ -" mrs r0, cpsr\n" \ -" orr lr, r0, #128\n" \ +" mrs ip, cpsr\n" \ +" orr lr, ip, #128\n" \ " msr cpsr_c, lr\n" \ " ldr lr, [%1]\n" \ " subs lr, lr, %2\n" \ " str lr, [%1]\n" \ -" msr cpsr_c, r0\n" \ -" movmi r0, %1\n" \ -" movpl r0, #0\n" \ +" msr cpsr_c, ip\n" \ +" movmi ip, %1\n" \ +" movpl ip, #0\n" \ " blmi " SYMBOL_NAME_STR(fail) "\n" \ -" mov %0, r0" \ +" mov %0, ip" \ : "=&r" (ret) \ : "r" (ptr), "I" (1) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ ret; \ }) @@ -52,18 +52,18 @@ ({ \ __asm__ __volatile__( \ "@ up_op\n" \ -" mrs r0, cpsr\n" \ -" orr lr, r0, #128\n" \ +" mrs ip, cpsr\n" \ +" orr lr, ip, #128\n" \ " msr cpsr_c, lr\n" \ " ldr lr, [%0]\n" \ " adds lr, lr, %1\n" \ " str lr, [%0]\n" \ -" msr cpsr_c, r0\n" \ -" movle r0, %0\n" \ +" msr cpsr_c, ip\n" \ +" movle ip, %0\n" \ " blle " SYMBOL_NAME_STR(wake) \ : \ : "r" (ptr), "I" (1) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ }) /* @@ -78,36 +78,36 @@ ({ \ __asm__ __volatile__( \ "@ down_op_write\n" \ -" mrs r0, cpsr\n" \ -" orr lr, r0, #128\n" \ +" mrs ip, cpsr\n" \ +" orr lr, ip, #128\n" \ " msr cpsr_c, lr\n" \ " ldr lr, [%0]\n" \ " subs lr, lr, %1\n" \ " str lr, [%0]\n" \ -" msr cpsr_c, r0\n" \ -" movne r0, %0\n" \ +" msr cpsr_c, ip\n" \ +" movne ip, %0\n" \ " blne " SYMBOL_NAME_STR(fail) \ : \ : "r" (ptr), "I" (RW_LOCK_BIAS) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ }) #define __up_op_write(ptr,wake) \ ({ \ __asm__ __volatile__( \ "@ up_op_read\n" \ -" mrs r0, cpsr\n" \ -" orr lr, r0, #128\n" \ +" mrs ip, cpsr\n" \ +" orr lr, ip, #128\n" \ " msr cpsr_c, lr\n" \ " ldr lr, [%0]\n" \ " adds lr, lr, %1\n" \ " str lr, [%0]\n" \ -" msr cpsr_c, r0\n" \ -" movcs r0, %0\n" \ +" msr cpsr_c, ip\n" \ +" movcs ip, %0\n" \ " blcs " SYMBOL_NAME_STR(wake) \ : \ : "r" (ptr), "I" (RW_LOCK_BIAS) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ }) #define __down_op_read(ptr,fail) \ @@ -117,18 +117,18 @@ ({ \ __asm__ __volatile__( \ "@ up_op_read\n" \ -" mrs r0, cpsr\n" \ -" orr lr, r0, #128\n" \ +" mrs ip, cpsr\n" \ +" orr lr, ip, #128\n" \ " msr cpsr_c, lr\n" \ " ldr lr, [%0]\n" \ " adds lr, lr, %1\n" \ " str lr, [%0]\n" \ -" msr cpsr_c, r0\n" \ -" moveq r0, %0\n" \ +" msr cpsr_c, ip\n" \ +" moveq ip, %0\n" \ " bleq " SYMBOL_NAME_STR(wake) \ : \ : "r" (ptr), "I" (1) \ - : "r0", "lr", "cc"); \ + : "ip", "lr", "cc"); \ }) #endif diff --git a/include/asm-arm/softirq.h b/include/asm-arm/softirq.h index f98754813137..01e0d73d1062 100644 --- a/include/asm-arm/softirq.h +++ b/include/asm-arm/softirq.h @@ -4,14 +4,12 @@ #include #include -extern unsigned int local_bh_count[NR_CPUS]; - -#define cpu_bh_disable(cpu) do { local_bh_count[(cpu)]++; barrier(); } while (0) -#define cpu_bh_enable(cpu) do { barrier(); local_bh_count[(cpu)]--; } while (0) +#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0) +#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0) #define local_bh_disable() cpu_bh_disable(smp_processor_id()) #define local_bh_enable() cpu_bh_enable(smp_processor_id()) -#define in_softirq() (local_bh_count[smp_processor_id()] != 0) +#define in_softirq() (local_bh_count(smp_processor_id()) != 0) #endif /* __ASM_SOFTIRQ_H */ diff --git a/include/asm-arm/string.h b/include/asm-arm/string.h index dfe4cd9aca1e..2a8ab162412f 100644 --- a/include/asm-arm/string.h +++ b/include/asm-arm/string.h @@ -13,12 +13,17 @@ extern char * strrchr(const char * s, int c); extern char * strchr(const char * s, int c); #define __HAVE_ARCH_MEMCPY +extern void * memcpy(void *, const void *, __kernel_size_t); + #define __HAVE_ARCH_MEMMOVE +extern void * memmove(void *, const void *, __kernel_size_t); + #define __HAVE_ARCH_MEMCHR -extern void * memchr(const void *cs, int c, size_t count); +extern void * memchr(const void *, int, __kernel_size_t); #define __HAVE_ARCH_MEMZERO #define __HAVE_ARCH_MEMSET +extern void * memset(void *, int, __kernel_size_t); extern void __memzero(void *ptr, __kernel_size_t n); @@ -36,4 +41,3 @@ extern void __memzero(void *ptr, __kernel_size_t n); #define memzero(p,n) ({ if ((n) != 0) __memzero((p),(n)); (p); }) #endif - diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index ca6da3e13207..9755af1ab0e5 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h @@ -65,7 +65,7 @@ #define __NR_mpx (__NR_SYSCALL_BASE+ 56) #define __NR_setpgid (__NR_SYSCALL_BASE+ 57) #define __NR_ulimit (__NR_SYSCALL_BASE+ 58) -#define __NR_oldolduname (__NR_SYSCALL_BASE+ 59) + #define __NR_umask (__NR_SYSCALL_BASE+ 60) #define __NR_chroot (__NR_SYSCALL_BASE+ 61) #define __NR_ustat (__NR_SYSCALL_BASE+ 62) @@ -115,7 +115,7 @@ #define __NR_stat (__NR_SYSCALL_BASE+106) #define __NR_lstat (__NR_SYSCALL_BASE+107) #define __NR_fstat (__NR_SYSCALL_BASE+108) -#define __NR_olduname (__NR_SYSCALL_BASE+109) + #define __NR_iopl (__NR_SYSCALL_BASE+110) #define __NR_vhangup (__NR_SYSCALL_BASE+111) #define __NR_idle (__NR_SYSCALL_BASE+112) diff --git a/include/asm-mips/delay.h b/include/asm-mips/delay.h index a7fa5e56f261..98fe1ec3d286 100644 --- a/include/asm-mips/delay.h +++ b/include/asm-mips/delay.h @@ -12,8 +12,6 @@ #include -#include - extern __inline__ void __delay(unsigned long loops) { diff --git a/include/asm-mips/hardirq.h b/include/asm-mips/hardirq.h index 59d6681dec7b..cba4ccf0dcf8 100644 --- a/include/asm-mips/hardirq.h +++ b/include/asm-mips/hardirq.h @@ -10,8 +10,6 @@ #ifndef _ASM_HARDIRQ_H #define _ASM_HARDIRQ_H -#include - #include #include #include diff --git a/include/asm-mips/pgalloc.h b/include/asm-mips/pgalloc.h index a91913bcc72b..c9600661eb90 100644 --- a/include/asm-mips/pgalloc.h +++ b/include/asm-mips/pgalloc.h @@ -12,8 +12,6 @@ #include -#include - /* TLB flushing: * * - flush_tlb_all() flushes all processes TLB entries diff --git a/include/asm-mips/processor.h b/include/asm-mips/processor.h index ab996d0b292c..d6fb7526dffa 100644 --- a/include/asm-mips/processor.h +++ b/include/asm-mips/processor.h @@ -16,8 +16,6 @@ #include -#include - /* * Default implementation of macro that returns current * instruction pointer ("program counter"). diff --git a/include/asm-mips64/delay.h b/include/asm-mips64/delay.h index 4c05d3cc146d..2913275ab688 100644 --- a/include/asm-mips64/delay.h +++ b/include/asm-mips64/delay.h @@ -13,8 +13,6 @@ #include -#include - extern __inline__ void __delay(unsigned long loops) { diff --git a/include/asm-mips64/dma.h b/include/asm-mips64/dma.h index df2f47f6c425..e1caa024a71c 100644 --- a/include/asm-mips64/dma.h +++ b/include/asm-mips64/dma.h @@ -13,6 +13,7 @@ #ifndef _ASM_DMA_H #define _ASM_DMA_H +#include #include /* need byte IO */ #include /* And spinlocks */ #include diff --git a/include/asm-mips64/pgalloc.h b/include/asm-mips64/pgalloc.h index 4db514c487d2..74d3e29982e4 100644 --- a/include/asm-mips64/pgalloc.h +++ b/include/asm-mips64/pgalloc.h @@ -12,8 +12,6 @@ #include -#include - /* TLB flushing: * * - flush_tlb_all() flushes all processes TLB entries diff --git a/include/asm-mips64/processor.h b/include/asm-mips64/processor.h index 7245e27b0888..1932672e7c8a 100644 --- a/include/asm-mips64/processor.h +++ b/include/asm-mips64/processor.h @@ -20,7 +20,6 @@ */ #define current_text_addr() ({ __label__ _l; _l: &&_l;}) -#include #if !defined (_LANGUAGE_ASSEMBLY) #include #include diff --git a/include/asm-mips64/sn/addrs.h b/include/asm-mips64/sn/addrs.h index 225adb30c932..706d8fbd104a 100644 --- a/include/asm-mips64/sn/addrs.h +++ b/include/asm-mips64/sn/addrs.h @@ -10,6 +10,7 @@ #ifndef _ASM_SN_ADDRS_H #define _ASM_SN_ADDRS_H +#include #if _LANGUAGE_C #include #endif /* _LANGUAGE_C */ diff --git a/include/asm-mips64/sn/agent.h b/include/asm-mips64/sn/agent.h index f9115805ef69..76004336a241 100644 --- a/include/asm-mips64/sn/agent.h +++ b/include/asm-mips64/sn/agent.h @@ -12,6 +12,7 @@ #ifndef _ASM_SGI_SN_AGENT_H #define _ASM_SGI_SN_AGENT_H +#include #include #include //#include diff --git a/include/asm-mips64/sn/intr.h b/include/asm-mips64/sn/intr.h index 33a8f2202ff8..79f4020c0ea1 100644 --- a/include/asm-mips64/sn/intr.h +++ b/include/asm-mips64/sn/intr.h @@ -1,17 +1,12 @@ -/************************************************************************** - * * - * Copyright (C) 1992-1997, Silicon Graphics, Inc. * - * * - * These coded instructions, statements, and computer programs contain * - * unpublished proprietary information of Silicon Graphics, Inc., and * - * are protected by Federal copyright law. They may not be disclosed * - * to third parties or copied or duplicated in any form, in whole or * - * in part, without the prior written consent of Silicon Graphics, Inc. * - * * - **************************************************************************/ - -#ifndef __SYS_SN_INTR_H__ -#define __SYS_SN_INTR_H__ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997 Silicon Graphics, Inc. + */ +#ifndef __ASM_SN_INTR_H +#define __ASM_SN_INTR_H /* Number of interrupt levels associated with each interrupt register. */ #define N_INTPEND_BITS 64 @@ -124,4 +119,4 @@ #define NI_BRDCAST_ERR_B 40 #define NI_BRDCAST_ERR_A 39 -#endif /* __SYS_SN_INTR_H__ */ +#endif /* __ASM_SN_INTR_H */ diff --git a/include/asm-mips64/sn/intr_public.h b/include/asm-mips64/sn/intr_public.h index 63d3e6ebc180..a22b0a4bfad6 100644 --- a/include/asm-mips64/sn/intr_public.h +++ b/include/asm-mips64/sn/intr_public.h @@ -1,17 +1,12 @@ -/************************************************************************** - * * - * Copyright (C) 1992-1997, Silicon Graphics, Inc. * - * * - * These coded instructions, statements, and computer programs contain * - * unpublished proprietary information of Silicon Graphics, Inc., and * - * are protected by Federal copyright law. They may not be disclosed * - * to third parties or copied or duplicated in any form, in whole or * - * in part, without the prior written consent of Silicon Graphics, Inc. * - * * - **************************************************************************/ - -#ifndef __SYS_SN_INTR_PUBLIC_H__ -#define __SYS_SN_INTR_PUBLIC_H__ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997 Silicon Graphics, Inc. + */ +#ifndef __ASM_SN_INTR_PUBLIC_H +#define __ASM_SN_INTR_PUBLIC_H /* REMEMBER: If you change these, the whole world needs to be recompiled. @@ -55,5 +50,4 @@ typedef struct hub_intmasks_s { } hub_intmasks_t; #endif /* _LANGUAGE_C */ -#endif /* __SYS_SN_INTR_PUBLIC_H__ */ - +#endif /* __ASM_SN_INTR_PUBLIC_H */ diff --git a/include/asm-mips64/sn/io.h b/include/asm-mips64/sn/io.h index 4c95ae1d86f2..b0f7a215193c 100644 --- a/include/asm-mips64/sn/io.h +++ b/include/asm-mips64/sn/io.h @@ -11,6 +11,7 @@ #ifndef _ASM_SN_IO_H #define _ASM_SN_IO_H +#include #if !defined(CONFIG_SGI_IO) #include diff --git a/include/asm-mips64/sn/klconfig.h b/include/asm-mips64/sn/klconfig.h index 46433db7f04e..3f042a9830c3 100644 --- a/include/asm-mips64/sn/klconfig.h +++ b/include/asm-mips64/sn/klconfig.h @@ -32,37 +32,35 @@ * that offsets of existing fields do not change. */ +#include #include #include +#if defined(CONFIG_SGI_IP27) || defined(CONFIG_SGI_IP35) +#include +#include +#include +#endif /* !CONFIG_SGI_IP27 || !CONFIG_SGI_IP35 */ #if defined(CONFIG_SGI_IP27) #include //#include // XXX Stolen from : #define MAX_ROUTER_PORTS (6) /* Max. number of ports on a router */ #include -#include //#include -#include -#include //#include -#if defined(CONFIG_SGI_IO) -// The hack file has to be before vector and after sn0_fru.... -#include -#include -#include -#endif /* CONFIG_SGI_IO */ #elif defined(CONFIG_SGI_IP35) -#include #include -#include #include -#include #include -#include -#include #include -#include #endif /* !CONFIG_SGI_IP27 && !CONFIG_SGI_IP35 */ +#if (defined(CONFIG_SGI_IP27) && defined(CONFIG_SGI_IO)) || \ + defined(CONFIG_SGI_IP35) +// The hack file has to be before vector and after sn0_fru.... +#include +#include +#include +#endif /* !(CONFIG_SGI_IP27 && CONFIG_SGI_IO) || !CONFIG_SGI_IP35 */ #define KLCFGINFO_MAGIC 0xbeedbabe diff --git a/include/asm-mips64/sn/kldir.h b/include/asm-mips64/sn/kldir.h index 67d650905e25..3ca24005693a 100644 --- a/include/asm-mips64/sn/kldir.h +++ b/include/asm-mips64/sn/kldir.h @@ -12,6 +12,7 @@ #ifndef _ASM_SN_KLDIR_H #define _ASM_SN_KLDIR_H +#include #if defined(CONFIG_SGI_IO) #include #endif diff --git a/include/asm-mips64/sn/nmi.h b/include/asm-mips64/sn/nmi.h index 580cde744e90..b1ea725e068a 100644 --- a/include/asm-mips64/sn/nmi.h +++ b/include/asm-mips64/sn/nmi.h @@ -1,17 +1,12 @@ -/************************************************************************** - * * - * Copyright (C) 1992-1997, Silicon Graphics, Inc. * - * * - * These coded instructions, statements, and computer programs contain * - * unpublished proprietary information of Silicon Graphics, Inc., and * - * are protected by Federal copyright law. They may not be disclosed * - * to third parties or copied or duplicated in any form, in whole or * - * in part, without the prior written consent of Silicon Graphics, Inc. * - * * - **************************************************************************/ - -#ifndef __SYS_SN_NMI_H__ -#define __SYS_SN_NMI_H__ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997 Silicon Graphics, Inc. + */ +#ifndef __ASM_SN_NMI_H +#define __ASM_SN_NMI_H #ident "$Revision: 1.1 $" @@ -127,5 +122,4 @@ struct reg_struct { #define CACHE_ERR_OFF 0x128 #define NMISR_OFF 0x130 - -#endif /* __SYS_SN_NMI_H__ */ +#endif /* __ASM_SN_NMI_H */ diff --git a/include/asm-ppc/bitops.h b/include/asm-ppc/bitops.h index d5506a3480d3..8fea036b99c9 100644 --- a/include/asm-ppc/bitops.h +++ b/include/asm-ppc/bitops.h @@ -6,8 +6,6 @@ #ifndef _PPC_BITOPS_H #define _PPC_BITOPS_H -#include -#include #include extern void set_bit(int nr, volatile void *addr); @@ -278,3 +276,4 @@ found_middle: #define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size) #endif /* _PPC_BITOPS_H */ + diff --git a/include/asm-ppc/cpm_8260.h b/include/asm-ppc/cpm_8260.h index c479f87d2026..5f500d5c3338 100644 --- a/include/asm-ppc/cpm_8260.h +++ b/include/asm-ppc/cpm_8260.h @@ -124,6 +124,14 @@ typedef struct cpm_buf_desc { #define BD_SC_OV ((ushort)0x0002) /* Overrun */ #define BD_SC_CD ((ushort)0x0001) /* ?? */ +/* Function code bits, usually generic to devices. +*/ +#define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ +#define CPMFCR_EB ((u_char)0x10) /* Set big endian byte order */ +#define CPMFCR_TC2 ((u_char)0x04) /* Transfer code 2 value */ +#define CPMFCR_DTB ((u_char)0x02) /* Use local bus for data when set */ +#define CPMFCR_BDB ((u_char)0x01) /* Use local bus for BD when set */ + /* Parameter RAM offsets from the base. */ #define PROFF_SCC1 ((uint)0x8000) @@ -184,13 +192,6 @@ typedef struct smc_uart { uint smc_stmp; /* SDMA Temp */ } smc_uart_t; -/* Function code bits. -*/ -#define SMC_GBL ((u_char)0x20) /* Set memory snooping */ -#define SMC_EB ((u_char)0x10) /* Set big endian byte order */ -#define SMC_TC2 ((u_char)0x04) /* Transfer code 2 value */ -#define SMC_DTB ((u_char)0x02) /* Use local bus when set */ - /* SMC uart mode register (Internal memory map). */ #define SMCMR_REN ((ushort)0x0001) @@ -337,10 +338,6 @@ typedef struct scc_param { uint scc_tcrc; /* Internal */ } sccp_t; -/* Function code bits. -*/ -#define SCC_EB ((u_char)0x10) /* Set big endian byte order */ - /* CPM Ethernet through SCC1. */ typedef struct scc_enet { diff --git a/include/asm-ppc/init.h b/include/asm-ppc/init.h index 106e57c1af5f..a25f6015e9ea 100644 --- a/include/asm-ppc/init.h +++ b/include/asm-ppc/init.h @@ -16,6 +16,12 @@ __argprep __prep; \ __argprep +#define __chrp __attribute__ ((__section__ (".text.chrp"))) +#define __chrpdata __attribute__ ((__section__ (".data.chrp"))) +#define __chrpfunc(__argchrp) \ + __argchrp __chrp; \ + __argchrp + #define __apus __attribute__ ((__section__ (".text.apus"))) #define __apusdata __attribute__ ((__section__ (".data.apus"))) #define __apusfunc(__argapus) \ diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h index e069f8b152b0..a4f6b0a4bfb9 100644 --- a/include/asm-ppc/page.h +++ b/include/asm-ppc/page.h @@ -1,4 +1,7 @@ #include +#ifndef __ASSEMBLY__ +#include /* for xmon definition */ +#endif /* ndef __ASSEMBLY__ */ #ifndef _PPC_PAGE_H #define _PPC_PAGE_H diff --git a/include/asm-ppc/string.h b/include/asm-ppc/string.h index e0158a215ad7..d912a6b5fed2 100644 --- a/include/asm-ppc/string.h +++ b/include/asm-ppc/string.h @@ -15,5 +15,15 @@ extern int strcasecmp(const char *, const char *); extern int strncasecmp(const char *, const char *, int); +extern char * strcpy(char *,const char *); +extern char * strncpy(char *,const char *, __kernel_size_t); +extern __kernel_size_t strlen(const char *); +extern int strcmp(const char *,const char *); +extern char * strcat(char *, const char *); +extern void * memset(void *,int,__kernel_size_t); +extern void * memcpy(void *,const void *,__kernel_size_t); +extern void * memmove(void *,const void *,__kernel_size_t); +extern int memcmp(const void *,const void *,__kernel_size_t); +extern void * memchr(const void *,int,__kernel_size_t); #endif diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h index e28f6bfff8b7..84a7a01f489c 100644 --- a/include/linux/hdreg.h +++ b/include/linux/hdreg.h @@ -181,6 +181,8 @@ struct hd_geometry { #define HDIO_GET_DMA 0x030b /* get use-dma flag */ #define HDIO_GET_NICE 0x030c /* get nice flags */ #define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */ +#define HDIO_DRIVE_CMD_AEB 0x031e +#define HDIO_DRIVE_TASK 0x031e #define HDIO_DRIVE_CMD 0x031f /* execute a special drive command */ /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */ @@ -207,7 +209,6 @@ struct hd_big_geometry { #define HDIO_GETGEO_BIG 0x0330 /* */ #define HDIO_GETGEO_BIG_RAW 0x0331 /* */ - #define __NEW_HD_DRIVE_ID /* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */ struct hd_driveid { @@ -272,7 +273,7 @@ struct hd_driveid { unsigned short CurAPMvalues; /* current APM values */ unsigned short word92; /* reserved (word 92) */ unsigned short hw_config; /* hardware config */ - unsigned short words94_125[31];/* reserved words 94-125 */ + unsigned short words94_125[32];/* reserved words 94-125 */ unsigned short last_lun; /* reserved (word 126) */ unsigned short word127; /* reserved (word 127) */ unsigned short dlf; /* device lock function @@ -293,8 +294,10 @@ struct hd_driveid { * 1 read-look-ahead * 0 write cache */ - unsigned short words130_159[30];/* reserved vendor words 130-159 */ - unsigned short words160_255[96];/* reserved words 160-255 */ + unsigned short words130_155[26];/* reserved vendor words 130-155 */ + unsigned short word156; + unsigned short words157_159[3];/* reserved vendor words 157-159 */ + unsigned short words160_255[95];/* reserved words 160-255 */ }; /* diff --git a/include/linux/hdsmart.h b/include/linux/hdsmart.h index 509b591d2835..7974a47fe582 100644 --- a/include/linux/hdsmart.h +++ b/include/linux/hdsmart.h @@ -17,123 +17,108 @@ #ifndef _LINUX_HDSMART_H #define _LINUX_HDSMART_H +#define OFFLINE_FULL_SCAN 0 +#define SHORT_SELF_TEST 1 +#define EXTEND_SELF_TEST 2 +#define SHORT_CAPTIVE_SELF_TEST 129 +#define EXTEND_CAPTIVE_SELF_TEST 130 + /* smart_attribute is the vendor specific in SFF-8035 spec */ -struct ata_smart_attribute { - unsigned char id; - unsigned short status_flag; - unsigned char normalized; - unsigned char worse_normal; - unsigned char raw[6]; - unsigned char reserv; -} __attribute__ ((packed)); +typedef struct ata_smart_attribute_s { + unsigned char id; + unsigned short status_flag; + unsigned char normalized; + unsigned char worse_normal; + unsigned char raw[6]; + unsigned char reserv; +} __attribute__ ((packed)) ata_smart_attribute_t; /* smart_values is format of the read drive Atrribute command */ -struct ata_smart_values { - unsigned short revnumber; - struct ata_smart_attribute vendor_attributes [30]; - unsigned char offline_data_collection_status; - unsigned char self_test_exec_status; - unsigned short total_time_to_complete_off_line; - unsigned char vendor_specific_366; - unsigned char offline_data_collection_capability; - unsigned short smart_capability; - unsigned char errorlog_capability; - unsigned char vendor_specific_371; - unsigned char short_test_completion_time; - unsigned char extend_test_completion_time; - unsigned char reserved_374_385 [12]; - unsigned char vendor_specific_386_509 [125]; - unsigned char chksum; -} __attribute__ ((packed)); +typedef struct ata_smart_values_s { + unsigned short revnumber; + ata_smart_attribute_t vendor_attributes [30]; + unsigned char offline_data_collection_status; + unsigned char self_test_exec_status; + unsigned short total_time_to_complete_off_line; + unsigned char vendor_specific_366; + unsigned char offline_data_collection_capability; + unsigned short smart_capability; + unsigned char errorlog_capability; + unsigned char vendor_specific_371; + unsigned char short_test_completion_time; + unsigned char extend_test_completion_time; + unsigned char reserved_374_385 [12]; + unsigned char vendor_specific_386_509 [125]; + unsigned char chksum; +} __attribute__ ((packed)) ata_smart_values_t; /* Smart Threshold data structures */ /* Vendor attribute of SMART Threshold */ -struct ata_smart_threshold_entry { - unsigned char id; - unsigned char normalized_threshold; - unsigned char reserved[10]; -} __attribute__ ((packed)); +typedef struct ata_smart_threshold_entry_s { + unsigned char id; + unsigned char normalized_threshold; + unsigned char reserved[10]; +} __attribute__ ((packed)) ata_smart_threshold_entry_t; /* Format of Read SMART THreshold Command */ -struct ata_smart_thresholds { - unsigned short revnumber; - struct ata_smart_threshold_entry thres_entries[30]; - unsigned char reserved[149]; - unsigned char chksum; -} __attribute__ ((packed)); - -struct ata_smart_errorlog_command_struct { - unsigned char devicecontrolreg; - unsigned char featuresreg; - unsigned char sector_count; - unsigned char sector_number; - unsigned char cylinder_low; - unsigned char cylinder_high; - unsigned char drive_head; - unsigned char commandreg; - unsigned int timestamp; -} __attribute__ ((packed)); - -struct ata_smart_errorlog_error_struct { - unsigned char error_condition; - unsigned char extended_error[14]; - unsigned char state; - unsigned short timestamp; -} __attribute__ ((packed)); - -struct ata_smart_errorlog_struct { - struct ata_smart_errorlog_command_struct commands[6]; - struct ata_smart_errorlog_error_struct error_struct; -} __attribute__ ((packed)); - -struct ata_smart_errorlog { - unsigned char revnumber; - unsigned char error_log_pointer; - struct ata_smart_errorlog_struct errorlog_struct[5]; - unsigned short ata_error_count; - unsigned short non_fatal_count; - unsigned short drive_timeout_count; - unsigned char reserved[53]; -} __attribute__ ((packed)); - -struct ata_smart_selftestlog_struct { - unsigned char selftestnumber; - unsigned char selfteststatus; - unsigned short timestamp; - unsigned char selftestfailurecheckpoint; - unsigned int lbafirstfailure; - unsigned char vendorspecific[15]; -} __attribute__ ((packed)); - -struct ata_smart_selftestlog { - unsigned short revnumber; - struct ata_smart_selftestlog_struct selftest_struct[21]; - unsigned char vendorspecific[2]; - unsigned char mostrecenttest; - unsigned char resevered[2]; - unsigned char chksum; -} __attribute__ ((packed)); - -#if !defined(__KERNEL__) || defined(_IDE_DISK_C) -/* smartctl version number */ -#define VERSION_MAJOR 1 -#define VERSION_MINOR 2 - -/* Number of ata device to scan */ -int numdevices; - -/* how often SMART is checks in seconds */ -int checktime = 1800; - -typedef struct atadevices_s { - int fd; - char devicename[14]; - int selftest; - struct hd_driveid drive; - struct ata_smart_values smartval; - struct ata_smart_thresholds smartthres; -} atadevices_t; - -#endif /* !defined(__KERNEL__) || defined(_IDE_DISK_C) */ +typedef struct ata_smart_thresholds_s { + unsigned short revnumber; + ata_smart_threshold_entry_t thres_entries[30]; + unsigned char reserved[149]; + unsigned char chksum; +} __attribute__ ((packed)) ata_smart_thresholds_t; + +typedef struct ata_smart_errorlog_command_struct_s { + unsigned char devicecontrolreg; + unsigned char featuresreg; + unsigned char sector_count; + unsigned char sector_number; + unsigned char cylinder_low; + unsigned char cylinder_high; + unsigned char drive_head; + unsigned char commandreg; + unsigned int timestamp; +} __attribute__ ((packed)) ata_smart_errorlog_command_struct_t; + +typedef struct ata_smart_errorlog_error_struct_s { + unsigned char error_condition; + unsigned char extended_error[14]; + unsigned char state; + unsigned short timestamp; +} __attribute__ ((packed)) ata_smart_errorlog_error_struct_t; + +typedef struct ata_smart_errorlog_struct_s { + ata_smart_errorlog_command_struct_t commands[6]; + ata_smart_errorlog_error_struct_t error_struct; +} __attribute__ ((packed)) ata_smart_errorlog_struct_t; + +typedef struct ata_smart_errorlog_s { + unsigned char revnumber; + unsigned char error_log_pointer; + ata_smart_errorlog_struct_t errorlog_struct[5]; + unsigned short ata_error_count; + unsigned short non_fatal_count; + unsigned short drive_timeout_count; + unsigned char reserved[53]; + unsigned char chksum; +} __attribute__ ((packed)) ata_smart_errorlog_t; + +typedef struct ata_smart_selftestlog_struct_s { + unsigned char selftestnumber; + unsigned char selfteststatus; + unsigned short timestamp; + unsigned char selftestfailurecheckpoint; + unsigned int lbafirstfailure; + unsigned char vendorspecific[15]; +} __attribute__ ((packed)) ata_smart_selftestlog_struct_t; + +typedef struct ata_smart_selftestlog_s { + unsigned short revnumber; + ata_smart_selftestlog_struct_t selftest_struct[21]; + unsigned char vendorspecific[2]; + unsigned char mostrecenttest; + unsigned char resevered[2]; + unsigned char chksum; +} __attribute__ ((packed)) ata_smart_selftestlog_t; #endif /* _LINUX_HDSMART_H */ diff --git a/include/linux/ide.h b/include/linux/ide.h index ea395aaa86f8..8804c9777f91 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -63,6 +63,12 @@ void cmd640_dump_regs (void); */ #define IDE_DRIVE_CMD 99 /* (magic) undef to reduce kernel size*/ +/* + * IDE_DRIVE_TASK is used to implement many features needed for raw tasks + */ +#define IDE_DRIVE_TASK 98 +#define IDE_DRIVE_CMD_AEB 98 + /* * "No user-serviceable parts" beyond this point :) *****************************************************************************/ @@ -302,6 +308,10 @@ typedef struct ide_drive_s { char driver_req[10]; /* requests specific driver */ int last_lun; /* last logical unit */ int forced_lun; /* if hdxlun was given at boot */ + int lun; /* logical unit */ + byte init_speed; /* transfer rate set at boot */ + byte current_speed; /* current transfer rate set */ + byte dn; /* now wide spread use */ } ide_drive_t; /* @@ -336,7 +346,8 @@ typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *); * support all possible PIO settings. They may silently ignore * or round values as they see fit. */ -typedef void (ide_tuneproc_t)(ide_drive_t *, byte); +typedef void (ide_tuneproc_t) (ide_drive_t *, byte); +typedef int (ide_speedproc_t) (ide_drive_t *, byte); /* * This is used to provide support for strange interfaces @@ -374,6 +385,7 @@ typedef struct hwif_s { ide_drive_t drives[MAX_DRIVES]; /* drive info */ struct gendisk *gd; /* gendisk structure */ ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */ + ide_speedproc_t *speedproc; /* routine to retune DMA modes for drives */ ide_selectproc_t *selectproc; /* tweaks hardware to select drive */ ide_resetproc_t *resetproc; /* routine to reset controller after a disk reset */ ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */ @@ -409,6 +421,7 @@ typedef struct hwif_s { unsigned long last_time; /* time when previous rq was done */ #endif byte straight8; /* Alan's straight 8 check */ + void *hwif_data; /* extra hwif data */ } ide_hwif_t; /* @@ -728,14 +741,16 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err); * Issue ATA command and wait for completion. */ int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf); +int ide_wait_cmd_task (ide_drive_t *drive, byte *buf); void ide_delay_50ms (void); int system_bus_clock(void); +byte ide_auto_reduce_xfer (ide_drive_t *drive); int ide_driveid_update (ide_drive_t *drive); -int ide_ata66_check (ide_drive_t *drive, int cmd, int nsect, int feature); +int ide_ata66_check (ide_drive_t *drive, byte cmd, byte nsect, byte feature); int ide_config_drive_speed (ide_drive_t *drive, byte speed); -int set_transfer (ide_drive_t *drive, int cmd, int nsect, int feature); +int set_transfer (ide_drive_t *drive, byte cmd, byte nsect, byte feature); /* * ide_system_bus_speed() returns what we think is the system VESA/PCI @@ -769,37 +784,10 @@ request_queue_t *ide_get_queue (kdev_t dev); */ int drive_is_flashcard (ide_drive_t *drive); -int ide_spin_wait_hwgroup(ide_drive_t *drive, unsigned long *flags); +int ide_spin_wait_hwgroup (ide_drive_t *drive); void ide_timer_expiry (unsigned long data); void ide_intr (int irq, void *dev_id, struct pt_regs *regs); -void do_ide0_request (request_queue_t * q); -#if MAX_HWIFS > 1 -void do_ide1_request (request_queue_t * q); -#endif -#if MAX_HWIFS > 2 -void do_ide2_request (request_queue_t * q); -#endif -#if MAX_HWIFS > 3 -void do_ide3_request (request_queue_t * q); -#endif -#if MAX_HWIFS > 4 -void do_ide4_request (request_queue_t * q); -#endif -#if MAX_HWIFS > 5 -void do_ide5_request (request_queue_t * q); -#endif -#if MAX_HWIFS > 6 -void do_ide6_request (request_queue_t * q); -#endif -#if MAX_HWIFS > 7 -void do_ide7_request (request_queue_t * q); -#endif -#if MAX_HWIFS > 8 -void do_ide8_request (request_queue_t * q); -#endif -#if MAX_HWIFS > 9 -void do_ide9_request (request_queue_t * q); -#endif +void do_ide_request (request_queue_t * q); void ide_init_subdrivers (void); #ifndef _IDE_C diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 61f672a3c042..311bdd66d64e 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -70,6 +70,7 @@ typedef struct zone_struct { typedef struct zonelist_struct { zone_t * zones [MAX_NR_ZONES+1]; // NULL delimited int gfp_mask; + atomic_t free_before_allocate; } zonelist_t; #define NR_GFPINDEX 0x100 diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 0c84b76c4c79..ddd0563a5588 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -98,7 +99,6 @@ do { \ /* Inode Flags */ #define NFS_USE_READDIRPLUS(inode) ((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0) -#define NFS_MONOTONE_COOKIES(inode) ((NFS_SERVER(inode)->flags & NFS_NONMONOTONE_COOKIES) ? 0 : 1) /* * These are the default flags for swap requests @@ -155,6 +155,17 @@ extern struct inode_operations nfs_file_inode_operations; extern struct file_operations nfs_file_operations; extern struct address_space_operations nfs_file_aops; +static __inline__ struct rpc_cred * +nfs_file_cred(struct file *file) +{ + struct rpc_cred *cred = (struct rpc_cred *)(file->private_data); +#ifdef RPC_DEBUG + if (cred && cred->cr_magic != RPCAUTH_CRED_MAGIC) + BUG(); +#endif + return cred; +} + /* * linux/fs/nfs/dir.c */ diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h index 8e11ef368f69..7b7df5b06f20 100644 --- a/include/linux/nfs_mount.h +++ b/include/linux/nfs_mount.h @@ -54,11 +54,4 @@ struct nfs_mount_data { #define NFS_MOUNT_NONLM 0x0200 /* 3 */ #define NFS_MOUNT_FLAGMASK 0xFFFF -/* - * Private flags - not to be set by mount program - */ -#ifdef __KERNEL__ -#define NFS_NONMONOTONE_COOKIES 0x00010000 -#endif /* __KERNEL__ */ - #endif diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 475fced7c0d9..5f6572b22216 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -40,7 +40,7 @@ struct nfs_page { #define NFS_WBACK_BUSY(req) ((req)->wb_flags & PG_BUSY) -extern struct nfs_page *nfs_create_request(struct dentry *dentry, +extern struct nfs_page *nfs_create_request(struct file *file, struct page *page, unsigned int offset, unsigned int count); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index eca3e1b2d570..1e6147c355dd 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -106,7 +106,6 @@ struct nfs_writeres { * Argument struct for decode_entry function */ struct nfs_entry { - struct page * page; __u64 ino; __u64 cookie, prev_cookie; @@ -115,8 +114,6 @@ struct nfs_entry { int eof; struct nfs_fh fh; struct nfs_fattr fattr; - unsigned long offset, - prev; }; /* @@ -326,10 +323,10 @@ struct nfs_rpc_ops { struct nfs_fh *, struct nfs_fattr *); int (*access) (struct dentry *, int , int); int (*readlink)(struct dentry *, void *, unsigned int); - int (*read) (struct dentry *, struct nfs_fattr *, + int (*read) (struct file *, struct nfs_fattr *, int, loff_t, unsigned int, void *buffer, int *eofp); - int (*write) (struct dentry *, struct nfs_fattr *, + int (*write) (struct file *, struct nfs_fattr *, int, loff_t, unsigned int, void *buffer, struct nfs_writeverf *verfp); int (*commit) (struct dentry *, struct nfs_fattr *, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index b65681331c9b..b7a9f8fbe8ab 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1175,7 +1175,15 @@ #define PCI_DEVICE_ID_INTEL_82443BX_0 0x7190 #define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191 #define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192 +#define PCI_DEVICE_ID_INTEL_82440MX_1 0x7194 +#define PCI_DEVICE_ID_INTEL_82443MX_0 0x7198 +#define PCI_DEVICE_ID_INTEL_82443MX_1 0x7199 +#define PCI_DEVICE_ID_INTEL_82443MX_2 0x719a +#define PCI_DEVICE_ID_INTEL_82443MX_3 0x719b +#define PCI_DEVICE_ID_INTEL_82372FB_0 0x7600 #define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 +#define PCI_DEVICE_ID_INTEL_82372FB_2 0x7602 +#define PCI_DEVICE_ID_INTEL_82372FB_3 0x7603 #define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 #define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 #define PCI_DEVICE_ID_INTEL_82451NX 0x84ca diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index d106c881abb5..242be9730f1b 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -25,6 +25,9 @@ struct rpc_cred { unsigned long cr_expire; /* when to gc */ unsigned short cr_count; /* ref count */ unsigned short cr_flags; /* various flags */ +#ifdef RPC_DEBUG + unsigned long cr_magic; /* 0x0f4aa4f0 */ +#endif uid_t cr_uid; @@ -34,6 +37,8 @@ struct rpc_cred { #define RPCAUTH_CRED_UPTODATE 0x0002 #define RPCAUTH_CRED_DEAD 0x0004 +#define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 + /* * Client authentication handle */ diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 612ce337d41b..fefe0681d132 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -3,6 +3,7 @@ #include #include +#include #include @@ -24,6 +25,11 @@ long vread(char *buf, char *addr, unsigned long count); void vmfree_area_pages(unsigned long address, unsigned long size); int vmalloc_area_pages(unsigned long address, unsigned long size); +/* vmlist_lock is a read-write spinlock that protects vmlist + * Used in mm/vmalloc.c (get_vm_area() and vfree()) and fs/proc/kcore.c. + */ +extern rwlock_t vmlist_lock; + extern struct vm_struct * vmlist; #endif diff --git a/include/linux/wait.h b/include/linux/wait.h index 6d8f5dae61af..6ac1f0e88fe4 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -27,7 +27,7 @@ extern int printk(const char *fmt, ...); #define WQ_BUG() do { \ printk("wq bug, forcing oops.\n"); \ - *(int*)0 = 0; \ + BUG(); \ } while (0) #define CHECK_MAGIC(x) if (x != (long)&(x)) \ diff --git a/init/main.c b/init/main.c index 6cb645c1f4d0..04180c8e9340 100644 --- a/init/main.c +++ b/init/main.c @@ -405,9 +405,18 @@ static int __init debug_kernel(char *str) return 1; } +static int __init quiet_kernel(char *str) +{ + if (*str) + return 0; + console_loglevel = 4; + return 1; +} + __setup("ro", readonly); __setup("rw", readwrite); __setup("debug", debug_kernel); +__setup("quiet", quiet_kernel); /* * This is a simple kernel command line parsing function: it parses diff --git a/ipc/util.c b/ipc/util.c index 8771f73d11ae..29819efbb021 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -159,25 +159,19 @@ struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id) void* ipc_alloc(int size) { void* out; - if(size > PAGE_SIZE) { - lock_kernel(); + if(size > PAGE_SIZE) out = vmalloc(size); - unlock_kernel(); - } else { + else out = kmalloc(size, GFP_KERNEL); - } return out; } void ipc_free(void* ptr, int size) { - if(size > PAGE_SIZE) { - lock_kernel(); + if(size > PAGE_SIZE) vfree(ptr); - unlock_kernel(); - } else { + else kfree(ptr); - } } /* diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c index 4060c802ac9b..3f3b5fc16fd8 100644 --- a/kernel/exec_domain.c +++ b/kernel/exec_domain.c @@ -23,7 +23,7 @@ struct exec_domain default_exec_domain = { }; static struct exec_domain *exec_domains = &default_exec_domain; -static spinlock_t exec_domains_lock = SPIN_LOCK_UNLOCKED; +static rwlock_t exec_domains_lock = RW_LOCK_UNLOCKED; static asmlinkage void no_lcall7(int segment, struct pt_regs * regs) { @@ -48,15 +48,15 @@ static struct exec_domain *lookup_exec_domain(unsigned long personality) unsigned long pers = personality & PER_MASK; struct exec_domain *it; - spin_lock(&exec_domains_lock); + read_lock(&exec_domains_lock); for (it=exec_domains; it; it=it->next) if (pers >= it->pers_low && pers <= it->pers_high) { if (!try_inc_mod_count(it->module)) continue; - spin_unlock(&exec_domains_lock); + read_unlock(&exec_domains_lock); return it; } - spin_unlock(&exec_domains_lock); + read_unlock(&exec_domains_lock); /* Should never get this far. */ printk(KERN_ERR "No execution domain for personality 0x%02lx\n", pers); @@ -71,15 +71,15 @@ int register_exec_domain(struct exec_domain *it) return -EINVAL; if (it->next) return -EBUSY; - spin_lock(&exec_domains_lock); + write_lock(&exec_domains_lock); for (tmp=exec_domains; tmp; tmp=tmp->next) if (tmp == it) { - spin_unlock(&exec_domains_lock); + write_unlock(&exec_domains_lock); return -EBUSY; } it->next = exec_domains; exec_domains = it; - spin_unlock(&exec_domains_lock); + write_unlock(&exec_domains_lock); return 0; } @@ -88,17 +88,17 @@ int unregister_exec_domain(struct exec_domain *it) struct exec_domain ** tmp; tmp = &exec_domains; - spin_lock(&exec_domains_lock); + write_lock(&exec_domains_lock); while (*tmp) { if (it == *tmp) { *tmp = it->next; it->next = NULL; - spin_unlock(&exec_domains_lock); + write_unlock(&exec_domains_lock); return 0; } tmp = &(*tmp)->next; } - spin_unlock(&exec_domains_lock); + write_unlock(&exec_domains_lock); return -EINVAL; } @@ -148,11 +148,11 @@ int get_exec_domain_list(char * page) int len = 0; struct exec_domain * e; - spin_lock(&exec_domains_lock); + read_lock(&exec_domains_lock); for (e=exec_domains; e && len < PAGE_SIZE - 80; e=e->next) len += sprintf(page+len, "%d-%d\t%-16s\t[%s]\n", e->pers_low, e->pers_high, e->name, e->module ? e->module->name : "kernel"); - spin_unlock(&exec_domains_lock); + read_unlock(&exec_domains_lock); return len; } diff --git a/mm/highmem.c b/mm/highmem.c index 11e03521eb5d..7c9dbc695413 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -60,7 +60,7 @@ struct page * prepare_highmem_swapout(struct page * page) * ok, we can just forget about our highmem page since * we stored its data into the new regular_page. */ - __free_page(page); + page_cache_release(page); new_page = mem_map + MAP_NR(regular_page); LockPage(new_page); return new_page; @@ -78,7 +78,7 @@ struct page * replace_with_highmem(struct page * page) if (!highpage) return page; if (!PageHighMem(highpage)) { - __free_page(highpage); + page_cache_release(highpage); return page; } @@ -94,7 +94,7 @@ struct page * replace_with_highmem(struct page * page) * We can just forget the old page since * we stored its data into the new highmem-page. */ - __free_page(page); + page_cache_release(page); return highpage; } diff --git a/mm/memory.c b/mm/memory.c index e5a54892590c..de7dc07f8c91 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -156,7 +156,7 @@ int copy_page_range(struct mm_struct *dst, struct mm_struct *src, unsigned long address = vma->vm_start; unsigned long end = vma->vm_end; unsigned long cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE; - + src_pgd = pgd_offset(src, address)-1; dst_pgd = pgd_offset(dst, address)-1; @@ -878,7 +878,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, new_page = old_page; } spin_unlock(&mm->page_table_lock); - __free_page(new_page); + page_cache_release(new_page); return 1; /* Minor fault */ bad_wp_page: @@ -1022,7 +1022,7 @@ void swapin_readahead(swp_entry_t entry) /* Ok, do the async read-ahead now */ new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset), 0); if (new_page != NULL) - __free_page(new_page); + page_cache_release(new_page); swap_free(SWP_ENTRY(SWP_TYPE(entry), offset)); } return; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 926364499a50..8961addd543f 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -243,6 +243,9 @@ struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order) if (page) return page; } + /* Somebody else is freeing pages? */ + if (atomic_read(&zonelist->free_before_allocate)) + try_to_free_pages(zonelist->gfp_mask); } /* @@ -270,7 +273,11 @@ struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order) */ if (!(current->flags & PF_MEMALLOC)) { int gfp_mask = zonelist->gfp_mask; - if (!try_to_free_pages(gfp_mask)) { + int result; + atomic_inc(&zonelist->free_before_allocate); + result = try_to_free_pages(gfp_mask); + atomic_dec(&zonelist->free_before_allocate); + if (!result) { if (!(gfp_mask & __GFP_HIGH)) goto fail; } @@ -414,6 +421,7 @@ static inline void build_zonelists(pg_data_t *pgdat) zonelist = pgdat->node_zonelists + i; memset(zonelist, 0, sizeof(*zonelist)); + atomic_set(&zonelist->free_before_allocate, 0); zonelist->gfp_mask = i; j = 0; k = ZONE_NORMAL; diff --git a/mm/swap_state.c b/mm/swap_state.c index 347f87372e1f..2405aba2ffbf 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -136,7 +136,7 @@ void free_page_and_swap_cache(struct page *page) } UnlockPage(page); } - page_cache_release(page); + page_cache_release(page); } diff --git a/mm/swapfile.c b/mm/swapfile.c index c4b4733b7dd9..55ef476a38a0 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -377,7 +377,7 @@ static int try_to_unuse(unsigned int type) page we've been using. */ if (PageSwapCache(page)) delete_from_swap_cache(page); - __free_page(page); + page_cache_release(page); /* * Check for and clear any overflowed swap map counts. */ diff --git a/mm/vmalloc.c b/mm/vmalloc.c index ae8e64351c1b..00879933cfff 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -3,14 +3,17 @@ * * Copyright (C) 1993 Linus Torvalds * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 + * SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian , May 2000 */ #include #include +#include #include #include +rwlock_t vmlist_lock = RW_LOCK_UNLOCKED; struct vm_struct * vmlist = NULL; static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size) @@ -163,11 +166,13 @@ struct vm_struct * get_vm_area(unsigned long size, unsigned long flags) if (!area) return NULL; addr = VMALLOC_START; + write_lock(&vmlist_lock); for (p = &vmlist; (tmp = *p) ; p = &tmp->next) { if (size + addr < (unsigned long) tmp->addr) break; addr = tmp->size + (unsigned long) tmp->addr; if (addr > VMALLOC_END-size) { + write_unlock(&vmlist_lock); kfree(area); return NULL; } @@ -177,6 +182,7 @@ struct vm_struct * get_vm_area(unsigned long size, unsigned long flags) area->size = size + PAGE_SIZE; area->next = *p; *p = area; + write_unlock(&vmlist_lock); return area; } @@ -190,14 +196,17 @@ void vfree(void * addr) printk(KERN_ERR "Trying to vfree() bad address (%p)\n", addr); return; } + write_lock(&vmlist_lock); for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) { if (tmp->addr == addr) { *p = tmp->next; vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size); kfree(tmp); + write_unlock(&vmlist_lock); return; } } + write_unlock(&vmlist_lock); printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr); } @@ -235,6 +244,7 @@ long vread(char *buf, char *addr, unsigned long count) if ((unsigned long) addr + count < count) count = -(unsigned long) addr; + read_lock(&vmlist_lock); for (tmp = vmlist; tmp; tmp = tmp->next) { vaddr = (char *) tmp->addr; if (addr >= vaddr + tmp->size - PAGE_SIZE) @@ -242,7 +252,7 @@ long vread(char *buf, char *addr, unsigned long count) while (addr < vaddr) { if (count == 0) goto finished; - put_user('\0', buf); + *buf = '\0'; buf++; addr++; count--; @@ -251,12 +261,13 @@ long vread(char *buf, char *addr, unsigned long count) do { if (count == 0) goto finished; - put_user(*addr, buf); + *buf = *addr; buf++; addr++; count--; } while (--n > 0); } finished: + read_unlock(&vmlist_lock); return buf - buf_start; } diff --git a/mm/vmscan.c b/mm/vmscan.c index c96b1bc9122a..143c74833d31 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -79,7 +79,7 @@ drop_pte: mm->swap_cnt--; vma->vm_mm->rss--; flush_tlb_page(vma, address); - __free_page(page); + page_cache_release(page); goto out_failed; } @@ -151,7 +151,7 @@ drop_pte: if (file) fput(file); if (!error) goto out_free_success; - __free_page(page); + page_cache_release(page); return error; } @@ -184,7 +184,7 @@ drop_pte: rw_swap_page(WRITE, page, 0); out_free_success: - __free_page(page); + page_cache_release(page); return 1; out_swap_free: swap_free(entry); diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index b8c0a7be877c..7eb578a60b63 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -84,6 +84,11 @@ rpcauth_init_credcache(struct rpc_auth *auth) static inline void rpcauth_crdestroy(struct rpc_auth *auth, struct rpc_cred *cred) { +#ifdef RPC_DEBUG + if (cred->cr_magic != RPCAUTH_CRED_MAGIC) + BUG(); + cred->cr_magic = 0; +#endif if (auth->au_ops->crdestroy) auth->au_ops->crdestroy(cred); else @@ -190,8 +195,13 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags) } spin_unlock(&rpc_credcache_lock); - if (!cred) + if (!cred) { cred = auth->au_ops->crcreate(taskflags); +#ifdef RPC_DEBUG + if (cred) + cred->cr_magic = RPCAUTH_CRED_MAGIC; +#endif + } if (cred) rpcauth_insert_credcache(auth, cred);